def test_properties(): import random random.seed(57) for i in range(100): x = random.gauss(0.1, 2.3) y = random.gauss(2.1, 4.3) z = random.gauss(-0.13, 1.3) vx = random.gauss(3.1, 6.3) vy = random.gauss(5.1, 24.3) vz = random.gauss(-1.13, 31.3) t = random.gauss(0.1, 1.1) w = random.gauss(1000.0, 10.0) f = random.gauss(1000.0, 10.0) v = random.choice([True, False]) ray1 = batoid.Ray(x, y, z, vx, vy, vz, t, w, f, v) ray2 = batoid.Ray([x, y, z], [vx, vy, vz], t, w, f, v) for ray in [ray1, ray2]: assert ray.x == x assert ray.y == y assert ray.z == z assert ray.vx == vx assert ray.vy == vy assert ray.vz == vz assert ray.t == t assert ray.wavelength == w assert ray.vignetted == v assert ray1 == ray2
def test_plane_refraction_reversal(): import random random.seed(57) wavelength = 500e-9 # arbitrary plane = batoid.Plane() m1 = batoid.ConstMedium(1.5) 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) ray = batoid.Ray([x, y, -10], normalized(np.array([vx, vy, 1]))/m1.getN(wavelength), 0) rray = plane.refract(ray.copy(), m1, m2) np.testing.assert_allclose(np.linalg.norm(rray.v), 1./m2.getN(wavelength), rtol=1e-14) # 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 = plane.intersect(return_ray.copy()) 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 = plane.refract(return_ray.copy(), m2, m1) np.testing.assert_allclose(np.linalg.norm(cray.v), 1./m1.getN(wavelength), rtol=1e-14) 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], -10, rtol=0, atol=1e-10)
def test_positionAtTime(): import random random.seed(5) for i in range(100): x = random.gauss(0.1, 2.3) y = random.gauss(2.1, 4.3) z = random.gauss(-0.13, 1.3) vx = random.gauss(3.1, 6.3) vy = random.gauss(5.1, 24.3) vz = random.gauss(-1.13, 31.3) t0 = random.gauss(0.1, 1.1) t = random.gauss(5.5, 1.3) # Test both ways of constructing a Ray ray1 = batoid.Ray(x, y, z, vx, vy, vz, t0) ray2 = batoid.Ray([x, y, z], [vx, vy, vz], t0) ray3 = batoid.Ray((x, y, z), (vx, vy, vz), t0) ray4 = batoid.Ray(np.array([x, y, z]), np.array([vx, vy, vz]), t0) for ray in [ray1, ray2, ray3, ray4]: np.testing.assert_allclose( ray.positionAtTime(t)[0], x + vx * (t - t0)) np.testing.assert_allclose( ray.positionAtTime(t)[1], y + vy * (t - t0)) np.testing.assert_allclose( ray.positionAtTime(t)[2], z + vz * (t - t0)) assert ray1 == ray2 == ray3 == ray4 do_pickle(ray1)
def test_paraboloid_reflection_reversal(): import random random.seed(5772) para = batoid.Paraboloid(-5.0) 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, -10], v, 0) rray = para.reflect(ray.copy()) # Invert the reflected 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 = para.intersect(return_ray.copy()) # 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) # Reflect and propagate back to t=0. cray = para.reflect(return_ray.copy()) cray = cray.positionAtTime(0) np.testing.assert_allclose(cray[0], x, rtol=0, atol=1e-10) np.testing.assert_allclose(cray[1], y, rtol=0, atol=1e-10) np.testing.assert_allclose(cray[2], -10, rtol=0, atol=1e-10)
def test_intersect(): np.random.seed(5772) def f(x, y): return x**2*y - y**2*x + 3*x - 2 + 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) for _ in range(1000): # If we shoot rays straight up, then it's easy to predict the # intersection points. x = np.random.uniform(0.1, 0.9) y = np.random.uniform(0.1, 0.9) r0 = batoid.Ray(x, y, -10, 0, 0, 1, 0) r = bc.intersect(r0) np.testing.assert_allclose(r.r[0], x) np.testing.assert_allclose(r.r[1], y) np.testing.assert_allclose(r.r[2], bc.sag(x, y), rtol=0, atol=1e-9) # intersect should fail, but gracefully, outside of grid domain r0 = batoid.Ray(-1, -1, -10, 0, 0, 1, 0) assert bc.intersect(r0).failed
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
def test_fail(): plane = batoid.Plane() ray = batoid.Ray([0, 0, -1], [0, 0, -1]) ray = plane.intersect(ray) assert ray.failed ray = batoid.Ray([0, 0, -1], [0, 0, -1]) plane.intersectInPlace(ray) assert ray.failed
def test_fail(): zernike = batoid.Zernike([0,0,0,0,1]) ray = batoid.Ray([0,0,zernike.sag(0,0)-1], [0,0,-1]) ray = zernike.intersect(ray) assert ray.failed ray = batoid.Ray([0,0,zernike.sag(0,0)-1], [0,0,-1]) zernike.intersect(ray) assert ray.failed
def test_fail(): sphere = batoid.Sphere(1.0) ray = batoid.Ray([0,0,-1], [0,0,-1]) ray = sphere.intersect(ray) assert ray.failed ray = batoid.Ray([0,0,-1], [0,0,-1]) sphere.intersect(ray) assert ray.failed
def test_fail(): asphere = batoid.Asphere(1.0, 1.0, [1.0, 1.0]) ray = batoid.Ray([0,0,-1], [0,0,-1]) ray = asphere.intersect(ray) assert ray.failed ray = batoid.Ray([0,0,-1], [0,0,-1]) asphere.intersect(ray) assert ray.failed
def test_fail(): para = batoid.Paraboloid(1.0) ray = batoid.Ray([0,0,-1], [0,0,-1]) ray = para.intersect(ray) assert ray.failed ray = batoid.Ray([0,0,-1], [0,0,-1]) para.intersectInPlace(ray) assert ray.failed
def test_fail(): quad = batoid.Quadric(1.0, 1.0) ray = batoid.Ray([0, 0, -1], [0, 0, -1]) ray = quad.intersect(ray) assert ray.failed ray = batoid.Ray([0, 0, -1], [0, 0, -1]) quad.intersectInPlace(ray) assert ray.failed
def test_intersect(): import random random.seed(577) for i in range(100): R = random.gauss(25.0, 0.2) conic = random.uniform(-2.0, 1.0) quad = batoid.Quadric(R, conic) for j in range(100): x = random.gauss(0.0, 1.0) y = random.gauss(0.0, 1.0) # If we shoot rays straight up, then it's easy to predict the # intersection points. r0 = batoid.Ray((x, y, -10), (0, 0, 1), 0) r = quad.intersect(r0) np.testing.assert_allclose(r.r[0], x) np.testing.assert_allclose(r.r[1], y) np.testing.assert_allclose(r.r[2], quad.sag(x, y), rtol=0, atol=1e-9) # Check normal for R=0 paraboloid (a plane) quad = batoid.Quadric(0.0, 0.0) np.testing.assert_array_equal(quad.normal(0.1, 0.1), [0, 0, 1])
def test_plane_reflection_plane(): import random random.seed(5) plane = batoid.Plane() 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, -10], v, 0) rray = plane.reflect(ray.copy()) # 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. np.testing.assert_allclose( np.dot(np.cross(ray.v, plane.normal(rray.r[0], rray.r[1])), rray.v), 0.0, rtol=0, atol=1e-15) # Actually, reflection off a plane is pretty straigtforward to test # directly. np.testing.assert_allclose(ray.v[0], rray.v[0]) np.testing.assert_allclose(ray.v[1], rray.v[1]) np.testing.assert_allclose(ray.v[2], -rray.v[2])
def test_intersect_vectorized(): np.random.seed(57721) jmaxmax = 50 r0s = [ batoid.Ray([ np.random.normal(0.0, 0.1), np.random.normal(0.0, 0.1), np.random.normal(10.0, 0.1) ], [ np.random.normal(0.0, 0.1), np.random.normal(0.0, 0.1), np.random.normal(-1.0, 0.1) ], np.random.normal(0.0, 0.1)) for i in range(100) ] r0s = batoid.RayVector(r0s) for i in range(100): jmax = np.random.randint(1, jmaxmax) coef = np.random.normal(size=jmax + 1) * 1e-3 R_outer = np.random.uniform(0.5, 5.0) R_inner = np.random.uniform(0.0, 0.8 * R_outer) zernike = batoid.Zernike(coef, R_outer=R_outer, R_inner=R_inner) r1s = zernike.intersect(r0s) r2s = batoid.RayVector([zernike.intersect(r0) for r0 in r0s]) assert r1s == r2s
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)
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) # 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) # propagate all the way to t=0 final_rays = final_rays.propagatedToTime(0.0) final_rays.toCoordSysInPlace(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)
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.copy(), m1, m2) np.testing.assert_allclose(np.linalg.norm(rray.v), 1./m2.getN(wavelength), rtol=1e-14) # 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)
def test_fail(): surface = batoid.Sphere(1.0) ray = batoid.Ray([0, 10, -1], [0, 0, 1]) ray = surface.intersect(ray) assert ray.failed do_pickle(ray)
def test_plane_refraction_plane(): import random random.seed(5) wavelength = 500e-9 # arbitrary plane = batoid.Plane() m1 = batoid.ConstMedium(1.1) m2 = batoid.ConstMedium(1.3) 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, -10], v/m1.getN(wavelength), 0) rray = plane.refract(ray.copy(), m1, m2) np.testing.assert_allclose(np.linalg.norm(rray.v), 1./m2.getN(wavelength), rtol=1e-14) # 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. normal = plane.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)
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)
def test_intersect_vectorized(): import random random.seed(5772) r0s = [ batoid.Ray([ random.gauss(0.0, 0.1), random.gauss(0.0, 0.1), random.gauss(10.0, 0.1) ], [ random.gauss(0.0, 0.1), random.gauss(0.0, 0.1), random.gauss(-1.0, 0.1) ], random.gauss(0.0, 0.1)) for i in range(1000) ] r0s = batoid.RayVector(r0s) for i in range(100): R = random.gauss(25.0, 0.2) conic = random.uniform(-2.0, 1.0) ncoefs = random.randint(0, 4) coefs = [random.gauss(0, 1e-10) for i in range(ncoefs)] asphere = batoid.Asphere(R, conic, coefs) r1s = asphere.intersect(r0s) r2s = batoid.RayVector([asphere.intersect(r0) for r0 in r0s]) np.testing.assert_allclose(asphere.sag(r1s.x, r1s.y), r1s.z, rtol=0, atol=1e-12) assert r1s == r2s
def test_table_medium_refraction(): import random random.seed(57721566) filename = os.path.join(batoid.datadir, "media", "silica_dispersion.txt") wave, n = np.genfromtxt(filename).T table = batoid.Table(wave, n, batoid.Table.Interpolant.linear) silica = batoid.TableMedium(table) air = batoid.ConstMedium(1.000277) asphere = batoid.Asphere(25.0, -0.97, [1e-3, 1e-5]) for i in range(10000): x = random.gauss(0, 1) y = random.gauss(0, 1) vx = random.gauss(0, 1e-1) vy = random.gauss(0, 1e-1) wavelength = random.uniform(0.3, 1.2) ray = batoid.Ray(x, y, -0.1, vx, vy, 1, 0, wavelength) cm1 = batoid.ConstMedium(silica.getN(wavelength)) cm2 = batoid.ConstMedium(air.getN(wavelength)) rray1 = asphere.refract(ray, silica, air) rray2 = asphere.refract(ray, cm1, cm2) assert rray1 == rray2
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)
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
def randomRay(): import random return batoid.Ray( randomVec3(), randomVec3(), random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1), )
def test_fail(): plane = batoid.Plane() assert plane.allowReverse == False ray = batoid.Ray([0, 0, -1], [0, 0, -1]) ray = plane.intersect(ray) assert ray.failed ray = batoid.Ray([0, 0, -1], [0, 0, -1]) plane.intersectInPlace(ray) assert ray.failed # These should succeed though if allowReverse is True plane = batoid.Plane(allowReverse=True) assert plane.allowReverse == True ray = batoid.Ray([0, 0, -1], [0, 0, -1]) ray = plane.intersect(ray) assert not ray.failed ray = batoid.Ray([0, 0, -1], [0, 0, -1]) plane.intersectInPlace(ray) assert not ray.failed
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)
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)
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] 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 name in surface_names: surface = tf[name] s = surface['out'] v = s.v / np.linalg.norm(s.v) s.toCoordSysInPlace(batoid.CoordSys()) 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