uberpolka.c

Go to the documentation of this file.
00001 /*
00002 *  Copyright (C) 2007 Bruce Allen, Bernd Machenschalk, Xavier Siemens
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 /*       uberpolka - the pulsar koinzidenz analysis code for einstein@home       */
00022 /*                                                                               */
00023 /*                   Xavier Siemens,  Bruce Allen,  Bernd Machenschalk           */
00024 /*                                                                               */
00025 /*                   (takes in two Fstats file to look for coincidence)          */
00026 /*                                                                               */
00027 /*                                  UWM - January  2005                          */
00028 /*********************************************************************************/
00029 
00030 
00031 #include <stdio.h>
00032 #include <string.h>
00033 #include <stdlib.h>
00034 #if HAVE_UNISTD_H
00035 #include <unistd.h>
00036 #endif
00037 #include <math.h>
00038 
00039 #include <lal/LALDatatypes.h>
00040 #include <lal/LALMalloc.h>
00041 #include <lal/LALConstants.h>
00042 #include <lal/LALStatusMacros.h>
00043 #include <lal/ConfigFile.h>
00044 
00045 #include <lalapps.h>
00046 
00047 #include "getopt.h"
00048 
00049 RCSID ("$Id: uberpolka.c,v 1.60 2007/06/08 15:29:51 bema Exp $");
00050 
00051 /* some error codes and messages */
00052 #define POLKAC_ENULL            1
00053 #define POLKAC_ENONULL          2
00054 #define POLKAC_ESYS             3
00055 #define POLKAC_EINVALIDFSTATS   4
00056 #define POLKAC_EMEM             5
00057 
00058 #define POLKAC_MSGENULL         "Arguments contained an unexpected null pointer"
00059 #define POLKAC_MSGENONULL       "Input pointer was not NULL"
00060 #define POLKAC_MSGESYS          "System call failed (probably file IO"
00061 #define POLKAC_MSGEINVALIDFSTATS "Invalid Fstats file"
00062 #define POLKAC_MSGEMEM          "Sorry, ran out of memory... bye."
00063 
00064 #ifndef USE_BOINC
00065 #define USE_BOINC 0
00066 #endif
00067 
00068 #if USE_BOINC
00069 /* BOINC includes */
00070 #include "boinc_api.h"
00071 #include "filesys.h"
00072 /* alias fopen - this will take care of architecture-specific problem handling */
00073 #define fopen boinc_fopen
00074 /* this global variable communicates the output filename to the calling routine in CFS */
00075 extern CHAR *Outputfilename;
00076 /* communicating the progress to the graphics thread */
00077 extern double *fraction_done_hook;
00078 /* define LALPrintError locally again, otherwise the stderr redirection
00079    doesn't seem to work on the Mac */
00080 int myPrintError( const char *fmt, ... )
00081 {
00082   int n;
00083   va_list ap;
00084   va_start( ap, fmt );
00085   n = vfprintf( stderr, fmt, ap );
00086   va_end( ap );
00087   return n;
00088 }
00089 #else
00090 #define myPrintError LALPrintError
00091 #endif
00092 
00093 /* this is defined in C99 and *should* be in math.h.  Long term
00094    protect this with a HAVE_FINITE */
00095 #ifdef _MSC_VER
00096 #include <float.h>
00097 #define finite _finite
00098 #else
00099 int finite(double);
00100 #endif
00101 
00102 #define UBERPOLKA_EXIT_ERRCLINE 31
00103 #define UBERPOLKA_EXIT_READCND  32
00104 #define UBERPOLKA_EXIT_FCTEST   33
00105 #define UBERPOLKA_EXIT_OUTFAIL  34
00106 
00107 struct PolkaCommandLineArgsTag 
00108 {
00109   char *FstatsFile1; /* Names of Fstat files to be read in */
00110   char *FstatsFile2;
00111   char *OutputFile;
00112   REAL8 Deltaf;      /* Size of coincidence window in Hz */
00113   REAL8 DeltaAlpha;  /* Size of coincidence window in radians */
00114   REAL8 DeltaDelta;  /* Size of coincidence window in radians */
00115   REAL8 fmin;        /* Minimum frequency of candidate in first IFO */
00116   REAL8 fmax;        /* Maximum frequency of candidate in first IFO */
00117   UINT4 EAH;         /* Einstein at home flag for alternative output */ 
00118 } PolkaCommandLineArgs;
00119 
00120 /* This structure contains the indices corresponding to the 
00121 coarse frequency and sky bins */
00122 typedef struct CandidateListTag
00123 {
00124   REAL8 f;           /* Frequency */
00125   REAL4 Alpha;       /* longitude -> REAL4*/
00126   REAL4 Delta;       /* latitude -> REAL4 */
00127   REAL4 F;           /* Maximum value of F for the cluster -> REAL4*/
00128   REAL4 lfa;         /* log of false alarm probability for that candidate ->REAL4*/
00129   INT4 iCand;
00130   INT4 CtagCounter; /* contains the cumulative sum of coincident candidates so far */
00131   INT4  iFreq;       /* INT2 , delete? */
00132   INT2 iDelta;      /* -157-157 -> INT2, delete?  */
00133   UINT4  Ctag;        /* tag for candidate if it's been found in coincidence, just a Bit, maybe coded as CtagC-2 */
00134 } CandidateList; /* ~ Fstat lines */ 
00135 
00136 typedef struct CoincidentPairsTag 
00137 {
00138   INT4 c1;             /* number in Fstats file that corresponds to first member of pair */
00139   INT4 c2;             /* number in Fstats file that corresponds to second member of pair */
00140   /* REAL8 fa; */       /* joint false alarm for that pair */
00141   REAL4 lfa;            /* log of joint false alarm for that pair */
00142 } CoincidentPairs; /* ~ coninc */
00143 
00144 int ReadCommandLine(int argc,char *argv[],struct PolkaCommandLineArgsTag *CLA);
00145 int ReadCandidateFiles(struct PolkaCommandLineArgsTag CLA);
00146 int ReadOneCandidateFile(CandidateList **CList, const char *fname);
00147 int compareCIStructs(const void *ip, const void *jp);
00148 int compareCdaf(const void *ip, const void *jp);
00149 int compareCPfa(const void *ip, const void *jp);
00150 int FineCoincidenceTest(CandidateList c1, CandidateList c2, struct PolkaCommandLineArgsTag CLA);
00151 int OutputCoincidences(struct PolkaCommandLineArgsTag CLA);
00152 
00153 extern INT4 lalDebugLevel;
00154 
00155 CandidateList *SortedC1,*SortedC2;
00156 CoincidentPairs *CP;
00157 
00158 UINT4  CLength=0,CLength1=0,CLength2=0;
00159 
00160 INT4 numCoincidences=0;
00161 REAL8 MaxAngularDistance;
00162 
00163 #ifndef FALSE
00164 #define FALSE (1==0)
00165 #endif
00166 #ifndef TRUE
00167 #define TRUE  (1==1)
00168 #endif
00169 
00170 /* main() mapped to polka() if using boinc */
00171 #if USE_BOINC
00172 int polka(int argc,char *argv[])
00173 #else
00174 int main(int argc,char *argv[]) 
00175 #endif
00176 {
00177   UINT4 i;
00178 #if USE_BOINC
00179   REAL8 local_fraction_done;
00180 #endif
00181 
00182   lalDebugLevel = 0;
00183 
00184   /* Reads command line arguments */
00185   if (ReadCommandLine(argc,argv,&PolkaCommandLineArgs)) {
00186     fprintf(stderr,"ReadCommandLine failed\n");
00187     return UBERPOLKA_EXIT_ERRCLINE;
00188   }
00189 
00190   MaxAngularDistance=sqrt(pow(PolkaCommandLineArgs.DeltaAlpha,2)+pow(PolkaCommandLineArgs.DeltaDelta,2))+1e-8;
00191 
00192   /* Reads in candidare files, set CLength1 and CLength2 */
00193   if (ReadCandidateFiles(PolkaCommandLineArgs)) {
00194     fprintf(stderr,"ReadCandidateFiles failed\n");
00195     return UBERPOLKA_EXIT_READCND;
00196   }
00197 
00198   if (CLength1 != 0 && CLength2 != 0 )
00199     {
00200       /* Initialise arrays of sorted candidates to use for bsearch */
00201       for (i=0;i<CLength1;i++)
00202         {
00203           SortedC1[i].iFreq=(INT4) (SortedC1[i].f/(PolkaCommandLineArgs.Deltaf));
00204           SortedC1[i].iDelta=(INT4)(SortedC1[i].Delta/(PolkaCommandLineArgs.DeltaDelta));
00205          }
00206       for (i=0;i<CLength2;i++)
00207         {
00208           SortedC2[i].iFreq=(INT4) (SortedC2[i].f/(PolkaCommandLineArgs.Deltaf));
00209           SortedC2[i].iDelta=(INT4)(SortedC2[i].Delta/(PolkaCommandLineArgs.DeltaDelta));
00210         }
00211 
00212       /* sort arrays of candidates */
00213       qsort(SortedC1, (size_t)CLength1, sizeof(CandidateList), compareCIStructs);
00214       qsort(SortedC2, (size_t)CLength2, sizeof(CandidateList), compareCIStructs);
00215 
00216       for (i=0;i<CLength1;i++) SortedC1[i].iCand=i;
00217       for (i=0;i<CLength2;i++) SortedC2[i].iCand=i;
00218       
00219       /* loop iover candidates in first array */
00220       for (i=0; i < CLength1; i++)
00221         {
00222 #if USE_BOINC
00223           /* make sure the cpu time is updated */ 
00224           if (boinc_time_to_checkpoint())
00225             boinc_checkpoint_completed();
00226 #endif
00227           if  (SortedC1[i].f >= PolkaCommandLineArgs.fmin && SortedC1[i].f <= PolkaCommandLineArgs.fmax)
00228             {
00229               int iFreq2, iDelta2;
00230 
00231               /* Loop to run bsearch etc. on all surrounding boxes */
00232               for (iFreq2=SortedC1[i].iFreq-1; iFreq2 <= SortedC1[i].iFreq+1; iFreq2++)
00233                 {
00234                   for (iDelta2=SortedC1[i].iDelta-1; iDelta2 <= SortedC1[i].iDelta+1; iDelta2++)
00235                     {
00236                       CandidateList *p, can;
00237                       
00238                       can.iFreq=iFreq2;
00239                       can.iDelta=iDelta2;
00240                           
00241                       p=bsearch(&can,SortedC2,(size_t)CLength2, sizeof(CandidateList),compareCIStructs);
00242                       
00243                       if (p != NULL)
00244                         {
00245                           /* Now we've found at least one candidate */
00246                           /* we need to move to the right edge (without segfaulting!) */
00247                           
00248                           while ( p->iCand > 0 && !compareCIStructs(p, p-1) )
00249                             p--;
00250                           
00251                           /* Now p points to first coincident event in the second list */
00252                           
00253                           /* Now loop over candidates found in the second list and do the fine coincidence test */
00254                           if(FineCoincidenceTest(SortedC1[i],*p, PolkaCommandLineArgs)) {
00255                             fprintf(stderr,"FineCoincidenceTest failed\n");
00256                             return UBERPOLKA_EXIT_FCTEST;
00257                           }
00258                           while ( (int)p->iCand <  (int)CLength2-1 &&  !compareCIStructs(p, p+1) )
00259                             { 
00260                               p++;
00261                               if(FineCoincidenceTest(SortedC1[i],*p, PolkaCommandLineArgs)) {
00262                                 fprintf(stderr,"FineCoincidenceTest failed in loop\n");
00263                                 return UBERPOLKA_EXIT_FCTEST;
00264                               }
00265                             }
00266 
00267                         }/* check that besearch was non-null */
00268                     } /* loop over deltas */
00269                 }/* loop over frequencies */    
00270             } /* check that frequency lies between two input bounds */
00271 #if USE_BOINC
00272           local_fraction_done = 0.99 + 0.01 * (double)i / (double)CLength1;
00273           /* update progress, the last % is reserved for polka */
00274           boinc_fraction_done(local_fraction_done);
00275           /* pass variable externally to graphics routines */
00276           if (fraction_done_hook != NULL)
00277             *fraction_done_hook = local_fraction_done;
00278 #endif
00279         }/* loop over 1st candidate list */      
00280     }/* check that we have candidates in both files */
00281   
00282   /* Ouput candidates */
00283   if (OutputCoincidences( PolkaCommandLineArgs )) {
00284     fprintf(stderr,"OutputCoincidences failed\n");
00285     return UBERPOLKA_EXIT_OUTFAIL;
00286   }
00287   
00288   if(CLength1) LALFree(SortedC1);
00289   if(CLength2) LALFree(SortedC2);
00290 
00291   LALCheckMemoryLeaks(); 
00292 
00293   return 0;
00294  
00295 }
00296 
00297 /*******************************************************************************/
00298 
00299 int OutputCoincidences(struct PolkaCommandLineArgsTag CLA)
00300 {
00301   INT4 *indicesCCfa=NULL;
00302   INT4 i;
00303   FILE *fpOut;
00304 #if USE_BOINC
00305   static char resolved_filename[256];
00306 #endif
00307 
00308   /* allocate space */
00309   if (numCoincidences != 0){ 
00310     if (!(indicesCCfa=(INT4 *)LALMalloc(sizeof(INT4) * numCoincidences))){
00311       myPrintError("Unable to allocate index array in main\n");
00312       return 1;
00313     }
00314   }
00315 
00316   for (i=0; i < numCoincidences; i++) indicesCCfa[i]=i;
00317   qsort((void *)indicesCCfa, (size_t)numCoincidences, sizeof(int), compareCPfa);
00318 
00319   /* open and write the file */
00320 #if USE_BOINC
00321   if (boinc_resolve_filename(CLA.OutputFile, resolved_filename, sizeof(resolved_filename))) {
00322     myPrintError(
00323             "Can't resolve file \"%s\"\n"
00324             "If running a non-BOINC test, create [INPUT] or touch [OUTPUT] file\n",
00325             CLA.OutputFile);
00326     boinc_finish(2);
00327   }
00328   fpOut=fopen(resolved_filename,"wb");
00329   if (!fpOut){
00330     myPrintError("Unable to open output file \"%s\" for writing\n", resolved_filename);
00331     return 1;
00332   }
00333 #else
00334   fpOut=fopen(CLA.OutputFile,"wb");
00335   if (!fpOut){
00336     myPrintError("Unable to open output file \"%s\" for writing\n", CLA.OutputFile);
00337     return 1;
00338   }
00339 #endif
00340   if (!CLA.EAH)
00341     {
00342       /* sort in increasing probability of joint false alarm */
00343       for (i=0; i < numCoincidences; i++) 
00344         {
00345           UINT4 k = indicesCCfa[i];  /* print out ordered by joint significance */
00346           UINT4 k1 = CP[k].c1;
00347           UINT4 k2 = CP[k].c2;
00348           fprintf(fpOut,"%1.15e %e %e %e %e %1.15e %e %e %e %e %e\n",
00349                   SortedC1[k1].f, SortedC1[k1].Alpha, SortedC1[k1].Delta, 
00350                   SortedC1[k1].F, exp(SortedC1[k1].lfa),
00351                   SortedC2[k2].f, SortedC2[k2].Alpha, SortedC2[k2].Delta, 
00352                   SortedC2[k2].F, exp(SortedC2[k2].lfa),
00353                                   exp(SortedC1[k1].lfa)*exp(SortedC2[k2].lfa));
00354         }
00355     }else{
00356       /* sort by delta, alpha, f (just like Fstats file) */
00357       qsort(SortedC1, (size_t)CLength1, sizeof(CandidateList), compareCdaf);
00358       qsort(SortedC2, (size_t)CLength2, sizeof(CandidateList), compareCdaf);
00359 
00360       fprintf(fpOut,"%%1\n");
00361       {
00362         int k=-1;    
00363         for (i=0; i < (int)CLength1; i++)
00364           {
00365             if (SortedC1[i].Ctag) 
00366               {
00367                 k++;
00368                 fprintf(fpOut,"%16.12f %10.8f %10.8f %20.17f\n",
00369                         SortedC1[i].f,SortedC1[i].Alpha,SortedC1[i].Delta,SortedC1[i].F);
00370                 SortedC1[i].CtagCounter=k;
00371               }
00372           }
00373       }
00374       fprintf(fpOut,"%%2\n");
00375       {
00376         int k=-1;
00377         for (i=0; i < (int)CLength2; i++)
00378           {
00379             if (SortedC2[i].Ctag) 
00380               {
00381                 k++;
00382                 fprintf(fpOut,"%16.12f %10.8f %10.8f %20.17f\n",
00383                         SortedC2[i].f,SortedC2[i].Alpha,SortedC2[i].Delta,SortedC2[i].F);  
00384                 SortedC2[i].CtagCounter=k;
00385               }    
00386           }
00387       }
00388       /* sort arrays of candidates back to the order they were in */
00389       qsort(SortedC1, (size_t)CLength1, sizeof(CandidateList), compareCIStructs);
00390       qsort(SortedC2, (size_t)CLength2, sizeof(CandidateList), compareCIStructs);
00391 
00392       fprintf(fpOut,"%%coincidences\n");
00393       /* sort in increasing probability of joint false alarm */
00394       qsort((void *)indicesCCfa, (size_t)numCoincidences, sizeof(int), compareCPfa);
00395       
00396       for (i=0; i < numCoincidences; i++) 
00397         {
00398           UINT4 k = indicesCCfa[i];  /* print out ordered by joint significance */
00399           fprintf(fpOut,"%d %d %e\n",
00400                   SortedC1[CP[k].c1].CtagCounter,SortedC2[CP[k].c2].CtagCounter,exp(CP[k].lfa));
00401         }
00402     }
00403   /* write end marker */
00404   fprintf(fpOut,"%%DONE\n");    
00405 #if USE_BOINC
00406   /* make the output filename known to teh boinc main() routine in ComputeFStatistic */
00407   Outputfilename=resolved_filename;
00408 #endif
00409   fclose(fpOut);
00410 
00411   if (numCoincidences != 0){ 
00412     LALFree ( CP );
00413     LALFree(indicesCCfa);
00414   }
00415 
00416   return 0;
00417 }
00418 
00419 /*******************************************************************************/
00420 #define BLOCKSIZE 16384
00421 
00422 int FineCoincidenceTest(CandidateList c1, CandidateList c2, struct PolkaCommandLineArgsTag CLA)
00423 {
00424   
00425   REAL8 f1=c1.f,f2=c2.f, F1=c1.F, F2=c2.F;
00426   REAL8 Alpha1=c1.Alpha,Delta1=c1.Delta;
00427   REAL8 Alpha2=c2.Alpha,Delta2=c2.Delta;
00428   REAL8 n1[3],n2[3],AngularDistance;
00429   REAL8 cosAngularDistance, difff;
00430 
00431   n1[0]=cos(Alpha1)*cos(Delta1);
00432   n1[1]=sin(Alpha1)*cos(Delta1);
00433   n1[2]=sin(Delta1);
00434   
00435   n2[0]=cos(Alpha2)*cos(Delta2);
00436   n2[1]=sin(Alpha2)*cos(Delta2);
00437   n2[2]=sin(Delta2);
00438  
00439   cosAngularDistance=n1[0]*n2[0]+n1[1]*n2[1]+n1[2]*n2[2];
00440   if (cosAngularDistance  >  1.0) cosAngularDistance =  1.0;
00441   if (cosAngularDistance  < -1.0) cosAngularDistance = -1.0;
00442         
00443   AngularDistance=acos(cosAngularDistance);
00444   
00445   difff=fabs(f1 - f2);
00446               
00447   /* check difference in frequencies because we're not guaranteed 
00448      sufficient closeness at the edges of array */
00449   if ( difff <= CLA.Deltaf) 
00450     {
00451       if ( AngularDistance <= MaxAngularDistance )
00452         {       
00453           CoincidentPairs *thisCP;
00454 
00455           /* tag the candidates that have been found in coincidence */
00456           SortedC1[c1.iCand].Ctag=1;
00457           SortedC2[c2.iCand].Ctag=1;
00458                   
00459           /* seems we found a coincident candidate: let's make space for it to be stored */
00460           
00461           if (numCoincidences % BLOCKSIZE == 0)
00462             {
00463               if ( (CP = LALRealloc ( CP, (numCoincidences + BLOCKSIZE) * sizeof(CoincidentPairs) )) == NULL) {
00464                 fprintf (stderr, "Error: polka ran out of memory allocating %d coincident candidate (CP).\n",numCoincidences);
00465                 return 1;
00466               }
00467             }
00468 
00469           numCoincidences ++;
00470           
00471           thisCP = &(CP[ numCoincidences - 1]); /* point to current new coincidences */
00472           /*
00473           SortedC1[c1.iCand].fa=(1+F1/2)*exp(-F1/2);
00474           SortedC2[c2.iCand].fa=(1+F2/2)*exp(-F2/2);
00475 
00476           log(a*exp(b)) == log(exp(log(a))*exp(b)) == log(exp(log(a)+b)) == log(a)+b
00477           */
00478           SortedC1[c1.iCand].lfa=log(1+F1/2)-F1/2;
00479           SortedC2[c2.iCand].lfa=log(1+F2/2)-F2/2;
00480           
00481           thisCP->c1=c1.iCand;
00482           thisCP->c2=c2.iCand;
00483           thisCP->lfa=SortedC1[c1.iCand].lfa+SortedC2[c2.iCand].lfa;
00484 
00485         }
00486     }
00487   return 0;
00488 } 
00489 
00490 /*******************************************************************************/
00491 
00492 /* Sorting function to sort candidate indices INCREASING order of f, delta, alpha */
00493 int compareCIStructs(const void *a, const void *b)
00494 {
00495   const CandidateList *ip = a;
00496   const CandidateList *jp = b;
00497   INT4 ifreq1,ifreq2;
00498 
00499   ifreq1=ip->iFreq;
00500   ifreq2=jp->iFreq;
00501 
00502   if (ifreq1 < ifreq2)
00503     return -1;
00504   
00505   if (ifreq1 == ifreq2)
00506     {
00507       INT4 iDelta1, iDelta2;
00508 
00509       iDelta1=ip->iDelta;
00510       iDelta2=jp->iDelta;
00511       
00512       if (iDelta1 < iDelta2)
00513         return -1;
00514 
00515       if (iDelta1 > iDelta2)
00516         return 1;
00517   
00518       if (iDelta1 == iDelta2)           
00519         return 0;
00520     }
00521   return 1;
00522 }
00523 
00524 /*******************************************************************************/
00525 
00526 /* Sorting function to sort candidate indices INCREASING order of f, delta, alpha */
00527 int compareCdaf(const void *a, const void *b)
00528 {
00529   const CandidateList *ip = a;
00530   const CandidateList *jp = b;
00531 
00532   REAL8 Delta1, Delta2;
00533 
00534   Delta1=ip->Delta;
00535   Delta2=jp->Delta;
00536 
00537   if (Delta1 < Delta2)
00538     return -1;
00539   
00540   if (Delta1 == Delta2)
00541     {
00542       REAL8 Alpha1, Alpha2;
00543 
00544       Alpha1=ip->Alpha;
00545       Alpha2=jp->Alpha;
00546           
00547       if (Alpha1 < Alpha2)
00548         return -1;
00549   
00550       if (Alpha1 > Alpha2)
00551         return 1;
00552   
00553       if (Alpha1 == Alpha2)
00554         {
00555           REAL8 freq1,freq2;
00556 
00557           freq1=ip->f;
00558           freq2=jp->f;
00559 
00560           if (freq1 < freq2)
00561             return -1;
00562 
00563           if (freq1 > freq2)
00564             return 1;
00565 
00566           /* This should never ever happen */
00567           if (freq1 == freq2)
00568             return 0;
00569         }
00570     }
00571 
00572   return 1;
00573 
00574 }
00575 
00576 /*******************************************************************************/
00577 
00578 /* Sorting function to sort second candidate list into increasing order of fa */
00579 int compareCPfa(const void *ip, const void *jp)
00580 {
00581   REAL8 di, dj;
00582 
00583   di=CP[*(const int *)ip].lfa;
00584   dj=CP[*(const int *)jp].lfa;
00585 
00586   if (di<dj)
00587     return -1;
00588   
00589   if (di==dj)
00590     return (ip > jp);
00591 
00592   return 1;
00593 }
00594 
00595 /*******************************************************************************/
00596 
00597 int ReadCandidateFiles(struct PolkaCommandLineArgsTag CLA)
00598 {
00599   
00600   if (ReadOneCandidateFile ( &SortedC1, CLA.FstatsFile1)) return 1;
00601   CLength1=CLength;
00602 
00603   if (ReadOneCandidateFile ( &SortedC2, CLA.FstatsFile2)) return 1;
00604   CLength2=CLength;
00605 
00606   return 0;
00607 
00608 } /* ReadCandidateFiles() */
00609 
00610 
00611 /*******************************************************************************/
00612 
00613 #define DONE_MARKER "%DONE\n"
00614 
00615 /* read and parse the given candidate 'Fstats'-file fname into the candidate-list CList */
00616 int  ReadOneCandidateFile (CandidateList **CList, const char *fname)
00617 {
00618   UINT4 i;
00619   INT4 j, uplim;
00620   UINT4 numlines;
00621   REAL8 epsilon=1e-5;
00622   char line1[256];
00623   FILE *fp;
00624   INT4 read;
00625   UINT4 checksum=0;
00626   UINT4 bytecount=0;
00627 
00628   /* ------ Open and count candidates file ------ */
00629   i=0;
00630   fp=fopen(fname,"rb");
00631   if (fp==NULL) 
00632     {
00633       myPrintError("File %s doesn't exist!\n",fname);
00634       return 1;
00635     }
00636   while(fgets(line1,sizeof(line1),fp)) {
00637     unsigned int k;
00638     size_t len=strlen(line1);
00639 
00640     /* check that each line ends with a newline char (no overflow of
00641        line1 or null chars read) */
00642     if (!len || line1[len-1] != '\n') {
00643       myPrintError(
00644               "Line %d of file %s is too long or has no NEWLINE.  First 255 chars are:\n%s\n",
00645               i+1, fname, line1);
00646       fclose(fp);
00647       return 1;
00648     }
00649 
00650     /* increment line counter */
00651     i++;
00652 
00653     /* maintain a running checksum and byte count */
00654     bytecount+=len;
00655     for (k=0; k<len; k++)
00656       checksum+=(int)line1[k];
00657   }
00658   numlines=i;
00659   /* -- close candidate file -- */
00660   fclose(fp);     
00661 
00662   if ( numlines == 0) 
00663     {
00664       myPrintError ("ERROR: File '%s' has no lines so is not properly terminated by: %s", fname, DONE_MARKER);
00665       return 1;
00666     }
00667 
00668   /* output a record of the running checksun amd byte count */
00669   myPrintError( "%s: bytecount %" LAL_UINT4_FORMAT " checksum %" LAL_UINT4_FORMAT "\n", fname, bytecount, checksum);
00670 
00671   /* check validity of this Fstats-file */
00672   if ( strcmp(line1, DONE_MARKER ) ) 
00673     {
00674       myPrintError ("ERROR: File '%s' is not properly terminated by: %sbut has %s instead", fname, DONE_MARKER, line1);
00675       return 1;
00676     }
00677   else
00678     numlines --;        /* avoid stepping on DONE-marker */
00679 
00680   CLength=numlines;
00681   
00682   /* reserve memory for fstats-file contents */
00683   if (numlines > 0)
00684     {
00685       *CList = (CandidateList *)LALMalloc (numlines*sizeof(CandidateList));
00686       if ( !CList )
00687         {
00688           myPrintError ("Could not allocate memory for candidate file %s\n\n", fname);
00689           return 1;
00690         }
00691     }
00692 
00693   /* ------ Open and count candidates file ------ */
00694   i=0;
00695   fp=fopen(fname,"rb");
00696   if (fp==NULL) 
00697     {
00698       myPrintError("fopen(%s) failed!\n", fname);
00699       LALFree ((*CList));
00700       return 1;
00701     }
00702   while(i < numlines && fgets(line1,sizeof(line1),fp))
00703     {
00704       REAL8 dmp1, dmp2, dmp3;
00705       char newline='\0';
00706       CandidateList *cl=&(*CList)[i];
00707 
00708       if (strlen(line1)==0 || line1[strlen(line1)-1] != '\n') {
00709         myPrintError(
00710                 "Line %d of file %s is too long or has no NEWLINE.  First 255 chars are:\n%s\n",
00711                 i+1, fname, line1);
00712         LALFree ((*CList));
00713         fclose(fp);
00714         return 1;
00715       }
00716       
00717       cl->Ctag=0;
00718       cl->CtagCounter=-1;
00719 
00720       read = sscanf (line1, 
00721                      "%" LAL_REAL8_FORMAT " %" LAL_REAL4_FORMAT " %" LAL_REAL4_FORMAT " %" LAL_REAL8_FORMAT 
00722                      " %" LAL_REAL8_FORMAT " %" LAL_REAL8_FORMAT " %" LAL_REAL4_FORMAT "%c", 
00723                      &(cl->f), &(cl->Alpha), &(cl->Delta), &dmp1, &dmp2, &dmp3, &(cl->F), &newline );
00724 
00725       /* check that values that are read in are sensible */
00726       if (
00727           cl->f < 0.0                        ||
00728           cl->F < 0.0                        ||
00729           cl->Alpha <         0.0 - epsilon  ||
00730           cl->Alpha >   LAL_TWOPI + epsilon  ||
00731           cl->Delta < -0.5*LAL_PI - epsilon  ||
00732           cl->Delta >  0.5*LAL_PI + epsilon  ||                                                                 
00733           !finite(cl->f)                     ||
00734           !finite(cl->Alpha)                 ||
00735           !finite(cl->Delta)                 ||
00736           !finite(dmp1)                      ||
00737           !finite(dmp2)                      ||
00738           !finite(dmp3)                      ||
00739           !finite(cl->F)
00740           ) {
00741           myPrintError(
00742                   "Line %d of file %s has invalid values.\n"
00743                   "First 255 chars are:\n"
00744                   "%s\n"
00745                   "1st and 7th field should be positive.\n" 
00746                   "2nd field should lie between 0 and %1.15f.\n" 
00747                   "3rd field should lie between %1.15f and %1.15f.\n"
00748                   "All fields should be finite\n",
00749                   i+1, fname, line1, (double)LAL_TWOPI, (double)-LAL_PI/2.0, (double)LAL_PI/2.0);
00750           LALFree ((*CList));
00751           fclose(fp);
00752           return 1;
00753         }
00754            
00755            
00756 
00757       /* check that the FIRST character following the Fstat value is a
00758          newline.  Note deliberate LACK OF WHITE SPACE char before %c
00759          above */
00760       if (newline != '\n') {
00761         myPrintError(
00762                 "Line %d of file %s had extra chars after F value and before newline.\n"
00763                 "First 255 chars are:\n"
00764                 "%s\n",
00765                 i+1, fname, line1);
00766         LALFree ((*CList));
00767         fclose(fp);
00768         return 1;
00769       }
00770 
00771       /* check that we read 7 quantities with exactly the right format */
00772       if ( read != 8 )
00773         {
00774           myPrintError ("Found %d not %d values on line %d in file '%s'\n"
00775                          "Line in question is\n%s",
00776                          read, 8, i+1, fname, line1);               
00777           LALFree ((*CList));
00778           fclose(fp);
00779           return 1;
00780         }
00781 
00782       i++;
00783     }
00784   /* check that we read ALL lines! */
00785   if (i != numlines) {
00786     myPrintError(
00787             "Read of file %s terminated after %d line but numlines=%d\n",
00788             fname, i, numlines);
00789     LALFree((*CList));
00790     fclose(fp);
00791     return 1;
00792   }
00793 
00794   /* read final line with %DONE\n marker */
00795   if (!fgets(line1, sizeof(line1), fp)) {
00796     myPrintError(
00797             "Failed to find marker line of file %s\n",
00798             fname);
00799     LALFree((*CList));
00800     fclose(fp);
00801     return 1;
00802   }
00803 
00804   /* check for %DONE\n marker */
00805   if (strcmp(line1, DONE_MARKER)) {
00806     myPrintError(
00807             "Failed to parse marker: 'final' line of file %s contained %s not %s",
00808             fname, line1, DONE_MARKER);
00809     LALFree ((*CList));
00810     fclose(fp);
00811     return 1;
00812   }
00813 
00814   /* check that we are now at the end-of-file */
00815   if (fgetc(fp) != EOF) {
00816     myPrintError(
00817             "File %s did not terminate after %s",
00818             fname, DONE_MARKER);
00819     LALFree ((*CList));
00820     fclose(fp);
00821     return 1;
00822   }
00823 
00824   /* -- close candidate file -- */
00825   fclose(fp);     
00826 
00827   /* Finally, check that candidates are in the correct order */
00828   uplim = -1+(int)CLength;
00829   for (j=0; j<uplim; j++)
00830     {
00831       if(compareCdaf(*CList+j,*CList+j+1) != -1)
00832         {
00833           myPrintError( "Candidates in line %d and %d in Fstats file %s are not in the correct order. Exiting.\n", 
00834                   j+1,j+2, fname);
00835           LALFree ((*CList));
00836           return 1;
00837         }
00838     }
00839 
00840   return 0;
00841 
00842 } /* ReadOneCandidateFile() */
00843 
00844 /*******************************************************************************/
00845 
00846 int ReadCommandLine(int argc,char *argv[],struct PolkaCommandLineArgsTag *CLA) 
00847 {
00848   INT2 errflg = 0;
00849   INT4 c; 
00850   INT4 option_index = 0;
00851 
00852   const char *optstring = "h1:2:f:a:d:m:M:o:s:e:b";
00853   struct option long_options[] =
00854     {
00855       {"fstatsfile1",           required_argument, 0,   '1'},
00856       {"fstatsfile2",           required_argument, 0,   '2'},
00857       {"frequency-window",      required_argument, 0,   'f'},
00858       {"delta-window",          required_argument, 0,   'd'},
00859       {"alpha-window",          required_argument, 0,   'a'},
00860       {"fmin",                  required_argument, 0,   's'},
00861       {"fmax",                  required_argument, 0,   'e'},
00862       {"outputfile",            required_argument, 0,   'o'},
00863       {"EAHoutput",             no_argument, 0,         'b'},
00864       {"help",                  no_argument, 0,         'h'},
00865       {0, 0, 0, 0}
00866     };
00867 
00868   /* Initialize default values */
00869   CLA->FstatsFile1=NULL;
00870   CLA->FstatsFile2=NULL;
00871   CLA->OutputFile=NULL;
00872   CLA->Deltaf=0.0;
00873   CLA->DeltaAlpha=0;
00874   CLA->DeltaDelta=0;
00875   CLA->fmin=0;
00876   CLA->fmax=0;
00877   CLA->EAH=0;
00878 
00879   /* reset gnu getopt */
00880   optind = 0;
00881 
00882   /* Scan through list of command line arguments */
00883   while (1)
00884     {
00885       c = getopt_long(argc, argv, optstring, long_options, &option_index);      
00886       if (c == -1) 
00887         break;
00888       switch (c) {
00889       case '1':
00890         /* SFT directory */
00891         CLA->FstatsFile1=optarg;
00892         break;
00893       case '2':
00894         /* calibration files directory */
00895         CLA->FstatsFile2=optarg;
00896         break;
00897       case 'o':
00898         /* calibration files directory */
00899         CLA->OutputFile=optarg;
00900         break;
00901       case 'f':
00902         /* Spin down order */
00903         CLA->Deltaf=atof(optarg);
00904         break;
00905       case 'a':
00906         /* Spin down order */
00907         CLA->DeltaAlpha=atof(optarg);
00908         break;
00909       case 's':
00910         /* Spin down order */
00911         CLA->fmin=atof(optarg);
00912         break;
00913       case 'e':
00914         /* Spin down order */
00915         CLA->fmax=atof(optarg);
00916         break;
00917       case 'd':
00918         /* Spin down order */
00919         CLA->DeltaDelta=atof(optarg);
00920         break;
00921       case 'b':
00922         /* Spin down order */
00923         CLA->EAH=1;
00924         break;
00925       case 'h':
00926         /* print usage/help message */
00927         myPrintError("Arguments are (defaults):\n");
00928         myPrintError("\t--fstatsfile1 (-1)\tSTRING\tFirst candidates Fstats file\n");
00929         myPrintError("\t--fstatsfile2 (-2)\tSTRING\tSecond candidates Fstats file\n");
00930         myPrintError("\t--outputfile  (-o)\tSTRING\tName of ouput candidates file\n");
00931         myPrintError("\t--frequency-window (-f)\tFLOAT\tFrequency window in Hz (0.0)\n");
00932         myPrintError("\t--alpha-window (-a)\tFLOAT\tAlpha window in radians (0.0)\n");
00933         myPrintError("\t--delta-window (-d)\tFLOAT\tDelta window in radians (0.0)\n");
00934         myPrintError("\t--fmin (-s)\tFLOAT\t Minimum frequency of candidate in 1st IFO\n");
00935         myPrintError("\t--fmax (-e)\tFLOAT\t Maximum frequency of candidate in 1st IFO\n");
00936         myPrintError("\t--EAHoutput (-b)\tFLAG\t Einstein at home output flag. \n");
00937         myPrintError("\t--help        (-h)\t\tThis message\n");
00938         exit(0);
00939