GPU sweep now multi-stage (up to 10 coils); raise max_stages to 10
The GPU batch sweep processes multi-stage configs round-by-round: at round s every still-alive config with a stage s runs its discharge in one batch, carrying the slug's global position/velocity forward to the next round. Configs with fewer stages drop out of later rounds. Analytic constant-velocity sensor trigger per stage. Validated vs CPU run_coilgun for multi-stage configs (<=3% exit velocity). Default max_stages 4 -> 10. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,28 +9,30 @@ from gausse.storage.database import count_runs, fetch_runs, open_connection
|
||||
DB = ComponentDatabase.load()
|
||||
|
||||
|
||||
def test_gpu_sweep_records_all_and_writes_single_stage(tmp_path):
|
||||
def test_gpu_sweep_records_all_runs(tmp_path):
|
||||
db_path = tmp_path / "gpu.sqlite3"
|
||||
summary = run_gpu_sweep(db_path, n_runs=300, seed=3, prefer_gpu=False, batch_size=300)
|
||||
assert summary["n_runs"] == 300
|
||||
conn = open_connection(db_path)
|
||||
assert count_runs(conn) == 300
|
||||
rows = fetch_runs(conn)
|
||||
# GPU-путь одноступенчатый
|
||||
# многоступенчатые конфиги допустимы (до max_stages)
|
||||
stage_counts = set()
|
||||
for r in rows:
|
||||
g = genome_from_dict(json.loads(r.genome_json))
|
||||
assert len(g.stages) == 1
|
||||
stage_counts.add(len(g.stages))
|
||||
assert r.search_mode.startswith("gpu-sweep")
|
||||
assert max(stage_counts) >= 2, "должны встречаться многоступенчатые конфиги"
|
||||
|
||||
|
||||
def test_gpu_sweep_matches_cpu_within_tolerance(tmp_path):
|
||||
"""Честная сверка: GPU-батч должен давать те же exit_v, что CPU run_coilgun."""
|
||||
"""Честная сверка: GPU-батч (в т.ч. многоступ.) даёт те же exit_v, что CPU run_coilgun."""
|
||||
db_path = tmp_path / "gpu.sqlite3"
|
||||
run_gpu_sweep(db_path, n_runs=1500, seed=5, prefer_gpu=False, batch_size=1500)
|
||||
run_gpu_sweep(db_path, n_runs=2000, seed=5, prefer_gpu=False, batch_size=2000)
|
||||
conn = open_connection(db_path)
|
||||
bounds = SearchBounds(min_stages=1, max_stages=1)
|
||||
feasible = fetch_runs(conn, feasible=True, order_by_efficiency_desc=True, limit=10)
|
||||
assert len(feasible) >= 3, "нужно несколько реализуемых для сверки"
|
||||
bounds = SearchBounds()
|
||||
feasible = fetch_runs(conn, feasible=True, order_by_efficiency_desc=True, limit=12)
|
||||
assert len(feasible) >= 3
|
||||
checked = 0
|
||||
for r in feasible:
|
||||
g = genome_from_dict(json.loads(r.genome_json))
|
||||
@@ -38,8 +40,8 @@ def test_gpu_sweep_matches_cpu_within_tolerance(tmp_path):
|
||||
cpu = run_coilgun(config)
|
||||
if not cpu.feasible:
|
||||
continue
|
||||
# фикс.шаг батча vs адаптивный solve_ivp + аналитический триггер: ~2%
|
||||
assert abs(r.exit_velocity_mps - cpu.exit_v_mps) <= 0.02 * abs(cpu.exit_v_mps) + 0.1, \
|
||||
f"GPU {r.exit_velocity_mps:.2f} vs CPU {cpu.exit_v_mps:.2f}"
|
||||
# фикс.шаг батча + аналитический триггер vs адаптивный solve_ivp: ~3%
|
||||
assert abs(r.exit_velocity_mps - cpu.exit_v_mps) <= 0.03 * abs(cpu.exit_v_mps) + 0.2, \
|
||||
f"GPU {r.exit_velocity_mps:.2f} vs CPU {cpu.exit_v_mps:.2f} ({len(g.stages)} ступ.)"
|
||||
checked += 1
|
||||
assert checked >= 3
|
||||
|
||||
Reference in New Issue
Block a user