BlackHoleMode.c

Go to the documentation of this file.
00001 /*
00002 *  Copyright (C) 2007 Bernd Machenschalk, Jolien Creighton
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 #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  * NOTE: STRANGE CONVENTIONS ...
00054  *
00055  * Use sign of a to indicate branch: a > 0 means +ve omega branch.
00056  *                                   a < 0 means -ve omega branch.
00057  *
00058  */
00059 
00060 
00061 /* preprocessor macros */
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  * XLAL Routines
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 /* Note: A and omega are input and output.
00329  * On input, they are an initial guess for the solver */
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   /* if a is negative, use an identity to obtain eigenvalues from -m mode */
00337   if ( ( aIsNegative = mysignbit( a ) ) )
00338   {
00339     a = fabs(a);
00340     m = -m;
00341     /* now use identity to modify the guessed eigenvalue */
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     /* EINVAL */
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   /* if a was negative, apply the identity to restore this eigenvalue */
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; /* 1.0/sqrt(27.0) */
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   /* do the positive eigenvalues first */
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   /* now do the negative eigenvalues */
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   /* locate the value of a in the table that is closer to zero than
00487    * the requested value */
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   /* here is the guess */
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; /* 1.0/sqrt(27.0) */
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   /* step towards desired value of a */
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   /* we now have our guess */
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     /* EMAXIT */
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   /* params.a = fabs(params.a); */
00585   if ( XLALBlackHoleModeKerrAngularCoefficients(&alp, &bet, &gam, n, &params) < 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)); /* Eq. 19, first line */
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     if ( cabs2(term) < SMALL )
00602       break;
00603       */
00604     if ( cabs2(term) < 1e-4 )
00605       break;
00606     if ( XLALBlackHoleModeKerrAngularCoefficients(&alp, &bet, &gam, n, &params) < 0 )
00607       XLAL_ERROR( func, XLAL_EFUNC );
00608     /* Eq. 19, second line: */
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   /* gsl_integration_qags( &function, -1, 1, 0, LAL_REAL8_EPS, WORKSPACESIZE, work, &integral, &error ); */
00646   gsl_integration_qags( &function, -1, 1, 0, 1e-6, WORKSPACESIZE, work, &integral, &error );
00647   gsl_integration_workspace_free( work );
00648 
00649   /* get complex part so that spheroidal wave function is real at mu=0 */
00650   if ( XLALSpheroidalWaveFunction1( &swf, 0.0, params ) < 0 )
00651     XLAL_ERROR( func, XLAL_EFUNC );
00652   *norm = conj(cdivr(swf,cabs(swf)));
00653 
00654   /* sign convention: to agree with sw spherical harmonics */
00655   /* TODO: CHECKME */
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 /* Here a is in standard conventions, not Leaver's */
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; /* to convert from standard conventions to Leaver conventions */
00689   params->l = l;
00690   params->m = m;
00691   params->s = s;
00692   XLALBlackHoleModeEigenvaluesLeaver( &params->A, &params->omega, params->a, params->l, params->m, params->s );
00693   return 0;
00694 }
00695 
00696 /* Here a is in standarad conventions, not Leaver's */
00697 int XLALSpinWeightedSpheroidalHarmonic( COMPLEX16 *result, REAL8 mu, REAL8 a, int l, int m, int s )
00698 {
00699   struct tagBlackHoleMode params;
00700   XLALSetBlackHoleModeParams( &params, a, l, m, s );
00701   XLALSpheroidalWaveFunction( result, mu, &params );
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; /* cosine of inclinaion */
00719 
00720   mu = cos( inclinationRad );
00721   XLALSpheroidalWaveFunction( &swf_1, mu, mode );
00722   XLALSpheroidalWaveFunction( &swf_2, -mu, mode );
00723 
00724   /* change from Leaver's conventions to usual conventions */
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; /* cosine of inclinaion */
00755   REAL8 dt; /* time step in seconds */
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( &params, spinParam, l, m, s );
00773   XLALSpheroidalWaveFunction( &swf_1, mu, &params );
00774   XLALSpheroidalWaveFunction( &swf_2, -mu, &params );
00775 
00776   /* change from Leaver's conventions to usual conventions */
00777   omega = cmulr( params.omega, 0.5 );
00778 
00779   /* how many points in the waveform to compute */
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     /* warning: waveform will be truncated */
00786     ndat = plus->data->length;
00787   }
00788 
00789   /* compute complex amplitude and phase factors */
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   /* zero the data */
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 }

Generated on Sat Jul 19 03:13:56 2008 for LAL by  doxygen 1.5.2