Skip to content
Open
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
e930a2e
initial commit to add a quadcoil-based objective. A direct interface …
lankef Apr 4, 2025
69a5e87
initial commit of the QUADCOIL objective, tweaking 2 control flows in…
lankef Apr 7, 2025
74892d8
still debugging instability
lankef Apr 8, 2025
395d8f9
Improving printing
Apr 9, 2025
6426650
Initial commit about single-stage
lankef Sep 23, 2025
925e19e
fixing init
lankef Sep 23, 2025
773651e
Updating QuadcoilObject
Sep 24, 2025
c36d534
Completing QUADCOIL single-stage interface, testing
Sep 24, 2025
dc6a65e
Renaming and minor bug fixes
Sep 24, 2025
45e88d8
Fixes for static attrs
Sep 24, 2025
f243182
Fixes for static attrs
Sep 24, 2025
59ec216
Merge remote-tracking branch 'origin/master' into ffu/quadcoil
Sep 24, 2025
a7c368f
Merge remote-tracking branch 'origin/master' into ffu/quadcoil
Sep 29, 2025
87c86e4
Merge remote-tracking branch 'origin/master' into ffu/quadcoil
Oct 10, 2025
7e6d350
Testing for static argument error
Oct 10, 2025
6507199
Fixing quadcoil
Oct 17, 2025
c4300f5
Adding simsopt curve conversion
Oct 20, 2025
c4754d4
Accommodating external fields in QuadcoilProxy
Oct 22, 2025
25e96af
Minor changes
Oct 29, 2025
3afd240
QuadcoilField first working. Adding external coil support.
Nov 7, 2025
e47c443
Fixing single stage. Re-organizing quadcoil-related codes to reduce c…
Nov 26, 2025
8d8de33
minor fix, registering quadcoilfield.
Dec 4, 2025
b96e3db
Fixing data_index for quadcoilfield
Dec 4, 2025
18e82c0
Adding conversion from QuadcoilProxy to QuadcoilField for cutting
Dec 16, 2025
a5455f8
Minor update. Attempting to write a quadcoil proxy-> quadcoilfield co…
Dec 23, 2025
1d0ff07
Minor correction, fixing coil conversion to follow simsopt updates
Jan 22, 2026
0ecd9f1
Merge remote-tracking branch 'origin/master' into ffu/quadcoil
Jan 23, 2026
b6fea15
Moving `_set_tight_layout` from line 988 to 973 to avoid RuntimeError…
Feb 12, 2026
8fa750d
removing quadcoil single-stage files that are immature and not ready …
Feb 23, 2026
7b576d1
removing quadcoil single-stage files that are immature and not ready …
Feb 23, 2026
218ba1a
Cleanup, completing QuadcoilProxy -> FourierCurrentPorentialField con…
Feb 23, 2026
312c961
Minor fix, starting documentation
Feb 24, 2026
778f77b
Merge remote-tracking branch 'origin/master' into ffu/quadcoil-qss-pr…
Feb 24, 2026
39d5bea
Adding a QUADCOIL test case. Cleaning up quadcoil integration.
Mar 3, 2026
06c74ff
Adding docstrings
Mar 3, 2026
702d446
Merge branch 'master' into ffu/quadcoil-qss-pre-commit
lankef Mar 3, 2026
1cfc920
Responding to Rory Conlin's comments
Mar 6, 2026
66250f0
Updating docstring
Mar 6, 2026
61c5c12
Fixing docstring
Mar 12, 2026
9faf614
Add QuadcoilProxy objective to API documentation
lankef Mar 25, 2026
fcd9cc1
Update docstring default values for metric parameters in _quadcoil.py
lankef Mar 25, 2026
cf3ad2b
Renaming compute_full to solve_quadcoil and compute_surface_current_f…
Mar 25, 2026
13d3ad2
Merge branch 'ffu/quadcoil-qss-pre-commit' of https://github.com/Plas…
Mar 25, 2026
2ea1032
Merge branch 'master' into ffu/quadcoil-qss-pre-commit
YigitElma Apr 2, 2026
7dfc348
Merge branch 'master' into ffu/quadcoil-qss-pre-commit
dpanici Apr 16, 2026
4090f6a
a minor renaming (solve_quadcoil_surface_current_field --> solve_quad…
Apr 24, 2026
73a1afe
Merge branch 'ffu/quadcoil-qss-pre-commit' of https://github.com/Plas…
Apr 24, 2026
eaff201
Notebook update to switch from simsopt plotting to desc plotting.
Apr 24, 2026
90c862c
Update desc/geometry/curve.py
lankef May 2, 2026
9871de1
formatting docstring
May 2, 2026
887dfc0
Merge branch 'ffu/quadcoil-qss-pre-commit' of https://github.com/Plas…
May 2, 2026
4942d9d
formatting warnings with f-string to improve readability. Formatting …
May 2, 2026
d947a56
moving static_attrs definitions to right after the docstring.
May 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions desc/coils.py
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,33 @@ def from_values(cls, current, coords, N=10, s=None, basis="xyz", name=""):
name=name,
)

@classmethod
def from_simsopt(coil_simsopt, name=""):
Comment thread
dpanici marked this conversation as resolved.
"""Load a simsopt coil as a FourierXYZCoil.

Parameters
----------
coil_simsopt : simsopt.field.Coil
A simsopt coil
name : str
Name for this coil.

Returns
-------
coil : FourierXYZCoil
A FourierXYZCoil.
"""
current = coil_simsopt.current.get_value()
curve = FourierXYZCurve.from_simsopt(coil_simsopt.curve)
return FourierXYZCoil(
current=current,
X_n=curve.X_n,
Y_n=curve.Y_n,
Z_n=curve.Z_n,
modes=curve.X_basis.modes[:, 2],
name=name,
)


class FourierPlanarCoil(_Coil, FourierPlanarCurve):
"""Coil that lies in a plane.
Expand Down
44 changes: 44 additions & 0 deletions desc/geometry/curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,50 @@ def from_values(cls, coords, N=10, s=None, basis="xyz", name=""):
X_n=X_n, Y_n=Y_n, Z_n=Z_n, modes=basis.modes[:, 2], name=name
)

@classmethod
def from_simsopt(curve_simsopt, name=""):
Comment thread
dpanici marked this conversation as resolved.
"""Load a simsopt CurveXYZFourier as a FourierXYZCurve.

Parameters
----------
coil_simsopt : simsopt.geo.CurveXYZFourier
A simsopt curve
name : str
Name for this curve.

Returns
-------
coil : FourierXYZCurve
A FourierXYZCurve.
"""
try:
from simsopt.geo import CurveXYZFourier
except ModuleNotFoundError:
raise ModuleNotFoundError(
"desc.geometry.from_simsopt requires a " "simsopt installation"
Comment thread
lankef marked this conversation as resolved.
Outdated
)
if not isinstance(curve_simsopt, CurveXYZFourier):
raise AttributeError("The imput curve must be a Simsopt CurveXYZFourier")
dofs = curve_simsopt.get_dofs()
order = curve_simsopt.order
# [xc0, xs1, xc1, ....]
x = dofs[: 2 * order + 1]
y = dofs[2 * order + 1 : 4 * order + 2]
z = dofs[4 * order + 2 :]

def convert_x(x):
xc = x[::2]
xs = x[1:][::2]
xn = np.concatenate((np.flip(xs), xc))
return xn

xn = convert_x(x)
yn = convert_x(y)
zn = convert_x(z)
modes = np.arange(-order, order + 1)
curve_desc = FourierXYZCurve(xn, yn, zn, modes=modes, name=name)
return curve_desc

def _get_ess_scale(self, alpha=1.2, order=np.inf, min_value=1e-7):
"""Create x_scale using exponential spectral scaling.

Expand Down
2 changes: 1 addition & 1 deletion desc/io/optimizable_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def _make_hashable(x):

def _unmake_hashable(x):
# turn tuple of ints and shape to ndarray
if isinstance(x, tuple) and x[0] == "ndarray":
if isinstance(x, tuple) and len(x) and x[0] == "ndarray":

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think it hurts to have it, but why did you need this change?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The default values for some QUADCOIL arguments are empty list/tuples (I had to do it because the adjoint derivative is wrapped in a vjp rule before handed to DESC and this way some flows are simpler). Without this check it breaks DESC Optimizable.

return np.array(x[2]).reshape(x[1])
if isinstance(x, list):
return [_unmake_hashable(y) for y in x]
Expand Down
1 change: 1 addition & 0 deletions desc/objectives/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
)
from ._power_balance import FusionPower, HeatingPowerISS04
from ._profiles import Pressure, RotationalTransform, Shear, ToroidalCurrent
from ._quadcoil import QuadcoilProxy
from ._stability import BallooningStability, MagneticWell, MercierStability
from .getters import (
get_equilibrium_objective,
Expand Down
Loading
Loading