Esempio n. 1
0
def test_sag():
    np.random.seed(57)
    for _ in range(100):
        s1 = batoid.Sphere(np.random.uniform(1, 3))
        s2 = batoid.Paraboloid(np.random.uniform(1, 3))
        sum = batoid.Sum([s1, s2])

        x = np.random.normal(size=5000)
        y = np.random.normal(size=5000)

        np.testing.assert_allclose(
            sum.sag(x, y),
            s1.sag(x, y) + s2.sag(x, y),
            rtol=1e-12,
            atol=1e-12
        )

        s3 = batoid.Quadric(np.random.uniform(3, 5), np.random.uniform(-0.1, 0.1))
        sum2 = batoid.Sum([s1, s2, s3])

        np.testing.assert_allclose(
            sum2.sag(x, y),
            s1.sag(x, y) + s2.sag(x, y) + s3.sag(x, y),
            rtol=1e-12,
            atol=1e-12
        )
Esempio n. 2
0
def test_ne():
    objs = [
        batoid.Sum([batoid.Plane(), batoid.Plane()]),
        batoid.Sum([batoid.Plane(), batoid.Sphere(1.0)]),
        batoid.Sum([batoid.Plane(), batoid.Plane(), batoid.Plane()]),
        batoid.Plane()
    ]
    all_obj_diff(objs)
Esempio n. 3
0
def test_properties():
    np.random.seed(5)
    for _ in range(100):
        s1 = batoid.Sphere(np.random.uniform(1, 3))
        s2 = batoid.Paraboloid(np.random.uniform(1, 3))
        sum = batoid.Sum([s1, s2])
        do_pickle(sum)
        # check commutativity
        assert sum == batoid.Sum([s2, s1])

        # order of sum.surfaces is not guaranteed
        assert s1 in sum.surfaces
        assert s2 in sum.surfaces

        s3 = batoid.Quadric(np.random.uniform(3, 5), np.random.uniform(-0.1, 0.1))
        sum2 = batoid.Sum([s1, s2, s3])
        do_pickle(sum2)
        # check commutativity
        assert sum2 == batoid.Sum([s2, s3, s1])
        assert sum2 == batoid.Sum([s3, s1, s2])
        assert sum2 == batoid.Sum([s3, s2, s1])
        assert sum2 == batoid.Sum([s2, s1, s3])
        assert sum2 == batoid.Sum([s1, s3, s2])

        assert s1 in sum2.surfaces
        assert s2 in sum2.surfaces
        assert s3 in sum2.surfaces

        do_pickle(sum)
Esempio n. 4
0
def test_intersect():
    np.random.seed(57721)
    rv0 = batoid.RayVector([
        batoid.Ray(
            np.random.normal(scale=0.1),
            np.random.normal(scale=0.1),
            10,
            np.random.normal(scale=1e-4),
            np.random.normal(scale=1e-4),
            -1
        )
        for _ in range(100)
    ])
    for _ in range(100):
        s1 = batoid.Sphere(np.random.uniform(3, 10))
        s2 = batoid.Paraboloid(np.random.uniform(3, 10))
        sum = batoid.Sum([s1, s2])

        rv = batoid.RayVector(rv0)
        rv1 = sum.intersect(rv)
        rv2 = batoid.RayVector([sum.intersect(r) for r in rv])
        rv3 = batoid.RayVector(rv)
        sum.intersectInPlace(rv)

        for r in rv3:
            sum.intersectInPlace(r)

        assert rays_allclose(rv1, rv)
        assert rays_allclose(rv2, rv)
        assert rays_allclose(rv3, rv)
Esempio n. 5
0
def test_refract():
    rng = np.random.default_rng(577215)
    size = 10_000
    for _ in range(100):
        s1 = batoid.Sphere(1. / rng.normal(0., 0.2))
        s2 = batoid.Paraboloid(rng.uniform(1, 3))
        sum = batoid.Sum([s1, s2])
        m0 = batoid.ConstMedium(rng.normal(1.2, 0.01))
        m1 = batoid.ConstMedium(rng.normal(1.3, 0.01))
        x = rng.uniform(-1, 1, size=size)
        y = rng.uniform(-1, 1, 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)
        rvr = batoid.refract(sum, rv.copy(), m0, m1)
        rvr2 = sum.refract(rv.copy(), m0, m1)
        rays_allclose(rvr, rvr2)
        # print(f"{np.sum(rvr.failed)/len(rvr)*100:.2f}% failed")
        normal = sum.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)
Esempio n. 6
0
def test_reflect():
    rng = np.random.default_rng(57721)
    size = 10_000
    for _ in range(100):
        s1 = batoid.Sphere(1. / rng.normal(0., 0.2))
        s2 = batoid.Paraboloid(rng.uniform(1, 3))
        sum = batoid.Sum([s1, s2])
        x = rng.uniform(-1, 1, size=size)
        y = rng.uniform(-1, 1, 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.full_like(x, 1)
        rv = batoid.RayVector(x, y, z, vx, vy, vz)
        rvr = batoid.reflect(sum, rv.copy())
        rvr2 = sum.reflect(rv.copy())
        rays_allclose(rvr, rvr2)
        # print(f"{np.sum(rvr.failed)/len(rvr)*100:.2f}% failed")
        normal = sum.normal(rvr.x, rvr.y)

        # Test law of reflection
        a0 = np.einsum("ad,ad->a", normal, rv.v)[~rvr.failed]
        a1 = np.einsum("ad,ad->a", normal, -rvr.v)[~rvr.failed]
        np.testing.assert_allclose(a0, a1, rtol=0, atol=1e-12)

        # 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)
Esempio n. 7
0
def test_sum_bicubic():
    import os
    import yaml

    fn = os.path.join(batoid.datadir, "LSST", "LSST_i.yaml")
    config = yaml.safe_load(open(fn))
    telescope = batoid.parse.parse_optic(config['opticalSystem'])
    xcos, ycos, zcos = batoid.utils.gnomonicToDirCos(np.deg2rad(0.8),
                                                     np.deg2rad(0.8))
    rays = batoid.circularGrid(
        telescope.dist, telescope.pupilSize / 2,
        telescope.pupilSize * telescope.pupilObscuration / 2, xcos, ycos,
        -zcos, 50, 50, 750e-9, 1.0, telescope.inMedium)
    out, _ = telescope.trace(rays)

    m2 = telescope.itemDict['LSST.M2']

    xs = np.linspace(-m2.outRadius, m2.outRadius, 200)
    ys = xs
    zs = np.zeros((200, 200), dtype=float)
    bicubic = batoid.Bicubic(xs, ys, zs)

    m2.surface = batoid.Sum([m2.surface, bicubic])
    out2, _ = telescope.trace(rays)

    # Don't expect exact equality, but should be very similar
    assert rays_allclose(out, out2, atol=1e-13)
Esempio n. 8
0
def test_add_plane():
    np.random.seed(577)
    for _ in range(100):
        # Adding a plane should have zero effect on sag or normal vector
        s1 = batoid.Sphere(np.random.uniform(1, 3))
        s2 = batoid.Plane()
        sum = batoid.Sum([s1, s2])

        x = np.random.normal(size=5000)
        y = np.random.normal(size=5000)

        np.testing.assert_allclose(
            sum.sag(x, y),
            s1.sag(x, y),
            rtol=1e-12,
            atol=1e-12
        )

        for _x, _y in zip(x[:100], y[:100]):
            np.testing.assert_allclose(
                sum.normal(_x, _y),
                s1.normal(_x, _y),
                rtol=1e-12,
                atol=1e-12
            )
Esempio n. 9
0
def test_sum_paraboloid():
    # para_sag = r^2/(2*R^2)
    # so two paraboloids yields r^2 * (1/(2*R1) + 1/(2*R2))
    # so (1/(2*R1) + 1/(2*R2)) = 1/(2*R)
    # implies
    # 0.5/(1/(2*R1) + 1/(2*R2)) = R
    np.random.seed(5772)
    for _ in range(100):
        R1 = np.random.uniform(1, 2)
        R2 = np.random.uniform(2, 3)
        Rsum = 0.5/(1/(2*R1) + 1/(2*R2))

        para1 = batoid.Paraboloid(R1)
        para2 = batoid.Paraboloid(R2)
        paraSum = batoid.Paraboloid(Rsum)
        paraSum2 = batoid.Sum([para1, para2])

        x = np.random.normal(size=5000)
        y = np.random.normal(size=5000)

        np.testing.assert_allclose(
            paraSum.sag(x, y),
            paraSum2.sag(x, y),
            rtol=1e-12,
            atol=1e-12
        )

        for _x, _y in zip(x[:100], y[:100]):
            np.testing.assert_allclose(
                paraSum.normal(_x, _y),
                paraSum2.normal(_x, _y),
                rtol=1e-12,
                atol=1e-12
            )
Esempio n. 10
0
def test_sum_paraboloid():
    # para_sag = r^2/(2*R^2)
    # so two paraboloids yields r^2 * (1/(2*R1) + 1/(2*R2))
    # so (1/(2*R1) + 1/(2*R2)) = 1/(2*R)
    # implies
    # 0.5/(1/(2*R1) + 1/(2*R2)) = R
    rng = np.random.default_rng(57721566)
    for _ in range(100):
        R1 = rng.uniform(1, 2)
        R2 = rng.uniform(2, 3)
        Rsum = 0.5 / (1 / (2 * R1) + 1 / (2 * R2))

        para1 = batoid.Paraboloid(R1)
        para2 = batoid.Paraboloid(R2)
        paraSum = batoid.Paraboloid(Rsum)
        paraSum2 = batoid.Sum([para1, para2])

        x = rng.normal(size=5000)
        y = rng.normal(size=5000)

        np.testing.assert_allclose(paraSum.sag(x, y),
                                   paraSum2.sag(x, y),
                                   rtol=0,
                                   atol=1e-12)

        np.testing.assert_allclose(
            paraSum.normal(x, y),
            paraSum2.normal(x, y),
            rtol=0,
            atol=1e-12,
        )
Esempio n. 11
0
def test_sum_bicubic():
    telescope = batoid.Optic.fromYaml("LSST_i.yaml")
    xcos, ycos, zcos = batoid.utils.gnomonicToDirCos(
        np.deg2rad(0.8), np.deg2rad(0.8)
    )
    rays = batoid.circularGrid(
        telescope.backDist,
        telescope.pupilSize/2,
        telescope.pupilSize*telescope.pupilObscuration/2,
        xcos, ycos, -zcos,
        50, 50, 750e-9, 1.0, telescope.inMedium
    )
    out = telescope.trace(rays)

    m2 = telescope['LSST.M2']

    xs = np.linspace(-m2.outRadius, m2.outRadius, 200)
    ys = xs
    zs = np.zeros((200, 200), dtype=float)
    bicubic = batoid.Bicubic(xs, ys, zs)

    m2.surface = batoid.Sum([m2.surface, bicubic])
    out2 = telescope.trace(rays)

    # Don't expect exact equality, but should be very similar
    assert rays_allclose(out, out2, atol=1e-13)
Esempio n. 12
0
def test_fail():
    sum = batoid.Sum([batoid.Plane(), batoid.Sphere(1.0)])
    rv = batoid.RayVector(0, 10, 0, 0, 0, -1)  # Too far to side
    rv2 = batoid.intersect(sum, rv.copy())
    np.testing.assert_equal(rv2.failed, np.array([True]))
    # This one passes
    rv = batoid.RayVector(0, 0, -1, 0, 0, +1)
    rv2 = batoid.intersect(sum, rv.copy())
    np.testing.assert_equal(rv2.failed, np.array([False]))
Esempio n. 13
0
def test_fail():
    sum = batoid.Sum([batoid.Plane(), batoid.Sphere(1.0)])
    ray = batoid.Ray([0,0,sum.sag(0,0)-1], [0,0,-1])
    ray = sum.intersect(ray)
    assert ray.failed

    ray = batoid.Ray([0,0,sum.sag(0,0)-1], [0,0,-1])
    sum.intersectInPlace(ray)
    assert ray.failed
Esempio n. 14
0
def test_properties():
    rng = np.random.default_rng(5)
    for i in range(100):
        s1 = batoid.Sphere(rng.uniform(1, 3))
        s2 = batoid.Paraboloid(rng.uniform(1, 3))
        sum = batoid.Sum([s1, s2])
        do_pickle(sum)

        assert s1 is sum.surfaces[0]
        assert s2 is sum.surfaces[1]

        s3 = batoid.Quadric(rng.uniform(3, 5), rng.uniform(-0.1, 0.1))
        sum2 = batoid.Sum([s1, s2, s3])
        do_pickle(sum2)

        assert s1 is sum2.surfaces[0]
        assert s2 is sum2.surfaces[1]
        assert s3 is sum2.surfaces[2]
Esempio n. 15
0
def test_LSST_M1_zernike():
    """See how much a ~100 nm zernike perturbation to M1 affects wavefront zernikes
    """
    np.random.seed(5772156)

    telescope = batoid.Optic.fromYaml("LSST_r.yaml")
    theta_x = np.deg2rad(1.185)
    theta_y = np.deg2rad(0.45)
    fiducialZernikes = batoid.psf.zernike(telescope, theta_x, theta_y, 750e-9)

    N = 256
    xs = np.linspace(-8.36/2, 8.36/2, N)
    ys = np.linspace(-8.36/2, 8.36/2, N)

    jmax = 22
    for _ in range(10):
        coef = np.random.normal(size=jmax+1)*1e-7/np.sqrt(jmax)  # aim for ~100 nm rms
        R_inner = np.random.uniform(0.0, 0.65)

        zsurf = batoid.Zernike(coef, R_outer=8.36/2, R_inner=0.61*8.36/2)
        zs = zsurf.sag(*np.meshgrid(xs, ys))
        bc = batoid.Bicubic(xs, ys, zs)

        # Add Zernike perturbation to M1
        zTelescope = batoid.Optic.fromYaml("LSST_r.yaml")
        zPerturbedM1 = batoid.Sum([
            zTelescope['LSST.M1'].surface,
            zsurf
        ])
        zTelescope['LSST.M1'].surface = zPerturbedM1
        zZernikes = batoid.psf.zernike(zTelescope, theta_x, theta_y, 750e-9)

        # Repeat with bicubic perturbation
        bcTelescope = batoid.Optic.fromYaml("LSST_r.yaml")
        bcPerturbedM1 = batoid.Sum([
            bcTelescope['LSST.M1'].surface,
            bc
        ])
        bcTelescope['LSST.M1'].surface = bcPerturbedM1
        bcZernikes = batoid.psf.zernike(bcTelescope, theta_x, theta_y, 750e-9)

        np.testing.assert_allclose(zZernikes, bcZernikes, rtol=0, atol=1e-3)
Esempio n. 16
0
def test_properties():
    np.random.seed(5)
    for _ in range(100):
        s1 = batoid.Sphere(np.random.uniform(1, 3))
        s2 = batoid.Paraboloid(np.random.uniform(1, 3))
        sum = batoid.Sum([s1, s2])
        do_pickle(sum)

        assert s1 is sum.surfaces[0]
        assert s2 is sum.surfaces[1]

        s3 = batoid.Quadric(np.random.uniform(3, 5), np.random.uniform(-0.1, 0.1))
        sum2 = batoid.Sum([s1, s2, s3])
        do_pickle(sum2)

        assert s1 is sum2.surfaces[0]
        assert s2 is sum2.surfaces[1]
        assert s3 is sum2.surfaces[2]

        do_pickle(sum)
    def update(self, deltax):
        """
        Update the telescope based on the provided update to the optical state.

        Parameters
        ----------
        deltax: aos.state.ZernikeState
            The change in the optical state to apply to the telescope.
        """
        super().update(deltax)
        m2surf = self.optic.itemDict['LSST.M2']
        m2residual = batoid.Zernike(deltax.m2zer, R_outer=m2surf.outRadius, R_inner=m2surf.inRadius)

        if isinstance(m2surf, batoid.Sum):
            m2nominal = m2surf.surfaces[0]
        else:
            m2nominal = m2surf.surface
        self.optic.itemDict['LSST.M2'].surface = batoid.Sum([m2nominal, m2residual])

        m1surf = self.optic.itemDict['LSST.M1']
        m3surf = self.optic.itemDict['LSST.M3']
        
        # spread across all M1M3
        m1m3residual = batoid.Zernike(deltax.m1m3zer, R_outer=m1surf.outRadius, R_inner=m3surf.inRadius)

        if isinstance(m1surf, batoid.Sum):
            m1nominal = m1surf.surfaces[0]
        else:
            m1nominal = m1surf.surface
    
        if isinstance(m3surf, batoid.Sum):
            m3nominal = m3surf.surfaces[0]
        else:
            m3nominal = m3surf.surface

        self.optic.itemDict['LSST.M1'].surface = batoid.Sum([m1nominal, m1m3residual])
        self.optic.itemDict['LSST.M3'].surface = batoid.Sum([m3nominal, m1m3residual])
Esempio n. 18
0
def test_normal():
    rng = np.random.default_rng(577)
    for _ in range(100):
        s1 = batoid.Sphere(rng.uniform(1, 3))
        s2 = batoid.Paraboloid(rng.uniform(1, 3))
        sum = batoid.Sum([s1, s2])

        x = rng.normal(size=5000)
        y = rng.normal(size=5000)

        n1 = s1.normal(x, y)
        n2 = s2.normal(x, y)
        nx = n1[:, 0] / n1[:, 2] + n2[:, 0] / n2[:, 2]
        ny = n1[:, 1] / n1[:, 2] + n2[:, 1] / n2[:, 2]
        nz = 1. / np.sqrt(nx * nx + ny * ny + 1)
        nx *= nz
        ny *= nz
        normal = np.array([nx, ny, nz]).T
        np.testing.assert_allclose(sum.normal(x, y),
                                   normal,
                                   rtol=0,
                                   atol=1e-12)

        s3 = batoid.Quadric(rng.uniform(3, 5), rng.uniform(-0.1, 0.1))
        sum2 = batoid.Sum([s1, s2, s3])
        n3 = s3.normal(x, y)
        nx = n1[:, 0] / n1[:, 2] + n2[:, 0] / n2[:, 2] + n3[:, 0] / n3[:, 2]
        ny = n1[:, 1] / n1[:, 2] + n2[:, 1] / n2[:, 2] + n3[:, 1] / n3[:, 2]
        nz = 1. / np.sqrt(nx * nx + ny * ny + 1)
        nx *= nz
        ny *= nz
        normal = np.array([nx, ny, nz]).T

        np.testing.assert_allclose(sum2.normal(x, y),
                                   normal,
                                   rtol=0,
                                   atol=1e-12)
    def update(self, deltax):
        """
        Update the telescope based on the provided update to the optical state.

        Parameters
        ----------
        deltax: aos.state.BendingState
            The change in the optical state to apply to the telescope.
        """
        super().update(deltax)

        self.m1m3res.applyBending(deltax.m1m3modes)
        self.m2res.applyBending(deltax.m2modes)
        m1m3bicubic = batoid.Bicubic(self.m1m3res.x, self.m1m3res.y, self.m1m3res.surfResidual)
        m2bicubic = batoid.Bicubic(self.m2res.x, self.m2res.y, self.m2res.surfResidual)

        m1surf = self.optic.itemDict['LSST.M1']
        if isinstance(m1surf, batoid.Sum):
            m1nominal = m1surf.surfaces[0]
        else:
            m1nominal = m1surf.surface
        self.optic.itemDict['LSST.M1'].surface = batoid.Sum([m1nominal, m1m3bicubic])

        m3surf = self.optic.itemDict['LSST.M3']
        if isinstance(m1surf, batoid.Sum):
            m3nominal = m3surf.surfaces[0]
        else:
            m3nominal = m3surf.surface
        self.optic.itemDict['LSST.M3'].surface = batoid.Sum([m3nominal, m1m3bicubic])

        m2surf = self.optic.itemDict['LSST.M2']
        if isinstance(m1surf, batoid.Sum):
            m2nominal = m2surf.surfaces[0]
        else:
            m2nominal = m2surf.surface
        self.optic.itemDict['LSST.M2'].surface = batoid.Sum([m2nominal, m2bicubic])
Esempio n. 20
0
def test_withSurface():
    telescope = batoid.Optic.fromYaml("HSC.yaml")
    rays = batoid.RayVector.asPolar(telescope,
                                    wavelength=620e-9,
                                    theta_x=np.deg2rad(0.1),
                                    theta_y=0.0,
                                    nrad=10,
                                    naz=60)
    trays = telescope.trace(rays.copy())
    for key, item in telescope.itemDict.items():
        if not isinstance(item, batoid.Interface):
            continue
        # Do a trivial surface replacement
        surf2 = batoid.Sum([batoid.Plane(), item.surface])
        telescope2 = telescope.withSurface(key, surf2)
        assert telescope != telescope2
        trays2 = telescope.trace(rays.copy())
        rays_allclose(trays, trays2)
Esempio n. 21
0
def test_add_plane():
    rng = np.random.default_rng(5772156)
    for _ in range(100):
        # Adding a plane should have zero effect on sag or normal vector
        s1 = batoid.Sphere(rng.uniform(1, 3))
        s2 = batoid.Plane()
        sum = batoid.Sum([s1, s2])

        x = rng.normal(size=5000)
        y = rng.normal(size=5000)

        np.testing.assert_allclose(sum.sag(x, y),
                                   s1.sag(x, y),
                                   rtol=0,
                                   atol=1e-12)

        np.testing.assert_allclose(
            sum.normal(x, y),
            s1.normal(x, y),
            rtol=0,
            atol=1e-12,
        )
Esempio n. 22
0
def test_intersect():
    rng = np.random.default_rng(5772)
    size = 10_000
    for _ in range(100):
        s1 = batoid.Sphere(1. / rng.normal(0., 0.2))
        s2 = batoid.Paraboloid(rng.uniform(1, 3))
        sum = batoid.Sum([s1, s2])
        sumCoordSys = batoid.CoordSys(origin=[0, 0, -1])
        x = rng.uniform(-1, 1, size=size)
        y = rng.uniform(-1, 1, size=size)
        z = np.full_like(x, -10.0)
        # If we shoot rays straight up, then it's easy to predict the intersection
        vx = np.zeros_like(x)
        vy = np.zeros_like(x)
        vz = np.ones_like(x)
        rv = batoid.RayVector(x, y, z, vx, vy, vz)
        np.testing.assert_allclose(rv.z, -10.0)
        rv2 = batoid.intersect(sum, rv.copy(), sumCoordSys)
        assert rv2.coordSys == sumCoordSys

        rv2 = rv2.toCoordSys(batoid.CoordSys())
        np.testing.assert_allclose(rv2.x, x)
        np.testing.assert_allclose(rv2.y, y)
        np.testing.assert_allclose(rv2.z,
                                   sum.sag(x, y) - 1,
                                   rtol=0,
                                   atol=1e-12)

        # Check default intersect coordTransform
        rv2 = rv.copy().toCoordSys(sumCoordSys)
        batoid.intersect(sum, rv2)
        assert rv2.coordSys == sumCoordSys
        rv2 = rv2.toCoordSys(batoid.CoordSys())
        np.testing.assert_allclose(rv2.x, x)
        np.testing.assert_allclose(rv2.y, y)
        np.testing.assert_allclose(rv2.z,
                                   sum.sag(x, y) - 1,
                                   rtol=0,
                                   atol=1e-12)
Esempio n. 23
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()
Esempio n. 24
0
def parallel_trace_timing(nside=1024, nthread=None, minChunk=None):
    if nthread is not None:
        print("setting nthread to {}".format(nthread))
        batoid._batoid.setNThread(nthread)
    print("Using {} threads".format(batoid._batoid.getNThread()))

    if minChunk is not None:
        print("setting 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
    dirCos = batoid.utils.gnomicToDirCos(np.deg2rad(0.3), np.deg2rad(0.3))

    if args.lsst:
        fn = os.path.join(batoid.datadir, "LSST", "LSST_i.yaml")
        pm = 'LSST.M1'
    elif args.decam:
        fn = os.path.join(batoid.datadir, "DECam", "DECam.yaml")
        pm = 'BlancoDECam.PM'
    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'])

    rays = batoid.circularGrid(
        telescope.dist, 0.5 * telescope.pupilSize,
        0.5 * telescope.pupilObscuration * telescope.pupilSize, dirCos[0],
        dirCos[1], -dirCos[2], nside, nside, 750e-9, 1.0, telescope.inMedium)

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

    # 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
        rad = telescope.pupilSize / 2 * 1.1
        xs = np.linspace(-rad, rad, 100)
        ys = np.linspace(-rad, rad, 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])

    if args.immutable:
        print("Immutable trace")
        t0 = time.time()

        for _ in range(args.nrepeat):
            rays_in = batoid.RayVector(rays)
            rays_out, _ = telescope.trace(rays_in)

        t1 = time.time()
        print("{} rays per second".format(int(nrays * args.nrepeat /
                                              (t1 - t0))))
        print()
    else:
        print("Trace in place")
        t0 = time.time()

        for _ in range(args.nrepeat):
            rays_out = batoid.RayVector(rays)
            telescope.traceInPlace(rays_out)

        t1 = time.time()
        print("{} rays per second".format(int(nrays * args.nrepeat /
                                              (t1 - t0))))

    if args.plot:
        import matplotlib.pyplot as plt
        rays_out.trimVignettedInPlace()
        x = rays_out.x
        y = rays_out.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_[-5, 5])
        plt.ylim(np.std(y) * np.r_[-5, 5])
        plt.xlabel("x (microns)")
        plt.ylabel("y (microns)")
        plt.show()
Esempio n. 25
0
def parallel_trace_timing(args):
    print("Using nrad of {:_d}".format(args.nrad))

    if args.lsst:
        print("Tracing through LSST optics")
        telescope = batoid.Optic.fromYaml("LSST_r.yaml")
        pm = 'M1'
    elif args.decam:
        print("Tracing through DECam optics")
        telescope = batoid.Optic.fromYaml("DECam.yaml")
        pm = 'PM'
    else:
        print("Tracing through HSC optics")
        telescope = batoid.Optic.fromYaml("HSC.yaml")
        pm = 'PM'

    building = []
    for _ in range(args.nrepeat):
        t0 = time.time()
        rays = batoid.RayVector.asPolar(optic=telescope,
                                        wavelength=620e-9,
                                        theta_x=np.deg2rad(0.3),
                                        theta_y=np.deg2rad(0.3),
                                        inner=0.5 * telescope.pupilSize *
                                        telescope.pupilObscuration,
                                        nrad=args.nrad,
                                        naz=int(2 * np.pi * args.nrad))
        t1 = time.time()
        building.append(t1 - t0)
    building = np.array(building)

    nrays = len(rays)
    print("Tracing {:_d} rays.".format(nrays))
    print(f"Minimum CPU RAM: {2*nrays*74/1024**3:.2f} GB")
    print(f"Minimum GPU RAM: {nrays*74/1024**3:.2f} GB")
    print()
    print()
    if args.nrepeat > 1:
        print("Generating: {:_} +/- {:_} rays per second".format(
            int(np.mean(nrays / building)),
            int(np.std(nrays / building) / np.sqrt(args.nrepeat))))
    else:
        print("Generating: {:_} rays per second".format(
            int(nrays / building[0])))

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

    # Optionally perturb primary mirror using bicubic spline
    if args.perturbBC != 0:
        orig = telescope[pm].surface
        rad = telescope.pupilSize / 2 * 1.1
        xs = np.linspace(-rad, rad, 100)
        ys = np.linspace(-rad, rad, 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[pm].surface = batoid.Sum([orig, bc])

    copying = []
    tracing = []
    overall = []

    for _ in range(args.nrepeat):
        t1 = time.time()
        rays_out = rays.copy()
        t2 = time.time()
        telescope.trace(rays_out)
        rays_out.r  # force copy back to host if doing gpu
        rays_out.v
        rays_out.t
        rays_out.flux
        rays_out.vignetted
        rays_out.failed
        t3 = time.time()
        copying.append(t2 - t1)
        tracing.append(t3 - t2)
        overall.append(t3 - t1)
    copying = np.array(copying)
    tracing = np.array(tracing)
    overall = np.array(overall)

    if args.nrepeat > 1:
        print()
        print("copying: {:_} +/- {:_} rays per second".format(
            int(np.mean(nrays / copying)),
            int(np.std(nrays / copying) / np.sqrt(args.nrepeat))))
        print()
        print("tracing: {:_} +/- {:_} rays per second".format(
            int(np.mean(nrays / tracing)),
            int(np.std(nrays / tracing) / np.sqrt(args.nrepeat))))
        print()
        print("overall")
        print("-------")
        print("{:_} +/- {:_} rays per second".format(
            int(np.mean(nrays / overall)),
            int(np.std(nrays / overall) / np.sqrt(args.nrepeat))))
        print()
    else:
        print()
        print("copying: {:_} rays per second".format(int(nrays / copying)))
        print()
        print("tracing: {:_} rays per second".format(int(nrays / tracing)))
        print()
        print("overall")
        print("-------")
        print("{:_} rays per second".format(int(nrays / overall)))
        print()

    if args.plot or args.show:
        import matplotlib.pyplot as plt
        w = ~rays_out.vignetted
        x = rays_out.x[w]
        y = rays_out.y[w]
        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_[-5, 5])
        plt.ylim(np.std(y) * np.r_[-5, 5])
        plt.xlabel("x (microns)")
        plt.ylabel("y (microns)")
        plt.savefig("parallel_trace_timing.png")
        if args.show:
            plt.show()