00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <math.h>
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024
00025 #include <gsl/gsl_vector.h>
00026 #include <gsl/gsl_multiroots.h>
00027 #include <gsl/gsl_integration.h>
00028
00029 #include <lal/LALStdlib.h>
00030 #include <lal/LALConstants.h>
00031 #define LAL_USE_COMPLEX_SHORT_MACROS
00032 #include <lal/LALComplex.h>
00033 #include <lal/BlackHoleMode.h>
00034
00035 NRCSID (BLACKHOLEMODEC,"$Id: BlackHoleMode.c,v 1.7 2007/06/08 14:41:52 bema Exp $");
00036
00037
00038 static int mysignbit( REAL8 x )
00039 {
00040 if ( x == 0 )
00041 {
00042 REAL8 y = 0;
00043 if ( memcmp( &x, &y, sizeof(x) ) )
00044 return 1;
00045 return 0;
00046 }
00047 return x < 0.0;
00048 }
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 #define TINY LAL_REAL8_MIN
00063 #define EPS LAL_REAL4_EPS
00064 #define SMALL LAL_REAL4_EPS
00065 #define MAXITER 10000
00066 #define ctiny crect(TINY,0)
00067 #define RCmul(x,a) cmulr((a),(x))
00068
00069 enum { LAL_BLACK_HOLE_MODE_DATA_TABLE_SIZE = 10 };
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 static int XLALBlackHoleModeEigenSolveContinuedFraction(
00080 COMPLEX16 *result,
00081 int (*coef)(COMPLEX16 *, COMPLEX16 *, COMPLEX16 *, int n, void *),
00082 void *params
00083 )
00084 {
00085 static const char *func = "XLALBlackHoleModeEigenSolveContinuedFraction";
00086 int n = 0;
00087 COMPLEX16 a, b, alp, gam;
00088 COMPLEX16 C, D, Delta;
00089
00090 a = czero;
00091 coef( &alp, &b, &gam, n, params );
00092 a = cneg(cmul(a,gam));
00093 if ( cabs(b) < TINY )
00094 *result = ctiny;
00095 else
00096 *result = b;
00097 C = *result;
00098 D = czero;
00099
00100 while ( n++ < MAXITER )
00101 {
00102 COMPLEX16 prev = *result;
00103 a = alp;
00104 coef( &alp, &b, &gam, n, params );
00105 a = cneg(cmul(a,gam));
00106 C = cadd(b,cdiv(a,C));
00107 D = cadd(b,cmul(a,D));
00108 if (cabs(D) < TINY)
00109 D = ctiny;
00110 if (cabs(C) < TINY)
00111 C = ctiny;
00112 D = cinv(D);
00113 Delta = cmul(C,D);
00114 *result = cmul(*result,Delta);
00115 if (cabs(csub(*result,prev))<SMALL)
00116 return 0;
00117 }
00118 XLAL_ERROR( func, XLAL_EMAXITER );
00119 return -1;
00120 }
00121
00122
00123
00124 static int XLALBlackHoleModeSchwarzschildCoefficients( COMPLEX16 *alp, COMPLEX16 *bet, COMPLEX16 *gam, int n, void *params )
00125 {
00126 struct tagBlackHoleMode *p = params;
00127 int l, s;
00128 COMPLEX16 omega, rho, A;
00129
00130 s = p->s;
00131 l = p->l;
00132 omega = p->omega;
00133 A = crect(l*(l+1)-s*(s+1),0.0);
00134 rho = cneg(cmul(I,omega));
00135 *alp = cadd(RCmul(n,cadd(csetr(n),RCmul(2,cadd(cunit,rho)))),
00136 cadd(RCmul(2,rho),cunit));
00137 *bet = cneg(cadd(RCmul(2*n,cadd(csetr(n),cadd(RCmul(4,rho),cunit))),
00138 cadd(cmul(RCmul(4,rho),cadd(RCmul(2,rho),cunit)),cadd(A,csetr(1+s)))));
00139 *gam = cadd(RCmul(n,cadd(csetr(n),RCmul(4,rho))),
00140 cadd(RCmul(4,cmul(rho,rho)),csetr(-s*s)));
00141
00142 return 0;
00143 }
00144
00145 static int XLALBlackHoleModeKerrRadialCoefficients( COMPLEX16 *alp, COMPLEX16 *bet, COMPLEX16 *gam, int n, void *params )
00146 {
00147 struct tagBlackHoleMode *p = params;
00148 int m=p->m, s=p->s;
00149 REAL8 a=p->a;
00150 REAL8 b=sqrt(1-4*a*a);
00151 COMPLEX16 omega=p->omega, A=p->A;
00152 COMPLEX16 c0,c1,c2,c3,c4,cfact,rho,omega2;
00153
00154 rho = cneg(cmul(I,omega));
00155 omega2 = cmul(omega,omega);
00156
00157 cfact = RCmul(1/b,csub(omega,csetr(2*a*m)));
00158 c0 = cadd(csetr(1-s),cadd(rho,cneg(cmul(I,cfact))));
00159 c1 = cadd(csetr(-4),cadd(RCmul(-2*(2+b),rho),cmul(cseti(2),cfact)));
00160 c2 = cadd(csetr(s+3),cadd(RCmul(3,rho),cneg(cmul(I,cfact))));
00161 c3 = cadd(RCmul(4+2*b-a*a,omega2),
00162 cadd(RCmul(-2*m*a,omega),
00163 cadd(csetr(-s-1),
00164 cadd(RCmul(-2-b,rho),
00165 cadd(cneg(A),
00166 cmul(cadd(RCmul(2,omega),I),cfact))))));
00167 c4 = cadd(csetr(s+1),
00168 cadd(RCmul(-2,omega2),
00169 cadd(RCmul(2*s+3,rho),
00170 cneg(cmul(cadd(RCmul(2,omega),I),cfact)))));
00171 *alp = cadd(RCmul(n,cadd(csetr(n),cadd(c0,cunit))),c0);
00172 *bet = cadd(RCmul(n,cadd(csetr(-2*n),cadd(c1,csetr(2)))),c3);
00173 *gam = cadd(RCmul(n,cadd(csetr(n),cadd(c2,csetr(-3)))),
00174 cadd(c4,cadd(cneg(c2),csetr(2))));
00175 return 0;
00176 }
00177
00178 static int XLALBlackHoleModeKerrAngularCoefficients( COMPLEX16 *alp, COMPLEX16 *bet, COMPLEX16 *gam, int n, void *params )
00179 {
00180 struct tagBlackHoleMode *p = params;
00181 int m=p->m, s=p->s;
00182 REAL8 a=p->a;
00183 COMPLEX16 omega=p->omega, A=p->A;
00184 COMPLEX16 w;
00185 REAL8 k1=0.5*abs(m-s),k2=0.5*abs(m+s);
00186
00187 w = RCmul(a,omega);
00188 *alp = csetr(-2*(n+1)*(n+2*k1+1));
00189 *bet = cadd(csetr(n*(n+2*k1+2*k2+1)+(k1+k2)*(k1+k2+1)-s*(s+1)),
00190 cadd(RCmul(-2*(2*n+2*k1+s+1),w),
00191 cadd(cneg(cmul(w,w)),cneg(A))));
00192 *gam = RCmul(2*(n+k1+k2+s),w);
00193 return 0;
00194 }
00195
00196 static int XLALBlackHoleModeEigenSolveSchwarzschildResid( const gsl_vector *x, void *params, gsl_vector *f )
00197 {
00198 COMPLEX16 cf;
00199 struct tagBlackHoleMode *p = params;
00200 creal(p->omega) = gsl_vector_get(x,0);
00201 cimag(p->omega) = gsl_vector_get(x,1);
00202
00203 XLALBlackHoleModeEigenSolveContinuedFraction( &cf, XLALBlackHoleModeSchwarzschildCoefficients, p );
00204
00205 gsl_vector_set(f, 0, creal(cf));
00206 gsl_vector_set(f, 1, cimag(cf));
00207 return 0;
00208 }
00209
00210 static int XLALBlackHoleModeEigenSolveKerrResid( const gsl_vector *x, void *params, gsl_vector *f )
00211 {
00212 COMPLEX16 cf1, cf2;
00213 struct tagBlackHoleMode *p = params;
00214 creal(p->A) = gsl_vector_get(x,0);
00215 cimag(p->A) = gsl_vector_get(x,1);
00216 creal(p->omega) = gsl_vector_get(x,2);
00217 cimag(p->omega) = gsl_vector_get(x,3);
00218
00219 XLALBlackHoleModeEigenSolveContinuedFraction( &cf1, XLALBlackHoleModeKerrRadialCoefficients, p );
00220 XLALBlackHoleModeEigenSolveContinuedFraction( &cf2, XLALBlackHoleModeKerrAngularCoefficients, p );
00221
00222 gsl_vector_set(f, 0, creal(cf1));
00223 gsl_vector_set(f, 1, cimag(cf1));
00224 gsl_vector_set(f, 2, creal(cf2));
00225 gsl_vector_set(f, 3, cimag(cf2));
00226 return 0;
00227 }
00228
00229
00230 static int XLALBlackHoleModeEigenSolveSchwarzschild( COMPLEX16 *omega, int l, int m, int s )
00231 {
00232 static const char *func = "XLALBlackHoleModeEigenSolveSchwarzschild";
00233 enum { ndim = 2 };
00234 struct tagBlackHoleMode p;
00235 const gsl_multiroot_fsolver_type *solverType;
00236 gsl_multiroot_fsolver *solver;
00237 gsl_multiroot_function f;
00238 gsl_vector *x;
00239 size_t iter = 0;
00240 int status;
00241
00242 f.f = &XLALBlackHoleModeEigenSolveSchwarzschildResid;
00243 f.n = ndim;
00244 f.params = &p;
00245 x = gsl_vector_alloc( ndim );
00246 gsl_vector_set( x, 0, omega->re );
00247 gsl_vector_set( x, 1, omega->im );
00248 p.a = 0.0;
00249 p.l = l;
00250 p.m = m;
00251 p.s = s;
00252
00253 solverType = gsl_multiroot_fsolver_hybrids;
00254 solver = gsl_multiroot_fsolver_alloc( solverType, ndim );
00255 gsl_multiroot_fsolver_set(solver, &f, x);
00256
00257 do
00258 {
00259 ++iter;
00260 status = gsl_multiroot_fsolver_iterate( solver );
00261 if ( status )
00262 break;
00263 status = gsl_multiroot_test_residual(solver->f, EPS);
00264 }
00265 while ( status == GSL_CONTINUE && iter < MAXITER );
00266 if ( iter >= MAXITER )
00267 XLAL_ERROR( func, XLAL_EMAXITER );
00268
00269 omega->re = gsl_vector_get(solver->x, 0);
00270 omega->im = gsl_vector_get(solver->x, 1);
00271
00272 gsl_multiroot_fsolver_free(solver);
00273 gsl_vector_free(x);
00274 return 0;
00275 }
00276
00277 static int XLALBlackHoleModeEigenSolveKerr( COMPLEX16 *A, COMPLEX16 *omega, REAL8 a, int l, int m, int s )
00278 {
00279 static const char *func = "XLALBlackHoleModeEigenSolveKerr";
00280 enum { ndim = 4 };
00281 struct tagBlackHoleMode p;
00282 const gsl_multiroot_fsolver_type *solverType;
00283 gsl_multiroot_fsolver *solver;
00284 gsl_multiroot_function f;
00285 gsl_vector *x;
00286 size_t iter = 0;
00287 int status;
00288
00289 f.f = &XLALBlackHoleModeEigenSolveKerrResid;
00290 f.n = ndim;
00291 f.params = &p;
00292 x = gsl_vector_alloc( ndim );
00293 gsl_vector_set( x, 0, A->re );
00294 gsl_vector_set( x, 1, A->im );
00295 gsl_vector_set( x, 2, omega->re );
00296 gsl_vector_set( x, 3, omega->im );
00297 p.a = a;
00298 p.l = l;
00299 p.m = m;
00300 p.s = s;
00301
00302 solverType = gsl_multiroot_fsolver_hybrids;
00303 solver = gsl_multiroot_fsolver_alloc( solverType, ndim );
00304 gsl_multiroot_fsolver_set(solver, &f, x);
00305
00306 do
00307 {
00308 ++iter;
00309 status = gsl_multiroot_fsolver_iterate( solver );
00310 if ( status )
00311 break;
00312 status = gsl_multiroot_test_residual(solver->f, EPS);
00313 }
00314 while ( status == GSL_CONTINUE && iter < MAXITER );
00315 if ( iter >= MAXITER )
00316 XLAL_ERROR( func, XLAL_EMAXITER );
00317
00318 A->re = gsl_vector_get(solver->x, 0);
00319 A->im = gsl_vector_get(solver->x, 1);
00320 omega->re = gsl_vector_get(solver->x, 2);
00321 omega->im = gsl_vector_get(solver->x, 3);
00322
00323 gsl_multiroot_fsolver_free(solver);
00324 gsl_vector_free(x);
00325 return 0;
00326 }
00327
00328
00329
00330 static int XLALBlackHoleModeEigenSolve( COMPLEX16 *A, COMPLEX16 *omega, REAL8 a, int l, int m, int s )
00331 {
00332 static const char *func = "XLALBlackHoleModeEigenSolve";
00333 int aIsNegative;
00334 int status;
00335
00336
00337 if ( ( aIsNegative = mysignbit( a ) ) )
00338 {
00339 a = fabs(a);
00340 m = -m;
00341
00342 A->im = -A->im;
00343 omega->re = -omega->re;
00344 }
00345
00346 if ( a >= 0.5 || l < 0 || abs(m) > l || s > 0 || s < -2 )
00347
00348 return -1;
00349
00350 if ( a == 0 )
00351 status = XLALBlackHoleModeEigenSolveSchwarzschild( omega, l, m, s );
00352 else
00353 status = XLALBlackHoleModeEigenSolveKerr( A, omega, a, l, m, s );
00354
00355 if ( status < 0 )
00356 XLAL_ERROR( func, XLAL_EFUNC );
00357
00358
00359 if ( aIsNegative )
00360 {
00361 A->im = -A->im;
00362 omega->re = -omega->re;
00363 }
00364
00365 return 0;
00366 }
00367
00368
00369 void XLALDestroyBlackHoleModeTable( BlackHoleModeTable *mode )
00370 {
00371 if ( mode )
00372 {
00373 LALFree( mode->positiveEigenTable );
00374 LALFree( mode->negativeEigenTable );
00375 LALFree( mode );
00376 }
00377 return;
00378 }
00379
00380 static int XLALBlackHoleModeMakeEigenTable( BlackHoleModeTable *mode )
00381 {
00382 static const char *func = "XLALBlackHoleModeMakeEigenTable";
00383 const REAL8 fact = 0.19245008972987525483;
00384 size_t nobj = LAL_BLACK_HOLE_MODE_DATA_TABLE_SIZE;
00385 int l,m,s;
00386 REAL8 a;
00387 COMPLEX16 A;
00388 COMPLEX16 omega;
00389 size_t i;
00390
00391 if ( mode->positiveEigenTable || mode->negativeEigenTable )
00392 XLAL_ERROR( func, XLAL_EINVAL );
00393
00394 mode->eigenTableSize = nobj;
00395 mode->positiveEigenTable = LALCalloc(nobj, sizeof(*mode->positiveEigenTable));
00396 mode->negativeEigenTable = LALCalloc(nobj, sizeof(*mode->negativeEigenTable));
00397 if ( ! mode->positiveEigenTable || ! mode->negativeEigenTable )
00398 XLAL_ERROR( func, XLAL_ENOMEM );
00399
00400 l = mode->l;
00401 m = mode->m;
00402 s = mode->s;
00403
00404
00405 A = crect(l*(l+1) - s*(s+1),0);
00406 omega = RCmul(fact,crect(2*l+1,-1));
00407 a = 0;
00408 for ( i = 0; i < nobj; ++i )
00409 {
00410 struct tagBlackHoleModeEigenvalues *eigen = mode->positiveEigenTable + i;
00411 a = 0.5 * tanh(0.5*i);
00412 if ( XLALBlackHoleModeEigenSolve( &A, &omega, a, l, m, s ) < 0 )
00413 {
00414 XLALDestroyBlackHoleModeTable( mode );
00415 XLAL_ERROR( func, XLAL_EFUNC );
00416 }
00417 eigen->a = a;
00418 eigen->A = A;
00419 eigen->omega = omega;
00420 a += 0.1 * (0.5 - a);
00421 }
00422
00423
00424 A = crect(l*(l+1) - s*(s+1),0);
00425 omega = RCmul(fact,crect(-2*l+1,-1));
00426 a = 0;
00427 for ( i = 0; i < nobj; ++i )
00428 {
00429 struct tagBlackHoleModeEigenvalues *eigen = mode->negativeEigenTable + i;
00430 a = 0.5 * tanh(0.5*i);
00431 if ( XLALBlackHoleModeEigenSolve( &A, &omega, -a, l, m, s ) < 0 )
00432 {
00433 XLALDestroyBlackHoleModeTable( mode );
00434 XLAL_ERROR( func, XLAL_EFUNC );
00435 }
00436 eigen->a = -a;
00437 eigen->A = A;
00438 eigen->omega = omega;
00439 a += 0.1 * (0.5 - a);
00440 }
00441
00442 return 0;
00443 }
00444
00445
00446 BlackHoleModeTable * XLALCreateBlackHoleModeTable( int l, int m, int s )
00447 {
00448 static const char *func = "XLALCreateBlackHoleModeTable";
00449 BlackHoleModeTable *mode;
00450
00451 if ( l < 0 || abs(m) > l || s > 0 || s < -2 )
00452 XLAL_ERROR_NULL( func, XLAL_EINVAL );
00453
00454 mode = LALCalloc( 1, sizeof( *mode ) );
00455 if ( ! mode )
00456 XLAL_ERROR_NULL( func, XLAL_ENOMEM );
00457
00458 mode->l = l;
00459 mode->m = m;
00460 mode->s = s;
00461
00462 if ( XLALBlackHoleModeMakeEigenTable( mode ) < 0 )
00463 {
00464 XLALDestroyBlackHoleModeTable( mode );
00465 XLAL_ERROR_NULL( func, XLAL_EFUNC );
00466 }
00467
00468 return mode;
00469 }
00470
00471
00472 int XLALBlackHoleModeEigenvaluesLeaverT( COMPLEX16 *A, COMPLEX16 *omega, REAL8 a, BlackHoleModeTable *mode )
00473 {
00474 static const char *func = "XLALBlackHoleModeEigenvaluesLeaverT";
00475 struct tagBlackHoleModeEigenvalues *eigen;
00476 int l, m, s;
00477 size_t i;
00478
00479 if ( ! (fabs(a) < 0.5) )
00480 XLAL_ERROR( func, XLAL_EINVAL );
00481
00482 l = mode->l;
00483 m = mode->m;
00484 s = mode->s;
00485
00486
00487
00488 eigen = mysignbit(a) ? mode->negativeEigenTable : mode->positiveEigenTable;
00489 for ( i = 1; i < mode->eigenTableSize; ++i )
00490 if ( fabs( a ) < fabs( eigen[i].a ) )
00491 break;
00492
00493
00494 *A = eigen[i-1].A;
00495 *omega = eigen[i-1].omega;
00496
00497 if ( XLALBlackHoleModeEigenSolve( A, omega, a, l, m, s ) < 0 )
00498 XLAL_ERROR( func, XLAL_EFUNC );
00499
00500 return 0;
00501 }
00502
00503
00504 int XLALBlackHoleModeEigenvaluesLeaver( COMPLEX16 *A, COMPLEX16 *omega, REAL8 a, int l, int m, int s )
00505 {
00506 static const char *func = "XLALBlackHoleModeEigenvaluesLeaver";
00507 const REAL8 fact = 0.19245008972987525483;
00508 size_t nobj = LAL_BLACK_HOLE_MODE_DATA_TABLE_SIZE;
00509 size_t i;
00510 int sign;
00511
00512 if ( ! (fabs(a) < 0.5) )
00513 XLAL_ERROR( func, XLAL_EINVAL );
00514 sign = mysignbit(a) ? -1 : 1;
00515
00516
00517 *A = crect(l*(l+1) - s*(s+1),0);
00518 *omega = RCmul(fact,crect(sign*2*l+1,-1));
00519 for ( i = 0; i < nobj; ++i )
00520 {
00521 REAL8 atry = sign * 0.5 * tanh(0.5*i);
00522 if ( fabs(atry) > fabs(a) )
00523 break;
00524 if ( XLALBlackHoleModeEigenSolve( A, omega, atry, l, m, s ) < 0 )
00525 XLAL_ERROR( func, XLAL_EFUNC );
00526 }
00527
00528
00529
00530 if ( XLALBlackHoleModeEigenSolve( A, omega, a, l, m, s ) < 0 )
00531 XLAL_ERROR( func, XLAL_EFUNC );
00532
00533 return 0;
00534 }
00535
00536
00537 int XLALSpheroidalWaveFunction1( COMPLEX16 *result, REAL8 mu, struct tagBlackHoleMode *mode )
00538 {
00539 #if 0
00540 int s = mode->s, m = mode->m;
00541 REAL8 k1 = 0.5*abs(m - s), k2 = 0.5*abs(m + s);
00542 REAL8 fact = 1 + mu;
00543 REAL8 prod = fact;
00544 COMPLEX16 alp, bet, gam;
00545 COMPLEX16 sum, a, a_;
00546 size_t n = 0;
00547
00548 sum = a_ = cunit;
00549 XLALBlackHoleModeKerrAngularCoefficients(&alp, &bet, &gam, n, mode);
00550 a = cdiv(cmul(bet,a_),cneg(alp));
00551 while ( n++ < MAXITER )
00552 {
00553 COMPLEX16 aa, delta;
00554 delta = cmulr(a,prod);
00555 sum = cadd(sum,delta);
00556 if ( cabs2(delta) < SMALL )
00557 break;
00558 XLALBlackHoleModeKerrAngularCoefficients(&alp, &bet, &gam, n, mode);
00559 aa = a;
00560 a = cdiv(cadd(cmul(bet,a),cmul(gam,a_)),cneg(alp));
00561 a_ = aa;
00562 prod *= fact;
00563 }
00564 if ( n >= MAXITER)
00565
00566 abort();
00567
00568 *result = cmulr(sum,pow(1+mu,k1)*pow(1-mu,k2));
00569 *result = cmul(*result,cexp(cmulr(mode->omega,mu*mode->a)));
00570 return 0;
00571
00572 #else
00573 static const char *func = "XLALSpheroidalWaveFunction1";
00574 struct tagBlackHoleMode params;
00575 int s=mode->s, m=mode->m;
00576 REAL8 k1=0.5*abs(m-s), k2=0.5*abs(m+s);
00577 REAL8 prod, fact=1+mu;
00578 COMPLEX16 sum, term;
00579 COMPLEX16 aprev, a, anext;
00580 COMPLEX16 alp, bet, gam;
00581 size_t n = 0;
00582
00583 params = *mode;
00584
00585 if ( XLALBlackHoleModeKerrAngularCoefficients(&alp, &bet, &gam, n, ¶ms) < 0 )
00586 XLAL_ERROR( func, XLAL_EFUNC );
00587
00588 prod = 1;
00589 sum = cunit;
00590 a = cunit;
00591 anext = cneg(cdiv(cmul(bet,a),alp));
00592
00593 while ( n++ < MAXITER )
00594 {
00595 aprev = a;
00596 a = anext;
00597 prod *= fact;
00598 term = cmulr(a,prod);
00599 sum = cadd(sum,term);
00600
00601
00602
00603
00604 if ( cabs2(term) < 1e-4 )
00605 break;
00606 if ( XLALBlackHoleModeKerrAngularCoefficients(&alp, &bet, &gam, n, ¶ms) < 0 )
00607 XLAL_ERROR( func, XLAL_EFUNC );
00608
00609 anext = cneg(cdiv(cadd(cmul(bet,a),cmul(gam,aprev)),alp));
00610 }
00611 if ( n >= MAXITER)
00612 XLAL_ERROR( func, XLAL_EMAXITER );
00613
00614 *result = cmulr(sum,pow(1+mu,k1)*pow(1-mu,k2));
00615 *result = cmul(*result,cexp(cmulr(mode->omega,mu*mode->a)));
00616 return 0;
00617 #endif
00618 }
00619
00620
00621 static REAL8 XLALSpheroidalWaveFunction1Abs2( REAL8 mu, void *params )
00622 {
00623 static const char *func = "XLALSpheroidalWaveFunction1Abs2";
00624 COMPLEX16 swf;
00625 REAL8 result;
00626 if ( XLALSpheroidalWaveFunction1( &swf, mu, params ) )
00627 XLAL_ERROR_REAL8( func, XLAL_EFUNC );
00628 result = cabs2(swf);
00629 return result;
00630 }
00631
00632 int XLALSpheroidalWaveFunctionNorm( COMPLEX16 *norm, struct tagBlackHoleMode *params )
00633 {
00634 static const char *func = "XLALSpheroidalWaveFunctionNorm";
00635 enum { WORKSPACESIZE = 1000 };
00636 gsl_integration_workspace *work;
00637 gsl_function function;
00638 REAL8 integral, error;
00639 COMPLEX16 swf;
00640 int signneg;
00641
00642 work = gsl_integration_workspace_alloc( WORKSPACESIZE );
00643 function.function = XLALSpheroidalWaveFunction1Abs2;
00644 function.params = params;
00645
00646 gsl_integration_qags( &function, -1, 1, 0, 1e-6, WORKSPACESIZE, work, &integral, &error );
00647 gsl_integration_workspace_free( work );
00648
00649
00650 if ( XLALSpheroidalWaveFunction1( &swf, 0.0, params ) < 0 )
00651 XLAL_ERROR( func, XLAL_EFUNC );
00652 *norm = conj(cdivr(swf,cabs(swf)));
00653
00654
00655
00656
00657 if ( XLALSpheroidalWaveFunction1( &swf, -1.0, params ) < 0 )
00658 XLAL_ERROR( func, XLAL_EFUNC );
00659 swf = cmul(swf,*norm);
00660 signneg = ( params->l - ( params->m > params->s ? params->m : params->s ) ) % 2 ? 0 : 1;
00661 if ( signneg && creal(swf) > 0 || ! signneg && creal(swf) < 0 )
00662 *norm = cneg(*norm);
00663
00664 *norm = cdivr(*norm,sqrt(integral));
00665
00666 return 0;
00667 }
00668
00669 int XLALSpheroidalWaveFunction( COMPLEX16 *result, REAL8 mu, struct tagBlackHoleMode *params )
00670 {
00671 static const char *func = "XLALSpheroidalWaveFunction";
00672 COMPLEX16 norm;
00673 if ( XLALSpheroidalWaveFunctionNorm( &norm, params ) < 0 )
00674 XLAL_ERROR( func, XLAL_EFUNC );
00675 if ( XLALSpheroidalWaveFunction1( result, mu, params ) < 0 )
00676 XLAL_ERROR( func, XLAL_EFUNC );
00677 *result = cmul( *result, norm );
00678 return 0;
00679 }
00680
00681
00682
00683 int XLALSetBlackHoleModeParams( struct tagBlackHoleMode *params, REAL8 a, int l, int m, int s )
00684 {
00685 static const char *func = "XLALSetBlackHoleModeParams";
00686 if ( l < 0 || abs(m) > l || s > 0 || s < -2 )
00687 XLAL_ERROR( func, XLAL_EINVAL );
00688 params->a = 0.5 * a;
00689 params->l = l;
00690 params->m = m;
00691 params->s = s;
00692 XLALBlackHoleModeEigenvaluesLeaver( ¶ms->A, ¶ms->omega, params->a, params->l, params->m, params->s );
00693 return 0;
00694 }
00695
00696
00697 int XLALSpinWeightedSpheroidalHarmonic( COMPLEX16 *result, REAL8 mu, REAL8 a, int l, int m, int s )
00698 {
00699 struct tagBlackHoleMode params;
00700 XLALSetBlackHoleModeParams( ¶ms, a, l, m, s );
00701 XLALSpheroidalWaveFunction( result, mu, ¶ms );
00702 return 0;
00703 }
00704
00705 int XLALBlackHoleRingdownAmplitude(
00706 COMPLEX16 *amplitudePlus,
00707 COMPLEX16 *amplitudeCross,
00708 REAL8 massSolar,
00709 REAL8 fracMassLoss,
00710 REAL8 distanceMpc,
00711 REAL8 inclinationRad,
00712 REAL8 azimuthRad,
00713 BlackHoleMode *mode
00714 )
00715 {
00716 COMPLEX16 swf_1, swf_2;
00717 COMPLEX16 omega, amp;
00718 REAL8 mu;
00719
00720 mu = cos( inclinationRad );
00721 XLALSpheroidalWaveFunction( &swf_1, mu, mode );
00722 XLALSpheroidalWaveFunction( &swf_2, -mu, mode );
00723
00724
00725 omega = cmulr( mode->omega, 0.5 );
00726
00727 amp = cexp(cmulr(I, mode->m*azimuthRad));
00728 amp = cmulr( amp, -4.0*massSolar*sqrt(-1.0*cimag(omega)*0.5*fracMassLoss/cabs2(omega)));
00729 amp = cmulr( amp, LAL_MRSUN_SI/(distanceMpc*1e6*LAL_PC_SI));
00730
00731 *amplitudePlus = cmul(cadd(swf_1,swf_2),amp);
00732 *amplitudeCross = cmul(cmul(I,csub(swf_1,swf_2)),amp);
00733
00734 return 0;
00735 }
00736
00737 int XLALBlackHoleRingdownWaveform(
00738 REAL4TimeSeries *plus,
00739 REAL4TimeSeries *cross,
00740 REAL8 massSolar,
00741 REAL8 spinParam,
00742 REAL8 fracMassLoss,
00743 REAL8 distanceMpc,
00744 REAL8 inclinationRad,
00745 REAL8 azimuthRad,
00746 int l,
00747 int m
00748 )
00749 {
00750 static const char *func = "XLALBlackHoleRingdownWaveform";
00751 const int s = -2;
00752 struct tagBlackHoleMode params;
00753 COMPLEX16 swf_1, swf_2, omega;
00754 REAL8 mu;
00755 REAL8 dt;
00756 COMPLEX16 amplitude_1, I_omega_dt_1;
00757 COMPLEX16 amplitude_2, I_omega_dt_2;
00758 INT4 ndat;
00759 INT4 i;
00760
00761 if ( ! plus || ! cross )
00762 XLAL_ERROR( func, XLAL_EFAULT );
00763 if ( plus->deltaT != cross->deltaT )
00764 XLAL_ERROR( func, XLAL_EINVAL );
00765 if ( ! plus->data || ! cross->data
00766 || plus->data->length != cross->data->length )
00767 XLAL_ERROR( func, XLAL_EINVAL );
00768
00769 mu = cos( inclinationRad );
00770 dt = plus->deltaT;
00771
00772 XLALSetBlackHoleModeParams( ¶ms, spinParam, l, m, s );
00773 XLALSpheroidalWaveFunction( &swf_1, mu, ¶ms );
00774 XLALSpheroidalWaveFunction( &swf_2, -mu, ¶ms );
00775
00776
00777 omega = cmulr( params.omega, 0.5 );
00778
00779
00780 ndat = ceil( log( LAL_REAL4_EPS ) * massSolar * LAL_MTSUN_SI / ( cimag(omega) * dt ) );
00781 if ( ndat < 1 )
00782 XLAL_ERROR( func, XLAL_EBADLEN );
00783 if ( ndat > (INT4)plus->data->length )
00784 {
00785
00786 ndat = plus->data->length;
00787 }
00788
00789
00790 amplitude_1 = cmul(swf_1, cexp(cmulr(I, m*azimuthRad)));
00791 amplitude_1 = cmulr(amplitude_1, -4.0*massSolar*sqrt(-1.0*cimag(omega)*0.5*fracMassLoss/cabs2(omega)));
00792 amplitude_1 = cmulr(amplitude_1, LAL_MRSUN_SI/(distanceMpc*1e6*LAL_PC_SI));
00793 I_omega_dt_1 = cmulr(cmul(I,omega),-1.0*dt/(massSolar*LAL_MTSUN_SI));
00794
00795 amplitude_2 = conj(cmul(swf_2, cexp(cmulr(I, m*azimuthRad))));
00796 amplitude_2 = cmulr(amplitude_2, -4.0*massSolar*sqrt(-1.0*cimag(omega)*0.5*fracMassLoss/cabs2(omega)));
00797 amplitude_2 = cmulr(amplitude_2, LAL_MRSUN_SI/(distanceMpc*1e6*LAL_PC_SI));
00798 I_omega_dt_2 = cmulr(cmul(I,conj(omega)),dt/(massSolar*LAL_MTSUN_SI));
00799
00800
00801 memset( plus->data->data, 0, plus->data->length * sizeof( *plus->data->data ) );
00802 memset( cross->data->data, 0, cross->data->length * sizeof( *cross->data->data ) );
00803
00804 for ( i = 0; i < ndat; ++i )
00805 {
00806 COMPLEX16 strain_1, strain_2, strain;
00807 strain_1 = cmul( amplitude_1, cexp( cmulr( I_omega_dt_1, i ) ) );
00808 strain_2 = cmul( amplitude_2, cexp( cmulr( I_omega_dt_2, i ) ) );
00809 strain = cadd( strain_1, strain_2 );
00810 plus->data->data[i] = creal( strain );
00811 cross->data->data[i] = -1.0 * cimag( strain );
00812 }
00813
00814 return ndat;
00815 }