00001 /* 00002 * Copyright (C) 2007 Jolien Creighton, Reinhard Prix, Teviet Creighton, John Whelan 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with with program; see the file COPYING. If not, write to the 00016 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 00017 * MA 02111-1307 USA 00018 */ 00019 00020 /** \file 00021 * \ingroup SkyCoordinates 00022 * \author Creighton, T. D. 00023 * \date $Date: 2008/05/22 19:27:42 $ 00024 * \brief Converts among equatorial, geographic, and horizon coordinates. 00025 * 00026 * $Id: TerrestrialCoordinates.c,v 1.20 2008/05/22 19:27:42 teviet Exp $ 00027 * 00028 00029 \par Description 00030 00031 The functions LALEquatorialToGeographic() and 00032 LALGeographicToEquatorial() convert between equatorial and 00033 geographic coordinate systems, reading coordinates in the first system 00034 from <tt>*input</tt> and storing the new coordinates in <tt>*output</tt>. 00035 The two pointers may point to the same object, in which case the 00036 conversion is done in place. The functions will also check 00037 <tt>input->system</tt> and set <tt>output->system</tt> as appropriate. 00038 Because the geographic coordinate system is not fixed, one must also 00039 specify the time of the transformation in <tt>*gpsTime</tt>. 00040 00041 The function LALSystemToHorizon() transforms coordinates from 00042 either celestial equatorial coordinates or geographic coordinates to a 00043 horizon coordinate system, reading coordinates in the first system 00044 from <tt>*input</tt> and storing the horizon coordinates in 00045 <tt>*output</tt>, as above. The parameter <tt>*zenith</tt> specifies the 00046 direction of the vertical axis <em>in the original coordinate 00047 system</em>; the routine checks to see that <tt>input->system</tt> and 00048 <tt>zenith->system</tt> agree. Normally this routine is used to convert 00049 from <em>geographic</em> latitude and longitude to a horizon system, in 00050 which case <tt>*zenith</tt> simply stores the geographic (geodetic) 00051 coordinates of the observer; if converting from equatorial 00052 coordinates, <tt>zenith->longitude</tt> should store the local mean 00053 sidereal time of the horizon system. 00054 00055 The function LALHorizonToSystem() does the reverse of the 00056 above, transforming coordinates from horizon coordinates to either 00057 equatorial or geographic coordinates as specified by 00058 <tt>zenith->system</tt>; the value of <tt>output->system</tt> is set to 00059 agree with <tt>zenith->system</tt>. 00060 00061 Although it is conventional to specify an observation location by its 00062 <em>geodetic</em> coordinates, some routines may provide or require 00063 <em>geocentric</em> coordinates. The routines 00064 LALGeocentricToGeodetic() and LALGeodeticToGeocentric() 00065 perform this computation, reading and writing to the variable 00066 parameter structure <tt>*location</tt>. The function 00067 LALGeocentricToGeodetic() reads the fields <tt>location->x</tt>, 00068 <tt>y</tt>, <tt>z</tt>, and computes <tt>location->zenith</tt> and 00069 <tt>location->altitude</tt>. The function 00070 LALGeodeticToGeocentric() does the reverse, and also sets the 00071 fields <tt>location->position</tt> and <tt>location->radius</tt>. 00072 00073 \par Algorithm 00074 00075 These routines follow the formulae in Sec.5.1 of \ref Lang_K1999, 00076 which we reproduce below. 00077 00078 \paragraph{Geographic coordinates:} Since geographic and equatorial 00079 coordinates share the same \f$z\f$-axis, the geographic latitude \f$\phi\f$ of 00080 a direction in space is the same as its declination \f$\delta\f$, and 00081 longitude \f$\lambda\f$ and right ascension \f$\alpha\f$ differ only through 00082 the rotation of the Earth: 00083 \f{equation} 00084 \label{eq:lambda-geographic} 00085 \lambda = \alpha - \left(\frac{2\pi\,\mathrm{radians}} 00086 {24\,\mathrm{hours}}\right)\times\mathrm{GMST} \; , 00087 \f} 00088 where GMST is Greenwich mean sidereal time. The conversion routines 00089 here simply use the functions in the <tt>date</tt> package to compute 00090 GMST for a given GPS time, and add it to the longitude. While this is 00091 simple enough, it does involve several function calls, so it is 00092 convenient to collect these into one routine. 00093 00094 \paragraph{Horizon coordinates:} We correct a typographical 00095 error on the second line of Eq.(5.45) of \ref Lang_K1999 (it should 00096 have \f$\cos A\f$, not \f$\sin A\f$). We also note that while our latitudinal 00097 coordinate is just the altitude \f$a\f$ in this system, our longitudinal 00098 coordinate increases counterclockwise, and thus corresponds to the 00099 <em>negative</em> of the azimuth \f$A\f$ as defined by \ref Lang_K1999. 00100 So we have: 00101 \f{eqnarray} 00102 \label{eq:altitude-horizon} 00103 a & = & \arcsin(\sin\delta\sin\phi + \cos\delta\cos\phi\cos h) \; , \\ 00104 \label{eq:azimuth-horizon} 00105 -A & = & \arctan\!2(\cos\delta\sin h, \sin\delta\cos\phi - 00106 \cos\delta\sin\phi\cos h) \; , 00107 \f} 00108 where \f$\delta\f$ is the declination (geographic latitude) of the 00109 direction being transformed, \f$\phi\f$ is the geographic latitude of the 00110 observer's zenith (i.e.\ the observer's <em>geodetic</em> latitude), and 00111 \f$h\f$ is the <em>hour angle</em> of the direction being transformed. This 00112 is defined as: 00113 \f{eqnarray} 00114 h & = & \lambda_\mathrm{zenith} - \lambda \nonumber\\ 00115 & = & \mathrm{LMST} - \alpha \nonumber 00116 \f} 00117 where LMST is the local mean sidereal time at the point of 00118 observation. The inverse transformation is: 00119 \f{eqnarray} 00120 \label{eq:delta-horizon} 00121 \delta & = & \arcsin(\sin a\sin\phi + \cos a\cos A\cos\phi) \; , \\ 00122 \label{eq:h-horizon} 00123 h & = & \arctan\!2[\cos a\sin(-A), \sin a\cos\phi - 00124 \cos a\cos A\sin\phi] \; . 00125 \f} 00126 As explained in <tt>CelestialCoordinates.c</tt>, the function 00127 \f$\arctan\!2(y,x)\f$ returns the argument of the complex number \f$x+iy\f$. 00128 00129 \image html inject_geodetic.png "Fig. 1: The difference between geodetic and geocentric latitude." 00130 \latexonly 00131 \newpage 00132 \begin{wrapfigure}{r}{0.35\textwidth} 00133 \vspace{-2ex} 00134 \begin{center} 00135 \resizebox{0.3\textwidth}{!}{\includegraphics{inject_geodetic}} \\ 00136 \parbox{0.3\textwidth}{\caption{\label{fig:geodetic} The difference 00137 between geodetic and geocentric latitude.}} 00138 \end{center} 00139 \vspace{-2ex} 00140 \end{wrapfigure} 00141 \paragraph{Geocentric coordinates:} 00142 \endlatexonly \htmlonly 00143 <b>Geocentric coordinates:</b>\endhtmlonly 00144 As shown in 00145 \latexonly Fig.~\ref{fig:geodetic},\endlatexonly 00146 \htmlonly Fig. 1,\endhtmlonly 00147 the ellipticity of the Earth means that the 00148 vertical axis of a point on the Earth's surface does not pass through 00149 the geometric centre of the Earth. This means that the geodetic 00150 latitude of a location (defined as the latitude angle 00151 \f$\phi_\mathrm{geodetic}\f$ of that location's zenith direction) is 00152 typically some 10 arcminutes larger than its geocentric latitude 00153 (defined as the latitude angle \f$\phi_\mathrm{geographic}\f$ of the 00154 position vector from the geocentre through the location). 00155 Cartographers traditionally refer to locations by their geodetic 00156 coordinates, since these can be determined locally; however, 00157 geocentric coordinates are required if one wants to construct a 00158 uniform Cartesian system for the Earth as a whole. 00159 00160 To transform from geodetic to geocentric coordinates, one first 00161 defines a ``reference ellipsoid'', the best-fit ellipsoid to the 00162 surface of the Earth. This is specified by the polar and equatorial 00163 radii of the Earth \f$r_p\f$ and \f$r_e\f$, or equivalently by \f$r_e\f$ and a 00164 flattening factor: 00165 \f[ 00166 f \equiv 1 - \frac{r_p}{r_e} = 0.00335281 \; . 00167 \f] 00168 (This constant will eventually migrate into <tt>LALConstants.h</tt>.) 00169 The surface of the ellipsoid is then specified by the equation 00170 \f[ 00171 r = r_e ( 1 - f\sin^2\phi ) \; , 00172 \f] 00173 where \f$\phi=\phi_\mathrm{geodetic}\f$ is the geodetic latitude. For 00174 points off of the reference ellipsoid, the transformation from 00175 geodetic coordinates \f$\lambda\f$, \f$\phi\f$ to geocentric Cartesian 00176 coordinates is: 00177 \f{eqnarray} 00178 x & = & ( r_e C + h ) \cos\phi\cos\lambda \; , \\ 00179 y & = & ( r_e C + h ) \cos\phi\sin\lambda \; , \\ 00180 z & = & ( r_e S + h ) \sin\phi \; , 00181 \f} 00182 where 00183 \f{eqnarray} 00184 C & = & \frac{1}{\sqrt{\cos^2\phi + (1-f)^2\sin^2\phi}} \; , \\ 00185 S & = & (1-f)^2 C \; , 00186 \f} 00187 and \f$h\f$ is the perpendicular elevation of the location above the 00188 reference ellipsoid. The geocentric spherical coordinates are given 00189 simply by: 00190 \f{eqnarray} 00191 r & = & \sqrt{ x^2 + y^2 + z^2 } \; , \\ 00192 \lambda_\mathrm{geocentric} & = & \lambda \quad = \quad 00193 \lambda_\mathrm{geodetic} \; , \\ 00194 \phi_\mathrm{geocentric} & = & \arcsin( z/r ) \; . 00195 \f} 00196 When computing \f$r\f$ we are careful to factor out the largest component 00197 before computing the sum of squares, to avoid floating-point overflow; 00198 however this should be unnecessary for radii near the surface of the 00199 Earth. 00200 00201 The inverse transformation is somewhat trickier. Eq.(5.29) 00202 of \ref Lang_K1999 conveniently gives the transformation in terms 00203 of a sequence of intermediate variables, but unfortunately these 00204 variables are not particularly computer-friendly, in that they are 00205 prone to underflow or overflow errors. The following equations 00206 essentially reproduce this sequence using better-behaved methods of 00207 calculation. 00208 00209 Given geocentric Cartesian coordinates 00210 \f$x=r\cos\phi_\mathrm{geocentric}\cos\lambda\f$, 00211 \f$y=r\cos\phi_\mathrm{geocentric}\sin\lambda\f$, and 00212 \f$z=r\sin\phi_\mathrm{geocentric}\f$, one computes the following: 00213 \f{eqnarray} 00214 \varpi & = & \sqrt{ \left(\frac{x}{r_e}\right)^2 00215 + \left(\frac{y}{r_e}\right)^2 } \;,\nonumber\\ 00216 E & = & (1-f)\left|\frac{z}{r_e}\right| - f(2-f) \;,\nonumber\\ 00217 F & = & (1-f)\left|\frac{z}{r_e}\right| + f(2-f) \;,\nonumber\\ 00218 P & = & \frac{4}{3}\left( EF + \varpi^2 \right) \quad = \quad 00219 \frac{4}{3}\left[ \varpi^2 + (1-f)^2\left(\frac{z}{r_e}\right)^2 00220 - f^2(2-f)^2 \right] \;,\nonumber\\ 00221 Q & = & 2(F^2 - E^2) \quad = \quad 00222 8f(1-f)(2-f)\left|\frac{z}{r_e}\right| \;,\nonumber\\ 00223 D & = & P^3 + \varpi^2 Q^2 \;,\nonumber\\ 00224 v & = & \left\{\begin{array}{lr} 00225 \left(\sqrt{D}+\varpi Q\right)^{1/3} 00226 - \left(\sqrt{D}-\varpi Q\right)^{1/3} & 00227 D\geq0 \\ 00228 2\sqrt{-P}\cos\left(\frac{1}{3} 00229 \arccos\left[\frac{Q\varpi}{P\sqrt{-P}}\right]\right) & 00230 D\leq0 \end{array}\right.\nonumber\\ 00231 G & = & \mbox{$\frac{1}{2}$}\left(E+\sqrt{E^2 + \varpi v}\right)\;,\nonumber\\ 00232 H & = & \frac{\varpi^2 F - \varpi vG}{G^2(2G-E)} \;,\nonumber\\ 00233 t & = & G\left(\sqrt{1+H}-1\right) \;.\nonumber 00234 \f} 00235 Once we have \f$t\f$ and \f$\varpi\f$, we can compute the geodetic longitude 00236 \f$\lambda\f$, latitude \f$\phi\f$, and elevation \f$h\f$: 00237 \f{eqnarray} 00238 \lambda & = & \arctan\!2(y,x) \; , \\ 00239 \phi & = & \mathrm{sgn}({z})\arctan\left[\frac{2}{1-f} 00240 \left(\frac{(\varpi-t)(\varpi+t)}{\varpi t}\right)\right] \; , \\ 00241 h & = & r_e(\varpi-t/\varpi)\cos\phi 00242 + [z-\mathrm{sgn}({z})r_e(1-f)]\sin\phi \; . 00243 \f} 00244 These formulae, however, introduce certain concerns of numerical 00245 precision that have been only partially dealt with in this code. 00246 Specifically: 00247 00248 - There is a coordinate singularity at \f$\varpi=0\f$, which we deal 00249 with by setting \f$\phi=\pm90^\circ\f$ and \f$\lambda\f$ arbitrarily to 00250 \f$0^\circ\f$. When \f$z=0\f$ as well, we arbitrarily choose the positive 00251 sign for \f$\phi\f$. However, the computation of \f$h\f$ in particular has 00252 tricky cancelations as \f$\varpi\rightarrow0\f$, which may give rise to 00253 numerical errors. These have not yet been thoroughly explored. 00254 00255 - There is another coordinate singularity when \f$D\rightarrow0\f$, 00256 which defines an ellipsoid with equatorial radius 00257 \f$r_0=r_ef(2-f)=42.6977\f$km and axial height \f$z_0=r_e/(1-f)=42.8413\f$km. 00258 Within this ellipsoid, lines of constant latitude begin to cross one 00259 another. The listed solution is an analytic continuation of the 00260 exterior solution which assigns these points a unique, if arbitrary, 00261 geodetic latitude. This solution has some peculiar behaviour, such as 00262 giving points in the equatorial plane a positive latitude. In 00263 practice, however, users will rarely be interested coordinate 00264 transformations deep within the Earth's core. 00265 00266 - The equations for \f$v\f$ and \f$G\f$ have square and cube roots of 00267 expressions involving squares and cubes of numbers. For formal 00268 robustness one should factor out the leading-order dependence, so that 00269 one is assured of taking squares and cubes of numbers near unity. 00270 However, we are using <tt>REAL8</tt> precision, and have already 00271 normalized our distances by the Earth's radius \f$r_e\f$, so the point is 00272 almost certainly irrelevant. 00273 00274 - The expression for \f$H\f$ may go to zero, leading to precision 00275 errors in \f$t\f$; the number of digits of precision lost is on the order 00276 of the number of leading zeros after the decimal place in \f$H\f$. I 00277 arbitrarily state that we should not lose more than 4 of our 16 00278 decimal places of precision, meaning that we should series-expand the 00279 square root for \f$H<10^{-4}\f$. To get our 12 places of precision back, 00280 we need an expansion to \f$H^3\f$: 00281 \f[ 00282 t \approx G\left(\frac{1}{2}H - \frac{3}{8}H^2 00283 + \frac{5}{16}H^3\right) \; . 00284 \f] 00285 00286 \item When computing \f$\phi\f$, we first compute \f$t-\varpi\f$, \f$t+\varpi\f$, 00287 \f$t^{-1}\f$, and \f$\varpi^{-1}\f$, sort them by order of magnitude, and 00288 alternately multiply large and small terms. We note that if the 00289 argument of the \f$\arctan\f$ function is large we have 00290 \f[ 00291 \arctan(x) = \mathrm{sgn}(x)\frac{\pi}{2} 00292 - \arctan\left(\frac{1}{x}\right) \; , 00293 \f] 00294 but the <tt>atan()</tt> function in the C math library should be smart 00295 enough to do this itself. 00296 00297 00298 <b>Ellipsoidal vs. orthometric elevation:</b> In this module it 00299 is assumed that all elevations refer heights above the reference 00300 ellipsoid. This is the elevation computed by such techniques as GPS 00301 triangulation. However, the ``true'' orthometric elevation refers to 00302 the height above the mean sea level or <em>geoid</em>, a level surface 00303 in the Earth's gravitational potential. Thus, even if two points have 00304 the same ellipsoidal elevation, water will still flow from the higher 00305 to the lower orthometric elevation. 00306 00307 The difference between the geoid and reference ellipsoid is called the 00308 ``undulation of the geoid'', and can vary by over a hundred metres 00309 over the Earth's surface. However, it can only be determined through 00310 painstaking measurements of local variations in the Earth's 00311 gravitational field. For this reason we will ignore the undulation of 00312 the geoid. 00313 00314 \par Uses 00315 \code 00316 LALGPStoUTC() 00317 XLALGreenwichMeanSiderealTime() 00318 LALDHeapSort() 00319 \endcode 00320 00321 */ 00322 00323 00324 /*---------- laldoc-documentation follows ---------- */ 00325 00326 /*********************** <lalVerbatim file="TerrestrialCoordinatesCV"> 00327 Author: Creighton, T. D. 00328 $Id: TerrestrialCoordinates.c,v 1.20 2008/05/22 19:27:42 teviet Exp $ 00329 **************************************************** </lalVerbatim> */ 00330 00331 /********************************************************** <lalLaTeX> 00332 00333 \subsection{Module \texttt{TerrestrialCoordinates.c}} 00334 \label{ss:TerrestrialCoordinates.c} 00335 00336 Converts among equatorial, geographic, and horizon coordinates. 00337 00338 \subsubsection*{Prototypes} 00339 \vspace{0.1in} 00340 \input{TerrestrialCoordinatesCP} 00341 \idx{LALEquatorialToGeographic()} 00342 \idx{LALGeographicToEquatorial()} 00343 \idx{LALSystemToHorizon()} 00344 \idx{LALHorizonToSystem()} 00345 00346 \subsubsection*{Description} 00347 00348 The functions \verb@LALEquatorialToGeographic()@ and 00349 \verb@LALGeographicToEquatorial()@ convert between equatorial and 00350 geographic coordinate systems, reading coordinates in the first system 00351 from \verb@*input@ and storing the new coordinates in \verb@*output@. 00352 The two pointers may point to the same object, in which case the 00353 conversion is done in place. The functions will also check 00354 \verb@input->system@ and set \verb@output->system@ as appropriate. 00355 Because the geographic coordinate system is not fixed, one must also 00356 specify the time of the transformation in \verb@*gpsTime@. 00357 00358 The function \verb@LALSystemToHorizon()@ transforms coordinates from 00359 either celestial equatorial coordinates or geographic coordinates to a 00360 horizon coordinate system, reading coordinates in the first system 00361 from \verb@*input@ and storing the horizon coordinates in 00362 \verb@*output@, as above. The parameter \verb@*zenith@ specifies the 00363 direction of the vertical axis \emph{in the original coordinate 00364 system}; the routine checks to see that \verb@input->system@ and 00365 \verb@zenith->system@ agree. Normally this routine is used to convert 00366 from \emph{geographic} latitude and longitude to a horizon system, in 00367 which case \verb@*zenith@ simply stores the geographic (geodetic) 00368 coordinates of the observer; if converting from equatorial 00369 coordinates, \verb@zenith->longitude@ should store the local mean 00370 sidereal time of the horizon system. 00371 00372 The function \verb@LALHorizonToSystem()@ does the reverse of the 00373 above, transforming coordinates from horizon coordinates to either 00374 equatorial or geographic coordinates as specified by 00375 \verb@zenith->system@; the value of \verb@output->system@ is set to 00376 agree with \verb@zenith->system@. 00377 00378 Although it is conventional to specify an observation location by its 00379 \emph{geodetic} coordinates, some routines may provide or require 00380 \emph{geocentric} coordinates. The routines 00381 \verb@LALGeocentricToGeodetic()@ and \verb@LALGeodeticToGeocentric()@ 00382 perform this computation, reading and writing to the variable 00383 parameter structure \verb@*location@. The function 00384 \verb@LALGeocentricToGeodetic()@ reads the fields \verb@location->x@, 00385 \verb@y@, \verb@z@, and computes \verb@location->zenith@ and 00386 \verb@location->altitude@. The function 00387 \verb@LALGeodeticToGeocentric()@ does the reverse, and also sets the 00388 fields \verb@location->position@ and \verb@location->radius@. 00389 00390 \subsubsection*{Algorithm} 00391 00392 These routines follow the formulae in Sec.~5.1 of~\cite{Lang_K:1999}, 00393 which we reproduce below. 00394 00395 \paragraph{Geographic coordinates:} Since geographic and equatorial 00396 coordinates share the same $z$-axis, the geographic latitude $\phi$ of 00397 a direction in space is the same as its declination $\delta$, and 00398 longitude $\lambda$ and right ascension $\alpha$ differ only through 00399 the rotation of the Earth: 00400 \begin{equation} 00401 \label{eq:lambda-geographic} 00402 \lambda = \alpha - \left(\frac{2\pi\,\mathrm{radians}} 00403 {24\,\mathrm{hours}}\right)\times\mathrm{GMST} \; , 00404 \end{equation} 00405 where GMST is Greenwich mean sidereal time. The conversion routines 00406 here simply use the functions in the \verb@date@ package to compute 00407 GMST for a given GPS time, and add it to the longitude. While this is 00408 simple enough, it does involve several function calls, so it is 00409 convenient to collect these into one routine. 00410 00411 \paragraph{Horizon coordinates:} We correct a typographical 00412 error on the second line of Eq.~5.45 of~\cite{Lang_K:1999} (it should 00413 have $\cos A$, not $\sin A$). We also note that while our latitudinal 00414 coordinate is just the altitude $a$ in this system, our longitudinal 00415 coordinate increases counterclockwise, and thus corresponds to the 00416 \emph{negative} of the azimuth $A$ as defined by~\cite{Lang_K:1999}. 00417 So we have: 00418 \begin{eqnarray} 00419 \label{eq:altitude-horizon} 00420 a & = & \arcsin(\sin\delta\sin\phi + \cos\delta\cos\phi\cos h) \; , \\ 00421 \label{eq:azimuth-horizon} 00422 -A & = & \arctan\!2(\cos\delta\sin h, \sin\delta\cos\phi - 00423 \cos\delta\sin\phi\cos h) \; , 00424 \end{eqnarray} 00425 where $\delta$ is the declination (geographic latitude) of the 00426 direction being transformed, $\phi$ is the geographic latitude of the 00427 observer's zenith (i.e.\ the observer's \emph{geodetic} latitude), and 00428 $h$ is the \emph{hour angle} of the direction being transformed. This 00429 is defined as: 00430 \begin{eqnarray} 00431 h & = & \lambda_\mathrm{zenith} - \lambda \nonumber\\ 00432 & = & \mathrm{LMST} - \alpha \nonumber 00433 \end{eqnarray} 00434 where LMST is the local mean sidereal time at the point of 00435 observation. The inverse transformation is: 00436 \begin{eqnarray} 00437 \label{eq:delta-horizon} 00438 \delta & = & \arcsin(\sin a\sin\phi + \cos a\cos A\cos\phi) \; , \\ 00439 \label{eq:h-horizon} 00440 h & = & \arctan\!2[\cos a\sin(-A), \sin a\cos\phi - 00441 \cos a\cos A\sin\phi] \; . 00442 \end{eqnarray} 00443 As explained in \verb@CelestialCoordinates.c@, the function 00444 $\arctan\!2(y,x)$ returns the argument of the complex number $x+iy$. 00445 00446 \newpage 00447 00448 \begin{wrapfigure}{r}{0.35\textwidth} 00449 \vspace{-2ex} 00450 \begin{center} 00451 \resizebox{0.3\textwidth}{!}{\includegraphics{inject_geodetic}} \\ 00452 \parbox{0.3\textwidth}{\caption{\label{fig:geodetic} The difference 00453 between geodetic and geocentric latitude.}} 00454 \end{center} 00455 \vspace{-2ex} 00456 \end{wrapfigure} 00457 \paragraph{Geocentric coordinates:} As shown in 00458 Fig.~\ref{fig:geodetic}, the ellipticity of the Earth means that the 00459 vertical axis of a point on the Earth's surface does not pass through 00460 the geometric centre of the Earth. This means that the geodetic 00461 latitude of a location (defined as the latitude angle 00462 $\phi_\mathrm{geodetic}$ of that location's zenith direction) is 00463 typically some 10~arcminutes larger than its geocentric latitude 00464 (defined as the latitude angle $\phi_\mathrm{geographic}$ of the 00465 position vector from the geocentre through the location). 00466 Cartographers traditionally refer to locations by their geodetic 00467 coordinates, since these can be determined locally; however, 00468 geocentric coordinates are required if one wants to construct a 00469 uniform Cartesian system for the Earth as a whole. 00470 00471 To transform from geodetic to geocentric coordinates, one first 00472 defines a ``reference ellipsoid'', the best-fit ellipsoid to the 00473 surface of the Earth. This is specified by the polar and equatorial 00474 radii of the Earth $r_p$ and $r_e$, or equivalently by $r_e$ and a 00475 flattening factor: 00476 $$ 00477 f \equiv 1 - \frac{r_p}{r_e} = 0.00335281 \; . 00478 $$ 00479 (This constant will eventually migrate into \verb@LALConstants.h@.) 00480 The surface of the ellipsoid is then specified by the equation 00481 $$ 00482 r = r_e ( 1 - f\sin^2\phi ) \; , 00483 $$ 00484 where $\phi=\phi_\mathrm{geodetic}$ is the geodetic latitude. For 00485 points off of the reference ellipsoid, the transformation from 00486 geodetic coordinates $\lambda$, $\phi$ to geocentric Cartesian 00487 coordinates is: 00488 \begin{eqnarray} 00489 x & = & ( r_e C + h ) \cos\phi\cos\lambda \; , \\ 00490 y & = & ( r_e C + h ) \cos\phi\sin\lambda \; , \\ 00491 z & = & ( r_e S + h ) \sin\phi \; , 00492 \end{eqnarray} 00493 where 00494 \begin{eqnarray} 00495 C & = & \frac{1}{\sqrt{\cos^2\phi + (1-f)^2\sin^2\phi}} \; , \\ 00496 S & = & (1-f)^2 C \; , 00497 \end{eqnarray} 00498 and $h$ is the perpendicular elevation of the location above the 00499 reference ellipsoid. The geocentric spherical coordinates are given 00500 simply by: 00501 \begin{eqnarray} 00502 r & = & \sqrt{ x^2 + y^2 + z^2 } \; , \\ 00503 \lambda_\mathrm{geocentric} & = & \lambda \quad = \quad 00504 \lambda_\mathrm{geodetic} \; , \\ 00505 \phi_\mathrm{geocentric} & = & \arcsin( z/r ) \; . 00506 \end{eqnarray} 00507 When computing $r$ we are careful to factor out the largest component 00508 before computing the sum of squares, to avoid floating-point overflow; 00509 however this should be unnecessary for radii near the surface of the 00510 Earth. 00511 00512 The inverse transformation is somewhat trickier. Eq.~5.29 00513 of~\cite{Lang_K:1999} conveniently gives the transformation in terms 00514 of a sequence of intermediate variables, but unfortunately these 00515 variables are not particularly computer-friendly, in that they are 00516 prone to underflow or overflow errors. The following equations 00517 essentially reproduce this sequence using better-behaved methods of 00518 calculation. 00519 00520 Given geocentric Cartesian coordinates 00521 $x=r\cos\phi_\mathrm{geocentric}\cos\lambda$, 00522 $y=r\cos\phi_\mathrm{geocentric}\sin\lambda$, and 00523 $z=r\sin\phi_\mathrm{geocentric}$, one computes the following: 00524 \begin{eqnarray} 00525 \varpi & = & \sqrt{ \left(\frac{x}{r_e}\right)^2 00526 + \left(\frac{y}{r_e}\right)^2 } \;,\nonumber\\ 00527 E & = & (1-f)\left|\frac{z}{r_e}\right| - f(2-f) \;,\nonumber\\ 00528 F & = & (1-f)\left|\frac{z}{r_e}\right| + f(2-f) \;,\nonumber\\ 00529 P & = & \frac{4}{3}\left( EF + \varpi^2 \right) \quad = \quad 00530 \frac{4}{3}\left[ \varpi^2 + (1-f)^2\left(\frac{z}{r_e}\right)^2 00531 - f^2(2-f)^2 \right] \;,\nonumber\\ 00532 Q & = & 2\varpi(F^2 - E^2) \quad = \quad 00533 8\varpi f(1-f)(2-f)\left|\frac{z}{r_e}\right| \;,\nonumber\\ 00534 D & = & P^3 + Q^2 \;,\nonumber\\ 00535 v & = & \left\{\begin{array}{lr} 00536 \left(\sqrt{D}+Q\right)^{1/3} 00537 - \left(\sqrt{D}-Q\right)^{1/3} & 00538 D\geq0 \\ 00539 2\sqrt{-P}\cos\left(\frac{1}{3} 00540 \arccos\left[\frac{Q}{-P\sqrt{-P}}\right]\right) & 00541 D\leq0 \end{array}\right.\nonumber\\ 00542 W & = & \sqrt{E^2 + \varpi v} \nonumber\\[1ex] 00543 G & = & \mbox{$\frac{1}{2}$}\left(E+W\right)\;,\nonumber\\ 00544 t & = & \sqrt{G^2+\frac{\varpi^2 F - \varpi vG}{W}}-G \;.\nonumber 00545 \end{eqnarray} 00546 Once we have $t$ and $\varpi$, we can compute the geodetic longitude 00547 $\lambda$, latitude $\phi$, and elevation $h$: 00548 \begin{eqnarray} 00549 \lambda & = & \arctan\!2(y,x) \; , \\ 00550 \phi & = & \mathrm{sgn}({z})\arctan\left[\frac{1}{2(1-f)} 00551 \left(\frac{(\varpi-t)(\varpi+t)}{\varpi t}\right)\right] \; , \\ 00552 h & = & r_e(\varpi-t/\varpi)\cos\phi 00553 + [z-\mathrm{sgn}({z})r_e(1-f)]\sin\phi \; . 00554 \end{eqnarray} 00555 00556 \begin{wrapfigure}{r}{0.47\textwidth} 00557 \vspace{-8ex} 00558 \begin{center} 00559 \resizebox{0.42\textwidth}{!}{\includegraphics{inject_geodeticsing}} \\ 00560 \parbox{0.42\textwidth}{\caption{\label{fig:geodeticsing} Singular 00561 surfaces in the geodetic coordinate system. The ellipticity of this 00562 spheroid has been exaggerated compared with the Earth.}} 00563 \end{center} 00564 \vspace{-7ex} 00565 \end{wrapfigure} 00566 \noindent These formulae still leave certain areas where coordinate 00567 singularities or numerical cancelations can occur. Some of these have 00568 been dealt with in the code: 00569 \begin{itemize} 00570 \item There is a coordinate singularity at $\varpi=0$, which we deal 00571 with by setting $\phi=\pm90^\circ$ and $\lambda$ arbitrarily to 00572 $0^\circ$. When $z=0$ as well, we arbitrarily choose the positive 00573 sign for $\phi$. As $\varpi\rightarrow0$, there are cancellations in 00574 the computation of $G$ and $t$, which call for special treatment 00575 (below). 00576 00577 \item There is another coordinate singularity when $D\leq0$, where 00578 lines of constant geodetic latitude will cross each other, as shown in 00579 Fig.~\ref{fig:geodeticsing}. That is, a given point within this 00580 region can be assigned a range of geodetic latitudes. The 00581 multi-valued region lies within an inner ellipsoid $P\leq0$, which in 00582 the case of the Earth has equatorial radius $r_0=r_ef(2-f)=42.6977$km 00583 and axial height $z_0=r_0/(1-f)=42.8413$km. The formula for $v$, 00584 above, has an analytic continuation to $D\leq0$, assigning consistent 00585 (though not unique) values of latitute and elevation to these points. 00586 \end{itemize} 00587 00588 \begin{itemize} 00589 \item Near the equator we have $Q\rightarrow0$, and the first 00590 expression for $v$ becomes a difference of nearly-equal numbers, 00591 leading to loss of precision. To deal with this, we write that 00592 expression for $v$ as: 00593 $$ 00594 \begin{array}{rcl@{\qquad}c@{\qquad}l} 00595 v &=& D^{1/6}\left[(1+B)^{1/3}-(1-B)^{1/3}\right] 00596 &\mbox{where}& B \;\;=\;\; \displaystyle \frac{Q}{\sqrt{D}} \\ 00597 &\approx& D^{1/6}\left[\frac{2}{3}B+\frac{10}{81}B^3\right] 00598 &\mbox{as}& B \;\;\rightarrow\;\;0 00599 \end{array} 00600 $$ 00601 00602 The switch from the ``exact'' formula to the series expansion is done 00603 for $B<10^{-3}$ (within about $2^\circ$ of the equator). This was 00604 found by experimentation to be the point where the inaccuracy of the 00605 series expansion is roughly equal to the imprecision in evaluating the 00606 ``exact'' formula. The resulting position errors are of order 1 part 00607 in $10^{12}$ or less; i.e.\ about 3--4 digits loss of precision. 00608 00609 \item In some places we have expressions of the form $\sqrt{a^2+b}-a$, 00610 which becomes a difference of nearly equal numbers for $|b|\ll a^2$, 00611 resulting in loss of precision. There are three distinct lines or 00612 surfaces where this occurs: 00613 \begin{enumerate} 00614 \item Near the ellipsoidal surface $P\approx0$, the expression $\sqrt{D}-Q$ 00615 in the equation for $v$ becomes of this form. 00616 \item Near the polar axis $\varpi\approx0$, the expression for $t$ 00617 becomes of this form. 00618 \item Near the polar axis $\varpi\approx0$ within the inner ellipsoid, 00619 we have $E<0$ and the expression for $G$ becomes of this form. 00620 \end{enumerate} 00621 In each case, we expand in the small parameter $H=b/a^2$, giving: 00622 $$ 00623 \sqrt{a^2+b}-a \;\;\approx\;\; a\left(\mbox{$\frac{1}{2}$}H 00624 -\mbox{$\frac{1}{8}$}H^2+\mbox{$\frac{1}{16}$}H^3\right) 00625 \qquad\mbox{for}\qquad |H| = \left|\frac{b}{a^2}\right| \ll 1 00626 $$ 00627 00628 We switch to the series expansion for $|H|<\times10^{-4}$, which again 00629 is the point where residual errors in the series expansion are about 00630 the same as the loss of precision without the expansion. This formula 00631 converges much better than the one for $v$ (above), resulting in 00632 negligible loss of precision in the final position. 00633 00634 \item The only remaining known numerical singularities are at the 00635 poles of the inner ellipsoid, shown as red dots in 00636 Fig.~\ref{fig:geodeticsing}. These points stubbornly resist 00637 high-precision calculation. However, they are extremely unlikely to 00638 come up in practice. 00639 \end{itemize} 00640 00641 \paragraph{Ellipsoidal vs.\ orthometric elevation:} In this module it 00642 is assumed that all elevations refer heights above the reference 00643 ellipsoid. This is the elevation computed by such techniques as GPS 00644 triangulation. However, the ``true'' orthometric elevation refers to 00645 the height above the mean sea level or \emph{geoid}, a level surface 00646 in the Earth's gravitational potential. Thus, even if two points have 00647 the same ellipsoidal elevation, water will still flow from the higher 00648 to the lower orthometric elevation. 00649 00650 The difference between the geoid and reference ellipsoid is called the 00651 ``undulation of the geoid'', and can vary by over a hundred metres 00652 over the Earth's surface. However, it can only be determined through 00653 painstaking measurements of local variations in the Earth's 00654 gravitational field. For this reason we will ignore the undulation of 00655 the geoid. 00656 00657 \subsubsection*{Uses} 00658 \begin{verbatim} 00659 XLALGreenwichMeanSiderealTime() 00660 \end{verbatim} 00661 00662 \subsubsection*{Notes} 00663 00664 \vfill{\footnotesize\input{TerrestrialCoordinatesCV}} 00665 00666 ******************************************************* </lalLaTeX> */ 00667 00668 00669 #include <math.h> 00670 #include <lal/LALStdlib.h> 00671 #include <lal/LALConstants.h> 00672 #include <lal/Date.h> 00673 #include <lal/Sort.h> 00674 #include <lal/SkyCoordinates.h> 00675 #include <string.h> 00676 00677 #define LAL_EARTHFLAT (0.00335281) 00678 #define LAL_HSERIES (0.0001) /* value H below which we expand sqrt(1+H)-1 */ 00679 #define LAL_BSERIES (0.001) /* value B below which we expand v */ 00680 00681 NRCSID( TERRESTRIALCOORDINATESC, "$Id: TerrestrialCoordinates.c,v 1.20 2008/05/22 19:27:42 teviet Exp $" ); 00682 00683 /* <lalVerbatim file="TerrestrialCoordinatesCP"> */ 00684 void 00685 LALEquatorialToGeographic( LALStatus *stat, 00686 SkyPosition *output, 00687 SkyPosition *input, 00688 LIGOTimeGPS *gpsTime ) 00689 { /* </lalVerbatim> */ 00690 REAL8 gmst; /* siderial time (radians) */ 00691 00692 INITSTATUS( stat, "LALEquatorialToGeographic", TERRESTRIALCOORDINATESC ); 00693 00694 /* Make sure parameter structures exist. */ 00695 ASSERT( input, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00696 ASSERT( output, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00697 ASSERT( gpsTime, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00698 00699 /* Make sure we're given the right coordinate system. */ 00700 if ( input->system != COORDINATESYSTEM_EQUATORIAL ) { 00701 ABORT( stat, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); 00702 } 00703 00704 /* Compute the Greenwich mean sidereal time. */ 00705 gmst = fmod( XLALGreenwichMeanSiderealTime( gpsTime ), LAL_TWOPI ); 00706 00707 /* Add to longitude, and exit. */ 00708 output->system = COORDINATESYSTEM_GEOGRAPHIC; 00709 output->longitude = fmod( input->longitude - gmst, LAL_TWOPI ); 00710 if ( output->longitude < 0.0 ) 00711 output->longitude += LAL_TWOPI; 00712 output->latitude = input->latitude; 00713 RETURN( stat ); 00714 } 00715 00716 00717 /* <lalVerbatim file="TerrestrialCoordinatesCP"> */ 00718 void 00719 LALGeographicToEquatorial( LALStatus *stat, 00720 SkyPosition *output, 00721 SkyPosition *input, 00722 LIGOTimeGPS *gpsTime ) 00723 { /* </lalVerbatim> */ 00724 REAL8 gmst; /* siderial time (radians) */ 00725 00726 INITSTATUS( stat, "LALEquatorialToGeographic", TERRESTRIALCOORDINATESC ); 00727 00728 /* Make sure parameter structures exist. */ 00729 ASSERT( input, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00730 ASSERT( output, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00731 ASSERT( gpsTime, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00732 00733 /* Make sure we're given the right coordinate system. */ 00734 if ( input->system != COORDINATESYSTEM_GEOGRAPHIC ) { 00735 ABORT( stat, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); 00736 } 00737 00738 /* Compute the Greenwich mean sidereal time. */ 00739 gmst = fmod( XLALGreenwichMeanSiderealTime( gpsTime ), LAL_TWOPI ); 00740 00741 /* Subtract from longitude, and exit. */ 00742 output->system = COORDINATESYSTEM_EQUATORIAL; 00743 output->longitude = fmod( input->longitude + gmst, LAL_TWOPI ); 00744 if ( output->longitude < 0.0 ) 00745 output->longitude += LAL_TWOPI; 00746 output->latitude = input->latitude; 00747 RETURN( stat ); 00748 } 00749 00750 00751 /* <lalVerbatim file="TerrestrialCoordinatesCP"> */ 00752 void 00753 LALSystemToHorizon( LALStatus *stat, 00754 SkyPosition *output, 00755 SkyPosition *input, 00756 const SkyPosition *zenith ) 00757 { /* </lalVerbatim> */ 00758 REAL8 h, sinH, cosH; /* hour angle, and its sine and cosine */ 00759 REAL8 sinP, cosP; /* sin and cos of zenith latitude */ 00760 REAL8 sinD, cosD; /* sin and cos of position latitude (declination) */ 00761 REAL8 sina, sinA, cosA; /* sin and cos of altitude and -azimuth */ 00762 00763 INITSTATUS( stat, "LALSystemToHorizon", TERRESTRIALCOORDINATESC ); 00764 00765 /* Make sure parameter structures exist. */ 00766 ASSERT( input, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00767 ASSERT( output, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00768 ASSERT( zenith, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00769 00770 /* Make sure we have consistent input coordinate systems. */ 00771 if ( input->system != zenith->system ) { 00772 ABORT( stat, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); 00773 } 00774 if ( ( zenith->system != COORDINATESYSTEM_EQUATORIAL ) && 00775 ( zenith->system != COORDINATESYSTEM_GEOGRAPHIC ) ) { 00776 ABORT( stat, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); 00777 } 00778 00779 /* Compute intermediates. */ 00780 h = zenith->longitude - input->longitude; 00781 sinH = sin( h ); 00782 cosH = cos( h ); 00783 sinP = sin( zenith->latitude ); 00784 cosP = cos( zenith->latitude ); 00785 sinD = sin( input->latitude ); 00786 cosD = cos( input->latitude ); 00787 00788 /* Compute components. */ 00789 sina = sinD*sinP + cosD*cosP*cosH; 00790 sinA = cosD*sinH; 00791 cosA = sinD*cosP - cosD*sinP*cosH; 00792 00793 /* Compute final results. */ 00794 output->system = COORDINATESYSTEM_HORIZON; 00795 output->latitude = asin( sina ); 00796 output->longitude = atan2( sinA, cosA ); 00797 00798 /* Optional phase correction. */ 00799 if ( output->longitude < 0.0 ) 00800 output->longitude += LAL_TWOPI; 00801 00802 RETURN( stat ); 00803 } 00804 00805 00806 /* <lalVerbatim file="TerrestrialCoordinatesCP"> */ 00807 void 00808 LALHorizonToSystem( LALStatus *stat, 00809 SkyPosition *output, 00810 SkyPosition *input, 00811 const SkyPosition *zenith ) 00812 { /* </lalVerbatim> */ 00813 REAL8 sinP, cosP; /* sin and cos of zenith latitude */ 00814 REAL8 sina, cosa; /* sin and cos of altitude */ 00815 REAL8 sinA, cosA; /* sin and cos of -azimuth */ 00816 REAL8 sinD, sinH, cosH; /* sin and cos of declination and hour angle */ 00817 00818 INITSTATUS( stat, "LALHorizonToSystem", TERRESTRIALCOORDINATESC ); 00819 00820 /* Make sure parameter structures exist. */ 00821 ASSERT( input, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00822 ASSERT( output, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00823 ASSERT( zenith, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00824 00825 /* Make sure we're given the right coordinate system. */ 00826 if ( input->system != COORDINATESYSTEM_HORIZON ) { 00827 ABORT( stat, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); 00828 } 00829 if ( ( zenith->system != COORDINATESYSTEM_EQUATORIAL ) && 00830 ( zenith->system != COORDINATESYSTEM_GEOGRAPHIC ) ) { 00831 ABORT( stat, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); 00832 } 00833 00834 /* Compute intermediates. */ 00835 sinP = sin( zenith->latitude ); 00836 cosP = cos( zenith->latitude ); 00837 sina = sin( input->latitude ); 00838 cosa = cos( input->latitude ); 00839 sinA = sin( input->longitude ); 00840 cosA = cos( input->longitude ); 00841 00842 /* Compute components. */ 00843 sinD = sina*sinP + cosa*cosA*cosP; 00844 sinH = cosa*sinA; 00845 cosH = sina*cosP - cosa*cosA*sinP; 00846 00847 /* Compute final results. */ 00848 output->system = zenith->system; 00849 output->latitude = asin( sinD ); 00850 output->longitude = zenith->longitude - atan2( sinH, cosH ); 00851 00852 /* Optional phase correction. */ 00853 if ( output->longitude < 0.0 ) 00854 output->longitude += LAL_TWOPI; 00855 00856 RETURN( stat ); 00857 } 00858 00859 00860 /* <lalVerbatim file="TerrestrialCoordinatesCP"> */ 00861 void 00862 LALGeodeticToGeocentric( LALStatus *stat, EarthPosition *location ) 00863 { /* </lalVerbatim> */ 00864 REAL8 c, s; /* position components in and orthogonal to the equator */ 00865 REAL8 cosP, sinP; /* cosine and sine of latitude */ 00866 REAL8 fFac; /* ( 1 - f )^2 */ 00867 REAL8 x, y; /* Cartesian coordinates */ 00868 REAL8 maxComp, r; /* max{x,y,z}, and sqrt(x^2+y^2+z^2) */ 00869 00870 INITSTATUS( stat, "LALGeodeticToGeocentric", TERRESTRIALCOORDINATESC ); 00871 00872 /* Make sure parameter structure exists. */ 00873 ASSERT( location, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00874 00875 /* Make sure the geodetic coordinates are in the right system. */ 00876 if ( location->geodetic.system != COORDINATESYSTEM_GEOGRAPHIC ) { 00877 ABORT( stat, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); 00878 } 00879 00880 /* Compute intermediates. */ 00881 fFac = 1.0 - LAL_EARTHFLAT; 00882 fFac *= fFac; 00883 cosP = cos( location->geodetic.latitude ); 00884 sinP = sin( location->geodetic.latitude ); 00885 c = sqrt( 1.0 / ( cosP*cosP + fFac*sinP*sinP ) ); 00886 s = fFac*c; 00887 c = ( LAL_REARTH_SI*c + location->elevation )*cosP; 00888 s = ( LAL_REARTH_SI*s + location->elevation )*sinP; 00889 00890 /* Compute Cartesian coordinates. */ 00891 location->x = x = c*cos( location->geodetic.longitude ); 00892 location->y = y = c*sin( location->geodetic.longitude ); 00893 location->z = s; 00894 00895 /* Compute the radius. */ 00896 maxComp = x; 00897 if ( y > maxComp ) 00898 maxComp = y; 00899 if ( s > maxComp ) 00900 maxComp = s; 00901 x /= maxComp; 00902 y /= maxComp; 00903 s /= maxComp; 00904 r = sqrt( x*x + y*y + s*s ); 00905 00906 /* Compute the spherical coordinates, and exit. */ 00907 location->radius = maxComp*r; 00908 location->geocentric.longitude = location->geodetic.longitude; 00909 location->geocentric.latitude = asin( s / r ); 00910 location->geocentric.system = COORDINATESYSTEM_GEOGRAPHIC; 00911 RETURN( stat ); 00912 } 00913 00914 00915 /* <lalVerbatim file="TerrestrialCoordinatesCP"> */ 00916 void 00917 LALGeocentricToGeodetic( LALStatus *stat, EarthPosition *location ) 00918 { /* </lalVerbatim> */ 00919 REAL8 x, y, z; /* normalized geocentric coordinates */ 00920 REAL8 pi; /* axial distance */ 00921 00922 /* Declare some local constants. */ 00923 const REAL8 rInv = 1.0 / LAL_REARTH_SI; 00924 const REAL8 f1 = 1.0 - LAL_EARTHFLAT; 00925 const REAL8 f2 = LAL_EARTHFLAT*( 2.0 - LAL_EARTHFLAT ); 00926 00927 INITSTATUS( stat, "LALGeocentricToGeodetic", TERRESTRIALCOORDINATESC ); 00928 00929 /* Make sure parameter structure exists. */ 00930 ASSERT( location, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00931 00932 /* See if we've been given a special set of coordinates. */ 00933 x = rInv*location->x; 00934 y = rInv*location->y; 00935 z = rInv*location->z; 00936 pi = sqrt( x*x + y*y ); 00937 location->geodetic.system = COORDINATESYSTEM_GEOGRAPHIC; 00938 location->geodetic.longitude = atan2( y, x ); 00939 location->radius = LAL_REARTH_SI*sqrt( x*x + y*y + z*z ); 00940 if ( pi == 0.0 ) { 00941 if ( z >= 0.0 ) { 00942 location->geodetic.latitude = LAL_PI_2; 00943 location->elevation = z - f1; 00944 } else { 00945 location->geodetic.latitude = -LAL_PI_2; 00946 location->elevation = -z - f1; 00947 } 00948 location->elevation *= LAL_REARTH_SI; 00949 } 00950 00951 /* Do the general transformation even if z=0. */ 00952 else { 00953 REAL8 za, e, f, p, p3, q, q2, d, d2, b, v, w, g, h, gh, t, phi, tanP; 00954 /* intermediate variables */ 00955 00956 /* See if we're inside the singular ellipsoid. 00957 if ( pi <= 1.01*f2 ) { 00958 REAL8 z1 = z*f1/f2; 00959 REAL8 p1 = pi/f2; 00960 if ( z1*z1 + p1*p1 < 1.02 ) { 00961 ABORT( stat, SKYCOORDINATESH_ESING, SKYCOORDINATESH_MSGESING ); 00962 } 00963 } */ 00964 00965 /* Compute intermediates variables. */ 00966 za = f1*fabs( z ); 00967 e = za - f2; 00968 f = za + f2; 00969 p = ( 4.0/3.0 )*( pi*pi + za*za - f2*f2 ); 00970 p3 = p*p*p; 00971 q = 8.0*pi*f2*za; 00972 q2 = q*q; 00973 h = p3/q2; 00974 d = p3 + q2; 00975 00976 /* Compute v, using series expansion if necessary. */ 00977 if ( d >= 0.0 ) { 00978 d2 = sqrt( d ); 00979 b = q/d2; 00980 if ( fabs( h ) < LAL_HSERIES ) { 00981 if ( h < 0.0 ) 00982 v = pow( d2 + q, 1.0/3.0 ) 00983 + pow( -0.5*q*h*( 1.0 - 0.25*h*( 1.0 - 0.5*h ) ), 1.0/3.0 ); 00984 else 00985 v = pow( d2 + q, 1.0/3.0 ) 00986 - pow( 0.5*q*h*( 1.0 - 0.25*h*( 1.0 - 0.5*h ) ), 1.0/3.0 ); 00987 } else if ( b < LAL_BSERIES ) { 00988 v = pow( d2, 1.0/3.0 )*( b*( 2.0/3.0 + b*b*10.0/81.0 ) ); 00989 } else if ( b < 1.0 ) { 00990 v = pow( d2, 1.0/3.0 )*( pow( 1.0 + b, 1.0/3.0 ) - 00991 pow( 1.0 - b, 1.0/3.0 ) ); 00992 } else { 00993 v = pow( d2, 1.0/3.0 )*( pow( b + 1.0, 1.0/3.0 ) + 00994 pow( b - 1.0, 1.0/3.0 ) ); 00995 } 00996 } else { 00997 v = 2.0*sqrt( -p )*cos( acos( q/( -p*sqrt( -p ) ) )/3.0 ); 00998 } 00999 01000 /* Compute t, using series expansion if necessary. */ 01001 h = v*pi/( e*e ); 01002 w = fabs( e )*sqrt( 1.0 + h ); 01003 if ( e > 0.0 || h > LAL_HSERIES ) 01004 g = 0.5*( e + w ); 01005 else 01006 g = -0.25*e*h*( 1.0 - 0.25*h*( 1.0 - 0.5*h ) ); 01007 gh = fabs( pi*( f*pi - v*g )/w ); 01008 h = gh/( g*g ); 01009 if ( fabs( h ) > LAL_HSERIES ) 01010 t = g*( sqrt( 1.0 + h ) - 1.0 ); 01011 else 01012 t = 0.5*g*h*( 1.0 - 0.25*h*( 1.0 - 0.5*h ) ); 01013 01014 /* Compute latitude, longitude, and elevation. */ 01015 tanP = ( pi - t )*( pi + t )/( 2.0*f1*pi*t ); 01016 phi = atan( tanP ); 01017 location->geodetic.latitude = phi; 01018 if ( z < 0.0 ) 01019 location->geodetic.