def testSphericalFromCartesian(self): """ Note that xyz[i][j] is the ith component of the jth vector Each column of xyz is a vector """ nsamples = 10 radius = self.rng.random_sample(nsamples) * 10.0 theta = self.rng.random_sample(nsamples) * np.pi - 0.5 * np.pi phi = self.rng.random_sample(nsamples) * 2.0 * np.pi points = [] for ix in range(nsamples): vv = [radius[ix] * np.cos(theta[ix]) * np.cos(phi[ix]), radius[ix] * np.cos(theta[ix]) * np.sin(phi[ix]), radius[ix] * np.sin(theta[ix])] points.append(vv) points = np.array(points) lon, lat = utils.sphericalFromCartesian(points) for ix in range(nsamples): self.assertAlmostEqual(np.cos(lon[ix]), np.cos(phi[ix]), 5) self.assertAlmostEqual(np.sin(lon[ix]), np.sin(phi[ix]), 5) self.assertAlmostEqual(np.cos(lat[ix]), np.cos(theta[ix]), 5) self.assertAlmostEqual(np.sin(lat[ix]), np.sin(theta[ix]), 5) # test passing in the points one at a time for pp, th, ph in zip(points, theta, phi): lon, lat = utils.sphericalFromCartesian(pp) self.assertAlmostEqual(np.cos(lon), np.cos(ph), 5) self.assertAlmostEqual(np.sin(lon), np.sin(ph), 5) self.assertAlmostEqual(np.cos(lat), np.cos(th), 5) self.assertAlmostEqual(np.sin(lat), np.sin(th), 5)
def test_trixel_bounding_circle(self): """ Verify that the trixel's bounding_circle method returns a circle that contains all of the corners of the trixel """ rng = np.random.RandomState(142) n_test_cases = 5 for i_test in range(n_test_cases): htmid = (13 << 6) + rng.randint(1, 2**6 - 1) trixel = trixelFromHtmid(htmid) bounding_circle = trixel.bounding_circle ra_0, dec_0 = sphericalFromCartesian(bounding_circle[0]) ra_list = [] dec_list = [] for cc in trixel.corners: ra, dec = sphericalFromCartesian(cc) ra_list.append(ra) dec_list.append(dec) ra_list = np.array(ra_list) dec_list = np.array(dec_list) distance = _angularSeparation(ra_0, dec_0, ra_list, dec_list) distance = arcsecFromRadians(distance) radius = arcsecFromRadians(bounding_circle[2]) self.assertLessEqual(distance.max() - radius, 1.0e-8) self.assertLess(np.abs(distance.max() - radius), 1.0e-8)
def testSphericalFromCartesian(self): """ Note that xyz[i][j] is the ith component of the jth vector Each column of xyz is a vector """ numpy.random.seed(42) nsamples = 10 radius = numpy.random.random_sample(nsamples)*10.0 theta = numpy.random.random_sample(nsamples)*numpy.pi-0.5*numpy.pi phi = numpy.random.random_sample(nsamples)*2.0*numpy.pi points = [] for ix in range(nsamples): vv = [radius[ix]*numpy.cos(theta[ix])*numpy.cos(phi[ix]), radius[ix]*numpy.cos(theta[ix])*numpy.sin(phi[ix]), radius[ix]*numpy.sin(theta[ix])] points.append(vv) points = numpy.array(points) lon, lat = utils.sphericalFromCartesian(points) for ix in range(nsamples): self.assertAlmostEqual(numpy.cos(lon[ix]), numpy.cos(phi[ix]), 5) self.assertAlmostEqual(numpy.sin(lon[ix]), numpy.sin(phi[ix]), 5) self.assertAlmostEqual(numpy.cos(lat[ix]), numpy.cos(theta[ix]), 5) self.assertAlmostEqual(numpy.sin(lat[ix]), numpy.sin(theta[ix]), 5) for pp, th, ph in zip(points, theta, phi): lon, lat = utils.sphericalFromCartesian(pp) self.assertAlmostEqual(numpy.cos(lon), numpy.cos(ph), 5) self.assertAlmostEqual(numpy.sin(lon), numpy.sin(ph), 5) self.assertAlmostEqual(numpy.cos(lat), numpy.cos(th), 5) self.assertAlmostEqual(numpy.sin(lat), numpy.sin(th), 5)
def test_trixel_bounding_circle(self): """ Verify that the trixel's bounding_circle method returns a circle that contains all of the corners of the trixel """ rng = np.random.RandomState(142) n_test_cases = 5 for i_test in range(n_test_cases): htmid = (13 << 6)+rng.randint(1, 2**6-1) trixel = trixelFromHtmid(htmid) bounding_circle = trixel.bounding_circle ra_0, dec_0 = sphericalFromCartesian(bounding_circle[0]) ra_list = [] dec_list = [] for cc in trixel.corners: ra, dec = sphericalFromCartesian(cc) ra_list.append(ra) dec_list.append(dec) ra_list = np.array(ra_list) dec_list = np.array(dec_list) distance = _angularSeparation(ra_0, dec_0, ra_list, dec_list) distance = arcsecFromRadians(distance) radius = arcsecFromRadians(bounding_circle[2]) self.assertLessEqual(distance.max()-radius, 1.0e-8) self.assertLess(np.abs(distance.max()-radius), 1.0e-8)
def test_HalfSpaceIntersection(self): # Test that the two roots of an intersection are the # correct angular distance from the centers of the # half spaces ra1 = 22.0 dec1 = 45.0 rad1 = 10.0 ra2 = 23.5 dec2 = 37.9 rad2 = 9.2 hs1 = halfSpaceFromRaDec(ra1, dec1, rad1) hs2 = halfSpaceFromRaDec(ra2, dec2, rad2) roots = intersectHalfSpaces(hs1, hs2) self.assertEqual(len(roots), 2) self.assertAlmostEqual(np.sqrt(np.sum(roots[0]**2)), 1.0, 10) self.assertAlmostEqual(np.sqrt(np.sum(roots[1]**2)), 1.0, 10) ra_r1, dec_r1 = np.degrees(sphericalFromCartesian(roots[0])) ra_r2, dec_r2 = np.degrees(sphericalFromCartesian(roots[1])) dd = angularSeparation(ra1, dec1, ra_r1, dec_r1) self.assertAlmostEqual(dd, rad1, 10) dd = angularSeparation(ra1, dec1, ra_r2, dec_r2) self.assertAlmostEqual(dd, rad1, 10) dd = angularSeparation(ra2, dec2, ra_r1, dec_r1) self.assertAlmostEqual(dd, rad2, 10) dd = angularSeparation(ra2, dec2, ra_r2, dec_r2) self.assertAlmostEqual(dd, rad2, 10) # test that two non-intersecting HalfSpaces return no roots hs1 = halfSpaceFromRaDec(0.0, 90.0, 1.0) hs2 = halfSpaceFromRaDec(20.0, -75.0, 5.0) roots = intersectHalfSpaces(hs1, hs2) self.assertEqual(len(roots), 0) # test that two half spaces that are inside each other # return no roots hs1 = halfSpaceFromRaDec(77.0, 10.0, 20.0) hs2 = halfSpaceFromRaDec(75.0, 8.0, 0.2) roots = intersectHalfSpaces(hs1, hs2) self.assertEqual(len(roots), 0) # test that two half spaces with identical centers # return no roots hs1 = halfSpaceFromRaDec(11.0, -23.0, 1.0) hs2 = halfSpaceFromRaDec(11.0, -23.0, 0.2) roots = intersectHalfSpaces(hs1, hs2) self.assertEqual(len(roots), 0) roots = intersectHalfSpaces(hs1, hs1) self.assertEqual(len(roots), 0)
def get_center(self): """ Return the RA, Dec of the center of the circle bounding this trixel (RA, Dec both in degrees) """ ra, dec = sphericalFromCartesian(self.bounding_circle[0]) return np.degrees(ra), np.degrees(dec)
def testCartesianFromSpherical(self): nsamples = 10 theta = self.rng.random_sample(nsamples) * np.pi - 0.5 * np.pi phi = self.rng.random_sample(nsamples) * 2.0 * np.pi points = [] for ix in range(nsamples): vv = [np.cos(theta[ix]) * np.cos(phi[ix]), np.cos(theta[ix]) * np.sin(phi[ix]), np.sin(theta[ix])] points.append(vv) points = np.array(points) lon, lat = utils.sphericalFromCartesian(points) outPoints = utils.cartesianFromSpherical(lon, lat) for pp, oo in zip(points, outPoints): np.testing.assert_array_almost_equal(pp, oo, decimal=6) # test passing in arguments as floats for ix, (ll, bb) in enumerate(zip(lon, lat)): xyz = utils.cartesianFromSpherical(ll, bb) self.assertIsInstance(xyz[0], np.float) self.assertIsInstance(xyz[1], np.float) self.assertIsInstance(xyz[2], np.float) self.assertAlmostEqual(xyz[0], outPoints[ix][0], 12) self.assertAlmostEqual(xyz[1], outPoints[ix][1], 12) self.assertAlmostEqual(xyz[2], outPoints[ix][2], 12) # test _xyz_from_ra_dec <-> testCartesianFromSpherical np.testing.assert_array_equal(utils.cartesianFromSpherical(lon, lat), utils._xyz_from_ra_dec(lon, lat).transpose())
def transform(self, ra, dec): """ ra, dec are in degrees; return the RA, Dec coordinates of the point about the new field center """ xyz = cartesianFromSpherical(np.radians(ra), np.radians(dec)).transpose() xyz = np.dot(self._transformation, xyz).transpose() ra_out, dec_out = sphericalFromCartesian(xyz) return np.degrees(ra_out), np.degrees(dec_out)
def transform(self, ra, dec): """ ra, dec are in radians; return the RA, Dec coordinates of the point about the new field center """ xyz = cartesianFromSpherical(ra, dec).transpose() xyz = np.dot(self._transformation, xyz).transpose() ra_out, dec_out = sphericalFromCartesian(xyz) return ra_out, dec_out
def testSphericalFromCartesian(self): """ Note that xyz[i][j] is the ith component of the jth vector Each column of xyz is a vector """ nsamples = 10 radius = self.rng.random_sample(nsamples) * 10.0 theta = self.rng.random_sample(nsamples) * np.pi - 0.5 * np.pi phi = self.rng.random_sample(nsamples) * 2.0 * np.pi points = [] for ix in range(nsamples): vv = [radius[ix] * np.cos(theta[ix]) * np.cos(phi[ix]), radius[ix] * np.cos(theta[ix]) * np.sin(phi[ix]), radius[ix] * np.sin(theta[ix])] points.append(vv) points = np.array(points) lon, lat = utils.sphericalFromCartesian(points) for ix in range(nsamples): self.assertAlmostEqual(np.cos(lon[ix]), np.cos(phi[ix]), 5) self.assertAlmostEqual(np.sin(lon[ix]), np.sin(phi[ix]), 5) self.assertAlmostEqual(np.cos(lat[ix]), np.cos(theta[ix]), 5) self.assertAlmostEqual(np.sin(lat[ix]), np.sin(theta[ix]), 5) # test passing in the points one at a time for pp, th, ph in zip(points, theta, phi): lon, lat = utils.sphericalFromCartesian(pp) self.assertAlmostEqual(np.cos(lon), np.cos(ph), 5) self.assertAlmostEqual(np.sin(lon), np.sin(ph), 5) self.assertAlmostEqual(np.cos(lat), np.cos(th), 5) self.assertAlmostEqual(np.sin(lat), np.sin(th), 5) # test ra_dec_from_xyz <-> sphericalFromCartesian np.testing.assert_array_equal(utils.sphericalFromCartesian(points), utils._ra_dec_from_xyz(points[:, 0], points[:, 1], points[:, 2])) # now, test passing one at a time for pp in points: np.testing.assert_array_equal(utils.sphericalFromCartesian(pp), utils._ra_dec_from_xyz(pp[0], pp[1], pp[2]))
def fovCorners(obs, side_length): """ obs is an ObservationMetaData side_length in arcminutes """ # find the center of the field of view and convert it into "Observed RA, Dec" pointing_lon, pointing_lat = _observedFromICRS(np.array([obs._pointingRA]), np.array([obs._pointingDec ]), obs_metadata=obs, epoch=2000.0) # figure out the length of the diagonal of your square field of view hypotenuse = np.sqrt(2.0 * (side_length / 60.0)**2) half_length = np.radians(0.5 * hypotenuse) # Create a fiducial field of view cetnered on the north pole. # We will take this field of viewand rotate it so that it has # the correct orientation, then translate it down the celestial # sphere to the actual position of your telescope pointing. native_lon_list = np.array([0.0, np.pi / 2.0, np.pi, 1.5 * np.pi]) native_lat_list = np.array([0.5 * np.pi - half_length] * 4) # rotate your field of view to account for the rotation of the sky rot_angle = -1.0 * obs._rotSkyPos + 0.25 * np.pi # the extra 0.25 pi is to align our field # of view so that rotSkyPos=0 puts the # northern edge vertically up (when we # created the field of view, one of the # corners was vertically up) cosRot = np.cos(rot_angle) sinRot = np.sin(rot_angle) rotz = np.array([[cosRot, sinRot, 0.0], [-sinRot, cosRot, 0.0], [0.0, 0.0, 1.0]]) xyz = cartesianFromSpherical(native_lon_list, native_lat_list) rot_xyz = [] for vec in xyz: new_xyz = np.dot(rotz, vec) rot_xyz.append(new_xyz) rot_xyz = np.array(rot_xyz) rot_lon, rot_lat = sphericalFromCartesian(rot_xyz) # translate the field of view down to the actual telescope pointing ra_obs, dec_obs = _lonLatFromNativeLonLat(rot_lon, rot_lat, pointing_lon[0], pointing_lat[0]) return np.degrees( _icrsFromObserved(ra_obs, dec_obs, obs_metadata=obs, epoch=2000.0))
def check_pt(self, pt, answer): """ Take a Cartesian point (pt) and a known htmid for that point (answer). Find the htmid for the point using findHtmid and verify that we get the expected answer. """ ra, dec = sphericalFromCartesian(pt) ii = findHtmid(np.degrees(ra), np.degrees(dec), 3) binary = '{0:b}'.format(ii) self.assertEqual(binary, answer)
def _dePrecess(self, ra_in, dec_in, obs_metadata): """ Transform a set of RA, Dec pairs by subtracting out a rotation which represents the effects of precession, nutation, and aberration. Specifically: Calculate the displacement between the boresite and the boresite corrected for precession, nutation, and aberration (not refraction). Convert boresite and corrected boresite to Cartesian coordinates. Calculate the rotation matrix to go between those Cartesian vectors. Convert [ra_in, dec_in] into Cartesian coordinates. Apply the rotation vector to those Cartesian coordinates. Convert back to ra, dec-like coordinates @param [in] ra_in is a numpy array of RA in radians @param [in] dec_in is a numpy array of Dec in radians @param [in] obs_metadata is an ObservationMetaData @param [out] ra_out is a numpy array of de-precessed RA in radians @param [out] dec_out is a numpy array of de-precessed Dec in radians """ if len(ra_in) == 0: return np.array([[], []]) # Calculate the rotation matrix to go from the precessed bore site # to the ICRS bore site xyz_bore = cartesianFromSpherical(np.array([obs_metadata._pointingRA]), np.array([obs_metadata._pointingDec])) precessedRA, precessedDec = _observedFromICRS(np.array([obs_metadata._pointingRA]), np.array([obs_metadata._pointingDec]), obs_metadata=obs_metadata, epoch=2000.0, includeRefraction=False) xyz_precessed = cartesianFromSpherical(precessedRA, precessedDec) rotMat = rotationMatrixFromVectors(xyz_precessed[0], xyz_bore[0]) xyz_list = cartesianFromSpherical(ra_in, dec_in) xyz_de_precessed = np.array([np.dot(rotMat, xx) for xx in xyz_list]) ra_deprecessed, dec_deprecessed = sphericalFromCartesian(xyz_de_precessed) return np.array([ra_deprecessed, dec_deprecessed])
def _applyPrecession(ra, dec, epoch=2000.0, mjd=None): """ _applyPrecession() applies precesion and nutation to coordinates between two epochs. Accepts RA and dec as inputs. Returns corrected RA and dec (in radians). Assumes FK5 as the coordinate system units: ra_in (radians), dec_in (radians) The precession-nutation matrix is calculated by the palpy.prenut method which uses the IAU 2006/2000A model @param [in] ra in radians @param [in] dec in radians @param [in] epoch is the epoch of the mean equinox (in years; default 2000) @param [in] mjd is an instantiation of the ModifiedJulianDate class representing the date of the observation @param [out] a 2-D numpy array in which the first row is the RA corrected for precession and nutation and the second row is the Dec corrected for precession and nutation (both in radians) """ if hasattr(ra, '__len__'): if len(ra) != len(dec): raise RuntimeError( "You supplied %d RAs but %d Decs to applyPrecession" % (len(ra), len(dec))) if mjd is None: raise RuntimeError("You need to supply applyPrecession with an mjd") # Determine the precession and nutation # palpy.prenut takes the julian epoch for the mean coordinates # and the MJD for the the true coordinates # # TODO it is not specified what this MJD should be (i.e. in which # time system it should be reckoned) rmat = palpy.prenut(epoch, mjd.TT) # Apply rotation matrix xyz = cartesianFromSpherical(ra, dec) xyz = np.dot(rmat, xyz.transpose()).transpose() raOut, decOut = sphericalFromCartesian(xyz) return np.array([raOut, decOut])
def _applyPrecession(ra, dec, epoch=2000.0, mjd=None): """ _applyPrecession() applies precesion and nutation to coordinates between two epochs. Accepts RA and dec as inputs. Returns corrected RA and dec (in radians). Assumes FK5 as the coordinate system units: ra_in (radians), dec_in (radians) The precession-nutation matrix is calculated by the palpy.prenut method which uses the IAU 2006/2000A model @param [in] ra in radians @param [in] dec in radians @param [in] epoch is the epoch of the mean equinox (in years; default 2000) @param [in] mjd is an instantiation of the ModifiedJulianDate class representing the date of the observation @param [out] a 2-D numpy array in which the first row is the RA corrected for precession and nutation and the second row is the Dec corrected for precession and nutation (both in radians) """ if hasattr(ra, '__len__'): if len(ra) != len(dec): raise RuntimeError("You supplied %d RAs but %d Decs to applyPrecession" % (len(ra), len(dec))) if mjd is None: raise RuntimeError("You need to supply applyPrecession with an mjd") # Determine the precession and nutation #palpy.prenut takes the julian epoch for the mean coordinates #and the MJD for the the true coordinates # #TODO it is not specified what this MJD should be (i.e. in which #time system it should be reckoned) rmat=palpy.prenut(epoch, mjd.TT) # Apply rotation matrix xyz = cartesianFromSpherical(ra,dec) xyz = numpy.dot(rmat,xyz.transpose()).transpose() raOut,decOut = sphericalFromCartesian(xyz) return numpy.array([raOut,decOut])
def smear_ra_dec(ra_deg, dec_deg, delta_ast, rng): xyz = cartesianFromSpherical(np.radians(ra_deg), np.radians(dec_deg)) ra_out = np.zeros(len(ra_deg), dtype=float) dec_out = np.zeros(len(dec_deg), dtype=float) for ii in range(len(ra_deg)): random_vec = rng.normal(0.0, 1.0, 3) parallel = np.dot(random_vec, xyz[ii]) random_vec -= parallel * xyz[ii] random_vec /= np.sqrt(np.dot(random_vec, random_vec)) cos_d = np.cos(delta_ast[ii]) sin_d = np.sin(delta_ast[ii]) new_xyz = cos_d * xyz[ii] + sin_d * random_vec new_xyz /= np.sqrt(np.dot(new_xyz, new_xyz)) new_ra, new_dec = sphericalFromCartesian(new_xyz) ra_out[ii] = np.degrees(new_ra) dec_out[ii] = np.degrees(new_dec) return ra_out, dec_out
def _icrsFromPhoSim(self, raPhoSim, decPhoSim, obs_metadata): """ This method will convert from the 'deprecessed' coordinates expected by PhoSim to ICRS coordinates Parameters ---------- raPhoSim is the PhoSim RA-like coordinate (in radians) decPhoSim is the PhoSim Dec-like coordinate (in radians) obs_metadata is an ObservationMetaData characterizing the telescope pointing Returns ------- raICRS in radians decICRS in radians """ # Calculate the rotation matrix to go from the ICRS bore site to the # precessed bore site xyz_bore = cartesianFromSpherical(np.array([obs_metadata._pointingRA]), np.array([obs_metadata._pointingDec])) precessedRA, precessedDec = _observedFromICRS(np.array([obs_metadata._pointingRA]), np.array([obs_metadata._pointingDec]), obs_metadata=obs_metadata, epoch=2000.0, includeRefraction=False) xyz_precessed = cartesianFromSpherical(precessedRA, precessedDec) rotMat = rotationMatrixFromVectors(xyz_bore[0], xyz_precessed[0]) # apply this rotation matrix to the PhoSim RA, Dec-like coordinates, # transforming back to "Observed" RA and Dec xyz_list = cartesianFromSpherical(raPhoSim, decPhoSim) xyz_obs = np.array([np.dot(rotMat, xx) for xx in xyz_list]) ra_obs, dec_obs = sphericalFromCartesian(xyz_obs) # convert to ICRS coordinates return _icrsFromObserved(ra_obs, dec_obs, obs_metadata=obs_metadata, epoch=2000.0, includeRefraction=False)
def testCartesianFromSpherical(self): numpy.random.seed(42) nsamples = 10 theta = numpy.random.random_sample(nsamples)*numpy.pi-0.5*numpy.pi phi = numpy.random.random_sample(nsamples)*2.0*numpy.pi points = [] for ix in range(nsamples): vv = [numpy.cos(theta[ix])*numpy.cos(phi[ix]), numpy.cos(theta[ix])*numpy.sin(phi[ix]), numpy.sin(theta[ix])] points.append(vv) points = numpy.array(points) lon, lat = utils.sphericalFromCartesian(points) outPoints = utils.cartesianFromSpherical(numpy.array(lon), numpy.array(lat)) for pp, oo in zip(points, outPoints): numpy.testing.assert_array_almost_equal(pp, oo, decimal=6)
def test_trixel_from_htmid(self): """ Check that trixelFromHtmid works by finding the htmid from an RA, Dec pair, instantiating the Trixel corresponding to that htmid, and verifying that that Trixel (and not its neighbors) contains the RA, Dec pair. """ rng = np.random.RandomState(88) n_tests = 100 for i_test in range(n_tests): pt = rng.normal(0.0, 1.0, 3) ra, dec = sphericalFromCartesian(pt) ra = np.degrees(ra) dec = np.degrees(dec) ii = findHtmid(ra, dec, 5) tt = trixelFromHtmid(ii) self.assertTrue(tt.contains(ra, dec)) tt1 = trixelFromHtmid(ii - 1) self.assertFalse(tt1.contains(ra, dec)) tt2 = trixelFromHtmid(ii + 1) self.assertFalse(tt2.contains(ra, dec))
def test_trixel_from_htmid(self): """ Check that trixelFromHtmid works by finding the htmid from an RA, Dec pair, instantiating the Trixel corresponding to that htmid, and verifying that that Trixel (and not its neighbors) contains the RA, Dec pair. """ rng = np.random.RandomState(88) n_tests = 100 for i_test in range(n_tests): pt = rng.normal(0.0, 1.0, 3) ra, dec = sphericalFromCartesian(pt) ra = np.degrees(ra) dec = np.degrees(dec) ii = findHtmid(ra, dec, 5) tt = trixelFromHtmid(ii) self.assertTrue(tt.contains(ra, dec)) tt1 = trixelFromHtmid(ii-1) self.assertFalse(tt1.contains(ra, dec)) tt2 = trixelFromHtmid(ii+1) self.assertFalse(tt2.contains(ra, dec))
def trixel_intersects_half_space(trix, hspace): """ This is a brute force method to determine whether a trixel is inside, or at least intersects, a halfspace. """ if hspace.phi > 0.25 * np.pi: raise RuntimeError("trixel_intersects_half_space is not safe for " "large HalfSpaces") # if any of the trixel's corners are within the # HalfSpace, return True raRad, decRad = sphericalFromCartesian(hspace.vector) for corner in trix.corners: raRad1, decRad1 = sphericalFromCartesian(corner) if _angularSeparation(raRad, decRad, raRad1, decRad1) < hspace.phi: return True # if the trixel contains the HalfSpace's center, # return True if trix.contains_pt(hspace.vector): return True sinphi = np.abs(np.sin(hspace.phi)) # Iterate over each pair of corners (c1, c2). For each pair, # construct a coordinate basis in which +z is in the # direction of c3, and +x is along the # unit vector defining c_i such that the angle # phi of c_j in the x,y plane is positive. This coordinate # system is such that the trixel edge defined by c1, c2 is # now along the equator of the unit sphere. Find the point # of closest approach of the HalfSpace's center to the equator. # If that point is between c1 and c2, return True. for i_c_1 in range(3): c1 = trix.corners[i_c_1] for i_c_2 in range(3): if i_c_2 <= i_c_1: continue c2 = trix.corners[i_c_2] i_c_3 = 3 - (i_c_1 + i_c_2) c3 = trix.corners[i_c_3] assert i_c_3 != i_c_2 assert i_c_3 != i_c_1 assert i_c_1 != i_c_2 z_axis = np.array([ c1[1] * c2[2] - c1[2] * c2[1], c2[0] * c1[2] - c1[0] * c2[2], c1[0] * c2[1] - c2[0] * c1[1] ]) z_axis = z_axis / np.sqrt((z_axis**2).sum()) if np.dot(z_axis, c3) < 0.0: z_axis *= -1.0 assert np.abs(1.0 - np.dot(z_axis, z_axis)) < 1.0e-10 assert np.abs(1.0 - np.dot(c1, c1)) < 1.0e-10 assert np.abs(1.0 - np.dot(c2, c2)) < 1.0e-10 assert np.abs(np.dot(z_axis, c1)) < 1.0e-10 assert np.abs(np.dot(z_axis, c2)) < 1.0e-10 # if the dot product of the center of the HalfSpace # with the z axis of the new coordinate system is # greater than the sine of the radius of the # halfspace, then there is no way that the halfspace # intersects the equator of the unit sphere in this # coordinate system if np.abs(np.dot(z_axis, hspace.vector)) > sinphi: continue x_axis = c1 y_axis = -1.0 * np.array([ x_axis[1] * z_axis[2] - x_axis[2] * z_axis[1], z_axis[0] * x_axis[2] - x_axis[0] * z_axis[2], x_axis[0] * z_axis[1] - z_axis[0] * x_axis[1] ]) cos_a = np.dot(x_axis, c2) sin_a = np.dot(y_axis, c2) if sin_a < 0.0: x_axis = c2 y_axis = -1.0 * np.array([ x_axis[1] * z_axis[2] - x_axis[2] * z_axis[1], z_axis[0] * x_axis[2] - x_axis[0] * z_axis[2], x_axis[0] * z_axis[1] - z_axis[0] * x_axis[1] ]) cos_a = np.dot(x_axis, c1) sin_a = np.dot(y_axis, c1) assert cos_a >= 0.0 assert sin_a >= 0.0 assert np.abs(1.0 - cos_a**2 - sin_a**2) < 1.0e-10 assert np.abs(np.dot(x_axis, z_axis)) < 1.0e-10 assert np.abs(np.dot(x_axis, y_axis)) < 1.0e-10 assert np.abs(np.dot(y_axis, z_axis)) < 1.0e-10 x_center = np.dot(x_axis, hspace.vector) # if the x-coordinate of the HalfSpace's center is # negative, the HalfSpace is on the opposite side # of the unit sphere; ignore this pair c1, c2 if x_center < 0.0: continue y_center = np.dot(y_axis, hspace.vector) # tan_a is the tangent of the angle between # the x_axis and the other trixel corner in # the x, y plane tan_a = sin_a / cos_a # tan_extreme is the tangent of the angle in # the x, y plane defining the point of closest # approach of the HalfSpace's center to the # equator. If this point is between c1, c2, # return True. tan_extreme = y_center / x_center if tan_extreme > 0.0 and tan_extreme < tan_a: return True return False
def __next__(self): if self._tile_to_do == 0: self._valid_tiles = 0 self._n_chunks += 1 if self.chunk_size is None: results = self._galaxy_query.fetchall() elif self.chunk_size is not None: results = self._galaxy_query.fetchmany(self.chunk_size) else: raise StopIteration self._galaxy_cache = self.dbobj._convert_results_to_numpy_recarray_catalogDBObj(results) self._n_rows += len(self._galaxy_cache) if len(self._galaxy_cache) == 0: raise StopIteration current_chunk = copy.deepcopy(self._galaxy_cache) rot_mat = self._rotate_to_sky[self._tile_to_do] bounds = self._00_bounds[self._tile_to_do] sky_tile = self._sky_tile[self._tile_to_do] tile_idx = self._tile_idx[self._tile_to_do] make_the_cut = None for bb in bounds: htmid_min = bb[0] << 2*(21-self._trixel_search_level) htmid_max = (bb[1]+1) << 2*(21-self._trixel_search_level) valid = ((current_chunk['htmid']>=htmid_min) & (current_chunk['htmid']<=htmid_max)) if make_the_cut is None: make_the_cut = valid else: make_the_cut |= valid good_dexes = np.where(make_the_cut)[0] if len(good_dexes) < len(current_chunk): current_chunk = current_chunk[good_dexes] self._tile_to_do += 1 if self._tile_to_do >= len(self._rotate_to_sky): self._tile_to_do = 0 if len(current_chunk) == 0: return self.__next__() xyz = cartesianFromSpherical(np.radians(current_chunk['ra']), np.radians(current_chunk['dec'])) xyz_sky = np.dot(rot_mat, xyz.transpose()).transpose() final_cut = sky_tile.contains_many_pts(xyz_sky) final_cut &= self.obs_hs.contains_many_pts(xyz_sky) final_cut = np.where(final_cut) xyz_sky = xyz_sky[final_cut] current_chunk = current_chunk[final_cut] if len(current_chunk) == 0: return self.__next__() ra_dec_sky = sphericalFromCartesian(xyz_sky) current_chunk['ra'] = np.degrees(ra_dec_sky[0]) % 360.0 current_chunk['dec'] = np.degrees(ra_dec_sky[1]) % 360.0 current_chunk['dec'] = np.where(current_chunk['dec']<270.0, current_chunk['dec'], current_chunk['dec']-360.0) current_chunk['dec'] = np.where(np.abs(current_chunk['dec'])<=90.0, current_chunk['dec'], 180.0-current_chunk['dec']) if self._has_J2000: current_chunk['raJ2000'] = ra_dec_sky[0] % (2.0*np.pi) _dec = ra_dec_sky[1] % (2.0*np.pi) current_chunk['decJ2000'] = np.where(_dec<1.5*np.pi, _dec, _dec-2.0*np.pi) current_chunk['decJ2000'] = np.where(np.abs(current_chunk['decJ2000'])<=0.5*np.pi, current_chunk['decJ2000'], np.pi-current_chunk['decJ2000']) #>>> r2 = recfunc.append_fields(r,['d','e'],d,dtypes=[float, int], usemask=False, asrecarray=True) galtileid = tile_idx*100000000+current_chunk['id'] current_chunk = np_recfn.append_fields(current_chunk, ['galtileid'], [galtileid], dtypes=[int], usemask=False, asrecarray=True) self._valid_tiles += 1 self._rows_kept += len(current_chunk) return self._postprocess_results(current_chunk)
def __init__(self, dbobj, colnames, obs_metadata, chunk_size, constraint): """ Parameters ---------- dbobj -- a CatalogDBObject connected to the 'galaxies' table on the UW CatSim server colnames -- a list of the columns to query chunk_size -- size of chunks to return constraint -- a string specifying a SQL 'WHERE' clause """ self.arbitrarySQL = False self.dbobj = dbobj if 'ra' not in colnames: query_colnames = ['htmid', 'galid', 'ra', 'dec'] + colnames else: query_colnames = ['htmid', 'galid'] + colnames self._column_query = dbobj._get_column_query(query_colnames) self.chunk_size = chunk_size tile_idx_list = np.sort(self._find_tiles(obs_metadata)) self._trixel_search_level = 9 self.obs_metadata = obs_metadata total_trixel_bounds = [] self._00_bounds = [] self._rotate_to_sky = [] self._sky_tile = [] self._tile_idx = [] # construct a HalfSpace based on obs_metadata self.obs_hs = halfSpaceFromRaDec(obs_metadata.pointingRA, obs_metadata.pointingDec, obs_metadata.boundLength) obs_where_clause = "(" for tile_idx in tile_idx_list: rotate_to_00 = self.uwgalaxy_tiles.rotation_matrix(tile_idx) # find the bounds for trixels contained by the field of view # when rotated from the current tile to RA=Dec=0 new_vv = np.dot(rotate_to_00, self.obs_hs.vector) new_ra, new_dec = sphericalFromCartesian(new_vv) new_obs = ObservationMetaData(pointingRA=np.degrees(new_ra), pointingDec=np.degrees(new_dec), boundType='circle', boundLength=self.obs_metadata.boundLength) if obs_where_clause != "(": obs_where_clause += " OR (" else: obs_where_clause += "(" obs_where_clause += new_obs.bounds.to_SQL('ra', 'dec') obs_where_clause += ")" obs_hs_00 = HalfSpace(new_vv, self.obs_hs.dd) obs_hs_00_trixels = obs_hs_00.findAllTrixels(self._trixel_search_level) # find the trixels in the current tile when it is rotated # to RA=Dec=0 sky_tile = self.uwgalaxy_tiles.tile(tile_idx) single_tile = sky_tile.rotate(rotate_to_00) local_bounds = single_tile.find_all_trixels(self._trixel_search_level) local_bounds = HalfSpace.join_trixel_bound_sets(local_bounds, obs_hs_00_trixels) total_trixel_bounds += local_bounds self._sky_tile.append(sky_tile) self._00_bounds.append(local_bounds) self._rotate_to_sky.append(np.linalg.inv(rotate_to_00)) self._tile_idx.append(tile_idx) obs_where_clause += ")" total_trixel_bounds = HalfSpace.merge_trixel_bounds(total_trixel_bounds) where_clause = "(" for i_bound, bound in enumerate(total_trixel_bounds): if i_bound>0: where_clause += " OR " htmid_min = bound[0] << 2*(21-self._trixel_search_level) htmid_max = (bound[1]+1) << 2*(21-self._trixel_search_level) assert levelFromHtmid(htmid_min) == 21 assert levelFromHtmid(htmid_max) == 21 assert htmid_min<htmid_max where_clause += "(htmid>=%d AND htmid<=%d)" % (htmid_min, htmid_max) where_clause += ")" where_clause += " AND " where_clause += obs_where_clause if constraint is not None: where_clause += " AND (%s)" % text(constraint) query = self._column_query query = query.filter(text(where_clause)) query = query.order_by('redshift') self._galaxy_query = dbobj.connection.session.execute(query) self._tile_to_do = 0 self._has_J2000 = False if 'raJ2000' in colnames: self._has_J2000 = True self._valid_tiles = 0 self._n_chunks = 0 self._n_rows = 0 self._rows_kept = 0
def trixel_intersects_half_space(trix, hspace): """ This is a brute force method to determine whether a trixel is inside, or at least intersects, a halfspace. """ if hspace.phi > 0.25*np.pi: raise RuntimeError("trixel_intersects_half_space is not safe for " "large HalfSpaces") # if any of the trixel's corners are within the # HalfSpace, return True raRad, decRad = sphericalFromCartesian(hspace.vector) for corner in trix.corners: raRad1, decRad1 = sphericalFromCartesian(corner) if _angularSeparation(raRad, decRad, raRad1, decRad1) < hspace.phi: return True # if the trixel contains the HalfSpace's center, # return True if trix.contains_pt(hspace.vector): return True sinphi = np.abs(np.sin(hspace.phi)) # Iterate over each pair of corners (c1, c2). For each pair, # construct a coordinate basis in which +z is in the # direction of c3, and +x is along the # unit vector defining c_i such that the angle # phi of c_j in the x,y plane is positive. This coordinate # system is such that the trixel edge defined by c1, c2 is # now along the equator of the unit sphere. Find the point # of closest approach of the HalfSpace's center to the equator. # If that point is between c1 and c2, return True. for i_c_1 in range(3): c1 = trix.corners[i_c_1] for i_c_2 in range(3): if i_c_2 <= i_c_1: continue c2 = trix.corners[i_c_2] i_c_3 = 3 - (i_c_1+i_c_2) c3 = trix.corners[i_c_3] assert i_c_3 != i_c_2 assert i_c_3 != i_c_1 assert i_c_1 != i_c_2 z_axis = np.array([c1[1]*c2[2]-c1[2]*c2[1], c2[0]*c1[2]-c1[0]*c2[2], c1[0]*c2[1]-c2[0]*c1[1]]) z_axis = z_axis/np.sqrt((z_axis**2).sum()) if np.dot(z_axis, c3) < 0.0: z_axis *= -1.0 assert np.abs(1.0-np.dot(z_axis, z_axis)) < 1.0e-10 assert np.abs(1.0-np.dot(c1, c1)) < 1.0e-10 assert np.abs(1.0-np.dot(c2, c2)) < 1.0e-10 assert np.abs(np.dot(z_axis, c1)) < 1.0e-10 assert np.abs(np.dot(z_axis, c2)) < 1.0e-10 # if the dot product of the center of the HalfSpace # with the z axis of the new coordinate system is # greater than the sine of the radius of the # halfspace, then there is no way that the halfspace # intersects the equator of the unit sphere in this # coordinate system if np.abs(np.dot(z_axis, hspace.vector)) > sinphi: continue x_axis = c1 y_axis = -1.0*np.array([x_axis[1]*z_axis[2]-x_axis[2]*z_axis[1], z_axis[0]*x_axis[2]-x_axis[0]*z_axis[2], x_axis[0]*z_axis[1]-z_axis[0]*x_axis[1]]) cos_a = np.dot(x_axis, c2) sin_a = np.dot(y_axis, c2) if sin_a < 0.0: x_axis = c2 y_axis = -1.0*np.array([x_axis[1]*z_axis[2]-x_axis[2]*z_axis[1], z_axis[0]*x_axis[2]-x_axis[0]*z_axis[2], x_axis[0]*z_axis[1]-z_axis[0]*x_axis[1]]) cos_a = np.dot(x_axis, c1) sin_a = np.dot(y_axis, c1) assert cos_a >= 0.0 assert sin_a >= 0.0 assert np.abs(1.0-cos_a**2-sin_a**2) < 1.0e-10 assert np.abs(np.dot(x_axis, z_axis)) < 1.0e-10 assert np.abs(np.dot(x_axis, y_axis)) < 1.0e-10 assert np.abs(np.dot(y_axis, z_axis)) < 1.0e-10 x_center = np.dot(x_axis, hspace.vector) # if the x-coordinate of the HalfSpace's center is # negative, the HalfSpace is on the opposite side # of the unit sphere; ignore this pair c1, c2 if x_center < 0.0: continue y_center = np.dot(y_axis, hspace.vector) # tan_a is the tangent of the angle between # the x_axis and the other trixel corner in # the x, y plane tan_a = sin_a/cos_a # tan_extreme is the tangent of the angle in # the x, y plane defining the point of closest # approach of the HalfSpace's center to the # equator. If this point is between c1, c2, # return True. tan_extreme = y_center/x_center if tan_extreme > 0.0 and tan_extreme < tan_a: return True return False