Разведка перед А2: сходимость и цена решателя при параметрах перекалибровки
30.09.2026. Ветка air/a2-pre от feature/air-model (4828b63: А1 влит — Pr_t = 0,85, θ′_d, h при const).
Код и данные — tools/research/a2pre/ (README — команды воспроизведения). Решатель air.py не правился:
меняются только A.Params. Все таблицы делает один скрипт (analyze.py → out/tables.md).
По решению пользователя сделана только матрица. Повторный анализ несошедшихся точек Морриса (139 из 205)
перенесён в волну Б: его делаем после совместной калибровки Askervein + Perdigão, если её итог окажется
неудовлетворительным.
Что с чем сравнивали
Как параметры попадают в решатель. В эталоне это air.py → Params, в игре — AirCase.p
(scripts/atmosphere/air_model/air_case.gd). AirRuntime их не переопределяет. Сейчас в игре стоит
λ/h = 0,25 (LAM_FRAC), α = 0,14, z0 = 0,1 м, max_profile = 1,8, Pr_t = 0,85, local_k вкл, k_relax = 0,5,
heat_sweeps = 4 и 1-й порядок переноса. Отдельно от решателя WindModel берёт configs/atmosphere.json:
wind.shear_exponent 0,14 и roughness_height_m 1 м. Последнее — пол профиля, а не z0.
Params() по умолчанию совпадает с AirCase.p игры.
| набор | λ/h | α | z0, м | max_profile | зачем |
|---|---|---|---|---|---|
| old | 0,25 | 0,14 | 0,1 | 1,8 | игра сейчас |
| new | 0,031 | 0,235 | 0,09 | 2,0 | перекалибровка Askervein (tools/research/recal) |
| lam | 0,031 | 0,14 | 0,1 | 1,8 | вклад одного λ/h |
| new_z003 | 0,031 | 0,235 | 0,03 | 2,0 | влияние z0 = 0,09 (край диапазона) |
Как применён α. В постановке α и z0 не связаны. α задаёт степенной профиль фона притока min((z/z_sat)^α, 1) с z_sat = 10·max_profile^(1/α). z0 входит только в сопротивление земли C_d = (κ/ln(Δz/2z0))² и в u* = κU10/ln(10/z0). α перекалибровки подогнан при max_profile = 2,0. Эта пара задаёт насыщение профиля на высоте z_sat = 191 м. При игровом 1,8 и α = 0,235 насыщение было бы на 122 м, это другой профиль. Поэтому в наборе new α применён вместе с max_profile 2,0.
Оговорки по физике:
- Штиль. При U10 = 0 фон притока равен нулю, и α и max_profile не действуют вовсе. u* = 0, поэтому z0 действует только через C_d. Отличия old от new в штиль — это λ/h и (слабо) z0.
- α не переносится на Онгудай в полдень напрямую. 0,235 — эффективный показатель нейтрального Askervein: сильный ветер, пустошь и профиль мачты RS до 267 м. Нейтральный лог-профиль при z0 = 0,09 на 10–200 м даёт α ≈ 1/ln(45/0,09) ≈ 0,16. В конвективном полдне сдвиг ещё меньше (≈ 0,1) из-за перемешивания слоя. Здесь α = 0,235 взят как есть, чтобы увидеть влияние на численную сторону. Какое α ставить в игре, решает пользователь (журнал, «30.09.2026 вечер»).
- z0 = 0,09 для Онгудая почти совпадает с игровым 0,1 и лежит внутри диапазона луга и кустарника 0,03–0,3 (Wieringa 1993). «Край диапазона» относится к сетке Askervein (0,01–0,09), а не к степи.
Условия. Онгудай 12:00, ветер 150°. Сетки: цепочка «область 400 м → окно 100 м → окно 50 м», как в игре и
в приёмке А1; отдельно область 200 м (эталон picard/, только для old и new). Случаи: штиль с нагревом,
3 м/с с нагревом, 3 м/с без нагрева, штиль без нагрева (контроль: 11 итераций, поле нулевое);
heat_mode = cbl и surface. Критерии — как у эталона: mom 2e-5, θ′ 5e-7, div 1e-6, не больше 3000 итераций.
Всего 36 сценариев и 120 решений, float32, RTX 4070 SUPER, GPU свободен. Решатель считал 1019 с,
весь прогон по часам — 1094 с.
Матрица (окно 50 м, если не сказано иное)
Итерации: область / w100 / w50; max — предел 3000. Подъём — max w на 200 м над землёй в 1,5 км от старта.
| условия | heat_mode | old | new | lam | new_z003 |
|---|---|---|---|---|---|
| штиль, нагрев | cbl | ok 161/71/161, 0,407 | 161/61/max, 0,50 | 161/141/max, 0,51 | 161/81/max, 0,51 |
| штиль, нагрев | surface | 271/181/max, 1,97 | max/max/max, 2,34 | max/1111/max, 2,26 | max/max/max, 2,04 |
| 3 м/с, нагрев | cbl | 131/41/61, 1,33 | 131/41/51, 1,45 | 131/41/51, 1,36 | 131/41/51, 1,46 |
| 3 м/с, нагрев | surface | 121/51/91, 1,58 | 131/61/max, 2,10 | 141/71/max, 2,24 | 131/61/max, 2,10 |
| 3 м/с, без нагрева | cbl | 151/41/41, 0,89 | 141/41/51, 0,98 | 161/41/51, 0,84 | 141/41/51, 0,99 |
| область 200 м, 3 м/с, нагрев | cbl | max (цикл 5–10e-7) | ok 181 | — | — |
| область 200 м, штиль, нагрев | cbl / surface | 261 / 481 | 251 / max | — | — |
| область 200 м, 3 м/с | surface / без нагрева | 541 / 191 | 181 / 201 | — | — |
| набор | решений | не сошлось | медиана итер. | p90 | GPU, с | мс/итер 400 / 200 / 100 / 50 м |
|---|---|---|---|---|---|---|
| old | 24 | 2 | 126 | 523 | 241 | 11,8 / 38,8 / 9,5 / 14,8 |
| new | 24 | 6 | 136 | 3000 | 372 | 13,0 / 39,2 / 10,5 / 15,2 |
| lam | 18 | 4 | 136 | 3000 | 196 | 12,0 / — / 9,9 / 15,0 |
| new_z003 | 18 | 5 | 106 | 3000 | 210 | 11,8 / — / 9,6 / 14,8 |
- Цена итерации от параметров не зависит. Разница ±5–10 % — шум замера. Так и должно быть: те же ядра и сетки. Время решения растёт только за счёт числа итераций.
- Баланс тепла в норме во всех случаях: остаток ≤ 5e-3 от суммы потоков.
- Приёмка А1 воспроизведена побитно: old, штиль, cbl, w50 — 0,407 м/с, 161 итерация.
Характер несходимости
Во всех 18 несошедшихся решениях невязка не убывает, а качается на плато. Наклон ln θ′ на второй половине
истории ≈ 0, размах ×1,2–3, период 20–140 итераций; у областей с surface — длинные волны ≈ 400–1500 итераций.
Это предельный цикл, а не медленная сходимость. Картинки — out/fig_matrix_hist.png, out/fig_maps.png.
- Где. Везде максимум невязки лежит в полосе верха слоя перемешивания: 0,75–1,1 z_i, z_i = 3362 м над
морем, max на 3,3–3,6 км. На эту полосу приходится 92–100 % Σr², кроме областей с surface (43–58 %).
- 3 м/с: добавляется западная выходная грань. У old 200 м там 92 % Σr², это случай А1.3. У new/lam w50 surface — 23–41 %.
- Штиль: невязка сидит внутри окна, у граней ≤ 26 %, а не у выходной грани.
- Потолок окна. Потолок окон w100 и w50 — 3925–4000 м: 2000 м над максимумом рельефа окна. Верхняя зона релаксации к родителю (1000 м) начинается с 2925–3000 м, поэтому z_i = 3362 м лежит внутри неё. Цикл окон в штиль — в этой зоне.
- Что держит.
- Штиль: оба критерия. Импульс держится 4,6e-5 при пороге 2e-5, θ′ — 3,8e-6 при 5e-7. Это в 2–8 раз выше порога: решения не «чуть-чуть не дотянули».
- 3 м/с: только θ′. old 200 м — 6,7e-7, на грани порога; new w50 surface — 2e-6.
Вывод
- Несходимость не исчезла, она сместилась. Новые параметры лечат известный случай А1.3 (область 200 м, 3 м/с, нагрев cbl: max → ok за 181 итерацию). Зато ломают штиль в окне 50 м при cbl, который на old сходился за 161 итерацию: max, цикл в 7× порога по θ′. Кроме того, при surface не сходятся уже и области. Итого не сошлось 2 из 24 решений на old и 6 из 24 на new.
- Причина — λ/h, а не α и не z0. Набор lam (только λ/h 0,031) даёт ту же картину, что new. new_z003 отличается от new только z0 и повторяет new по сходимости. Подъём у старта при 3 м/с сдвигается на 0,01 (1,45 против 1,46 м/с). z0 = 0,09 на сходимость и цену не влияет. При малом λ/h длина перемешивания λ = max(40 м, λ/h·h) почти везде равна порогу 40 м. Тогда фоновая K в слое мала, и местная K(Ri) по сдвигу и N² становится главной. Её связка с θ′ у верха слоя перемешивания — та самая жёсткая обратная связь из диагноза А1.3. На old её глушил большой фоновый K.
- Физические числа. Подъём у старта при 3 м/с и cbl (все сошлись): 1,33 → 1,45 м/с. Из этой разницы +0,09 м/с даёт профиль притока (α и max_profile), +0,03 — λ/h. В штиль 0,41 → 0,50 м/с, но на несошедшемся решении это число условно.
- Задача А2 не сузилась, а уточнилась.
- Цель — предельный цикл местного K(Ri) ↔ θ′ ↔ w в полосе верха слоя перемешивания. Он есть на обоих наборах и при обоих heat_mode, а при переходе на новые параметры проявляется шире (штиль, окна).
- Выходная грань вторична: её вклад заметен только при ветре. Пересмотр θ′ = 0 на выходной грани в первую очередь не нужен.
- Проверять кандидата А2 надо на новых параметрах, а не на old. Иначе правка «вылечит» 200 м, 3 м/с, а окно 50 м в штиль останется в цикле.
Что делать первым (в А2). Прогнать ту же матрицу (run.py matrix, около 18 мин GPU) на наборе new с
k_relax 0,25, затем с heat_sweeps 8. Это кандидаты А1.3, первый — решение пользователя. Условие приёмки —
все cbl-случаи old и new ok. Surface — отдельно, пока heat_mode не выбран по физике.
Если k_relax не хватит, есть дешёвая проверка: поднять потолок окна так, чтобы z_i не попадал в верхнюю
зону релаксации к родителю. Сейчас top_above = 2000 м, а z_i на 1,5 км выше рельефа окна. Это гипотеза,
её не проверяли.
Переводить игру на новые параметры (λ/h 0,031 и т. д.) — только вместе с правкой сходимости или после неё. Иначе полдень в штиль в окнах игры будет упираться в предел итераций.
Границы разведки
- Один час дня и одно место (Онгудай, 12:00, 150°). Ветер — 0 и 3 м/с; 6–8 м/с не считались. Область 200 м посчитана только для old и new.
- Эталон — Python/CuPy
air.py. Цена итерации в Godot ниже: 400 м — 4,2 мс по bench А1.3 против 11,8 мс здесь, но она тоже не зависит от параметров. Статусы сходимости GPU-решателя игры совпадают с эталоном по контракту C1, здесь это не перепроверялось. - Точки Морриса не пересчитывались: 2 из 64 цепочек, прерванные, лежат в
out/morris_rerun.jsonlи не обрабатывались. Замечание кdocs/research/air-model-sensitivity.md: «139 из 205» — это число точек, где не сошлось любое решение цепочки 400/100/50 м, а не только окно 50 м. Область 400 м не сошлась в 94 из них (45 + 37 + 12).
Картинки и данные
tools/research/a2pre/out/fig_matrix_hist.png— истории невязок θ′ и импульса, old против new (штиль cbl и surface, 200 м 3 м/с и штиль);tools/research/a2pre/out/fig_matrix_iters.png— итерации всех решений матрицы по наборам;tools/research/a2pre/out/fig_maps.png— где невязка в конце (план, max по высоте);tools/research/a2pre/out/tables.md,summary.json,matrix.jsonl(истории невязок, плато, баланс, ключевые числа, где невязка),matrix_maps.npz.