А2: сходимость в штиль
01.10.2026. Ветка air/a2: feature/air-model 0788cf7 плюс влитая разведка air/a2-pre. Разведка, наборы old/new
и матрица описаны в docs/archive/plan/air-model-a2pre.md. Код и данные лежат в tools/research/a2pre/, команды — в
README, раздел «А2». Все таблицы строит один скрипт: analyze_a2.py → out/a2_tables.md.
Итог
k_relax0,5 → 0,1. Это нижняя релаксация обновления местного K(Ri). Значение сменено вair.py → ParamsиAirCase.p.- Сходятся все cbl-случаи обоих наборов: old 16/16, new 16/16.
- Цепочка игры стоит столько же итераций: old 892 → 892, new 3712 (с предельным циклом) → 922.
- Физика та же: сошедшиеся cbl-решения отличаются от прежних не больше чем на 0,01 м/с по ключевым числам.
- Пропуск прохода θ′_d у решения без нагрева (air.py и GPU). Без нагрева и без θ′_d у родителя уравнение θ′_d однородно, его решение θ′_d ≡ 0 точно. Итерации те же, итерация стоит 79 % от полной на 400 м (3,18 против 4,02 мс) и 76 % на 200 м. Так в игре дешевле каждое решение пары «без нагрева», то есть w_mech.
- Параметры модели игры не менялись: λ/h, α, z0, max_profile,
wind.*. Схема, условие на выходной грани и потолок окна (C1 v3, C7 v3) тоже не трогались.
Что гоняли
Условия — как в разведке. Онгудай, 12:00, ветер 150°. Цепочка «область 400 → окно 100 → окно 50 м» и
отдельно область 200 м. Случаи: штиль и 3 м/с, с нагревом и без; heat_mode cbl и surface. Критерий: mom 2e-5,
θ′ 5e-7, div 1e-6, не больше 3000 итераций. Эталон — air.py, float32, CuPy, RTX 4070 SUPER. GPU делили с
тестами и чужим процессом, поэтому время шумное, а итерации детерминированы.
Первая пачка — варианты из задания (
run.py a2, 84 сценария на old и new):- kr25 —
k_relax0,25; - hs8 —
heat_sweeps8; - kr25hs8 — их сочетание;
- top3000 — диагностика гипотезы разведки: потолок окон 3000 м над рельефом окна вместо 2000 м. Тогда z_i лежит ниже верхней зоны релаксации к родителю.
- kr25 —
Отбор (
run.py scan). Проверяли ещё дешёвые численные параметры в границах C1 на двух трудных cbl-случаях. Первый — new, штиль, нагрев, цепочка 400/100/50; не сходится окно 50 м. Второй — old, область 200 м, 3 м/с, нагрев; это случай А1.3. Результаты по вариантам:вариант new: окно 50 м в штиль old: 200 м, 3 м/с k_relax 0,1 ok 211 ok 171 dtau_th 600 max max dtau_th 300 max max dtau_per_m 0,2 max max dtau_per_m 0,15 max max mom_sweeps 4 max max vcycles 2 max max Оба случая сводит только k_relax 0,1.
Вторая пачка (
run.py a2 kr10,kr15, 48 сценариев) — k_relax 0,1 и 0,15 на полной матрице.
Результаты
Цепочка игры — cbl, 400/100/50, штиль и 3 м/с, с нагревом и без: 12 решений. Её цена — Σ итераций × мс/итер варианта (CuPy). У heat_sweeps 8 и высокого потолка окна итерация дороже, у k_relax цена итерации та же.
| вариант | набор | cbl не сошлось | surface не сошлось | Σ итер. цепочки | мс/итер 400 / 100 / 50 м | цена цепочки, с |
|---|---|---|---|---|---|---|
| до А2 (k_relax 0,5) | old | 1 / 16 (200 м, 3 м/с) | 1 / 8 | 892 | 11,8 / 9,5 / 14,8 | 11,0 |
| до А2 | new | 1 / 16 (окно 50, штиль) | 5 / 8 | 3712 | 13,0 / 10,5 / 15,4 | 55,5 |
| kr25 | old | 0 / 16 | 1 / 8 | 892 | 12,1 / 9,9 / 15,1 | 11,3 |
| kr25 | new | 1 / 16 | 2 / 8 | 3712 | 12,3 / 9,9 / 15,3 | 54,5 |
| hs8 | old | 0 / 16 | 1 / 8 | 972 | 16,5 / 13,1 / 19,4 | 16,2 |
| hs8 | new | 1 / 16 | 4 / 8 | 3802 | 16,6 / 13,1 / 19,5 | 71,5 |
| kr25 + hs8 | old | 0 / 16 | 1 / 8 | 952 | 16,7 / 13,2 / 19,7 | 16,1 |
| kr25 + hs8 | new | 0 / 16 | 2 / 8 | 1042 | 22,2 / 13,4 / 25,5 | 22,9 |
| top3000 (диагностика) | old | 1 / 12 | 1 / 6 | 3722 | 12,3 / 12,1 / 20,0 | 69,9 |
| top3000 | new | 1 / 12 | 3 / 6 | 3722 | 12,3 / 12,0 / 20,0 | 69,7 |
| kr10 (выбран) | old | 0 / 16 | 0 / 8 | 892 | 12,2 / 10,1 / 15,4 | 11,5 |
| kr10 | new | 0 / 16 | 2 / 8 | 922 | 12,2 / 10,0 / 15,4 | 12,0 |
| kr15 | old | 0 / 16 | 0 / 8 | 882 | 13,6 / 11,0 / 17,2 | 12,6 |
| kr15 | new | 0 / 16 | 2 / 8 | 932 | 13,0 / 11,0 / 16,4 | 13,0 |
Итерации по решениям. Для цепочки — 400/100/50, для области — 200 м; max — предел 3000:
| условия | old до | old kr10 | new до | new kr10 |
|---|---|---|---|---|
| штиль, нагрев, cbl | 161/71/161 | 161/61/161 | 161/61/max | 161/61/211 |
| 3 м/с, нагрев, cbl | 131/41/61 | 131/41/61 | 131/41/51 | 131/41/51 |
| 3 м/с, без нагрева | 151/41/41 | 151/41/51 | 141/41/51 | 141/41/51 |
| штиль, без нагрева | 11/11/11 | 11/11/11 | 11/11/11 | 11/11/11 |
| 200 м, штиль, нагрев, cbl | 261 | 251 | 251 | 261 |
| 200 м, 3 м/с, нагрев, cbl | max | 171 | 181 | 181 |
| 200 м, 3 м/с, без нагрева | 191 | 191 | 201 | 201 |
| штиль, нагрев, surface | 271/181/max | 261/191/201 | max/max/max | max/2041/471 |
| 3 м/с, нагрев, surface | 121/51/91 | 121/51/81 | 131/61/max | 131/61/61 |
| 200 м, штиль, surface | 481 | 471 | max | max |
| 200 м, 3 м/с, surface | 541 | 161 | 181 | 181 |
Выбор: k_relax 0,1.
- Среди вариантов, где сошлись все cbl-случаи обоих наборов (kr10, kr15, kr25 + hs8), у него наименьшая цена цепочки: 11,5 + 12,0 с.
- По итерациям kr10 и kr15 равны: 892 + 922 и 882 + 932. kr10 взят из-за запаса. Граница лежит между 0,15 и 0,25: при 0,25 окно 50 м в штиль снова в цикле, при 0,15 оно сходится за 221 итерацию, при 0,1 — за 211. Волна Б сменит час, место и параметры, и больший запас демпфирования там нужнее, чем 0,01 м/с расхождения.
- Сочетание kr25 + hs8 тоже сводит все cbl-случаи, но на 13 % больше итераций (1042 против 922 на new). К тому же итерация на 30–80 % дороже из-за 8 прогонок тепла. Цена цепочки — 22,9 с против 12,0 с на new.
Почему это работает.
- Предельный цикл — это обратная связь «местное K(Ri) ↔ θ′ ↔ w» у верха слоя перемешивания. Число Ri, а с ним и K, отзывается на dθ′/dz этой же итерации.
- При малом λ/h фоновое K мало, и K(Ri) скачет от итерации к итерации. Нижняя релаксация 0,1 сглаживает K по итерациям Пикара: обновление за итерацию не больше 10 % разрыва до K(Ri).
- Неподвижная точка при этом та же: K = K(Ri), уравнения не меняются.
- Лишние прогонки тепла (hs8) не помогают: цикл сидит не в неточности решения θ′ за итерацию, а в связи с K. Меньший шаг псевдовремени (dtau) и больше прогонок импульса тоже не помогают.
Гипотеза «потолок окна» отвергнута. top3000 ставит z_i ниже верхней зоны релаксации окна, но окно 50 м в штиль не сходится на обоих наборах. На old оно даже сломалось: max против 161 итерации до. Правка C7 не нужна.
Физика не изменилась
- Сошедшиеся решения kr10 сравнивались с сошедшимися решениями до А2 по ключевым числам: подъём у старта, скорость и θ′ на 50 м, max w, p99 w на 200 м. Наибольшее |Δ| на cbl — 0,007 м/с для old (15 пар решений) и 0,009 м/с для new (15 пар), оба раза в области 200 м в штиль.
- Для сравнения: холодный и тёплый старт одной задачи до А2 расходятся на 0,062 м/с max|Δu|.
- На surface наибольшее расхождение 0,06 м/с (max w, окно 100 м в штиль, old) — в пределах того же допуска остановки.
Подъём у старта (окно 50 м), м/с:
| условия | old до | old kr10 | new до | new kr10 |
|---|---|---|---|---|
| штиль, нагрев, cbl | 0,407 | 0,405 | 0,504 (max) | 0,507 |
| 3 м/с, нагрев, cbl | 1,33 | 1,33 | 1,45 | 1,45 |
| 3 м/с, без нагрева | 0,894 | 0,892 | 0,98 | 0,98 |
| 200 м, 3 м/с, нагрев, cbl | 1,44 (max) | 1,43 | 1,56 | 1,56 |
Askervein check25 (recal/run_grid.py check25, нейтральный случай): χ² 68,06/44 — как до А2. Итераций 91, как
до. Наблюдаемые отличаются не больше чем на 1e-5.
Игра: до и после (GPU-решатель, параметры игры = old)
Логи — tools/research/a2pre/out/bench/{before,after}_*.log. Итерации те же. Время шумное: те же прогоны до
А2 давали разброс 4,2–4,6 мс/итер на 400 м.
| что | до А2 | после |
|---|---|---|
GPU-тесты test_air_ | 58/58 | 58/58 |
| контракты (headless) | — | 26/26 |
| bench 400 м: итерация / без θ′_d | 4,64 мс / — | 4,02 мс / 3,18 мс (79 %) |
| bench 200 м: итерация / без θ′_d | 16,3 мс / — | 15,0 мс / 11,3 мс (76 %) |
| bench 400 м, пара (без + с), загрузка | 280 итер. (151 + 131), GPU 1,44 с | 280 итер., GPU 1,15 с |
| bench 200 м, 3 м/с с нагревом | пропущено (max 3000) | ok 170 итер. (эталон 171), GPU 2,7 с |
| bench 200 м, 3 м/с, пара, загрузка | пропущено | 370 итер. (191 + 171), GPU 5,2 с |
| «Рассчитываем ветер», область 400 м, 3 м/с (AirRuntime) | 3,73 с стены, GPU 1,37 с, итер. [150, 130] | 3,55 с, GPU 1,17 с, [150, 130] |
| загрузка с окнами (AirRuntime) | 6,49 с стены | 6,29 с |
| окно 50 м при загрузке | итер. [40, 70], GPU 635 мс | [50, 60], GPU 567 мс |
| пересчёт по сроку, тёплый | GPU 1,02 с, итер. [80, 130] | GPU 0,91 с, [80, 130] |
На новых параметрах (волна Б) цепочка в штиль сходится за 161/61/211 итераций вместо предела 3000 в окне 50 м.
Тёплый старт того же поля — теперь 20 итераций вместо 10.
- K не входит в состояние тёплого старта. Он начинает с K_b и при k_relax 0,1 доходит до K(Ri) за ~20 итераций (0,9²⁰ ≈ 0,12).
- Порог проверки в
test_air_picard_bench.gd::test_warm_startподнят с 10 до 20. - Тёплый пересчёт соседнего срока (12:00 → 12:30) — 50 итераций, как до.
- Расхождение холодного и тёплого решения 12:30 выросло до 0,113 м/с max|Δu| (было 0,062). Оба решения прошли критерий, это его допуск при более медленном K.
Фикстуры
Пересчитаны тем же генератором, k_relax теперь записан в params JSON:
picard/:picard_gpu_refs.py. Область 200 м, 3 м/с с нагревом: max 3001 → ok 171.window/:window_gpu_refs.py. Окно 50 м без нагрева: 41 → 51.ref/:fixtures.py, итерации те же — 10/710/60/320.
Пропуск 200 м, 3 м/с в bench снят.
Границы
- Одно место и один час: Онгудай, 12:00, 150°. Ветер 0 и 3 м/с, 6–8 м/с в матрице не считались (6 м/с есть в фикстурах и bench — сходится).
- Surface (выбор heat_mode — задача А3) на new не сходится в 2 из 8 решений: штиль, область 400 и 200 м — длинные волны невязки, как в разведке. k_relax их не лечит (при 0,25 — тоже 2 из 8).
- Точки Морриса не пересчитывались (волна Б).
- Цена итерации в CuPy и в Godot разная (400 м: 12 и 4 мс), отношение вариантов то же.
Открытые вопросы (координатору)
- K в состоянии тёплого старта (
state():nu,nuh) вернуло бы тёплому старту тех же условий 10 итераций вместо 20 и сократило бы пересчёт в полёте на время релаксации K. Это меняет форматstate()иwarm(C9, AM-06Б) — через координатора. - Правки C1 v3 (θ′ на выходной грани) и C7 v3 (потолок окна) по итогам А2 не нужны.