def geoFromICRS(icrsP, icrsV, agData): """ Converts ICRS coordinates to apparent geocentric coordinates. Inputs: - icrsP(3) ICRS cartesian position (au) - icrsV(3) ICRS cartesian velocity (au/year) (e.g. proper motion and radial velocity) - agData an AppGeoData object containing star-independent apparent geocentric data Returns: - appGeoP(3) apparent geocentric cartesian position (au), a numpy.array Warnings: - Uses the approximation ICRS = FK5 J2000. - Not fully accurate for solar system objects. Details: The following approximations have been used: - FK5 J2000 is the same as ICRS - The annual aberration correction is only appropriate for stellar objects; it introduces unacceptable errors for solar system objects. - No correction is applied for the bending of light by sun's gravity. This introduces errors on the order of 0.02" at a distance of 20 degrees from the sun (Wallace, 1986) References: ABERAT, from the APPLE (J2000) subroutine library, U.S. Naval Observatory P.T. Wallace's MAPQK routine P.T. Wallace, "Proposals for Keck Tel. Point. Algorithms", 1986 (unpub.) "The Astronomical Almanac" for 1978, U.S. Naval Observatory """ # make sure inputs are floating-point numpy arrays icrsP = numpy.asarray(icrsP, dtype=float) icrsV = numpy.asarray(icrsV, dtype=float) # correct for velocity and Earth's offset from the barycenter p2 = icrsP + icrsV * agData.dtPM - agData.bPos # here is where the correction for sun's gravity belongs # correct for annual aberration p2Dir, p2Mag = llv.vn(p2) dot2 = numpy.dot(p2Dir, agData.bVelC) # i.e. dot2 = p2 dot bVelC / |p2| # but handles |p2|=0 gracefully (by setting dot2 to 0) vfac = p2Mag * (1.0 + dot2 / (1.0 + agData.bGamma)) p3 = ((p2 * agData.bGamma) + (vfac * agData.bVelC)) / (1.0 + dot2) # correct position for precession and nutation return numpy.dot(agData.pnMat, p3)
def geoFromICRS(icrsP, icrsV, agData): """ Converts ICRS coordinates to apparent geocentric coordinates. Inputs: - icrsP(3) ICRS cartesian position (au) - icrsV(3) ICRS cartesian velocity (au/year) (e.g. proper motion and radial velocity) - agData an AppGeoData object containing star-independent apparent geocentric data Returns: - appGeoP(3) apparent geocentric cartesian position (au), a numpy.array Warnings: - Uses the approximation ICRS = FK5 J2000. - Not fully accurate for solar system objects. Details: The following approximations have been used: - FK5 J2000 is the same as ICRS - The annual aberration correction is only appropriate for stellar objects; it introduces unacceptable errors for solar system objects. - No correction is applied for the bending of light by sun's gravity. This introduces errors on the order of 0.02" at a distance of 20 degrees from the sun (Wallace, 1986) References: ABERAT, from the APPLE (J2000) subroutine library, U.S. Naval Observatory P.T. Wallace's MAPQK routine P.T. Wallace, "Proposals for Keck Tel. Point. Algorithms", 1986 (unpub.) "The Astronomical Almanac" for 1978, U.S. Naval Observatory """ # make sure inputs are floating-point numpy arrays icrsP = numpy.asarray(icrsP, dtype = float) icrsV = numpy.asarray(icrsV, dtype = float) # correct for velocity and Earth's offset from the barycenter p2 = icrsP + icrsV * agData.dtPM - agData.bPos # here is where the correction for sun's gravity belongs # correct for annual aberration p2Dir, p2Mag = llv.vn(p2) dot2 = numpy.dot(p2Dir, agData.bVelC) # i.e. dot2 = p2 dot bVelC / |p2| # but handles |p2|=0 gracefully (by setting dot2 to 0) vfac = p2Mag * (1.0 + dot2 / (1.0 + agData.bGamma)) p3 = ((p2 * agData.bGamma) + (vfac * agData.bVelC)) / (1.0 + dot2) # correct position for precession and nutation return numpy.dot(agData.pnMat, p3)
def geoFromTopo(appTopoP, last, obsData): """ Converts apparent topocentric coordinates to apparent geocentric coordinates. Inputs: - appTopoP(3) apparent topocentric cartesian position (au) (az/alt) - last local apparent sidereal time, as an angle (deg) - obsData an ObserverData object Returns: - appGeoP(3) apparent geocentric cartesian position (au) (RA/Dec), a numpy.array Warnings: Computation of diurnal aberration is slightly approximate (see notes below), but not enough to make a difference on the sky. References: see topoFromGeo (note: the variables are identical) """ # compute useful quantities sinLAST = RO.MathUtil.sind(last) cosLAST = RO.MathUtil.cosd(last) # rotate apparent topocentric position to HA/Dec; posC = haDecFromAzAlt(appTopoP, obsData.latitude) # remove correction for diurnal aberration # following Pat Wallace's sla_OAPQK, the same equation is used # as applying the correction, but the sign of obsData.diurAbVecMag is reversed cDir, cMag = llv.vn(posC) diurAbScaleCorr = 1.0 + (obsData.diurAbVecMag * cDir[1]) posB = numpy.array(( posC[0] * diurAbScaleCorr, (posC[1] - (obsData.diurAbVecMag * cMag)) * diurAbScaleCorr, posC[2] * diurAbScaleCorr, )) # correct position for diurnal parallax (needed for planets, not stars) posA = posB + obsData.p # rotate position from (-HA)/Dec to RA/Dec (but cartesian) return numpy.array(( cosLAST * posA[0] - sinLAST * posA[1], sinLAST * posA[0] + cosLAST * posA[1], posA[2], ))
def geoFromTopo(appTopoP, last, obsData): """ Converts apparent topocentric coordinates to apparent geocentric coordinates. Inputs: - appTopoP(3) apparent topocentric cartesian position (au) (az/alt) - last local apparent sidereal time, as an angle (deg) - obsData an ObserverData object Returns: - appGeoP(3) apparent geocentric cartesian position (au) (RA/Dec), a numpy.array Warnings: Computation of diurnal aberration is slightly approximate (see notes below), but not enough to make a difference on the sky. References: see topoFromGeo (note: the variables are identical) """ # compute useful quantities sinLAST = RO.MathUtil.sind (last) cosLAST = RO.MathUtil.cosd (last) # rotate apparent topocentric position to HA/Dec; posC = haDecFromAzAlt (appTopoP, obsData.latitude) # remove correction for diurnal aberration # following Pat Wallace's sla_OAPQK, the same equation is used # as applying the correction, but the sign of obsData.diurAbVecMag is reversed cDir, cMag = llv.vn(posC) diurAbScaleCorr = 1.0 + (obsData.diurAbVecMag * cDir[1]) posB = numpy.array (( posC[0] * diurAbScaleCorr, (posC[1] - (obsData.diurAbVecMag * cMag)) * diurAbScaleCorr, posC[2] * diurAbScaleCorr, )) # correct position for diurnal parallax (needed for planets, not stars) posA = posB + obsData.p # rotate position from (-HA)/Dec to RA/Dec (but cartesian) return numpy.array(( cosLAST * posA[0] - sinLAST * posA[1], sinLAST * posA[0] + cosLAST * posA[1], posA[2], ))
def topoFromGeo(appGeoP, last, obsData): """ Converts apparent geocentric coordinates to apparent topocentric coordinates (not corrected for refraction). Inputs: - appGeoP(3) current app. geocentric cartesian position (au) (RA/Dec) - last local apparent sidereal time, as an angle (deg) - obsData an ObserverData object Returns: - appTopo(3) apparent topocentric cartesian position (au) (az/alt), a numpy.array Details: The following approximation is used: - pole wander is ignored References: P.T. Wallace, "Proposals for Keck Tel. Pointing Algorithms", 1986 (unpub) """ sinLAST = RO.MathUtil.sind(last) cosLAST = RO.MathUtil.cosd(last) # rotate position and offset to (-ha)/Dec (still cartesian, of course) posA = numpy.array(( cosLAST * appGeoP[0] + sinLAST * appGeoP[1], -sinLAST * appGeoP[0] + cosLAST * appGeoP[1], appGeoP[2], )) # correct position for diurnal parallax posB = posA - obsData.p # correct position for diurnal aberration # follows Pat Wallace's AOPQK bDir, bMag = llv.vn(posB) diurAbScaleCorr = 1.0 - (obsData.diurAbVecMag * bDir[1]) posC = numpy.array(( posB[0] * diurAbScaleCorr, (posB[1] + (obsData.diurAbVecMag * bMag)) * diurAbScaleCorr, posB[2] * diurAbScaleCorr, )) # rotate position (posC) to alt/az; return azAltFromHADec(posC, obsData.latitude)
def topoFromGeo(appGeoP, last, obsData): """ Converts apparent geocentric coordinates to apparent topocentric coordinates (not corrected for refraction). Inputs: - appGeoP(3) current app. geocentric cartesian position (au) (RA/Dec) - last local apparent sidereal time, as an angle (deg) - obsData an ObserverData object Returns: - appTopo(3) apparent topocentric cartesian position (au) (az/alt), a numpy.array Details: The following approximation is used: - pole wander is ignored References: P.T. Wallace, "Proposals for Keck Tel. Pointing Algorithms", 1986 (unpub) """ sinLAST = RO.MathUtil.sind (last) cosLAST = RO.MathUtil.cosd (last) # rotate position and offset to (-ha)/Dec (still cartesian, of course) posA = numpy.array(( cosLAST * appGeoP[0] + sinLAST * appGeoP[1], -sinLAST * appGeoP[0] + cosLAST * appGeoP[1], appGeoP[2], )) # correct position for diurnal parallax posB = posA - obsData.p # correct position for diurnal aberration # follows Pat Wallace's AOPQK bDir, bMag = llv.vn(posB) diurAbScaleCorr = 1.0 - (obsData.diurAbVecMag * bDir[1]) posC = numpy.array (( posB[0] * diurAbScaleCorr, (posB[1] + (obsData.diurAbVecMag * bMag)) * diurAbScaleCorr, posB[2] * diurAbScaleCorr, )) # rotate position (posC) to alt/az; return azAltFromHADec (posC, obsData.latitude)
def icrsFromGeo (appGeoP, agData): """ Converts apparent geocentric coordinates to ICRS. Inputs: - appGeoP(3) apparent geocentric cartesian position (au) - agData an AppGeoData object containing star-independent apparent geocentric data Returns - icrsP ICRS cartesian position (au), a numpy.array Warnings: - Uses the approximation ICRS = FK5 J2000.0 - Not fully accurate for solar system objects. - Requires iteration, so it will be slower than GeoFromICRS Error Conditions: Raises RuntimeError if iteration fails to converge. Details: The following approximations have been used: - The annual aberration correction is only appropriate for stellar objects; it introduces unacceptable errors for solar system objects. - No correction is applied for the bending of light by sun's gravity. This introduces errors on the order of 0.02" at a distance of 20 degrees from the sun (Wallace, 1986) icrsFromGeo performs the inverse transform of geoFromICRS. Unfortunately, some of the equations (e.g. annual aberration) are not invertable, so they have been solved by iteration. To make the code easier to follow, the symbols used here are identical to those used in GeoFromICRS. The convergence criterion is set by the magic numbers _MaxIter and _Accuracy. References: GeoFromICRS aberat, an APPLE (J2000) subroutine; U.S. Naval Observatory P.T. Wallace's MAPQK routine P.T. Wallace, "Proposals for Keck Tel. Point. Algorithms," 1986 (unpub.) "The Astronomical Almanac" for 1978, U.S. Naval Observatory """ # compute constants needed to check iteration approxMagP = RO.MathUtil.vecMag(appGeoP) allowedErr = _Accuracy * approxMagP # correct position for nutation and precession p3 = numpy.dot(numpy.transpose(agData.pnMat), appGeoP) # iterively correct for annual aberration itNum = 1 maxErr = approxMagP p2 = p3.copy() while (maxErr > allowedErr) and (itNum <= _MaxIter): itNum += 1 p2Dir, p2Mag = llv.vn (p2) dot2 = numpy.dot(p2Dir, agData.bVelC) vfac = p2Mag * (1.0 + dot2 / (1.0 + agData.bGamma)) oldP2 = p2.copy() p2 = (((1.0 + dot2) * p3) - (vfac * agData.bVelC)) / agData.bGamma maxErr = max (abs (p2 - oldP2)) # if no convergence, complain and exit if (itNum > _MaxIter): raise RuntimeError('aberration correction failed to converge;' + \ 'after %s iterations; fractional error = %s, max allowed = %s' \ % (_MaxIter, maxErr, allowedErr)) # here is where the (iterative) correction for sun's gravity belongs # correct for Earth's offset from the barycenter return p2 + agData.bPos
def icrsFromGeo(appGeoP, agData): """ Converts apparent geocentric coordinates to ICRS. Inputs: - appGeoP(3) apparent geocentric cartesian position (au) - agData an AppGeoData object containing star-independent apparent geocentric data Returns - icrsP ICRS cartesian position (au), a numpy.array Warnings: - Uses the approximation ICRS = FK5 J2000.0 - Not fully accurate for solar system objects. - Requires iteration, so it will be slower than GeoFromICRS Error Conditions: Raises RuntimeError if iteration fails to converge. Details: The following approximations have been used: - The annual aberration correction is only appropriate for stellar objects; it introduces unacceptable errors for solar system objects. - No correction is applied for the bending of light by sun's gravity. This introduces errors on the order of 0.02" at a distance of 20 degrees from the sun (Wallace, 1986) icrsFromGeo performs the inverse transform of geoFromICRS. Unfortunately, some of the equations (e.g. annual aberration) are not invertable, so they have been solved by iteration. To make the code easier to follow, the symbols used here are identical to those used in GeoFromICRS. The convergence criterion is set by the magic numbers _MaxIter and _Accuracy. References: GeoFromICRS aberat, an APPLE (J2000) subroutine; U.S. Naval Observatory P.T. Wallace's MAPQK routine P.T. Wallace, "Proposals for Keck Tel. Point. Algorithms," 1986 (unpub.) "The Astronomical Almanac" for 1978, U.S. Naval Observatory """ # compute constants needed to check iteration approxMagP = RO.MathUtil.vecMag(appGeoP) allowedErr = _Accuracy * approxMagP # correct position for nutation and precession p3 = numpy.dot(numpy.transpose(agData.pnMat), appGeoP) # iterively correct for annual aberration itNum = 1 maxErr = approxMagP p2 = p3.copy() while (maxErr > allowedErr) and (itNum <= _MaxIter): itNum += 1 p2Dir, p2Mag = llv.vn(p2) dot2 = numpy.dot(p2Dir, agData.bVelC) vfac = p2Mag * (1.0 + dot2 / (1.0 + agData.bGamma)) oldP2 = p2.copy() p2 = (((1.0 + dot2) * p3) - (vfac * agData.bVelC)) / agData.bGamma maxErr = max(abs(p2 - oldP2)) # if no convergence, complain and exit if (itNum > _MaxIter): raise RuntimeError('aberration correction failed to converge;' + \ 'after %s iterations; fractional error = %s, max allowed = %s' \ % (_MaxIter, maxErr, allowedErr)) # here is where the (iterative) correction for sun's gravity belongs # correct for Earth's offset from the barycenter return p2 + agData.bPos