Optimization
Helicon provides analytical pre-screening, Bayesian optimization, and Pareto front analysis.
Analytical Pre-Screening
Fast coil geometry evaluation without PIC simulation:
from helicon.optimize.analytical import screen_geometry
from helicon.fields.biot_savart import Coil
coils = [Coil(z=0.0, r=0.12, I=50000.0)]
result = screen_geometry(coils, z_min=-0.3, z_max=2.0)
print(f"Mirror ratio: R_B = {result.mirror_ratio:.2f}")
print(f"Thrust efficiency: η_T = {result.thrust_efficiency:.3f}")
print(f"Divergence angle: θ = {result.divergence_half_angle_deg:.1f}°")
The analytical model applies paraxial approximation theory (Breizman-Arefiev / Little-Choueiri):
\[\eta_T = 1 - \frac{1}{R_B}\]
where \(R_B = B_{throat}/B_{exhaust}\) is the magnetic mirror ratio.
Constrained Optimization
from helicon.optimize.constraints import CoilConstraints, evaluate_constraints
constraints = CoilConstraints(
max_current_MA_turns=0.1, # 100 kA-turns per coil
min_separation_m=0.05, # 5 cm between coils
max_field_T=5.0, # 5 T peak field
)
violations = evaluate_constraints(coils, constraints)
print(violations) # empty list if all satisfied
Bayesian Optimization
Requires pip install "helicon[botorch]":
from helicon.optimize.bayesian import BayesianOptimizer, SearchSpace
space = SearchSpace(
parameters={
"coils.0.I": (20000, 80000),
"coils.0.r": (0.05, 0.20),
"coils.0.z": (-0.10, 0.0),
},
objectives=["thrust_N", "detachment_momentum"],
)
optimizer = BayesianOptimizer(
base_config=config,
space=space,
n_initial=10,
n_iterations=40,
output_base="bo_results/",
)
result = optimizer.run(dry_run=True)
print(f"Best thrust: {result.best_thrust_N:.4f} N")
Pareto Front Analysis
For multi-objective optimization:
from helicon.optimize.pareto import ParetoFront
# objectives: list of (thrust_N, efficiency) tuples
objectives = [(r.thrust_N, r.detachment_momentum) for r in reports]
front = ParetoFront.compute(objectives, maximize=[True, True])
print(f"Pareto front has {len(front.points)} points")
print(f"Hypervolume: {front.hypervolume:.4f}")
for pt in front.points:
print(f" Thrust={pt[0]:.4f} N, η_det={pt[1]:.3f}")
MLX Gradient-Based Optimization
For Apple Silicon, the MLX backend supports mx.grad for coil current optimization:
import mlx.core as mx
from helicon.fields.biot_savart import compute_bfield_mlx_differentiable, Grid
grid = Grid(z_min=-0.3, z_max=2.0, r_max=0.5, nz=64, nr=32)
r_flat = mx.array(grid.r_flat.astype("float32"))
z_flat = mx.array(grid.z_flat.astype("float32"))
def objective(coil_params):
Br, Bz = compute_bfield_mlx_differentiable(coil_params, r_flat, z_flat)
# Maximize B_z at throat (z=0, r=0)
throat_idx = mx.argmin((r_flat**2 + z_flat**2))
return -Bz[throat_idx] # minimize negative = maximize
coil_params = mx.array([[0.0, 0.12, 50000.0]], dtype=mx.float32)
grad_fn = mx.grad(objective)
grads = grad_fn(coil_params)
print(f"∂obj/∂I = {grads[0, 2].item():.6e}")
Grid Convergence
Verify that simulation results are resolution-independent:
from helicon.runner.convergence import run_convergence_study
result = run_convergence_study(
config,
resolutions=[(128, 64), (256, 128), (512, 256)],
output_base="convergence/",
dry_run=True,
)
print(f"Convergence order: {result.convergence_order:.2f}")
print(f"Extrapolated thrust: {result.extrapolated_thrust_N:.4f} N")
Richardson extrapolation gives the grid-converged thrust estimate.