예제 #1
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)
예제 #2
0
def test_intersect():
    rng = np.random.default_rng(577)
    tanx = rng.uniform(-0.1, 0.1)
    tany = rng.uniform(-0.1, 0.1)
    size = 10_000
    tiltedCoordSys = batoid.CoordSys(origin=[0, 0, -1])
    tilted = batoid.Tilted(tanx, tany)
    x = rng.normal(0.0, 1.0, size=size)
    y = rng.normal(0.0, 1.0, size=size)
    z = np.full_like(x, -100.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, -100.0)
    rv2 = batoid.intersect(tilted, rv.copy(), tiltedCoordSys)
    assert rv2.coordSys == tiltedCoordSys
    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, tilted.sag(x, y) - 1, rtol=0, atol=1e-12)

    # Check default intersect coordTransform
    rv2 = rv.copy().toCoordSys(tiltedCoordSys)
    batoid.intersect(tilted, rv2)
    assert rv2.coordSys == tiltedCoordSys
    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, tilted.sag(x, y) - 1, rtol=0, atol=1e-12)
예제 #3
0
def test_intersect():
    rng = np.random.default_rng(5772)
    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)
        quadCoordSys = batoid.CoordSys(origin=[0, 0, -1])
        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)
        # 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, -100.0)
        rv2 = batoid.intersect(quad, rv.copy(), quadCoordSys)
        assert rv2.coordSys == quadCoordSys

        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, quad.sag(x, y)-1, rtol=0, atol=1e-9)

        # Check default intersect coordTransform
        rv2 = rv.copy().toCoordSys(quadCoordSys)
        batoid.intersect(quad, rv2)
        assert rv2.coordSys == quadCoordSys
        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, quad.sag(x, y)-1, rtol=0, atol=1e-9)
예제 #4
0
def test_ne():
    objs = [
        batoid.Ray((0, 0, 0), (0, 0, 0)),
        batoid.Ray((0, 0, 0), (0, 0, 0), coordSys=batoid.CoordSys((0, 0, 1))),
        batoid.Ray((0, 0, 1), (0, 0, 0)),
        batoid.Ray((0, 1, 0), (0, 0, 0)),
        batoid.Ray((0, 0, 0), (0, 0, 0), t=1),
        batoid.Ray((0, 0, 0), (0, 0, 0), wavelength=500e-9),
        batoid.Ray((0, 0, 0), (0, 0, 0), wavelength=500e-9, flux=1.2),
        batoid.Ray((0, 0, 0), (0, 0, 0), vignetted=True),
        batoid.Ray(failed=True), (0, 0, 0),
        batoid.RayVector([
            batoid.Ray((0, 0, 1), (0, 0, 0)),
            batoid.Ray((0, 0, 0), (0, 0, 0))
        ]),
        batoid.RayVector([
            batoid.Ray((0, 0, 1), (0, 0, 0),
                       coordSys=batoid.CoordSys((0, 0, 1))),
            batoid.Ray((0, 0, 0), (0, 0, 0),
                       coordSys=batoid.CoordSys((0, 0, 1)))
        ]),
        batoid.RayVector([
            batoid.Ray((0, 0, 0), (0, 0, 0)),
            batoid.Ray((0, 0, 1), (0, 0, 0))
        ]),
        batoid.RayVector([batoid.Ray((0, 0, 0), (0, 0, 0))])
    ]
    all_obj_diff(objs)
예제 #5
0
def test_intersect():
    rng = np.random.default_rng(577)
    size = 10_000
    planeCoordSys = batoid.CoordSys(origin=[0, 0, -1])
    plane = batoid.Plane()
    x = rng.normal(0.0, 1.0, size=size)
    y = rng.normal(0.0, 1.0, size=size)
    z = np.full_like(x, -100.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, -100.0)
    rv2 = batoid.intersect(plane, rv.copy(), planeCoordSys)
    assert rv2.coordSys == planeCoordSys
    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, -1, rtol=0, atol=1e-12)

    # Check default intersect coordTransform
    rv2 = rv.copy().toCoordSys(planeCoordSys)
    batoid.intersect(plane, rv2)
    assert rv2.coordSys == planeCoordSys
    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, -1, rtol=0, atol=1e-12)
예제 #6
0
def test_ne():
    objs = [
        batoid.CoordSys(),
        batoid.CoordTransform(batoid.CoordSys(), batoid.CoordSys()),
        batoid.CoordTransform(batoid.CoordSys(),
                              batoid.CoordSys(origin=(0, 0, 1)))
    ]
    all_obj_diff(objs)
예제 #7
0
def test_simple_transform():
    rng = np.random.default_rng(5)
    size = 10_000

    # Worked a few examples out manually
    # Example 1
    coordSys1 = batoid.CoordSys()
    coordSys2 = batoid.CoordSys().shiftGlobal([0, 0, 1])
    rv = randomRayVector(rng, size, coordSys1)
    transform = batoid.CoordTransform(coordSys1, coordSys2)
    rv2 = batoid.applyForwardTransform(transform, rv.copy())
    np.testing.assert_allclose(rv.x, rv2.x)
    np.testing.assert_allclose(rv.y, rv2.y)
    np.testing.assert_allclose(rv.z - 1, rv2.z)
    # Repeat using toCoordSys
    rv3 = rv.copy().toCoordSys(coordSys2)
    np.testing.assert_allclose(rv.x, rv3.x)
    np.testing.assert_allclose(rv.y, rv3.y)
    np.testing.assert_allclose(rv.z - 1, rv3.z)
    # Transform of numpy array
    x, y, z = transform.applyForwardArray(rv.x, rv.y, rv.z)
    np.testing.assert_allclose(rv2.x, x)
    np.testing.assert_allclose(rv2.y, y)
    np.testing.assert_allclose(rv2.z, z)

    # Example 2
    # First for a single specific point I worked out
    coordSys1 = batoid.CoordSys()
    coordSys2 = batoid.CoordSys(origin=[1, 1, 1], rot=batoid.RotY(np.pi / 2))
    x = y = z = np.array([2])
    vx = vy = vz = np.array([0])
    rv = batoid.RayVector(x, y, z, vx, vy, vz)
    transform = batoid.CoordTransform(coordSys1, coordSys2)
    rv2 = batoid.applyForwardTransform(transform, rv.copy())
    np.testing.assert_allclose(rv2.r, [[-1, 1, 1]])
    # Transform of numpy array
    x, y, z = transform.applyForwardArray(rv.x, rv.y, rv.z)
    np.testing.assert_allclose(rv2.x, x)
    np.testing.assert_allclose(rv2.y, y)
    np.testing.assert_allclose(rv2.z, z)

    # Here's the generalization
    # Also using alternate syntax for applyForward here.
    rv = randomRayVector(rng, size, coordSys1)
    rv2 = transform.applyForward(rv.copy())
    np.testing.assert_allclose(rv2.x, 1 - rv.z)
    np.testing.assert_allclose(rv2.y, rv.y - 1)
    np.testing.assert_allclose(rv2.z, rv.x - 1)
    rv3 = rv.copy().toCoordSys(coordSys2)
    np.testing.assert_allclose(rv3.x, 1 - rv.z)
    np.testing.assert_allclose(rv3.y, rv.y - 1)
    np.testing.assert_allclose(rv3.z, rv.x - 1)
    # Transform of numpy array
    x, y, z = transform.applyForwardArray(rv.x, rv.y, rv.z)
    np.testing.assert_allclose(rv2.x, x)
    np.testing.assert_allclose(rv2.y, y)
    np.testing.assert_allclose(rv2.z, z)
예제 #8
0
파일: psf.py 프로젝트: nregnault/batoid
def wavefront(optic, theta_x, theta_y, wavelength, nx=32, sphereRadius=None):
    """Compute wavefront.

    Parameters
    ----------
    optic : batoid.Optic
        Optic for which to compute wavefront.
    theta_x, theta_y : float
        Field of incoming rays (gnomic projection)
    wavelength : float
        Wavelength of incoming rays
    nx : int, optional
        Size of ray grid to generate to compute wavefront.  Default: 32
    sphereRadius : float, optional
        Radius of reference sphere in meters.  If None, then use optic.sphereRadius.

    Returns
    -------
    wavefront : batoid.Lattice
        A batoid.Lattice object containing the wavefront values in waves and
        the primitive lattice vectors of the entrance pupil grid in meters.
    """
    dirCos = gnomicToDirCos(theta_x, theta_y)
    rays = batoid.rayGrid(
        optic.dist, optic.pupilSize,
        dirCos[0], dirCos[1], -dirCos[2],
        nx, wavelength, 1.0, optic.inMedium
    )

    if sphereRadius is None:
        sphereRadius = optic.sphereRadius

    outCoordSys = batoid.CoordSys()
    optic.traceInPlace(rays, outCoordSys=outCoordSys)
    w = np.where(1-rays.vignetted)[0]
    point = np.mean(rays.r[w], axis=0)

    # We want to place the vertex of the reference sphere one radius length away from the
    # intersection point.  So transform our rays into that coordinate system.
    transform = batoid.CoordTransform(
            outCoordSys, batoid.CoordSys(point+np.array([0,0,sphereRadius])))
    transform.applyForwardInPlace(rays)

    sphere = batoid.Sphere(-sphereRadius)
    sphere.intersectInPlace(rays)

    w = np.where(1-rays.vignetted)[0]
    # Should potentially try to make the reference time w.r.t. the chief ray instead of the mean
    # of the good (unvignetted) rays.
    t0 = np.mean(rays.t[w])

    arr = np.ma.masked_array((t0-rays.t)/wavelength, mask=rays.vignetted).reshape(nx, nx)
    primitiveVectors = np.vstack([[optic.pupilSize/nx, 0], [0, optic.pupilSize/nx]])
    return batoid.Lattice(arr, primitiveVectors)
예제 #9
0
def test_ne():
    objs = [
        batoid.CoordSys(),
        batoid.CoordSys([0,0,1]),
        batoid.CoordSys([0,1,0]),
        batoid.CoordSys(batoid.RotX(0.1)),
        batoid.CoordTransform(batoid.CoordSys(), batoid.CoordSys()),
        batoid.CoordTransform(batoid.CoordSys(), batoid.CoordSys([0,0,1])),
        batoid.CoordTransform(batoid.CoordSys(), batoid.CoordSys(batoid.RotX(0.1)))
    ]
    all_obj_diff(objs)
예제 #10
0
def test_combinations():
    # Test some particular combinations of coord sys transformations

    # +90 around x, followed by shift to (1, 0, 0)
    # equivalent to shift first, and then rotation +90 about x
    # latter rotation can be either global or local, since origin is unaffected
    # (1, 0, 0) -> (1, 0, 0)
    # by convention for local rotation
    # and by coincidence (origin is on xaxis) for global rotation
    coordSys = batoid.CoordSys()
    coordSys1 = coordSys.rotateGlobal(batoid.RotX(np.pi / 2)).shiftGlobal(
        [1, 0, 0])
    coordSys2 = coordSys.shiftGlobal([1, 0,
                                      0]).rotateLocal(batoid.RotX(np.pi / 2))
    coordSys3 = coordSys.shiftGlobal([1, 0,
                                      0]).rotateGlobal(batoid.RotX(np.pi / 2))
    np.testing.assert_allclose(coordSys1.origin, coordSys2.origin)
    np.testing.assert_allclose(coordSys1.rot, coordSys2.rot)
    np.testing.assert_allclose(coordSys1.origin, coordSys3.origin)
    np.testing.assert_allclose(coordSys1.rot, coordSys3.rot)

    # +45 around x, followed by sqrt(2) in new y direction, which is the (0, 1, 1)
    # direction in global coords, followed by -45 about x.
    # Should be parallel to global coords, but origin at (0, 1, 1)
    coordSys1 = (batoid.CoordSys().rotateGlobal(batoid.RotX(
        np.pi / 4)).shiftLocal([0, np.sqrt(2),
                                0]).rotateLocal(batoid.RotX(-np.pi / 4)))
    coordSys2 = batoid.CoordSys().shiftLocal([0, 1, 1])
    np.testing.assert_allclose(coordSys1.origin,
                               coordSys2.origin,
                               rtol=0,
                               atol=1e-15)
    np.testing.assert_allclose(coordSys1.rot,
                               coordSys2.rot,
                               rtol=0,
                               atol=1e-15)

    # rotate +90 around point (1, 0, 0) with rot axis parallel to y axis.
    # moves origin from (0, 0, 0) to (1, 0, 1)
    coordSys = batoid.CoordSys()
    coordSys1 = coordSys.rotateGlobal(batoid.RotY(np.pi / 2), [1, 0, 0])
    coordSys2 = coordSys.rotateGlobal(batoid.RotY(np.pi / 2)).shiftGlobal(
        [1, 0, 1])
    # local coords of global (1, 0, 1) are (-1, 0, 1)
    coordSys3 = coordSys.rotateGlobal(batoid.RotY(np.pi / 2)).shiftLocal(
        [-1, 0, 1])
    np.testing.assert_allclose(coordSys1.origin, coordSys2.origin)
    np.testing.assert_allclose(coordSys1.rot, coordSys2.rot)
    np.testing.assert_allclose(coordSys1.origin, coordSys3.origin)
    np.testing.assert_allclose(coordSys1.rot, coordSys3.rot)
예제 #11
0
def test_intersect():
    rng = np.random.default_rng(5772)
    size = 10_000

    for _ in range(10):
        def f(x, y):
            a = rng.uniform(size=5)
            return (
                a[0]*x**2*y - a[1]*y**2*x + a[2]*3*x - a[3]
                + a[4]*np.sin(y)*np.cos(x)**2
            )

        xs = np.linspace(0, 1, 1000)
        ys = np.linspace(0, 1, 1000)

        zs = f(*np.meshgrid(xs, ys))
        bc = batoid.Bicubic(xs, ys, zs)

        bcCoordSys = batoid.CoordSys(origin=[0, 0, -1])
        x = rng.uniform(0.1, 0.9, size=size)
        y = rng.uniform(0.1, 0.9, 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(bc, rv.copy(), bcCoordSys)
        assert rv2.coordSys == bcCoordSys

        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, bc.sag(x, y)-1,
            rtol=0, atol=1e-12
        )

        # Check default intersect coordTransform
        rv2 = rv.copy().toCoordSys(bcCoordSys)
        batoid.intersect(bc, rv2)
        assert rv2.coordSys == bcCoordSys
        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, bc.sag(x, y)-1,
            rtol=0, atol=1e-12
        )
예제 #12
0
def test_shift():
    rng = np.random.default_rng(57)
    globalCoordSys = batoid.CoordSys()
    for i in range(30):
        x, y, z = rng.normal(0.1, 2.3, size=3)
        newCoordSys = globalCoordSys.shiftGlobal([x, y, z])
        do_pickle(newCoordSys)
        np.testing.assert_array_equal(newCoordSys.xhat, [1, 0, 0])
        np.testing.assert_array_equal(newCoordSys.yhat, [0, 1, 0])
        np.testing.assert_array_equal(newCoordSys.zhat, [0, 0, 1])
        np.testing.assert_array_equal(newCoordSys.origin, [x, y, z])
        np.testing.assert_array_equal(newCoordSys.rot, np.eye(3))

        for j in range(30):
            x2, y2, z2 = rng.normal(0.1, 2.3, size=3)
            newNewCoordSys = newCoordSys.shiftGlobal([x2, y2, z2])
            np.testing.assert_array_equal(newNewCoordSys.xhat, [1, 0, 0])
            np.testing.assert_array_equal(newNewCoordSys.yhat, [0, 1, 0])
            np.testing.assert_array_equal(newNewCoordSys.zhat, [0, 0, 1])
            np.testing.assert_array_equal(newNewCoordSys.origin,
                                          [x + x2, y + y2, z + z2])
            np.testing.assert_array_equal(newNewCoordSys.rot, np.eye(3))

            newNewCoordSys = newCoordSys.shiftLocal([x2, y2, z2])
            np.testing.assert_array_equal(newNewCoordSys.xhat, [1, 0, 0])
            np.testing.assert_array_equal(newNewCoordSys.yhat, [0, 1, 0])
            np.testing.assert_array_equal(newNewCoordSys.zhat, [0, 0, 1])
            np.testing.assert_array_equal(newNewCoordSys.origin,
                                          [x + x2, y + y2, z + z2])
            np.testing.assert_array_equal(newNewCoordSys.rot, np.eye(3))
예제 #13
0
def test_asphere_reflection_coordtransform():
    import random
    random.seed(5772156)
    asphere = batoid.Asphere(23.0, -0.97, [1e-5, 1e-6])
    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 = np.array([vx, vy, 1])
        v /= np.linalg.norm(v)
        ray = batoid.Ray([x, y, -0.1], v, 0)
        ray2 = ray.copy()

        cs = batoid.CoordSys(
            [random.uniform(-0.01, 0.01),
             random.uniform(-0.01, 0.01),
             random.uniform(-0.01, 0.01)],
            (batoid.RotX(random.uniform(-0.01, 0.01))
             .dot(batoid.RotY(random.uniform(-0.01, 0.01)))
             .dot(batoid.RotZ(random.uniform(-0.01, 0.01)))
            )
        )

        rray = asphere.reflect(ray, coordSys=cs)
        rray2 = asphere.reflect(ray2.toCoordSys(cs))
        assert ray_isclose(rray, rray2)
예제 #14
0
def parse_coordSys(config, coordSys=batoid.CoordSys()):
    """
    @param config  configuration dictionary
    @param coordSys  sys to which transformations in config are added
    """
    shift = [0.0, 0.0, 0.0]
    if any(x in config for x in ['x', 'y', 'z']):
        if 'shift' in config:
            raise ValueError("Cannot specify both shift and x/y/z")
        x = config.pop('x', 0.0)
        y = config.pop('y', 0.0)
        z = config.pop('z', 0.0)
        shift = [x, y, z]
    elif 'shift' in config:
        shift = config.pop('shift')
    if shift != [0.0, 0.0, 0.0]:
        coordSys = coordSys.shiftLocal(shift)
    # At most one (nonzero) rotation can be included and is applied after the shift.
    rotXYZ = np.array([config.pop('rot' + axis, 0.0) for axis in 'XYZ'])
    axes = np.where(rotXYZ != 0)[0]
    if len(axes) > 1:
        raise ValueError('Cannot specify rotation about more than one axis.')
    elif len(axes) == 1:
        axis, angle = axes[0], rotXYZ[axes[0]]
        rotator = (batoid.RotX, batoid.RotY, batoid.RotZ)[axis](angle)
        coordSys = coordSys.rotateLocal(rotator)
    return coordSys
예제 #15
0
def test_ne():
    objs = [
        batoid.Mirror(batoid.Plane()),
        batoid.Detector(batoid.Plane()),
        batoid.Baffle(batoid.Plane()),
        batoid.RefractiveInterface(batoid.Plane()),
        batoid.Mirror(batoid.Paraboloid(0.1)),
        batoid.Detector(batoid.Paraboloid(0.1)),
        batoid.Baffle(batoid.Paraboloid(0.1)),
        batoid.RefractiveInterface(batoid.Paraboloid(0.1)),
        batoid.Mirror(batoid.Plane(), obscuration=batoid.ObscCircle(0.1)),
        batoid.Mirror(batoid.Plane(), inMedium=batoid.ConstMedium(1.1)),
        batoid.Mirror(batoid.Plane(), outMedium=batoid.ConstMedium(1.1)),
        batoid.Mirror(batoid.Plane(), coordSys=batoid.CoordSys([0, 0, 1])),
        batoid.CompoundOptic(
            [batoid.Mirror(batoid.Plane()),
             batoid.Mirror(batoid.Plane())]),
        batoid.CompoundOptic(
            [batoid.Mirror(batoid.Plane()),
             batoid.Baffle(batoid.Plane())]),
        batoid.CompoundOptic([
            batoid.RefractiveInterface(batoid.Plane()),
            batoid.RefractiveInterface(batoid.Plane())
        ]),
        batoid.Lens([
            batoid.RefractiveInterface(batoid.Plane()),
            batoid.RefractiveInterface(batoid.Plane())
        ]),
    ]
    all_obj_diff(objs)
예제 #16
0
파일: psf.py 프로젝트: jmeyers314/5planes
def wavefront(optic,
              wavelength,
              theta_x=0,
              theta_y=0,
              nx=32,
              rays=None,
              saveRays=False,
              sphereRadius=None):
    if rays is None:
        xcos = np.sin(theta_x)
        ycos = np.sin(theta_y)
        zcos = -np.sqrt(1.0 - xcos**2 - ycos**2)

        rays = batoid.rayGrid(optic.dist, optic.pupilSize, xcos, ycos, zcos,
                              nx, wavelength, optic.inMedium)
    if saveRays:
        rays = batoid.RayVector(rays)
    if sphereRadius is None:
        sphereRadius = optic.sphereRadius

    outCoordSys = batoid.CoordSys()
    optic.traceInPlace(rays, outCoordSys=outCoordSys)
    goodRays = batoid._batoid.trimVignetted(rays)
    point = np.array(
        [np.mean(goodRays.x),
         np.mean(goodRays.y),
         np.mean(goodRays.z)])

    # We want to place the vertex of the reference sphere one radius length away from the
    # intersection point.  So transform our rays into that coordinate system.
    transform = batoid.CoordTransform(
        outCoordSys, batoid.CoordSys(point + np.array([0, 0, sphereRadius])))
    transform.applyForwardInPlace(rays)

    sphere = batoid.Sphere(-sphereRadius)
    sphere.intersectInPlace(rays)
    goodRays = batoid._batoid.trimVignetted(rays)
    # Should potentially try to make the reference time w.r.t. the chief ray instead of the mean
    # of the good (unvignetted) rays.
    t0 = np.mean(goodRays.t0)

    ts = rays.t0[:]
    isV = rays.isVignetted[:]
    ts -= t0
    ts /= wavelength
    wf = np.ma.masked_array(ts, mask=isV)
    return wf
예제 #17
0
def randomCoordSys():
    import random
    return batoid.CoordSys(
        randomVec3(),
        (batoid.RotX(random.uniform(0, 1))
         .dot(batoid.RotY(random.uniform(0, 1)))
         .dot(batoid.RotZ(random.uniform(0, 1))))
    )
예제 #18
0
def test_intersect():
    rng = np.random.default_rng(57721)
    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

        zernikeCoordSys = batoid.CoordSys(origin=[0, 0, -1])
        x = rng.uniform(-lim, lim, size=size)
        y = rng.uniform(-lim, lim, 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(zernike, rv.copy(), zernikeCoordSys)
        assert rv2.coordSys == zernikeCoordSys

        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, zernike.sag(x, y)-1,
            rtol=0, atol=1e-12
        )

        # Check default intersect coordTransform
        rv2 = rv.copy().toCoordSys(zernikeCoordSys)
        batoid.intersect(zernike, rv2)
        assert rv2.coordSys == zernikeCoordSys
        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, zernike.sag(x, y)-1,
            rtol=0, atol=1e-12
        )
예제 #19
0
def test_ne():
    objs = [
        batoid.SimpleCoating(0.0, 1.0),
        batoid.SimpleCoating(0.0, 0.1),
        batoid.SimpleCoating(0.1, 0.1),
        batoid.CoordSys()
    ]
    all_obj_diff(objs)
예제 #20
0
def test_HSC_trace():
    fn = os.path.join(batoid.datadir, "HSC", "HSC_old.yaml")
    config = yaml.load(open(fn))
    telescope = batoid.parse.parse_optic(config['opticalSystem'])

    # Zemax has a number of virtual surfaces that we don't trace in batoid.  Also, the HSC.yaml
    # above includes Baffle surfaces not in Zemax.  The following lists select out the surfaces in
    # common to both models.
    HSC_surfaces = [
        3, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 24, 25, 28, 29,
        31
    ]
    surface_names = [
        'PM', 'G1_entrance', 'G1_exit', 'G2_entrance', 'G2_exit',
        'ADC1_entrance', 'ADC1_exit', 'ADC2_entrance', 'ADC2_exit',
        'G3_entrance', 'G3_exit', 'G4_entrance', 'G4_exit', 'G5_entrance',
        'G5_exit', 'F_entrance', 'F_exit', 'W_entrance', 'W_exit', 'D'
    ]

    for fn in [
            "HSC_raytrace_1.txt", "HSC_raytrace_2.txt", "HSC_raytrace_3.txt"
    ]:
        filename = os.path.join(directory, "testdata", fn)
        with open(filename) as f:
            arr = np.loadtxt(f, skiprows=22, usecols=list(range(0, 12)))
        arr0 = arr[0]
        ray = batoid.Ray(arr0[1] / 1000,
                         arr0[2] / 1000,
                         16.0,
                         arr0[4],
                         arr0[5],
                         -arr0[6],
                         t=0,
                         wavelength=750e-9)
        tf = telescope.traceFull(ray)

        i = 0
        for surface in tf:
            if surface['name'] != surface_names[i]:
                continue

            s = surface['out']
            v = s.v / np.linalg.norm(s.v)

            transform = batoid.CoordTransform(surface['outCoordSys'],
                                              batoid.CoordSys())
            s = transform.applyForward(s)
            bt_isec = np.array([s.x, s.y, s.z - 16.0])
            zx_isec = arr[HSC_surfaces[i] - 1][1:4] / 1000
            np.testing.assert_allclose(bt_isec, zx_isec, rtol=0,
                                       atol=1e-9)  # nanometer agreement

            bt_angle = np.array([v[0], v[1], v[2]])
            zx_angle = arr[HSC_surfaces[i] - 1][4:7]
            # direction cosines agree to 1e-9
            np.testing.assert_allclose(bt_angle, zx_angle, rtol=0, atol=1e-9)

            i += 1
예제 #21
0
def test_HSC_trace():
    telescope = batoid.Optic.fromYaml("HSC_old.yaml")

    # Zemax has a number of virtual surfaces that we don't trace in batoid.
    # Also, the HSC.yaml above includes Baffle surfaces not in Zemax.  The
    # following lists select out the surfaces in common to both models.
    HSC_surfaces = [
        3, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 24, 25, 28, 29,
        31
    ]
    surface_names = [
        'PM', 'G1_entrance', 'G1_exit', 'G2_entrance', 'G2_exit',
        'ADC1_entrance', 'ADC1_exit', 'ADC2_entrance', 'ADC2_exit',
        'G3_entrance', 'G3_exit', 'G4_entrance', 'G4_exit', 'G5_entrance',
        'G5_exit', 'F_entrance', 'F_exit', 'W_entrance', 'W_exit', 'D'
    ]

    for fn in [
            "HSC_raytrace_1.txt", "HSC_raytrace_2.txt", "HSC_raytrace_3.txt"
    ]:
        filename = os.path.join(directory, "testdata", fn)
        with open(filename) as f:
            arr = np.loadtxt(f, skiprows=22, usecols=list(range(0, 12)))
        arr0 = arr[0]
        rv = batoid.RayVector(arr0[1] / 1000,
                              arr0[2] / 1000,
                              16.0,
                              arr0[4],
                              arr0[5],
                              -arr0[6],
                              t=0,
                              wavelength=750e-9)
        tf = telescope.traceFull(rv)

        i = 0
        for name in surface_names:
            surface = tf[name]
            srv = surface['out']

            srv.toCoordSys(batoid.CoordSys())
            bt_isec = np.array([srv.x, srv.y, srv.z - 16.0]).T[0]
            zx_isec = arr[HSC_surfaces[i] - 1][1:4] / 1000
            # nanometer agreement
            np.testing.assert_allclose(bt_isec, zx_isec, rtol=0, atol=1e-9)

            v = srv.v / np.linalg.norm(srv.v)
            bt_angle = v[0]
            zx_angle = arr[HSC_surfaces[i] - 1][4:7]
            # direction cosines agree to 1e-9
            np.testing.assert_allclose(bt_angle, zx_angle, rtol=0, atol=1e-9)

            i += 1
예제 #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)
예제 #23
0
def test_intersect():
    rng = np.random.default_rng(5772)
    size = 10_000
    for i in range(100):
        R = 1. / rng.normal(0.0, 0.3)
        sphereCoordSys = batoid.CoordSys(origin=[0, 0, -1])
        sphere = batoid.Sphere(R)
        x = rng.uniform(-0.3 * abs(R), 0.3 * abs(R), size=size)
        y = rng.uniform(-0.3 * abs(R), 0.3 * abs(R), size=size)
        z = np.full_like(x, -2 * abs(R))
        # 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, -2 * abs(R))
        rv2 = batoid.intersect(sphere, rv.copy(), sphereCoordSys)
        assert rv2.coordSys == sphereCoordSys

        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,
                                   sphere.sag(x, y) - 1,
                                   rtol=0,
                                   atol=1e-9)

        # Check default intersect coordTransform
        rv2 = rv.copy().toCoordSys(sphereCoordSys)
        batoid.intersect(sphere, rv2)
        assert rv2.coordSys == sphereCoordSys
        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,
                                   sphere.sag(x, y) - 1,
                                   rtol=0,
                                   atol=1e-9)
예제 #24
0
def test_properties():
    rng = np.random.default_rng(5)
    size = 10
    for i in range(100):
        x = rng.normal(size=size)
        y = rng.normal(size=size)
        z = rng.normal(size=size)
        vx = rng.normal(size=size)
        vy = rng.normal(size=size)
        vz = rng.normal(size=size)
        t = rng.normal(size=size)
        w = rng.normal(size=size)
        fx = rng.normal(size=size)
        vig = rng.choice([True, False], size=size)
        fa = rng.choice([True, False], size=size)
        cs = batoid.CoordSys(
            origin=rng.normal(size=3),
            rot=batoid.RotX(rng.normal()) @ batoid.RotY(rng.normal()))

        rv = batoid.RayVector(x, y, z, vx, vy, vz, t, w, fx, vig, fa, cs)

        np.testing.assert_array_equal(rv.x, x)
        np.testing.assert_array_equal(rv.y, y)
        np.testing.assert_array_equal(rv.z, z)
        np.testing.assert_array_equal(rv.r[:, 0], x)
        np.testing.assert_array_equal(rv.r[:, 1], y)
        np.testing.assert_array_equal(rv.r[:, 2], z)
        np.testing.assert_array_equal(rv.vx, vx)
        np.testing.assert_array_equal(rv.vy, vy)
        np.testing.assert_array_equal(rv.vz, vz)
        np.testing.assert_array_equal(rv.v[:, 0], vx)
        np.testing.assert_array_equal(rv.v[:, 1], vy)
        np.testing.assert_array_equal(rv.v[:, 2], vz)
        np.testing.assert_array_equal(rv.k[:, 0], rv.kx)
        np.testing.assert_array_equal(rv.k[:, 1], rv.ky)
        np.testing.assert_array_equal(rv.k[:, 2], rv.kz)
        np.testing.assert_array_equal(rv.t, t)
        np.testing.assert_array_equal(rv.wavelength, w)
        np.testing.assert_array_equal(rv.flux, fx)
        np.testing.assert_array_equal(rv.vignetted, vig)
        np.testing.assert_array_equal(rv.failed, fa)
        assert rv.coordSys == cs

        rv._syncToDevice()
        do_pickle(rv)
예제 #25
0
파일: parse.py 프로젝트: nregnault/batoid
def parse_coordSys(config, coordSys=batoid.CoordSys()):
    """
    @param config  configuration dictionary
    @param coordSys  sys to which transformations in config are added
    """
    if any(x in config for x in ['x', 'y', 'z']):
        if 'shift' in config:
            raise ValueError("Cannot specify both shift and x/y/z")
        x = config.pop('x', 0.0)
        y = config.pop('y', 0.0)
        z = config.pop('z', 0.0)
        shift = [x, y, z]
    elif 'shift' in config:
        shift = config.pop('shift')
    # Leaving rotation out for the moment...
    if shift != [0.0, 0.0, 0.0]:
        coordSys = coordSys.shiftLocal(shift)
    return coordSys
예제 #26
0
def test_ne():
    rng = np.random.default_rng(57)

    N1 = rng.integers(1, 5)
    N2 = rng.integers(1, 5)
    N3 = rng.integers(1, 5)
    arr = np.ones((N1, N2, N3))
    pv1 = rng.uniform(-1.0, 1.0, size=3)
    pv2 = rng.uniform(-1.0, 1.0, size=3)
    pv3 = rng.uniform(-1.0, 1.0, size=3)

    lattice1 = batoid.Lattice(arr, np.vstack([pv1, pv2, pv3]))
    lattice2 = batoid.Lattice(arr[..., 0], np.vstack([pv1, pv2, pv3])[:2, :2])
    lattice3 = batoid.Lattice(arr, 2 * np.vstack([pv1, pv2, pv3]))
    lattice4 = batoid.Lattice(2 * arr, np.vstack([pv1, pv2, pv3]))

    objs = [batoid.CoordSys(), lattice1, lattice2, lattice3, lattice4]
    all_obj_diff(objs)
예제 #27
0
def test_shift():
    import random
    random.seed(5)
    globalCoordSys = batoid.CoordSys()
    for i in range(30):
        x = random.gauss(0.1, 2.3)
        y = random.gauss(0.1, 2.3)
        z = random.gauss(0.1, 2.3)
        newCoordSys = globalCoordSys.shiftGlobal([x, y, z])
        do_pickle(newCoordSys)
        np.testing.assert_array_equal(newCoordSys.xhat, [1,0,0])
        np.testing.assert_array_equal(newCoordSys.yhat, [0,1,0])
        np.testing.assert_array_equal(newCoordSys.zhat, [0,0,1])
        np.testing.assert_array_equal(newCoordSys.origin, [x,y,z])
        np.testing.assert_array_equal(newCoordSys.rot, np.eye(3))

        coordTransform = batoid.CoordTransform(globalCoordSys, newCoordSys)
        do_pickle(coordTransform)

        for j in range(30):
            x2 = random.gauss(0.1, 2.3)
            y2 = random.gauss(0.1, 2.3)
            z2 = random.gauss(0.1, 2.3)
            newNewCoordSys = newCoordSys.shiftGlobal([x2, y2, z2])
            np.testing.assert_array_equal(newNewCoordSys.xhat, [1,0,0])
            np.testing.assert_array_equal(newNewCoordSys.yhat, [0,1,0])
            np.testing.assert_array_equal(newNewCoordSys.zhat, [0,0,1])
            np.testing.assert_array_equal(newNewCoordSys.origin, [x+x2, y+y2, z+z2])
            np.testing.assert_array_equal(newNewCoordSys.rot, np.eye(3))

            newNewCoordSys = newCoordSys.shiftLocal([x2, y2, z2])
            np.testing.assert_array_equal(newNewCoordSys.xhat, [1,0,0])
            np.testing.assert_array_equal(newNewCoordSys.yhat, [0,1,0])
            np.testing.assert_array_equal(newNewCoordSys.zhat, [0,0,1])
            np.testing.assert_array_equal(newNewCoordSys.origin, [x+x2, y+y2, z+z2])
            np.testing.assert_array_equal(newNewCoordSys.rot, np.eye(3))
예제 #28
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()
예제 #29
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}")
예제 #30
0
def randomCoordSys(rng):
    return batoid.CoordSys(
        rng.uniform(size=3), (batoid.RotX(rng.uniform()).dot(
            batoid.RotY(rng.uniform())).dot(batoid.RotZ(rng.uniform()))))