DopplerLatticeCovering.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Reinhard Prix
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 /**
00021  * \author Reinhard Prix
00022  * \date 2006
00023  * \file
00024  * \brief Functions for optimal lattice-covering of Doppler-spaces.
00025  * NOTE: this module always uses *ECLIPTIC* coordinates for interal operations
00026  */
00027 
00028 /*---------- INCLUDES ----------*/
00029 #include <math.h>
00030 #include <gsl/gsl_sys.h>
00031 
00032 #include <lal/LALStdlib.h>
00033 #include <lal/DetectorSite.h>
00034 #include <lal/LALError.h>
00035 #include <lal/LatticeCovering.h>
00036 #include <lal/LogPrintf.h>
00037 
00038 #include <lal/FlatPulsarMetric.h>
00039 #include <lal/DopplerFullScan.h>
00040 #include <lal/DopplerLatticeCovering.h>
00041 
00042 /*---------- DEFINES ----------*/
00043 NRCSID( DOPPLERLATTICECOVERING, "$Id: DopplerLatticeCovering.c,v 1.1 2007/10/26 16:03:10 reinhard Exp $" );
00044 
00045 /* turn off  gsl range-checking in non-debug compilations */
00046 #ifdef LAL_NDEBUG
00047 #define GSL_RANGE_CHECK_OFF 1
00048 #endif
00049 
00050 #define EPS_REAL8       1e-10   /**< relative error used in REAL8 comparisons */
00051 
00052 #define TRUE (1==1)
00053 #define FALSE (1==0)
00054 
00055 #define NUM_SPINS       PULSAR_MAX_SPINS
00056 #define DIM_CANONICAL   (2 + NUM_SPINS)         /**< dimension of 'canonical' Doppler-space */
00057 
00058 #define MIN(x,y) (x < y ? x : y)
00059 #define MAX(x,y) (x > y ? x : y)
00060 #define SIGN(x) ( x < 0 ? -1 : ( x > 0 ? 1 : 0 ) )
00061 
00062 #define SQUARE(x) ( (x) * (x) )
00063 #define VECT_NORM(x) sqrt( SQUARE((x)[0]) + SQUARE((x)[1]) + SQUARE((x)[2]) )
00064 #define VECT_ADD(x,y) do { (x)[0] += (y)[0]; (x)[1] += (y)[1]; (x)[2] += (y)[2]; } while(0)
00065 #define VECT_MULT(x,k) do { (x)[0] *= k; (x)[1] *= k; (x)[2] *= k; } while(0)
00066 #define VECT_COPY(dst,src) do { (dst)[0] = (src)[0]; (dst)[1] = (src)[1]; (dst)[2] = (src)[2]; } while(0)
00067 
00068 #define VECT_HEMI(x) ( (x)[2] < 0 ? HEMI_SOUTH : ( (x)[2] > 0 ? HEMI_NORTH : 0 ) )
00069 
00070 /*---------- internal types ----------*/
00071 typedef enum {
00072   HEMI_BOTH  =  0,      /**< points lie on both hemispheres */
00073   HEMI_NORTH =  1,      /**< all points on northern hemisphere */
00074   HEMI_SOUTH =  2       /**< all points on southern hemisphere */
00075 } hemisphere_t;
00076 
00077 typedef REAL8 vect2D_t[2];      /**< 2D vector */
00078 typedef REAL8 vect3D_t[3];      /**< 3D vector */
00079 
00080 /** 2D-polygon of points {nX, nY} on a single hemisphere of ecliptic sky-sphere */
00081 typedef struct {
00082   UINT4 length;                 /**< number of elements */
00083   vect2D_t *data;               /**< array of 2D vectors */
00084 } vect2Dlist_t;
00085 
00086 /** List of 3D vectors */
00087 typedef struct {
00088   UINT4 length;                 /**< number of elements */
00089   vect3D_t *data;               /**< array of 3D vectors */
00090 } vect3Dlist_t;
00091 
00092 /** 'standard' representation of Doppler-paremeters */
00093 typedef struct {
00094   vect2D_t vn;                  /**< X, Y, component of ecliptic unit-vector to sky-location */
00095   PulsarSpins fkdot;            /**< vector of spins f^(k) */
00096 } dopplerParams_t;
00097 
00098 /** boundary of (single-hemisphere) search region in Doppler-space */
00099 typedef struct {
00100   vect2Dlist_t skyRegion;       /**< (ecliptic) 2D vector-polygon {kX, kY} defining the sky search-region */
00101   hemisphere_t hemisphere;      /**< hemisphere of sky vector-polygon */
00102   LIGOTimeGPS refTime;          /**< SSB reference GPS-time at which spin-range is defined */
00103   PulsarSpins fkdot;            /**< Vector of canonical spin-values w^(k) */
00104   PulsarSpins fkdotBand;        /**< Vector of canonical spin-bands Delta w^(k) */
00105 } dopplerBoundary_t;
00106 
00107 struct tagDopplerLatticeScan {
00108   scan_state_t state;           /**< current state of the scan: idle, ready of finished */
00109   REAL8 Tspan;                  /**< total observation time spanned */
00110   dopplerBoundary_t boundary;   /**< boundary of search-space to cover */
00111   UINT4 dimLattice;             /**< dimension of nonzero-band search-lattice (can be <= dimCanonical) */
00112   gsl_vector *canonicalOrigin;  /**< 'origin' of the lattice in canonical coords {lb0, lb1, lb2, ... } */
00113   gsl_vector *dopplerUnits;     /**< conversion-factors from 'doppler' {f0, nX, nY, f1, ...} to 'canonical'-coords */
00114   gsl_matrix *latticeGenerator; /**< generating matrix for the lattice: rows are the lattice-vectors */
00115   gsl_vector_int *latticeIndex; /**< "Index" = multi-dim index-counters of current lattice point */
00116   gsl_vector_int *prevIndexBoundaryUp;  /**< last positive turning point */
00117   gsl_vector_int *prevIndexCenter; /**< where was our index-center previously */
00118   gsl_vector_int *map2canonical;/**< mapping of lattice-Index into (canonical) Index {i0, i1, i2, ... } */
00119 };
00120 
00121 /*---------- empty initializers ---------- */
00122 dopplerParams_t empty_dopplerParams;
00123 
00124 /*---------- Global variables ----------*/
00125 extern INT4 lalDebugLevel;
00126 
00127 /*---------- internal function prototypes ----------*/
00128 void skyRegionString2vect3D ( LALStatus *, vect3Dlist_t **skyRegionEcl, const CHAR *skyRegionString );
00129 void setupSearchRegion ( LALStatus *status, DopplerLatticeScan *scan, const DopplerRegion *searchRegion );
00130 
00131 hemisphere_t onWhichHemisphere ( const vect3Dlist_t *skypoints );
00132 int skyposToVect3D ( vect3D_t *eclVect, const SkyPosition *skypos );
00133 int vect2DToSkypos ( SkyPosition *skypos, const vect2D_t *vect2D, hemisphere_t hemi );
00134 int findCenterOfMass ( vect3D_t *center, const vect3Dlist_t *points );
00135 
00136 int IndexToCanonical ( gsl_vector **canonicalOffset, const gsl_vector_int *Index, const DopplerLatticeScan *scan );
00137 int XLALIndexToDoppler ( dopplerParams_t *doppler, const gsl_vector_int *Index, const DopplerLatticeScan *scan );
00138 int isIndexInsideBoundary ( const gsl_vector_int *Index, const DopplerLatticeScan *scan );
00139 
00140 int convertDoppler2Canonical ( gsl_vector **canonicalPoint, const dopplerParams_t *doppler, const gsl_vector *dopplerUnits );
00141 int convertCanonical2Doppler ( dopplerParams_t *doppler, const gsl_vector *canonical, const gsl_vector *dopplerUnits );
00142 
00143 int vect2DInPolygon ( const vect2D_t *point, const vect2Dlist_t *polygon );
00144 int isDopplerInsideBoundary ( const dopplerParams_t *doppler,  const dopplerBoundary_t *boundary );
00145 
00146 int fprintf_vect2D ( FILE *fp, const vect2D_t *vect, hemisphere_t hemi );
00147 int fprintf_vect2Dlist ( FILE *fp, const vect2Dlist_t *list, hemisphere_t hemi );
00148 DopplerLatticeScan *XLALDuplicateDopplerLatticeScan ( const DopplerLatticeScan *scan );
00149 
00150 /*==================== FUNCTION DEFINITIONS ====================*/
00151 
00152 /* ------------------------------------------------------ */
00153 /* -------------------- EXTERNAL API -------------------- */
00154 /* ------------------------------------------------------ */
00155 
00156 /** Initialize search-grid using optimal lattice-covering
00157  */
00158 void
00159 InitDopplerLatticeScan ( LALStatus *status,
00160                          DopplerLatticeScan **scan,             /**< [out] initialized scan-state for lattice-scan */
00161                          const DopplerLatticeInit *init         /**< [in] scan init parameters */
00162                          )
00163 {
00164   DopplerLatticeScan *ret = NULL;
00165   gsl_matrix *gij, *gijLattice;
00166   UINT4 i, j;
00167 
00168   INITSTATUS( status, "InitDopplerLatticeScan", DOPPLERLATTICECOVERING );
00169   ATTATCHSTATUSPTR ( status );
00170 
00171   ASSERT ( scan, status, DOPPLERSCANH_ENULL, DOPPLERSCANH_MSGENULL );
00172   ASSERT ( *scan == NULL, status, DOPPLERSCANH_ENONULL, DOPPLERSCANH_MSGENONULL );
00173   ASSERT ( init, status, DOPPLERSCANH_ENULL, DOPPLERSCANH_MSGENULL );
00174 
00175   /* prepare scan-structure to return */
00176   if ( (ret = LALCalloc ( 1, sizeof(*ret) )) == NULL ) {
00177     ABORT (status, DOPPLERSCANH_EMEM, DOPPLERSCANH_MSGEMEM);
00178   }
00179 
00180   /* first store observation-time, required for conversion 'Doppler <--> canonical' */
00181   ret->Tspan = init->Tspan;
00182 
00183   /* ----- get search-Region ----- */
00184   TRY ( setupSearchRegion ( status->statusPtr, ret, &(init->searchRegion) ), status );
00185 
00186   /* ----- compute flat metric ----- */
00187   if ( (gij = gsl_matrix_calloc (DIM_CANONICAL, DIM_CANONICAL)) == NULL ) {
00188     ABORT (status, DOPPLERSCANH_EMEM, DOPPLERSCANH_MSGEMEM);
00189   }
00190 
00191   if ( XLALFlatMetricCW ( gij, init->searchRegion.refTime, init->startTime, init->Tspan, init->ephemeris ) ) {
00192     ABORT ( status, DOPPLERSCANH_EXLAL, DOPPLERSCANH_MSGEXLAL );
00193   }
00194 #ifdef DEBUG_ANS
00195   fprintf ( stderr, "\ngij = ");
00196   XLALfprintfGSLmatrix ( stderr, "% 15.9e ", gij );
00197 #endif
00198 
00199   /* ----- reduce metric to subspace with actual nonzero search-bands !! ----- */
00200   if ( ( gijLattice = gsl_matrix_calloc ( ret->dimLattice, ret->dimLattice )) == NULL ) {
00201     ABORT (status, DOPPLERSCANH_EMEM, DOPPLERSCANH_MSGEMEM);
00202   }
00203   for ( i=0; i < ret->dimLattice; i ++ )
00204     {
00205       for ( j=i; j < ret->dimLattice; j ++ )
00206         {
00207           UINT4 iMap, jMap;
00208           REAL8 gijMap;
00209           iMap = gsl_vector_int_get( ret->map2canonical, i );
00210           jMap = gsl_vector_int_get( ret->map2canonical, j );
00211           gijMap = gsl_matrix_get ( gij, iMap, jMap );
00212           gsl_matrix_set ( gijLattice, i, j, gijMap );
00213           gsl_matrix_set ( gijLattice, j, i, gijMap );
00214         } /* for j < dimLattice */
00215     } /* for i < dimLattice */
00216 
00217 #ifdef DEBUG_ANS
00218   fprintf ( stderr, "gijLattice = ");
00219   XLALfprintfGSLmatrix ( stderr, "% 15.9e ", gijLattice );
00220 #endif
00221 
00222   /* ----- compute generating matrix for the lattice ----- */
00223   if ( XLALFindCoveringGenerator (&(ret->latticeGenerator), LATTICE_TYPE_ANSTAR, sqrt(init->metricMismatch), gijLattice ) ) {
00224     ABORT ( status, DOPPLERSCANH_EXLAL, DOPPLERSCANH_MSGEXLAL );
00225   }
00226 #ifdef DEBUG_ANS
00227   fprintf ( stderr, "generator = ");
00228   XLALfprintfGSLmatrix ( stderr, "% 15.9e ", ret->latticeGenerator );
00229 
00230   fprintf ( stderr, "origin = ");
00231   XLALfprintfGSLvector ( stderr, "% .9e ", ret->canonicalOrigin );
00232   fprintf ( stderr, "\n");
00233 #endif
00234 
00235   /* ----- prepare Index-counters to generate lattice-points ----- */
00236   if ( (ret->latticeIndex = gsl_vector_int_calloc ( ret->dimLattice )) == NULL ) {
00237     ABORT (status, DOPPLERSCANH_EMEM, DOPPLERSCANH_MSGEMEM);
00238   }
00239   if ( (ret->prevIndexBoundaryUp = gsl_vector_int_calloc ( ret->dimLattice )) == NULL ) {
00240     ABORT (status, DOPPLERSCANH_EMEM, DOPPLERSCANH_MSGEMEM);
00241   }
00242   if ( (ret->prevIndexCenter = gsl_vector_int_calloc ( ret->dimLattice )) == NULL ) {
00243     ABORT (status, DOPPLERSCANH_EMEM, DOPPLERSCANH_MSGEMEM);
00244   }
00245 
00246   /* clean up memory */
00247   gsl_matrix_free ( gij );
00248   gsl_matrix_free ( gijLattice );
00249 
00250   /* return final scan-state */
00251   ret->state = STATE_READY;
00252   (*scan) = ret;
00253 
00254   /* debug */
00255   {
00256     PulsarDopplerParams doppler = empty_PulsarDopplerParams;
00257     XLALgetCurrentDopplerPos ( &doppler, ret, COORDINATESYSTEM_EQUATORIAL );
00258     fprintf ( stderr, "dopplerOrigin: ");
00259     fprintfDopplerParams ( stderr, &doppler );
00260   }
00261 
00262 
00263   DETATCHSTATUSPTR ( status );
00264   RETURN ( status );
00265 
00266 } /* InitDopplerLatticeScan() */
00267 
00268 
00269 /** Free an allocated DopplerLatticeScan.
00270  * Return: 0=OK, -1=ERROR
00271  */
00272 int
00273 XLALFreeDopplerLatticeScan ( DopplerLatticeScan **scan )
00274 {
00275   if ( !scan || !(*scan) )
00276     return -1;
00277 
00278   if ( (*scan)->boundary.skyRegion.data )
00279     LALFree ( (*scan)->boundary.skyRegion.data );
00280 
00281   if ( (*scan)->canonicalOrigin )
00282     gsl_vector_free ( (*scan)->canonicalOrigin );
00283 
00284   if ( (*scan)->latticeGenerator )
00285     gsl_matrix_free ( (*scan)->latticeGenerator );
00286 
00287   if ( (*scan)->latticeIndex )
00288     gsl_vector_int_free ( (*scan)->latticeIndex );
00289 
00290   if ( (*scan)->prevIndexBoundaryUp )
00291     gsl_vector_int_free ( (*scan)->prevIndexBoundaryUp );
00292 
00293   if ( (*scan)->prevIndexCenter )
00294     gsl_vector_int_free ( (*scan)->prevIndexCenter );
00295 
00296   if ( (*scan)->map2canonical )
00297     gsl_vector_int_free ( (*scan)->map2canonical );
00298 
00299   LALFree ( (*scan) );
00300   (*scan) = NULL;
00301 
00302   return 0;
00303 
00304 } /* XLALFreeDopplerLatticeScan() */
00305 
00306 
00307 /** Return current lattice Index of the scan:
00308  * allocate Index here if *Index == NULL, otherwise use given vector
00309  * [has to have right dimension]
00310  */
00311 int
00312 XLALgetCurrentLatticeIndex ( gsl_vector_int **Index, const DopplerLatticeScan *scan  )
00313 {
00314   const CHAR *fn = "XLALgetCurrentLatticeIndex()";
00315 
00316   if ( !Index || !scan || (scan->state != STATE_READY ) ) {
00317     XLAL_ERROR (fn, XLAL_EINVAL );
00318   }
00319 
00320   if ( *Index == NULL ) /* allocate output-vector */
00321     {
00322       if ( ((*Index) = gsl_vector_int_calloc ( scan->dimLattice )) == NULL ) {
00323         XLAL_ERROR (fn, XLAL_ENOMEM );
00324       }
00325     }
00326   else if ( (*Index)->size != scan->dimLattice ) {
00327     LALPrintError ("\n\nOutput vector has wrong dimension %d instead of %d!\n\n", (*Index)->size, scan->dimLattice);
00328     XLAL_ERROR (fn, XLAL_EINVAL );
00329   }
00330 
00331   gsl_vector_int_memcpy ( (*Index), scan->latticeIndex );
00332 
00333   return 0;
00334 } /* XLALgetCurrentLatticeIndex() */
00335 
00336 /** Set the current index of the scan.
00337  */
00338 int
00339 XLALsetCurrentLatticeIndex ( DopplerLatticeScan *scan, const gsl_vector_int *Index )
00340 {
00341   const CHAR *fn = "XLALsetCurrentLatticeIndex()";
00342 
00343   if ( !Index || !scan || (scan->state != STATE_READY) || (Index->size != scan->dimLattice) ) {
00344     XLAL_ERROR (fn, XLAL_EINVAL );
00345   }
00346 
00347   gsl_vector_int_memcpy ( scan->latticeIndex, Index );
00348 
00349   return 0;
00350 } /* XLALsetCurrentLatticeIndex() */
00351 
00352 /** Count number of templates in lattice-grid by stepping through the whole
00353  * grid. NOTE: original scan-state isn't modified.
00354  *
00355  * Return: > 0: OK, -1=ERROR
00356  */
00357 REAL8
00358 XLALCountLatticeTemplates ( const DopplerLatticeScan *scan )
00359 {
00360   int ret;
00361   REAL8 counter;
00362   DopplerLatticeScan *dupl;
00363 
00364  if ( !scan || scan->state != STATE_READY )
00365     return -1;
00366 
00367  if ( (dupl = XLALDuplicateDopplerLatticeScan ( scan )) == NULL )
00368    return -1;
00369 
00370  counter = 0;
00371  while ( (ret = XLALadvanceLatticeIndex ( dupl )) == 0 )
00372    counter ++;
00373 
00374  XLALFreeDopplerLatticeScan ( &dupl );
00375 
00376  if ( ret < 0 )
00377    return -1;
00378  else
00379    return counter;
00380 
00381 } /* XLALCountLatticeTemplates() */
00382 
00383 
00384 /** The central "lattice-stepping" function: advance to the 'next' Index-point, taking care not
00385  * to leave the boundary, and to cover the whole (convex!) search-region eventually!
00386  *
00387  * \note Algorithm:
00388  o) start with first Index-dimension aI = 0
00389  1) if Index(aI) >= 0: Index(aI) ++; else   Index(aI) --;
00390     i.e. increase for pos Index, decrease for negative ones ==> always walk "outwards"
00391     from origin, towards boundaries)
00392  o) if resulting point lies inside boundary ==> keep & return
00393 
00394  o) if boundary was crossed: return aI to origin: Index(aI) = 0;
00395  o) step to next dimension: aI ++;
00396  o) if no more dimensions left: aI >= dim ==> no further lattice-points! RETURN
00397  o) else continue at 1)
00398  *
00399  *
00400  * Return: 0=OK, -1=ERROR,  +1=No more lattice points left
00401  */
00402 int
00403 XLALadvanceLatticeIndex ( DopplerLatticeScan *scan )
00404 {
00405   const CHAR *fn = "XLALadvanceLatticeIndex()";
00406   UINT4 dim, aI;
00407   int ret;
00408   gsl_vector_int *next_Index;
00409 
00410   if ( !scan || scan->state != STATE_READY ) {
00411     XLAL_ERROR (fn, XLAL_EINVAL );
00412   }
00413 
00414   dim = scan->dimLattice;
00415 
00416   if ( (next_Index = gsl_vector_int_calloc ( dim )) == NULL ) {
00417     XLAL_ERROR (fn, XLAL_ENOMEM );
00418   }
00419 
00420   gsl_vector_int_memcpy ( next_Index, scan->latticeIndex );
00421 
00422   aI = 0;
00423   do
00424     {
00425       int *pindex = gsl_vector_int_ptr (next_Index, aI);        /* pointer to current Index-element */
00426       int prev_center = gsl_vector_int_get ( scan->prevIndexCenter, aI ) ;
00427       /* check sign of current Index-element  */
00428       if ( ((*pindex) - prev_center) >= 0 )     /* step "up" if "above" center */
00429         {
00430           (*pindex) ++;
00431           ret = isIndexInsideBoundary ( next_Index, scan );
00432           if ( ret < 0 ) return -1;     /* ERROR */
00433           else if ( ret > 0 )
00434             {
00435               gsl_vector_int_memcpy ( scan->latticeIndex, next_Index );
00436               return 0; /* OK: found point */
00437             }
00438           else  /* reached "upper" boundary on aI */
00439             {
00440               UINT4 bI;
00441               gsl_vector_int_set ( scan->prevIndexBoundaryUp, aI, (*pindex) - 1 ); /* keep track of new turning point */
00442               (*pindex) = prev_center;  /* return to (previous) center of the line */
00443               for (bI=0; bI < aI; bI ++ )
00444                 {
00445                   gsl_vector_int_set ( next_Index, bI, 0 ); /* return to origin for all lower dimensions */
00446                   gsl_vector_int_set ( scan->prevIndexBoundaryUp, bI, 0 );
00447                   gsl_vector_int_set ( scan->prevIndexCenter, bI, 0 );
00448                 }
00449             } /* reached 'upper' boundary */
00450         } /* try a step "up" */
00451 
00452       /* try a step "down" */
00453       (*pindex) --;
00454       ret = isIndexInsideBoundary ( next_Index, scan );
00455       if ( ret < 0 ) return -1; /* ERROR */
00456       else if ( ret > 0 )
00457         {
00458           gsl_vector_int_memcpy ( scan->latticeIndex, next_Index );
00459           return 0;     /* OK: found point */
00460         }
00461 
00462       /* reached "lower" boundary on aI ==> bump next dimension*/
00463       {
00464         /* try advancing to the next dimension
00465          * the key-trick is that we re-center the point in aI, so we should
00466          * have better chances of success in advancing.
00467          * Note: this will probably only work for sure [if at all?]
00468          * for convex regions to be filled
00469          */
00470         int thisBoundaryDown = (*pindex) + 1;
00471         int thisBoundaryUp   = gsl_vector_int_get ( scan->prevIndexBoundaryUp, aI );
00472         int new_center = (int)(0.5 * (thisBoundaryUp + thisBoundaryDown) );
00473         (*pindex) = new_center;
00474         gsl_vector_int_set ( scan->prevIndexCenter, aI, new_center );
00475       }
00476 
00477       aI ++;
00478 
00479     } while ( aI < dim );
00480 
00481   gsl_vector_int_free ( next_Index );
00482 
00483   return 1;     /* no more points could be found! */
00484 
00485 } /* XLALadvanceLatticeIndex() */
00486 
00487 
00488 /** Return the current doppler-position {Freq, Alpha, Delta, f1dot, f2dot, ... } of the lattice-scan
00489  *  NOTE: the skyposition coordinate-system is chosen via 'skyCoords' in [EQUATORIAL, ECLIPTIC]
00490  */
00491 int
00492 XLALgetCurrentDopplerPos ( PulsarDopplerParams *pos, const DopplerLatticeScan *scan, CoordinateSystem skyCoords )
00493 {
00494   const CHAR *fn = "XLALgetCurrentDopplerPos()";
00495   dopplerParams_t doppler = empty_dopplerParams;
00496   SkyPosition skypos = empty_SkyPosition;
00497 
00498   if ( !pos || !scan || (scan->state != STATE_READY) ) {
00499     XLAL_ERROR (fn, XLAL_EINVAL );
00500   }
00501 
00502   if ( XLALIndexToDoppler ( &doppler, scan->latticeIndex, scan ) ) {
00503     XLAL_ERROR (fn, XLAL_EFUNC );
00504   }
00505 
00506   skypos.system = skyCoords;
00507   if ( vect2DToSkypos ( &skypos, (const vect2D_t*)&(doppler.vn), scan->boundary.hemisphere) ) {
00508     XLAL_ERROR (fn, XLAL_EFUNC );
00509   }
00510 
00511   /* convert into PulsarDopplerParams type */
00512   pos->refTime          = scan->boundary.refTime;
00513   pos->Alpha            = skypos.longitude;
00514   pos->Delta            = skypos.latitude;
00515   memcpy ( pos->fkdot, doppler.fkdot, sizeof(pos->fkdot) );
00516   pos->orbit            = NULL;         /* FIXME: not supported yet */
00517 
00518   return 0;
00519 } /* XLALgetCurrentDopplerPos() */
00520 
00521 
00522 
00523 /* ------------------------------------------------------------ */
00524 /* -------------------- INTERNAL functions -------------------- */
00525 /* ------------------------------------------------------------ */
00526 
00527 /** Return a copy a full DopplerLatticeScan state, useful as a backup
00528  * while counting the lattice.
00529  *
00530  * Return: NULL=ERROR
00531  */
00532 DopplerLatticeScan *
00533 XLALDuplicateDopplerLatticeScan ( const DopplerLatticeScan *scan )
00534 {
00535   DopplerLatticeScan *ret;
00536   size_t size;
00537   void *src, *dst;
00538 
00539   if (!scan || scan->state == STATE_IDLE )
00540     return NULL;
00541 
00542   if ( (ret = LALCalloc ( 1, sizeof(*ret) )) == NULL )
00543     return NULL;
00544 
00545   (*ret) = (*scan);     /* struct-copy everything non-alloc'ed */
00546 
00547   /* properly copy everything alloc'ed */
00548 
00549   /* 'char*' */
00550   if ( (src = scan->boundary.skyRegion.data) )
00551     {
00552       size = sizeof(*scan->boundary.skyRegion.data);
00553       if ( (dst = LALCalloc(1, size)) == NULL  )
00554         return NULL;
00555       memcpy ( dst, src, size );
00556       ret->boundary.skyRegion.data = dst;
00557     }
00558 
00559   /* gsl_vector */
00560   if ( (src = scan->canonicalOrigin) )
00561     {
00562       size = scan->canonicalOrigin->size;
00563       if ( (dst = gsl_vector_alloc(size)) == NULL  )
00564         return NULL;
00565       gsl_vector_memcpy ( dst, src );
00566       ret->canonicalOrigin = dst;
00567     }
00568 
00569   /* gsl_matrix */
00570   if ( (src = scan->latticeGenerator) )
00571     {
00572       size = scan->latticeGenerator->size1;
00573       if ( (dst = gsl_matrix_alloc(size,size)) == NULL  )
00574         return NULL;
00575       gsl_matrix_memcpy ( dst, src );
00576       ret->latticeGenerator = dst;
00577     }
00578 
00579   /* gsl_vector_int */
00580   if ( (src = scan->latticeIndex) )
00581     {
00582       size = scan->latticeIndex->size;
00583       if ( (dst = gsl_vector_int_alloc(size)) == NULL  )
00584         return NULL;
00585       gsl_vector_int_memcpy ( dst, src );
00586       ret->latticeIndex = dst;
00587     }
00588   if ( (src = scan->prevIndexBoundaryUp) )
00589     {
00590       size = scan->prevIndexBoundaryUp->size;
00591       if ( (dst = gsl_vector_int_alloc(size)) == NULL  )
00592         return NULL;
00593       gsl_vector_int_memcpy ( dst, src );
00594       ret->prevIndexBoundaryUp = dst;
00595     }
00596   if ( (src = scan->prevIndexCenter) )
00597     {
00598       size = scan->prevIndexCenter->size;
00599       if ( (dst = gsl_vector_int_alloc(size)) == NULL  )
00600         return NULL;
00601       gsl_vector_int_memcpy ( dst, src );
00602       ret->prevIndexCenter = dst;
00603     }
00604   if ( (src = scan->map2canonical) )
00605     {
00606       size = scan->map2canonical->size;
00607       if ( (dst = gsl_vector_int_alloc(size)) == NULL  )
00608         return NULL;
00609       gsl_vector_int_memcpy ( dst, src );
00610       ret->map2canonical = dst;
00611     }
00612 
00613   return ret;
00614 
00615 } /* XLALDuplicateDopplerLatticeScan() */
00616 
00617 
00618 
00619 /** Convert given Index into doppler-params
00620  * Return: 0=OK, -1=ERROR
00621  */
00622 int
00623 XLALIndexToDoppler ( dopplerParams_t *doppler, const gsl_vector_int *Index, const DopplerLatticeScan *scan )
00624 {
00625   const CHAR *fn = "XLALIndexToDoppler()";
00626   gsl_vector *canonical = NULL;
00627 
00628   if ( !doppler || !Index || !scan ) {
00629     XLAL_ERROR (fn, XLAL_EINVAL );
00630   }
00631 
00632   if ( IndexToCanonical ( &canonical, Index, scan ) ) {
00633     XLAL_ERROR (fn, XLAL_EFUNC );
00634   }
00635 
00636   if ( convertCanonical2Doppler ( doppler, canonical, scan->dopplerUnits ) ) {
00637     gsl_vector_free ( canonical );
00638     XLAL_ERROR (fn, XLAL_EFUNC );
00639   }
00640   gsl_vector_free ( canonical );
00641 
00642   return 0;
00643 
00644 } /* XLALIndexToDoppler() */
00645 
00646 
00647 
00648 /** Determine whether the given lattice-Index corresponds to a Doppler-point
00649  * that lies within the search-boundary
00650  *  Return: TRUE, FALSE,  -1 = ERROR
00651  */
00652 int
00653 isIndexInsideBoundary ( const gsl_vector_int *Index, const DopplerLatticeScan *scan )
00654 {
00655   dopplerParams_t doppler = empty_dopplerParams;
00656 
00657   if ( !Index || !scan || scan->state != STATE_READY )
00658     return -1;
00659 
00660   if ( XLALIndexToDoppler ( &doppler, Index, scan ) )
00661     return -1;
00662 
00663   return ( isDopplerInsideBoundary ( &doppler,  &scan->boundary ) );
00664 
00665 } /* isIndexInsideBoundary() */
00666 
00667 
00668 /** Determine whether the given Doppler-point lies within the search-boundary
00669  *  Return: TRUE, FALSE,  -1 = ERROR
00670  */
00671 int
00672 isDopplerInsideBoundary ( const dopplerParams_t *doppler,  const dopplerBoundary_t *boundary )
00673 {
00674   vect2D_t skyPoint = {0, 0};
00675   int insideSky, insideSpins;
00676   UINT4 s;
00677 
00678   if ( !doppler || !boundary )
00679     return -1;
00680 
00681   skyPoint[0] = doppler->vn[0];
00682   skyPoint[1] = doppler->vn[1];
00683 
00684   if ( (insideSky = vect2DInPolygon ( (const vect2D_t*)skyPoint, &(boundary->skyRegion) )) < 0 )
00685     return -1;
00686 
00687 #ifdef DEBUG_ANS
00688   /* ===== debug ===== */
00689   {
00690     FILE *fp = fopen ("gridpoints.dat", "ab");
00691     fprintf (fp, "%f, %f, ", skyPoint[0], skyPoint[1] );
00692     fprintf_vect2D ( fp, (const vect2D_t*)skyPoint, boundary->hemisphere );
00693     fclose(fp);
00694   }
00695 #endif
00696 
00697   insideSpins = TRUE;
00698   for ( s=0; s < NUM_SPINS; s ++ )
00699     {
00700       double fkdotMax = boundary->fkdot[s] + boundary->fkdotBand[s];
00701       double fkdotMin = boundary->fkdot[s];
00702       if ( ( gsl_fcmp ( doppler->fkdot[s], fkdotMax, EPS_REAL8 ) > 0 ) ||
00703            ( gsl_fcmp ( doppler->fkdot[s], fkdotMin, EPS_REAL8 ) < 0 ) )
00704         insideSpins = ( insideSpins && FALSE );
00705     } /* for s < NUM_SPINS */
00706 
00707   return ( insideSky && insideSpins );
00708 
00709 } /* insideBoundary() */
00710 
00711 
00712 /** Translate the input 'DopplerRegion' into an internal representation for the scan.
00713  *
00714  * \note DopplerLatticeScan->Tspan must have been set! This is used for conversion Doppler -> canonical
00715  */
00716 void
00717 setupSearchRegion ( LALStatus *status, DopplerLatticeScan *scan, const DopplerRegion *searchRegion )
00718 {
00719   UINT4 i;
00720   vect3Dlist_t *points3D = NULL;
00721 
00722   INITSTATUS( status, "InitDopplerLatticeScan", DOPPLERLATTICECOVERING );
00723   ATTATCHSTATUSPTR ( status );
00724 
00725   ASSERT ( scan, status, DOPPLERSCANH_ENULL, DOPPLERSCANH_MSGENULL );
00726   ASSERT ( searchRegion, status, DOPPLERSCANH_ENULL, DOPPLERSCANH_MSGENULL );
00727 
00728   /* ----- convert sky-string to polygon ----- */
00729   TRY ( skyRegionString2vect3D ( status->statusPtr, &points3D, searchRegion->skyRegionString ), status );
00730 
00731   /* ----- map lattice-indices to Doppler-dimensions with nonzero search-bands ----- */
00732   {
00733     gsl_vector_int *mapTmp;
00734     UINT4 s, l;
00735     if ( (mapTmp = gsl_vector_int_calloc ( DIM_CANONICAL )) == NULL ) { /* <= dimLattice */
00736       ABORT (status, DOPPLERSCANH_EMEM, DOPPLERSCANH_MSGEMEM);
00737     }
00738     l=0;
00739     if ( searchRegion->fkdotBand[0] )
00740       gsl_vector_int_set ( mapTmp, l++, 0 );
00741     if ( points3D->length > 1 )         /* more than one point: must be a 2D area */
00742       {
00743         gsl_vector_int_set ( mapTmp, l++, 1 );
00744         gsl_vector_int_set ( mapTmp, l++, 2 );
00745       }
00746     for (s=1; s < NUM_SPINS; s ++ )
00747       {
00748         if ( searchRegion->fkdotBand[s] )
00749           gsl_vector_int_set ( mapTmp, l++, 2 + s );
00750       } /* for s < NUM_SPINS */
00751 
00752     /* cut down to minimum size */
00753     if ( (l > 0) && (scan->map2canonical = gsl_vector_int_calloc ( l ) ) == NULL ) {
00754       ABORT (status, DOPPLERSCANH_EMEM, DOPPLERSCANH_MSGEMEM);
00755     }
00756     for ( i=0; i < l; i ++ )
00757       gsl_vector_int_set ( scan->map2canonical, i, gsl_vector_int_get ( mapTmp, i ) );
00758     gsl_vector_int_free ( mapTmp );
00759 
00760     scan->dimLattice = scan->map2canonical->size;       /* dimension of actual search-lattice */
00761 
00762   } /* find mapping lattice <--> dopplerSpace */
00763 
00764 
00765   /* ----- get unit-conversion factors from 'doppler' --> 'canonical' ----- */
00766   {
00767     REAL8 FreqMax = searchRegion->fkdot[0] + searchRegion->fkdotBand[0];
00768     REAL8 Tspan = scan->Tspan;
00769     REAL8 convFact;
00770     UINT4 s;
00771 
00772     if ( (scan->dopplerUnits = gsl_vector_calloc ( DIM_CANONICAL )) == NULL ) {
00773       ABORT (status, DOPPLERSCANH_EMEM, DOPPLERSCANH_MSGEMEM);
00774     }
00775 
00776     convFact = - (LAL_TWOPI * LAL_AU_SI / LAL_C_SI ) * FreqMax; /* convert nX,Y --> kX,Y */
00777     gsl_vector_set ( scan->dopplerUnits, 1, convFact );
00778     gsl_vector_set ( scan->dopplerUnits, 2, convFact );
00779 
00780     convFact = LAL_TWOPI * Tspan;
00781     gsl_vector_set ( scan->dopplerUnits, 0, convFact );         /* convert Freq --> w0 */
00782     for ( s=1; s < NUM_SPINS; s ++ )
00783       {
00784         convFact *= Tspan;
00785         gsl_vector_set ( scan->dopplerUnits, s+2, convFact );   /* convert fkdot --> wk */
00786       }
00787 
00788   } /* get unit-conversions */
00789 
00790   if ( (scan->boundary.hemisphere = onWhichHemisphere ( points3D )) == HEMI_BOTH )
00791     {
00792       LALPrintError ("\n\nSorry, currently only (ecliptic) single-hemisphere sky-regions are supported!\n");
00793       ABORT ( status, DOPPLERSCANH_EINPUT, DOPPLERSCANH_MSGEINPUT );
00794     }
00795   if ( (scan->boundary.skyRegion.data = LALCalloc ( points3D->length, sizeof(scan->boundary.skyRegion.data[0]) )) == NULL ) {
00796     ABORT (