-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add rational fits #223
base: main
Are you sure you want to change the base?
add rational fits #223
Conversation
This PR is quite long, so I want to highlight the main changes
Other changes including the tests are straightforward. I Had to change a few things to make the tests pass because we have changed the default to |
Hi @vijayvarma392, this PR is now ready to be reviewed. I have summarized the main changes here. I think at this point, I would like to have your comments for making further changes. |
Dictionary of arguments to be passed to the rational | ||
fit function. Defaults are set using | ||
`utils.get_default_rational_fit_kwargs` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should indicate here already that only one of spline_kwargs or rational_fit_kwargs are allowed.
Question: Would it be better to have interp_kwargs, which has a key 'interp_type' that can be 'spline' or 'rational' fit? In the future, if we add extra options like Toni's PN inspired fits, that would make it easier.
This is more of a question for you rather than a suggestion because I don't know if that will make the code more complicated than it needs to be. Either way, needs to be clear that only one is allowed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use spline kwargs for things other than interpolating the omega_gw extrema. For example, we interpolate zeroecc data using spline. So providing just rational_fit kwargs won't work because rational_fit is only good for interpolating monotonic trends.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically we will need to make all interpolation thing work with a single method if we want the user to provide only one of them. Here, we wanted to use rational fit for the omega envelope mainly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you suggest?
gw_eccentricity/eccDefinition.py
Outdated
using models like SEOB or TEOB. | ||
- Faster to construct and evaluate. | ||
- Since it fits through every data point, it may exhibit oscillatory | ||
behavior, particularly near the merger. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
near the merger, especially for noisy NR data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
gw_eccentricity/eccDefinition.py
Outdated
modes from numerical simulations. | ||
- Better monotonic behaviour, particularly near the merger. | ||
- Significantly slower compared to the `spline` method. This is because | ||
finding optimal numerator and denominator degree needs several iterations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you say a rough number instead of "Significantly slower"?
gw_eccentricity/eccDefinition.py
Outdated
self.rational_fit_kwargs["verbose"] = self.debug_level | ||
# keep history of rational fit degree and nonmonotonicity of the corresponding fits | ||
self.rational_fit_nonmonotonicity_history = {"pericenters": {}, "apocenters": {}} | ||
# Update the degrees used to construct the final fits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the comment be: This is used to keep track and update the degrees used to construct the final fits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so I am using rational_fit_nonmonotonicity_history
to keep track of what degrees are being iterated over and the corresponding behaviour, i.e., is it nonmonotonic? And using rational_fit_degrees
to store the final degree used to build the fits. Instead of using "update the degrees", I changed it to "store degrees" to better convey the purpose.
gw_eccentricity/eccDefinition.py
Outdated
self.available_averaging_methods \ | ||
= self.get_available_omega_gw_averaging_methods() | ||
self.debug_level = self.extra_kwargs["debug_level"] | ||
# set verbose to debug_level. If verbose is True, then it prints information | ||
# of each iteration for rational fits for a given degree. | ||
self.rational_fit_kwargs["verbose"] = self.debug_level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just call it debug_level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"verbose" is the keyword used in the routine for rational fit, so I have kept that the same and instead assign value to it using debug_level
gw_eccentricity/eccDefinition.py
Outdated
@@ -1184,6 +1228,180 @@ def interp_extrema(self, extrema_type="pericenters"): | |||
raise Exception( | |||
f"Sufficient number of {extrema_type} are not found." | |||
" Can not create an interpolant.") | |||
|
|||
def get_rat_fit(self, x, y): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, don't like the name...come up with a way to not call the two things get_rat_fit and get_rational_fit? Easily confused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed get_rat_fit
to get_rational_fit_wrapper
gw_eccentricity/eccDefinition.py
Outdated
This function ensures that the rational fit uses the optimal degree for | ||
the numerator and denominator. It first checks for nonmonotonicity in the | ||
fit's derivative and lowers the degrees if necessary. Only if the initial | ||
degree was monotonic (no reduction needed), it attempts to increase the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Only if the initial degree was monotonic" --> "Only if the fit for the initial degree was monotonic"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
gw_eccentricity/eccDefinition.py
Outdated
# make sure that description is not None. A description is needed to | ||
# update the optimal values of the numerator and denominator degrees | ||
# used to build the final rational fit | ||
if description is None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
description --> data_name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
gw_eccentricity/eccDefinition.py
Outdated
fit's derivative and lowers the degrees if necessary. Only if the initial | ||
degree was monotonic (no reduction needed), it attempts to increase the | ||
degrees to find a higher-degree fit. If increasing the degrees causes | ||
nonmonotonicity, it reverts to the previous valid monotonic fit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Say something about how the initial degrees should be set? Through self.rational_fit_kwargs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
gw_eccentricity/eccDefinition.py
Outdated
# value is found by doing some iterations. | ||
if not (self.rational_fit_kwargs["num_degree"] and self.rational_fit_kwargs["denom_degree"]): | ||
self.rational_fit_kwargs["num_degree"], self.rational_fit_kwargs["denom_degree"] \ | ||
= self.get_approximate_degree_for_rational_fit() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this still work if the user gives only one of num_degree and denom_degree?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I have changed this part of the code so that it does the following: If both are None, i.e., unspecified only then use the function to set the approximate degree to both num and denom. If any one of the degrees is given, use it to set the other.
num_degree, denom_degree = 6, 6 | ||
else: | ||
num_degree, denom_degree = 5 + int(np.log10(approximate_num_orbits)), 5 + int(np.log10(approximate_num_orbits)) | ||
return num_degree, denom_degree |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you check for approximate_num_orbits <= 5 once, you don't need to check for approximate_num_orbits > 5 again in elif. Something like:
if orbits <= 5:
bla
elif orbits <= 20:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How did you arrive at these choices? Add some comments about how you got there and how important these particular choices are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
corrected. These are based on limited investigations. It needs a lot more tests to set more optimal values which I intend to do once this is merged. I have noted this using TODO at the top
gw_eccentricity/eccDefinition.py
Outdated
= self.get_approximate_degree_for_rational_fit() | ||
|
||
rat_fit = self.get_rat_fit(x, y) | ||
t = np.arange(x[0], x[-1], self.t[1] - self.t[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
best not to call this t. There is already a self.t, and the natural thing to do is to assume they are the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
gw_eccentricity/eccDefinition.py
Outdated
degrees_were_reduced = False | ||
|
||
# Check for nonmonotonicity and lower degrees if needed | ||
while self.check_if_domega_dt_is_nonmonotonic(t, rat_fit(t), 1.0, description): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the function be called something other than check_if_domega_dt_is_nonmonotonic
? Isn't the data allowed to be things other than omega?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I have changed it to check_if_first_derivative_is_not_strictly_monotonic
gw_eccentricity/eccDefinition.py
Outdated
debug_level=self.debug_level, important=False) | ||
|
||
rat_fit = self.get_rat_fit(x, y) | ||
# If no degrees were reduced, try increasing the degree for better fit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for a better fit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
gw_eccentricity/eccDefinition.py
Outdated
self.rational_fit_kwargs["num_degree"], self.rational_fit_kwargs["denom_degree"] \ | ||
= new_num_degree, new_denom_degree | ||
new_rat_fit = self.get_rat_fit(x, y) | ||
if self.check_if_domega_dt_is_nonmonotonic(t, new_rat_fit(t), 1.0, description): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this check happens twice for the same fit in some cases? Maybe rework the code so that that doesn't happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
gw_eccentricity/eccDefinition.py
Outdated
@@ -1597,6 +1814,33 @@ def measure_ecc(self, tref_in=None, fref_in=None): | |||
# return measured eccentricity, mean anomaly and reference time or | |||
# frequency where these are measured. | |||
return self.make_return_dict_for_eccentricity_and_mean_anomaly() | |||
|
|||
def build_omega_gw_extrema_interpolants(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a docstring explaining what it's doing and why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Add
rational_fit
as an alternative method to interpolate the omega at the extrema.This PR introduces a new option in
extra_kwargs
foromega_gw_extrema_interpolation_method
which defaults to the spline-based interpolation.omega_gw_extrema_interpolation_method
can be set to either of the following values:InterpolatedUnivariateSpline
withk=3
(as default).polyrat.StabilizedSKRationalApproximation
rational_fit
improves the fit to theomega_gw
at pericenter and apocenters, particularly near the merger wherespline
struggles to remain monotonic.