Requested during deployment: make the DB maximally detailed, add an
experiment process log, and a web UI to watch runs live.
- optim/objective.py build_detail(): each stored run now records
inter-coil distances, absolute coil positions along the tube, every
component part number/spec, winding geometry, computed physics
(resistance, air inductance, peak current, peak field), and per-stage
outcome (entry/exit velocity, sensor timing, energy breakdown)
- optim/progress_log.py: append-only <db>.log with progress %, feasible
rate, throughput, ETA, and a line on each new best efficiency; wired
into both sweep and evolve
- src/gausse/web/: stdlib-only (http.server) dashboard `gausse serve` --
self-contained HTML polling /api/overview every 3s: counters, KPD
histogram, top-configs table with per-run drill-down, failure reasons,
live log tail. No new dependencies.
- docker-compose.yml: `web` service on port 8000
- 77 tests pass locally and in Docker
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real 5000-run sweep + 600-genome evolution through docker compose run,
not a synthetic smoke test. Two concrete outcomes worth recording:
1. Quantitative confirmation of the sensor discussion from the original
planning conversation: inductive pickup sensor reached only 0.2%
feasibility (6/2965 configs using it), vs ~45-47% for optical/Hall,
because its trigger threshold sits above the fixed launch velocity.
2. Best honest result after the efficiency-metric fix: single stage,
80.97% efficiency, 26.4 m/s, ~1029 RUB in real parts.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- report/plots.py: current/field/velocity plots per stage, Agg backend so
it works headless in Docker/on a server
- report/bom.py: itemized bill of materials with real component prices
- report/summary.py: honest text/JSON summary including a
"model limitations" section and a saturation warning flag per stage
- report/animate.py: the visualization the user explicitly asked for --
a GIF of the slug flying through the tube with each coil glowing by its
instantaneous current, reconstructing the pre-trigger ballistic flight
segment (not just the stored discharge phase) for a continuous timeline
- cli.py: sweep/evolve/simulate/report subcommands now actually call the
underlying modules instead of being stubs
- Extended StageResult/StageOutcome with the coil/entry-state fields the
report layer needed (mu_eff, turns, coil_length, entry_x/v) rather than
recomputing them by other means
Verified end-to-end through `docker compose run`, not just pytest: a real
sweep (30 runs, 11 feasible) followed by `report --animate` produced a
correct GIF/plots/BOM/summary for the actual best result found (32.8%
efficiency, 982 RUB) -- not a synthetic fixture.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- optim/worker_context.py: shared per-process DB/bounds init, extracted
from sweep.py so evolutionary.py doesn't reach into another module's
private state
- optim/objective.py: build_run_record() shared between sweep and
evolutionary so both write identically-shaped rows
- optim/evolutionary.py: tournament selection, whole-stage-swap crossover,
elitism, structural mutation (stage count itself evolves), then a serial
Nelder-Mead polish of the best genome's continuous parameters with
discrete component choices frozen
- Found and fixed a real crash: crossover() indexed into an empty
inter_stage_gaps_m list when both parents had only 1 stage (0 gaps),
raising IndexError. Fixed the fallback to only choose from gaps that
actually exist, defaulting to a neutral value (clipped later by
repair()) when neither parent has one. Added a regression test.
- Verified 59/59 tests pass both locally and inside the Docker image
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- storage/schema.py: `runs` table recording every evaluated configuration,
feasible or not, with an honest infeasible_reason instead of dropping
failures
- storage/database.py: WAL-mode SQLite, single-writer-over-a-queue pattern
for safe concurrent writes from many sweep worker processes
- Testing with real multiprocessing.Process (not mocks) caught a genuine
bug: a duplicate run_id raised inside the writer loop and killed the
writer process, silently halting queue drainage for the rest of a
sweep. Fixed by catching the insert error per-record and logging to
stderr instead of crashing; added a regression test for it.
- Verified locally and inside the Docker image (43/43 tests both ways)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dockerfile (non-root user, UID 1000 to match typical host users so bind
mounts don't end up root-owned) + docker-compose.yml with a ./results
volume for the SQLite database and reports that Stage 5/6 will write.
Verified by actually building the image and running the full test suite
and CLI inside the container, not just writing the files and assuming
they work.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wire (Cu/Al ПЭТВ-2), capacitors (350-450V electrolytic bank), switches
(КУ202Н/BT151 SCR, IRFP250/IRFP4468 MOSFET, IRG4PC50F IGBT), sensors
(A3144E Hall, TCST2103 optical, LM393-based inductive pickup), and
projectile materials (Ст3, Сталь 10, армко-железо) sourced from
procontact74.ru/chipdip.ru/cable.ru research.
Every entry's `source` field states plainly whether the number is a
REAL scraped retail price/spec (with URL) or an ОЦЕНКА (estimate) with
its basis (e.g. aluminum magnet wire has no self-service retail price
in RU stores, so it's priced as a fraction of equivalent copper) — no
value is presented as real when it isn't. Added a smoke test proving
the real database runs end-to-end through the full physics + chaining
pipeline, not just against synthetic test fixtures.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- physics/sensors.py: optical/Hall (velocity-independent) and inductive
(velocity-scaled, sech^2 spatial sensitivity) trigger events for solve_ivp
- sim/stage.py: flight-to-trigger -> fire delay -> discharge -> energy
accounting, returning StageResult(feasible=False, reason=...) instead of
raising when a sensor never fires or discharge never commutates
- Found and fixed a real bug caught by the energy-conservation test: the
saturation clamp was applied to the mechanical force but not the
electrical back-EMF term, silently breaking energy balance by ~15%.
Removed the dynamic clamp (documented as a deferred nonlinear-L(x,I)
limitation) and kept saturation as a diagnostic-only warning
(StageResult.saturation_warning) so numbers stay honest rather than
quietly wrong. Balance error is now ~0.02%.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- components/schema.py + database.py: typed loader for real retail parts
(wire, capacitors, switches, sensors, projectile materials)
- physics/inductance.py: multilayer solenoid inductance (Wheeler) with
ferromagnetic-slug coupling via smooth overlap model and analytic dL/dx
- physics/force.py: F = 0.5*I^2*dL/dx with a saturation clamp
- physics/circuit.py: coupled [Q,I,x,v] discharge ODE
- Validated against textbook RLC analytical solutions (under/over/critically
damped) and energy conservation, not just spot-checked by eye
- PLAN.md updated with animation (per-run field visualization) and
GPU-accelerated batch sweep as explicit later stages
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
src-layout Python package with CLI stub (sweep/evolve/simulate/report
subcommands), pyproject.toml pinned to numpy/scipy/matplotlib, and PLAN.md
tracking the implementation roadmap.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>