Example #1
0
    def testGetVectorValue(self):
        """Test if getVector() returns the expected value.

        The test includes conformance to vector-angle conventions.
        """
        for lon, lat, vector in [
            (0.0 * degrees, 0.0 * degrees,
             lsst.sphgeom.Vector3d(1.0, 0.0, 0.0)),
            (90.0 * degrees, 0.0 * degrees,
             lsst.sphgeom.Vector3d(0.0, 1.0, 0.0)),
            (0.0 * degrees, 90.0 * degrees,
             lsst.sphgeom.Vector3d(0.0, 0.0, 1.0)),
        ]:
            for point in (
                    SpherePoint(lon, lat),
                    SpherePoint(lon.asDegrees(), lat.asDegrees(), degrees),
                    SpherePoint(lon.asRadians(), lat.asRadians(), radians),
            ):
                newVector = point.getVector()
                self.assertIsInstance(newVector, lsst.sphgeom.UnitVector3d)
                for oldElement, newElement in zip(vector, newVector):
                    self.assertAlmostEqual(oldElement, newElement)

                # Convert back to spherical.
                newLon, newLat = SpherePoint(newVector)
                self.assertAlmostEqual(newLon.asDegrees(), lon.asDegrees())
                self.assertAlmostEqual(newLat.asDegrees(), lat.asDegrees())

        # Try some un-normalized ones, too.
        pointList = [
            ((0.0, 0.0), lsst.sphgeom.Vector3d(1.3, 0.0, 0.0)),
            ((90.0, 0.0), lsst.sphgeom.Vector3d(0.0, 1.2, 0.0)),
            ((0.0, 90.0), lsst.sphgeom.Vector3d(0.0, 0.0, 2.3)),
            ((0.0, 0.0), lsst.sphgeom.Vector3d(0.5, 0.0, 0.0)),
            ((90.0, 0.0), lsst.sphgeom.Vector3d(0.0, 0.7, 0.0)),
            ((0.0, 90.0), lsst.sphgeom.Vector3d(0.0, 0.0, 0.9)),
        ]

        for lonLat, vector in pointList:
            # Only convert from vector to spherical.
            point = SpherePoint(vector)
            newLon, newLat = point
            self.assertAlmostEqual(lonLat[0], newLon.asDegrees())
            self.assertAlmostEqual(lonLat[1], newLat.asDegrees())
            vector = lsst.sphgeom.Vector3d(point.getVector())
            self.assertAlmostEqual(1.0, vector.getSquaredNorm())

        # Ill-defined points should be all NaN after normalization
        cleanValues = [0.5, -0.3, 0.2]
        badValues = [nan, inf, -inf]
        for i in range(3):
            for badValue in badValues:
                values = cleanValues[:]
                values[i] = badValue
                nonFiniteVector = lsst.sphgeom.Vector3d(*values)
                for element in SpherePoint(nonFiniteVector).getVector():
                    self.assertTrue(math.isnan(element))
    def testGetVectorValue(self):
        """Test if getVector() returns the expected value.

        The test includes conformance to vector-angle conventions.
        """
        for lon, lat, vector in [
            (0.0*degrees, 0.0*degrees, lsst.sphgeom.Vector3d(1.0, 0.0, 0.0)),
            (90.0*degrees, 0.0*degrees, lsst.sphgeom.Vector3d(0.0, 1.0, 0.0)),
            (0.0*degrees, 90.0*degrees, lsst.sphgeom.Vector3d(0.0, 0.0, 1.0)),
        ]:
            for point in (
                SpherePoint(lon, lat),
                SpherePoint(lon.asDegrees(), lat.asDegrees(), degrees),
                SpherePoint(lon.asRadians(), lat.asRadians(), radians),
            ):
                newVector = point.getVector()
                self.assertIsInstance(newVector, lsst.sphgeom.UnitVector3d)
                for oldElement, newElement in zip(vector, newVector):
                    self.assertAlmostEqual(oldElement, newElement)

                # Convert back to spherical.
                newLon, newLat = SpherePoint(newVector)
                self.assertAlmostEqual(newLon.asDegrees(), lon.asDegrees())
                self.assertAlmostEqual(newLat.asDegrees(), lat.asDegrees())

        # Try some un-normalized ones, too.
        pointList = [
            ((0.0, 0.0), lsst.sphgeom.Vector3d(1.3, 0.0, 0.0)),
            ((90.0, 0.0), lsst.sphgeom.Vector3d(0.0, 1.2, 0.0)),
            ((0.0, 90.0), lsst.sphgeom.Vector3d(0.0, 0.0, 2.3)),
            ((0.0, 0.0), lsst.sphgeom.Vector3d(0.5, 0.0, 0.0)),
            ((90.0, 0.0), lsst.sphgeom.Vector3d(0.0, 0.7, 0.0)),
            ((0.0, 90.0), lsst.sphgeom.Vector3d(0.0, 0.0, 0.9)),
        ]

        for lonLat, vector in pointList:
            # Only convert from vector to spherical.
            point = SpherePoint(vector)
            newLon, newLat = point
            self.assertAlmostEqual(lonLat[0], newLon.asDegrees())
            self.assertAlmostEqual(lonLat[1], newLat.asDegrees())
            vector = lsst.sphgeom.Vector3d(point.getVector())
            self.assertAlmostEqual(1.0, vector.getSquaredNorm())

        # Ill-defined points should be all NaN after normalization
        cleanValues = [0.5, -0.3, 0.2]
        badValues = [nan, inf, -inf]
        for i in range(3):
            for badValue in badValues:
                values = cleanValues[:]
                values[i] = badValue
                nonFiniteVector = lsst.sphgeom.Vector3d(*values)
                for element in SpherePoint(nonFiniteVector).getVector():
                    self.assertTrue(math.isnan(element))
Example #3
0
 def testToUnitXZY(self):
     """Test that the numpy-vectorized transformation from (lat, lon) to
     (x, y, z) matches SpherePoint.getVector().
     """
     for units in (degrees, radians):
         scale = float(180.0 * degrees) / float(1.0 * units)
         lon = scale * np.random.rand(5, 3)
         lat = scale * (np.random.rand(5, 3) - 0.5)
     x, y, z = SpherePoint.toUnitXYZ(longitude=lon,
                                     latitude=lat,
                                     units=units)
     for i in range(lon.shape[0]):
         for j in range(lon.shape[1]):
             s = SpherePoint(lon[i, j], lat[i, j], units)
             u1 = s.getVector()
             u2 = lsst.sphgeom.UnitVector3d(x=x[i, j], y=y[i, j], z=z[i, j])
             self.assertFloatsAlmostEqual(np.array(u1, dtype=float),
                                          np.array(u2, dtype=float))
Example #4
0
def computeAzAltFromBasePupil(vectorBase, vectorPupil):
    """Compute az/alt from a vector in the base frame
    and the same vector in the pupil frame.

    Parameters
    ----------
    vectorBase : `iterable` of three `float`
        3-dimensional vector in the :ref:`base frame
        <lsst.cbp.base_frame>`.
    vectorPupil : `iterable` of `float`
        The same vector in the :ref:`pupil frame <lsst.cbp.pupil_frame>`.
        This vector should be within 45 degrees or so of the optical axis
        for accurate results.

    Returns
    -------
    pupilAzAlt : `lsst.geom.SpherePoint`
        Pointing of the pupil frame as :ref:`internal azimuth, altitude
        <lsst.cbp.internal_angles>`.

    Raises
    ------
    ValueError
        If vectorPupil x <= 0

    Notes
    -----
    The magnitude of each vector is ignored, except that a reasonable
    magnitude is required in order to compute an accurate unit vector.
    """
    if vectorPupil[0] <= 0:
        raise ValueError("vectorPupil x must be > 0: {}".format(vectorPupil))

    # Compute telescope altitude using:
    #
    #     base z = sin(alt) pupil x + cos(alt) pupil z
    #
    # One way to derive this is from the last row of an Euler rotation
    # matrix listed in the comments for convertVectorFromBaseToPupil.
    spBase = SpherePoint(Vector3d(*vectorBase))
    spPupil = SpherePoint(Vector3d(*vectorPupil))
    xb, yb, zb = spBase.getVector()
    xp, yp, zp = spPupil.getVector()
    factor = 1 / math.fsum((xp**2, zp**2))
    addend1 = xp * zb
    addend2 = zp * math.sqrt(math.fsum((xp**2, zp**2, -zb**2)))
    if zp == 0:
        sinAlt = zb / xp
    else:
        sinAlt = factor * (addend1 - addend2)
    alt = math.asin(sinAlt) * radians

    # Consider the spherical triangle connecting the telescope pointing
    # (pupil frame x axis), the vector, and zenith (the base frame z axis).
    # The length of all sides is known:
    # - sideA is the side connecting the vector to the pupil frame x axis
    #         (since 0, 0 is a unit vector pointing along pupil frame x);
    # - sideB is the side connecting telescope pointing to the zenith
    # - sideC is the side connecting the vector to the zenith
    #
    # Solve for angleA, the angle between the sides at the zenith;
    # that angle is the difference in azimuth between the telescope pointing
    # and the azimuth of the base vector.
    sideA = SpherePoint(0, 0, radians).separation(spPupil).asRadians()
    sideB = math.pi / 2 - alt.asRadians()
    sideC = math.pi / 2 - spBase[1].asRadians()

    # sideA can be small or zero so use a half angle formula
    # sides B and C will always be well away from 0 and 180 degrees
    semiPerimeter = 0.5 * math.fsum((sideA, sideB, sideC))
    sinHalfAngleA = math.sqrt(
        math.sin(semiPerimeter - sideB) * math.sin(semiPerimeter - sideC) /
        (math.sin(sideB) * math.sin(sideC)))
    daz = 2 * math.asin(sinHalfAngleA) * radians
    if spPupil[0].wrapCtr() > 0:
        daz = -daz
    az = spBase[0] + daz
    global _RecordError
    if _RecordError:  # to study sources of numerical imprecision
        global _ErrorLimitArcsec, _ErrorList
        sp = SpherePoint(az, alt)
        vectorBaseRT = convertVectorFromPupilToBase(vectorPupil, sp)
        errorArcsec = SpherePoint(Vector3d(*vectorBaseRT)).separation(
            SpherePoint(Vector3d(*vectorBase))).asArcseconds()
        if errorArcsec > _ErrorLimitArcsec:
            _ErrorList.append((errorArcsec, vectorBase, vectorPupil))
    return SpherePoint(az, alt)
Example #5
0
 def trim(row):
     coord = SpherePoint(row[self.config.raColName],
                         row[self.config.decColName], radians)
     return region.contains(coord.getVector())