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 )
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)
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, )
def test_ne(): objs = [ batoid.Paraboloid(1.0), batoid.Paraboloid(2.0), batoid.Plane() ] all_obj_diff(objs)
def test_properties(): rng = np.random.default_rng(5) for i in range(100): R = rng.normal(0.0, 0.3) # negative allowed para = batoid.Paraboloid(R) assert para.R == R do_pickle(para)
def test_reflect(): rng = np.random.default_rng(57721) size = 10_000 for i in range(100): R = 1. / rng.normal(0.0, 0.3) # negative allowed para = batoid.Paraboloid(R) 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) 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(para, rv.copy()) rvr2 = para.reflect(rv.copy()) rays_allclose(rvr, rvr2) # print(f"{np.sum(rvr.failed)/len(rvr)*100:.2f}% failed") normal = para.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_ne(): objs = [ batoid.Plane(), batoid.Plane(allowReverse=True), batoid.Paraboloid(2.0), ] all_obj_diff(objs)
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.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 = 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_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)
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)
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(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_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 )
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)
def test_properties(): import random random.seed(5) for i in range(100): R = random.gauss(0.7, 0.8) para = batoid.Paraboloid(R) assert para.R == R do_pickle(para)
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(): para = batoid.Paraboloid(1.0) rv = batoid.RayVector(0, 0, -10, 0, 0.99, np.sqrt(1 - 0.99**2)) # Too shallow rv2 = batoid.intersect(para, 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(para, rv.copy()) np.testing.assert_equal(rv2.failed, np.array([False]))
def test_intersect(): import random random.seed(577) for i in range(100): R = random.gauss(10.0, 0.1) para = batoid.Paraboloid(R) for j in range(10): 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, -1000), (0, 0, 1), 0) r = para.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], para.sag(x, y), rtol=0, atol=1e-9) # Check normal for R=0 paraboloid (a plane) para = batoid.Paraboloid(0.0) np.testing.assert_array_equal(para.normal(0.1, 0.1), [0,0,1])
def test_reflect_to_focus(): rng = np.random.default_rng(5772156) size = 10_000 for i in range(100): R = rng.normal(0, 3.0) para = batoid.Paraboloid(R) x = rng.normal(size=size) y = rng.normal(size=size) rv = batoid.RayVector(x, y, -1000, 0, 0, 1) para.reflect(rv) # Now, see if rays pass through paraboloid focus at (0, 0, R/2) # Solve 0 = x + vx (t - t0) for t, then propagate to that t t = rv.t[0] - rv.r[0, 0] / rv.v[0, 0] focus = rv.positionAtTime(t) np.testing.assert_allclose(focus[:, 0], 0, atol=1e-12) np.testing.assert_allclose(focus[:, 1], 0, atol=1e-12) np.testing.assert_allclose(focus[:, 2], R / 2, atol=1e-12)
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]
def test_paraboloid(): rng = np.random.default_rng(57721566) size = 1000 for i in range(100): R = 1/rng.normal(0.0, 0.3) conic = -1.0 quad = batoid.Quadric(R, conic) para = batoid.Paraboloid(R) x = rng.uniform(-0.7*R, 0.7*R, size=size) y = rng.uniform(-0.7*R, 0.7*R, size=size) np.testing.assert_allclose( quad.sag(x,y), para.sag(x, y), rtol=0, atol=1e-11 ) np.testing.assert_allclose( quad.normal(x,y), para.normal(x, y), rtol=0, atol=1e-11 )
def test_paraboloid_reflection_plane(): import random random.seed(577) para = batoid.Paraboloid(-0.1) 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), (vx, vy, 1), 0) rray = para.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, para.normal(rray.r[0], rray.r[1])), rray.v), 0.0, rtol=0, atol=1e-15)
def test_sag(): import random random.seed(57) for i in range(100): R = random.gauss(0.2, 0.3) para = batoid.Paraboloid(R) for j in range(10): x = random.gauss(0.0, 1.0) y = random.gauss(0.0, 1.0) result = para.sag(x, y) np.testing.assert_allclose(result, (x*x + y*y)/2/R) # 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)) np.testing.assert_allclose(para.sag(x, y), (x*x + y*y)/2/R) # Make sure non-unit stride arrays also work np.testing.assert_allclose(para.sag(x[::5,::2], y[::5,::2]), ((x*x + y*y)/2/R)[::5,::2])
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(0.05, 0.01) para = batoid.Paraboloid(R) r1s = para.intersect(r0s) r2s = batoid.RayVector([para.intersect(r0) for r0 in r0s]) assert r1s == r2s
def test_paraboloid_reflection_to_focus(): import random random.seed(57721) for i in range(100): R = random.gauss(0, 3.0) para = batoid.Paraboloid(R) for j in range(100): x = random.gauss(0, 1) y = random.gauss(0, 1) ray = batoid.Ray((x,y,-1000), (0,0,1), 0) rray = para.reflect(ray.copy()) # Now see if rray goes through (0,0,R/2) # Solve the x equation: 0 = rray.r[0] + rray.v[0]*(t-t0) for t: # t = t0 - p0[0]/vx t = rray.t - rray.r[0]/rray.v[0] focus = rray.positionAtTime(t) np.testing.assert_allclose(focus[0], 0, atol=1e-12) np.testing.assert_allclose(focus[1], 0, atol=1e-12) np.testing.assert_allclose(focus[2], R/2.0, atol=1e-12)
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 test_paraboloid_refraction_reversal(): import random random.seed(5772) wavelength = 500e-9 # arbitrary para = batoid.Paraboloid(-20.0) m1 = batoid.ConstMedium(1.43) m2 = batoid.ConstMedium(1.34) 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 = para.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 = para.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 = para.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], -10, rtol=0, atol=1e-10)
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)
def test_normal(): rng = np.random.default_rng(577) for i in range(100): R = rng.normal(0.0, 0.3) para = batoid.Paraboloid(R) for j in range(10): x = rng.normal() y = rng.normal() result = para.normal(x, y) normal = np.array([-x / R, -y / R, 1]) normal /= np.sqrt(np.sum(np.square(normal))) np.testing.assert_allclose(result, normal) # Check 0,0 np.testing.assert_equal(para.normal(0, 0), np.array([0, 0, 1])) # Check vectorization x = rng.normal(size=(10, 10)) y = rng.normal(size=(10, 10)) normal = np.dstack([-x / R, -y / R, np.ones_like(x)]) normal /= np.sqrt(np.sum(np.square(normal), axis=-1))[..., None] np.testing.assert_allclose(para.normal(x, y), normal) # Make sure non-unit stride arrays also work np.testing.assert_allclose(para.normal(x[::5, ::2], y[::5, ::2]), normal[::5, ::2])
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)