Skip to content
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

ag/cross section fix #428

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft

ag/cross section fix #428

wants to merge 2 commits into from

Conversation

andrewgiuliani
Copy link
Contributor

I have used the Surface.cross_section algorithm on the entire QUASR database, and notice that very infrequently, the algorithm fails, see below

image

I rewrote the algorithm, making it simpler, to fix the bug. Rerunning the new algorithm on the entire dataset, I can't find any incorrect cross sections anymore.

image

Note that the jagged cross section where varphi=0 is because it uniformly samples the cross section in the Boozer theta angle, which may be insufficient as you can see.

@andrewgiuliani andrewgiuliani requested review from mp5650 and removed request for mp5650 November 7, 2024 16:54
Copy link
Contributor

@mishapadidar mishapadidar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your logic is correct. Most of the notes are for readability and code clean up. Still a bit confused on how the algorithm works though, namely the use of the put_angle_between_left_and_right function.

@@ -333,19 +340,15 @@ def cross_section(self, phi, thetas=None):
single curve.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a description of the arguments, i.e.

inputs
-------
phi: float, cylindrical angle between [0, 2pi] defining the cross section.
thetas: optional, Union[int, arrayLike, None]. Poloidal angle values at which to evaluate the surface on the cross section. If thetas is an integer, then the same number of evenly spaced points are used. Alternatively, thetas can be an array of poloidal angles values between [0,1]. 

@@ -333,19 +340,15 @@ def cross_section(self, phi, thetas=None):
single curve.
"""

# phi is assumed to be between [-pi, pi], so if it does not lie on that interval
# phi is assumed to be between [0, 2*pi], so if it does not lie on that interval
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make phi and theta follow the same convention, i.e. both in [0,1]?

@@ -333,19 +340,15 @@ def cross_section(self, phi, thetas=None):
single curve.
"""

# phi is assumed to be between [-pi, pi], so if it does not lie on that interval
# phi is assumed to be between [0, 2*pi], so if it does not lie on that interval
# we shift it by multiples of 2pi until it does
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be correcting the inputs or expecting phi to be within a range? If we expect phi in [0, 1] or [0, 2pi] then we users should coerce their inputs to [0, 1] or [0, 2pi]? We would then can replace this code with assert (0 <= phi) & (phi <= 1), "phi must be in [0,1]. If we make this change, we should look to make sure we aren't breaking usage in other functions.

Alternatively, in the docstring we could specify that any value of phi is acceptable. Then this code would stay.
What do you think?

cyl_phi_right = cyl_phi[1, :]

phi = phi*np.ones(varphi_left.size)
def put_angle_between_left_and_right(angle, left_bound, right_bound):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add some description. function name says angle, is that phi or varphi?

phi = phi - 2. * np.pi
if phi < -np.pi:
phi = phi + 2. * np.pi

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if phi is the cylindrical phi for our surface, can we just return the points from gamma?

angle = np.arctan2(gamma[:, 1], gamma[:, 0])
angle = np.where(angle < 0, angle+2*np.pi, angle)
shifted_angle = put_angle_between_left_and_right(angle, left_bound, right_bound)
return shifted_angle

def bisection(phia, a, phic, c):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use scipy bisection or root finding?

cyl_phi_right = cyl_phi[idx_right, np.arange(idx_right.size)]

# this function converts varphi to cylindrical phi, ensuring that the returned angle
# lies between left_bound and right_bound.
def varphi2phi(varphi_in, left_bound, right_bound):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

describe a little here as well

k = np.ceil((left_bound-angle)/(2*np.pi))
shifted_angle = angle + 2*np.pi * k
if not np.all((left_bound <= shifted_angle) & (shifted_angle <= right_bound)):
import ipdb;ipdb.set_trace()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove debugging code?

cyl_phi = np.where(cyl_phi < 0, cyl_phi + 2*np.pi, cyl_phi)
cyl_phi[1, :] += 2*np.pi # second row is the same as the first row, but shifted by 2pi

varphi_left = varphigrid[0, :]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we trying to determine bisection bounds here?

@@ -425,7 +411,8 @@ def bisection(phia, a, phic, c):
err = np.max(np.abs(a - c))
b = (a + c) / 2.
return b


phi = put_angle_between_left_and_right(phi, cyl_phi_left, cyl_phi_right)
# bisect cyl_phi to compute the cross section
sol = bisection(cyl_phi_left, varphi_left, cyl_phi_right, varphi_right)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just trying to understand here: it looks like, for each theta, we are doing a bisection over varphi, so that varphi2phi(varphi) = phi. Why do we need to know cyl_phi_right and cyl_phi_left?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants