Coverage for pesummary/gw/conversions/remnant.py: 27.8%
205 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-05-02 08:42 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-05-02 08:42 +0000
1# Licensed under an MIT style license -- see LICENSE.md
3import numpy as np
5from pesummary.utils.utils import logger, iterator
6from pesummary.utils.decorators import array_input
7from .spins import chi_p
9__author__ = ["Charlie Hoy <charlie.hoy@ligo.org>"]
11try:
12 import lalsimulation
13 from lalsimulation import (
14 FLAG_SEOBNRv4P_HAMILTONIAN_DERIVATIVE_NUMERICAL,
15 FLAG_SEOBNRv4P_EULEREXT_QNM_SIMPLE_PRECESSION,
16 FLAG_SEOBNRv4P_ZFRAME_L
17 )
18 from lal import MSUN_SI
19except ImportError:
20 pass
22DEFAULT_SEOBFLAGS = {
23 "SEOBNRv4P_SpinAlignedEOBversion": 4,
24 "SEOBNRv4P_SymmetrizehPlminusm": 1,
25 "SEOBNRv4P_HamiltonianDerivative": FLAG_SEOBNRv4P_HAMILTONIAN_DERIVATIVE_NUMERICAL,
26 "SEOBNRv4P_euler_extension": FLAG_SEOBNRv4P_EULEREXT_QNM_SIMPLE_PRECESSION,
27 "SEOBNRv4P_Zframe": FLAG_SEOBNRv4P_ZFRAME_L,
28 "SEOBNRv4P_debug": 0
29}
32@array_input()
33def final_mass_of_merger_from_NSBH(
34 mass_1, mass_2, spin_1z, lambda_2, approximant="IMRPhenomNSBH"
35):
36 """Calculate the final mass resulting from an NSBH merger using NSBH
37 waveform models given samples for mass_1, mass_2, spin_1z and lambda_2.
38 mass_1 and mass_2 should be in solar mass units.
39 """
40 from .tidal import _check_NSBH_approximant
41 return _check_NSBH_approximant(
42 approximant, mass_1, mass_2, spin_1z, lambda_2
43 )[4]
46@array_input()
47def final_spin_of_merger_from_NSBH(
48 mass_1, mass_2, spin_1z, lambda_2, approximant="IMRPhenomNSBH"
49):
50 """Calculate the final spin resulting from an NSBH merger using NSBH
51 waveform models given samples for mass_1, mass_2, spin_1z and lambda_2.
52 mass_1 and mass_2 should be in solar mass units.
53 """
54 from .tidal import _check_NSBH_approximant
55 return _check_NSBH_approximant(
56 approximant, mass_1, mass_2, spin_1z, lambda_2
57 )[5]
60@array_input()
61def _final_from_initial_NSBH(*args, **kwargs):
62 """Calculate the final mass and final spin given the initial parameters
63 of the binary using the approximant directly
64 """
65 return [
66 final_mass_of_merger_from_NSBH(*args, **kwargs),
67 final_spin_of_merger_from_NSBH(*args, **kwargs)
68 ]
71def _wrapper_return_final_mass_and_final_spin_from_waveform(args):
72 """Wrapper function to calculate the remnant properties for a given waveform
73 for a pool of workers
75 Parameters
76 ----------
77 args: np.ndarray
78 2 dimensional array giving arguments to pass to
79 _return_final_mass_and_final_spin_from_waveform. The first argument
80 in each sublist is the keyword and the second argument in each sublist
81 is the item you wish to pass
82 """
83 kwargs = {arg[0]: arg[1] for arg in args}
84 return _return_final_mass_and_final_spin_from_waveform(**kwargs)
87def _return_final_mass_and_final_spin_from_waveform(
88 mass_function=None, spin_function=None, mass_function_args=[],
89 spin_function_args=[], mass_function_return_function=None,
90 mass_function_return_index=None, spin_function_return_function=None,
91 spin_function_return_index=None, mass_1_index=0, mass_2_index=1,
92 nsamples=0, approximant=None, default_SEOBNRv4P_kwargs=False
93):
94 """Return the final mass and final spin given functions to use
96 Parameters
97 ----------
98 mass_function: func
99 function you wish to use to calculate the final mass
100 spin_function: func
101 function you wish to use to calculate the final spin
102 mass_function_args: list
103 list of arguments you wish to pass to mass_function
104 spin_function_args: list
105 list of arguments you wish to pass to spin_function
106 mass_function_return_function: str, optional
107 function used to extract the final mass from the quantity returned from
108 mass_function. For example, if mass_function returns a list and the
109 final_mass is a property of the 3 arg of this list,
110 mass_function_return_function='[3].final_mass'
111 mass_function_return_index: str, optional
112 if mass_function returns a list of parameters,
113 mass_function_return_index indicates the index of `final_mass` in the
114 list
115 spin_function_return_function: str, optional
116 function used to extract the final spin from the quantity returned from
117 spin_function. For example, if spin_function returns a list and the
118 final_spin is a property of the 3 arg of this list,
119 spin_function_return_function='[3].final_spin'
120 spin_function_return_index: str, optional
121 if spin_function returns a list of parameters,
122 spin_function_return_index indicates the index of `final_spin` in the
123 list
124 mass_1_index: int, optional
125 the index of mass_1 in mass_function_args. Default is 0
126 mass_2_index: int, optional
127 the index of mass_2 in mass_function_args. Default is 1
128 nsamples: int, optional
129 the total number of samples
130 approximant: str, optional
131 the approximant used
132 default_SEOBNRv4P_kwargs: Bool, optional
133 if True, use the default SEOBNRv4P flags
134 """
135 if default_SEOBNRv4P_kwargs:
136 mode_array, seob_flags = _setup_SEOBNRv4P_args()
137 mass_function_args += [mode_array, seob_flags]
138 spin_function_args += [mode_array, seob_flags]
139 fm = mass_function(*mass_function_args)
140 if mass_function_return_function is not None:
141 fm = eval("fm{}".format(mass_function_return_function))
142 elif mass_function_return_index is not None:
143 fm = fm[mass_function_return_index]
144 fs = spin_function(*spin_function_args)
145 if spin_function_return_function is not None:
146 fs = eval("fs{}".format(spin_function_return_function))
147 elif spin_function_return_index is not None:
148 fs = fs[spin_function_return_index]
149 final_mass = fm * (
150 mass_function_args[mass_1_index] + mass_function_args[mass_2_index]
151 ) / MSUN_SI
152 final_spin = fs
153 return final_mass, final_spin
156def _setup_SEOBNRv4P_args(mode=[2, 2], seob_flags=DEFAULT_SEOBFLAGS):
157 """Setup the SEOBNRv4P[HM] kwargs
158 """
159 from lalsimulation import (
160 SimInspiralCreateModeArray, SimInspiralModeArrayActivateMode
161 )
162 from lal import DictInsertINT4Value, CreateDict
164 mode_array = SimInspiralCreateModeArray()
165 SimInspiralModeArrayActivateMode(mode_array, mode[0], mode[1])
166 _seob_flags = CreateDict()
167 for key, item in seob_flags.items():
168 DictInsertINT4Value(_seob_flags, key, item)
169 return mode_array, _seob_flags
172@array_input()
173def _final_from_initial_BBH(
174 mass_1, mass_2, spin_1x, spin_1y, spin_1z, spin_2x, spin_2y, spin_2z,
175 approximant="SEOBNRv4", iota=None, luminosity_distance=None, f_ref=None,
176 phi_ref=None, mode=[2, 2], delta_t=1. / 4096, seob_flags=DEFAULT_SEOBFLAGS,
177 return_fits_used=False, multi_process=None
178):
179 """Calculate the final mass and final spin given the initial parameters
180 of the binary using the approximant directly
182 Parameters
183 ----------
184 mass_1: float/np.ndarray
185 primary mass of the binary
186 mass_2: float/np.ndarray
187 secondary mass of the binary
188 spin_1x: float/np.ndarray
189 x component of the primary spin
190 spin_1y: float/np.ndarray
191 y component of the primary spin
192 spin_1z: float/np.ndarray
193 z component of the primary spin
194 spin_2x: float/np.ndarray
195 x component of the secondary spin
196 spin_2y: float/np.ndarray
197 y component of the secondary spin
198 spin_2z: float/np.ndarray
199 z component of the seconday spin
200 approximant: str
201 name of the approximant you wish to use for the remnant fits
202 iota: float/np.ndarray, optional
203 the angle between the total orbital angular momentum and the line of
204 sight of the source. Used when calculating the remnant fits for
205 SEOBNRv4PHM. Since we only need the EOB dynamics here it does not matter
206 what we pass
207 luminosity_distance: float/np.ndarray, optional
208 the luminosity distance of the source. Used when calculating the
209 remnant fits for SEOBNRv4PHM. Since we only need the EOB dynamics here
210 it does not matter what we pass.
211 f_ref: float/np.ndarray, optional
212 the reference frequency at which the spins are defined
213 phi_ref: float/np.ndarray, optional
214 the coalescence phase of the binary
215 mode: list, optional
216 specific mode to use when calculating the remnant fits for SEOBNRv4PHM.
217 Since we only need the EOB dynamics here it does not matter what we
218 pass.
219 delta_t: float, optional
220 the sampling rate used in the analysis, Used when calculating the
221 remnant fits for SEOBNRv4PHM
222 seob_flags: dict, optional
223 dictionary containing the SEOB flags. Used when calculating the remnant
224 fits for SEOBNRv4PHM
225 return_fits_used: Bool, optional
226 if True, return the approximant that was used.
227 multi_process: int, optional
228 the number of cores to use when calculating the remnant fits
229 """
230 from lalsimulation import (
231 SimIMREOBFinalMassSpin, SimInspiralGetSpinSupportFromApproximant,
232 SimIMRSpinPrecEOBWaveformAll, SimPhenomUtilsIMRPhenomDFinalMass,
233 SimPhenomUtilsPhenomPv2FinalSpin
234 )
235 import multiprocessing
237 def convert_args_for_multi_processing(kwargs):
238 args = []
239 for n in range(kwargs["nsamples"]):
240 _args = []
241 for key, item in kwargs.items():
242 if key == "mass_function_args" or key == "spin_function_args":
243 _args.append([key, [arg[n] for arg in item]])
244 else:
245 _args.append([key, item])
246 args.append(_args)
247 return args
249 try:
250 approx = getattr(lalsimulation, approximant)
251 except AttributeError:
252 raise ValueError(
253 "The waveform '{}' is not supported by lalsimulation"
254 )
256 m1 = mass_1 * MSUN_SI
257 m2 = mass_2 * MSUN_SI
258 kwargs = {"nsamples": len(mass_1), "approximant": approximant}
259 if approximant.lower() in ["seobnrv4p", "seobnrv4phm"]:
260 if any(i is None for i in [iota, luminosity_distance, f_ref, phi_ref]):
261 raise ValueError(
262 "The approximant '{}' requires samples for iota, f_ref, "
263 "phi_ref and luminosity_distance. Please pass these "
264 "samples.".format(approximant)
265 )
266 if len(delta_t) == 1:
267 delta_t = [delta_t[0]] * len(mass_1)
268 elif len(delta_t) != len(mass_1):
269 raise ValueError(
270 "Please provide either a single 'delta_t' that is is used for "
271 "all samples, or a single 'delta_t' for each sample"
272 )
273 mode_array, _seob_flags = _setup_SEOBNRv4P_args(
274 mode=mode, seob_flags=seob_flags
275 )
276 args = np.array([
277 phi_ref, delta_t, m1, m2, f_ref, luminosity_distance, iota,
278 spin_1x, spin_1y, spin_1z, spin_2x, spin_2y, spin_2z,
279 [mode_array] * len(mass_1), [_seob_flags] * len(mass_1)
280 ])
281 kwargs.update(
282 {
283 "mass_function": SimIMRSpinPrecEOBWaveformAll,
284 "spin_function": SimIMRSpinPrecEOBWaveformAll,
285 "mass_function_args": args,
286 "spin_function_args": args,
287 "mass_function_return_function": "[21].data[6]",
288 "spin_function_return_function": "[21].data[7]",
289 "mass_1_index": 2,
290 "mass_2_index": 3,
291 }
292 )
293 elif approximant.lower() in ["seobnrv4"]:
294 spin1 = np.array([spin_1x, spin_1y, spin_1z]).T
295 spin2 = np.array([spin_2x, spin_2y, spin_2z]).T
296 app = np.array([approx] * len(mass_1))
297 kwargs.update(
298 {
299 "mass_function": SimIMREOBFinalMassSpin,
300 "spin_function": SimIMREOBFinalMassSpin,
301 "mass_function_args": [m1, m2, spin1, spin2, app],
302 "spin_function_args": [m1, m2, spin1, spin2, app],
303 "mass_function_return_index": 1,
304 "spin_function_return_index": 2
305 }
306 )
307 elif "phenompv3" in approximant.lower():
308 kwargs.update(
309 {
310 "mass_function": SimPhenomUtilsIMRPhenomDFinalMass,
311 "spin_function": SimPhenomUtilsPhenomPv2FinalSpin,
312 "mass_function_args": [m1, m2, spin_1z, spin_2z],
313 "spin_function_args": [m1, m2, spin_1z, spin_2z]
314 }
315 )
316 if SimInspiralGetSpinSupportFromApproximant(approx) > 2:
317 # matches the waveform's internal usage as corrected in
318 # https://git.ligo.org/lscsoft/lalsuite/-/merge_requests/1270
319 _chi_p = chi_p(mass_1, mass_2, spin_1x, spin_1y, spin_2x, spin_2y)
320 kwargs["spin_function_args"].append(_chi_p)
321 else:
322 kwargs["spin_function_args"].append(np.zeros_like(mass_1))
323 else:
324 raise ValueError(
325 "The waveform '{}' is not support by this function.".format(
326 approximant
327 )
328 )
330 args = convert_args_for_multi_processing(kwargs)
331 if multi_process is not None and multi_process[0] != 1:
332 _multi_process = multi_process[0]
333 if approximant.lower() in ["seobnrv4p", "seobnrv4phm"]:
334 logger.warning(
335 "Ignoring passed 'mode' and 'seob_flags' options. Defaults "
336 "must be used with multiprocessing. If you wish to use custom "
337 "options, please set `multi_process=None`"
338 )
339 _kwargs = kwargs.copy()
340 _kwargs["mass_function_args"] = kwargs["mass_function_args"][:-2]
341 _kwargs["spin_function_args"] = kwargs["spin_function_args"][:-2]
342 _kwargs["default_SEOBNRv4P_kwargs"] = True
343 args = convert_args_for_multi_processing(_kwargs)
344 with multiprocessing.Pool(_multi_process) as pool:
345 data = np.array(list(
346 iterator(
347 pool.imap(
348 _wrapper_return_final_mass_and_final_spin_from_waveform,
349 args
350 ), tqdm=True, desc="Evaluating {} fit".format(approximant),
351 logger=logger, total=len(mass_1)
352 )
353 )).T
354 else:
355 final_mass, final_spin = [], []
356 _iterator = iterator(
357 range(kwargs["nsamples"]), tqdm=True, total=len(mass_1),
358 desc="Evaluating {} fit".format(approximant), logger=logger
359 )
360 for i in _iterator:
361 data = _wrapper_return_final_mass_and_final_spin_from_waveform(
362 args[i]
363 )
364 final_mass.append(data[0])
365 final_spin.append(data[1])
366 data = [final_mass, final_spin]
367 if return_fits_used:
368 return data, [approximant]
369 return data
372def final_remnant_properties_from_NRSurrogate(
373 *args, f_low=20., f_ref=20., model="NRSur7dq4Remnant", return_fits_used=False,
374 properties=["final_mass", "final_spin", "final_kick"], approximant="SEOBNRv4PHM"
375):
376 """Return the properties of the final remnant resulting from a BBH merger using
377 NRSurrogate fits
379 Parameters
380 ---------
381 f_low: float/np.ndarray
382 The low frequency cut-off used in the analysis. Default is 20Hz
383 f_ref: float/np.ndarray
384 The reference frequency used in the analysis. Default is 20Hz
385 model: str, optional
386 The name of the NRSurrogate model you wish to use
387 return_fits_used: Bool, optional
388 if True, return the approximant that was used.
389 properties: list, optional
390 The list of properties you wish to calculate
391 approximant: str, optional
392 The approximant that was used to generate the posterior samples
393 """
394 from .nrutils import NRSur_fit
396 fit = NRSur_fit(
397 *args, f_low=f_low, f_ref=f_ref, model=model, fits=properties,
398 approximant=approximant
399 )
400 if return_fits_used:
401 return fit, [model]
402 return fit
405def final_mass_of_merger_from_NR(
406 *args, NRfit="average", final_spin=None, return_fits_used=False
407):
408 """Return the final mass resulting from a BBH merger using NR fits
410 Parameters
411 ----------
412 NRfit: str
413 Name of the fit you wish to use. If you wish to use a precessing fit
414 please use the syntax 'precessing_{}'.format(fit_name). If you wish
415 to have an average NR fit, then pass 'average'
416 final_spin: float/np.ndarray, optional
417 precomputed final spin of the remnant.
418 return_fits_used: Bool, optional
419 if True, return the fits that were used. Only used when NRfit='average'
420 """
421 from pesummary.gw.conversions import nrutils
423 if NRfit.lower() == "average":
424 func = getattr(nrutils, "bbh_final_mass_average")
425 elif "panetal" in NRfit.lower():
426 func = getattr(
427 nrutils, "bbh_final_mass_non_spinning_Panetal"
428 )
429 else:
430 func = getattr(
431 nrutils, "bbh_final_mass_non_precessing_{}".format(NRfit)
432 )
433 if "healy" in NRfit.lower():
434 return func(*args, final_spin=final_spin)
435 if NRfit.lower() == "average":
436 return func(*args, return_fits_used=return_fits_used)
437 return func(*args)
440def final_mass_of_merger_from_NRSurrogate(
441 *args, model="NRSur7dq4Remnant", return_fits_used=False, approximant="SEOBNRv4PHM"
442):
443 """Return the final mass resulting from a BBH merger using NRSurrogate
444 fits
445 """
446 data = final_remnant_properties_from_NRSurrogate(
447 *args, model=model, properties=["final_mass"],
448 return_fits_used=return_fits_used,
449 approximant=approximant
450 )
451 if return_fits_used:
452 return data[0]["final_mass"], data[1]
453 return data["final_mass"]
456def final_mass_of_merger_from_waveform(*args, NSBH=False, **kwargs):
457 """Return the final mass resulting from a BBH/NSBH merger using a given
458 approximant
460 Parameters
461 ----------
462 NSBH: Bool, optional
463 if True, use NSBH waveform fits. Default False
464 """
465 if NSBH or "nsbh" in kwargs.get("approximant", "").lower():
466 return _final_from_initial_NSBH(*args, **kwargs)[1]
467 return _final_from_initial_BBH(*args, **kwargs)[0]
470def final_spin_of_merger_from_NR(
471 *args, NRfit="average", return_fits_used=False
472):
473 """Return the final spin resulting from a BBH merger using NR fits
475 Parameters
476 ----------
477 NRfit: str
478 Name of the fit you wish to use. If you wish to use a precessing fit
479 please use the syntax 'precessing_{}'.format(fit_name). If you wish
480 to have an average NR fit, then pass 'average'
481 return_fits_used: Bool, optional
482 if True, return the fits that were used. Only used when NRfit='average'
483 """
484 from pesummary.gw.conversions import nrutils
486 if NRfit.lower() == "average":
487 func = getattr(nrutils, "bbh_final_spin_average_precessing")
488 elif "pan" in NRfit.lower():
489 func = getattr(
490 nrutils, "bbh_final_spin_non_spinning_Panetal"
491 )
492 elif "precessing" in NRfit.lower():
493 func = getattr(
494 nrutils, "bbh_final_spin_precessing_{}".format(
495 NRfit.split("precessing_")[1]
496 )
497 )
498 else:
499 func = getattr(
500 nrutils, "bbh_final_spin_non_precessing_{}".format(NRfit)
501 )
502 if NRfit.lower() == "average":
503 return func(*args, return_fits_used=return_fits_used)
504 return func(*args)
507def final_spin_of_merger_from_NRSurrogate(
508 *args, model="NRSur7dq4Remnant", return_fits_used=False, approximant="SEOBNRv4PHM"
509):
510 """Return the final spin resulting from a BBH merger using NRSurrogate
511 fits
512 """
513 data = final_remnant_properties_from_NRSurrogate(
514 *args, model=model, properties=["final_spin"],
515 return_fits_used=return_fits_used, approximant=approximant
516 )
517 if return_fits_used:
518 return data[0]["final_spin"], data[1]
519 return data["final_spin"]
522def final_spin_of_merger_from_waveform(*args, NSBH=False, **kwargs):
523 """Return the final spin resulting from a BBH/NSBH merger using a given
524 approximant.
526 Parameters
527 ----------
528 NSBH: Bool, optional
529 if True, use NSBH waveform fits. Default False
530 """
531 if NSBH or "nsbh" in kwargs.get("approximant", "").lower():
532 return _final_from_initial_NSBH(*args, **kwargs)[1]
533 return _final_from_initial_BBH(*args, **kwargs)[1]
536def final_kick_of_merger_from_NRSurrogate(
537 *args, model="NRSur7dq4Remnant", return_fits_used=False, approximant="SEOBNRv4PHM"
538):
539 """Return the final kick of the remnant resulting from a BBH merger
540 using NRSurrogate fits
541 """
542 data = final_remnant_properties_from_NRSurrogate(
543 *args, model=model, properties=["final_kick"],
544 return_fits_used=return_fits_used, approximant=approximant
545 )
546 if return_fits_used:
547 return data[0]["final_kick"], data[1]
548 return data["final_kick"]
551def final_mass_of_merger(
552 *args, method="NR", approximant="SEOBNRv4", NRfit="average",
553 final_spin=None, return_fits_used=False, model="NRSur7dq4Remnant"
554):
555 """Return the final mass resulting from a BBH merger
557 Parameters
558 ----------
559 mass_1: float/np.ndarray
560 float/array of masses for the primary object
561 mass_2: float/np.ndarray
562 float/array of masses for the secondary object
563 spin_1z: float/np.ndarray
564 float/array of primary spin aligned with the orbital angular momentum
565 spin_2z: float/np.ndarray
566 float/array of secondary spin aligned with the orbital angular momentum
567 method: str
568 The method you wish to use to calculate the final mass of merger. Either
569 NR, NRSurrogate or waveform
570 approximant: str
571 Name of the approximant you wish to use if the chosen method is waveform
572 or NRSurrogate
573 NRFit: str
574 Name of the NR fit you wish to use if chosen method is NR
575 return_fits_used: Bool, optional
576 if True, return the NR fits that were used. Only used when
577 NRFit='average' or when method='NRSurrogate'
578 model: str, optional
579 The NRSurrogate model to use when evaluating the fits
580 """
581 if method.lower() == "nr":
582 mass_func = final_mass_of_merger_from_NR
583 kwargs = {
584 "NRfit": NRfit, "final_spin": final_spin,
585 "return_fits_used": return_fits_used
586 }
587 elif "nrsur" in method.lower():
588 mass_func = final_mass_of_merger_from_NRSurrogate
589 kwargs = {
590 "approximant": approximant, "return_fits_used": return_fits_used,
591 "model": model
592 }
593 else:
594 mass_func = final_mass_of_merger_from_waveform
595 kwargs = {"approximant": approximant}
597 return mass_func(*args, **kwargs)
600def final_spin_of_merger(
601 *args, method="NR", approximant="SEOBNRv4", NRfit="average",
602 return_fits_used=False, model="NRSur7dq4Remnant"
603):
604 """Return the final mass resulting from a BBH merger
606 Parameters
607 ----------
608 mass_1: float/np.ndarray
609 float/array of masses for the primary object
610 mass_2: float/np.ndarray
611 float/array of masses for the secondary object
612 a_1: float/np.ndarray
613 float/array of primary spin magnitudes
614 a_2: float/np.ndarray
615 float/array of secondary spin magnitudes
616 tilt_1: float/np.ndarray
617 float/array of primary spin tilt angle from the orbital angular momentum
618 tilt_2: float/np.ndarray
619 float/array of secondary spin tilt angle from the orbital angular
620 momentum
621 phi_12: float/np.ndarray
622 float/array of samples for the angle between the in-plane spin
623 components
624 method: str
625 The method you wish to use to calculate the final mass of merger. Either
626 NR, NRSurrogate or waveform
627 approximant: str
628 Name of the approximant you wish to use if the chosen method is waveform
629 or NRSurrogate
630 NRFit: str
631 Name of the NR fit you wish to use if chosen method is NR
632 return_fits_used: Bool, optional
633 if True, return the NR fits that were used. Only used when
634 NRFit='average' or when method='NRSurrogate'
635 model: str, optional
636 The NRSurrogate model to use when evaluating the fits
637 """
638 if method.lower() == "nr":
639 spin_func = final_spin_of_merger_from_NR
640 kwargs = {"NRfit": NRfit, "return_fits_used": return_fits_used}
641 elif "nrsur" in method.lower():
642 spin_func = final_spin_of_merger_from_NRSurrogate
643 kwargs = {
644 "approximant": approximant, "return_fits_used": return_fits_used,
645 "model": model
646 }
647 else:
648 spin_func = final_spin_of_merger_from_waveform
649 kwargs = {"approximant": approximant}
651 return spin_func(*args, **kwargs)
654def final_kick_of_merger(
655 *args, method="NR", approximant="SEOBNRv4", NRfit="average",
656 return_fits_used: False, model="NRSur7dq4Remnant"
657):
658 """Return the final kick velocity of the remnant resulting from a BBH merger
660 Parameters
661 ----------
662 mass_1: float/np.ndarray
663 float/array of masses for the primary object
664 mass_2: float/np.ndarray
665 float/array of masses for the secondary object
666 a_1: float/np.ndarray
667 float/array of primary spin magnitudes
668 a_2: float/np.ndarray
669 float/array of secondary spin magnitudes
670 tilt_1: float/np.ndarray
671 float/array of primary spin tilt angle from the orbital angular momentum
672 tilt_2: float/np.ndarray
673 float/array of secondary spin tilt angle from the orbital angular
674 momentum
675 phi_12: float/np.ndarray
676 float/array of samples for the angle between the in-plane spin
677 components
678 method: str
679 The method you wish to use to calculate the final kick of merger. Either
680 NR, NRSurrogate or waveform
681 approximant: str
682 Name of the approximant you wish to use if the chosen method is waveform
683 or NRSurrogate
684 NRFit: str
685 Name of the NR fit you wish to use if chosen method is NR
686 return_fits_used: Bool, optional
687 if True, return the NR fits that were used. Only used when
688 NRFit='average' or when method='NRSurrogate'
689 model: str, optional
690 The NRSurrogate model to use when evaluating the fits
691 """
692 if "nrsur" not in method.lower():
693 raise NotImplementedError(
694 "Currently you can only work out the final kick velocity using "
695 "NRSurrogate fits."
696 )
697 velocity_func = final_kick_of_merger_from_NRSurrogate
698 kwargs = {
699 "approximant": approximant, "return_fits_used": return_fits_used,
700 "model": model
701 }
702 return velocity_func(*args, **kwargs)
705def peak_luminosity_of_merger(*args, NRfit="average", return_fits_used=False):
706 """Return the peak luminosity of an aligned-spin BBH using NR fits
708 Parameters
709 ----------
710 mass_1: float/np.ndarray
711 float/array of masses for the primary object
712 mass_2: float/np.ndarray
713 float/array of masses for the secondary object
714 spin_1z: float/np.ndarray
715 float/array of primary spin aligned with the orbital angular momentum
716 spin_2z: float/np.ndarray
717 float/array of secondary spin aligned with the orbital angular momentum
718 NRFit: str
719 Name of the NR fit you wish to use if chosen method is NR
720 return_fits_used: Bool, optional
721 if True, return the NR fits that were used. Only used when
722 NRFit='average'
723 """
724 from pesummary.gw.conversions import nrutils
726 if NRfit.lower() == "average":
727 func = getattr(nrutils, "bbh_peak_luminosity_average")
728 else:
729 func = getattr(
730 nrutils, "bbh_peak_luminosity_non_precessing_{}".format(NRfit)
731 )
732 if NRfit.lower() == "average":
733 return func(*args, return_fits_used=return_fits_used)
734 return func(*args)