-
Notifications
You must be signed in to change notification settings - Fork 633
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
fix hankel overflow from high index/freq #2371
Conversation
# Fix hankel functions for large imaginary arguments and remove nans and infs when non-indexed | ||
scaled_hankel1 = lambda o, kr: hankel1e(o, kr) * np.exp(1j * kr - shift) | ||
scaled_hankel2 = lambda o, kr: hankel2e(o, kr) * np.exp(-1j * kr - shift) | ||
scaled_jv = lambda o, kr: jve(o, kr) * np.exp(np.abs(kr.imag) - shift) |
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 am now using the exponential hankel functions and pass in the following wrappers that scale by the inverse of the exponential to correctly pass in a hankel function (or bessel at the origin).
In the exponential I am "shifting" by some amount shift
, which really is just an extra factor being multiplied into the system. This is explained below:
# Find large imaginary argument hankel shift | ||
r, _ = self.get_r_rhat(X, X0) | ||
kr = (k * r).flatten() | ||
max_imag = np.abs(kr.imag[np.argmax(np.abs(kr.imag))]) | ||
max_float = int(np.log(float_info.max) / 2) | ||
shift = 0 if np.abs(max_imag) < max_float else max_imag - max_float |
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 use sys.float_info.max
to create a threshold. If the argument into the hankel functions (scale
component, reformulating with the exponential bessel functions would be useless because the overflow would instead still happen in my normalizing exponential term
If we want to use another way of deciding the threshold besides sys.float_info.max
then I can change it.
def get_r_rhat(self, X, X0): | ||
"""Returns r and rhat before normalizing rhat to be used in green2d and get_fields for overflow prediction""" |
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 created this new function to minimize the amount of repeated code because I now need the term get_fields
as well as green2d
.
o_fields2D = self.green2d( | ||
X[:, outgoing_arg][..., np.newaxis], |
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 am now passing in my masks for outgoing_arg
, incoming_arg
, and waist_points
before calling green2D to eliminate the overflows that were happening when the wrong hankel was being used for a given argument despite those indices of X
not being used. Before I was doing this while constructing the final fields2D
array.
So this changes the scaling of the resulting fields? I would suggest rescaling all the time, not just when (Unfortunately, this complicates the meaning of the beam amplitude parameter.) |
The scaling only changes the order of magnitude of the Hankel amplitudes. Phase is preserved. In addition, after calling green 2D where needed, the final fields are normalized such that the beam waist is amplitude 1. Thus, the scaling only affects the algorithm’s intermediate magnitudes, preserving the magnitude of the final output. Thus I wouldn’t expect a discontinuity in the output. in other words, when rescaling |
This should fix the issues with overflows from the hankel functions. I had to reformulate and manipulate a few things so I will explain in detail: