Skip to content

Commit

Permalink
replace omega22 -> omega_gw
Browse files Browse the repository at this point in the history
  • Loading branch information
md-arif-shaikh committed Jun 6, 2024
1 parent e7bf6ed commit 3700c93
Show file tree
Hide file tree
Showing 11 changed files with 863 additions and 691 deletions.
349 changes: 222 additions & 127 deletions examples/gw_eccentricity_demo.ipynb

Large diffs are not rendered by default.

921 changes: 487 additions & 434 deletions gw_eccentricity/eccDefinition.py

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions gw_eccentricity/eccDefinitionUsingAmplitude.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def __init__(self, *args, **kwargs):
"""
super().__init__(*args, **kwargs)
self.data_for_finding_extrema = self.get_data_for_finding_extrema()
self.label_for_data_for_finding_extrema = r"$A_{22}$"
self.label_for_data_for_finding_extrema = r"$A_{\mathrm{gw}}$"
self.method = "Amplitude"

def get_data_for_finding_extrema(self):
Expand All @@ -29,13 +29,13 @@ def get_data_for_finding_extrema(self):
In the derived classes, one need to override this function
to return the appropriate data that is to be used. For example,
in residual amplitude method, this function would return
residual amp22, whereas for frequency method, it would
residual amp_gw, whereas for frequency method, it would
return omega22 and so on.
"""
return self.amp22
return self.amp_gw

def find_extrema(self, extrema_type="pericenters"):
"""Find the extrema in the amp22.
"""Find the extrema in the amp_gw.
parameters:
-----------
Expand Down
12 changes: 6 additions & 6 deletions gw_eccentricity/eccDefinitionUsingAmplitudeFits.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __init__(self, *args, **kwargs):
dataDict: Dictionary containing the waveform data.
"""
super().__init__(*args, **kwargs)
self.data_str = "amp22"
self.data_str = "amp_gw"
self.label_for_data_for_finding_extrema = labelsDict[self.data_str]
self.label_for_fit_to_data_for_finding_extrema \
= labelsDict[f"{self.data_str}_fit"]
Expand All @@ -30,16 +30,16 @@ def __init__(self, *args, **kwargs):
"kwargs_for_fits_methods",
"eccDefinitionUsingAmplitudeFits.get_default_kwargs_for_fits_methods()")
self.set_fit_variables()
# Make a copy of amp22 and use it to set data_for_finding_extrema.
# Make a copy of amp_gw and use it to set data_for_finding_extrema.
# This would ensure that any modification of data_for_finding_extrema
# does not modify amp22.
self.data_for_finding_extrema = self.amp22.copy()
# does not modify amp_gw.
self.data_for_finding_extrema = self.amp_gw.copy()
# FIXME: Find a better solution
# It turns out that since in MKS units amplitude is very small
# The envelope fitting does not work properly. Maybe there is a better
# way to do this but scaling the amp22 data by its value at the global
# way to do this but scaling the amp_gw data by its value at the global
# peak (the merger time) solves this issue.
self.data_for_finding_extrema /= self.amp22_merger
self.data_for_finding_extrema /= self.amp_gw_merger

def get_default_kwargs_for_fits_methods(self):
"""Get default fits kwargs.
Expand Down
4 changes: 2 additions & 2 deletions gw_eccentricity/eccDefinitionUsingFrequency.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ def __init__(self, *args, **kwargs):
dataDict: Dictionary containing the waveform data.
"""
super().__init__(*args, **kwargs)
self.label_for_data_for_finding_extrema = r"$\omega_{22}$"
self.label_for_data_for_finding_extrema = r"$\omega_{\mathrm{gw}}$"
self.method = "Frequency"

def get_data_for_finding_extrema(self):
"""Get the data for extrema finding."""
return self.omega22
return self.omega_gw
94 changes: 47 additions & 47 deletions gw_eccentricity/eccDefinitionUsingFrequencyFits.py

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions gw_eccentricity/eccDefinitionUsingResidualAmplitude.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def __init__(self, *args, **kwargs):
"""
super().__init__(*args, **kwargs)
self.method = "ResidualAmplitude"
self.label_for_data_for_finding_extrema = r"$\Delta A_{22}$"
self.label_for_data_for_finding_extrema = r"$\Delta A_{\mathrm{gw}}$"

def check_and_raise_zeroecc_data_not_found(self, method):
"""Raise exception if zeroecc data not found for Residual method.
Expand Down Expand Up @@ -56,4 +56,4 @@ def check_and_raise_zeroecc_data_not_found(self, method):
def get_data_for_finding_extrema(self):
"""Get the data for extrema finding."""
self.check_and_raise_zeroecc_data_not_found("ResidualAmplitude")
return self.res_amp22
return self.res_amp_gw
4 changes: 2 additions & 2 deletions gw_eccentricity/eccDefinitionUsingResidualFrequency.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ def __init__(self, *args, **kwargs):
"""
super().__init__(*args, **kwargs)
self.method = "ResidualFrequency"
self.label_for_data_for_finding_extrema = r"$\Delta\omega_{22}$"
self.label_for_data_for_finding_extrema = r"$\Delta\omega_{\mathrm{gw}}$"

def get_data_for_finding_extrema(self):
"""Get the data for extrema finding."""
self.check_and_raise_zeroecc_data_not_found("ResidualFrequency")
return self.res_omega22
return self.res_omega_gw
131 changes: 69 additions & 62 deletions gw_eccentricity/gw_eccentricity.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,29 +63,32 @@ def measure_eccentricity(tref_in=None,
method="Amplitude",
dataDict=None,
num_orbits_to_exclude_before_merger=2,
precessing=False,
extra_kwargs=None):
"""Measure eccentricity and mean anomaly from a gravitational waveform.
Eccentricity is measured using the GW frequency omega22(t) =
dphi22(t)/dt, where phi22(t) is the phase of the (2, 2) waveform
mode. We currently only allow time-domain, nonprecessing waveforms. We
evaluate omega22(t) at pericenter times, t_pericenters, and build a
spline interpolant omega22_pericenters(t) using those data
points. Similarly, we build omega22_apocenters(t) using omega22(t) at
the apocenter times, t_apocenters.
Using omega22_pericenters(t) and omega22_apocenters(t), we first
compute e_omega22(t), as described in Eq.(4) of arXiv:2302.11257. We
then use e_omega22(t) to compute the eccentricity egw(t) using Eq.(8)
Eccentricity is measured using the GW frequency omega_gw(t) =
d(phase_gw)/dt, where phase_gw(t) is the phase of the (2, 2) waveform mode
for nonprecessing systems. See `eccDefinition.get_amp_phase_omega_gw` for
more details. We currently only allow time-domain, nonprecessing
waveforms. We evaluate omega_gw(t) at pericenter times, t_pericenters, and
build a spline interpolant omega_gw_pericenters(t) using those data
points. Similarly, we build omega_gw_apocenters(t) using omega_gw(t) at the
apocenter times, t_apocenters.
Using omega_gw_pericenters(t) and omega_gw_apocenters(t), we first
compute e_omega_gw(t), as described in Eq.(4) of arXiv:2302.11257. We
then use e_omega_gw(t) to compute the eccentricity e_gw(t) using Eq.(8)
of arXiv:2302.11257. Mean anomaly is defined using t_pericenters, as
described in Eq.(10) of arXiv:2302.11257.
To find t_pericenters/t_apocenters, one can look for extrema in different
waveform data, like omega22(t) or Amp22(t), the amplitude of the (2, 2)
mode. Pericenters correspond to the local maxima, while apocenters
correspond to the local minima in the data. The method option
(described below) lets the user pick which waveform data to use to find
t_pericenters/t_apocenters.
waveform data, like omega_gw(t) or amp_gw(t), the amplitude of the (2, 2)
mode for nonprecessing systems. See `eccDefinition.get_amp_phase_omega_gw`
for more details on amp_gw. Pericenters correspond to the local maxima,
while apocenters correspond to the local minima in the data. The method
option (described below) lets the user pick which waveform data to use to
find t_pericenters/t_apocenters.
Parameters
----------
Expand All @@ -99,11 +102,11 @@ def measure_eccentricity(tref_in=None,
tref_in/fref_in should be provided.
Given an fref_in, we find the corresponding tref_in such that
omega22_average(tref_in) = 2 * pi * fref_in. Here, omega22_average(t)
omega_gw_average(tref_in) = 2 * pi * fref_in. Here, omega_gw_average(t)
is a monotonically increasing average frequency obtained from the
instantaneous omega22(t). omega22_average(t) defaults to the orbit
averaged omega22, but other options are available (see
omega22_averaging_method below).
instantaneous omega_gw(t). omega_gw_average(t) defaults to the orbit
averaged omega_gw, but other options are available (see
omega_gw_averaging_method below).
Eccentricity and mean anomaly measurements are returned on a subset of
tref_in/fref_in, called tref_out/fref_out, which are described below.
Expand All @@ -115,22 +118,22 @@ def measure_eccentricity(tref_in=None,
method : str, default: ``Amplitude``
Which waveform data to use for finding extrema. Options are:
- "Amplitude": Finds extrema of Amp22(t).
- "Frequency": Finds extrema of omega22(t).
- "ResidualAmplitude": Finds extrema of resAmp22(t), the residual
amplitude, obtained by subtracting the Amp22(t) of the quasicircular
counterpart from the Amp22(t) of the eccentric waveform. The
- "Amplitude": Finds extrema of amp_gw(t).
- "Frequency": Finds extrema of omega_gw(t).
- "ResidualAmplitude": Finds extrema of resamp_gw(t), the residual
amplitude, obtained by subtracting the amp_gw(t) of the quasicircular
counterpart from the amp_gw(t) of the eccentric waveform. The
quasicircular counterpart is described in the documentation of
dataDict below.
- "ResidualFrequency": Finds extrema of resomega22(t), the residual
frequency, obtained by subtracting the omega22(t) of the
quasicircular counterpart from the omega22(t) of the eccentric
- "ResidualFrequency": Finds extrema of resomega_gw(t), the residual
frequency, obtained by subtracting the omega_gw(t) of the
quasicircular counterpart from the omega_gw(t) of the eccentric
waveform.
- "AmplitudeFits": Uses Amp22(t) and iteratively subtracts a
PN-inspired fit of the extrema of Amp22(t) from it, and finds extrema
- "AmplitudeFits": Uses amp_gw(t) and iteratively subtracts a
PN-inspired fit of the extrema of amp_gw(t) from it, and finds extrema
of the residual.
- "FrequencyFits": Uses omega22(t) and iteratively subtracts a
PN-inspired fit of the extrema of omega22(t) from it, and finds
- "FrequencyFits": Uses omega_gw(t) and iteratively subtracts a
PN-inspired fit of the extrema of omega_gw(t) from it, and finds
extrema of the residual.
The available list of methods can be also obtained from
Expand Down Expand Up @@ -205,7 +208,7 @@ def measure_eccentricity(tref_in=None,
- "t": 1d array of times.
- Should be uniformly sampled, with a small enough time step so
that omega22(t) can be accurately computed, if necessary. We use
that omega_gw(t) can be accurately computed, if necessary. We use
a 4th-order finite difference scheme. In dimensionless units, we
recommend a time step of dtM = 0.1M to be conservative, but one
may be able to get away with larger time steps like dtM = 1M. The
Expand Down Expand Up @@ -283,26 +286,28 @@ def measure_eccentricity(tref_in=None,
spline_kwargs:
Dictionary of arguments to be passed to the spline interpolation
routine (scipy.interpolate.InterpolatedUnivariateSpline) used to
compute quantities like omega22_pericenters(t) and
omega22_apocenters(t).
compute quantities like omega_gw_pericenters(t) and
omega_gw_apocenters(t).
Defaults are set using utils.get_default_spline_kwargs
extrema_finding_kwargs:
Dictionary of arguments to be passed to the extrema finder,
scipy.signal.find_peaks.
The Defaults are the same as those of scipy.signal.find_peaks,
except for the "width", which sets the minimum allowed "full width
at half maximum" for the extrema. Setting this can help avoid
false extrema in noisy data (for example, due to junk radiation in
NR). The default for "width" is set using phi22(t) near the
merger. Starting from 4 cycles of the (2, 2) mode before the
merger, we find the number of time steps taken to cover 2 cycles,
let's call this "the gap". Note that 2 cycles of the (2, 2) mode
are approximately one orbit, so this allows us to approximate the
at half maximum" for the extrema. Setting this can help avoid false
extrema in noisy data (for example, due to junk radiation in
NR). The default for "width" is set using phase_gw(t) near the
merger. For nonprecessing systems, phase_gw = phase of the (2, 2)
mode. Starting from 4 cycles of the (2, 2) mode before the merger,
we find the number of time steps taken to cover 2 cycles, let's
call this "the gap". Note that 2 cycles of the (2, 2) mode are
approximately one orbit, so this allows us to approximate the
smallest gap between two pericenters/apocenters. However, to be
conservative, we divide this gap by 4 and set it as the width
parameter for find_peaks. See
eccDefinition.get_width_for_peak_finder_from_phase22 for more
eccDefinition.get_width_for_peak_finder_from_phase_gw for more
details.
debug_level: int
Expand All @@ -320,31 +325,32 @@ def measure_eccentricity(tref_in=None,
`gwecc_{method}_*.pdf`.
Default is False.
omega22_averaging_method:
Options for obtaining omega22_average(t) from the instantaneous
omega22(t).
omega_gw_averaging_method:
Options for obtaining omega_gw_average(t) from the instantaneous
omega_gw(t). For nonprecessing systems, omega_gw(t) is the same as
the omega(t) of the (2, 2) mode. See `get_amp_phase_omega_gw` for
more details:
- "orbit_averaged_omega22": First, orbit averages are obtained at
each pericenter by averaging omega22(t) over the time from the
- "orbit_averaged_omega_gw": First, orbit averages are obtained at
each pericenter by averaging omega_gw(t) over the time from the
current pericenter to the next one. This average value is
associated with the time at midpoint between the current and the
next pericenter. Similarly, orbit averages are computed at
associated with the time at mid point between the current and the
next pericenter. Similarly orbit averages are computed at
apocenters. Finally, a spline interpolant is constructed between
all of these orbit averages at extrema locations. However, the
final time over which the spline is constructed is constrained to
be between tmin_for_fref and tmax_for_fref which are close to
tmin and tmax, respectively. See eccDefinition.get_fref_bounds()
for details.
- "mean_of_extrema_interpolants":
The mean of omega22_pericenters(t) and omega22_apocenters(t) is
used as a proxy for the average frequency.
- "omega22_zeroecc": omega22(t) of the quasicircular counterpart
- "mean_of_extrema_interpolants": The mean of
omega_gw_pericenters(t) and omega_gw_apocenters(t) is used as a
proxy for the average frequency.
- "omega_gw_zeroecc": omega_gw(t) of the quasicircular counterpart
is used as a proxy for the average frequency. This can only be
used if "t_zeroecc" and "hlm_zeroecc" are provided in dataDict.
See Sec. IID of arXiv:2302.11257 for a more detailed description of
"omega22_average".
Default is "orbit_averaged_omega22".
See Sec. IID of arXiv:2302.11257 for more detail description of
average omega_gw. Default is "orbit_averaged_omega_gw".
treat_mid_points_between_pericenters_as_apocenters:
If True, instead of trying to find apocenter locations by looking
Expand Down Expand Up @@ -400,9 +406,9 @@ def measure_eccentricity(tref_in=None,
tmin = max(t_pericenters[0], t_apocenters[0])
As eccentricity measurement relies on the interpolants
omega22_pericenters(t) and omega22_apocenters(t), the above cutoffs
omega_gw_pericenters(t) and omega_gw_apocenters(t), the above cutoffs
ensure that we only compute the eccentricity where both
omega22_pericenters(t) and omega22_apocenters(t) are within their
omega_gw_pericenters(t) and omega_gw_apocenters(t) are within their
bounds.
fref_out:
Expand All @@ -415,8 +421,8 @@ def measure_eccentricity(tref_in=None,
fref_out is set as
fref_out = fref_in[fref_in >= fref_min && fref_in <= fref_max],
where fref_min/fref_max are minimum/maximum allowed reference
frequency, with fref_min = omega22_average(tmin_for_fref)/2/pi
and fref_max = omega22_average(tmax_for_fref)/2/pi.
frequency, with fref_min = omega_gw_average(tmin_for_fref)/2/pi
and fref_max = omega_gw_average(tmax_for_fref)/2/pi.
tmin_for_fref/tmax_for_fref are close to tmin/tmax, see
eccDefinition.get_fref_bounds() for details.
Expand All @@ -438,7 +444,8 @@ def measure_eccentricity(tref_in=None,

if method in available_methods:
gwecc_object = available_methods[method](
dataDict, num_orbits_to_exclude_before_merger, extra_kwargs)
dataDict, num_orbits_to_exclude_before_merger,
precessing, extra_kwargs)
return_dict = gwecc_object.measure_ecc(
tref_in=tref_in, fref_in=fref_in)
return_dict.update({"gwecc_object": gwecc_object})
Expand Down
19 changes: 18 additions & 1 deletion gw_eccentricity/plot_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,5 +186,22 @@ def use_fancy_plotsettings(usetex=True, style="Notebook"):
"chi1z": r"$\chi_{1z}$",
"chi2z": r"$\chi_{2z}$",
"h22_real": r"Re[$\mathpzc{h}_{22}$]",
"chirp_mass": r"$\mathcal{M}$"
"chirp_mass": r"$\mathcal{M}$",
"amp_gw": r"$A_{\mathrm{gw}}$",
"phase_gw": r"$\Phi_{\mathrm{gw}}$",
"omega_gw": r"$\omega_{\mathrm{gw}}$",
"amp_gw_fit": r"$A^{\mathrm{fit}}_{\mathrm{gw}}$",
"omega_gw_fit": r"$\omega^{\mathrm{fit}}_{\mathrm{gw}}$",
"omega_gw_fit_pericenters": r"$\omega^{\mathrm{fit,p}}_{\mathrm{gw}}$",
"omega_gw_fit_apocenters": r"$\omega^{\mathrm{fit,a}}_{\mathrm{gw}}$",
"omega_gw_pericenters": r"$\omega^{\mathrm{p}}_{\mathrm{gw}}$",
"omega_gw_apocenters": r"$\omega^{\mathrm{a}}_{\mathrm{gw}}$",
"omega_gw_average": r"$\langle\omega_{\mathrm{gw}}\rangle$",
"omega_gw_average_dimless": r"$\langle\omega_{\mathrm{gw}}\rangle$ [rad/$M$]",
"f_gw_average": r"$\langle f_{\mathrm{gw}}\rangle$",
"f_gw_average_ref": r"$\langle f_{\mathrm{gw, ref}}\rangle$",
"f_gw_ref": r"$f_{\mathrm{gw, ref}}$",
"res_omega_gw": r"$\Delta\omega_{\mathrm{gw}}$",
"res_omega_gw_dimless": r"$\Delta\omega_{\mathrm{gw}}$ [rad/$M$]",
"res_amp_gw": r"$\Delta A_{\mathrm{gw}}$",
}
Loading

0 comments on commit 3700c93

Please sign in to comment.