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)
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_rotation(): try: import galsim except ImportError: print("optic rotation test requires GalSim") return np.random.seed(57) telescope = batoid.Optic.fromYaml("HSC.yaml") rot = batoid.RotX(np.random.uniform(low=0.0, high=2*np.pi)) rot = rot.dot(batoid.RotY(np.random.uniform(low=0.0, high=2*np.pi))) rot = rot.dot(batoid.RotZ(np.random.uniform(low=0.0, high=2*np.pi))) rotInv = np.linalg.inv(rot) # It's hard to test the two telescopes for equality due to rounding errors, so we test by # comparing zernikes rotTel = telescope.withLocalRotation(rot).withLocalRotation(rotInv) theta_x = np.random.uniform(-0.005, 0.005) theta_y = np.random.uniform(-0.005, 0.005) wavelength = 750e-9 np.testing.assert_allclose( batoid.psf.zernike(telescope, theta_x, theta_y, wavelength), batoid.psf.zernike(rotTel, theta_x, theta_y, wavelength), atol=1e-5 ) for item in telescope.itemDict: rotTel = telescope.withLocallyRotatedOptic(item, rot) rotTel = rotTel.withLocallyRotatedOptic(item, rotInv) rotTel2 = telescope.withLocallyRotatedOptic(item, np.eye(3)) theta_x = np.random.uniform(-0.005, 0.005) theta_y = np.random.uniform(-0.005, 0.005) np.testing.assert_allclose( batoid.psf.zernike(telescope, theta_x, theta_y, wavelength), batoid.psf.zernike(rotTel, theta_x, theta_y, wavelength), atol=1e-5 ) np.testing.assert_allclose( batoid.psf.zernike(telescope, theta_x, theta_y, wavelength), batoid.psf.zernike(rotTel2, theta_x, theta_y, wavelength), atol=1e-5 ) # Test with non-fully-qualified name rotTel = telescope.withLocallyRotatedOptic('G1', rot) rotTel = rotTel.withLocallyRotatedOptic('G1', rotInv) rotTel2 = rotTel.withLocallyRotatedOptic('G1', np.eye(3)) np.testing.assert_allclose( batoid.psf.zernike(telescope, theta_x, theta_y, wavelength), batoid.psf.zernike(rotTel, theta_x, theta_y, wavelength), atol=1e-5 ) np.testing.assert_allclose( batoid.psf.zernike(telescope, theta_x, theta_y, wavelength), batoid.psf.zernike(rotTel2, theta_x, theta_y, wavelength), atol=1e-5 )
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)))) )
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)
def update(self, deltax): """ Updates the optic. Parameters ---------- deltax: aos.state.State The change in the optical state. Notes ----- Rotations only commute for small angles; otherwise order matters. """ camx, camy, camz, camrx, camry = deltax.camhex self.optic = self.optic.withGloballyShiftedOptic('LSST.LSSTCamera', [camx, camy, camz]) camrot = np.dot(batoid.RotX(camrx), batoid.RotY(camry)) self.optic = self.optic.withLocallyRotatedOptic('LSST.LSSTCamera', camrot) m2x, m2y, m2z, m2rx, m2ry = deltax.m2hex self.optic = self.optic.withGloballyShiftedOptic('LSST.M2', [m2x, m2y, m2z]) m2rot = np.dot(batoid.RotX(m2rx), batoid.RotY(m2ry)) self.optic = self.optic.withLocallyRotatedOptic('LSST.M2', m2rot)
def test_rotation(): try: import galsim except ImportError: print("optic rotation test requires GalSim") return np.random.seed(57) fn = os.path.join(batoid.datadir, "HSC", "HSC.yaml") config = yaml.load(open(fn)) telescope = batoid.parse.parse_optic(config['opticalSystem']) rot = batoid.RotX(np.random.uniform(low=0.0, high=2 * np.pi)) rot = rot.dot(batoid.RotY(np.random.uniform(low=0.0, high=2 * np.pi))) rot = rot.dot(batoid.RotZ(np.random.uniform(low=0.0, high=2 * np.pi))) rotInv = np.linalg.inv(rot) # It's hard to test the two telescopes for equality due to rounding errors, so we test by # comparing zernikes rotTel = telescope.withLocalRotation(rot).withLocalRotation(rotInv) theta_x = np.random.uniform(-0.005, 0.005) theta_y = np.random.uniform(-0.005, 0.005) wavelength = 750e-9 np.testing.assert_allclose(batoid.psf.zernike(telescope, theta_x, theta_y, wavelength), batoid.psf.zernike(rotTel, theta_x, theta_y, wavelength), atol=1e-5) for item in telescope.itemDict: rotTel = telescope.withLocallyRotatedOptic(item, rot) rotTel = rotTel.withLocallyRotatedOptic(item, rotInv) rotTel2 = telescope.withLocallyRotatedOptic(item, np.eye(3)) theta_x = np.random.uniform(-0.005, 0.005) theta_y = np.random.uniform(-0.005, 0.005) np.testing.assert_allclose(batoid.psf.zernike(telescope, theta_x, theta_y, wavelength), batoid.psf.zernike(rotTel, theta_x, theta_y, wavelength), atol=1e-5) np.testing.assert_allclose(batoid.psf.zernike(telescope, theta_x, theta_y, wavelength), batoid.psf.zernike(rotTel2, theta_x, theta_y, wavelength), atol=1e-5)
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)
def randomCoordSys(rng): return batoid.CoordSys( rng.uniform(size=3), (batoid.RotX(rng.uniform()).dot( batoid.RotY(rng.uniform())).dot(batoid.RotZ(rng.uniform()))))
def test_rotation(): rng = np.random.default_rng(57) telescope = batoid.Optic.fromYaml("HSC.yaml") rot = batoid.RotX(rng.uniform(low=0.0, high=2 * np.pi)) rot = rot.dot(batoid.RotY(rng.uniform(low=0.0, high=2 * np.pi))) rot = rot.dot(batoid.RotZ(rng.uniform(low=0.0, high=2 * np.pi))) rotInv = np.linalg.inv(rot) # It's hard to test the two telescopes for equality due to rounding errors, # so we test by comparing zernikes rotTel = telescope.withLocalRotation(rot).withLocalRotation(rotInv) theta_x = rng.uniform(-0.005, 0.005) theta_y = rng.uniform(-0.005, 0.005) wavelength = 750e-9 for k in telescope.itemDict.keys(): np.testing.assert_allclose(telescope[k].coordSys.origin, rotTel[k].coordSys.origin, rtol=0, atol=1e-14) np.testing.assert_allclose(telescope[k].coordSys.rot, rotTel[k].coordSys.rot, rtol=0, atol=1e-14) np.testing.assert_allclose(batoid.zernikeGQ(telescope, theta_x, theta_y, wavelength), batoid.zernikeGQ(rotTel, theta_x, theta_y, wavelength), atol=1e-7) for item in telescope.itemDict: rotTel = telescope.withLocallyRotatedOptic(item, rot) rotTel = rotTel.withLocallyRotatedOptic(item, rotInv) rotTel2 = telescope.withLocallyRotatedOptic(item, np.eye(3)) theta_x = rng.uniform(-0.005, 0.005) theta_y = rng.uniform(-0.005, 0.005) np.testing.assert_allclose(batoid.zernikeGQ(telescope, theta_x, theta_y, wavelength), batoid.zernikeGQ(rotTel, theta_x, theta_y, wavelength), atol=1e-7) np.testing.assert_allclose(batoid.zernikeGQ(telescope, theta_x, theta_y, wavelength), batoid.zernikeGQ(rotTel2, theta_x, theta_y, wavelength), atol=1e-7) # Test with non-fully-qualified name rotTel = telescope.withLocallyRotatedOptic('G1', rot) rotTel = rotTel.withLocallyRotatedOptic('G1', rotInv) rotTel2 = rotTel.withLocallyRotatedOptic('G1', np.eye(3)) np.testing.assert_allclose(batoid.zernikeGQ(telescope, theta_x, theta_y, wavelength), batoid.zernikeGQ(rotTel, theta_x, theta_y, wavelength), atol=1e-7) np.testing.assert_allclose(batoid.zernikeGQ(telescope, theta_x, theta_y, wavelength), batoid.zernikeGQ(rotTel2, theta_x, theta_y, wavelength), atol=1e-7)
def test_params(): rng = np.random.default_rng(5) for _ in range(30): origin = rng.uniform(size=3) rot = (batoid.RotX(rng.uniform()) @ batoid.RotY(rng.uniform()) @ batoid.RotZ(rng.uniform())) coordSys = batoid.CoordSys(origin, rot) np.testing.assert_equal(coordSys.origin, origin) np.testing.assert_equal(coordSys.rot, rot) np.testing.assert_equal(coordSys.xhat, rot[:, 0]) np.testing.assert_equal(coordSys.yhat, rot[:, 1]) np.testing.assert_equal(coordSys.zhat, rot[:, 2]) coordSys = batoid.CoordSys(origin=origin) np.testing.assert_equal(coordSys.origin, origin) np.testing.assert_equal(coordSys.rot, np.eye(3)) np.testing.assert_equal(coordSys.xhat, [1, 0, 0]) np.testing.assert_equal(coordSys.yhat, [0, 1, 0]) np.testing.assert_equal(coordSys.zhat, [0, 0, 1]) coordSys = batoid.CoordSys(rot=rot) np.testing.assert_equal(coordSys.origin, np.zeros(3)) np.testing.assert_equal(coordSys.rot, rot) np.testing.assert_equal(coordSys.xhat, rot[:, 0]) np.testing.assert_equal(coordSys.yhat, rot[:, 1]) np.testing.assert_equal(coordSys.zhat, rot[:, 2]) coordSys = batoid.CoordSys() np.testing.assert_equal(coordSys.origin, np.zeros(3)) np.testing.assert_equal(coordSys.rot, np.eye(3)) np.testing.assert_equal(coordSys.xhat, [1, 0, 0]) np.testing.assert_equal(coordSys.yhat, [0, 1, 0]) np.testing.assert_equal(coordSys.zhat, [0, 0, 1]) coordSys = batoid.CoordSys() coordSys = coordSys.rotateGlobal(rot).shiftGlobal(origin) np.testing.assert_equal(coordSys.origin, origin) np.testing.assert_equal(coordSys.rot, rot) np.testing.assert_equal(coordSys.xhat, rot[:, 0]) np.testing.assert_equal(coordSys.yhat, rot[:, 1]) np.testing.assert_equal(coordSys.zhat, rot[:, 2]) coordSys = batoid.CoordSys() coordSys = coordSys.rotateLocal(rot).shiftGlobal(origin) np.testing.assert_equal(coordSys.origin, origin) np.testing.assert_equal(coordSys.rot, rot) np.testing.assert_equal(coordSys.xhat, rot[:, 0]) np.testing.assert_equal(coordSys.yhat, rot[:, 1]) np.testing.assert_equal(coordSys.zhat, rot[:, 2]) coordSys = batoid.CoordSys() coordSys = coordSys.shiftLocal(origin).rotateLocal(rot) np.testing.assert_equal(coordSys.origin, origin) np.testing.assert_equal(coordSys.rot, rot) np.testing.assert_equal(coordSys.xhat, rot[:, 0]) np.testing.assert_equal(coordSys.yhat, rot[:, 1]) np.testing.assert_equal(coordSys.zhat, rot[:, 2]) coordSys = batoid.CoordSys() coordSys = coordSys.shiftGlobal(origin).rotateLocal(rot) np.testing.assert_equal(coordSys.origin, origin) np.testing.assert_equal(coordSys.rot, rot) np.testing.assert_equal(coordSys.xhat, rot[:, 0]) np.testing.assert_equal(coordSys.yhat, rot[:, 1]) np.testing.assert_equal(coordSys.zhat, rot[:, 2]) # Can't simply do a global rotation after a shift, since that will # change the origin too. Works if we manually specify the rotation # center though coordSys = batoid.CoordSys() coordSys1 = coordSys.shiftGlobal(origin) coordSys = coordSys1.rotateGlobal(rot, origin, coordSys) np.testing.assert_equal(coordSys.origin, origin) np.testing.assert_equal(coordSys.rot, rot) np.testing.assert_equal(coordSys.xhat, rot[:, 0]) np.testing.assert_equal(coordSys.yhat, rot[:, 1]) np.testing.assert_equal(coordSys.zhat, rot[:, 2])
def test_rotate(): rng = np.random.default_rng(57) for _ in range(10): r1 = batoid.RotX(rng.uniform()) r2 = batoid.RotY(rng.uniform()) r3 = batoid.RotZ(rng.uniform()) r4 = batoid.RotX(rng.uniform()) r5 = batoid.RotY(rng.uniform()) r6 = batoid.RotZ(rng.uniform()) rot = r6 @ r5 @ r4 @ r3 @ r2 @ r1 coordSys = batoid.CoordSys().rotateGlobal(rot) np.testing.assert_equal(coordSys.xhat, rot[:, 0]) np.testing.assert_equal(coordSys.yhat, rot[:, 1]) np.testing.assert_equal(coordSys.zhat, rot[:, 2]) np.testing.assert_equal(coordSys.origin, 0) rot1 = r3 @ r2 @ r1 rot2 = r6 @ r5 @ r4 coordSys = batoid.CoordSys().rotateGlobal(rot1).rotateGlobal(rot2) np.testing.assert_allclose(coordSys.xhat, rot[:, 0]) np.testing.assert_allclose(coordSys.yhat, rot[:, 1]) np.testing.assert_allclose(coordSys.zhat, rot[:, 2]) np.testing.assert_equal(coordSys.origin, 0) coordSys = batoid.CoordSys(rot=rot1) coordSys2 = coordSys.rotateLocal(batoid.RotX(np.pi / 2)) # Since second rotation was about the local X, both should have same # xhat np.testing.assert_allclose(coordSys.xhat, coordSys2.xhat) # 90 degree positive rotation then means y -> -z, z -> y np.testing.assert_allclose(coordSys.yhat, -coordSys2.zhat) np.testing.assert_allclose(coordSys.zhat, coordSys2.yhat) # Try a loop coordSys = batoid.CoordSys(rot=rot) coordSys = coordSys.rotateGlobal(batoid.RotX(0.1)) coordSys = coordSys.rotateGlobal(batoid.RotZ(np.pi)) coordSys = coordSys.rotateGlobal(batoid.RotX(0.1)) coordSys = coordSys.rotateGlobal(batoid.RotZ(np.pi)) # Should be back where we started... np.testing.assert_allclose(coordSys.rot, rot) # Miscentered origins origin = rng.uniform(size=3) coordSys = batoid.CoordSys(origin=origin, rot=rot) np.testing.assert_equal(origin, coordSys.origin) coordSys2 = coordSys.rotateGlobal(rot) np.testing.assert_equal(rot @ origin, coordSys2.origin) coordSys3 = coordSys.rotateLocal(rot) np.testing.assert_equal(origin, coordSys3.origin) # Miscentered rotation axes # Global with center specified is same as local coordSys = batoid.CoordSys(origin=origin, rot=rot) coordSys2 = coordSys.rotateLocal(rot) coordSys3 = coordSys.rotateGlobal(rot, origin, batoid.CoordSys()) np.testing.assert_allclose(coordSys2.origin, origin) np.testing.assert_allclose(coordSys2.origin, coordSys3.origin) np.testing.assert_allclose(coordSys2.rot, coordSys3.rot)