Coverage for /home/andrew/Documents/Research/gwent/gwent/waveform.py : 99%

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
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>
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)
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)
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
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
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
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]
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
58 Gamma1 = Lambda(eta, x_PN, 4)
59 Gamma2 = Lambda(eta, x_PN, 5)
60 Gamma3 = Lambda(eta, x_PN, 6)
62 f_peak = Calc_f_peak(f_RD, f_damp, [Gamma1, Gamma2, Gamma3])
64 f1 = 0.014
65 f3 = f_peak
66 f2 = (f1 + f3) / 2
68 cutoffFreq = Find_Cutoff_Freq(
69 f_RD, f_damp, [Gamma1, Gamma2, Gamma3], pct_of_peak=pct_of_peak
70 )
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 )
78 Mf = np.logspace(np.log10(f_low), np.log10(cutoffFreq), N)
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])
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
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))
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))
108 return [Mf, fullwaveform]
111def A_norm(freqs, eta):
112 """Calculates the constant scaling factor A_0
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
121 """
122 const = np.sqrt(2 * eta / 3 / np.pi ** (1 / 3))
123 return const * freqs ** -(7 / 6)
126def A_insp(freqs, eta, x1, x2, X_PN):
127 """Calculates the Inspiral Amplitude
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
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
152def DA_insp(freqs, eta, x1, x2, X_PN):
153 """Calculates Derivative of the inspiral amplitude.
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
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)
178 return DA_PN + DA_higher
181def A_MR(freqs, f_RD, f_damp, Gammas):
182 """Calculates the Normalized Merger-Ringdown Amplitude
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
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 )
205def DA_MR(freqs, f_RD, f_damp, Gammas):
206 """Calculates Derivative of the Merger-Ringdown Amplitude
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
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)
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)
242def A_int(freqs, delt):
243 """Calculates the Intermediate Amplitude
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
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 )
262def Lambda(eta, x_PN, lmbda):
263 """Gets the Lambdas from Eqn 31 in <https://arxiv.org/abs/1508.07253>
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
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)
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 )
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
406def PN_coeffs(eta, x1, x2, i):
407 """Gets the PN Amplitude coefficients
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
422 Notes
423 -----
424 Coefficients in appendix B (eqns B14-B20) of <https://arxiv.org/abs/1508.07253>
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
472def Calc_f_peak(f_RD, f_damp, Gammas):
473 """Calculates the frequency at the peak of the merger
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
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.
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
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
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
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)
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]
527def a_final(x1, x2, q, eta):
528 """The Final spin of the binary remnant black hole
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
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
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 )
564def chi_PN(eta, x1, x2):
565 """Calculates the PN reduced spin parameter
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.
576 Notes
577 -----
578 See Eq 5.9 in <https://arxiv.org/abs/1107.1267v2>
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