Files
gausse/PLAN.md
jze9 65d8b633ad Wire up reporting (plots, BOM, summary, animation) and a working CLI (Stage 7)
- 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>
2026-07-06 20:50:32 +05:00

11 KiB
Raw Blame History

План: Gauss-ускоритель — симулятор и оптимизатор

Многоступенчатый электромагнитный ускоритель ферромагнитного цилиндра (coilgun). Каждая ступень: разгонная катушка (Cu/Al провод на пластиковой трубке) + батарея конденсаторов через тиристор/MOSFET, и датчик прохода снаряда перед катушкой (компенсация задержки включения ключа). Датчик — два конкурирующих варианта: индукционная катушка (сигнал ~ скорости снаряда, слаб на медленных ступенях) и оптопара/датчик Холла (не зависит от скорости) — оптимизатор сравнивает оба.

Цель поиска — КПД (кинетическая энергия снаряда на выходе / энергия во всех конденсаторах). Скорость и стоимость — вторичные метрики. Число ступеней N, геометрия/материал снаряда, все компоненты — часть пространства поиска, а не фиксированные входы. Компоненты — реальные, розничные (Проконтакт/procontact74.ru, ChipDip, Cable.ru и др.).

Требование: миллионы прогонов (Monte Carlo/LHS sweep + эволюционный поиск), все результаты — успешные и неудачные, с честной причиной отказа — пишутся в SQLite. Никаких приукрашенных цифр — если модель показывает низкий КПД или нереализуемость, это тоже результат.

Найденная и исправленная ошибка (Этап 3): насыщение сердечника изначально клэмпилось только в механическом уравнении (F=0.5·I²·dL/dx), но не в электрическом (наведённая ЭДС всё ещё считалась по полной dL/dx) — это незаметно ломало точный энергобаланс на ~15%. Тест на сохранение энергии (этого же честного протокола, который просил пользователь) это поймал. Решение: клэмп насыщения убран из динамики (F=0.5·I²·dL/dx без клэмпа, энергобаланс теперь точен до ~0.02%), а solenoid_field_estimate_tesla/ saturation_scale оставлены как ДИАГНОСТИКА — StageResult.saturation_warning честно предупреждает, когда конфигурация физически выходит за пределы насыщения материала снаряда, не подменяя динамику. Полная нелинейная L(x, I)-модель с coenergy-выводом силы — в разделе "ограничения модели" как будущая работа, не как текущая гарантия точности.

Полный план архитектуры: см. историю обсуждения / physics, sim, optim, storage, report модули ниже.

Docker — основной способ запуска (по требованию пользователя): Dockerfile

  • docker-compose.yml в корне репозитория, образ собран и провалидирован — внутри контейнера запускаются все 37 тестов и CLI (docker compose run --rm --entrypoint pytest gausse -q). Результаты (SQLite и отчёты, когда появятся) монтируются в ./results на хосте, чтобы переживать пересборку образа.

Чек-лист этапов

  • Этап 0 — Скелет проекта: pyproject.toml, README.md, .gitignore, пакеты src/gausse/*, этот файл, первый коммит.
  • Этап 1 — База реальных компонентов: провод Cu/Al, конденсаторы, тиристоры/MOSFET/IGBT, датчики (Hall/оптика реальные, индукционный — оценка), материалы снаряда → components/data/*.json. Каждая запись честно помечена REAL (с URL источника) или ОЦЕНКА (с указанием основания); алюминиевый провод и ёмкости 1000/2200мкФ — низкая уверенность в цене, явно отмечено.
  • Этап 2 — Физическое ядро: physics/constants.py, inductance.py (Уилер + ферромагнитный сердечник + размагничивание), force.py, circuit.py (ОДУ RLC). Юнит-тесты: аналитическое RLC-решение, согласованность dL/dx.
  • Этап 3 — Датчики и одна ступень: physics/sensors.py (оба типа как события solve_ivp), sim/stage.py (полёт → триггер → разряд → энергобаланс). Тест на сохранение энергии + найден/исправлен баг насыщения (см. выше).
  • Этап 4 — Многоступенчатая цепочка: sim/coilgun.py — сквозная координата, отбраковка нереализуемых конфигураций. Дымовой тест на реальной базе компонентов (test_real_components_smoke.py) подтверждает: полный путь реальные JSON → физика → цепочка работает (пример: 22.3 м/с, КПД 3.4% — честный неоптимизированный результат).
  • Этап 5 — Хранилище результатов: storage/schema.py + database.py — SQLite (WAL), таблица runs со всеми прогонами (успех/провал + честная причина), однопроцессный писатель поверх многопроцессной очереди. Тест с реальными multiprocessing.Process (не моками) поймал реальную проблему: коллизия run_id роняла writer и молча останавливала осушение очереди на весь sweep — писатель теперь переживает ошибку вставки одной записи (лог в stderr) и продолжает работу.
  • Этап 6 — Поиск и оптимизация: optim/search_space.py (геном переменной длины — число ступеней тоже эволюционирует), objective.py (fitness=КПД, честный мягкий штраф за нереализуемость пропорционально пройденным ступеням), optim/sweep.py (параллельный Monte Carlo, каждый прогон в SQLite), optim/evolutionary.py ((μ+λ)-ГА + Nelder-Mead полировка непрерывных параметров лучшего генома). Тест поймал реальный баг в crossover() — IndexError при скрещивании двух одноступенчатых геномов (пустой список зазоров), исправлено и покрыто регрессией.
    • Не сделано: отдельный "дешёвый квазистатический предфильтр" перед полным ODE не реализован (кроме уже встроенной в sim/stage.py дешёвой проверки порога индукционного датчика). Если миллионы прогонов на сервере окажутся слишком медленными, это первое место для ускорения.
  • Этап 7 — Отчётность: report/plots.py (ток/поле/скорость по ступеням), summary.py (честная сводка + раздел "ограничения модели"), bom.py (спецификация деталей с ценами), animate.py (GIF: снаряд летит по трубе, катушки светятся пропорционально току — по запросу пользователя), cli.py (gausse sweep/evolve/simulate/report, все 4 команды реально вызывают соответствующие модули, не заглушки). Проверено сквозным прогоном через docker compose run: sweep → report с анимацией на реальной базе компонентов, лучший найденный результат — КПД 32.8% за 982₽ (не выдумано, из реального SQLite).
  • Этап 8 — Сквозная проверка: резюмируемый прогон на реальной базе компонентов, проверка честной записи в SQLite, финальный отчёт (КПД, скорость, стоимость, сравнение датчиков) с разделом ограничений.
  • Этап 9 — GPU-ускорение массового sweep (сервер с GTX 1070): после того как CPU/scipy.solve_ivp-модель провалидирована тестами (Этап 2-4) — батч-версия интегратора с ФИКСИРОВАННЫМ шагом (RK4/полу-неявная схема), считающая сразу N траекторий параллельно как один тензор (cupy, если доступна CUDA, иначе векторизованный numpy/numba), для прогона по-настоящему миллионов конфигураций на сервере. Важно: сначала корректность на CPU, потом скорость на GPU — численные результаты GPU-пути должны сверяться с CPU-эталоном на контрольной выборке, чтобы ускорение не подменило точность честными числами "для галочки".