feat(swopp3): integrate Phase 2 configurations and optimization updates#69
Closed
daniprec wants to merge 56 commits into
Closed
feat(swopp3): integrate Phase 2 configurations and optimization updates#69daniprec wants to merge 56 commits into
daniprec wants to merge 56 commits into
Conversation
Replace single average speed with per-segment speeds computed from haversine segment distances divided by equal time intervals. This correctly models varying speed along the route when segments have different spatial lengths.
Precompute Euclidean Distance Transform on Land init and expose Land.distance_penalty() that returns weight * sum(1/(edt+eps)) per route. Points near land receive large penalties; far points contribute negligibly. Fully JIT-compatible via map_coordinates.
…inutes) Add dt_eval_minutes parameter to _cma_evolution_strategy, optimize(), optimize_with_increasing_penalization(), swopp3_runner, and CLI. This allows using a finer evaluation time grid (Δt₂) independently of the corridor discretization (Δt₁), improving penalty sampling without increasing the CMA-ES search dimension.
In wind_penalty_smooth and wave_penalty_smooth, 'weight * sharpness' was mathematically a single scalar. Collapse into just 'weight' with default 50.0 (= old 10.0 * 5.0) for backward compatibility. The combined weather_penalty_smooth retains sharpness unchanged.
Two job scripts for the rust cluster: - swopp3_slurm_split_penalty.sh: wind=100, wave=100, distance=10 - swopp3_slurm_no_penalty.sh: no weather penalties, distance=10 Both use dt_eval_minutes=30 and per-corridor n_points (Atlantic=178, Pacific=293) for Δt₁=2h.
Thread travel_time and time_offset from run_case → run_optimised_departure → cmaes_optimize → penalty functions so weather lookups use the correct per-departure temporal offset.
…URM script Add --cmaes-k (default 10) and --sigma0 (default 0.1) CLI options to swopp3_run.py so CMA-ES exploration parameters can be tuned from the command line without code changes. Add swopp3_slurm_optimal_params.sh using the sweep-optimal parameters: K=15, sigma0=0.3, wind_pw=10, wave_pw=10, dist_pw=10.
The defaults dict in run_optimised_departure() was missing windfield and wavefield, so cmaes_optimize() received None for both. The penalty guards 'if wind_penalty_weight > 0 and windfield is not None' were always False — penalty code never executed in any SWOPP3 run. The _rise_cost closure correctly captured windfield/wavefield for energy computation, masking the fact that the penalty path was dead. Add windfield=windfield and wavefield=wavefield to defaults dict. Add regression test that asserts cmaes.optimize receives the actual field closures (not None).
Change jnp.sum → jnp.mean in wind_penalty_smooth, wave_penalty_smooth, and weather_penalty_smooth so the penalty magnitude is independent of route resolution (L). Previously, doubling L doubled the penalty for the same weather conditions, causing catastrophic energy explosions at high route resolutions. Add _safe_mean helper to handle the degenerate single-point curve edge case (0 segments → return 0 instead of NaN). Add resolution-independence tests verifying identical penalty values at L=10, L=50, and L=100 for constant fields.
- K=10 penalty weight sweep (array job: w50, w100, w200, w500) - K=10 hard weather penalty run (weather_pw=10) - K=15 sweep SLURM script (w200, w500)
- --popsize: CMA-ES population size (default 200) - --maxfevals: maximum function evaluations (default 25000) - --cmaes-verbose: enable per-generation CMA-ES logging - K15/p400/w1000 SLURM script using array tasks for Atlantic/Pacific parallelism
Using _safe_mean(excess**2) divided by all N segments, making the penalty negligible when only a few segments violate (e.g. w=1000 * mean(0.64/178) = 12 MWh, only 12% of energy). Switching to _safe_max(excess**2) directly penalises the worst-violating segment and is resolution-independent. Add _safe_max() helper that handles zero-segment edge case (single-point curve) by using jnp.max with initial=0.0 and a where mask.
Change array from 0-1 (Atlantic/Pacific) to 0-3, one per optimised case: 0=AO_WPS 1=AO_noWPS (Atlantic, n=178) 2=PO_WPS 3=PO_noWPS (Pacific, n=293) GC cases omitted (--strategy optimised): the great-circle route is deterministic and unaffected by penalty weights or CMA-ES parameters. Results can be copied from any prior run. Each task loads only its own corridor's ERA5 files (2 files vs 4 before), and all 4 cases run in parallel instead of sequentially per corridor.
20-task array job (5 weights x 4 optimised cases). GC cases skipped. Weights chosen to cover the equivalent range of the old mean-diluted sweep after accounting for the ~0.05 dilution factor (old w500 ≈ new w25).
_segment_midpoints used distance-proportional time (longer segments get more time, i.e. constant speed), but evaluate_route_energy uses uniform time per segment (dt = passage_hours / n_seg, i.e. variable speed). This caused the CMA-ES penalty to query weather at different timestamps than the post-hoc evaluation, so the optimizer was avoiding violations at the wrong times while the reported max_tws/max_hs saw violations at times the penalty never checked.
When track files referenced in File A are missing from the tracks/ directory, the scorer now reports: - How many tracks are missing out of the expected total per case - A clear PENALTY message explaining why energy was set to 1e12 - Guidance on how to fix the submission (include all File B CSVs) This helps submitters diagnose incomplete submissions, e.g. when optimisation for some cases hasn't finished yet.
Freol's reference tracks confirm the SWOPP3 Atlantic destination is USNYS (lat=40.6, lon=-69.0), not USNYC (lat=40.53, lon=-73.80). The USNYS port was already defined in _ports.py but not wired into the SWOPP3 case definitions. Updated: - routetools/swopp3.py: ROUTE_ATLANTIC, SWOPP3_CASES, _SWOPP3_PORT_CODES - codabench/scoring_program/scoring.py: all 4 Atlantic CASE_DEFS - tests/test_swopp3.py: all endpoint assertions - tests/test_swopp3_runner.py: helper and spy mock coordinates
MWA values near 360° (e.g. 356°) were converted directly to radians (~6.2 rad), making exp(-K_W·|mwa_rad|³) vanish and zeroing the wave added resistance term. Fix: center MWA to [-180°, 180°] via (mwa + 180) % 360 - 180 before radians conversion. Applied to all four power functions: predict_power_no_wps, predict_power_with_wps, predict_power_batch, predict_power_jax. Added regression tests for MWA symmetry (x vs 360-x), non-zero wave contribution at MWA=356°, batch symmetry, and wheel model parity.
Add TestCircularInterpolation class verifying that MWD interpolation across the 360°/0° boundary uses sin/cos decomposition instead of naive linear interpolation. Also add _interp_era5_angle_trilinear helper and precompute mwd_sin/mwd_cos in _load_era5_numpy.
6×6 grid of wind_penalty_weight × wave_penalty_weight (0-1000) as a SLURM array job (--array=0-35). Fixed K=15, σ₀=0.3. ERA5 data from /data/fjsuarez/era5/ (persistent NFS).
Jobs run as root where HOME=/root, but repo is at /home/fjsuarez/routetools. Replace $HOME references with absolute paths.
Resamples tracks to Δt₂ = 30 min, queries ERA5 fields at each evaluation point, and reports wind/wave violations as % of total evaluation points (not per-departure max).
…ing in main execution flow
…arify usage instructions
Add SWOPP3 experiment config support
- evaluate_route returns dict with energy, max_tws, max_hs, and wind/wave violation segment counts - validate_file_b returns (errors, land_count) tuple - score_submission collects per-case violation data and writes per-case wind/wave/land violation departure counts to scores - _write_detailed_results renders a violations summary HTML table showing which cases have weather or land constraint violations
The scorer uses USNYS (40.6, -69.0) as the Atlantic destination but the starting kit still had the old USNYC coordinates (40.53, -73.80). Routes generated by the starting kit would fail endpoint validation (4.8° off, well outside the 0.5° tolerance). Fixes #87
Add SWOPP3 analysis script and violations module
Member
Author
|
The branchs diverged on 16 March and now there are too many conflicts. I am opening a new branch to reconcile these two. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR integrates all configurations and experiments developed for SWOPP3 Phase 2 into the branch.
Key additions and updates
Land penalty
Weather data loader
RISE cost functions
Optimizer updates
Reproducibility infrastructure
Validation