Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-8a6b96f
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
tilts_at_infinity_utils.py
Go to the documentation of this file.
1"""
2This contains utility functions and definitions used in calc_tilts_prec_avg_regularized.py and
3hybrid_spin_evolution.py
4
5N. K. Johnson-McDaniel, 2021
6"""
7
8import numpy as np
9
10from lal import G_SI, C_SI, MSUN_SI
11
12import warnings
13from warnings import warn
14
15# Define the kg to m and s conversions
16
17kg_to_m = G_SI/C_SI**2
18
19kg_to_s = G_SI/C_SI**3
20
21# Setup for error handling
22
23class Error(Exception):
24 """Base class for exceptions in this module"""
25 pass
26
28 """Exception raised when the evolution finds that the system is nonprecessing to numerical accuracy."""
29
30 def __init__(self, message):
31 self.message = message
32
33# Setup for warnings
34
35class Warn(UserWarning):
36 """Base class for warnings in this module"""
37 pass
38
39class ValueWarning(Warn):
40 """Warning raised when an input is dubious"""
41 pass
42
43# Make warnings cleaner
44
45def warning_formatter(message, category, filename, lineno, file=None, line=None):
46 return '%s: %s\n'%(category.__name__, message)
47
48warnings.formatwarning = warning_formatter
49
50# Define functions
51
52
53def format_error(err):
54 return "%s: %s"%(type(err).__name__, err)
55
56
57def check_masses(m1, m2):
58 if m1 <= 0. or m2 <= 0.:
59 raise ValueError(
60 "The input masses must both be positive, while they are m1, m2 = %e, %e kg" % (m1, m2))
61
62 if m1 < 0.09*MSUN_SI or m2 < 0.09*MSUN_SI:
63 warn("One or both of the masses is rather small: m1 = %e kg = %e Msun, m2 = %e kg = %e Msun. "
64 "The masses must be input in kg." % (m1, m1/MSUN_SI, m2, m2/MSUN_SI), ValueWarning)
65
66
67def eq_mass_check(m1, m2, Lf):
68 if m1 == m2:
69 if Lf is None:
70 raise ValueError(
71 "Cannot compute tilts at infinity for exactly equal-mass binaries, as those quantities are not well "
72 "defined in this case.")
73 else:
74 raise ValueError(
75 "The computation of the bounds and average value of the tilts is not yet implemented for exactly "
76 "equal-mass binaries.")
77
78
79def check_spin_mags(chi1, chi2):
80 if chi1 < 0. or chi1 > 1. or chi2 < 0. or chi2 > 1.:
81 raise ValueError(
82 "The magnitudes of the spins must both be between 0 and 1, while they are chi1, chi2 = %f, %f" % (chi1, chi2))
83
84
85def check_tilts(tilt1, tilt2):
86 if tilt1 < 0. or tilt1 > np.pi or tilt2 < 0. or tilt2 > np.pi:
87 raise ValueError(
88 "The tilt angles must both be between 0 and pi, while they are tilt1, tilt2 = %f, %f" % (tilt1, tilt2))
89
90
91def check_fref(fref, m1, m2, evol_type):
92 if fref <= 0.:
93 raise ValueError(
94 "The reference frequency must be positive, while it is fref = %f Hz" % fref)
95
96 f_ISCO = 6.**(-1.5)/(np.pi*(m1 + m2)*kg_to_s)
97
98 if fref > f_ISCO:
99 warn("The reference frequency should not be close to merger, where the %s evolution is highly inaccurate, "
100 "while it is fref = %f Hz, which is greater than the Schwarzschild ISCO frequency associated "
101 "with the binary's total mass of %f Hz"%(evol_type, fref, f_ISCO), ValueWarning)
102
103
104def package_tilts(tilt1, tilt2, Lf, swap):
105 """
106 Package tilts to be returned by prec_avg_tilt_comp_vec_inputs() or prec_avg_tilt_comp() depending on whether
107 Lf is None or not. Also swaps the tilts if necessary. Only works in the case when Lf is not None when the
108 min, max, and average values are all the same.
109
110 Inputs:
111
112 tilt1, tilt2: Tilts
113 Lf: Final orbital angular momentum (here just acts as a switch depending on whether it is None or not)
114 swap: Whether to swap tilt1 and tilt2 before returning (True) or not (False)
115
116 Output: dictionary with entries 'tilt1_inf', 'tilt2_inf' for evolution to infinity--Lf is None--and entries
117 'tilt1_sep_min', 'tilt1_sep_max', 'tilt1_sep_avg', 'tilt2_sep_min', 'tilt2_sep_max', 'tilt2_sep_avg'
118 for evolution to a finite separation (i.e., a finite orbital angular momentum), when Lf is not None
119 """
120
121 if swap:
122 tilt1, tilt2 = tilt2, tilt1
123
124 if Lf is None:
125 return {'tilt1_inf': tilt1, 'tilt2_inf': tilt2}
126 else:
127 return {'tilt1_sep_min': tilt1, 'tilt1_sep_max': tilt1, 'tilt1_sep_avg': tilt1, 'tilt2_sep_min': tilt2,
128 'tilt2_sep_max': tilt2, 'tilt2_sep_avg': tilt2}
129
130
131def evolution_error_handling(failure_mode, failure_message, failure_output, failure_output_string, Lf, swap, hybrid_evol=False):
132 """
133 Take care of the error message or warning and returning something for the tilts when the
134 precession-averaged evolution fails. Append entries for tilts at transition in the case where hybrid evolution fails.
135
136 Inputs:
137 failure_mode: The failure mode (either "Error", "NAN", or "None")
138 failure_message: The message to print in the error or warning
139 failure output: What to output for the tilts in the event of a failure
140 failure_output_string: The string associated with the failure output
141 Lf: Final orbital angular momentum (here just acts as a switch depending on whether it is None or not)
142 swap: Whether to swap tilt1 and tilt2 before returning (True) or not (False)
143 hybrid_evol: Flag to invoke error handling in the hybrid evolution code. Default: False
144
145 Output: dictionary with entries 'tilt1_inf', 'tilt2_inf' for evolution to infinity--Lf is None--and entries
146 'tilt1_sep_min', 'tilt1_sep_max', 'tilt1_sep_avg', 'tilt2_sep_min', 'tilt2_sep_max', 'tilt2_sep_avg'
147 for evolution to a finite separation (i.e., a finite orbital angular momentum), when Lf is not None.
148 The entries of the dictionary are failure_output
149 If hybrid_evol is set to True, entries 'tilt1_transition', 'tilt2_transition', 'phi12_transition', and 'f_transition' set as failure_output are appended to match the output of the hybrid evolution code.
150 """
151
152 if failure_mode == 'Error':
153 raise RuntimeError(failure_message)
154 else:
155 failure_message += " Returning %s for the tilts."%failure_output_string
156
157 warn(failure_message, RuntimeWarning)
158
159 if hybrid_evol:
160 hybrid_output_tilts = package_tilts(failure_output, failure_output, Lf, swap)
161 hybrid_output_tilts["tilt1_transition"] = failure_output
162 hybrid_output_tilts["tilt2_transition"] = failure_output
163 hybrid_output_tilts["phi12_transition"] = failure_output
164 hybrid_output_tilts["f_transition"] = failure_output
165 return hybrid_output_tilts
166
167 return package_tilts(failure_output, failure_output, Lf, swap)
Exception raised when the evolution finds that the system is nonprecessing to numerical accuracy.
def prec_avg_tilt_comp(m1, m2, chi1, chi2, tilt1, tilt2, phi12, fref, Lf=None, **kwargs)
Compute tilt angles at infinite separation or bounds and average value of tilt angles at finite separ...
def prec_avg_tilt_comp_vec_inputs(m1, m2, chi1_vec, chi2_vec, fref, L0_vec=None, Lf=None, du=1.e-3, ode_atol_base=1.e-8, ode_atol_inplane_spin_scaling=True, ode_atol_floor=1.e-13, ode_rtol=-1, method="lsoda", use_solve_ivp=False, solve_ivp_lsoda_min_step=0., use_fallback=True, du_fallback=1.e-5, ode_atol_fallback=1.e-13, ode_rtol_fallback=-1, method_fallback="lsoda", use_mpmath_fallback=True, mpmath_dps=30, ode_tol_mpmath=1.e-15, odefun_degree=None, polyroots_maxsteps=50, polyroots_extraprec=50, LPNorder=2, LPNspins=True, imag_tol=1.e-6, root_tol=1.e-6, lin_tol=-1, lin_tol_fallback=-1, root_tol_raise_err=False, failure_mode='None', version='v1')
Compute tilt angles at infinite separation or bounds and average value of tilt angles at finite separ...
def evolution_error_handling(failure_mode, failure_message, failure_output, failure_output_string, Lf, swap, hybrid_evol=False)
Take care of the error message or warning and returning something for the tilts when the precession-a...
def warning_formatter(message, category, filename, lineno, file=None, line=None)
def package_tilts(tilt1, tilt2, Lf, swap)
Package tilts to be returned by prec_avg_tilt_comp_vec_inputs() or prec_avg_tilt_comp() depending on ...