Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
5442ddc
Add AGENTS.md contributor guide
krystophny Dec 18, 2025
a82b4da
Clarify VMEC build config
krystophny Dec 18, 2025
110f7a8
Add fast smoke mode
krystophny Dec 18, 2025
82c8ed2
Allow tuning fast EP tracing
krystophny Dec 18, 2025
7114e10
Make plot_opt usable for smoke runs
krystophny Dec 18, 2025
92f02c9
Ignore run outputs and drop pysimple finalize
krystophny Dec 19, 2025
afe8037
Use SIMPLE proxy metric (confined/ideal/jpar) with tfinal=1e-2
krystophny Dec 19, 2025
67e6b54
Add Simsopt VMEC input and env override
krystophny Dec 19, 2025
e2ac48c
Add ALPES/QUASR VMEC input with licenses and notice
krystophny Dec 19, 2025
f69a56c
Add VMEC scaling script and reactor-scale ALPES input
krystophny Dec 19, 2025
7fa9aa8
Add scale-model alpha energy option for SIMPLE
krystophny Dec 19, 2025
046b130
Add production-mode env knobs and resume flag
krystophny Dec 19, 2025
0bcc699
Make SIMPLE metric failures non-fatal during optimization
krystophny Dec 19, 2025
ccf0637
Add checkpointing and resume via input.checkpoint
krystophny Dec 19, 2025
0c397fb
Make resume avoid archiving by default
krystophny Dec 19, 2025
76ba339
Checkpoint best candidate from objective evaluations
krystophny Dec 19, 2025
661db2c
Add log-based plot for SIMPLE proxy metric history
krystophny Dec 19, 2025
09191b1
Ignore out_s* run directories
krystophny Dec 19, 2025
1642126
Ignore out_s* symlink
krystophny Dec 19, 2025
a09e03a
Plot best-so-far objective and loss history
krystophny Dec 19, 2025
be03eba
Add uv-managed environment with editable NEAT and pysimple
krystophny Jul 9, 2026
08a47a5
Add barrier-overlap objective ported from sensopt
krystophny Jul 9, 2026
eb831aa
Add SIMPLE vs NEAT loss comparison script
krystophny Jul 9, 2026
aa96246
Add editable VMEC2000 dependency
krystophny Jul 9, 2026
733af0b
Treat times_lost at trace_time as confined in comparison
krystophny Jul 9, 2026
3011957
Enforce reactor-scale classifier objectives
krystophny Jul 10, 2026
4499790
Add reactor proxy calibration pipeline
krystophny Jul 11, 2026
149adf2
Resolve calibration inputs before VMEC runs
krystophny Jul 11, 2026
8bfacf6
Pin DESC and bundle calibration jobs
krystophny Jul 11, 2026
5afaa0d
Analyze local proxy calibration
krystophny Jul 11, 2026
904a879
Stream direct SIMPLE logs to disk
krystophny Jul 11, 2026
21d6536
Combine barrier and short-time loss proxies
krystophny Jul 11, 2026
4fded9e
Count both SIMPLE survivor channels
krystophny Jul 11, 2026
611ba17
Write portable calibration tables
krystophny Jul 11, 2026
bc00a47
Add editable NEAT dependency
krystophny Jul 12, 2026
74904a2
Render SIMPLE vs NEAT comparison figure
krystophny Jul 12, 2026
fa9d574
Make barrier proxy optimizer-ready
krystophny Jul 12, 2026
bc04917
Add isolated direct-loss evaluator
krystophny Jul 13, 2026
88115a6
Record SIMPLE and NEAT comparison results
krystophny Jul 13, 2026
fabd57e
Add data-informed direct-loss evaluator
krystophny Jul 13, 2026
350bde2
Generate bounded VMEC chart audits
krystophny Jul 13, 2026
3f0287d
Keep VMEC audit reference fixed
krystophny Jul 13, 2026
ca16500
Analyze paired direct-loss scouts
krystophny Jul 13, 2026
b793ff6
Optimize completed total loss directly
krystophny Jul 13, 2026
678fa26
Generate data-informed SCBO candidates
krystophny Jul 13, 2026
ea2c677
Prime SCBO from paired loss scouts
krystophny Jul 13, 2026
17eec97
Build paired SCBO worker responses
krystophny Jul 13, 2026
fae5f50
Treat rounded trace endpoints as confined
krystophny Jul 13, 2026
69132cc
Advance checkpointed SCBO waves
krystophny Jul 13, 2026
6074011
Prime production SCBO from resolved local data
krystophny Jul 13, 2026
2f78d32
Count local observations toward SCBO initialization
krystophny Jul 13, 2026
a649d0b
Start alpha SCBO in qualified local region
krystophny Jul 13, 2026
b0cdaf0
Analyze multiseed direct-loss promotions
krystophny Jul 13, 2026
cea82f0
Prime SCBO from resolved direct losses
krystophny Jul 13, 2026
cbadb60
Size SCBO initialization for resolved observations
krystophny Jul 13, 2026
0ab15c3
Add spatial barrier atlas and Condor workers
krystophny Jul 13, 2026
037814e
Overlay magnetic topology landmarks
krystophny Jul 13, 2026
963f48d
Add direct reference worker
krystophny Jul 13, 2026
f14703d
Support candidate manifests in direct worker
krystophny Jul 13, 2026
90022e9
Cap concurrent Condor materialization
krystophny Jul 13, 2026
f48f937
Plot radial hole topology evolution
krystophny Jul 13, 2026
c570e0a
Separate promotion birth-surface contracts
krystophny Jul 13, 2026
d594146
Generate capped Slurm candidate arrays
krystophny Jul 13, 2026
f0f728f
Resume incomplete spatial surface arrays
krystophny Jul 13, 2026
0e7024e
Expose spatial scheduler timeout
krystophny Jul 13, 2026
18091bf
Improve radial evolution tick readability
krystophny Jul 13, 2026
6c9fd63
Preserve adaptive surface radius in plot titles
krystophny Jul 13, 2026
d584bef
Render selected spatial lattice shift
krystophny Jul 13, 2026
ec3ee1e
Verify direct-worker code dependencies
krystophny Jul 13, 2026
62655b0
Separate adaptive surface tick labels
krystophny Jul 13, 2026
889c7a4
Plot spatial score against direct late loss
krystophny Jul 13, 2026
512f396
Plot s=0.25 promotion transfer
krystophny Jul 13, 2026
cf47fca
Add classifier radial proxy
krystophny Jul 13, 2026
2864b86
Use fast classifier without fractal cut
krystophny Jul 13, 2026
0f6e735
Plot topology and J-parallel surfaces
krystophny Jul 13, 2026
3ddffc2
Remove redundant DESC import
krystophny Jul 13, 2026
f01389b
Correct classifier code documentation
krystophny Jul 13, 2026
4a79f8d
Require ideal labels for radial width
krystophny Jul 13, 2026
1ec4e20
Gate classifier proxy heads
krystophny Jul 13, 2026
6ae146d
Require resolved classifier proxy gates
krystophny Jul 14, 2026
16fafcc
Support separate refinement designs
krystophny Jul 14, 2026
51c0cd4
Freeze classifier radial grids
krystophny Jul 14, 2026
1914f11
Gate held-out classifier predictions
krystophny Jul 14, 2026
8d2a846
Compare successive radial refinements
krystophny Jul 14, 2026
28bcad8
Bind workers to exact classifier grids
krystophny Jul 14, 2026
f501ecd
Add fixed outer-shell optimization proxy
krystophny Jul 14, 2026
2103b70
Add prompt early late optimizer responses
krystophny Jul 14, 2026
ba051a2
Make shell worker retries recover partial designs
krystophny Jul 14, 2026
8f670df
Optimize calibrated total alpha loss
krystophny Jul 14, 2026
4ed813c
Remove fast-ion proxy acquisition guard
krystophny Jul 14, 2026
03243a8
Cap Shell Proxy And Submit Validation
krystophny Jul 15, 2026
2b5b77e
Pass Validation Metadata Positionally
krystophny Jul 15, 2026
83e0b60
Replace Proxy Search With Direct Alpha Loss
krystophny Jul 15, 2026
62fcea1
Add Raw Optimizer Comparison
krystophny Jul 15, 2026
18f7a9e
Remove Chart Dependency From Raw Search
krystophny Jul 15, 2026
f27a747
Make Raw Search Environment Independent
krystophny Jul 15, 2026
15d059d
Optimize Barrier Overlap With Fast Classification
krystophny Aug 4, 2026
ad44ea7
Bound Barrier Pitch Grid To The Trapped Region
krystophny Aug 4, 2026
f420561
Add Single-Candidate Slurm Dispatcher
krystophny Aug 4, 2026
ea1a9fa
Build Candidates Without The VMEC Python Extension
krystophny Aug 4, 2026
bf87ab0
Reject Equilibria Too Coarse For SIMPLE Radial Splines
krystophny Aug 4, 2026
d195a84
Source Campaign Environment In The Slurm Job
krystophny Aug 4, 2026
7521de0
Add Continuous Barrier Metrics From The Classifier Margins
krystophny Aug 4, 2026
5710ba8
Fix The Mu Scale And Censor Unresolved Orbits
krystophny Aug 4, 2026
aae15d0
Report A Missing Smooth Value Instead Of Crashing
krystophny Aug 4, 2026
3cbfeff
Snapshot Code And Binary Into The Campaign Root
krystophny Aug 4, 2026
84b67d6
Add A Radial-Excursion Objective That Actually Has Data
krystophny Aug 4, 2026
9436d22
Report Every Smooth Classifier, Not Just Two
krystophny Aug 4, 2026
999e4e9
Use continuous fast-classifier barrier metrics
krystophny Aug 6, 2026
b4b06d2
Batch continuous classifier surfaces
krystophny Aug 6, 2026
b9b73f1
Normalize signed rotation drift
krystophny Aug 7, 2026
29049d6
Restore strict rotation validation
krystophny Aug 7, 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
Binary file added .DS_Store
Binary file not shown.
Binary file added ._.DS_Store
Binary file not shown.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,9 @@ dmypy.json

# Pyre type checker
.pyre/

# Optimization outputs
out_*/
out_s*/
out_s*
threed1.*
50 changes: 50 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Repository Guidelines

## Project Structure & Module Organization

- `main.py`: primary EP + equilibrium optimization driver (MPI-aware); produces
output folders like `out_s*_NFP*` and CSV logs `output_*.csv`.
- `initial_configs/`: VMEC input files used as starting points (e.g.
`initial_configs/input.nfp2_QA`).
- `Alan_objectives.py`: objective/penalty utilities (mirror ratio, elongation).
- `plot_opt.py`, `vmecPlot2.py`: post-processing and plotting helpers.
- `regression_test.py`, `test_search_global_minimum.py`: standalone scripts for
robustness checks / optimization experiments.

## Build, Test, and Development Commands

This repo is script-driven (no package build step). Use a Python environment
that has the scientific stack plus VMEC + NEAT installed.

- Install dependencies (examples):
- `python3 -m pip install numpy scipy pandas matplotlib mpi4py simsopt booz_xform`
- VMEC extension (required by `simsopt.mhd.Vmec`): `python3 -m pip install git+ssh://git@github.com/hiddenSymmetries/VMEC2000.git`
- NEAT (required by `from neat...`): `python3 -m pip install -e ../NEAT`
- If VMEC fails to build due to hardcoded compiler/library paths, edit the
VMEC2000 `cmake_config_file.json` to point at your `mpicc`/`mpifort` and
NetCDF include/lib directories (e.g. `/usr/include`, `/usr/lib`).
- Run optimization: `mpirun -n 4 python3 main.py` (or `python3 main.py` for
serial experiments).
- Plot results (after an optimization run): `python3 plot_opt.py`.

## Coding Style & Naming Conventions

- Python, 4-space indentation, keep lines reasonably short.
- Prefer `pathlib.Path` over manual string path joins in new code.
- Keep scripts runnable from the repository root (assume `initial_configs/` is
available via relative paths).

## Testing Guidelines

There is no pytest suite. Use quick smoke checks before larger runs:

- VMEC + SIMSOPT sanity run (writes to `/tmp`): `python3 -c "from simsopt.mhd import Vmec; import os; os.chdir('/tmp'); Vmec('path/to/initial_configs/input.nfp2_QA', verbose=False).run()"`
- Import sanity: `python3 -c "from neat.fields import Simple; from simsopt.mhd import Vmec"`

## Commit & Pull Request Guidelines

- Commit messages in this repo are short, imperative, and capitalized (e.g.
Added ..., Create ..., Initial commit); follow that style.
- PRs should describe the physics intent, list runtime/environment assumptions
(MPI size, key parameters), and include plots/CSV excerpts when they help
reviewers reproduce results.
6 changes: 3 additions & 3 deletions Alan_objectives.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,9 @@ def FindBoundary(theta,phi):
# Fit an ellipse to this cross-section shape
perim_resid = lambda a : perim - (4*a*ellipe(1 - ( A / (np.pi * a**2 ) )**2))
if iphi == 0:
a1 = fsolve(perim_resid, 1)
a1 = float(np.asarray(fsolve(perim_resid, 1)).item())
else:
a1 = fsolve(perim_resid, a1)
a1 = float(np.asarray(fsolve(perim_resid, a1)).item())
a2 = A / (np.pi * a1)
if a1 > a2:
maj = a1
Expand Down Expand Up @@ -275,4 +275,4 @@ def MirrorRatioPen(v, mirror_threshold=0.20, output_mirror=False):
# print("Mirror =",m)
pen = np.max([0,m-mirror_threshold])
if output_mirror: return m
else: return pen
else: return pen
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
# EPoptimization
Energetic Particle Stellarator Optimization

This branch runs a direct collisionless alpha-loss study. It minimizes the
measured 100 ms loss fraction for 256 deterministic 3.5 MeV alpha particles
born at `s = 0.25`. Mirror ratio and maximum elongation are broad feasibility
constraints; proxy, classifier, Gamma-c, and effective-ripple quantities do
not enter the objective.

`main.py` primes constrained TuRBO/SCBO from completed direct observations.
`generate_scbo_candidates.py` maps requests through the bounded ALPES-centered
eight-dimensional chart, and `run_direct_scbo_candidate.sh` evaluates VMEC,
geometry feasibility, and the pinned SIMPLE direct metric.

The campaign contract, exact executable hashes, provenance, and cluster
orchestration live in the companion `alpha-loss-optimization-data` repository
under `runs/alpha_direct_turbo_v1/`.
51 changes: 51 additions & 0 deletions advance_alpha_scbo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
from pathlib import Path


def advance(args: argparse.Namespace) -> None:
from simsopt_dfo.scbo_checkpoint import (
complete_candidates,
issue_candidates,
write_checkpoint,
)

state = json.loads(args.state.read_text())
responses = pending_responses(state, args.responses)
state = complete_candidates(state, responses)
state, requests = issue_candidates(state)
write_checkpoint(args.state, state)
args.requests.write_text(
json.dumps({"requests": requests}, indent=2, sort_keys=True) + "\n"
)


def pending_responses(state: dict, root: Path) -> list[dict]:
pending = {row["candidate_id"] for row in state["pending"]}
rows = [json.loads(path.read_text()) for path in Path(root).glob("*/response.json")]
selected = sorted(
(row for row in rows if row["candidate_id"] in pending),
key=lambda row: row["candidate_id"],
)
if {row["candidate_id"] for row in selected} != pending:
raise ValueError("SCBO response wave does not cover every pending candidate")
return selected


def parser() -> argparse.ArgumentParser:
root = argparse.ArgumentParser()
root.add_argument("--state", type=Path, required=True)
root.add_argument("--responses", type=Path, required=True)
root.add_argument("--requests", type=Path, required=True)
return root


def main() -> None:
advance(parser().parse_args())


if __name__ == "__main__":
main()
Loading