コード例 #1
0
ファイル: test_optic.py プロジェクト: tobias-liaudat/batoid
def test_optic():
    if __name__ == '__main__':
        nside = 128
    else:
        nside = 32

    rays = batoid.rayGrid(20, 12.0, 0.005, 0.005, -1.0, nside, 500e-9, 1.0,
                          batoid.ConstMedium(1.0))

    nrays = len(rays)
    print("Tracing {} rays.".format(nrays))
    t_fast = 0.0
    t_slow = 0.0

    telescope = batoid.Optic.fromYaml("HSC.yaml")
    do_pickle(telescope)

    t0 = time.time()

    rays_fast = telescope.trace(rays.copy())
    t1 = time.time()
    rays_slow = batoid.RayVector([telescope.trace(r.copy()) for r in rays])
    t2 = time.time()

    assert rays_fast == rays_slow
    t_fast = t1 - t0
    t_slow = t2 - t1
    print("Fast trace: {:5.3f} s".format(t_fast))
    print("            {} rays per second".format(int(nrays / t_fast)))
    print("Slow trace: {:5.3f} s".format(t_slow))
    print("            {} rays per second".format(int(nrays / t_slow)))
コード例 #2
0
def test_traceReverse():
    telescope = batoid.Optic.fromYaml("HSC.yaml")

    init_rays = batoid.RayVector.asGrid(
        # backDist=20, lx=8.3, nx=128,
        backDist=25,
        lx=8.3,
        nx=6,
        theta_x=0.005,
        theta_y=0.005,
        wavelength=500e-9,
        medium=batoid.ConstMedium(1.0))
    forward_rays = telescope.trace(init_rays.copy())

    # Now, turn the result rays around and trace backwards
    forward_rays.propagate(40.0)
    reverse_rays = forward_rays.copy()
    reverse_rays.vx[:] *= -1
    reverse_rays.vy[:] *= -1
    reverse_rays.vz[:] *= -1
    reverse_rays.t[:] *= -1

    final_rays = telescope.trace(reverse_rays.copy(), reverse=True)
    # propagate all the way to t=0
    final_rays.propagate(0.0)
    final_rays.toCoordSys(batoid.globalCoordSys)

    w = ~final_rays.vignetted
    np.testing.assert_allclose(init_rays.x[w], final_rays.x[w])
    np.testing.assert_allclose(init_rays.y[w], final_rays.y[w])
    np.testing.assert_allclose(init_rays.z[w], final_rays.z[w])
    np.testing.assert_allclose(init_rays.vx[w], -final_rays.vx[w])
    np.testing.assert_allclose(init_rays.vy[w], -final_rays.vy[w])
    np.testing.assert_allclose(init_rays.vz[w], -final_rays.vz[w])
    np.testing.assert_allclose(final_rays.t[w], 0)
コード例 #3
0
def test_optic():
    if __name__ == '__main__':
        nside = 128
    else:
        nside = 32

    rays = batoid.rayGrid(20, 12.0, 0.005, 0.005, -1.0, nside, 500e-9, 1.0,
                          batoid.ConstMedium(1.0))

    nrays = len(rays)
    print("Tracing {} rays.".format(nrays))
    t_fast = 0.0
    t_slow = 0.0

    fn = os.path.join(batoid.datadir, "HSC", "HSC.yaml")
    config = yaml.load(open(fn))
    telescope = batoid.parse.parse_optic(config['opticalSystem'])
    do_pickle(telescope)

    t0 = time.time()

    rays_fast, _ = telescope.trace(rays)
    t1 = time.time()
    rays_slow = batoid.RayVector([telescope.trace(r)[0] for r in rays])
    t2 = time.time()

    assert rays_fast == rays_slow
    t_fast = t1 - t0
    t_slow = t2 - t1
    print("Fast trace: {:5.3f} s".format(t_fast))
    print("            {} rays per second".format(int(nrays / t_fast)))
    print("Slow trace: {:5.3f} s".format(t_slow))
    print("            {} rays per second".format(int(nrays / t_slow)))
コード例 #4
0
ファイル: test_optic.py プロジェクト: tobias-liaudat/batoid
def test_traceReverse():
    if __name__ == '__main__':
        nside = 128
    else:
        nside = 32

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

    init_rays = batoid.rayGrid(20, 12.0, 0.005, 0.005, -1.0, nside, 500e-9,
                               1.0, batoid.ConstMedium(1.0))
    forward_rays = telescope.trace(init_rays.copy())

    # Now, turn the result rays around and trace backwards
    forward_rays.propagate(40.0)
    reverse_rays = batoid.RayVector(
        [batoid.Ray(r.r, -r.v, -r.t, r.wavelength) for r in forward_rays])

    final_rays = telescope.trace(reverse_rays.copy(), reverse=True)
    # propagate all the way to t=0
    final_rays = final_rays.propagate(0.0)
    final_rays.toCoordSys(batoid.globalCoordSys)

    w = np.where(np.logical_not(final_rays.vignetted))[0]
    for idx in w:
        np.testing.assert_allclose(init_rays[idx].x, final_rays[idx].x)
        np.testing.assert_allclose(init_rays[idx].y, final_rays[idx].y)
        np.testing.assert_allclose(init_rays[idx].z, final_rays[idx].z)
        np.testing.assert_allclose(init_rays[idx].vx, -final_rays[idx].vx)
        np.testing.assert_allclose(init_rays[idx].vy, -final_rays[idx].vy)
        np.testing.assert_allclose(init_rays[idx].vz, -final_rays[idx].vz)
        np.testing.assert_allclose(final_rays[idx].t, 0)
コード例 #5
0
def test_circularGrid():
    dist = 10.0
    outer = 4.1
    inner = 0.5
    xcos = 0.1
    ycos = 0.2
    zcos = -np.sqrt(1.0 - xcos**2 - ycos**2)
    nradii = 5
    naz = 50
    wavelength = 500e-9
    flux = 1.2
    medium = batoid.ConstMedium(1.2)

    rays = batoid.circularGrid(dist, outer, inner, xcos, ycos, zcos, nradii, naz, wavelength, flux, medium)
    assert rays.monochromatic == True
    # Check that all rays are perpendicular to v
    ray0 = rays[0]
    for ray in rays:
        dr = ray.r - ray0.r
        dp = np.dot(dr, ray0.v)
        np.testing.assert_allclose(dp, 0.0, atol=1e-14, rtol=0.0)
        np.testing.assert_allclose(ray.wavelength, wavelength)
        np.testing.assert_allclose(ray.flux, flux)
        np.testing.assert_allclose(np.linalg.norm(ray.v), 1./1.2)
        np.testing.assert_allclose(ray.v[0]*1.2, xcos)
        np.testing.assert_allclose(ray.v[1]*1.2, ycos)
コード例 #6
0
def test_traceReverse():
    if __name__ == '__main__':
        nside = 128
    else:
        nside = 32

    fn = os.path.join(batoid.datadir, "HSC", "HSC.yaml")
    config = yaml.load(open(fn))
    telescope = batoid.parse.parse_optic(config['opticalSystem'])

    init_rays = batoid.rayGrid(20, 12.0, 0.005, 0.005, -1.0, nside, 500e-9,
                               1.0, batoid.ConstMedium(1.0))
    forward_rays, _ = telescope.trace(init_rays, outCoordSys=batoid.CoordSys())

    # Now, turn the result rays around and trace backwards
    forward_rays = forward_rays.propagatedToTime(40.0)
    reverse_rays = batoid.RayVector(
        [batoid.Ray(r.r, -r.v, -r.t, r.wavelength) for r in forward_rays])

    final_rays, _ = telescope.traceReverse(reverse_rays,
                                           outCoordSys=batoid.CoordSys())
    # propagate all the way to t=0
    final_rays = final_rays.propagatedToTime(0.0)

    w = np.where(np.logical_not(final_rays.vignetted))[0]
    for idx in w:
        np.testing.assert_allclose(init_rays[idx].x, final_rays[idx].x)
        np.testing.assert_allclose(init_rays[idx].y, final_rays[idx].y)
        np.testing.assert_allclose(init_rays[idx].z, final_rays[idx].z)
        np.testing.assert_allclose(init_rays[idx].vx, -final_rays[idx].vx)
        np.testing.assert_allclose(init_rays[idx].vy, -final_rays[idx].vy)
        np.testing.assert_allclose(init_rays[idx].vz, -final_rays[idx].vz)
        np.testing.assert_allclose(final_rays[idx].t, 0)
コード例 #7
0
ファイル: test_rsplit.py プロジェクト: jmeyers314/batoid
def test_rSplit():
    rng = np.random.default_rng(5)
    for _ in range(100):
        R = rng.normal(0.7, 0.8)
        conic = rng.uniform(-2.0, 1.0)
        ncoef = rng.integers(0, 5)
        coefs = [rng.normal(0, 1e-10) for i in range(ncoef)]
        asphere = batoid.Asphere(R, conic, coefs)

        theta_x = rng.normal(0.0, 1e-8)
        theta_y = rng.normal(0.0, 1e-8)
        rays = batoid.RayVector.asPolar(
            backDist=10.0, medium=batoid.Air(),
            wavelength=500e-9, outer=0.25*R,
            theta_x=theta_x, theta_y=theta_y,
            nrad=10, naz=10
        )
        coating = batoid.SimpleCoating(0.9, 0.1)
        reflectedRays = asphere.reflect(rays.copy(), coating=coating)
        m1 = batoid.Air()
        m2 = batoid.ConstMedium(1.1)
        refractedRays = asphere.refract(rays.copy(), m1, m2, coating=coating)
        refractedRays2, reflectedRays2 = asphere.rSplit(rays, m1, m2, coating)

        rays_allclose(reflectedRays, reflectedRays2)
        rays_allclose(refractedRays, refractedRays2)
コード例 #8
0
ファイル: parse.py プロジェクト: nregnault/batoid
def parse_medium(value):
    from numbers import Real
    if isinstance(value, batoid.Medium):
        return value
    elif isinstance(value, Real):
        return batoid.ConstMedium(value)
    elif isinstance(value, str):
        if value == 'air':
            return batoid.Air()
        elif value == 'silica':
            return batoid.SellmeierMedium(0.6961663, 0.4079426, 0.8974794,
                                          0.0684043**2, 0.1162414**2,
                                          9.896161**2)
        elif value == 'hsc_air':
            return batoid.ConstMedium(1.0)
        w = [0.4, 0.6, 0.75, 0.9, 1.1]
        w = [w_ * 1e-6 for w_ in w]
        if value == 'hsc_silica':
            return batoid.TableMedium(
                batoid.Table(w, [
                    1.47009272, 1.45801158, 1.45421013, 1.45172729, 1.44917721
                ], batoid.Table.Interpolant.linear))
        elif value == 'hsc_bsl7y':
            return batoid.TableMedium(
                batoid.Table(w, [
                    1.53123287, 1.51671428, 1.51225242, 1.50939738, 1.50653251
                ], batoid.Table.Interpolant.linear))
        elif value == 'hsc_pbl1y':
            return batoid.TableMedium(
                batoid.Table(w, [
                    1.57046066, 1.54784671, 1.54157395, 1.53789058, 1.53457169
                ], batoid.Table.Interpolant.linear))
        elif value == 'NLAK10':
            return batoid.SellmeierMedium(1.72878017, 0.169257825, 1.19386956,
                                          0.00886014635, 0.0363416509,
                                          82.9009069)
        elif value == 'PFK85':
            return batoid.SumitaMedium(2.1858326, -0.0050155632, 0.0075107775,
                                       0.00017770562, -1.2164148e-05,
                                       6.1341005e-07)
        elif value == 'BK7':
            return batoid.SellmeierMedium(1.03961212, 0.231792344, 1.01046945,
                                          0.00600069867, 0.0200179144,
                                          103.560653)
        else:
            raise RuntimeError("Unknown medium {}".format(value))
コード例 #9
0
def test_rayGrid():
    dist = 10.0
    length = 10.0
    xcos = 0.1
    ycos = 0.2
    zcos = -np.sqrt(1.0 - xcos**2 - ycos**2)
    nside = 10
    wavelength = 500e-9
    flux = 1.2
    medium = batoid.ConstMedium(1.2)

    rays = batoid.rayGrid(
        dist, length, xcos, ycos, zcos, nside, wavelength, flux, medium,
        lattice=True
    )
    assert rays.monochromatic == True
    # Check that all rays are perpendicular to v
    ray0 = rays[0]
    for ray in rays:
        dr = ray.r - ray0.r
        dp = np.dot(dr, ray0.v)
        np.testing.assert_allclose(dp, 0.0, atol=1e-14, rtol=0.0)
        np.testing.assert_allclose(ray.wavelength, wavelength)
        np.testing.assert_allclose(ray.flux, flux)
        np.testing.assert_allclose(np.linalg.norm(ray.v), 1./1.2)
        np.testing.assert_allclose(ray.v[0]*1.2, xcos)
        np.testing.assert_allclose(ray.v[1]*1.2, ycos)

    # Check that ray that intersects at origin is initially dist away.
    # Need the ray that is in the middle in both dimensions...
    idx = np.ravel_multi_index((nside//2, nside//2), (nside, nside))
    rays.propagateInPlace(dist*1.2)
    np.testing.assert_equal(rays[idx].r, [0,0,0])
    # but mean position won't be the origin, since lattice implies off-center
    assert np.linalg.norm(np.mean(rays.r, axis=0)) > 0.5

    # Now try again with lattice flag set to False
    rays = batoid.rayGrid(
        dist, length, xcos, ycos, zcos, nside, wavelength, flux, medium,
        lattice=False
    )
    # "Central" ray will not intersect origin in this case, but average of
    # all rays should be the origin
    idx = np.ravel_multi_index((nside//2, nside//2), (nside, nside))
    rays.propagateInPlace(dist*1.2)
    assert np.linalg.norm(rays[idx].r) > 0.1
    np.testing.assert_allclose(np.linalg.norm(np.mean(rays.r, axis=0)), 0.0, rtol=0, atol=1e-14)

    # If we use an odd nside, then both the central point and the mean will be the origin.
    nside = 11
    rays = batoid.rayGrid(
        dist, length, xcos, ycos, zcos, nside, wavelength, flux, medium,
        lattice=False
    )
    idx = np.ravel_multi_index((nside//2, nside//2), (nside, nside))
    rays.propagateInPlace(dist*1.2)
    np.testing.assert_allclose(rays[idx].r, [0,0,0], rtol=0, atol=1e-14)
    np.testing.assert_allclose(np.linalg.norm(np.mean(rays.r, axis=0)), 0.0, rtol=0, atol=1e-14)
コード例 #10
0
def test_refract():
    rng = np.random.default_rng(5772156)
    size = 10_000

    for i in range(10):
        jmax = rng.integers(4, 100)
        coef = rng.normal(size=jmax+1)*1e-3
        R_outer = rng.uniform(0.5, 5.0)
        R_inner = rng.uniform(0.0, 0.65*R_outer)

        zernike = batoid.Zernike(coef, R_outer=R_outer, R_inner=R_inner)
        lim = 0.7*R_outer
        m0 = batoid.ConstMedium(rng.normal(1.2, 0.01))
        m1 = batoid.ConstMedium(rng.normal(1.3, 0.01))
        x = rng.uniform(-lim, lim, size=size)
        y = rng.uniform(-lim, lim, size=size)
        z = np.full_like(x, -10.0)
        vx = rng.uniform(-1e-5, 1e-5, size=size)
        vy = rng.uniform(-1e-5, 1e-5, size=size)
        vz = np.sqrt(1-vx*vx-vy*vy)/m0.n
        rv = batoid.RayVector(x, y, z, vx, vy, vz, t=0)
        rvr = batoid.refract(zernike, rv.copy(), m0, m1)
        rvr2 = zernike.refract(rv.copy(), m0, m1)
        rays_allclose(rvr, rvr2, atol=1e-13)
        # print(f"{np.sum(rvr.failed)/len(rvr)*100:.2f}% failed")
        normal = zernike.normal(rvr.x, rvr.y)

        # Test Snell's law
        s0 = np.sum(np.cross(normal, rv.v*m0.n)[~rvr.failed], axis=-1)
        s1 = np.sum(np.cross(normal, rvr.v*m1.n)[~rvr.failed], axis=-1)
        np.testing.assert_allclose(
            m0.n*s0, m1.n*s1,
            rtol=0, atol=1e-9
        )

        # Test that rv.v, rvr.v and normal are all in the same plane
        np.testing.assert_allclose(
            np.einsum(
                "ad,ad->a",
                np.cross(normal, rv.v),
                rv.v
            )[~rvr.failed],
            0.0,
            rtol=0, atol=1e-12
        )
コード例 #11
0
def test_refract():
    rng = np.random.default_rng(5772)
    for i in range(1000):
        R = rng.uniform(1.0, 2.0)
        sphere = batoid.Sphere(R)

        reflectivity = rng.uniform(0, 1)
        transmissivity = rng.uniform(0, 1)
        coating = batoid.SimpleCoating(reflectivity, transmissivity)

        m1 = batoid.ConstMedium(rng.uniform(1.1, 1.2))
        m2 = batoid.ConstMedium(rng.uniform(1.2, 1.3))

        rv = batoid.RayVector(0, 0, 10, 0, 0, -1, 0, 500e-9, 1.0)

        sphere.refract(rv, m1, m2, coating=coating)

        assert (rv.flux[0] == transmissivity)
コード例 #12
0
ファイル: test_Asphere.py プロジェクト: bregeon/batoid
def test_refract():
    rng = np.random.default_rng(577215)
    size = 10_000
    for i in range(100):
        zmax = np.inf
        while zmax > 3.0:
            R = 0.0
            while abs(R) < 15.0:  # Don't allow too small radius of curvature
                R = 1. / rng.normal(0.0, 0.3)  # negative allowed
            conic = rng.uniform(-2.0, 1.0)
            ncoef = rng.choice(5)
            coefs = [rng.normal(0, 1e-8) for i in range(ncoef)]
            asphere = batoid.Asphere(R, conic, coefs)
            lim = min(0.7 * abs(R) / np.sqrt(1 + conic) if conic > -1 else 5,
                      5)
            zmax = abs(asphere.sag(lim, lim))
        m0 = batoid.ConstMedium(rng.normal(1.2, 0.01))
        m1 = batoid.ConstMedium(rng.normal(1.3, 0.01))
        x = rng.uniform(-lim, lim, size=size)
        y = rng.uniform(-lim, lim, size=size)
        z = np.full_like(x, -10.0)
        vx = rng.uniform(-1e-5, 1e-5, size=size)
        vy = rng.uniform(-1e-5, 1e-5, size=size)
        vz = np.sqrt(1 - vx * vx - vy * vy) / m0.n
        rv = batoid.RayVector(x, y, z, vx, vy, vz, t=0)
        rvr = batoid.refract(asphere, rv.copy(), m0, m1)
        rvr2 = asphere.refract(rv.copy(), m0, m1)
        rays_allclose(rvr, rvr2)
        # print(f"{np.sum(rvr.failed)/len(rvr)*100:.2f}% failed")
        normal = asphere.normal(rvr.x, rvr.y)

        # Test Snell's law
        s0 = np.sum(np.cross(normal, rv.v * m0.n)[~rvr.failed], axis=-1)
        s1 = np.sum(np.cross(normal, rvr.v * m1.n)[~rvr.failed], axis=-1)
        np.testing.assert_allclose(m0.n * s0, m1.n * s1, rtol=0, atol=1e-9)

        # Test that rv.v, rvr.v and normal are all in the same plane
        np.testing.assert_allclose(np.einsum("ad,ad->a",
                                             np.cross(normal, rv.v),
                                             rv.v)[~rvr.failed],
                                   0.0,
                                   rtol=0,
                                   atol=1e-12)
コード例 #13
0
ファイル: test_medium.py プロジェクト: nregnault/batoid
def test_const_medium():
    import random
    random.seed(5)

    n = 1.4
    const_medium = batoid.ConstMedium(n)
    for i in range(100):
        w = random.uniform(0.5, 1.0)
        assert const_medium.getN(w) == n
    do_pickle(const_medium)
コード例 #14
0
ファイル: test_psf.py プロジェクト: dkirkby/batoid
def test_hsc_psf():
    # Just testing that doesn't crash for the moment
    fn = os.path.join(batoid.datadir, "HSC", "HSC.yaml")
    config = yaml.load(open(fn))
    telescope = batoid.parse.parse_optic(config['opticalSystem'])

    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.gnomicToDirCos(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()
コード例 #15
0
ファイル: test_Medium.py プロジェクト: jmeyers314/batoid
def test_ConstMedium():
    rng = np.random.default_rng(5)
    for i in range(100):
        n = rng.uniform(1.0, 2.0)
        const_medium = batoid.ConstMedium(n)
        wavelengths = rng.uniform(300e-9, 1100e-9, size=100)
        for w in wavelengths:
            assert const_medium.getN(w) == n
        np.testing.assert_array_equal(const_medium.getN(wavelengths),
                                      np.full_like(wavelengths, n))
    do_pickle(const_medium)
コード例 #16
0
ファイル: test_medium.py プロジェクト: nregnault/batoid
def test_ne():
    filename = os.path.join(batoid.datadir, "media", "silica_dispersion.txt")
    wave, n = np.genfromtxt(filename).T
    wave *= 1e-6  # microns -> meters
    table = batoid.Table(wave, n, batoid.Table.Interpolant.linear)
    table2 = batoid.Table(wave * 1.01, n, batoid.Table.Interpolant.linear)

    objs = [
        batoid.ConstMedium(1.0),
        batoid.ConstMedium(1.1),
        batoid.TableMedium(table),
        batoid.TableMedium(table2),
        batoid.SellmeierMedium(0.6961663, 0.4079426, 0.8974794, 0.0684043**2,
                               0.1162414**2, 9.896161**2),
        batoid.SellmeierMedium(0.4079426, 0.6961663, 0.8974794, 0.0684043**2,
                               0.1162414**2, 9.896161**2),
        batoid.Air(),
        batoid.Air(pressure=100)
    ]
    all_obj_diff(objs)
コード例 #17
0
def test_refract():
    rng = np.random.default_rng(577215)
    size = 10_000
    for i in range(100):
        R = 1./rng.normal(0.0, 0.3)
        conic = rng.uniform(-2.0, 1.0)
        quad = batoid.Quadric(R, conic)
        m0 = batoid.ConstMedium(rng.normal(1.2, 0.01))
        m1 = batoid.ConstMedium(rng.normal(1.3, 0.01))
        lim = min(0.7*abs(R)/np.sqrt(1+conic) if conic > -1 else 10, 10)
        x = rng.uniform(-lim, lim, size=size)
        y = rng.uniform(-lim, lim, size=size)
        z = np.full_like(x, -100.0)
        vx = rng.uniform(-1e-5, 1e-5, size=size)
        vy = rng.uniform(-1e-5, 1e-5, size=size)
        vz = np.sqrt(1-vx*vx-vy*vy)/m0.n
        rv = batoid.RayVector(x, y, z, vx, vy, vz)
        rvr = batoid.refract(quad, rv.copy(), m0, m1)
        rvr2 = quad.refract(rv.copy(), m0, m1)
        rays_allclose(rvr, rvr2)
        # print(f"{np.sum(rvr.failed)/len(rvr)*100:.2f}% failed")
        normal = quad.normal(rvr.x, rvr.y)

        # Test Snell's law
        s0 = np.sum(np.cross(normal, rv.v*m0.n)[~rvr.failed], axis=-1)
        s1 = np.sum(np.cross(normal, rvr.v*m1.n)[~rvr.failed], axis=-1)
        np.testing.assert_allclose(
            m0.n*s0, m1.n*s1,
            rtol=0, atol=1e-9
        )

        # Test that rv.v, rvr.v and normal are all in the same plane
        np.testing.assert_allclose(
            np.einsum(
                "ad,ad->a",
                np.cross(normal, rv.v),
                rv.v
            )[~rvr.failed],
            0.0,
            rtol=0, atol=1e-12
        )
コード例 #18
0
def test_paraboloid_refraction_plane():
    import random
    random.seed(577)
    wavelength = 500e-9  # arbitrary
    para = batoid.Paraboloid(-20.0)
    m1 = batoid.ConstMedium(1.11)
    m2 = batoid.ConstMedium(1.32)
    for i in range(1000):
        x = random.gauss(0, 1)
        y = random.gauss(0, 1)
        vx = random.gauss(0, 1e-1)
        vy = random.gauss(0, 1e-1)
        v = normalized(np.array([vx, vy, 1])) / m1.getN(wavelength)
        ray = batoid.Ray(x, y, -10, v[0], v[1], v[2], 0)
        rray = para.refract(ray, m1, m2)
        np.testing.assert_allclose(np.linalg.norm(rray.v),
                                   1. / m2.getN(wavelength),
                                   rtol=1e-15)
        # also check refractInPlace
        rray2 = batoid.Ray(ray)
        para.refractInPlace(rray2, m1, m2)
        assert rray == rray2

        # ray.v, surfaceNormal, and rray.v should all be in the same plane, and
        # hence (ray.v x surfaceNormal) . rray.v should have zero magnitude.
        # magnitude zero.
        normal = para.normal(rray.r[0], rray.r[1])
        np.testing.assert_allclose(np.dot(np.cross(ray.v, normal), rray.v),
                                   0.0,
                                   rtol=0,
                                   atol=1e-15)

        # Test Snell's law
        np.testing.assert_allclose(
            m1.getN(wavelength) *
            np.linalg.norm(np.cross(normalized(ray.v), normal)),
            m2.getN(wavelength) *
            np.linalg.norm(np.cross(normalized(rray.v), normal)),
            rtol=0,
            atol=1e-15)
コード例 #19
0
def test_asphere_refraction_reversal():
    import random
    random.seed(577215)
    wavelength = 500e-9  # arbitrary
    asphere = batoid.Asphere(23.0, -0.97, [1e-5, 1e-6])
    m1 = batoid.ConstMedium(1.7)
    m2 = batoid.ConstMedium(1.9)
    for i in range(1000):
        x = random.gauss(0, 1)
        y = random.gauss(0, 1)
        vx = random.gauss(0, 1e-1)
        vy = random.gauss(0, 1e-1)
        ray = batoid.Ray([x, y, -0.1],
                         normalized(np.array([vx, vy, 1])) /
                         m1.getN(wavelength), 0)
        rray = asphere.refract(ray, m1, m2)
        np.testing.assert_allclose(np.linalg.norm(rray.v),
                                   1. / m2.getN(wavelength),
                                   rtol=1e-15)

        # Invert the refracted ray, and see that it ends back at the starting
        # point

        # Keep going a bit before turning around though
        turn_around = rray.positionAtTime(rray.t + 0.1)
        return_ray = batoid.Ray(turn_around, -rray.v, -(rray.t + 0.1))
        riray = asphere.intersect(return_ray)
        # First check that we intersected at the same point
        np.testing.assert_allclose(rray.r[0], riray.r[0], rtol=0, atol=1e-10)
        np.testing.assert_allclose(rray.r[1], riray.r[1], rtol=0, atol=1e-10)
        np.testing.assert_allclose(rray.r[2], riray.r[2], rtol=0, atol=1e-10)
        # Refract and propagate back to t=0.
        cray = asphere.refract(return_ray, m2, m1)
        np.testing.assert_allclose(np.linalg.norm(cray.v),
                                   1. / m1.getN(wavelength),
                                   rtol=1e-15)
        cpoint = cray.positionAtTime(0)
        np.testing.assert_allclose(cpoint[0], x, rtol=0, atol=1e-10)
        np.testing.assert_allclose(cpoint[1], y, rtol=0, atol=1e-10)
        np.testing.assert_allclose(cpoint[2], -0.1, rtol=0, atol=1e-10)
コード例 #20
0
def test_asphere_refraction_plane():
    import random
    random.seed(57721)
    wavelength = 500e-9  # arbitrary
    asphere = batoid.Asphere(25.0, -0.97, [1e-3, 1e-5])
    m1 = batoid.ConstMedium(1.7)
    m2 = batoid.ConstMedium(1.2)
    for i in range(1000):
        x = random.gauss(0, 1)
        y = random.gauss(0, 1)
        vx = random.gauss(0, 1e-1)
        vy = random.gauss(0, 1e-1)
        v = normalized(np.array([vx, vy, 1])) / m1.getN(wavelength)
        ray = batoid.Ray((x, y, -0.1), (v[0], v[1], v[2]), 0)
        rray = asphere.refract(ray, m1, m2)
        np.testing.assert_allclose(np.linalg.norm(rray.v),
                                   1. / m2.getN(wavelength),
                                   rtol=1e-14)
        # also check refractInPlace
        rray2 = ray.copy()
        asphere.refractInPlace(rray2, m1, m2)
        assert rray == rray2

        # ray.v, surfaceNormal, and rray.v should all be in the same plane, and
        # hence (ray.v x surfaceNormal) . rray.v should have zero magnitude.
        # magnitude zero.
        normal = asphere.normal(rray.r[0], rray.r[1])
        np.testing.assert_allclose(np.dot(np.cross(ray.v, normal), rray.v),
                                   0.0,
                                   rtol=0,
                                   atol=1e-14)

        # Test Snell's law
        np.testing.assert_allclose(
            m1.getN(wavelength) *
            np.linalg.norm(np.cross(normalized(ray.v), normal)),
            m2.getN(wavelength) *
            np.linalg.norm(np.cross(normalized(rray.v), normal)),
            rtol=0,
            atol=1e-15)
コード例 #21
0
def test_inplace():
    rays = batoid.rayGrid(10.0, 10.0, 0.1, 0.1, 1.0, 1024, 500e-9, 1.0, batoid.ConstMedium(1.2))
    print("propagating {} rays.".format(len(rays)))
    rays2 = batoid.RayVector(rays)

    t0 = time.time()
    outrays = rays.propagatedToTime(11.2)
    t1 = time.time()
    rays2.propagateInPlace(11.2)
    t2 = time.time()

    print("immutable propagation took {:6.3f} seconds.".format(t1-t0))
    print("in-place propagation took  {:6.3f} seconds.".format(t2-t1))

    assert outrays == rays2
コード例 #22
0
def parse_medium(config):
    from numbers import Real
    if config is None:
        return None
    if isinstance(config, batoid.Medium):
        return config
    if isinstance(config, Real):
        return batoid.ConstMedium(config)
    # This dict may be referenced again in an ancestor config, so copy it
    # before parsing
    config = dict(**config)
    typ = config.pop('type')
    # TableMedium, Sellmeier, ConstMedium, SumitaMedium, Air end up here...
    evalstr = "batoid.{}(**config)".format(typ)
    return eval(evalstr)
コード例 #23
0
ファイル: test_ray.py プロジェクト: davidthomas5412/batoid
def test_pointSourceCircularGrid():
    source = [0, 1, 10]
    outer = 0.1
    inner = 0.0
    nradii = 2
    naz = 6
    wavelength = 500e-9
    flux = 1.0
    medium = batoid.ConstMedium(1)
    rays = batoid.pointSourceCircularGrid(source, outer, inner, nradii, naz,
                                          wavelength, flux, medium)
    # Verify that the central ray is pointed at the origin
    # (last ray is central if inner==0.0)
    centerRay = rays[len(rays) - 1]
    centerRay.propagateInPlace(np.sqrt(101))
    np.testing.assert_allclose(centerRay.r, [0, 0, 0], rtol=0, atol=1e-10)
コード例 #24
0
ファイル: test_optic.py プロジェクト: hbrunie/batoid
def test_traceFull():
    if __name__ == '__main__':
        nside = 128
    else:
        nside = 32

    rays = batoid.rayGrid(20, 12.0, 0.005, 0.005, -1.0, nside, 500e-9, 1.0, batoid.ConstMedium(1.0))

    nrays = len(rays)
    print("Tracing {} rays.".format(nrays))

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

    tf = telescope.traceFull(rays)
    rays = telescope.trace(rays)

    assert rays == tf['D']['out']
コード例 #25
0
ファイル: test_rsplit.py プロジェクト: nregnault/batoid
def test_rSplit():
    for i in range(100):
        R = np.random.normal(0.7, 0.8)
        conic = np.random.uniform(-2.0, 1.0)
        ncoef = np.random.randint(0, 4)
        coefs = [np.random.normal(0, 1e-10) for i in range(ncoef)]
        asphere = batoid.Asphere(R, conic, coefs)

        rays = batoid.rayGrid(10, 2*R, 0.0, 0.0, -1.0, 16, 500e-9, 1.0, batoid.Air())
        coating = batoid.SimpleCoating(0.9, 0.1)
        reflectedRays = asphere.reflect(rays, coating)
        m1 = batoid.Air()
        m2 = batoid.ConstMedium(1.1)
        refractedRays = asphere.refract(rays, m1, m2, coating)
        reflectedRays2, refractedRays2 = asphere.rSplit(rays, m1, m2, coating)

        assert reflectedRays == reflectedRays2
        assert refractedRays == refractedRays2
コード例 #26
0
def test_traceFull():
    if __name__ == '__main__':
        nside = 128
    else:
        nside = 32

    rays = batoid.rayGrid(20, 12.0, 0.005, 0.005, -1.0, nside, 500e-9, 1.0,
                          batoid.ConstMedium(1.0))

    nrays = len(rays)
    print("Tracing {} rays.".format(nrays))

    fn = os.path.join(batoid.datadir, "HSC", "HSC.yaml")
    config = yaml.load(open(fn))
    telescope = batoid.parse.parse_optic(config['opticalSystem'])

    tf = telescope.traceFull(rays)
    rays, _ = telescope.trace(rays)

    assert rays == tf[-1]['out']
コード例 #27
0
ファイル: test_Optic.py プロジェクト: bregeon/batoid
def test_optic():
    rays = batoid.RayVector.asGrid(backDist=20,
                                   lx=12,
                                   nx=128,
                                   theta_x=0.005,
                                   theta_y=0.005,
                                   wavelength=500e-9,
                                   medium=batoid.ConstMedium(1.0))

    nrays = len(rays)
    print("Tracing {} rays.".format(nrays))

    # Do one with full pathname
    import os
    filename = os.path.join(batoid.datadir, "HSC", "HSC.yaml")
    with np.testing.assert_raises(FileNotFoundError):
        telescope = batoid.Optic.fromYaml(filename + ".gobbledegook")
    telescope = batoid.Optic.fromYaml(filename)

    # ... and one without
    telescope = batoid.Optic.fromYaml("HSC.yaml")
    do_pickle(telescope)

    rays1 = telescope.trace(rays.copy())

    # Try tracing but skipping the baffles
    for k, v in telescope.itemDict.items():
        if isinstance(v, batoid.Baffle):
            v.skip = True
    rays2 = telescope.trace(rays.copy())
    # rays2 will have fewer rays vignetted rays
    assert np.sum(rays2.vignetted) < np.sum(rays1.vignetted)
    # every place where rays2 is vignetted, is also vignetted in rays1
    w = rays2.vignetted
    assert np.all(rays1.vignetted[w])
    # and every place rays1 is not vignetted has some coords as in rays2
    w = ~rays1.vignetted
    np.testing.assert_allclose(rays1.r[w], rays2.r[w])
    np.testing.assert_allclose(rays1.v[w], rays2.v[w])
    np.testing.assert_allclose(rays1.t[w], rays2.t[w])
コード例 #28
0
def test_uniformCircularGrid():
    dist = 10.0
    outer = 4.1
    inner = 0.5
    xcos = 0
    ycos = 0
    zcos = -1
    nray = 100000
    wavelength = 500e-9
    flux = 1.
    medium = batoid.ConstMedium(1.)
    seed = 0

    rays = batoid.uniformCircularGrid(dist, outer, inner, xcos, ycos, zcos, nray, wavelength, flux,
                                      medium, seed=seed)
    radius = np.hypot(rays.x, rays.y)
    angle = np.arctan2(rays.y, rays.x)

    np.testing.assert_almost_equal(radius.max(), outer, decimal=4)
    np.testing.assert_almost_equal(radius.min(), inner, decimal=4)
    np.testing.assert_almost_equal(rays.x.mean(), 0, decimal=2)
    np.testing.assert_almost_equal(rays.y.mean(), 0, decimal=2)
    np.testing.assert_almost_equal(angle.mean(), 0, decimal=2)

    # test radial distribution
    for cutoff in np.linspace(inner, outer, 5):
        frac = np.sum(radius < cutoff) / nray
        expected = (cutoff ** 2 - inner ** 2) / (outer ** 2 - inner ** 2)
        np.testing.assert_almost_equal(frac, expected, decimal=1)


    # test seed, reproducibility
    rays2 = batoid.uniformCircularGrid(dist, outer, inner, xcos, ycos, zcos, nray, wavelength, flux,
                                       medium, seed=seed)
    newseed = 666
    rays3 = batoid.uniformCircularGrid(dist, outer, inner, xcos, ycos, zcos, nray, wavelength, flux,
                                       medium, seed=newseed)

    assert np.all(rays.r == rays2.r)
    assert not np.all(rays2.r == rays3.r)
コード例 #29
0
def parallel_trace_timing(nside=1024, nthread=None, minChunk=None):
    if nthread is not None:
        print("setting to nthread to {}".format(nthread))
        batoid._batoid.setNThread(nthread)
    print("Using {} threads".format(batoid._batoid.getNThread()))

    if minChunk is not None:
        print("setting to minChunk to {}".format(minChunk))
        batoid._batoid.setMinChunk(minChunk)
    print("Using minChunk of {}".format(batoid._batoid.getMinChunk()))

    # 0.3, 0.3 should be in bounds for current wide-field telescopes
    theta_x = np.deg2rad(0.3)
    theta_y = np.deg2rad(0.3)
    dirCos = np.array([theta_x, theta_y, -1.0])
    dirCos = batoid.utils.normalized(dirCos)
    rays = batoid.circularGrid(
        20, 4.2, 0.5,
        dirCos[0], dirCos[1], dirCos[2],
        nside, nside, 700e-9, 1.0, batoid.ConstMedium(1.0)
    )

    nrays = len(rays)
    print("Tracing {} rays.".format(nrays))
    print()

    if args.lsst:
        fn = os.path.join(batoid.datadir, "LSST", "LSST_r.yaml")
        pm = 'LSST.M1'
    else:
        fn = os.path.join(batoid.datadir, "HSC", "HSC.yaml")
        pm = 'SubaruHSC.PM'
    config = yaml.load(open(fn))
    telescope = batoid.parse.parse_optic(config['opticalSystem'])

    # Optionally perturb the primary mirror using Zernike polynomial
    if args.perturbZ != 0:
        orig = telescope.itemDict[pm].surface
        coefs = np.random.normal(size=args.perturbZ+1)*1e-6 # micron perturbations
        perturbation = batoid.Zernike(coefs, R_outer=telescope.pupilSize)
        telescope.itemDict[pm].surface = batoid.Sum([orig, perturbation])

    # Optionally perturb primary mirror using bicubic spline
    if args.perturbBC != 0:
        orig = telescope.itemDict[pm].surface
        xs = np.linspace(-5, 5, 100)
        ys = np.linspace(-5, 5, 100)
        def f(x, y):
            return args.perturbBC*(np.cos(x) + np.sin(y))
        zs = f(*np.meshgrid(xs, ys))
        bc = batoid.Bicubic(xs, ys, zs)
        telescope.itemDict[pm].surface = batoid.Sum([orig, bc])

    print("Immutable trace")
    t0 = time.time()
    rays_out, _ = telescope.trace(rays)
    t1 = time.time()
    print("{} rays per second".format(int(nrays/(t1-t0))))
    print()

    print("Trace in place")
    t0 = time.time()
    telescope.traceInPlace(rays)
    t1 = time.time()
    print("{} rays per second".format(int(nrays/(t1-t0))))

    assert rays == rays_out

    if args.plot:
        import matplotlib.pyplot as plt
        rays.trimVignettedInPlace()
        x = rays.x
        y = rays.y
        x -= np.mean(x)
        y -= np.mean(y)
        x *= 1e6
        y *= 1e6
        plt.scatter(x, y, s=1, alpha=0.01)
        plt.xlim(np.std(x)*np.r_[-3,3])
        plt.ylim(np.std(y)*np.r_[-3,3])
        plt.xlabel("x (microns)")
        plt.ylabel("y (microns)")
        plt.show()
コード例 #30
0
def parse_optic(config,
                coordSys=batoid.CoordSys(),
                inMedium=batoid.ConstMedium(1.0),
                outMedium=None):
    """
    @param config  configuration dictionary
    @param coordSys  sys to which transformations in config are added
    @param inMedium  default in Medium, often set by optic parent
    @param outMedium default out Medium, often set by optic parent
    """
    if 'obscuration' in config:
        obscuration = parse_obscuration(config.pop('obscuration'))
    else:
        obscuration = None
    name = config.pop('name', "")
    if 'coordSys' in config:
        coordSys = parse_coordSys(config.pop('coordSys'), coordSys)
    inMedium = parse_medium(config.pop('inMedium', inMedium))
    outMedium = parse_medium(config.pop('outMedium', outMedium))
    if outMedium is None:
        outMedium = inMedium

    typ = config.pop('type')
    if typ == 'Mirror':
        surface = parse_surface(config.pop('surface'))
        return batoid.optic.Mirror(surface,
                                   name=name,
                                   coordSys=coordSys,
                                   obscuration=obscuration,
                                   inMedium=inMedium,
                                   outMedium=outMedium)
    elif typ == 'RefractiveInterface':
        surface = parse_surface(config.pop('surface'))
        return batoid.optic.RefractiveInterface(surface,
                                                name=name,
                                                coordSys=coordSys,
                                                obscuration=obscuration,
                                                inMedium=inMedium,
                                                outMedium=outMedium)
    elif typ == 'OPDScreen':
        surface = parse_surface(config.pop('surface'))
        screen = parse_surface(config.pop('screen'))
        return batoid.optic.OPDScreen(surface,
                                      screen,
                                      name=name,
                                      coordSys=coordSys,
                                      obscuration=obscuration,
                                      inMedium=inMedium,
                                      outMedium=outMedium)
    elif typ == 'Baffle':
        surface = parse_surface(config.pop('surface'))
        return batoid.optic.Baffle(surface,
                                   name=name,
                                   coordSys=coordSys,
                                   obscuration=obscuration,
                                   inMedium=inMedium,
                                   outMedium=outMedium)
    elif typ == 'Detector':
        surface = parse_surface(config.pop('surface'))
        return batoid.optic.Detector(surface,
                                     name=name,
                                     coordSys=coordSys,
                                     obscuration=obscuration,
                                     inMedium=inMedium,
                                     outMedium=outMedium)
    elif typ == 'Lens':
        medium = parse_medium(config.pop('medium'))
        itemsConfig = config.pop('items')
        items = [
            parse_optic(itemsConfig[0],
                        coordSys=coordSys,
                        inMedium=inMedium,
                        outMedium=medium),
            parse_optic(itemsConfig[1],
                        coordSys=coordSys,
                        inMedium=medium,
                        outMedium=outMedium)
        ]
        return batoid.optic.Lens(items,
                                 name=name,
                                 coordSys=coordSys,
                                 inMedium=inMedium,
                                 outMedium=outMedium)
    elif typ == 'CompoundOptic':
        itemsConfig = config.pop('items')
        items = [
            parse_optic(iC,
                        coordSys=coordSys,
                        inMedium=inMedium,
                        outMedium=outMedium) for iC in itemsConfig
        ]
        # Look for a few more possible attributes
        kwargs = {}
        for k in ['backDist', 'sphereRadius', 'pupilSize', 'pupilObscuration']:
            if k in config:
                kwargs[k] = config[k]
        if 'stopSurface' in config:
            kwargs['stopSurface'] = parse_optic(config['stopSurface'])
        return batoid.optic.CompoundOptic(items,
                                          inMedium=inMedium,
                                          outMedium=outMedium,
                                          name=name,
                                          coordSys=coordSys,
                                          **kwargs)
    elif typ == 'Interface':
        surface = parse_surface(config.pop('surface'))
        return batoid.optic.Interface(surface, name=name, coordSys=coordSys)
    else:
        raise ValueError(f"Unknown optic type: {typ}")