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) ncoefs = random.randint(0, 4) coefs = [random.gauss(0, 1e-10) for i in range(ncoefs)] asphere = batoid.Asphere(R, conic, coefs) 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 = asphere.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], asphere.sag(x, y), rtol=0, atol=1e-9) # Check normal for R=0 paraboloid (a plane) asphere = batoid.Asphere(0.0, 0.0, []) np.testing.assert_array_equal(asphere.normal(0.1, 0.1), [0, 0, 1]) # Check that normal parallelizes xs = np.random.normal(size=20) ys = np.random.normal(size=20) np.testing.assert_array_equal( asphere.normal(xs, ys), np.array([asphere.normal(x, y) for x, y in zip(xs, ys)])) # Test shape vectorization np.testing.assert_array_equal( asphere.normal(xs.reshape((10, 2)), ys.reshape((10, 2))), np.array([asphere.normal(x, y) for x, y in zip(xs, ys)]).reshape(10, 2, 3)) np.testing.assert_array_equal( asphere.normal(xs.reshape((2, 5, 2)), ys.reshape((2, 5, 2))), np.array([asphere.normal(x, y) for x, y in zip(xs, ys)]).reshape(2, 5, 2, 3)) # Also test non-unit strides on last index np.testing.assert_array_equal( asphere.normal(xs.reshape((10, 2))[::2], ys.reshape((10, 2))[::2]), np.array([asphere.normal(x, y) for x, y in zip(xs, ys)]).reshape(10, 2, 3)[::2])
def test_asphere_approximation(): rng = np.random.default_rng(5772156) xs = np.linspace(-1, 1, 1000) ys = np.linspace(-1, 1, 1000) xtest = np.random.uniform(-0.9, 0.9, size=1000) ytest = np.random.uniform(-0.9, 0.9, size=1000) for i in range(10): R = rng.normal(20.0, 1.0) conic = rng.uniform(-2.0, 1.0) ncoef = rng.choice(4) coefs = [rng.normal(0, 1e-10) for i in range(ncoef)] asphere = batoid.Asphere(R, conic, coefs) zs = asphere.sag(*np.meshgrid(xs, ys)) bc = batoid.Bicubic(xs, ys, zs) np.testing.assert_allclose( asphere.sag(xtest, ytest), bc.sag(xtest, ytest), atol=1e-12, rtol=0.0 ) np.testing.assert_allclose( asphere.normal(xtest, ytest), bc.normal(xtest, ytest), atol=1e-9, rtol=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)
def test_asphere_reflection_reversal(): 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) rray = asphere.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 = asphere.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-9) np.testing.assert_allclose(rray.r[1], riray.r[1], rtol=0, atol=1e-9) np.testing.assert_allclose(rray.r[2], riray.r[2], rtol=0, atol=1e-9) # Reflect and propagate back to t=0. cray = asphere.reflect(return_ray.copy()) cray = cray.positionAtTime(0) np.testing.assert_allclose(cray[0], x, rtol=0, atol=1e-9) np.testing.assert_allclose(cray[1], y, rtol=0, atol=1e-9) np.testing.assert_allclose(cray[2], -0.1, rtol=0, atol=1e-9)
def test_approximate_asphere(): np.random.seed(57721) xs = np.linspace(-1, 1, 1000) ys = np.linspace(-1, 1, 1000) xtest = np.random.uniform(-0.9, 0.9, size=1000) ytest = np.random.uniform(-0.9, 0.9, size=1000) for i in range(50): R = np.random.normal(20.0, 1.0) conic = np.random.uniform(-2.0, 1.0) ncoef = np.random.randint(0, 4) coefs = [np.random.normal(0, 1e-10) for i in range(ncoef)] asphere = batoid.Asphere(R, conic, coefs) zs = asphere.sag(*np.meshgrid(xs, ys)) bc = batoid.Bicubic(xs, ys, zs) np.testing.assert_allclose(asphere.sag(xtest, ytest), bc.sag(xtest, ytest), atol=1e-9, rtol=0.0) np.testing.assert_allclose(asphere.normal(xtest, ytest), bc.normal(xtest, ytest), atol=1e-8, rtol=0)
def test_rSplit(): rng = np.random.default_rng(5) for _ in range(100): R = rng.normal(0.7, 0.8) conic = rng.uniform(-2.0, 1.0) ncoef = rng.integers(0, 5) coefs = [rng.normal(0, 1e-10) for i in range(ncoef)] asphere = batoid.Asphere(R, conic, coefs) theta_x = rng.normal(0.0, 1e-8) theta_y = rng.normal(0.0, 1e-8) rays = batoid.RayVector.asPolar( backDist=10.0, medium=batoid.Air(), wavelength=500e-9, outer=0.25*R, theta_x=theta_x, theta_y=theta_y, nrad=10, naz=10 ) coating = batoid.SimpleCoating(0.9, 0.1) reflectedRays = asphere.reflect(rays.copy(), coating=coating) m1 = batoid.Air() m2 = batoid.ConstMedium(1.1) refractedRays = asphere.refract(rays.copy(), m1, m2, coating=coating) refractedRays2, reflectedRays2 = asphere.rSplit(rays, m1, m2, coating) rays_allclose(reflectedRays, reflectedRays2) rays_allclose(refractedRays, refractedRays2)
def test_sag(): rng = np.random.default_rng(57) for i in range(100): zmax = np.inf while zmax > 3.0: R = 0.0 while abs(R) < 15.0: # Don't allow too small radius of curvature R = 1. / rng.normal(0.0, 0.3) # negative allowed conic = rng.uniform(-2.0, 1.0) ncoef = rng.choice(5) coefs = [rng.normal(0, 1e-8) for i in range(ncoef)] asphere = batoid.Asphere(R, conic, coefs) lim = min(0.7 * abs(R) / np.sqrt(1 + conic) if conic > -1 else 5, 5) zmax = abs(asphere.sag(lim, lim)) for j in range(100): lim = 0.7 * abs(R) / np.sqrt(1 + conic) if conic > -1 else 1 x = rng.uniform(-lim, lim) y = rng.uniform(-lim, lim) result = asphere.sag(x, y) np.testing.assert_allclose(result, asphere_sag(R, conic, coefs)(x, y)) # Check that it returned a scalar float and not an array assert isinstance(result, float) # Check vectorization x = rng.uniform(-lim, lim, size=(10, 10)) y = rng.uniform(-lim, lim, size=(10, 10)) np.testing.assert_allclose(asphere.sag(x, y), asphere_sag(R, conic, coefs)(x, y)) # Make sure non-unit stride arrays also work np.testing.assert_allclose( asphere.sag(x[::5, ::2], y[::5, ::2]), asphere_sag(R, conic, coefs)(x, y)[::5, ::2])
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_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_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_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(): asphere = batoid.Asphere(1.0, 0.0, []) rv = batoid.RayVector(0, 10, 0, 0, 0, -1) # Too far to the side rv2 = batoid.intersect(asphere, 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(asphere, rv.copy()) np.testing.assert_equal(rv2.failed, np.array([False]))
def test_properties(): import random random.seed(5) for i in range(100): R = random.gauss(0.7, 0.8) conic = random.uniform(-2.0, 1.0) ncoef = random.randint(0, 4) coefs = [random.gauss(0, 1e-10) for i in range(ncoef)] asphere = batoid.Asphere(R, conic, coefs) assert asphere.R == R assert asphere.conic == conic assert asphere.coefs == coefs do_pickle(asphere)
def test_quad_plus_poly(): import random random.seed(5772) 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) quad = batoid.Quadric(R, conic) poly = py_poly(coefs) for j in range(100): x = random.gauss(0.0, 1.0) y = random.gauss(0.0, 1.0) np.testing.assert_allclose(asphere.sag(x, y), quad.sag(x, y)+poly(x, y))
def test_ne(): objs = [ batoid.Asphere(10.0, 1.0, []), batoid.Asphere(10.0, 1.0, [0]), batoid.Asphere(10.0, 1.0, [0,1]), batoid.Asphere(10.0, 1.0, [1,0]), batoid.Asphere(10.0, 1.1, []), batoid.Asphere(10.1, 1.0, []), batoid.Quadric(10.0, 1.0) ] all_obj_diff(objs)
def test_asphere_reflection_plane(): import random random.seed(577215) asphere = batoid.Asphere(25.0, -0.97, [1e-3, 1e-5]) 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), (vx, vy, 1), 0) rray = asphere.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, asphere.normal(rray.r[0], rray.r[1])), rray.v), 0.0, rtol=0, atol=1e-15)
def test_rSplit(): for i in range(100): R = np.random.normal(0.7, 0.8) conic = np.random.uniform(-2.0, 1.0) ncoef = np.random.randint(0, 4) coefs = [np.random.normal(0, 1e-10) for i in range(ncoef)] asphere = batoid.Asphere(R, conic, coefs) rays = batoid.rayGrid(10, 2*R, 0.0, 0.0, -1.0, 16, 500e-9, 1.0, batoid.Air()) coating = batoid.SimpleCoating(0.9, 0.1) reflectedRays = asphere.reflect(rays, coating) m1 = batoid.Air() m2 = batoid.ConstMedium(1.1) refractedRays = asphere.refract(rays, m1, m2, coating) reflectedRays2, refractedRays2 = asphere.rSplit(rays, m1, m2, coating) assert reflectedRays == reflectedRays2 assert refractedRays == refractedRays2
def test_refract(): rng = np.random.default_rng(577215) size = 10_000 for i in range(100): zmax = np.inf while zmax > 3.0: R = 0.0 while abs(R) < 15.0: # Don't allow too small radius of curvature R = 1. / rng.normal(0.0, 0.3) # negative allowed conic = rng.uniform(-2.0, 1.0) ncoef = rng.choice(5) coefs = [rng.normal(0, 1e-8) for i in range(ncoef)] asphere = batoid.Asphere(R, conic, coefs) lim = min(0.7 * abs(R) / np.sqrt(1 + conic) if conic > -1 else 5, 5) zmax = abs(asphere.sag(lim, lim)) m0 = batoid.ConstMedium(rng.normal(1.2, 0.01)) m1 = batoid.ConstMedium(rng.normal(1.3, 0.01)) x = rng.uniform(-lim, lim, size=size) y = rng.uniform(-lim, lim, size=size) z = np.full_like(x, -10.0) vx = rng.uniform(-1e-5, 1e-5, size=size) vy = rng.uniform(-1e-5, 1e-5, size=size) vz = np.sqrt(1 - vx * vx - vy * vy) / m0.n rv = batoid.RayVector(x, y, z, vx, vy, vz, t=0) rvr = batoid.refract(asphere, rv.copy(), m0, m1) rvr2 = asphere.refract(rv.copy(), m0, m1) rays_allclose(rvr, rvr2) # print(f"{np.sum(rvr.failed)/len(rvr)*100:.2f}% failed") normal = asphere.normal(rvr.x, rvr.y) # Test Snell's law s0 = np.sum(np.cross(normal, rv.v * m0.n)[~rvr.failed], axis=-1) s1 = np.sum(np.cross(normal, rvr.v * m1.n)[~rvr.failed], axis=-1) np.testing.assert_allclose(m0.n * s0, m1.n * s1, rtol=0, atol=1e-9) # Test that rv.v, rvr.v and normal are all in the same plane np.testing.assert_allclose(np.einsum("ad,ad->a", np.cross(normal, rv.v), rv.v)[~rvr.failed], 0.0, rtol=0, atol=1e-12)
def test_properties(): rng = np.random.default_rng(5) for i in range(100): zmax = np.inf while zmax > 3.0: R = 0.0 while abs(R) < 15.0: # Don't allow too small radius of curvature R = 1. / rng.normal(0.0, 0.3) # negative allowed conic = rng.uniform(-2.0, 1.0) ncoef = rng.choice(5) coefs = [rng.normal(0, 1e-8) for i in range(ncoef)] asphere = batoid.Asphere(R, conic, coefs) lim = min(0.7 * abs(R) / np.sqrt(1 + conic) if conic > -1 else 5, 5) zmax = abs(asphere.sag(lim, lim)) assert asphere.R == R assert asphere.conic == conic assert np.array_equal(asphere.coefs, coefs) do_pickle(asphere)
def test_reflect(): rng = np.random.default_rng(57721) size = 10_000 for i in range(100): zmax = np.inf while zmax > 3.0: R = 0.0 while abs(R) < 15.0: # Don't allow too small radius of curvature R = 1. / rng.normal(0.0, 0.3) # negative allowed conic = rng.uniform(-2.0, 1.0) ncoef = rng.choice(5) coefs = [rng.normal(0, 1e-8) for i in range(ncoef)] asphere = batoid.Asphere(R, conic, coefs) lim = min(0.7 * abs(R) / np.sqrt(1 + conic) if conic > -1 else 5, 5) zmax = abs(asphere.sag(lim, lim)) x = rng.uniform(-lim, lim, size=size) y = rng.uniform(-lim, lim, size=size) z = np.full_like(x, -10.0) vx = rng.uniform(-1e-5, 1e-5, size=size) vy = rng.uniform(-1e-5, 1e-5, size=size) vz = np.full_like(x, 1) rv = batoid.RayVector(x, y, z, vx, vy, vz) rvr = batoid.reflect(asphere, rv.copy()) rvr2 = asphere.reflect(rv.copy()) rays_allclose(rvr, rvr2) # print(f"{np.sum(rvr.failed)/len(rvr)*100:.2f}% failed") normal = asphere.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)
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_sag(): import random random.seed(57) 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) for j in range(100): x = random.gauss(0.0, 1.0) y = random.gauss(0.0, 1.0) result = asphere.sag(x, y) np.testing.assert_allclose(result, py_asphere(R, conic, coefs)(x, y)) # Check that it returned a scalar float and not an array assert isinstance(result, float) # Check vectorization x = np.random.normal(0.0, 1.0, size=(10, 10)) y = np.random.normal(0.0, 1.0, size=(10, 10)) # Make sure non-unit stride arrays also work np.testing.assert_allclose(asphere.sag(x[::5, ::2], y[::5, ::2]), py_asphere(R, conic, coefs)(x, y)[::5, ::2])
def test_intersect(): rng = np.random.default_rng(5772) size = 10_000 for i in range(100): zmax = np.inf while zmax > 3.0: R = 0.0 while abs(R) < 15.0: # Don't allow too small radius of curvature R = 1. / rng.normal(0.0, 0.3) # negative allowed conic = rng.uniform(-2.0, 1.0) ncoef = rng.choice(5) coefs = [rng.normal(0, 1e-8) for i in range(ncoef)] asphere = batoid.Asphere(R, conic, coefs) lim = min(0.7 * abs(R) / np.sqrt(1 + conic) if conic > -1 else 5, 5) zmax = abs(asphere.sag(lim, lim)) asphereCoordSys = 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(asphere, rv.copy(), asphereCoordSys) assert rv2.coordSys == asphereCoordSys 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, asphere.sag(x, y) - 1, rtol=0, atol=1e-12) # Straight down works too. rv2 = rv.copy() rv2.vz[:] *= -1 rv2 = batoid.intersect(asphere, rv.copy(), asphereCoordSys) assert rv2.coordSys == asphereCoordSys 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, asphere.sag(x, y) - 1, rtol=0, atol=1e-12) # Check default intersect coordTransform rv2 = rv.copy().toCoordSys(asphereCoordSys) batoid.intersect(asphere, rv2) assert rv2.coordSys == asphereCoordSys 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, asphere.sag(x, y) - 1, rtol=0, atol=1e-12)