-
Notifications
You must be signed in to change notification settings - Fork 22
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
ENHANCEMENT: Autograd to jax #319
base: dev
Are you sure you want to change the base?
Conversation
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.
Thanks for working on this! @jorgeypcb I made some comments throughout the code changes just to clarify certain changes and questions that I have. Just one larger item: the examples/tutorials also use autograd and will need to be updated too - I expect this will be simpler after updating all the source code but wanted to make sure you are aware.
As you make more updates, you should be able to just update this PR and don't need to make a new one.
tests/test_core.py
Outdated
|
||
import jax.numpy as jnp | ||
from jax import vmap | ||
from jax import jit |
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 explain why these need to be added to the tests since autograd is not used here?
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.
Because of the integration of Jax arrays in the core functions. I used JAX arrays in a lot of places for improved performance and compatibility with JAX's ecosystems. So I needed to modify some tests to specifically deal with those
# Set a tolerance or delta value | ||
tolerance = 1e-6 # You can adjust this based on your precision requirements | ||
zero_freq_check = jnp.allclose(modified_column, 1.0, atol=tolerance) | ||
assert zero_freq_check |
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.
Seems like test_zero_freq() should work fine as it was. Does this avoid an anticipated error?
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.
There are some numerical precision issues due to floating point arithmetic discrepancies with JAX arrays that were very annoying because they barely broke most of the tests with a very small margin.
zero_freq_check = jnp.allclose(modified_column, 1.0, atol=tolerance) | ||
assert zero_freq_check | ||
|
||
def test_time_zero(self, time_mat_sub, nfreq_tm): |
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.
Same question as above. I see the value of printing here though.
@@ -1022,7 +1052,8 @@ def test_hydrodynamic_impedance(self, data, hydro_data): | |||
@pytest.fixture(scope="class") | |||
def tol(self, data): | |||
"""Tolerance for function :python:`check_impedance`.""" | |||
return 0.01 | |||
# Use a relative tolerance with a scaling factor | |||
return 0.1 |
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 increase this tolerance?
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.
It was a similar problem with small margins due to the new JAX related calculations being introduced.
@@ -1544,7 +1576,7 @@ def test_error_spacing(self,): | |||
""" | |||
with pytest.raises(ValueError): | |||
freq = [0, 0.1, 0.2, 0.4] | |||
wot.frequency_parameters(freq) | |||
wot.frequency_parameters(jnp.array(freq)) |
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 function not evaluate if not a jax array?
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.
Yes that is right, I explicitly needed to convert the freq list with a JAX array before passing it to frquency_parameters because of the JAX operations related changes I made to frequency_parameters
x_wec = [0, amp, 0, 0] | ||
x_opt = [pid_p,] | ||
x_wec = np.array([0, amp, 0, 0]) | ||
x_opt = np.array([pid_p,]) |
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.
Are these necessary for the shift to JAX? And for any call to pto.force()?
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.
Are these necessary for the shift to JAX? And for any call to pto.force()?
If they are I don't think it is a big deal, because the user does not create x_wec
or x_opt
manually (except potentially x_wec_0
and x_opt_0
).
+ np.abs(delta) | ||
_log.warning( | ||
f'Real part of impedance for {dof} has negative or close to ' + | ||
f'zero terms. Shifting up by {delta:.2f}') |
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.
The damping shift should still be included here.
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.
Just added the damping shift back and checked that the test still passes. Thank you mentioning that
@@ -2494,7 +2533,7 @@ def frequency_parameters( | |||
return f1, nfreq | |||
|
|||
|
|||
def time_results(fd: DataArray, time: DataArray) -> ndarray: | |||
def time_results(fd: DataArray, time: DataArray) -> DataArray: |
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.
Is this changed because a function does not accept the JAX array?
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.
Yes, it was just for consistency with the DataArray inputs and the seamless integration with the xarray ecosystem DataArrays have
wecopttool/pto.py
Outdated
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 pto.py and waves.py are still being updated so will wait to add comments to those
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.
Yes, it passed all the tests but I am working on it because of problems with waves
print("rdir:", rdir) | ||
print("pow:", pow) | ||
print("s_param:", s_param) | ||
print("cs:", cs) |
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.
I don't think we should print these to maintain consistency with the rest of the waves.py functions.
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.
Those I was using for debugging the problems I was having with the waves test, I already removed them and I will make sure when I push the test_wave.py fully working, I don't leave any fugitive prints behind.
wecopttool/core.py
Outdated
@@ -59,12 +59,15 @@ | |||
from pathlib import Path | |||
import warnings | |||
from datetime import datetime | |||
|
|||
import xarray as xr |
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.
import xarray as xr |
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.
xarray is imported twice (it is imported below). Style: blank line between standard library imports and third party imports.
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.
Thank you! Good catch
wecopttool/core.py
Outdated
print("Size of time_mat after set and before slicing:", np.size(time_mat)) | ||
time_mat = time_mat.at[:, 1::2].set(np.cos(wt[:, :time_mat.shape[1] // 2])) | ||
print("Size of time_mat after set and slicing:", np.size(time_mat)) | ||
print("Final shape of time_mat:", time_mat.shape) |
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.
remove print statements or use the logger with level=debug
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.
good catch, I was using those for myself and missed them. Thank you
tests/test_waves.py
Outdated
print("wdir_mean:", wot.degrees_to_radians(wdir_mean)) | ||
print("directions:", directions) | ||
print("integral_f:", integral_f) | ||
print("argmax direction:", wot.degrees_to_radians(directions[np.argmax(integral_f)], True)) |
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 shouldn't have print statements in the tests. If these should be checked use assert
.
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.
Those I was using at the time when working on the wave test file, that test I actually already passed and deleted them but I have one more error to go, I am having some differences between the values of S_data and pm_spectrum on the assertion and right now the max difference I am seeing at a given index is 1.8, so a tolerance of 2 passes the test but that is too much don't you think? I thought this was a good time to ask you that. I a exploring why the JAX changes moved these calculations but I still can't quite figure it out , it really shouldn't have. but that test_time_series is the only one I have left throwing an error, that is the good news. The other 30 passed.
x_wec = [0, amp, 0, 0] | ||
x_opt = [pid_p,] | ||
x_wec = np.array([0, amp, 0, 0]) | ||
x_opt = np.array([pid_p,]) |
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.
Are these necessary for the shift to JAX? And for any call to pto.force()?
If they are I don't think it is a big deal, because the user does not create x_wec
or x_opt
manually (except potentially x_wec_0
and x_opt_0
).
Looking good! I added some minor comments. |
@jorgeypcb |
We could try! I will be testing that today and if it works I will see how it compares to the other pull request I did where I used the original setup with some slight changes to get it to work with cyipopt minimize_ipopt, to see which option is better. I did that pull request with my RageTech account 👍 |
Description
This PR is a demonstration of the changes being made to the source code in order to transition from autograd to jax FIX #118 .
Type of PR
Checklist for PR
Additional details