00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <stdlib.h>
00031 #include <math.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <lal/Date.h>
00036 #include <lal/DetResponse.h>
00037 #include <lal/LALStdlib.h>
00038 #include <lal/LALConstants.h>
00039 #include <lal/AVFactories.h>
00040 #include <lal/SeqFactories.h>
00041 #include <lal/LIGOMetadataTables.h>
00042 #include <lal/LIGOMetadataUtils.h>
00043 #include <lal/Units.h>
00044 #include <lal/SimulateCoherentGW.h>
00045 #include <lal/GenerateRing.h>
00046 #include <lal/Ring.h>
00047 #include <lal/TimeDelay.h>
00048 #include <lal/TimeSeries.h>
00049 #include <lal/GenerateInspRing.h>
00050
00051 NRCSID (GENERATEINSPRINGC,"$Id: GenerateInspRing.c,v 1.18 2008/01/31 18:41:18 sfairhur Exp $");
00052
00053 static SimRingdownTable*
00054 XLALDeriveRingdownParameters(
00055 SimRingdownTable *ringInj
00056 );
00057
00058
00059
00060 CoherentGW *
00061 XLALGenerateInspRing(
00062 CoherentGW *waveform,
00063 SimInspiralTable *inspiralInj,
00064 SimRingdownTable *ringInj,
00065 int injectSignalType
00066 )
00067 {
00068 static const char *func = "XLALGenerateInspRing";
00069
00070 REAL4 *a, *f;
00071 REAL4 *shift = NULL;
00072 REAL8 *phi;
00073
00074
00075 INT4 inputLength;
00076 INT4 outputLength;
00077 INT4 mergerLength;
00078 INT4 ringLength;
00079 INT4 endMerger = 0;
00080 INT4 condt;
00081
00082
00083 REAL8 phase;
00084 REAL8 mergerPhase;
00085 REAL8 phi0;
00086 REAL4 dt;
00087 REAL4 ampPlus;
00088 REAL4 ampPlusDot;
00089 REAL4 a2Plus;
00090 REAL4 ampCross;
00091 REAL4 ampCrossDot;
00092 REAL4 a2Cross;
00093 REAL4 freq;
00094 REAL4 freqDot;
00095 REAL4 freq0;
00096 REAL4 freqDot0;
00097 REAL4 polarization;
00098 REAL4 polDot;
00099 REAL4 dampFac;
00100 REAL4 phaseFac;
00101 REAL4 A, lambda;
00102 REAL4 tToRing;
00103 REAL4 tRing;
00104 REAL4 amp;
00105 INT4 n, N;
00106
00107
00108 REAL4 mTot = 0;
00109 REAL4 orbAngMom, totalAngMom;
00110 REAL4 Jx, Jy, Jz;
00111
00112 REAL4 splus, scross, cosiota, cosiotaA, cosiotaB;
00113
00114
00115
00116
00117
00118
00119
00120
00121 if ( !waveform || !(waveform->a->data) || !(waveform->f->data) ||
00122 !(waveform->phi->data) )
00123 {
00124 XLALPrintError("Invalid waveform passed as input to %s\n", func);
00125 XLAL_ERROR_NULL(func,XLAL_EIO);
00126 }
00127
00128 if ( (waveform->a->data->length < 2) )
00129 {
00130 XLALPrintError(
00131 "Length of waveform input to %s must be at least 2 points\n", func);
00132 XLAL_ERROR_NULL(func,XLAL_EIO);
00133 }
00134
00135 if ( !inspiralInj )
00136 {
00137 XLALPrintError("No sim inspiral table passed as input to %s\n", func);
00138 XLAL_ERROR_NULL(func,XLAL_EIO);
00139 }
00140
00141
00142 inputLength = waveform->a->data->length;
00143
00144
00145 dt = waveform->f->deltaT;
00146
00147 ampPlus = waveform->a->data->data[2*inputLength - 2];
00148 ampPlusDot = ampPlus - waveform->a->data->data[2*inputLength - 4];
00149
00150 ampCross = waveform->a->data->data[2*inputLength - 1];
00151 ampCrossDot = ampCross - waveform->a->data->data[2*inputLength - 3];
00152
00153 freq0 = waveform->f->data->data[inputLength - 1];
00154 freqDot0 = freq0 - waveform->f->data->data[inputLength - 2];
00155 freqDot0 /= dt;
00156
00157 phase = waveform->phi->data->data[inputLength - 1];
00158
00159
00160 if ( waveform->shift )
00161 {
00162 polarization = waveform->shift->data->data[inputLength - 1];
00163 polDot = polarization - waveform->shift->data->data[inputLength - 2];
00164 }
00165
00166 XLALPrintInfo(
00167 "Final inspiral frequency = %.2f Hz, fdot = %.2e Hz/s\n"
00168 "\n", freq0, freqDot0);
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 orbAngMom = 4 * inspiralInj->eta * 0.7;
00180 mTot = inspiralInj->mass1 + inspiralInj->mass2;
00181
00182 Jx = orbAngMom * sin(inspiralInj->inclination) +
00183 (inspiralInj->spin1x * inspiralInj->mass1 * inspiralInj->mass1 +
00184 inspiralInj->spin2x * inspiralInj->mass2 * inspiralInj->mass2) /
00185 (mTot * mTot) ;
00186 Jy = (inspiralInj->spin1y * inspiralInj->mass1 * inspiralInj->mass1 +
00187 inspiralInj->spin2y * inspiralInj->mass2 * inspiralInj->mass2) /
00188 (mTot * mTot) ;
00189 Jz = orbAngMom * cos(inspiralInj->inclination) +
00190 (inspiralInj->spin1z * inspiralInj->mass1 * inspiralInj->mass1 +
00191 inspiralInj->spin2z * inspiralInj->mass2 * inspiralInj->mass2) /
00192 (mTot * mTot);
00193 totalAngMom = pow(Jx * Jx + Jy * Jy + Jz * Jz, 0.5);
00194
00195 XLALPrintInfo( "Approximate orbital ang mom = %.2f\n", orbAngMom);
00196 XLALPrintInfo( "Approximate total angular momentum of inspiral:\n"
00197 "Jx = %.2f, Jy = %.2f, Jz = %.2f\n", Jx, Jy, Jz);
00198 XLALPrintInfo( "Estimated Final Spin = %.2f\n", totalAngMom );
00199
00200
00201 XLALPrintInfo( "Total inspiral mass = %.2f\n", mTot );
00202 mTot *= (1 - 0.01 * (1.0 + 6.0 * totalAngMom * totalAngMom ) );
00203 ringInj->mass = mTot;
00204 XLALPrintInfo( "Estimated Final Mass = %.2f\n", ringInj->mass );
00205
00206
00207 ringInj->spin = totalAngMom < 0.99 ? totalAngMom : 0.95;
00208
00209 ringInj->frequency = pow( LAL_C_SI, 3) / LAL_G_SI / LAL_MSUN_SI / 2.0 /
00210 LAL_PI * ( 1.0 - 0.63 * pow( ( 1.0 - ringInj->spin ), 0.3 ) ) /
00211 ringInj->mass;
00212 ringInj->quality = 2.0 * pow( ( 1.0 - ringInj->spin ), -0.45 );
00213
00214 XLALPrintInfo(
00215 "Estimated Ringdown Frequency = %.2f Hz, and Quality = %.2f\n"
00216 "\n", ringInj->frequency, ringInj->quality );
00217
00218 ringInj->longitude = inspiralInj->longitude;
00219 ringInj->latitude = inspiralInj->latitude;
00220 ringInj->distance = inspiralInj->distance;
00221
00222 XLALPrintInfo(
00223 "Ringdown longitude = %.2f, latitude = %.2f, distance = %.2f\n",
00224 ringInj->longitude, ringInj->latitude, ringInj->distance );
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 tToRing = 3 * freq0 / ( 8 * freqDot0 ) *
00256 (1 - pow( freq0 / (0.9 * ringInj->frequency), 8.0/3.0) );
00257 mergerLength = ceil( tToRing / dt ) - 1;
00258 phi0 = phase + LAL_TWOPI * 3 * freq0 * freq0 / (5 * freqDot0);
00259
00260 mergerPhase = phi0 - phase
00261 - ( LAL_TWOPI) * (3.0 * freq0 * freq0 ) / ( 5.0 * freqDot0 ) *
00262 pow( 1 - ( 8.0 * freqDot0 * tToRing) / ( 3.0 * freq0 ) , 5.0/8.0 );
00263
00264
00265 XLALPrintInfo( "Adding by hand a merger and ringdown\n");
00266 XLALPrintInfo( "Time to reach 0.9 of ringdown frequency = %.4f seconds,\n"
00267 "%d data points, %.2f radians in GW phase\n"
00268 "We then add the same length to asymptote to ringdown values\n",
00269 tToRing, mergerLength, mergerPhase);
00270
00271 if ( mergerPhase > 2 * LAL_TWOPI )
00272 {
00273 XLALPrintError("Failed to add a decent merger and ringdown\n"
00274 "The merger had a length of %.2f radians in GW phase (only allow 4pi)\n"
00275 "Returning null from %s\n",
00276 mergerPhase, func);
00277 XLALFree( waveform->a );
00278 XLALFree( waveform->phi );
00279 XLALFree( waveform->f );
00280 XLALFree( waveform->shift );
00281 XLAL_ERROR_NULL(func,XLAL_EFAILED);
00282 }
00283
00284
00285
00286 phaseFac = LAL_TWOPI * ringInj->frequency * dt;
00287 dampFac = exp( - phaseFac / (2 * ringInj->quality));
00288
00289 ringLength = ceil((24 * ringInj->quality)/( phaseFac));
00290 tRing = ringLength * dt;
00291
00292 XLALPrintInfo( "Time to damp the ringdown by exp(12) = %.4f seconds,\n"
00293 "%d data points, %.2f radians in GW phase\n"
00294 "\n", tRing, ringLength, ringLength * phaseFac);
00295
00296
00297
00298
00299 outputLength = inputLength + 2 * mergerLength - 1 + ringLength;
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 waveform->a->data->length = outputLength;
00311 waveform->a->data->data = (REAL4 *) XLALRealloc( ( waveform->a->data->data ),
00312 2*outputLength*sizeof(REAL4) );
00313 if ( !waveform->a->data->data )
00314 {
00315 XLALFree( waveform->a);
00316 XLAL_ERROR_NULL( func, XLAL_ENOMEM );
00317 }
00318
00319 memset(waveform->a->data->data + 2 * inputLength, 0,
00320 2 * (outputLength - inputLength) * sizeof(REAL4) );
00321 XLALResizeREAL8TimeSeries( waveform->phi, 0, outputLength);
00322 if ( !waveform->phi->data )
00323 {
00324 XLALFree( waveform->a);
00325 XLALFree( waveform->phi);
00326 XLAL_ERROR_NULL( func, XLAL_ENOMEM );
00327 }
00328
00329 XLALResizeREAL4TimeSeries( waveform->f, 0, outputLength);
00330 if ( !waveform->f->data->data )
00331 {
00332 XLALFree( waveform->a );
00333 XLALFree( waveform->phi );
00334 XLALFree( waveform->f );
00335 XLAL_ERROR_NULL( func, XLAL_ENOMEM );
00336 }
00337
00338 if ( waveform->shift )
00339 {
00340 XLALResizeREAL4TimeSeries( waveform->shift, 0, outputLength);
00341 if ( !waveform->f->data->data )
00342 {
00343 XLALFree( waveform->a );
00344 XLALFree( waveform->phi );
00345 XLALFree( waveform->f );
00346 XLALFree( waveform->shift );
00347 XLAL_ERROR_NULL( func, XLAL_ENOMEM );
00348 }
00349 }
00350
00351 a = &(waveform->a->data->data[2*inputLength]);
00352 phi = &(waveform->phi->data->data[inputLength]);
00353 f = &(waveform->f->data->data[inputLength]);
00354
00355 if ( waveform->shift )
00356 {
00357 shift = &(waveform->shift->data->data[inputLength]);
00358 }
00359
00360
00361
00362
00363
00364
00365
00366 freq = freq0;
00367
00368
00369 for ( n = 1; n < mergerLength + 1; n++ )
00370 {
00371 REAL4 factor = 1 - (8.0 * freqDot0 * n * dt) / (3.0 * freq0 );
00372 freq = *(f++) = freq0 * pow( factor , -3.0/8.0 );
00373 phase = *(phi++) = phi0 -
00374 LAL_TWOPI * 3.0 * freq0 * freq0 / (5.0 * freqDot0) *
00375 pow( factor , 5.0/8.0);
00376 if ( shift )
00377 {
00378 polarization = *(shift++) = polarization + polDot;
00379 }
00380 }
00381
00382
00383 ringInj->phase = phase;
00384
00385
00386
00387
00388
00389
00390 freqDot = (freq - *(f - 2)) / dt;
00391 A = ringInj->frequency - freq;
00392 lambda = freqDot / A;
00393
00394 XLALPrintInfo(
00395 "Starting to asymptote to ringdown\n"
00396 "Final 'merger' frequency = %.2f Hz, fdot = %.2e Hz/s\n",
00397 freq, freqDot);
00398 XLALPrintInfo(
00399 "Frequency evolution fitted to freq = f_ring - A exp(-lambda t)\n"
00400 "A = %.2f, lambda = %.2e\n"
00401 "\n", A, lambda);
00402
00403 condt = 0;
00404 for ( n = 1; n < mergerLength + ringLength; n++ )
00405 {
00406 phase = *(phi++) = phase + LAL_TWOPI * freq * dt;
00407 freq = *(f++) = ringInj->frequency - A * exp( - n * dt * lambda );
00408 if ( freq == ringInj->frequency & condt == 0)
00409 {
00410 endMerger = n - 1.0;
00411 condt = 1.0;
00412 }
00413 if ( shift )
00414 {
00415 polDot *= exp( - lambda * dt);
00416 polarization = *(shift++) = polarization + polDot;
00417 }
00418 }
00419
00420
00421 {
00422 REAL8 tRing;
00423 tRing = XLALGPSGetREAL8(&(inspiralInj->geocent_end_time));
00424 tRing += ( mergerLength + endMerger + 1.0) * dt;
00425 XLALGPSSetREAL8( &(ringInj->geocent_start_time), tRing );
00426 }
00427 XLALPrintInfo(
00428 "Ringdown start time = %d.%d\n", ringInj->geocent_start_time.gpsSeconds,
00429 ringInj->geocent_start_time.gpsNanoSeconds);
00430
00431
00432 ringInj->polarization = polarization;
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 N = 2 * mergerLength;
00463
00464 a2Plus = ((dampFac - 1) * ( ampPlus + N * ampPlusDot ) - ampPlusDot) /
00465 ( 2*N - N*N*(dampFac - 1) );
00466 a2Cross = ((dampFac - 1) * ( ampCross + N * ampCrossDot ) - ampCrossDot) /
00467 ( 2*N - N*N*(dampFac - 1) );
00468
00469 XLALPrintInfo( "Fitting amplitude evolution to a quadratic\n"
00470 "A = a_0 + a_1 * t + a_2 * t^2\n"
00471 "For plus polarization, a_0 = %.2e, a_1 = %.2e, a_2 = %.2e\n"
00472 "For cross polarization, a_0 = %.2e, a_1 = %.2e, a_2 = %.2e\n"
00473 "\n", ampPlus, ampPlusDot / dt, a2Plus / (dt * dt),
00474 ampCross, ampCrossDot / dt, a2Cross / (dt * dt) );
00475
00476
00477 for ( n = 1; n < N; n++ )
00478 {
00479 *(a++) = ampPlus + ampPlusDot * n + a2Plus * n * n;
00480 *(a++) = ampCross + ampCrossDot * n + a2Cross * n * n;
00481 }
00482
00483
00484 ampPlus = *(a - 2);
00485 ampCross = *(a - 1);
00486
00487 for ( n = 0; n < ringLength; n++ )
00488 {
00489 ampPlus = *(a++) = ampPlus * dampFac;
00490 ampCross = *(a++) = ampCross * dampFac;
00491 }
00492
00493
00494 n = 2.0*(inputLength + mergerLength + endMerger );
00495 ampPlus = waveform->a->data->data[n];
00496 n = 2.0*(inputLength + mergerLength + endMerger ) + 1.0;
00497 ampCross = waveform->a->data->data[n];
00498
00499 cosiotaA = ampPlus / ampCross *
00500 (1.0 + sqrt(1-ampCross*ampCross/ampPlus/ampPlus));
00501 cosiotaB = ampPlus / ampCross *
00502 (1.0 - sqrt(1-ampCross*ampCross/ampPlus/ampPlus));
00503
00504 if ( cosiotaA > -1.0 && cosiotaA < 1.0)
00505 cosiota = cosiotaA;
00506 else if ( cosiotaB > -1.0 && cosiotaB < 1.0)
00507 cosiota = cosiotaB;
00508 else
00509 {
00510 XLALPrintError("inclination angle out of range\n");
00511 XLALFree( waveform->a );
00512 XLALFree( waveform->phi );
00513 XLALFree( waveform->f );
00514 XLALFree( waveform->shift );
00515 XLAL_ERROR_NULL(func,XLAL_EFAILED);
00516 }
00517
00518
00519 ringInj->inclination = acos( cosiota );
00520 amp = ampPlus / ( 1.0 + cosiota * cosiota );
00521 ringInj->amplitude = sqrt( amp*amp);
00522
00523
00524 if ( injectSignalType == imr_ring_inject ||
00525 strstr(inspiralInj->waveform, "KludgeRingOnly") )
00526 {
00527 for ( n = 0; n < 2.0*(inputLength + mergerLength + endMerger ); n++ )
00528 {
00529 waveform->a->data->data[n]= 0;
00530 }
00531 }
00532 ringInj = XLALDeriveRingdownParameters(ringInj);
00533
00534 return( waveform );
00535 }
00536
00537 static SimRingdownTable*
00538 XLALDeriveRingdownParameters(
00539 SimRingdownTable *ringInj
00540 )
00541 {
00542 static const char *func = "XLALDeriveRingdownParameters";
00543 REAL4 cosiota;
00544 double splus, scross, fplus, fcross;
00545 double tDelay, tStart;
00546
00547 LALDetector lho = lalCachedDetectors[LALDetectorIndexLHODIFF];
00548 LALDetector llo = lalCachedDetectors[LALDetectorIndexLLODIFF];
00549
00550
00551 XLALPrintInfo( "Calculating (approximate) parameters for the ringdown\n" );
00552
00553
00554 memcpy( ringInj->waveform, "Ringdown",
00555 LIGOMETA_WAVEFORM_MAX * sizeof(CHAR));
00556 LALSnprintf( ringInj->coordinates, LIGOMETA_COORDINATES_MAX * sizeof(CHAR),
00557 "EQUATORIAL");
00558
00559
00560 ringInj->hrss = ringInj->amplitude * sqrt( 2 / LAL_PI / ringInj->frequency ) *
00561 pow( ( 2.0 * pow( ringInj->quality, 3.0 ) + ringInj->quality ) /
00562 ( 1.0 + 4.0 * pow ( ringInj->quality, 2 ) ) , 0.5);
00563
00564 XLALPrintInfo( "Ringdown h_rss = %.2g\n", ringInj->hrss);
00565
00566
00567 ringInj->epsilon = XLALBlackHoleRingEpsilon( ringInj->frequency,
00568 ringInj->quality, ringInj->distance, ringInj->amplitude );
00569 XLALPrintInfo( "Ringdown epsilon = %.2g\n", ringInj->epsilon);
00570
00571
00572 tStart = XLALGPSGetREAL8(&(ringInj->geocent_start_time) );
00573 ringInj->start_time_gmst = XLALGreenwichSiderealTime(
00574 &(ringInj->geocent_start_time), 0.0 );
00575
00576
00577 tDelay = XLALTimeDelayFromEarthCenter( lho.location, ringInj->longitude,
00578 ringInj->latitude, &(ringInj->geocent_start_time) );
00579 XLALGPSSetREAL8( &(ringInj->h_start_time), tDelay + tStart );
00580
00581 tDelay = XLALTimeDelayFromEarthCenter( llo.location, ringInj->longitude,
00582 ringInj->latitude, &(ringInj->geocent_start_time) );
00583 XLALGPSSetREAL8( &(ringInj->l_start_time), tDelay + tStart );
00584
00585 XLALPrintInfo( "Site start times:\n"
00586 "LHO: %d.%d GPS seconds\n"
00587 "LLO: %d.%d GPS seconds\n",
00588 ringInj->h_start_time.gpsSeconds, ringInj->h_start_time.gpsNanoSeconds,
00589 ringInj->l_start_time.gpsSeconds, ringInj->l_start_time.gpsNanoSeconds);
00590
00591
00592 cosiota = cos(ringInj->inclination);
00593 splus = -( 1.0 + cosiota * cosiota );
00594 scross = -2.0 * cosiota;
00595
00596 XLALComputeDetAMResponse(&fplus, &fcross, lho.response, ringInj->latitude,
00597 ringInj->longitude, ringInj->polarization, ringInj->start_time_gmst);
00598 ringInj->eff_dist_h = 2.0 * ringInj->distance;
00599 ringInj->eff_dist_h /= sqrt( splus*splus*fplus*fplus +
00600 scross*scross*fcross*fcross );
00601 ringInj->hrss_h = ringInj->amplitude * pow ( (
00602 (2*pow(ringInj->quality,3)+ringInj->quality ) *
00603 splus*splus*fplus*fplus +
00604 2*pow(ringInj->quality,2) * splus*scross*fplus*fcross +
00605 2*pow(ringInj->quality,3) * scross*scross*fcross*fcross )
00606 / 2.0 / LAL_PI / ringInj->frequency /
00607 ( 1.0 + 4.0 * pow ( ringInj->quality, 2 ) ) , 0.5 );
00608 XLALPrintInfo( "LHO response: F+ = %f, Fx = %f\n", fplus, fcross);
00609
00610
00611
00612 XLALComputeDetAMResponse(&fplus, &fcross, llo.response, ringInj->longitude,
00613 ringInj->latitude, ringInj->polarization, ringInj->start_time_gmst);
00614 ringInj->eff_dist_l = 2.0 * ringInj->distance;
00615 ringInj->eff_dist_l /= sqrt( splus*splus*fplus*fplus +
00616 scross*scross*fcross*fcross );
00617 ringInj->hrss_l = ringInj->amplitude * pow ( (
00618 (2*pow(ringInj->quality,3)+ringInj->quality ) *
00619 splus*splus*fplus*fplus +
00620 2*pow(ringInj->quality,2) * splus*scross*fplus*fcross +
00621 2*pow(ringInj->quality,3) * scross*scross*fcross*fcross )
00622 / 2.0 / LAL_PI / ringInj->frequency /
00623 ( 1.0 + 4.0 * pow ( ringInj->quality, 2 ) ) , 0.5 );
00624
00625 XLALPrintInfo( "LLO response: F+ = %f, Fx = %f\n", fplus, fcross);
00626 XLALPrintInfo( "Site effective distances:\n"
00627 "LHO: %f Mpc\n"
00628 "LLO: %f Mpc\n",
00629 ringInj->eff_dist_h, ringInj->eff_dist_l);
00630
00631 XLALPrintInfo( "Site h_rss:\n"
00632 "LHO: %g\n"
00633 "LLO: %g\n",
00634 ringInj->hrss_l, ringInj->hrss_l);
00635 return( ringInj );
00636 }
00637