Scattering Angles from EOB Data¶
This tutorial demonstrates how to compute scattering angles from hyperbolic encounters using Effective One Body (EOB) waveforms.
In hyperbolic encounters, two compact objects approach each other with sufficient energy to scatter rather than merge. The scattering angle quantifies the deflection of the trajectory.
Setup¶
First, we import the necessary modules:
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
import PyART.models.teob as teob
from PyART.analysis.scattering_angle import ScatteringAngle
import matplotlib.pyplot as plt
from PyART.utils.utils import D1
import numpy as np
WARNING: TEOBResumS not installed.
Define Configurations¶
We’ll test several different impact parameters (b) to see how they affect the scattering angle. Each configuration has:
b: impact parameter
chi1, chi2: dimensionless spins
E0: initial energy
p: dimensionless momentum parameter
configurations = [
{'b': 9.678, 'chi1':0., 'chi2':0., 'E0':1.0226, 'p':0.11456439, 'eob':None, 'scat':None},
{'b':10.000, 'chi1':0., 'chi2':0., 'E0':1.0226, 'p':0.11456439, 'eob':None, 'scat':None},
{'b':11.000, 'chi1':0., 'chi2':0., 'E0':1.0226, 'p':0.11456439, 'eob':None, 'scat':None},
{'b':12.000, 'chi1':0., 'chi2':0., 'E0':1.0226, 'p':0.11456439, 'eob':None, 'scat':None},
{'b':13.000, 'chi1':0., 'chi2':0., 'E0':1.0226, 'p':0.11456439, 'eob':None, 'scat':None},
]
n_conf = len(configurations)
# Initial separation and symmetric mass ratio
r0 = 100
nu = 0.25
Generate EOB Data and Compute Scattering Angles¶
For each configuration, we:
Set up the EOB parameters
Generate the EOB waveform
Compute the scattering angle (if not a capture)
cutoff_min = 25
for i in range(n_conf):
conf = configurations[i]
J0 = conf['p']*conf['b']/nu
eobpars = teob.CreateDict(r_hyp=r0, H_hyp=conf['E0'], J_hyp=J0, q=1,
chi1z=conf['chi1'], chi2z=conf['chi2'])
eob = teob.Waveform_EOB(pars=eobpars)
conf['eob'] = eob
E_final = eob.dyn['E'][-1]
print(f"Configuration {i+1}:")
print(f" Impact parameter b = {conf['b']:.3f}")
print(f" E0, J0 = {conf['E0']:.5f}, {J0:.5f}")
print(f" Final energy = {E_final:.5f}")
if E_final > 1:
# Scattering event (not a capture)
scat = ScatteringAngle(puncts=eob.dyn, nmin=2, nmax=10, n_extract=None,
hypfit=True,
r_cutoff_in_low=cutoff_min, r_cutoff_in_high=eob.dyn['r'][0],
r_cutoff_out_low=cutoff_min, r_cutoff_out_high=None, verbose=False)
conf['scat'] = scat
print(f" Scattering angle χ = {scat.chi:.2f}°")
else:
print(' Result: Capture!')
print()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[3], line 8
4 J0 = conf['p']*conf['b']/nu
6 eobpars = teob.CreateDict(r_hyp=r0, H_hyp=conf['E0'], J_hyp=J0, q=1,
7 chi1z=conf['chi1'], chi2z=conf['chi2'])
----> 8 eob = teob.Waveform_EOB(pars=eobpars)
9 conf['eob'] = eob
10 E_final = eob.dyn['E'][-1]
File /opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/site-packages/PyART/models/teob.py:27, in Waveform_EOB.__init__(self, pars)
25 self.pars = pars
26 self._kind = "EOB"
---> 27 self._run_py()
28 pass
File /opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/site-packages/PyART/models/teob.py:61, in Waveform_EOB._run_py(self)
59 self.domain = "Freq"
60 else:
---> 61 t, hp, hc, hlm, dyn = EOB.EOBRunPy(self.pars)
62 self._u = t
63 hlm_conv = convert_hlm(hlm)
NameError: name 'EOB' is not defined
Visualize Results¶
Now let’s plot the results for all scattering configurations:
Real part of the (2,2) mode strain
The Weyl scalar ψ₄
Radial distance vs time
Trajectories in the x-y plane with scattering angles
plt.figure(figsize=(12,9))
for conf in configurations:
eob = conf['eob']
scat = conf['scat']
if scat is None:
continue
# Plot waveform
plt.subplot(2,2,1)
plt.plot(eob.u, eob.hlm[(2,2)]['real'])
plt.xlim([-100, 100])
plt.xlabel('Time (M)')
plt.ylabel(r'Re[$h_{22}$]')
plt.title('Waveform (2,2) mode')
plt.grid(True, alpha=0.3)
# Plot psi4
dh = D1(eob.hlm[(2,2)]['z'], eob.u, 4)
psi4 = D1(dh, eob.u, 4)
b = conf['b']
chi_BH = conf['chi1']
plt.subplot(2,2,2)
plt.plot(eob.u, -psi4.real, label=f'b={b:.3f}, χ={chi_BH}')
plt.xlim([-100, 100])
plt.xlabel('Time (M)')
plt.ylabel(r'Re[$-\psi_4$]')
plt.title('Weyl scalar')
plt.legend()
plt.grid(True, alpha=0.3)
# Plot radial distance
x = eob.dyn['r']*np.cos(eob.dyn['phi'])
y = eob.dyn['r']*np.sin(eob.dyn['phi'])
r = np.sqrt(x**2 + y**2)
plt.subplot(2,2,3)
plt.plot(eob.dyn['t'], r)
plt.xlabel('Time (M)')
plt.ylabel('Radial distance r (M)')
plt.title('Radial distance vs time')
plt.grid(True, alpha=0.3)
# Plot trajectory
plt.subplot(2,2,4)
plt.plot(x, y, label=f'χ={scat.chi:.2f}°')
plt.xlabel('x (M)')
plt.ylabel('y (M)')
plt.title('Trajectories with scattering angles')
plt.legend()
plt.grid(True, alpha=0.3)
plt.axis('equal')
plt.tight_layout()
plt.show()
Summary¶
This tutorial demonstrated:
How to set up hyperbolic encounter parameters
How to generate EOB waveforms for scattering scenarios
How to compute scattering angles using the
ScatteringAngleclassHow to visualize the waveforms and trajectories
The scattering angle provides important information about the dynamics of hyperbolic encounters and can be used to validate EOB models against numerical relativity simulations.