NRWaveInject.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 S.Fairhurst, B. Krishnan, L.Santamaria
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 NRWaveInject.c
00021  *  \ingroup NRWaveInject
00022  *  \author S.Fairhurst, B.Krishnan, L.Santamaria
00023  * 
00024  *  \brief Functions for reading/writing numerical relativity waveforms
00025  *
00026  * $Id: NRWaveInject.c,v 1.56 2008/08/18 01:52:30 badri Exp $ 
00027  *
00028  */
00029 
00030 #include <lal/LALStdio.h>
00031 #include <lal/FileIO.h>
00032 #include <lal/NRWaveIO.h>
00033 #include <lal/LIGOMetadataTables.h>
00034 #include <lal/LIGOMetadataUtils.h>
00035 #include <lal/Date.h>
00036 #include <lal/Units.h>
00037 #include <lal/LALConstants.h>
00038 #include <lal/NRWaveInject.h>
00039 #include <lal/Random.h>
00040 #include <lal/Inject.h>
00041 #include <lal/LALSimulation.h>
00042 #include <lal/LALDetectors.h>
00043 #include <lal/LALComplex.h>
00044 #include <lal/DetResponse.h>
00045 #include <lal/TimeDelay.h>
00046 #include <lal/SkyCoordinates.h>
00047 #include <lal/TimeSeries.h>
00048 #include <lal/FrequencySeries.h>
00049 #include <lal/TimeFreqFFT.h>
00050 #include <lal/Window.h>
00051 
00052 #include <gsl/gsl_heapsort.h> 
00053 
00054 
00055 
00056 NRCSID (NRWAVEINJECTC, "$Id: NRWaveInject.c,v 1.56 2008/08/18 01:52:30 badri Exp $");
00057 
00058 int compare_abs_float(const void *a, const void *b);
00059 int compare_abs_double(const void *a, const void *b);
00060 
00061 /** Takes a strain of h+ and hx data and stores it in a temporal
00062  *  strain in order to perform the sum over l and m modes **/
00063 REAL4TimeVectorSeries *
00064 XLALSumStrain( 
00065     REAL4TimeVectorSeries *tempstrain,     /**< storing variable */ 
00066     REAL4TimeVectorSeries *strain          /**< variable to add  */)
00067 {
00068     UINT4      vecLength, length, k;
00069 
00070     vecLength = strain->data->vectorLength;
00071     length = strain->data->length;
00072 
00073     for ( k = 0; k < vecLength*length; k++)    
00074       {
00075         tempstrain->data->data[k] += strain->data->data[k];
00076       }
00077     return( tempstrain );
00078 }
00079 
00080 /* REAL8 version */
00081 REAL8TimeVectorSeries *
00082 XLALSumStrainREAL8( 
00083     REAL8TimeVectorSeries *tempstrain,     /**< storing variable */ 
00084     REAL8TimeVectorSeries *strain          /**< variable to add  */)
00085 {
00086     UINT4      vecLength, length, k;
00087 
00088     vecLength = strain->data->vectorLength;
00089     length = strain->data->length;
00090 
00091     for ( k = 0; k < vecLength*length; k++)    
00092       {
00093         tempstrain->data->data[k] += strain->data->data[k];
00094       }
00095     return( tempstrain );
00096 }
00097 
00098 
00099 /** Takes a (sky averaged) numerical relativity waveform and returns the
00100  * waveform appropriate for given coalescence phase and inclination angles */
00101 /* REAL4TimeVectorSeries */
00102 INT4 
00103 XLALOrientNRWave( 
00104     REAL4TimeVectorSeries *strain,         /**< sky average h+, hx data */ 
00105     UINT4                  modeL,          /**< L                       */
00106     INT4                   modeM,          /**< M                       */
00107     REAL4                  inclination,    /**< binary inclination      */
00108     REAL4                  coa_phase       /**< binary coalescence phase*/)
00109 {
00110     COMPLEX16  MultSphHarm;
00111     REAL4      tmp1, tmp2;
00112     UINT4      vecLength, k;
00113 
00114     vecLength = strain->data->vectorLength;
00115 
00116     /* Calculating the (2,2) Spherical Harmonic */
00117     /* need some error checking */
00118     XLALSphHarm( &MultSphHarm, modeL, modeM, inclination, coa_phase );
00119 
00120     /* Filling the data vector with the data multiplied by the Harmonic */
00121     for ( k = 0; k < vecLength; k++)
00122     {
00123         tmp1 = strain->data->data[k];
00124         tmp2 = strain->data->data[vecLength + k];
00125 
00126         strain->data->data[k] = 
00127             (tmp1 * MultSphHarm.re) + 
00128             (tmp2 * MultSphHarm.im);
00129 
00130         strain->data->data[vecLength + k] = 
00131             (tmp2 * MultSphHarm.re) -
00132             (tmp1 * MultSphHarm.im);
00133     }
00134 
00135     return 0;
00136 /*   return( strain ); */
00137 }
00138 
00139 
00140 /** Takes a (sky averaged) numerical relativity waveform and returns the
00141  * waveform appropriate for given coalescence phase and inclination angles */
00142 REAL8TimeVectorSeries *
00143 XLALOrientNRWaveREAL8( 
00144     REAL8TimeVectorSeries *strain,         /**< sky average h+, hx data */ 
00145     UINT4                  modeL,          /**< L                       */
00146     INT4                   modeM,          /**< M                       */
00147     REAL4                  inclination,    /**< binary inclination      */
00148     REAL4                  coa_phase       /**< binary coalescence phase*/)
00149 {
00150     COMPLEX16  MultSphHarm;
00151     REAL4      tmp1, tmp2;
00152     UINT4      vecLength, k;
00153 
00154     vecLength = strain->data->vectorLength;
00155 
00156     /* Calculating the (2,2) Spherical Harmonic */
00157     /* need some error checking */
00158     XLALSphHarm( &MultSphHarm, modeL, modeM, inclination, coa_phase );
00159 
00160     /* Filling the data vector with the data multiplied by the Harmonic */
00161     for ( k = 0; k < vecLength; k++)
00162     {
00163         tmp1 = strain->data->data[k];
00164         tmp2 = strain->data->data[vecLength + k];
00165 
00166         strain->data->data[k] = 
00167             (tmp1 * MultSphHarm.re) + 
00168             (tmp2 * MultSphHarm.im);
00169 
00170         strain->data->data[vecLength + k] = 
00171             (tmp2 * MultSphHarm.re) -
00172             (tmp1 * MultSphHarm.im);
00173     }
00174   return( strain );
00175 }
00176 
00177 
00178 REAL4TimeSeries *
00179 XLALCalculateNRStrain( REAL4TimeVectorSeries *strain, /**< h+, hx time series data*/
00180                        SimInspiralTable      *inj,    /**< injection details      */
00181                        CHAR                  *ifo,    /**< interferometer */
00182                        INT4            sampleRate     /**< sample rate of time series */)
00183 {
00184   LALDetector            det;
00185   double                 fplus;
00186   double                 fcross;
00187   double                 tDelay;
00188   REAL4TimeSeries       *htData = NULL;
00189   UINT4                  vecLength, k;
00190   InterferometerNumber   ifoNumber = LAL_UNKNOWN_IFO;
00191 
00192   /* get the detector information */
00193   memset( &det, 0, sizeof(LALDetector) );
00194   ifoNumber = XLALIFONumber( ifo );
00195   XLALReturnDetector( &det, ifoNumber );
00196 
00197   /* compute detector response */
00198   XLALComputeDetAMResponse(&fplus, &fcross, det.response, inj->longitude, 
00199       inj->latitude, inj->polarization, inj->end_time_gmst);
00200 
00201   /* calculate the time delay */
00202   tDelay = XLALTimeDelayFromEarthCenter( det.location, inj->longitude,
00203       inj->latitude, &(inj->geocent_end_time) );
00204 
00205   /* create htData */
00206   htData = LALCalloc(1, sizeof(*htData));
00207   if (!htData) 
00208   {
00209     XLAL_ERROR_NULL( "XLALCalculateNRStrain", XLAL_ENOMEM );
00210   }
00211   vecLength = strain->data->vectorLength;
00212   htData->data = XLALCreateREAL4Vector( vecLength );
00213   if ( ! htData->data )
00214   {
00215     XLAL_ERROR_NULL( "XLALCalculateNRStrain", XLAL_ENOMEM );
00216   }
00217 
00218   /* store the htData */  
00219 
00220   /* add timedelay to inj->geocent_end_time */
00221   {
00222     REAL8 tEnd;
00223     tEnd =  XLALGPSGetREAL8(&(inj->geocent_end_time) );
00224     tEnd += tDelay;
00225     XLALGPSSetREAL8(&(htData->epoch), tEnd );
00226   }
00227   /* Using XLALGPSAdd is bad because that changes the GPS time! */
00228   /*  htData->epoch = *XLALGPSAdd( &(inj->geocent_end_time), tDelay ); */
00229 
00230   htData->deltaT = strain->deltaT;
00231   htData->sampleUnits = lalADCCountUnit;
00232 
00233   for ( k = 0; k < vecLength; ++k )
00234   {
00235     htData->data->data[k] = (fplus * strain->data->data[k]  + 
00236                              fcross * strain->data->data[vecLength + k]) / inj->distance;
00237   }
00238 
00239   /*interpolate to given sample rate */
00240   htData = XLALInterpolateNRWave( htData, sampleRate);
00241 
00242   return( htData );
00243 }
00244 
00245 
00246 
00247 /** Function for interpolating time series to a given sampling rate. 
00248     Input vector is destroyed and a new vector is allocated.
00249 */
00250 REAL4TimeSeries *
00251 XLALInterpolateNRWave( REAL4TimeSeries *in,           /**< input strain time series */
00252                        INT4            sampleRate     /**< sample rate of time series */)
00253 {
00254 
00255   REAL4TimeSeries *ret=NULL;
00256   REAL8 deltaTin, deltaTout, r, y1, y2;
00257   REAL8 tObs; /* duration of signal */
00258   UINT4 k, lo, numPoints;
00259   
00260   deltaTin = in->deltaT;
00261   tObs = deltaTin * in->data->length;  
00262 
00263   /* length of output vector */ 
00264   numPoints = (UINT4) (sampleRate * tObs);
00265 
00266   /* allocate memory */
00267   ret = LALCalloc(1, sizeof(*ret));
00268   if (!ret) 
00269   {
00270     XLAL_ERROR_NULL( "XLALCalculateNRStrain", XLAL_ENOMEM );
00271   }
00272 
00273   ret->data = XLALCreateREAL4Vector( numPoints );
00274   if (! ret->data) 
00275   {
00276     XLAL_ERROR_NULL( "XLALCalculateNRStrain", XLAL_ENOMEM );
00277   }
00278 
00279   ret->deltaT = 1./sampleRate;
00280   deltaTout = ret->deltaT;
00281 
00282   /* copy stuff from in which should be the same */
00283   ret->epoch = in->epoch;
00284   ret->f0 = in->f0;
00285   ret->sampleUnits = in->sampleUnits;
00286   strcpy(ret->name, in->name);
00287 
00288   /* go over points of output vector and interpolate linearly
00289      using closest points of input */
00290   for (k = 0; k < numPoints; k++) {
00291 
00292     lo = (UINT4)( k*deltaTout / deltaTin);
00293 
00294     /* y1 and y2 are the input values at x1 and x2 */
00295     /* here we need to make sure that we don't exceed
00296        bounds of input vector */
00297     if ( lo < in->data->length - 1) {
00298       y1 = in->data->data[lo];
00299       y2 = in->data->data[lo+1];
00300 
00301       /* we want to calculate y2*r + y1*(1-r) where
00302          r = (x-x1)/(x2-x1) */
00303       r = k*deltaTout / deltaTin - lo;
00304       
00305       ret->data->data[k] = y2 * r + y1 * (1 - r);
00306     }
00307     else {
00308       ret->data->data[k] = 0.0;
00309     }    
00310   }
00311 
00312   /* destroy input vector */
00313   XLALDestroyREAL4Vector ( in->data);
00314   LALFree(in);
00315 
00316   return ret;
00317 }
00318 
00319 
00320 
00321 int compare_abs_float(const void *a, const void *b){
00322 
00323   const REAL4 *af, *bf;
00324 
00325   af = (const REAL4 *)a;
00326   bf = (const REAL4 *)b;
00327 
00328   if ( fabs(*af) > fabs(*bf))
00329     return 1;
00330   else if  ( fabs(*af) < fabs(*bf))
00331     return -1;
00332   else 
00333     return 0;
00334 }
00335 
00336 
00337 int compare_abs_double(const void *a, const void *b){
00338 
00339   const REAL8 *af, *bf;
00340 
00341   af = (const REAL8 *)a;
00342   bf = (const REAL8 *)b;
00343 
00344   if ( fabs(*af) > fabs(*bf))
00345     return 1;
00346   else if  ( fabs(*af) < fabs(*bf))
00347     return -1;
00348   else 
00349     return 0;
00350 }
00351 
00352 
00353 /** Function for calculating the coalescence time (defined to be the peak) of a NR wave */
00354 INT4
00355 XLALFindNRCoalescenceTime(REAL8 *tc, 
00356                           const REAL4TimeVectorSeries *in   /**< input strain time series */)
00357 {
00358 
00359   size_t *ind=NULL;
00360   size_t len;
00361   REAL4 *sumSquare=NULL;
00362   UINT4 k;
00363 
00364   len = in->data->vectorLength;
00365   ind = LALCalloc(1,len*sizeof(*ind));  
00366 
00367   sumSquare = LALCalloc(1, len*sizeof(*sumSquare)); 
00368 
00369   for (k=0; k < len; k++) {
00370     sumSquare[k] = in->data->data[k]*in->data->data[k] + 
00371       in->data->data[k + len]*in->data->data[k + len];
00372   }    
00373 
00374   gsl_heapsort_index( ind, sumSquare, len, sizeof(REAL4), compare_abs_float);
00375 
00376   *tc = ind[len-1] * in->deltaT;
00377 
00378   LALFree(ind);
00379   LALFree(sumSquare);
00380 
00381   return 0;
00382 }
00383 
00384 
00385 /** Function for calculating the coalescence time (defined to be the
00386     peak) of a NR wave 
00387     This uses the peak of h(t) 
00388 */
00389 INT4
00390 XLALFindNRCoalescenceTimeFromhoft(REAL8 *tc, 
00391                           const REAL4TimeSeries *in   /**< input strain time series */)
00392 {
00393 
00394   size_t *ind=NULL;
00395   size_t len;
00396 
00397   len = in->data->length;
00398   ind = LALCalloc(1,len*sizeof(*ind));  
00399 
00400 /*   gsl_heapsort_index( ind, in->data->data, len, sizeof(REAL4), compare_abs_float); */
00401 
00402   *tc = ind[len-1] * in->deltaT;
00403 
00404   LALFree(ind);
00405 
00406   return 0;
00407 }
00408 
00409 
00410 /** Function for calculating the coalescence time (defined to be the peak) of a NR wave */
00411 INT4
00412 XLALFindNRCoalescenceTimeREAL8(REAL8 *tc, 
00413                                const REAL8TimeSeries *in   /**< input strain time series */)
00414 {
00415 
00416   size_t *ind=NULL;
00417   size_t len;
00418 
00419   len = in->data->length;
00420   ind = LALCalloc(len, sizeof(*ind));  
00421 
00422   gsl_heapsort_index( ind, in->data->data, len, sizeof(REAL8), compare_abs_double);
00423 
00424   *tc = ind[len-1] * in->deltaT;
00425 
00426   LALFree(ind);
00427 
00428   return 0;
00429 }
00430 
00431 
00432 
00433 /** For given inspiral parameters, find nearest waveform in 
00434     catalog of numerical relativity waveforms.  At the moment, only
00435     the mass ratio is considered.  
00436 */
00437 INT4
00438 XLALFindNRFile( NRWaveMetaData   *out,       /**< output wave data */
00439                 NRWaveCatalog    *nrCatalog, /**< input  NR wave catalog  */
00440                 const SimInspiralTable *inj,       /**< injection details  */
00441                 INT4  modeL,                 /**< mode index l*/
00442                 INT4  modeM                  /**< mode index m*/)
00443 {
00444 
00445   REAL8 massRatioIn, massRatio, diff, newDiff;
00446   UINT4 k, best;
00447 
00448   /* check arguments are sensible */
00449   if ( !out ) {
00450     LALPrintError ("\nOutput pointer is NULL !\n\n");
00451     XLAL_ERROR ( "XLALFindNRFile", XLAL_EINVAL);
00452   }
00453 
00454   if ( !nrCatalog ) {
00455     LALPrintError ("\n NR Catalog pointer is NULL !\n\n");
00456     XLAL_ERROR ( "XLALFindNRFile", XLAL_EINVAL);
00457   }
00458 
00459   if ( !inj ) {
00460     LALPrintError ("\n SimInspiralTable pointer is NULL !\n\n");
00461     XLAL_ERROR ( "XLALFindNRFile", XLAL_EINVAL);
00462   }
00463 
00464   /* we want to check for the highest mass before calculating the mass ratio */
00465   if (inj->mass2 > inj->mass1) {
00466      massRatioIn = inj->mass2/inj->mass1;
00467   }
00468   else {
00469      massRatioIn = inj->mass1/inj->mass2;
00470   }
00471  
00472   /*   massRatio = nrCatalog->data[0].massRatio; */
00473   
00474   /*   diff = fabs(massRatio - massRatioIn); */
00475 
00476   /* look over catalog and fimd waveform closest in mass ratio */
00477   /* initialize diff */
00478   diff = -1;
00479   for (k = 0; k < nrCatalog->length; k++) {
00480 
00481     /* check catalog data is not null */
00482     if ( nrCatalog->data + k == NULL ) {
00483       LALPrintError ("\n NR Catalog data is NULL !\n\n");
00484       XLAL_ERROR ( "XLALFindNRFile", XLAL_EINVAL);
00485     }
00486 
00487     /* look for waveforms with correct mode values */
00488     if ((modeL == nrCatalog->data[k].mode[0]) && (modeM == nrCatalog->data[k].mode[1])) {
00489 
00490       massRatio = nrCatalog->data[k].massRatio;
00491       newDiff = fabs(massRatio - massRatioIn);
00492       
00493       if ( (diff < 0) || (diff > newDiff)) {
00494         diff = newDiff;
00495         best = k;
00496       }    
00497     } /* if (modeL == ...) */
00498   } /* loop over waveform catalog */
00499 
00500   /* error checking if waveforms with input mode values were not found */
00501   if ( diff < 0) {
00502     LALPrintError ("\n Input mode numbers not found !\n\n");
00503     XLAL_ERROR ( "XLALFindNRFile", XLAL_EINVAL);
00504   }
00505 
00506   /* copy best match to output */
00507   memcpy(out, nrCatalog->data + best, sizeof(NRWaveMetaData));
00508 
00509   return 0;
00510 
00511 }
00512 
00513 /** Spin 2 weighted spherical Harmonic */
00514 INT4 XLALSphHarm ( COMPLEX16 *out, /**< output */
00515                    UINT4   L,      /**< value of L */
00516                    INT4    M,      /**< value of M */
00517                    REAL4   theta,  /**< angle with respect to the z axis */
00518                    REAL4   phi     /**< angle with respect to the x axis */)
00519      
00520 {
00521     REAL4      deptheta; /** dependency on theta */
00522 
00523   /* check arguments are sensible */
00524     if ( !out ) {
00525       LALPrintError ("\nOutput pointer is NULL !\n\n");
00526       XLAL_ERROR ( "XLALSphHarm", XLAL_EINVAL);
00527     }
00528 
00529     if (L == 2)
00530     {
00531       switch ( M ){
00532       case -2:
00533         deptheta = sqrt( 5.0 / ( 64.0 * LAL_PI ) ) * ( 1.0 - cos( theta ))*( 1.0 - cos( theta ));
00534         out->re = deptheta * cos( -2.0*phi );
00535         out->im = deptheta * sin( -2.0*phi );
00536         break;
00537         
00538       case -1:
00539         deptheta = sqrt( 5.0 / ( 16.0 * LAL_PI ) ) * sin( theta )*( 1.0 - cos( theta ));
00540         out->re = deptheta * cos( -phi );
00541         out->im = deptheta * sin( -phi );
00542         break;
00543         
00544       case 0:
00545         deptheta = sqrt( 15.0 / ( 32.0 * LAL_PI ) ) * sin( theta )*sin( theta );
00546         out->re = deptheta;
00547         out->im = 0.0;
00548         break;
00549         
00550       case 1:
00551         deptheta = sqrt( 5.0 / ( 16.0 * LAL_PI ) ) * sin( theta )*( 1.0 + cos( theta ));
00552         out->re = deptheta * cos( phi );
00553         out->im = deptheta * sin( phi );
00554         break;
00555         
00556       case 2:
00557         deptheta = sqrt( 5.0 / ( 64.0 * LAL_PI ) ) * ( 1.0 + cos( theta ))*( 1.0 + cos( theta ));
00558         out->re = deptheta * cos( 2.0*phi );
00559         out->im = deptheta * sin( 2.0*phi );
00560         break;     
00561         
00562       default:
00563         /* Error message informing that the chosen M is incompatible with L*/
00564         LALPrintError ("\n Inconsistent (L, M) values \n\n");
00565         XLAL_ERROR ( "XLALSphHarm", XLAL_EINVAL);
00566         break;
00567       }  /* switch (M) */
00568     }  /* L==2*/
00569     
00570     else if (L == 3)
00571       {
00572         switch ( M ) {
00573         case -3:
00574           deptheta = sqrt(21./(2.*LAL_PI))*cos(theta/2.)*pow(sin(theta/2.),5);
00575           out->re = deptheta * cos( -3.0*phi );
00576           out->im = deptheta * sin( -3.0*phi );
00577           break;
00578           
00579         case -2:
00580           deptheta = sqrt(7./(4.*LAL_PI))*(2 + 3*cos(theta))*pow(sin(theta/2.),4);
00581           out->re = deptheta * cos( -2.0*phi );
00582           out->im = deptheta * sin( -2.0*phi );
00583           break;
00584           
00585         case -1:
00586           deptheta = sqrt(35./(2.*LAL_PI))*(sin(theta) + 4*sin(2*theta) - 3*sin(3*theta))/32.;
00587           out->re = deptheta * cos( -phi );
00588           out->im = deptheta * sin( -phi );
00589           break;
00590           
00591         case 0:
00592           deptheta = (sqrt(105./(2.*LAL_PI))*cos(theta)*pow(sin(theta),2))/4.;
00593           out->re = deptheta;
00594           out->im = 0.0;
00595           break;
00596           
00597         case 1:
00598           deptheta = -sqrt(35./(2.*LAL_PI))*(sin(theta) - 4*sin(2*theta) - 3*sin(3*theta))/32.;
00599           out->re = deptheta * cos( phi );
00600           out->im = deptheta * sin( phi );
00601           break;
00602           
00603         case 2:
00604           deptheta = sqrt(7./LAL_PI)*pow(cos(theta/2.),4)*(-2 + 3*cos(theta))/2.;
00605           out->re = deptheta * cos( 2.0*phi );
00606           out->im = deptheta * sin( 2.0*phi );
00607           break;           
00608           
00609         case 3:
00610           deptheta = -sqrt(21./(2.*LAL_PI))*pow(cos(theta/2.),5)*sin(theta/2.);
00611           out->re = deptheta * cos( 3.0*phi );
00612           out->im = deptheta * sin( 3.0*phi );
00613           break;           
00614           
00615         default:
00616           /* Error message informing that the chosen M is incompatible with L*/
00617           LALPrintError ("\n Inconsistent (L, M) values \n\n");
00618           XLAL_ERROR ( "XLALSphHarm", XLAL_EINVAL);
00619           break;
00620         } 
00621       }   /* L==3 */ 
00622     
00623     else if (L == 4)
00624     {
00625       switch ( M )      {
00626         
00627       case -4:
00628         deptheta = 3.*sqrt(7./LAL_PI)*pow(cos(theta/2.),2)*pow(sin(theta/2.),6);
00629         out->re = deptheta * cos( -4.0*phi );
00630         out->im = deptheta * sin( -4.0*phi );
00631         break;
00632         
00633       case -3:
00634         deptheta = 3.*sqrt(7./(2.*LAL_PI))*cos(theta/2.)*(1 + 2*cos(theta))*pow(sin(theta/2.),5);
00635         out->re = deptheta * cos( -3.0*phi );
00636         out->im = deptheta * sin( -3.0*phi );
00637         break;
00638         
00639       case -2:
00640         deptheta = (3*(9. + 14.*cos(theta) + 7.*cos(2*theta))*pow(sin(theta/2.),4))/(4.*sqrt(LAL_PI));
00641         out->re = deptheta * cos( -2.0*phi );
00642         out->im = deptheta * sin( -2.0*phi );
00643         break;
00644         
00645       case -1:
00646         deptheta = (3.*(3.*sin(theta) + 2.*sin(2*theta) + 7.*sin(3*theta) - 7.*sin(4*theta)))/(32.*sqrt(2*LAL_PI));
00647         out->re = deptheta * cos( -phi );
00648         out->im = deptheta * sin( -phi );
00649         break;
00650         
00651       case 0:
00652         deptheta = (3.*sqrt(5./(2.*LAL_PI))*(5. + 7.*cos(2*theta))*pow(sin(theta),2))/16.;
00653         out->re = deptheta;
00654         out->im = 0.0;
00655         break;
00656         
00657       case 1:
00658         deptheta = (3.*(3.*sin(theta) - 2.*sin(2*theta) + 7.*sin(3*theta) + 7.*sin(4*theta)))/(32.*sqrt(2*LAL_PI));
00659         out->re = deptheta * cos( phi );
00660         out->im = deptheta * sin( phi );
00661         break;
00662         
00663       case 2:
00664         deptheta = (3.*pow(cos(theta/2.),4)*(9. - 14.*cos(theta) + 7.*cos(2*theta)))/(4.*sqrt(LAL_PI));
00665         out->re = deptheta * cos( 2.0*phi );
00666         out->im = deptheta * sin( 2.0*phi );
00667         break;     
00668         
00669       case 3:
00670         deptheta = -3.*sqrt(7./(2.*LAL_PI))*pow(cos(theta/2.),5)*(-1. + 2.*cos(theta))*sin(theta/2.);
00671         out->re = deptheta * cos( 3.0*phi );
00672         out->im = deptheta * sin( 3.0*phi );
00673         break;     
00674         
00675       case 4:
00676         deptheta = 3.*sqrt(7./LAL_PI)*pow(cos(theta/2.),6)*pow(sin(theta/2.),2);
00677         out->re = deptheta * cos( 4.0*phi );
00678         out->im = deptheta * sin( 4.0*phi );
00679         break;     
00680         
00681       default:
00682         /* Error message informing that the chosen M is incompatible with L*/
00683         LALPrintError ("\n Inconsistent (L, M) values \n\n");
00684         XLAL_ERROR ( "XLALSphHarm", XLAL_EINVAL);
00685         break;
00686       }
00687     }    /* L==4 */
00688     
00689     else if (L == 5)
00690     {
00691         switch ( M )    {
00692 
00693         case -5:
00694           deptheta = sqrt(330./LAL_PI)*pow(cos(theta/2.),3)*pow(sin(theta/2.),7);
00695           out->re = deptheta * cos( -5.0*phi );
00696           out->im = deptheta * sin( -5.0*phi );
00697           break;
00698           
00699         case -4:
00700           deptheta = sqrt(33./LAL_PI)*pow(cos(theta/2.),2)*(2. + 5.*cos(theta))*pow(sin(theta/2.),6);
00701           out->re = deptheta * cos( -4.0*phi );
00702           out->im = deptheta * sin( -4.0*phi );
00703           break;
00704           
00705         case -3:
00706           deptheta = (sqrt(33./(2.*LAL_PI))*cos(theta/2.)*(17. + 24.*cos(theta) + 15.*cos(2.*theta))*pow(sin(theta/2.),5))/4.;
00707           out->re = deptheta * cos( -3.0*phi );
00708           out->im = deptheta * sin( -3.0*phi );
00709           break;
00710           
00711         case -2:
00712           deptheta = (sqrt(11./LAL_PI)*(32. + 57.*cos(theta) + 36.*cos(2.*theta) + 15.*cos(3.*theta))*pow(sin(theta/2.),4))/8.;
00713           out->re = deptheta * cos( -2.0*phi );
00714           out->im = deptheta * sin( -2.0*phi );
00715           break;
00716           
00717         case -1:
00718           deptheta = (sqrt(77./LAL_PI)*(2.*sin(theta) + 8.*sin(2.*theta) + 3.*sin(3.*theta) + 12.*sin(4.*theta) - 15.*sin(5.*theta)))/256.;
00719           out->re = deptheta * cos( -phi );
00720           out->im = deptheta * sin( -phi );
00721           break;
00722           
00723         case 0:
00724           deptheta = (sqrt(1155./(2.*LAL_PI))*(5.*cos(theta) + 3.*cos(3.*theta))*pow(sin(theta),2))/32.;
00725           out->re = deptheta;
00726           out->im = 0.0;
00727           break;
00728           
00729         case 1:
00730           deptheta = sqrt(77./LAL_PI)*(-2.*sin(theta) + 8.*sin(2.*theta) - 3.*sin(3.*theta) + 12.*sin(4.*theta) + 15.*sin(5.*theta))/256.;
00731           out->re = deptheta * cos( phi );
00732           out->im = deptheta * sin( phi );
00733           break;
00734           
00735         case 2:
00736           deptheta = sqrt(11./LAL_PI)*pow(cos(theta/2.),4)*(-32. + 57.*cos(theta) - 36.*cos(2.*theta) + 15.*cos(3.*theta))/8.;
00737           out->re = deptheta * cos( 2.0*phi );
00738           out->im = deptheta * sin( 2.0*phi );
00739           break;           
00740           
00741         case 3:
00742           deptheta = -sqrt(33./(2.*LAL_PI))*pow(cos(theta/2.),5)*(17. - 24.*cos(theta) + 15.*cos(2.*theta))*sin(theta/2.)/4.;
00743           out->re = deptheta * cos( 3.0*phi );
00744           out->im = deptheta * sin( 3.0*phi );
00745           break;           
00746           
00747         case 4:
00748           deptheta = sqrt(33./LAL_PI)*pow(cos(theta/2.),6)*(-2. + 5.*cos(theta))*pow(sin(theta/2.),2);
00749           out->re = deptheta * cos( 4.0*phi );
00750           out->im = deptheta * sin( 4.0*phi );
00751           break;           
00752           
00753         case 5:
00754           deptheta = -sqrt(330./LAL_PI)*pow(cos(theta/2.),7)*pow(sin(theta/2.),3);
00755           out->re = deptheta * cos( 5.0*phi );
00756           out->im = deptheta * sin( 5.0*phi );
00757           break;           
00758           
00759         default:
00760           /* Error message informing that the chosen M is incompatible with L*/
00761           LALPrintError ("\n Inconsistent (L, M) values \n\n");
00762           XLAL_ERROR ( "XLALSphHarm", XLAL_EINVAL);
00763           break;
00764         }
00765     }  /* L==5 */
00766     
00767     
00768     else 
00769     {
00770       /* Error message informing that L!=2 is not yet implemented*/
00771       LALPrintError ("\n These (L, M) values not implemented yet \n\n");
00772       XLAL_ERROR ( "XLALSphHarm", XLAL_EINVAL);
00773     }
00774     
00775     return 0;
00776 }
00777 
00778 
00779 void LALInjectStrainGW( LALStatus                 *status,
00780                         REAL4TimeSeries           *injData,
00781                         REAL4TimeVectorSeries     *strain,
00782                         SimInspiralTable          *thisInj,
00783                         CHAR                      *ifo,
00784                         REAL8                     dynRange)
00785 {
00786 
00787   REAL8 sampleRate;
00788   REAL4TimeSeries *htData = NULL;
00789   UINT4  k;
00790   REAL8 offset;
00791 
00792   INITSTATUS (status, "LALNRInject",  NRWAVEINJECTC);
00793   ATTATCHSTATUSPTR (status); 
00794 
00795   /* sampleRate = 1.0/strain->deltaT;   */
00796   /* use the sample rate required for the output time series */
00797   sampleRate = 1.0/injData->deltaT;
00798     
00799   /*compute strain for given sky location*/
00800   htData = XLALCalculateNRStrain( strain, thisInj, ifo, sampleRate );
00801 
00802   /* multiply the input data by dynRange */
00803   for ( k = 0 ; k < htData->data->length ; ++k )
00804   {
00805     htData->data->data[k] *= dynRange;
00806   }
00807 
00808   XLALFindNRCoalescenceTime( &offset, strain);
00809 
00810   XLALGPSAdd( &(htData->epoch), -offset);
00811 
00812   /* inject the htData into injection time stream */
00813   TRY( LALSSInjectTimeSeries( status->statusPtr, injData, htData ),
00814        status );
00815   
00816   /* set channel name */
00817   LALSnprintf( injData->name, LIGOMETA_CHANNEL_MAX * sizeof( CHAR ),
00818     "%s:STRAIN", ifo ); 
00819 
00820   XLALDestroyREAL4Vector ( htData->data);
00821   LALFree(htData);
00822 
00823   DETATCHSTATUSPTR(status);
00824   RETURN(status);
00825   
00826 }
00827 
00828 
00829 /** REAL8 version of above but using Jolien's new functions */
00830 void LALInjectStrainGWREAL8( LALStatus                 *status,
00831                              REAL8TimeSeries           *injData,
00832                              REAL8TimeVectorSeries     *strain,
00833                              SimInspiralTable          *thisInj,
00834                              CHAR                      *ifo,
00835                              REAL8                     dynRange)
00836 {
00837 
00838   REAL8 sampleRate;
00839   REAL8TimeSeries *htData = NULL;
00840   REAL8TimeSeries *hplus = NULL;  
00841   REAL8TimeSeries *hcross = NULL;  
00842   UINT4  k, len;
00843   REAL8 offset;
00844   InterferometerNumber  ifoNumber = LAL_UNKNOWN_IFO;
00845   LALDetector det;
00846 
00847   INITSTATUS (status, "LALNRInject",  NRWAVEINJECTC);
00848   ATTATCHSTATUSPTR (status); 
00849 
00850   /* get the detector information */
00851   memset( &det, 0, sizeof(LALDetector) );
00852   ifoNumber = XLALIFONumber( ifo );
00853   XLALReturnDetector( &det, ifoNumber );
00854 
00855   /* sampleRate = 1.0/strain->deltaT;   */
00856   /* use the sample rate required for the output time series */
00857   sampleRate = 1.0/injData->deltaT;
00858   len = strain->data->vectorLength;
00859 
00860   hplus = XLALCreateREAL8TimeSeries ( strain->name, &strain->epoch, strain->f0, 
00861                                       strain->deltaT, &strain->sampleUnits, len);
00862   hcross = XLALCreateREAL8TimeSeries ( strain->name, &strain->epoch, strain->f0, 
00863                                        strain->deltaT, &strain->sampleUnits, len);
00864   
00865   for ( k = 0; k < len; k++) {
00866     hplus->data->data[k] = strain->data->data[k];
00867     hplus->data->data[k] = strain->data->data[k + len];
00868   }
00869 
00870   htData = XLALSimDetectorStrainREAL8TimeSeries( hplus, hcross, thisInj->longitude, 
00871                                                  thisInj->latitude, thisInj->polarization, 
00872                                                  &det);
00873 
00874   XLALFindNRCoalescenceTimeREAL8( &offset, htData);
00875   XLALGPSAdd( &(htData->epoch), -offset);
00876 
00877   XLALSimAddInjectionREAL8TimeSeries( injData, htData, NULL);
00878   
00879   /* set channel name */
00880   LALSnprintf( injData->name, LIGOMETA_CHANNEL_MAX * sizeof( CHAR ),
00881     "%s:STRAIN", ifo ); 
00882 
00883   XLALDestroyREAL8TimeSeries ( htData);
00884   XLALDestroyREAL8TimeSeries ( hplus);
00885   XLALDestroyREAL8TimeSeries ( hcross);
00886 
00887   DETATCHSTATUSPTR(status);
00888   RETURN(status);
00889   
00890 }
00891 
00892 
00893 /** construct the channel name corresponding to a particular mode 
00894     and polarization in frame file containing nr data */
00895 CHAR* XLALGetNinjaChannelName(CHAR *polarisation, UINT4 l, INT4 m)
00896 {
00897   /* variables */
00898   CHAR sign;
00899   CHAR *channel=NULL;
00900 
00901   if ( !((strncmp(polarisation, "plus", 4) == 0) || (strncmp(polarisation, "cross", 5) == 0))) {
00902     XLAL_ERROR_NULL( "XLALGetNinjaChannelName",   XLAL_EINVAL ); 
00903   }
00904 
00905   /* allocate memory for channel */
00906   channel = (CHAR *)LALCalloc(1, LIGOMETA_CHANNEL_MAX * sizeof(CHAR));
00907 
00908   /* get sign of m */
00909   if (m < 0)
00910   {
00911     /* negative */
00912     strncpy(&sign, "n", 1);
00913   }
00914   else
00915   {
00916     /* positive */
00917     strncpy(&sign, "p", 1);
00918   }
00919 
00920   /* set channel name */
00921   LALSnprintf(channel, LIGOMETA_CHANNEL_MAX, "h%s_l%d_m%c%d", polarisation, l, sign, abs(m));
00922 
00923   /* return channel name */
00924   return channel;
00925 }
00926 
00927 
00928 /** Function for parsing numrel group name and converting it