Files
CFDManager/docs/theory/2d_solver/bench/README.md
T
NotBigGhostandClaude Opus 5 8d17bc8014 Валидационная кампания на 115 прогонов и Docker-образ для сервера
bench/ — список сценариев (порождается gen_scenarios.py, а не правится
руками), драйверы под Linux и Windows, предполётная проверка и описание.
Девять групп: эталоны первоисточников, цилиндр против литературы, модели
стенки и субсеточность, профили крыла, сложная и множественная геометрия,
границы домена, старт и время жизни, внутренние инварианты, сверхмелкие
сетки до 4096×2048. Стоимость планируется в обновлениях узлов —
единственной переносимой между машинами мере; в часы драйвер переводит её
по фактическим MLUPS, которые замеряет на месте (--calibrate). Итого
3.76e14 обновлений, ≈90 часов на 4070 Ti.

Гифки пишутся на всю длительность прогона в реальном времени, 10 кадр/с.
Число кадров этим задано жёстко, поэтому размер регулируется только кадром:
замерено 0.103 байта на пиксель после LZW, отсюда бюджет кадры×пиксели с
нижней границей по ширине. Итог 4.4 ГБ, самый тяжёлый файл 226 МБ.

preflight.py гоняет каждый сценарий на два шага. Окупился сразу: поймал,
что вся группа сверхмелких сеток падала на пределе GPU, а девять прогонов
группы F передавали --body-x дважды. Оба отказа проявились бы только на
сервере, часов через двадцать после старта кампании.

Docker: двухстадийная сборка, в образе libvulkan1 и vulkan-tools.
NVIDIA Container Toolkit подкладывает Vulkan-ICD только при graphics в
NVIDIA_DRIVER_CAPABILITIES — без него wgpu не увидит карту, поэтому
capabilities прописаны в образе, а vulkaninfo лежит внутрь для проверки.
ENTRYPOINT — драйвер кампании, CMD по умолчанию --dry-run, чтобы случайный
docker run не запустил сточасовую задачу. Проверено локально: образ
собирается, смоук проходит с монтированием результатов на хост, физика
совпадает с хостовой до последней цифры, --backend gpu без карты отказывает
явно. GPU-путь в контейнере проверяется только на машине с картой.

В README поправлено разделение вкладов в продольную акустику: измерением
2×2 показано, что 74.9% → 1.1% даёт ОДНОРОДНЫЙ СТАРТ, причём при полностью
выключенной губке, а губка снимает лишь остаток (1.12% → 0.83% при
утроении длины). При старте из покоя губка не помогает совсем — у стоячей
четвертьволновой моды там узел давления, где вязкость её не трогает.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 17:36:40 +03:00

114 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Валидационная кампания
115 прогонов, ≈90 часов на RTX 4070 Ti. Проверяет решатель по трём независимым линиям:
эталонам из статей авторов метода, литературе по обтеканию тел и внутренним инвариантам самой
схемы. Каждый прогон кладёт логи, ряды, машиночитаемую сводку и гифку в собственную папку.
## Быстрый старт на сервере
```sh
docker build -t kbc2d docs/theory/2d_solver
docker run --rm --gpus all --entrypoint python3 kbc2d preflight.py # сценарии стартуют
docker run --rm --gpus all kbc2d --calibrate # GPU виден
docker run -d --gpus all -v "$PWD/out:/work/bench/out" --name kbc2d kbc2d --resume
docker logs -f kbc2d
```
Первым делом стоит убедиться, что Vulkan внутри контейнера действительно видит карту:
```sh
docker run --rm --gpus all --entrypoint vulkaninfo kbc2d --summary | head -20
```
Если адаптеров ноль — почти наверняка дело в `NVIDIA_DRIVER_CAPABILITIES`: Container Toolkit
подкладывает Vulkan-ICD только при наличии `graphics` в списке. В образе это прописано, но
может быть переопределено снаружи.
## Без Docker
```sh
cargo build --release # из docs/theory/2d_solver
cd bench
python preflight.py # каждый сценарий стартует на два шага
./run_campaign.sh --calibrate # замерить MLUPS этой машины
KBC2D_GPU_MLUPS=1400 ./run_campaign.sh --dry-run
./run_campaign.sh --resume
```
Под Windows то же самое делает `run_campaign.ps1` (тот же `scenarios.json`); он нужен для
локальной отладки обвязки, целевая машина — Linux.
## Ключи драйвера
| ключ | что делает |
|---|---|
| `--dry-run` | печатает смету: что, сколько шагов, сколько часов. Ничего не считает |
| `--calibrate` | три коротких прогона, замер фактических MLUPS этой машины |
| `--smoke` | три самых дешёвых прогона: проверить обвязку, а не физику |
| `--resume` | пропускает прогоны, у которых уже есть `summary.json` |
| `--group A,B` | только выбранные группы |
| `--only cyl_re150` | по подстроке идентификатора |
| `--budget-hours 24` | остановиться, когда время выйдет |
Прогон, который упал или развалился, помечается в сводке и **не останавливает кампанию**:
группы E и G специально ищут предел устойчивости, там развал — ожидаемый результат.
## Что где лежит
```
out/summary.csv сводная таблица: id, группа, статус, секунды, стоимость
out/campaign.log журнал с отметками времени
out/<id>/cmd.txt точная команда, которой прогон был запущен
out/<id>/log.txt полный вывод
out/<id>/report.txt только итоговый отчёт
out/<id>/series.csv временные ряды по шагам
out/<id>/summary.json ключевые метрики машиночитаемо — с этого удобно начинать разбор
out/<id>/*.gif анимация
out/<id>/*_case.csv энергия, энстрофия, палинстрофия (эталонные течения)
out/<id>/xt_*.csv x–t диаграммы (группа G)
```
## Группы
| | прогонов | что проверяется |
|---|---|---|
| **A** | 12 | эталоны первоисточников: Тейлор–Грин (второй порядок сходимости; при фиксированном u₀ — полка O(Ma²)), сдвиговый слой Re=3·10⁴, затухающая турбулентность |
| **B** | 16 | цилиндр против литературы: стационар Re=20/40, дорожка Re=100…300, разрешение D=16…128, блокировка Ny/D=6…32 с экстраполяцией к бесконечной среде |
| **C** | 20 | модели стенки и субсеточность: hrr / grad / bouzidi / staircase при Re=150 и 2000, плюс сдвиг тела внутри клетки на 0 / ¼ / ½ для всех четырёх |
| **D** | 14 | профили крыла: поляра NACA 0012, Re-серия, изгиб 4412, сходимость по хорде |
| **E** | 12 | сложная и множественная геометрия: тандем, решётка, перфорация, многоэлементный профиль, сверхтонкая пластина, клин, зазубренная кромка |
| **F** | 9 | поле влияния и границы домена: отступы до входа и выхода, вложенный патч |
| **G** | 14 | старт, акустика, время жизни: x–t диаграммы, губки, предел по Re, прогон на 10⁷ шагов |
| **H** | 9 | инварианты: симметрия, зеркальность, зависимость от числа Маха, расхождение f32 против f64 |
| **I** | 9 | сверхмелкие сетки 4096×2048 по всем формам и композиции из трёх тел |
## Стоимость и время
Стоимость каждого прогона хранится в **обновлениях узлов** (`nodes_per_step × steps`) — это
единственная мера, переносимая между машинами. Часы драйвер получает, поделив её на MLUPS.
Оценки по умолчанию исходят из 1200 MLUPS на GPU и 22 на CPU; **`--calibrate` обязателен**,
потому что эти числа взяты с другой машины.
Пересобрать список с другой длительностью:
```sh
python gen_scenarios.py --scale 3 # все прогоны в полтора раза длиннее (≈135 ч)
```
## Что известно заранее
- **Точность f32.** Замерено на Тейлоре–Грине: GPU совпадает с CPU/f64, пока истинная ошибка
выше ~10⁻³, и промахивается в 40 раз, когда она ниже. Поэтому исследования сходимости из
группы A идут на CPU — это указано в самих сценариях.
- **Развалы ожидаемы** в группе G (предел по Re) и у прогона `A09_shear_n512_lbgk`: LBGK при
Re=3·10⁴ обязан развалиться там, где KBC доживает — это и есть проверяемое утверждение.
- **Гифки** пишутся на всю длительность прогона, в реальном времени, 10 кадр/с. Число кадров
этим задано жёстко (у самого длинного прогона их 16 666), поэтому единственный рычаг —
размер кадра. Замерено: 0.103 байта на пиксель после LZW; отсюда бюджет
кадры×пиксели ≤ 1.5·10⁹ на гифку, но ширина не опускается ниже 480 пикселей. Итог по
кампании: **≈4.4 ГБ**, самый тяжёлый файл 226 МБ.
- **Перед запуском** имеет смысл прогнать предполётную проверку: каждый сценарий стартует на
два шага, что ловит опечатки в ключах и несовместимые сочетания до того, как кампания уйдёт
считать на девяносто часов. Именно она поймала, что вся группа I падала на пределе GPU в
65535 рабочих групп на измерение.