Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
871d169
Add new integrator scripts for field tracing and guiding center dynamics
EstevaoMGomes Apr 20, 2025
f86f5ee
Improve loss functions speed
EstevaoMGomes Apr 20, 2025
408c2c5
Refine integrator analysis
EstevaoMGomes Apr 21, 2025
6ff79db
Optimize rotation matrix computation in RotatedCurve function
EstevaoMGomes Apr 27, 2025
fdb1508
Edit fo and gc integration analysis plots
EstevaoMGomes Apr 28, 2025
415bbae
Improve loss functions computational efficiency
EstevaoMGomes Apr 28, 2025
f38fdea
Feature: gradient analysis
EstevaoMGomes Apr 28, 2025
079cdb7
Add block_until_ready to integrators analysis
EstevaoMGomes May 4, 2025
fe5d81d
Minor tweaks to gradient analysis plot
EstevaoMGomes May 4, 2025
9595ab4
Create Poincare Plots analysis
EstevaoMGomes May 4, 2025
108123e
Refactor integrators analysis: add cyclotron frequency calculation an…
EstevaoMGomes May 11, 2025
c80ff2c
Change loss functions to be quadratic & implement separation loss
EstevaoMGomes May 11, 2025
ea0af03
Minor improvements in coils class
EstevaoMGomes May 11, 2025
5617e7f
Add join method to Particles class and optimize tracing parameters in…
EstevaoMGomes May 11, 2025
0bb4462
Simplify curve appending logic in apply_symmetries_to_curves
EstevaoMGomes May 11, 2025
91f8cd0
Update cyclotron frequency calculation and adjust tracing parameters …
EstevaoMGomes May 12, 2025
549a43f
Enhance Particles class with phase angle parameter and update Tracing…
EstevaoMGomes May 12, 2025
23bf271
Refactor coil separation loss function and optimize tracing parameter…
EstevaoMGomes May 12, 2025
dcef625
Tentative to incorporate pytree methods for BiotSavart class
EstevaoMGomes May 12, 2025
3c96714
Refactor Tracing class initialization and improve parameter handling …
EstevaoMGomes May 14, 2025
b1a227e
Add gc_vs_fo.py for particle tracing and visualization; adjust parame…
EstevaoMGomes May 14, 2025
8332e1e
Add output directory creation and update file saving paths in analysi…
EstevaoMGomes May 19, 2025
c64a9c1
Add comparison_coils.py for BiotSavart field analysis and performance…
EstevaoMGomes May 19, 2025
f867857
Fix errors derived from dynamics refactoring
EstevaoMGomes May 21, 2025
7d7be44
Enhance plotting in gc_integrators.py: adjust figure sizes, add toler…
EstevaoMGomes May 21, 2025
53682b6
Change dynamics to accept Integrator name
EstevaoMGomes May 24, 2025
093f11d
Add comparison_gc.py for comparing gc trajectories between SIMSOPT an…
EstevaoMGomes May 24, 2025
1c6584c
Fixed energy calculation for fo trajectories
EstevaoMGomes May 26, 2025
32b84ad
Finalize gc analysis ESSOS vs SIMSOPT
EstevaoMGomes May 26, 2025
f902e22
Add comparison script for fo tracing & improve gc script plots
EstevaoMGomes May 28, 2025
823c6db
Fixed error in dynamics when tracing fieldlines
EstevaoMGomes May 28, 2025
32c36b3
Based on work from PR #19
EstevaoMGomes Jun 6, 2025
798731d
Fix energy calls in integrators analysis
EstevaoMGomes Jun 6, 2025
c3134b9
Fixed loss functions and enhanced coil separation logic
EstevaoMGomes Jun 25, 2025
5a728c0
Fixed coils&surface opt example
EstevaoMGomes Jun 25, 2025
43dd5a0
Added extra simsopt compilation runs
EstevaoMGomes Jun 25, 2025
e6cb9fa
Added field line comparisons & minor improvements to fo and gc compar…
EstevaoMGomes Jun 25, 2025
97f2985
Improve length calculation & refactor gammas to lazy initialization &…
EstevaoMGomes Jun 26, 2025
312dab3
Fix coils.from_simsopt imports
EstevaoMGomes Jun 26, 2025
32fa067
Add loss function comparison with simsopt
EstevaoMGomes Jun 26, 2025
d4bb387
Add surface comparison with simsopt
EstevaoMGomes Jun 26, 2025
00f2160
Refactor surfaces gamma to lazy initialization & add SquaredFlux func…
EstevaoMGomes Jun 26, 2025
9c2407b
Fix Coils.from_ imports
EstevaoMGomes Jun 27, 2025
8975934
Finished surface comparison
EstevaoMGomes Jun 27, 2025
70dcaa6
Finish simsopt comparison & improve analysis plots
EstevaoMGomes Jul 9, 2025
bbf6cc4
Update Ubuntu for workflows
EstevaoMGomes Jul 9, 2025
e844b67
Merge branch 'main' into eg/analysis
EstevaoMGomes Sep 8, 2025
7d807ff
Fixed near-axis & surfaces examples
EstevaoMGomes Sep 22, 2025
9853449
Fixed merge changes
EstevaoMGomes Sep 22, 2025
1395650
Deleting comparison_simsopt folder in examples
EstevaoMGomes Sep 22, 2025
ddb2282
Changing surfaces.py to correct the number of modes used, added optio…
eduardolneto Oct 14, 2025
a0374cc
Fix(coils, fields): turned field BiotSavart into a PyTree and modifie…
EstevaoMGomes Oct 21, 2025
c7378bb
Fix: minor fixes
EstevaoMGomes Oct 27, 2025
d3b073c
Merge branch 'en/surface_modes_hotfix' into eg/analysis
EstevaoMGomes Oct 27, 2025
d40fa9c
Fix(coils): assertion removal in Coils class; Perf(coils): vmap & sep…
EstevaoMGomes Oct 28, 2025
37252ef
Fix(analysis): precompile coil gammas for comparison with simsopt
EstevaoMGomes Oct 28, 2025
df5a525
Fix(surfaces): PyTree able Surfaces
EstevaoMGomes Nov 5, 2025
a4fad74
Fix(fields,surfaces): fixed mpol in vmec import
EstevaoMGomes Nov 5, 2025
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
232 changes: 232 additions & 0 deletions analysis/comparisons_simsopt/coils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import os
from time import time
import jax.numpy as jnp
import matplotlib.pyplot as plt
plt.rcParams.update({'font.size': 18})
from jax import block_until_ready
from essos.fields import BiotSavart as BiotSavart_essos
from essos.coils import Coils, Curves
from simsopt import load
from simsopt.geo import CurveXYZFourier, curves_to_vtk
from simsopt.field import BiotSavart as BiotSavart_simsopt, coils_via_symmetries
from simsopt.configs import get_ncsx_data, get_w7x_data, get_hsx_data, get_giuliani_data

output_dir = os.path.join(os.path.dirname(__file__), '../output')
if not os.path.exists(output_dir):
os.makedirs(output_dir)

n_segments = 100

LandremanPaulQA_json_file = os.path.join(os.path.dirname(__file__), '../../examples/', 'input_files', 'SIMSOPT_biot_savart_LandremanPaulQA.json')
nfp_array = [3, 2, 5, 4, 2]
curves_array = [get_ncsx_data()[0], LandremanPaulQA_json_file, get_w7x_data()[0], get_hsx_data()[0], get_giuliani_data()[0]]
currents_array = [get_ncsx_data()[1], None, get_w7x_data()[1], get_hsx_data()[1], get_giuliani_data()[1]]
name_array = ["NCSX", "QA(json)", "W7-X", "HSX", "Giuliani"]

print(f'Output being saved to {output_dir}')
print(f'SIMSOPT LandremanPaulQA json file location: {LandremanPaulQA_json_file}')
for nfp, curves_stel, currents_stel, name in zip(nfp_array, curves_array, currents_array, name_array):
print(f' Running {name} and saving to output directory...')
if currents_stel is None:
json_file_stel = curves_stel
field_simsopt = load(json_file_stel)
coils_simsopt = field_simsopt.coils
curves_simsopt = [coil.curve for coil in coils_simsopt]
currents_simsopt = [coil.current for coil in coils_simsopt]
coils_essos = Coils.from_simsopt(json_file_stel, nfp)
curves_essos = Curves.from_simsopt(json_file_stel, nfp)
else:
coils_simsopt = coils_via_symmetries(curves_stel, currents_stel, nfp, True)
curves_simsopt = [c.curve for c in coils_simsopt]
currents_simsopt = [c.current for c in coils_simsopt]
field_simsopt = BiotSavart_simsopt(coils_simsopt)

coils_essos = Coils.from_simsopt(coils_simsopt, nfp)
curves_essos = Curves.from_simsopt(curves_simsopt, nfp)

field_essos = BiotSavart_essos(coils_essos)

coils_essos_to_simsopt = coils_essos.to_simsopt()
curves_essos_to_simsopt = curves_essos.to_simsopt()
field_essos_to_simsopt = BiotSavart_simsopt(coils_essos_to_simsopt)

# curves_to_vtk(curves_simsopt, os.path.join(output_dir,f"curves_simsopt_{name}"))
# curves_essos.to_vtk(os.path.join(output_dir,f"curves_essos_{name}"))
# curves_to_vtk(curves_essos_to_simsopt, os.path.join(output_dir,f"curves_essos_to_simsopt_{name}"))

base_coils_simsopt = coils_simsopt[:int(len(coils_simsopt)/2/nfp)]
R = jnp.mean(jnp.array([jnp.sqrt(coil.curve.x[coil.curve.local_dof_names.index('xc(0)')]**2
+coil.curve.x[coil.curve.local_dof_names.index('yc(0)')]**2)
for coil in base_coils_simsopt]))
x = jnp.array([R+0.01,R,R])
y = jnp.array([R,R+0.01,R-0.01])
z = jnp.array([0.05,0.06,0.07])

positions = jnp.array((x,y,z))

def update_nsegments_simsopt(curve_simsopt, n_segments):
new_curve = CurveXYZFourier(n_segments, curve_simsopt.order)
new_curve.x = curve_simsopt.x
return new_curve

coils_essos.n_segments = n_segments

base_curves_simsopt = [update_nsegments_simsopt(coil_simsopt.curve, n_segments) for coil_simsopt in base_coils_simsopt]
coils_simsopt = coils_via_symmetries(base_curves_simsopt, currents_simsopt[0:len(base_coils_simsopt)], nfp, True)
curves_simsopt = [c.curve for c in coils_simsopt]

# Running the first time for compilation
[curve.gamma() for curve in curves_simsopt]
[curve.gammadash() for curve in curves_simsopt]
[curve.gammadashdash() for curve in curves_simsopt]
coils_essos.gamma
coils_essos.gamma_dash
coils_essos.gamma_dashdash
coils_essos.curvature
coils_essos.reset_cache()

# Running the second time for coils characteristics comparison
start_time = time()
gamma_curves_simsopt = block_until_ready(jnp.array([curve.gamma() for curve in curves_simsopt]))
t_gamma_avg_simsopt = time() - start_time

start_time = time()
gamma_curves_essos = block_until_ready(jnp.array(coils_essos.gamma))
t_gamma_avg_essos = time() - start_time

start_time = time()
gammadash_curves_simsopt = block_until_ready(jnp.array([curve.gammadash() for curve in curves_simsopt]))
t_gammadash_avg_simsopt = time() - start_time

start_time = time()
gammadash_curves_essos = block_until_ready(jnp.array(coils_essos.gamma_dash))
t_gammadash_avg_essos = time() - start_time

start_time = time()
gammadashdash_curves_simsopt = block_until_ready(jnp.array([curve.gammadashdash() for curve in curves_simsopt]))
t_gammadashdash_avg_simsopt = time() - start_time

start_time = time()
gammadashdash_curves_essos = block_until_ready(jnp.array(coils_essos.gamma_dashdash))
t_gammadashdash_avg_essos = time() - start_time

start_time = time()
curvature_curves_simsopt = block_until_ready(jnp.array([curve.kappa() for curve in curves_simsopt]))
t_curvature_avg_simsopt = time() - start_time

start_time = time()
curvature_curves_essos = block_until_ready(jnp.array(coils_essos.curvature))
t_curvature_avg_essos = time() - start_time

gamma_error_avg = jnp.linalg.norm(gamma_curves_essos - gamma_curves_simsopt)
gammadash_error_avg = jnp.linalg.norm(gammadash_curves_essos - gammadash_curves_simsopt)
gammadashdash_error_avg = jnp.linalg.norm(gammadashdash_curves_essos - gammadashdash_curves_simsopt)
curvature_error_avg = jnp.linalg.norm(curvature_curves_essos - curvature_curves_simsopt)

# Magnetic field comparison

field_essos = BiotSavart_essos(coils_essos)
field_simsopt = BiotSavart_simsopt(coils_simsopt)

t_B_avg_essos = 0
t_B_avg_simsopt = 0
B_error_avg = 0
t_dB_by_dX_avg_essos = 0
t_dB_by_dX_avg_simsopt = 0
dB_by_dX_error_avg = 0

for position in positions:
field_essos.B(position)
time1 = time()
result_B_essos = field_essos.B(position)
t_B_avg_essos = t_B_avg_essos + time() - time1
normB_essos = jnp.linalg.norm(result_B_essos)

field_simsopt.set_points(jnp.array([position]))
field_simsopt.B()
time3 = time()
field_simsopt.set_points(jnp.array([position]))
result_simsopt = field_simsopt.B()
t_B_avg_simsopt = t_B_avg_simsopt + time() - time3
normB_simsopt = jnp.linalg.norm(jnp.array(result_simsopt))

B_error_avg = B_error_avg + jnp.abs(normB_essos - normB_simsopt)

field_essos.dB_by_dX(position)
time1 = time()
field_simsopt.set_points(jnp.array([position]))
result_dB_by_dX_essos = field_essos.dB_by_dX(position)
t_dB_by_dX_avg_essos = t_dB_by_dX_avg_essos + time() - time1
norm_dB_by_dX_essos = jnp.linalg.norm(result_dB_by_dX_essos)

field_simsopt.dB_by_dX()
time3 = time()
field_simsopt.set_points(jnp.array([position]))
result_dB_by_dX_simsopt = field_simsopt.dB_by_dX()
t_dB_by_dX_avg_simsopt = t_dB_by_dX_avg_simsopt + time() - time3
norm_dB_by_dX_simsopt = jnp.linalg.norm(jnp.array(result_dB_by_dX_simsopt))

dB_by_dX_error_avg = dB_by_dX_error_avg + jnp.abs(norm_dB_by_dX_essos - norm_dB_by_dX_simsopt)

# Labels and corresponding absolute errors (ESSOS - SIMSOPT)
quantities_errors = [
(r"$B$", jnp.abs(B_error_avg)),
(r"$B'$", jnp.abs(dB_by_dX_error_avg)),
(r"$\Gamma$", jnp.abs(gamma_error_avg)),
(r"$\Gamma'$", jnp.abs(gammadash_error_avg)),
(r"$\Gamma''$", jnp.abs(gammadashdash_error_avg)),
(r"$\kappa$", jnp.abs(curvature_error_avg)),
]

labels = [q[0] for q in quantities_errors]
error_vals = [q[1] for q in quantities_errors]

X_axis = jnp.arange(len(labels))
bar_width = 0.6

fig, ax = plt.subplots(figsize=(9, 6))
ax.bar(X_axis, error_vals, bar_width, color="darkorange", edgecolor="black")

ax.set_xticks(X_axis)
ax.set_xticklabels(labels)
ax.set_ylabel("Absolute error")
ax.set_yscale("log")
ax.set_ylim(1e-17, 1e-12)
ax.grid(axis='y', which='both', linestyle='--', linewidth=0.6)

plt.tight_layout()
plt.savefig(os.path.join(output_dir, f"comparisons_coils_error_{name}.pdf"), transparent=True)
plt.close()


# Labels and corresponding timings
quantities = [
(r"$B$", t_B_avg_essos, t_B_avg_simsopt),
(r"$B'$", t_dB_by_dX_avg_essos, t_dB_by_dX_avg_simsopt),
(r"$\Gamma$", t_gamma_avg_essos, t_gamma_avg_simsopt),
(r"$\Gamma'$", t_gammadash_avg_essos, t_gammadash_avg_simsopt),
(r"$\Gamma''$", t_gammadashdash_avg_essos, t_gammadashdash_avg_simsopt),
(r"$\kappa$", t_curvature_avg_essos, t_curvature_avg_simsopt),
]

labels = [q[0] for q in quantities]
essos_vals = [q[1] for q in quantities]
simsopt_vals = [q[2] for q in quantities]

X_axis = jnp.arange(len(labels))
bar_width = 0.35

fig, ax = plt.subplots(figsize=(9, 6))
ax.bar(X_axis - bar_width/2, essos_vals, bar_width, label="ESSOS", color="red", edgecolor="black")
ax.bar(X_axis + bar_width/2, simsopt_vals, bar_width, label="SIMSOPT", color="blue", edgecolor="black")

ax.set_xticks(X_axis)
ax.set_xticklabels(labels)
ax.set_ylabel("Computation time (s)")
ax.set_yscale("log")
ax.set_ylim(1e-5, 1e-1)
ax.grid(axis='y', which='both', linestyle='--', linewidth=0.6)
ax.legend(fontsize=12)
plt.tight_layout()
plt.savefig(os.path.join(output_dir, f"comparisons_coils_time_{name}.pdf"), transparent=True)
plt.close()
Loading
Loading