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: 2007/06/08 14:41:47 $ 00024 * \brief Automatically converts among sky coordinate systems. 00025 * 00026 * $Id: SkyCoordinates.c,v 1.12 2007/06/08 14:41:47 bema Exp $ 00027 * 00028 00029 \par Description 00030 00031 The function LALConvertSkyCoordinates() transforms the contents 00032 of \a *input to the system 00033 specified in \a *params, storing the result in \a *output 00034 (which may point to the same object as \a *input for an in-place 00035 transformation). The routine makes calls to the functions in 00036 CelestialCoordinates.c and TerrestrialCoordinates.c as 00037 required; the \a *params object must store any data fields 00038 required by these functions, or an error will occur. 00039 00040 00041 The function LALNormalizeSkyPosition() ``normalizes'' any given 00042 (spherical) sky-position (in radians), which means it projects the 00043 angles into \f$[0, 2\pi) \times [-\pi/2, \pi/2]\f$ if they lie outside. 00044 00045 00046 \par Algorithm 00047 00048 LALConvertSkyCoordinates() is structured as a simple loop over 00049 transformations, each of which moves the output sky position one step 00050 closer to the desired final coordinates system. The usual ``flow'' of 00051 the algorithm is: 00052 \image html inject_ConvFlow.png 00053 \latexonly 00054 \begin{center} 00055 horizon 00056 \makebox[0pt][l]{\raisebox{0.4ex}{$\rightarrow$}}% 00057 \makebox[0pt][l]{\raisebox{-0.2ex}{$\leftarrow$}} 00058 \quad geographic 00059 \makebox[0pt][l]{\raisebox{0.4ex}{$\rightarrow$}}% 00060 \makebox[0pt][l]{\raisebox{-0.2ex}{$\leftarrow$}} 00061 \quad equatorial 00062 \makebox[0pt][l]{\raisebox{2.2ex}{$\nearrow$}}% 00063 \makebox[0pt][l]{\raisebox{1.8ex}{$\,\swarrow$}}% 00064 \makebox[0pt][l]{\raisebox{-1.8ex}{$\,\searrow$}}% 00065 \makebox[0pt][l]{\raisebox{-2.2ex}{$\nwarrow$}} 00066 \quad 00067 \makebox[0pt][l]{\raisebox{4ex}{ecliptic}}% 00068 \makebox[0pt][l]{\raisebox{-4ex}{Galactic}} 00069 \end{center} 00070 \endlatexonly 00071 although one can also convert directly between equatorial and horizon 00072 coordinate systems if \a params->zenith is given in equatorial 00073 coordinates (i.e.\ if its longitudinal coordinate is the local mean 00074 sidereal time rather than the geographic longitude of the observer). 00075 This leads to the only error checking done within this function: when 00076 transforming to horizon coordinates, it checks that 00077 \a params->zenith is either in sky-fixed equatorial or Earth-fixed 00078 geographic coordinates. Other than this, error checking is left to 00079 the secondary function call; if a parameter is absent or poorly 00080 formatted, the called function will return an error. 00081 00082 \par Uses 00083 \code 00084 LALHorizonToSystem() LALSystemToHorizon() 00085 LALGeographicToEquatorial() LALEquatorialToGeographic() 00086 LALEquatorialToEcliptic() LALEclipticToEquatorial() 00087 LALEquatorialToGalactic() LALGalacticToEquatorial() 00088 \endcode 00089 00090 */ 00091 00092 /*---------- laldoc-version of documentation follows ---------- */ 00093 00094 /******************************* <lalVerbatim file="SkyCoordinatesCV"> 00095 Author: Creighton, T. D. 00096 $Id: SkyCoordinates.c,v 1.12 2007/06/08 14:41:47 bema Exp $ 00097 **************************************************** </lalVerbatim> */ 00098 00099 /********************************************************** <lalLaTeX> 00100 00101 \subsection{Module \texttt{SkyCoordinates.c}} 00102 \label{ss:SkyCoordinates.c} 00103 00104 Automatically converts among sky coordinate systems. 00105 00106 \subsubsection*{Prototypes} 00107 \vspace{0.1in} 00108 \input{SkyCoordinatesCP} 00109 \idx{LALConvertSkyCoordinates()} 00110 \idx{LALNormalizeSkyPosition()} 00111 00112 \subsubsection*{Description} 00113 00114 The function \verb+LALConvertSkyCoordinates()+ transforms the contents 00115 of <tt>*input</tt> to the system 00116 specified in <tt>*params</tt>, storing the result in <tt>*output</tt> 00117 (which may point to the same object as <tt>*input</tt> for an in-place 00118 transformation). The routine makes calls to the functions in 00119 <tt>CelestialCoordinates.c</tt> and <tt>TerrestrialCoordinates.c</tt> as 00120 required; the <tt>*params</tt> object must store any data fields 00121 required by these functions, or an error will occur. 00122 00123 00124 The function \verb+LALNormalizeSkyPosition()+ ``normalizes'' any given 00125 (spherical) sky-position (in radians), which means it projects the 00126 angles into $[0, 2\pi) \times [-\pi/2, \pi/2]$ if they lie outside. 00127 00128 00129 \subsubsection*{Algorithm} 00130 00131 \verb+LALConvertSkyCoordinates()+ is structured as a simple loop over 00132 transformations, each 00133 of which moves the output sky position one step closer to the desired 00134 final coordinates system. The usual ``flow'' of the algorithm is: 00135 \begin{center} 00136 horizon 00137 \makebox[0pt][l]{\raisebox{0.4ex}{$\rightarrow$}}% 00138 \makebox[0pt][l]{\raisebox{-0.2ex}{$\leftarrow$}} 00139 \quad geographic 00140 \makebox[0pt][l]{\raisebox{0.4ex}{$\rightarrow$}}% 00141 \makebox[0pt][l]{\raisebox{-0.2ex}{$\leftarrow$}} 00142 \quad equatorial 00143 \makebox[0pt][l]{\raisebox{2.2ex}{$\nearrow$}}% 00144 \makebox[0pt][l]{\raisebox{1.8ex}{$\,\swarrow$}}% 00145 \makebox[0pt][l]{\raisebox{-1.8ex}{$\,\searrow$}}% 00146 \makebox[0pt][l]{\raisebox{-2.2ex}{$\nwarrow$}} 00147 \quad 00148 \makebox[0pt][l]{\raisebox{4ex}{ecliptic}}% 00149 \makebox[0pt][l]{\raisebox{-4ex}{Galactic}} 00150 \end{center} 00151 although one can also convert directly between equatorial and horizon 00152 coordinate systems if <tt>params->zenith</tt> is given in equatorial 00153 coordinates (i.e.\ if its longitudinal coordinate is the local mean 00154 sidereal time rather than the geographic longitude of the observer). 00155 This leads to the only error checking done within this function: when 00156 transforming to horizon coordinates, it checks that 00157 <tt>params->zenith</tt> is either in sky-fixed equatorial or Earth-fixed 00158 geographic coordinates. Other than this, error checking is left to 00159 the secondary function call; if a parameter is absent or poorly 00160 formatted, the called function will return an error. 00161 00162 \subsubsection*{Uses} 00163 \begin{verbatim} 00164 LALHorizonToSystem() LALSystemToHorizon() 00165 LALGeographicToEquatorial() LALEquatorialToGeographic() 00166 LALEquatorialToEcliptic() LALEclipticToEquatorial() 00167 LALEquatorialToGalactic() LALGalacticToEquatorial() 00168 \end{verbatim} 00169 00170 \subsubsection*{Notes} 00171 00172 \vfill{\footnotesize\input{SkyCoordinatesCV}} 00173 00174 ******************************************************* </lalLaTeX> */ 00175 00176 #include <math.h> 00177 #include <lal/LALStdlib.h> 00178 #include <lal/LALConstants.h> 00179 #include <lal/SkyCoordinates.h> 00180 00181 #define LAL_ALPHAGAL (3.366032942) 00182 #define LAL_DELTAGAL (0.473477302) 00183 #define LAL_LGAL (0.576) 00184 00185 NRCSID( SKYCOORDINATESC, "$Id: SkyCoordinates.c,v 1.12 2007/06/08 14:41:47 bema Exp $" ); 00186 00187 /* <lalVerbatim file="SkyCoordinatesCP"> */ 00188 void 00189 LALConvertSkyCoordinates( LALStatus *stat, 00190 SkyPosition *output, 00191 SkyPosition *input, 00192 ConvertSkyParams *params ) 00193 { /* </lalVerbatim> */ 00194 SkyPosition temp; /* temporary sky position (duh) */ 00195 00196 INITSTATUS( stat, "LALConvertSkyCoordinates", SKYCOORDINATESC ); 00197 ATTATCHSTATUSPTR( stat ); 00198 00199 /* Make sure parameter structures exist. */ 00200 ASSERT( input, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00201 ASSERT( output, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00202 ASSERT( params, stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00203 00204 /* Start looping! */ 00205 temp = *input; 00206 while ( temp.system != params->system ) { 00207 00208 if ( temp.system == COORDINATESYSTEM_HORIZON ) 00209 /* Only one possible direction. */ 00210 TRY( LALHorizonToSystem( stat->statusPtr, &temp, &temp, 00211 params->zenith ), stat ); 00212 00213 else if ( temp.system == COORDINATESYSTEM_GEOGRAPHIC ) { 00214 /* Two possible directions. But, if headed towards the horizon 00215 coordinate system, make sure we can get there! */ 00216 if ( params->system == COORDINATESYSTEM_HORIZON ) { 00217 if ( params->zenith ) { 00218 if ( params->zenith->system == COORDINATESYSTEM_GEOGRAPHIC ) 00219 TRY( LALSystemToHorizon( stat->statusPtr, &temp, &temp, 00220 params->zenith ), stat ); 00221 else if ( params->zenith->system == COORDINATESYSTEM_EQUATORIAL ) 00222 TRY( LALGeographicToEquatorial( stat->statusPtr, &temp, &temp, 00223 params->gpsTime ), stat ); 00224 else 00225 ABORT( stat, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); 00226 } else 00227 ABORT( stat, SKYCOORDINATESH_ENUL, SKYCOORDINATESH_MSGENUL ); 00228 } else 00229 TRY( LALGeographicToEquatorial( stat->statusPtr, &temp, &temp, 00230 params->gpsTime ), stat ); 00231 } 00232 00233 else if ( temp.system == COORDINATESYSTEM_EQUATORIAL ) { 00234 /* Up to four possible directions, depending on 00235 params->zenith->system. */ 00236 if ( ( params->system == COORDINATESYSTEM_HORIZON ) && 00237 ( params->zenith ) && 00238 ( params->zenith->system == COORDINATESYSTEM_EQUATORIAL ) ) 00239 TRY( LALSystemToHorizon( stat->statusPtr, &temp, &temp, 00240 params->zenith ), stat ); 00241 else if ( params->system == COORDINATESYSTEM_ECLIPTIC ) 00242 TRY( LALEquatorialToEcliptic( stat->statusPtr, &temp, &temp ), 00243 stat ); 00244 else if ( params->system == COORDINATESYSTEM_GALACTIC ) 00245 TRY( LALEquatorialToGalactic( stat->statusPtr, &temp, &temp ), 00246 stat ); 00247 else 00248 TRY( LALEquatorialToGeographic( stat->statusPtr, &temp, &temp, 00249 params->gpsTime ), stat ); 00250 } 00251 00252 else if ( temp.system == COORDINATESYSTEM_ECLIPTIC ) { 00253 /* Only one possible direction. */ 00254 TRY( LALEclipticToEquatorial( stat->statusPtr, &temp, &temp ), 00255 stat ); 00256 } 00257 00258 else if ( temp.system == COORDINATESYSTEM_GALACTIC ) { 00259 /* Only one possible direction. */ 00260 TRY( LALGalacticToEquatorial( stat->statusPtr, &temp, &temp ), 00261 stat ); 00262 } 00263 00264 else 00265 ABORT( stat, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); 00266 } 00267 00268 /* We've gotten to the correct coordinate system. Set the output 00269 and return. */ 00270 *output = temp; 00271 DETATCHSTATUSPTR( stat ); 00272 RETURN( stat ); 00273 00274 } /* LALConvertSkyCoordinates */ 00275 00276 00277 00278 /** LAL interface to XLALNormalizeSkyPosition() 00279 */ 00280 void 00281 LALNormalizeSkyPosition (LALStatus *stat, 00282 SkyPosition *posOut, /**< [out] normalized sky-position */ 00283 const SkyPosition *posIn) /**< [in] general sky-position */ 00284 { 00285 SkyPosition tmp; /* allow posOut == posIn */ 00286 00287 INITSTATUS( stat, "NormalizeSkyPosition", SKYCOORDINATESC); 00288 00289 ASSERT (posIn, stat, SKYCOORDINATESH_ENUL , SKYCOORDINATESH_MSGENUL ); 00290 ASSERT (posOut, stat, SKYCOORDINATESH_ENUL , SKYCOORDINATESH_MSGENUL ); 00291 00292 tmp = *posIn; 00293 00294 XLALNormalizeSkyPosition ( &tmp ); 00295 00296 *posOut = tmp; 00297 00298 RETURN (stat); 00299 00300 } /* LALNormalizeSkyPosition() */ 00301 00302 00303 /** If sky-position is not in the canonical range 00304 * \f$(\alpha,\delta)\in [0,2\pi]\times[-\pi/2, \pi/2]\f$, normalize it 00305 * by mapping it into this coordinate-interval. 00306 * Based on Alicia's function with some additional "unwinding" added. 00307 * return 0 = OK, -1 = ERROR 00308 */ 00309 int 00310 XLALNormalizeSkyPosition ( SkyPosition *posInOut ) /**< [in,out] sky-position to normalize*/ 00311 { 00312 SkyPosition tmp; 00313 00314 if ( !posInOut ) 00315 return -1; 00316 00317 tmp = *posInOut; 00318 00319 /* FIRST STEP: completely "unwind" positions, i.e. make sure that 00320 * [0 <= alpha < 2pi] and [-pi < delta <= pi] */ 00321 /* normalize longitude */ 00322 while (tmp.longitude < 0) 00323 tmp.longitude += LAL_TWOPI; 00324 while (tmp.longitude >= LAL_TWOPI) 00325 tmp.longitude -= LAL_TWOPI; 00326 00327 /* pre-normalize (unwind) latitude */ 00328 while (tmp.latitude <= -LAL_PI) 00329 tmp.latitude += LAL_TWOPI; 00330 while (tmp.latitude > LAL_TWOPI) 00331 tmp.latitude -= LAL_TWOPI; 00332 00333 /* SECOND STEP: get latitude into canonical interval [-pi/2 <= delta <= pi/2 ] */ 00334 /* this requires also a change in longitude by adding/subtracting PI */ 00335 if (tmp.latitude > LAL_PI_2) 00336 { 00337 tmp.latitude = LAL_PI - tmp.latitude; 00338 if (tmp.longitude < LAL_PI) 00339 { 00340 tmp.longitude += LAL_PI; 00341 } 00342 else 00343 { 00344 tmp.longitude -= LAL_PI; 00345 } 00346 } 00347 00348 if (tmp.latitude < -LAL_PI_2) 00349 { 00350 tmp.latitude = -LAL_PI - tmp.latitude; 00351 if (tmp.longitude < LAL_PI) 00352 { 00353 tmp.longitude += LAL_PI; 00354 } 00355 else 00356 { 00357 tmp.longitude -= LAL_PI; 00358 } 00359 } 00360 00361 *posInOut = tmp; 00362 00363 return 0; 00364 00365 } /* XLALNormalizeSkyPosition() */
1.5.2