Skip to content

SurfaceCurve class and related optimization features - #2285

Open
singh-jaydeep wants to merge 34 commits into
masterfrom
js/surface-curve-consolidation
Open

SurfaceCurve class and related optimization features#2285
singh-jaydeep wants to merge 34 commits into
masterfrom
js/surface-curve-consolidation

Conversation

@singh-jaydeep

@singh-jaydeep singh-jaydeep commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Adds a new SurfaceCurve class, representing curves which are constrained to lie on a (toroidal) surface. This PR is meant to integrate the features added in the open PRs #819, #844, and replaces #2081.

Features

  • FourierRZSurfaceCurve class represents curves on a FourierRZToroidalSurface which can link poloidally or toroidally, and may circulate many times before closing. Parameterized using Fourier series for (theta(s), zeta(s)), s in [0,2pi). FourierRZSurfaceCoil is the coil version. These curves require either a surface or equilibrium as input. In the latter case, the surface is just the rho=1 flux surface.
  • SurfaceCurveConsistency is a linear objective which accepts a surface/equilibrium and a FourierRZSurfaceCurve, computing the difference between the surface/equilibrium.surface's params and those of the curve. Should be used in optimization when the underlying surface appears across different objectives. This also supports coilsets.
  • UmbilicHighCurvature is an objective from Adding a separate factor for NFP to calculate umbilic configurations #819. It computes the second principal curvature of the surface at points along the curve, pushing it to be more negative.

Notes

  • For surface curve coils to work with NFP and sym, they need to implement rigid transformations like rotmat and shift. I set them to the identity and zero vector, respectively, but they do not make a lot of sense for surface curves. And since they are optimizable, pretty much all optimizations involving surface curves will need a FixParameters(curve, {"rotmat":True, "shift": True}). Not sure if there is a way around this.
  • By default, all surface curves have the associated surface R_lmn, Z_lmn parameters as optimizable. So if you are optimizing a surface curve and don't want the surface to vary, users need to add FixParameteres(curve, {"R_lmn": True, "Z_lmn": True}).

To Do

  • Actually run some optimizations to make sure things are working. Update: Added a notebook (and html file, since I cannot get the plotly images to render on github for some reason) showing two optimizations. One is comparing REGCOIL + coil cutting to direct optimization of surface curves. The second roughly copies Rahul's umbilic curve optimization for the US131 equilibrium in the umbilic stellarators paper.
  • docs/tests

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Memory benchmark result

|               Test Name                |      %Δ      |    Master (MB)     |      PR (MB)       |    Δ (MB)    |    Time PR (s)     |  Time Master (s)   |
| -------------------------------------- | ------------ | ------------------ | ------------------ | ------------ | ------------------ | ------------------ |
  test_objective_jac_w7x                 |   -0.21 %    |     4.248e+03      |     4.239e+03      |    -8.79     |       32.89        |       30.00        |
  test_proximal_jac_w7x_with_eq_update   |   -0.28 %    |     6.830e+03      |     6.811e+03      |    -19.14    |       160.99       |       159.70       |
  test_proximal_freeb_jac                |    0.12 %    |     1.353e+04      |     1.354e+04      |    15.95     |       85.13        |       82.71        |
  test_proximal_freeb_jac_blocked        |    0.04 %    |     7.884e+03      |     7.887e+03      |     2.78     |       73.80        |       71.27        |
  test_proximal_freeb_jac_batched        |    0.02 %    |     7.878e+03      |     7.880e+03      |     1.63     |       72.15        |       70.54        |
  test_proximal_jac_ripple               |   -0.26 %    |     3.817e+03      |     3.807e+03      |    -9.80     |       56.46        |       55.70        |
  test_proximal_jac_ripple_bounce1d      |   -1.07 %    |     3.979e+03      |     3.936e+03      |    -42.70    |       71.13        |       69.10        |
  test_eq_solve                          |   -0.28 %    |     1.813e+03      |     1.808e+03      |    -5.09     |       54.16        |       53.28        |
  test_objective_quadratic_flux_jac      |    1.00 %    |     1.880e+03      |     1.899e+03      |    18.76     |       36.86        |       35.44        |

For the memory plots, go to the summary of Memory Benchmarks workflow and download the artifact.

singh-jaydeep and others added 14 commits August 7, 2026 17:48
Reconciles local work (Aug 16-18) with the remote-side commits (Aug 11-12).

Conflict in desc/geometry/curve.py (FourierRZSurfaceCurve.__init__) resolved
by keeping both intents, which were independent:

- local: require exactly one of surface/equilibrium, which makes the
  `elif surface is None` fallback to a default FourierRZToroidalSurface
  dead code, so it is dropped.
- remote (901be15 "negative secular terms"): drop the check_nonnegint
  calls on secular_theta/secular_zeta so negative values are allowed,
  consistent with the abs() already used in the gcd check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@singh-jaydeep
singh-jaydeep marked this pull request as ready for review August 20, 2026 00:52
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.21429% with 38 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.33%. Comparing base (7582fb3) to head (f1100be).

Files with missing lines Patch % Lines
desc/geometry/curve.py 86.01% 27 Missing ⚠️
desc/coils.py 91.11% 4 Missing ⚠️
desc/geometry/core.py 91.66% 3 Missing ⚠️
desc/objectives/linear_objectives.py 93.33% 3 Missing ⚠️
desc/objectives/_geometry.py 98.07% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2285      +/-   ##
==========================================
- Coverage   94.35%   94.33%   -0.02%     
==========================================
  Files         101      101              
  Lines       29036    29589     +553     
==========================================
+ Hits        27396    27912     +516     
- Misses       1640     1677      +37     
Files with missing lines Coverage Δ
desc/compute/_curve.py 100.00% <100.00%> (ø)
desc/compute/data_index.py 95.94% <ø> (ø)
desc/geometry/__init__.py 100.00% <100.00%> (ø)
desc/objectives/__init__.py 100.00% <ø> (ø)
desc/objectives/_coils.py 99.34% <100.00%> (+<0.01%) ⬆️
desc/objectives/_geometry.py 97.09% <98.07%> (+0.12%) ⬆️
desc/geometry/core.py 95.14% <91.66%> (-0.17%) ⬇️
desc/objectives/linear_objectives.py 96.07% <93.33%> (-0.18%) ⬇️
desc/coils.py 96.55% <91.11%> (-0.29%) ⬇️
desc/geometry/curve.py 94.12% <86.01%> (-2.33%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

1 participant