def test_precess(): # I don't have much of a test here. The formulae are what they are. # But it should at least be the case that a precession trip that ends up # back at the original epoch should leave the coord unchanged. orig = treecorr.CelestialCoord(0.234, 0.342) c1 = orig.precess(2000., 1950.) c2 = c1.precess(1950., 1900.) c3 = c2.precess(1900., 2000.) numpy.testing.assert_almost_equal(c3.ra, orig.ra) numpy.testing.assert_almost_equal(c3.dec, orig.dec) # I found a website that does precession calculations, so check that we are # consistent with them. # http://www.bbastrodesigns.com/coordErrors.html dra_1950 = -(2. + 39.07 / 60.) / 60. * treecorr.hours ddec_1950 = -(16. + 16.3 / 60.) / 60. * treecorr.degrees print('delta from website: ', dra_1950, ddec_1950) print('delta from precess: ', (c1.ra - orig.ra), (c1.dec - orig.dec)) numpy.testing.assert_almost_equal(dra_1950, c1.ra - orig.ra, decimal=5) numpy.testing.assert_almost_equal(ddec_1950, c1.dec - orig.dec, decimal=5) dra_1900 = -(5. + 17.74 / 60.) / 60. * treecorr.hours ddec_1900 = -(32. + 35.4 / 60.) / 60. * treecorr.degrees print('delta from website: ', dra_1900, ddec_1900) print('delta from precess: ', (c2.ra - orig.ra), (c2.dec - orig.dec)) numpy.testing.assert_almost_equal(dra_1900, c2.ra - orig.ra, decimal=5) numpy.testing.assert_almost_equal(ddec_1900, c2.dec - orig.dec, decimal=5)
def test_distance(): # First, let's test some distances that are easy to figure out # without any spherical trig. eq1 = treecorr.CelestialCoord(0., 0.) # point on the equator eq2 = treecorr.CelestialCoord(1., 0.) # 1 radian along equator eq3 = treecorr.CelestialCoord(pi, 0.) # antipode of eq1 north_pole = treecorr.CelestialCoord(0., pi / 2.) # north pole south_pole = treecorr.CelestialCoord(0., -pi / 2.) # south pole numpy.testing.assert_almost_equal(eq1.distanceTo(eq2), 1.) numpy.testing.assert_almost_equal(eq2.distanceTo(eq1), 1.) numpy.testing.assert_almost_equal(eq1.distanceTo(eq3), pi) numpy.testing.assert_almost_equal(eq2.distanceTo(eq3), pi - 1.) numpy.testing.assert_almost_equal(north_pole.distanceTo(south_pole), pi) numpy.testing.assert_almost_equal(eq1.distanceTo(north_pole), pi / 2.) numpy.testing.assert_almost_equal(eq2.distanceTo(north_pole), pi / 2.) numpy.testing.assert_almost_equal(eq3.distanceTo(north_pole), pi / 2.) numpy.testing.assert_almost_equal(eq1.distanceTo(south_pole), pi / 2.) numpy.testing.assert_almost_equal(eq2.distanceTo(south_pole), pi / 2.) numpy.testing.assert_almost_equal(eq3.distanceTo(south_pole), pi / 2.) c1 = treecorr.CelestialCoord(0.234, 0.342) # Some random point c2 = treecorr.CelestialCoord(0.234, -1.093) # Same meridian c3 = treecorr.CelestialCoord(pi + 0.234, -0.342) # Antipode c4 = treecorr.CelestialCoord(pi + 0.234, 0.832) # Different point on opposide meridian numpy.testing.assert_almost_equal(c1.distanceTo(c1), 0.) numpy.testing.assert_almost_equal(c1.distanceTo(c2), 1.435) numpy.testing.assert_almost_equal(c1.distanceTo(c3), pi) numpy.testing.assert_almost_equal(c1.distanceTo(c4), pi - 1.174) # Now some that require spherical trig calculations. # Importantly, this uses the more straightforward spherical trig formula, the cosine rule. # The CelestialCoord class uses a different formula that is more stable for very small # distances, which are typical in the correlation function calculation. c5 = treecorr.CelestialCoord(1.832, -0.723) # Some other random point # The standard formula is: # cos(d) = sin(dec1) sin(dec2) + cos(dec1) cos(dec2) cos(delta ra) d = arccos( sin(0.342) * sin(-0.723) + cos(0.342) * cos(-0.723) * cos(1.832 - 0.234)) numpy.testing.assert_almost_equal(c1.distanceTo(c5), d) # Tiny displacements should have dsq = (dra^2 cos^2 dec) + (ddec^2) c6 = treecorr.CelestialCoord(0.234 + 1.7e-9, 0.342) c7 = treecorr.CelestialCoord(0.234, 0.342 + 1.9e-9) c8 = treecorr.CelestialCoord(0.234 + 2.3e-9, 0.342 + 1.2e-9) # Note that the standard formula gets thsse wrong. d comes back as 0. d = arccos(sin(0.342) * sin(0.342) + cos(0.342) * cos(0.342) * cos(1.7e-9)) print('d(c6) = ', 1.7e-9 * cos(0.342), c1.distanceTo(c6), d) d = arccos( sin(0.342) * sin(0.342 + 1.9e-9) + cos(0.342) * cos(0.342 + 1.9e-9) * cos(0.)) print('d(c7) = ', 1.9e-9, c1.distanceTo(c7), d) d = arccos(sin(0.342) * sin(0.342) + cos(0.342) * cos(0.342) * cos(1.2e-9)) true_d = sqrt((2.3e-9 * cos(0.342))**2 + 1.2e-9**2) print('d(c7) = ', true_d, c1.distanceTo(c8), d) numpy.testing.assert_almost_equal( c1.distanceTo(c6) / (1.7e-9 * cos(0.342)), 1.0) numpy.testing.assert_almost_equal(c1.distanceTo(c7) / 1.9e-9, 1.0) numpy.testing.assert_almost_equal(c1.distanceTo(c8) / true_d, 1.0)
def test_galactic(): # According to wikipedia: http://en.wikipedia.org/wiki/Galactic_coordinate_system # the galactic center is located at 17h:45.6m, -28.94d center = treecorr.CelestialCoord((17. + 45.6 / 60.) * treecorr.hours, -28.94 * treecorr.degrees) print('center.galactic = ', center.galactic()) el, b = center.galactic() numpy.testing.assert_almost_equal(el, 0., decimal=3) numpy.testing.assert_almost_equal(b, 0., decimal=3) # The north pole is at 12h:51.4m, 27.13d north = treecorr.CelestialCoord((12. + 51.4 / 60.) * treecorr.hours, 27.13 * treecorr.degrees) print('north.galactic = ', north.galactic()) el, b = north.galactic() numpy.testing.assert_almost_equal(b, pi / 2., decimal=3) # The south pole is at 0h:51.4m, -27.13d south = treecorr.CelestialCoord((0. + 51.4 / 60.) * treecorr.hours, -27.13 * treecorr.degrees) print('south.galactic = ', south.galactic()) el, b = south.galactic() numpy.testing.assert_almost_equal(b, -pi / 2., decimal=3) # The anti-center is at 5h:42.6m, 28.92d anticenter = treecorr.CelestialCoord((5. + 45.6 / 60.) * treecorr.hours, 28.94 * treecorr.degrees) print('anticenter.galactic = ', anticenter.galactic()) el, b = anticenter.galactic() numpy.testing.assert_almost_equal(el, pi, decimal=3) numpy.testing.assert_almost_equal(b, 0., decimal=3) # Now test with some random values using this NASA website to get the correct answers: # http://lambda.gsfc.nasa.gov/toolbox/tb_coordconv.cfm # While I'm at it, they also give me eclipticc coords, so test those as well. coord1 = treecorr.CelestialCoord(13.234 * treecorr.degrees, -73.438 * treecorr.degrees) el, b = coord1.galactic() print('coord1 = ', coord1) print('el, b = ', el / treecorr.degrees, b / treecorr.degrees) numpy.testing.assert_almost_equal(el, (302.78430 - 360.) * treecorr.degrees, decimal=5) numpy.testing.assert_almost_equal(b, -43.68987 * treecorr.degrees, decimal=5) lam, beta = coord1.ecliptic() print('lam, beta = ', lam, beta) print('lam, beta = ', lam / treecorr.degrees, beta / treecorr.degrees) numpy.testing.assert_almost_equal(lam, (310.80568 - 360.) * treecorr.degrees, decimal=5) numpy.testing.assert_almost_equal(beta, -64.87384 * treecorr.degrees, decimal=5) coord2_1950 = treecorr.CelestialCoord(122.93 * treecorr.degrees, 16.01 * treecorr.degrees) coord2_2000 = coord2_1950.precess(1950., 2000.) print('coord2_1950 = ', coord2_1950) print('coord2_2000 = ', coord2_2000) numpy.testing.assert_almost_equal(coord2_2000.ra, 123.63697 * treecorr.degrees, decimal=5) numpy.testing.assert_almost_equal(coord2_2000.dec, 15.85722 * treecorr.degrees, decimal=5) el, b = coord2_1950.galactic(epoch=1950.) print('el, b = ', el / treecorr.degrees, b / treecorr.degrees) numpy.testing.assert_almost_equal(el, 207.37010 * treecorr.degrees, decimal=5) numpy.testing.assert_almost_equal(b, 25.35929 * treecorr.degrees, decimal=5) lam, beta = coord2_2000.ecliptic() print('lam, beta = ', lam, beta) print('lam, beta = ', lam / treecorr.degrees, beta / treecorr.degrees) numpy.testing.assert_almost_equal(lam, 122.28162 * treecorr.degrees, decimal=5) numpy.testing.assert_almost_equal(beta, -3.89215 * treecorr.degrees, decimal=5) lam, beta = coord2_1950.ecliptic(epoch=1950) print('lam, beta = ', lam, beta) print('lam, beta = ', lam / treecorr.degrees, beta / treecorr.degrees) numpy.testing.assert_almost_equal(lam, 121.58348 * treecorr.degrees, decimal=5) numpy.testing.assert_almost_equal(beta, -3.89734 * treecorr.degrees, decimal=5)
def test_projection(): # Test that a small triangle has the correct properties for each kind of projection center = treecorr.CelestialCoord(0.234, 0.342) cA = treecorr.CelestialCoord(-0.193, 0.882) cB = treecorr.CelestialCoord(-0.193 + 1.7e-6, 0.882 + 1.2e-6) cC = treecorr.CelestialCoord(-0.193 - 2.4e-6, 0.882 + 3.1e-6) a = cB.distanceTo(cC) b = cC.distanceTo(cA) c = cA.distanceTo(cB) A = cA.angleBetween(cB, cC) B = cB.angleBetween(cC, cA) C = cC.angleBetween(cA, cB) E = cA.area(cB, cC) # # The lambert is supposed to preserve area # pA = center.project(cA, projection='lambert') pB = center.project(cB, projection='lambert') pC = center.project(cC, projection='lambert') # The shoelace formula gives the area of a triangle given coordinates: # A = 1/2 abs( (x2-x1)*(y3-y1) - (x3-x1)*(y2-y1) ) area = 0.5 * abs((pB[0] - pA[0]) * (pC[1] - pA[1]) - (pC[0] - pA[0]) * (pB[1] - pA[1])) print('lambert area = ', area, E) numpy.testing.assert_almost_equal(area / E, 1, decimal=5) # Check that project_rad does the same thing pA2 = center.project_rad(cA.ra, cA.dec, projection='lambert') numpy.testing.assert_array_almost_equal(pA, pA2) # Check the deprojection cA2 = center.deproject(*pA, projection='lambert') numpy.testing.assert_almost_equal(cA.ra, cA2.ra) numpy.testing.assert_almost_equal(cA.dec, cA2.dec) cA3 = center.deproject_rad(*pA, projection='lambert') numpy.testing.assert_array_almost_equal([cA.ra, cA.dec], cA3) # The angles are not preserved a = sqrt((pB[0] - pC[0])**2 + (pB[1] - pC[1])**2) b = sqrt((pC[0] - pA[0])**2 + (pC[1] - pA[1])**2) c = sqrt((pA[0] - pB[0])**2 + (pA[1] - pB[1])**2) cosA = ((pB[0] - pA[0]) * (pC[0] - pA[0]) + (pB[1] - pA[1]) * (pC[1] - pA[1])) / (b * c) cosB = ((pC[0] - pB[0]) * (pA[0] - pB[0]) + (pC[1] - pB[1]) * (pA[1] - pB[1])) / (c * a) cosC = ((pA[0] - pC[0]) * (pB[0] - pC[0]) + (pA[1] - pC[1]) * (pB[1] - pC[1])) / (a * b) print('lambert cosA = ', cosA, cos(A)) print('lambert cosB = ', cosB, cos(B)) print('lambert cosC = ', cosC, cos(C)) # The deproject jacobian should tell us how the area changes dudx, dudy, dvdx, dvdy = center.deproject_jac(*pA, projection='lambert') jac_area = abs(dudx * dvdy - dudy * dvdx) print('lambert jac_area = ', jac_area, E / area) numpy.testing.assert_almost_equal(jac_area, E / area, decimal=5) # # The stereographic is supposed to preserve angles # pA = center.project(cA, projection='stereographic') pB = center.project(cB, projection='stereographic') pC = center.project(cC, projection='stereographic') # The easiest way to compute the angles is from the dot products: # a.b = ab cos(C) a = sqrt((pB[0] - pC[0])**2 + (pB[1] - pC[1])**2) b = sqrt((pC[0] - pA[0])**2 + (pC[1] - pA[1])**2) c = sqrt((pA[0] - pB[0])**2 + (pA[1] - pB[1])**2) cosA = ((pB[0] - pA[0]) * (pC[0] - pA[0]) + (pB[1] - pA[1]) * (pC[1] - pA[1])) / (b * c) cosB = ((pC[0] - pB[0]) * (pA[0] - pB[0]) + (pC[1] - pB[1]) * (pA[1] - pB[1])) / (c * a) cosC = ((pA[0] - pC[0]) * (pB[0] - pC[0]) + (pA[1] - pC[1]) * (pB[1] - pC[1])) / (a * b) print('stereographic cosA = ', cosA, cos(A)) print('stereographic cosB = ', cosB, cos(B)) print('stereographic cosC = ', cosC, cos(C)) numpy.testing.assert_almost_equal(cosA, cos(A), decimal=5) numpy.testing.assert_almost_equal(cosB, cos(B), decimal=5) numpy.testing.assert_almost_equal(cosC, cos(C), decimal=5) # Check that project_rad does the same thing pA2 = center.project_rad(cA.ra, cA.dec, projection='stereographic') numpy.testing.assert_array_almost_equal(pA, pA2) # Check the deprojection cA2 = center.deproject(*pA, projection='stereographic') numpy.testing.assert_almost_equal(cA.ra, cA2.ra) numpy.testing.assert_almost_equal(cA.dec, cA2.dec) cA3 = center.deproject_rad(*pA, projection='stereographic') numpy.testing.assert_array_almost_equal([cA.ra, cA.dec], cA3) # The area is not preserved area = 0.5 * abs((pB[0] - pA[0]) * (pC[1] - pA[1]) - (pC[0] - pA[0]) * (pB[1] - pA[1])) print('stereographic area = ', area, E) # The deproject jacobian should tell us how the area changes dudx, dudy, dvdx, dvdy = center.deproject_jac(*pA, projection='stereographic') jac_area = abs(dudx * dvdy - dudy * dvdx) print('stereographic jac_area = ', jac_area, E / area) numpy.testing.assert_almost_equal(jac_area, E / area, decimal=5) # # The gnomonic is supposed to turn great circles into straight lines # I don't actually have any tests of that though... # pA = center.project(cA, projection='gnomonic') pB = center.project(cB, projection='gnomonic') pC = center.project(cC, projection='gnomonic') # Check that project_rad does the same thing pA2 = center.project_rad(cA.ra, cA.dec, projection='gnomonic') numpy.testing.assert_array_almost_equal(pA, pA2) # Check the deprojection cA2 = center.deproject(*pA, projection='gnomonic') numpy.testing.assert_almost_equal(cA.ra, cA2.ra) numpy.testing.assert_almost_equal(cA.dec, cA2.dec) cA3 = center.deproject_rad(*pA, projection='gnomonic') numpy.testing.assert_array_almost_equal([cA.ra, cA.dec], cA3) # The angles are not preserved a = sqrt((pB[0] - pC[0])**2 + (pB[1] - pC[1])**2) b = sqrt((pC[0] - pA[0])**2 + (pC[1] - pA[1])**2) c = sqrt((pA[0] - pB[0])**2 + (pA[1] - pB[1])**2) cosA = ((pB[0] - pA[0]) * (pC[0] - pA[0]) + (pB[1] - pA[1]) * (pC[1] - pA[1])) / (b * c) cosB = ((pC[0] - pB[0]) * (pA[0] - pB[0]) + (pC[1] - pB[1]) * (pA[1] - pB[1])) / (c * a) cosC = ((pA[0] - pC[0]) * (pB[0] - pC[0]) + (pA[1] - pC[1]) * (pB[1] - pC[1])) / (a * b) print('gnomonic cosA = ', cosA, cos(A)) print('gnomonic cosB = ', cosB, cos(B)) print('gnomonic cosC = ', cosC, cos(C)) # The area is not preserved area = 0.5 * abs((pB[0] - pA[0]) * (pC[1] - pA[1]) - (pC[0] - pA[0]) * (pB[1] - pA[1])) print('gnomonic area = ', area, E) # The deproject jacobian should tell us how the area changes dudx, dudy, dvdx, dvdy = center.deproject_jac(*pA, projection='gnomonic') jac_area = abs(dudx * dvdy - dudy * dvdx) print('gnomonic jac_area = ', jac_area, E / area) numpy.testing.assert_almost_equal(jac_area, E / area, decimal=5) # # The postel is supposed to preserve distance from the center # pA = center.project(cA, projection='postel') pB = center.project(cB, projection='postel') pC = center.project(cC, projection='postel') dA = sqrt(pA[0]**2 + pA[1]**2) dB = sqrt(pB[0]**2 + pB[1]**2) dC = sqrt(pC[0]**2 + pC[1]**2) print('postel dA = ', dA, center.distanceTo(cA)) print('postel dB = ', dB, center.distanceTo(cB)) print('postel dC = ', dC, center.distanceTo(cC)) numpy.testing.assert_almost_equal(dA, center.distanceTo(cA)) numpy.testing.assert_almost_equal(dB, center.distanceTo(cB)) numpy.testing.assert_almost_equal(dC, center.distanceTo(cC)) # Check that project_rad does the same thing pA2 = center.project_rad(cA.ra, cA.dec, projection='postel') numpy.testing.assert_array_almost_equal(pA, pA2) # Check the deprojection cA2 = center.deproject(*pA, projection='postel') numpy.testing.assert_almost_equal(cA.ra, cA2.ra) numpy.testing.assert_almost_equal(cA.dec, cA2.dec) cA3 = center.deproject_rad(*pA, projection='postel') numpy.testing.assert_array_almost_equal([cA.ra, cA.dec], cA3) # The angles are not preserved a = sqrt((pB[0] - pC[0])**2 + (pB[1] - pC[1])**2) b = sqrt((pC[0] - pA[0])**2 + (pC[1] - pA[1])**2) c = sqrt((pA[0] - pB[0])**2 + (pA[1] - pB[1])**2) cosA = ((pB[0] - pA[0]) * (pC[0] - pA[0]) + (pB[1] - pA[1]) * (pC[1] - pA[1])) / (b * c) cosB = ((pC[0] - pB[0]) * (pA[0] - pB[0]) + (pC[1] - pB[1]) * (pA[1] - pB[1])) / (c * a) cosC = ((pA[0] - pC[0]) * (pB[0] - pC[0]) + (pA[1] - pC[1]) * (pB[1] - pC[1])) / (a * b) print('postel cosA = ', cosA, cos(A)) print('postel cosB = ', cosB, cos(B)) print('postel cosC = ', cosC, cos(C)) # The area is not preserved area = 0.5 * abs((pB[0] - pA[0]) * (pC[1] - pA[1]) - (pC[0] - pA[0]) * (pB[1] - pA[1])) print('postel area = ', area, E) # The deproject jacobian should tell us how the area changes dudx, dudy, dvdx, dvdy = center.deproject_jac(*pA, projection='postel') jac_area = abs(dudx * dvdy - dudy * dvdx) print('postel jac_area = ', jac_area, E / area) numpy.testing.assert_almost_equal(jac_area, E / area, decimal=5)
def test_angle(): # Again, let's start with some answers we can get by inspection. eq1 = treecorr.CelestialCoord(0., 0.) # point on the equator eq2 = treecorr.CelestialCoord(1., 0.) # 1 radian along equator eq3 = treecorr.CelestialCoord(pi, 0.) # antipode of eq1 north_pole = treecorr.CelestialCoord(0., pi / 2.) # north pole south_pole = treecorr.CelestialCoord(0., -pi / 2.) # south pole numpy.testing.assert_almost_equal(north_pole.angleBetween(eq1, eq2), -1.) numpy.testing.assert_almost_equal(north_pole.angleBetween(eq2, eq1), 1.) numpy.testing.assert_almost_equal(north_pole.angleBetween(eq2, eq3), 1. - pi) numpy.testing.assert_almost_equal(north_pole.angleBetween(eq3, eq2), pi - 1.) numpy.testing.assert_almost_equal(south_pole.angleBetween(eq1, eq2), 1.) numpy.testing.assert_almost_equal(south_pole.angleBetween(eq2, eq1), -1.) numpy.testing.assert_almost_equal(south_pole.angleBetween(eq2, eq3), pi - 1.) numpy.testing.assert_almost_equal(south_pole.angleBetween(eq3, eq2), 1. - pi) numpy.testing.assert_almost_equal(eq1.angleBetween(north_pole, eq2), pi / 2.) numpy.testing.assert_almost_equal(eq2.angleBetween(north_pole, eq1), -pi / 2.) numpy.testing.assert_almost_equal(north_pole.area(eq1, eq2), 1.) numpy.testing.assert_almost_equal(north_pole.area(eq2, eq1), 1.) numpy.testing.assert_almost_equal(south_pole.area(eq1, eq2), 1.) numpy.testing.assert_almost_equal(south_pole.area(eq2, eq1), 1.) # For arbitrary points, we can check that the spherical triangle satisfies # the spherical trig laws. cA = treecorr.CelestialCoord(0.234, 0.342) cB = treecorr.CelestialCoord(-0.193, 0.882) cC = treecorr.CelestialCoord(0.721, -0.561) a = cB.distanceTo(cC) b = cC.distanceTo(cA) c = cA.distanceTo(cB) A = cA.angleBetween(cB, cC) B = cB.angleBetween(cC, cA) C = cC.angleBetween(cA, cB) E = abs(A) + abs(B) + abs(C) - pi s = (a + b + c) / 2. # Law of cosines: numpy.testing.assert_almost_equal( cos(c), cos(a) * cos(b) + sin(a) * sin(b) * cos(C)) numpy.testing.assert_almost_equal( cos(a), cos(b) * cos(c) + sin(b) * sin(c) * cos(A)) numpy.testing.assert_almost_equal( cos(b), cos(c) * cos(a) + sin(c) * sin(a) * cos(B)) # Law of sines: numpy.testing.assert_almost_equal(sin(A) * sin(b), sin(B) * sin(a)) numpy.testing.assert_almost_equal(sin(B) * sin(c), sin(C) * sin(b)) numpy.testing.assert_almost_equal(sin(C) * sin(a), sin(A) * sin(c)) # Alternate law of cosines: numpy.testing.assert_almost_equal( cos(C), -cos(A) * cos(B) + sin(A) * sin(B) * cos(c)) numpy.testing.assert_almost_equal( cos(A), -cos(B) * cos(C) + sin(B) * sin(C) * cos(a)) numpy.testing.assert_almost_equal( cos(B), -cos(C) * cos(A) + sin(C) * sin(A) * cos(b)) # Spherical excess: numpy.testing.assert_almost_equal(cA.area(cB, cC), E) numpy.testing.assert_almost_equal(cA.area(cC, cB), E) numpy.testing.assert_almost_equal(cB.area(cA, cC), E) numpy.testing.assert_almost_equal(cB.area(cC, cA), E) numpy.testing.assert_almost_equal(cC.area(cB, cA), E) numpy.testing.assert_almost_equal(cC.area(cA, cB), E) # L'Huilier's formula for spherical excess: numpy.testing.assert_almost_equal( tan(E / 4)**2, tan(s / 2) * tan((s - a) / 2) * tan((s - b) / 2) * tan((s - c) / 2))