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

Add Bounding Box to Field Line Integration #908

Merged
merged 14 commits into from
Mar 1, 2024
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Changelog
=========

- Adds a bounding box to the `field_line_integrate` defined by `bounds_R` and `bounds_Z` keyword arguments, which form a hollow cylindrical bounding box. If the field line trajectory exits these bounds, the RHS will be multiplied by `exp(-(R**2+Z**2))` to stop the trajectory and prevent tracing the field line out to infinity, which is both costly and unnecessary when making a Poincare plot, which is the principle purpose of the function.

v0.10.4
-------

Expand Down
46 changes: 43 additions & 3 deletions desc/magnetic_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,8 @@
rtol=1e-8,
atol=1e-8,
maxstep=1000,
bounds_R=(0, np.inf),
bounds_Z=(-np.inf, np.inf),
):
"""Trace field lines by integration.

Expand All @@ -1401,6 +1403,21 @@
relative and absolute tolerances for ode integration
maxstep : int
maximum number of steps between different phis
bounds_R : tuple of (float,float), optional
R bounds for field line integration bounding box.
If supplied, the RHS of the field line equations will be
multipled by exp(-r) where r is the distance from the origin,
dpanici marked this conversation as resolved.
Show resolved Hide resolved
this is meant to prevent the field lines which escape to infinity from
slowing the integration down by being traced to infinity.
defaults to (0,np.inf)
bounds_Z : tuple of (float,float), optional
Z bounds for field line integration bounding box.
If supplied, the RHS of the field line equations will be
multipled by exp(-r) where r is the distance from the origin,
dpanici marked this conversation as resolved.
Show resolved Hide resolved
this is meant to prevent the field lines which escape to infinity from
slowing the integration down by being traced to infinity.
Defaults to (-np.inf,np.inf)


Returns
-------
Expand All @@ -1419,12 +1436,35 @@
def odefun(rpz, s):
rpz = rpz.reshape((3, -1)).T
r = rpz[:, 0]
z = rpz[:, 2]

Check warning on line 1439 in desc/magnetic_fields.py

View check run for this annotation

Codecov / codecov/patch

desc/magnetic_fields.py#L1439

Added line #L1439 was not covered by tests
# if bounds are given, will decay the magnetic field line eqn
# RHS if the trajectory is outside of bounds to avoid
# integrating the field line to infinity, which is costly
# and not useful in most cases
decay_factor = jnp.where(

Check warning on line 1444 in desc/magnetic_fields.py

View check run for this annotation

Codecov / codecov/patch

desc/magnetic_fields.py#L1444

Added line #L1444 was not covered by tests
jnp.any(
jnp.array(
[
jnp.less(r, bounds_R[0]),
jnp.greater(r, bounds_R[1]),
jnp.less(z, bounds_Z[0]),
jnp.greater(z, bounds_Z[1]),
]
)
),
jnp.exp(-(r**2 + z**2)),
f0uriest marked this conversation as resolved.
Show resolved Hide resolved
1.0,
)

br, bp, bz = field.compute_magnetic_field(
rpz, params, basis="rpz", source_grid=source_grid
).T
return jnp.array(
[r * br / bp * jnp.sign(bp), jnp.sign(bp), r * bz / bp * jnp.sign(bp)]
).squeeze()
return (

Check warning on line 1462 in desc/magnetic_fields.py

View check run for this annotation

Codecov / codecov/patch

desc/magnetic_fields.py#L1462

Added line #L1462 was not covered by tests
decay_factor
* jnp.array(
[r * br / bp * jnp.sign(bp), jnp.sign(bp), r * bz / bp * jnp.sign(bp)]
).squeeze()
)

intfun = lambda x: odeint(odefun, x, phis, rtol=rtol, atol=atol, mxstep=maxstep)
x = jnp.vectorize(intfun, signature="(k)->(n,k)")(x0)
Expand Down
12 changes: 12 additions & 0 deletions tests/test_magnetic_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,18 @@ def test_field_line_integrate(self):
r, z = field_line_integrate(r0, z0, phis, field)
np.testing.assert_allclose(r[-1], 10, rtol=1e-6, atol=1e-6)
np.testing.assert_allclose(z[-1], 0.001, rtol=1e-6, atol=1e-6)
# test that bounds work correctly, and stop integration when trajectory
# hits the bounds
dpanici marked this conversation as resolved.
Show resolved Hide resolved
r0 = [10.1]
z0 = [0.0]
# this will hit the R bound
# (there is no Z bound, and R would go to 10.1 if not bounded)
r, z = field_line_integrate(r0, z0, phis, field, bounds_R=(10.05, np.inf))
np.testing.assert_allclose(r[-1], 10.05, rtol=1e-6)
# this will hit the Z bound
# (there is no R bound, and Z would go to 0.1 if not bounded)
r, z = field_line_integrate(r0, z0, phis, field, bounds_Z=(-np.inf, 0.05))
np.testing.assert_allclose(z[-1], 0.05, rtol=1e-6)

@pytest.mark.unit
def test_Bnormal_calculation(self):
Expand Down
Loading