Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import numpy as np 

2 

3 

4def Get_Waveform(source, pct_of_peak=0.01): 

5 """Uses Mass Ratio (q <= 18), aligned spins (abs(a/m)~0.85 or when q=1 abs(a/m)<0.98), 

6 fitting coefficients for QNM type, and sampling rate 

7 Returns the frequency, the Phenom amplitude of the inspiral-merger-ringdown 

8 Uses methods found in <https://arxiv.org/abs/1508.07253> and <https://arxiv.org/abs/1508.07250> 

9 

10 Parameters 

11 ---------- 

12 source : object 

13 source object from StrainandNoise, contains all source parameters 

14 pct_of_peak : float, optional 

15 the percentange of the strain at merger that dictates the maximum frequency the waveform is calculated at in geometrized units (G=c=1) 

16 

17 Returns 

18 ------- 

19 Mf : numpy array of floats 

20 the waveform frequencies in geometrized units (G=c=1) 

21 fullwaveform : numpy array of floats 

22 the waveform strain in geometrized units (G=c=1) 

23 

24 """ 

25 f_low = source.f_low 

26 N = source.nfreqs 

27 q = source.q 

28 x1 = source.chi1 

29 x2 = source.chi2 

30 fitcoeffs = source._fitcoeffs 

31 

32 # M = m1+m2 #Total Mass 

33 # q = m2/m1 #Mass Ratio: Paper tested up to 18 

34 # eta = m1*m2/M**2 reduced mass: Paper tested up to 0.05 (q=18) 

35 eta = q / (q + 1) ** 2 

36 x_PN = chi_PN(eta, x1, x2) # PN reduced spin parameter 

37 a_f = a_final(x1, x2, q, eta) # dimensionless spin 

38 

39 ################## 

40 # Finds f_ringdown and f_damp from fit taken from <https://arxiv.org/abs/gr-qc/0512160> 

41 n = 0 # QNM indices 

42 l = 2 

43 m = 2 

44 numn = 3 # number of n's included in the table 

45 

46 index = (l - 2) * (2 * l + 1) * numn + (l - m) * numn + n 

47 f_fit = fitcoeffs[index][3:6] 

48 q_fit = fitcoeffs[index][6:9] 

49 

50 omega_RD = f_fit[0] + f_fit[1] * (1 - a_f) ** f_fit[2] # M omega_{lmn} 

51 tau = ( 

52 2 * (q_fit[0] + q_fit[1] * (1 - a_f) ** q_fit[2]) / omega_RD 

53 ) # tau_{lmn}/M = 2 Q_{lmn}/(M omega_{lmn}) 

54 ######################## 

55 f_RD = omega_RD / 2 / np.pi 

56 f_damp = 1 / tau / 2 / np.pi 

57 

58 Gamma1 = Lambda(eta, x_PN, 4) 

59 Gamma2 = Lambda(eta, x_PN, 5) 

60 Gamma3 = Lambda(eta, x_PN, 6) 

61 

62 f_peak = Calc_f_peak(f_RD, f_damp, [Gamma1, Gamma2, Gamma3]) 

63 

64 f1 = 0.014 

65 f3 = f_peak 

66 f2 = (f1 + f3) / 2 

67 

68 cutoffFreq = Find_Cutoff_Freq( 

69 f_RD, f_damp, [Gamma1, Gamma2, Gamma3], pct_of_peak=pct_of_peak 

70 ) 

71 

72 # If lowest frequency is greater than cutoffFreq, then raise error. 

73 if f_low >= cutoffFreq: 

74 raise ValueError( 

75 "Lower frequency bound (ie. f_low) must be lower than that of the merger ringdown." 

76 ) 

77 

78 Mf = np.logspace(np.log10(f_low), np.log10(cutoffFreq), N) 

79 

80 v1 = A_insp(f1, eta, x1, x2, x_PN) 

81 v2 = Lambda(eta, x_PN, 3) 

82 v3 = A_MR(f3, f_RD, f_damp, [Gamma1, Gamma2, Gamma3]) 

83 fund1 = DA_insp(f1, eta, x1, x2, x_PN) 

84 fund3 = DA_MR(f3, f_RD, f_damp, [Gamma1, Gamma2, Gamma3]) 

85 

86 ############################# 

87 # Calculate Solutions to eqn 21 in intermediate region 

88 Del_solns = A_intermediate( 

89 f1, f2, f3, v1, v2, v3, fund1, fund3 

90 ) # Solutions to eqn 21 

91 

92 ############################## 

93 # Calculate all sections of waveform and Paste together 

94 indxf1 = np.argmin(np.abs(Mf - f1)) 

95 indxfpeak = np.argmin(np.abs(Mf - f_peak)) 

96 

97 tmpinspiral = A_norm(Mf[0 : indxf1 + 1], eta) * A_insp( 

98 Mf[0 : indxf1 + 1], eta, x1, x2, x_PN 

99 ) 

100 tmpintermediate = A_norm(Mf[indxf1 + 1 : indxfpeak], eta) * A_int( 

101 Mf[indxf1 + 1 : indxfpeak], Del_solns 

102 ) 

103 tmpmergerringdown = A_norm(Mf[indxfpeak:], eta) * A_MR( 

104 Mf[indxfpeak:], f_RD, f_damp, [Gamma1, Gamma2, Gamma3] 

105 ) 

106 fullwaveform = np.hstack((tmpinspiral, tmpintermediate, tmpmergerringdown)) 

107 

108 return [Mf, fullwaveform] 

109 

110 

111def A_norm(freqs, eta): 

112 """Calculates the constant scaling factor A_0 

113 

114 Parameters 

115 ---------- 

116 freqs : array 

117 The frequencies in Natural units (Mf, G=c=1) of the waveform 

118 eta : float 

119 The reduced mass ratio 

120 

121 """ 

122 const = np.sqrt(2 * eta / 3 / np.pi ** (1 / 3)) 

123 return const * freqs ** -(7 / 6) 

124 

125 

126def A_insp(freqs, eta, x1, x2, X_PN): 

127 """Calculates the Inspiral Amplitude 

128 

129 Parameters 

130 ---------- 

131 freqs : array 

132 The frequencies in Natural units (Mf, G=c=1) of the waveform 

133 eta : float 

134 The reduced mass ratio 

135 x1 : float 

136 The dimensionless spin parameter abs(a/m) for black hole m1. 

137 x2 : float 

138 The dimensionless spin parameter abs(a/m) for black hole m2. 

139 x_PN : float 

140 The PN reduced spin parameter 

141 

142 """ 

143 A_PN = 0.0 

144 A_higher = 0.0 

145 for i in range(7): 

146 A_PN = A_PN + PN_coeffs(eta, x1, x2, i) * (np.pi * freqs) ** (i / 3) 

147 if i >= 1 and i <= 3: 

148 A_higher = A_higher + Lambda(eta, X_PN, i - 1) * freqs ** ((6 + i) / 3) 

149 return A_PN + A_higher 

150 

151 

152def DA_insp(freqs, eta, x1, x2, X_PN): 

153 """Calculates Derivative of the inspiral amplitude. 

154 

155 Parameters 

156 ---------- 

157 freqs : array 

158 The frequencies in Natural units (Mf, G=c=1) of the waveform 

159 eta : float 

160 The reduced mass ratio 

161 x1 : float 

162 The dimensionless spin parameter abs(a/m) for black hole m1. 

163 x2 : float 

164 The dimensionless spin parameter abs(a/m) for black hole m2. 

165 x_PN : float 

166 The PN reduced spin parameter 

167 

168 """ 

169 DA_PN = 0.0 

170 DA_higher = 0.0 

171 for i in range(7): 

172 PN_const = np.pi ** (i / 3) * (i / 3) * PN_coeffs(eta, x1, x2, i) 

173 DA_PN = DA_PN + PN_const * (freqs) ** ((i - 3) / 3) 

174 if i >= 1 and i <= 3: 

175 higher_const = ((6 + i) / 3) * Lambda(eta, X_PN, i - 1) 

176 DA_higher = DA_higher + higher_const * freqs ** ((i + 3) / 3) 

177 

178 return DA_PN + DA_higher 

179 

180 

181def A_MR(freqs, f_RD, f_damp, Gammas): 

182 """Calculates the Normalized Merger-Ringdown Amplitude 

183 

184 Parameters 

185 ---------- 

186 freqs : array 

187 The frequencies in Natural units (Mf, G=c=1) of the waveform 

188 f_RD : float 

189 Frequency of the Ringdown transition 

190 f_damp : float 

191 Damping frequency 

192 Gammas : array-like 

193 Normalizes lorentzian to correct shape 

194 

195 """ 

196 varf = freqs - f_RD 

197 fg_d = Gammas[2] * f_damp 

198 return ( 

199 (Gammas[0] * fg_d) 

200 / (varf ** 2 + fg_d ** 2) 

201 * np.exp(-(Gammas[1] / fg_d) * varf) 

202 ) 

203 

204 

205def DA_MR(freqs, f_RD, f_damp, Gammas): 

206 """Calculates Derivative of the Merger-Ringdown Amplitude 

207 

208 Parameters 

209 ---------- 

210 freqs : array 

211 The frequencies in Natural units (Mf, G=c=1) of the waveform 

212 f_RD : float 

213 Frequency of the Ringdown transition 

214 f_damp : float 

215 Damping frequency 

216 Gammas : array-like 

217 Normalizes lorentzian to correct shape 

218 

219 """ 

220 varf = freqs - f_RD 

221 fg_d = Gammas[2] * f_damp 

222 A_MR_0 = A_MR(freqs, f_RD, f_damp, Gammas) 

223 return -A_MR_0 * (2 * varf / (varf ** 2 + fg_d ** 2) + Gammas[1] / fg_d) 

224 

225 

226def A_intermediate(f1, f2, f3, v1, v2, v3, d1, d3): 

227 """Solves system of equations for intermediate amplitude matching""" 

228 Mat = np.array( 

229 [ 

230 [1.0, f1, f1 ** 2, f1 ** 3, f1 ** 4], 

231 [1.0, f2, f2 ** 2, f2 ** 3, f2 ** 4], 

232 [1.0, f3, f3 ** 2, f3 ** 3, f3 ** 4], 

233 [0.0, 1.0, 2 * f1, 3 * f1 ** 2, 4 * f1 ** 3], 

234 [0.0, 1.0, 2 * f3, 3 * f3 ** 2, 4 * f3 ** 3], 

235 ], 

236 dtype="float", 

237 ) 

238 a = np.array([v1, v2, v3, d1, d3], dtype="float") 

239 return np.linalg.solve(Mat, a) 

240 

241 

242def A_int(freqs, delt): 

243 """Calculates the Intermediate Amplitude 

244 

245 Parameters 

246 ---------- 

247 freqs : array 

248 The frequencies in Natural units (Mf, G=c=1) of the waveform 

249 delt : array 

250 Coefficient solutions to match the inspiral to the merger-ringdown portion of the waveform 

251 

252 """ 

253 return ( 

254 delt[0] 

255 + delt[1] * freqs 

256 + delt[2] * freqs ** 2 

257 + delt[3] * freqs ** 3 

258 + delt[4] * freqs ** 4 

259 ) 

260 

261 

262def Lambda(eta, x_PN, lmbda): 

263 """Gets the Lambdas from Eqn 31 in <https://arxiv.org/abs/1508.07253> 

264 

265 Parameters 

266 ---------- 

267 eta : float 

268 The reduced mass ratio 

269 x_PN : float 

270 The PN reduced spin parameter 

271 lmbda : int 

272 Iterator for different Lambda variables using the zeta function 

273 

274 """ 

275 xi = x_PN - 1 

276 xi2 = xi * xi 

277 xi3 = xi2 * xi 

278 eta2 = eta * eta 

279 if lmbda == 0: # rho1 

280 coeffs = zeta(0) 

281 elif lmbda == 1: # rho2 

282 coeffs = zeta(1) 

283 elif lmbda == 2: # rho3 

284 coeffs = zeta(2) 

285 elif lmbda == 3: # v2 

286 coeffs = zeta(3) 

287 elif lmbda == 4: # gamma1 

288 coeffs = zeta(4) 

289 elif lmbda == 5: # gamma2 

290 coeffs = zeta(5) 

291 elif lmbda == 6: # gamma3 

292 coeffs = zeta(6) 

293 

294 return ( 

295 coeffs[0] 

296 + coeffs[1] * eta 

297 + (coeffs[2] + coeffs[3] * eta + coeffs[4] * eta2) * xi 

298 + (coeffs[5] + coeffs[6] * eta + coeffs[7] * eta2) * xi2 

299 + (coeffs[8] + coeffs[9] * eta + coeffs[10] * eta2) * xi3 

300 ) 

301 

302 

303def zeta(k): 

304 """Coefficients in table 5 of <https://arxiv.org/abs/1508.07253>""" 

305 if k == 0: # rho 1 

306 coeffs = [ 

307 3931.9, 

308 -17395.8, 

309 3132.38, 

310 343966.0, 

311 -1.21626e6, 

312 -70698.0, 

313 1.38391e6, 

314 -3.96628e6, 

315 -60017.5, 

316 803515.0, 

317 -2.09171e6, 

318 ] 

319 elif k == 1: # rho 2 

320 coeffs = [ 

321 -40105.5, 

322 112253.0, 

323 23561.7, 

324 -3.47618e6, 

325 1.13759e7, 

326 754313.0, 

327 -1.30848e7, 

328 3.64446e7, 

329 596227.0, 

330 -7.42779e6, 

331 1.8929e7, 

332 ] 

333 elif k == 2: # rho 3 

334 coeffs = [ 

335 83208.4, 

336 -191238.0, 

337 -210916.0, 

338 8.71798e6, 

339 -2.69149e7, 

340 -1.98898e6, 

341 3.0888e7, 

342 -8.39087e7, 

343 -1.4535e6, 

344 1.70635e7, 

345 -4.27487e7, 

346 ] 

347 elif k == 3: # v 2 

348 coeffs = [ 

349 0.814984, 

350 2.57476, 

351 1.16102, 

352 -2.36278, 

353 6.77104, 

354 0.757078, 

355 -2.72569, 

356 7.11404, 

357 0.176693, 

358 -0.797869, 

359 2.11624, 

360 ] 

361 elif k == 4: # gamma 1 

362 coeffs = [ 

363 0.0069274, 

364 0.0302047, 

365 0.00630802, 

366 -0.120741, 

367 0.262716, 

368 0.00341518, 

369 -0.107793, 

370 0.27099, 

371 0.000737419, 

372 -0.0274962, 

373 0.0733151, 

374 ] 

375 elif k == 5: # gamma 2 

376 coeffs = [ 

377 1.01034, 

378 0.000899312, 

379 0.283949, 

380 -4.04975, 

381 13.2078, 

382 0.103963, 

383 -7.02506, 

384 24.7849, 

385 0.030932, 

386 -2.6924, 

387 9.60937, 

388 ] 

389 elif k == 6: # gamma 3 

390 coeffs = [ 

391 1.30816, 

392 -0.00553773, 

393 -0.0678292, 

394 -0.668983, 

395 3.40315, 

396 -0.0529658, 

397 -0.992379, 

398 4.82068, 

399 -0.00613414, 

400 -0.384293, 

401 1.75618, 

402 ] 

403 return coeffs 

404 

405 

406def PN_coeffs(eta, x1, x2, i): 

407 """Gets the PN Amplitude coefficients 

408 

409 Parameters 

410 ---------- 

411 eta : float 

412 The reduced mass ratio 

413 x1 : float 

414 The dimensionless spin parameter abs(a/m) for black hole m1. 

415 x2 : float 

416 The dimensionless spin parameter abs(a/m) for black hole m2. 

417 q : float 

418 The mass ratio m1/m2, m1<=m2 

419 i : int 

420 iterator to dictate which PN Amplitude to use 

421 

422 Notes 

423 ----- 

424 Coefficients in appendix B (eqns B14-B20) of <https://arxiv.org/abs/1508.07253> 

425 

426 """ 

427 delta = np.sqrt(1.0 - 4.0 * eta) 

428 chi_s = (x1 + x2) / 2.0 

429 chi_a = (x1 - x2) / 2.0 

430 if i == 0: 

431 A_i = 1 

432 elif i == 1: 

433 A_i = 0 

434 elif i == 2: 

435 A_i = -323 / 224 + (451 / 168) * eta 

436 elif i == 3: 

437 A_i = (27 / 8) * delta * chi_a + (27 / 8 - (11 / 6) * eta) * chi_s 

438 elif i == 4: 

439 A_i = ( 

440 -27312085 / 8128512 

441 - (1975055 / 338688) * eta 

442 + (105271 / 24192) * eta ** 2 

443 + (-81 / 32 + 8 * eta) * chi_a ** 2 

444 - 81 / 16 * delta * chi_a * chi_s 

445 + (-81 / 32 + 17 / 8 * eta) * chi_s ** 2 

446 ) 

447 elif i == 5: 

448 A_i = ( 

449 -85 * np.pi / 64 

450 + 85 * np.pi / 16 * eta 

451 + (285197 / 16128 - 1579 / 4032 * eta) * delta * chi_a 

452 + (285197 / 16128 - 15317 / 672 * eta - 2227 / 1008 * eta ** 2) * chi_s 

453 ) 

454 elif i == 6: 

455 A_i = ( 

456 -177520268561 / 8583708672 

457 + (545384828789 / 5007163392 - 205 * np.pi ** 2 / 48) * eta 

458 - 3248849057 / 178827264 * eta ** 2 

459 + 34473079 / 6386688 * eta ** 3 

460 + (1614569 / 64512 - 1873643 / 16128 * eta + 2167 / 42 * eta ** 2) 

461 * chi_a ** 2 

462 + (31 * np.pi / 12 - 7 * np.pi / 3 * eta) * chi_s 

463 + (1614569 / 64512 - 61391 / 1344 * eta + 57451 / 4032 * eta ** 2) 

464 * chi_s ** 2 

465 + delta 

466 * chi_a 

467 * (31 * np.pi / 12 + (1614569 / 32256 - 165961 / 2688 * eta) * chi_s) 

468 ) 

469 return A_i 

470 

471 

472def Calc_f_peak(f_RD, f_damp, Gammas): 

473 """Calculates the frequency at the peak of the merger 

474 

475 Parameters 

476 ---------- 

477 f_RD : float 

478 Frequency of the Ringdown transition 

479 f_damp : float 

480 Damping frequency 

481 Gammas : array-like 

482 Normalizes lorentzian to correct shape 

483 

484 Notes 

485 ----- 

486 There is a problem with this expression from the paper becoming imaginary if gamma2 >= 1 

487 so if gamma2 >= 1 then set the square root term to zero. 

488 

489 """ 

490 if Gammas[1] <= 1: 

491 f_max = np.abs( 

492 f_RD + f_damp * Gammas[2] * (np.sqrt(1 - Gammas[1] ** 2) - 1) / Gammas[1] 

493 ) 

494 else: 

495 f_max = np.abs(f_RD + (f_damp * Gammas[2] * -1) / Gammas[1]) 

496 return f_max 

497 

498 

499def Find_Cutoff_Freq(f_RD, f_damp, Gammas, pct_of_peak=0.0001): 

500 """Cutoff signal when the amplitude is a factor of 10 below the value at f_RD 

501 

502 Parameters 

503 ---------- 

504 f_RD : float 

505 Frequency of the Ringdown transition 

506 f_damp : float 

507 Damping frequency 

508 Gammas : array-like 

509 Normalizes lorentzian to correct shape 

510 

511 pct_of_peak : float, optional 

512 the percentange of the strain at merger that dictates the maximum 

513 frequency the waveform is calculated at in geometrized units (G=c=1) 

514 

515 """ 

516 tempfreqs = np.logspace(np.log10(f_RD), np.log10(10 * f_RD), 100) 

517 cutoffAmp = pct_of_peak * A_MR( 

518 f_RD, f_RD, f_damp, [Gammas[0], Gammas[1], Gammas[2]] 

519 ) 

520 merger_ringdown_Amp = A_MR( 

521 tempfreqs, f_RD, f_damp, [Gammas[0], Gammas[1], Gammas[2]] 

522 ) 

523 cutoffindex = np.argmin(np.abs(cutoffAmp - merger_ringdown_Amp)) 

524 return tempfreqs[cutoffindex] 

525 

526 

527def a_final(x1, x2, q, eta): 

528 """The Final spin of the binary remnant black hole 

529 

530 Parameters 

531 ---------- 

532 x1 : float 

533 The dimensionless spin parameter abs(a/m) for black hole m1. 

534 x2 : float 

535 The dimensionless spin parameter abs(a/m) for black hole m2. 

536 q : float 

537 The mass ratio m1/m2, m1<=m2 

538 eta : float 

539 The reduced mass ratio 

540 

541 Notes 

542 ----- 

543 Uses eq. 3 in <https://arxiv.org/abs/0904.2577>, changed to match our q convention 

544 a=J/M**2 where J = x1*m1**2 + x2*m2**2 

545 

546 """ 

547 a = (q ** 2 * x1 + x2) / (q ** 2 + 1) 

548 s4 = -0.1229 

549 s5 = 0.4537 

550 t0 = -2.8904 

551 t2 = -3.5171 

552 t3 = 2.5763 

553 return ( 

554 a 

555 + s4 * a ** 2 * eta 

556 + s5 * a * eta ** 2 

557 + t0 * a * eta 

558 + 2 * np.sqrt(3) * eta 

559 + t2 * eta ** 2 

560 + t3 * eta ** 3 

561 ) 

562 

563 

564def chi_PN(eta, x1, x2): 

565 """Calculates the PN reduced spin parameter 

566 

567 Parameters 

568 ---------- 

569 eta : float 

570 The reduced mass ratio 

571 x1 : float 

572 The dimensionless spin parameter abs(a/m) for black hole m1. 

573 x2 : float 

574 The dimensionless spin parameter abs(a/m) for black hole m2. 

575 

576 Notes 

577 ----- 

578 See Eq 5.9 in <https://arxiv.org/abs/1107.1267v2> 

579 

580 """ 

581 delta = np.sqrt(1.0 - 4.0 * eta) 

582 chi_s = (x1 + x2) / 2.0 

583 chi_a = (x1 - x2) / 2.0 

584 return chi_s * (1.0 - eta * 76.0 / 113.0) + delta * chi_a