Контракты модуля ann2
План — docs/plan/ann2.md (§3 — архитектура), журнал — docs/plan/ann2/. Код — исследовательский,
tools/research/ann2/; данные и прогоны — $AIR_NN_DATA/ann2/ (AIR_NN_DATA по умолчанию /home/greg/air_nn_data).
Изменение интерфейса — только через координатора: версия +1, что изменилось, уведомление потребителей.
A1. Данные и деление (версия 2)
Владелец: air-nn (П1 v3, П2 v4 «деление v3», П6), в ann2 — только чтение. Потребители: AN-2, AN-3.
Образцы — П1 v3 (
docs/contracts/air-nn.md): наборы изtools/research/air_nn_pilot/config.yaml(mainv1 +terrainv2/v3),cases/<id>.npz, оси[канал, высота, j, i], 13 высот AGL, dx = 400 м, 96 × 96; цель несошедшихся —targetП1 v3.Деление — то же, что у P2 (П2, «деление v3»): (г) отложенные горные системы — главная оценка, (б) Онгудай, (б′) отложенные процедурные, (а) новые условия, обучение. Тот же конфиг и зерно, что у прогона P2
runs/2026-10-03_p2b, — чтобы сравнение шло на тех же случаях.Чтение, повороты, карты П2 v4 и деление — импортом из
tools/research/air_nn_pilot/(dataset.py, prep и т. п.), без копирования и без правки этого каталога. Не хватает функции — обёртка вtools/research/ann2/.v2 (04.10, AN-4; решение пользователя — план §5 п. 6): режим случая — механический / конвективный по w*/U (w* по Дирдорфу из потока тепла и z_i случая, U — скорость притока, на какой высоте — записать) или z_i/L; порог и обоснование (литература + где решатель перестаёт сходиться) — в README
tools/research/ann2/, одна функцияregime(case). Обучение и проверка ann2 — только механические случаи; деление по местам и зерно — как v1 (конвективные случаи просто выпадают, отложенные группы не меняются).
A2. Вход и выход сети ann2 (версия 2)
Владелец: AN-2. Потребители: AN-3 (обучение, оценка), будущий экспорт ONNX.
Система координат: повёрнутая, как П2 v4 — точный поворот на k·90° (ветер «с запада» ±45°), остаток угла r — в условия (cos r, sin r); отражение поперёк ветра (y′ → −y′) — аугментация обучения по правилам П2 v4. Обратный поворот и отражение выхода — точные (тест: поворот ×4 и R∘R = тождество).
Карты 2D (float32, C_in × H × W): рельеф h − локальное среднее и прочие карты — из того, что есть у игры без решателя (рельеф, вода, поток тепла, z0); список, формулы и фиксированные нормировки — в README
tools/research/ann2/. Абсолютных координат клетки нет (сеть полностью свёрточная, работает на карте любого размера); признак, связанный с краем области решателя, — только с записью причины в README.Профиль атмосферы: столб притока U(z), θ(z) на сетке высот (не меньше 13 уровней П1) — вход 1D энкодера; плюс скаляры (cos r, sin r, dx, при необходимости z_i, Fr) — список и нормировки в README. Из профиля — FiLM 2D энкодера.
Высота: непрерывная η (м над рельефом клетки); в обучении — случайная в [25, 2000] м, цель — линейно между соседними уровнями П1; в оценке — заданные высоты.
Выход колонки на высоте η (порядок каналов фиксирован):
du_par,du_perp,w— в долях max(U(η), 1 м/с) (U(η) — скорость притока на этой высоте; du — отклонение от профиля притока),theta— θ′ в К (или на записанный масштаб),logsig_*— log σ по каждому из четырёх каналов. Решение без нагрева (m) — образец с нулевой картой потока тепла и маской на θ′ (если метаданные это подтверждают; иначе — записать, как сделано). Обратное преобразование в м/с, К и исходную систему — одна функция, ею пользуются и обучение, и оценка.Потеря: NLL Гаусса по каналам с масками + малый штраф дивергенции массового потока (вес — в конфиге).
Прогон:
$AIR_NN_DATA/ann2/runs/<имя>/:config.json(всё для воспроизведения, зерно),model.pt(state_dict + config),train_log.csv(шаг, потеря обучения, потеря проверки, время),metrics.json(A3). Продолжение после прерывания — с последней точки сохранения.Контрактный тест:
tools/research/ann2/tests/test_contract.py— формы и dtype батча загрузчика и выхода сети, карта 64² и 96² (полная свёрточность), поворот ×4 и R∘R = тождество, обратное преобразование выхода, конечность.v2 (04.10, AN-4): условия — N и Fr⁻¹ случая (из
Day.gammaи профиля случая, а не по фону 3 К/км), остальной состав и порядок скаляров — как v1, изменения нормировок — в README. Голова колонки — разложенная (как DeepONet): ветвь по η даёт K ≈ 16 базисных профилей на каждый канал (один раз на высоту, общие для всех клеток), карта признаков — K коэффициентов на клетку и канал, выход — скалярное произведение; каналы выхода, единицы и обратное преобразование — как v1. В каталоге прогона +best.pt— точка с наименьшей потерей проверки (ранняя остановка), её и оценивают.
A3. Оценка против P2 (версия 2)
Владелец: AN-2. Потребители: AN-3, координатор, пользователь.
- Скрипт
tools/research/ann2/evaluate.py --run <каталог прогона>считает на тех же случаях и клетках сеть ann2 и P2 (runs/2026-10-03_p2b) и печатает таблицу; итог —metrics.jsonиeval.mdв каталоге прогона. - Точки: все клетки области без
edge_cellsна 60 м над рельефом (линейно между 50 и 75 м), как П3 v2; полная карта 96² (сеть ann2 — целиком, без вырезок). - Числа (решение 04.10 — критерий 10–15 % скорости): ошибка ветра |Δ(u, v)| с нагревом — медиана и p90 по клеткам группы (как отчёт P2), м/с; относительная |Δ|/|V_решателя| — медиана; ρ₁₅ = |Δ| / max(0,15·|V_решателя|, 0,01 м/с) — медиана и p90; доля «ок15» (ρ₁₅ ≤ 1) и «ок10» (|Δ| ≤ max(0,10·|V|, 0,01 м/с)); 0,01 м/с — порядок шума решателя (AN-1). Подъём |Δw| с нагревом и без — медианы.
- Группы: (г) все / сошедшиеся / несошедшиеся (по статусу решения
h), (г) по корзинам U10 (0–2, 2–4, 4–6, ≥ 6 м/с), (б), (а), обучающие. Строка P2 в каждой группе; самопроверка — медиана ошибки P2 на (г) совпадает с отчётом P2 (≈ 0,62 м/с) до 0,01 м/с. - v2 (04.10, AN-4):
evaluate.py --run <имя> [--also <прогон> …]— ann2 (точкаbest.pt, если есть), прочие прогоны ann2 и P2 на одних клетках. Группы v1 считаются по механическим случаям (A1 v2) + отдельная строка «конвективные» (все отложенные (г) конвективные случаи) для всех сетей. Обязательная строкаcriterion_10_15: выполнен|нет— медиана относительной ошибки на (г) механических ≤ 0,15 (допустимо) / ≤ 0,10 (цель), отдельно от сравнения с P2. Самопроверка P2 — как v1 (на прежней группе (г) всех случаев).