Обтекание склона ветром: что у нас сейчас, как в жизни, что можно сделать
Исследование, без правок кода. Повод — отзыв пилота: «обтекание склона ветром ощущается не физично». Дополнительно от пилота:
- «Когда ветер дует в понижение между двумя вершинами (седловина, перевал) — там труба, ветер сильнее». Разобрано отдельно (§3.6, §4, варианты в §5).
- «А провалы чёткие, бросает конкретно ногами к тросам, похоже» — провалы и удары вниз ощущаются правильно. Любая переделка склонового потока обязана их сохранить (§1.6).
Сентябрь 2026. Ссылки на источники — в тексте и в конце.
1. Как сейчас считается ветер у рельефа
Всё проходит через одну функцию Atmosphere.air_velocity_at(pos)
(scripts/atmosphere/atmosphere.gd). Её вызывает модель полёта в трёх точках — центр и две
консоли (FlightModel._step_air, air_sampling.tip_fraction), поэтому разница потоков по размаху
кренит крыло. Рельеф атмосфера видит через кеш GroundField (ground_field.gd): сетка 30 м
(ground.cell_m), в каждом узле — высота, dh/dx, dh/dz (центральные разности, база 60 м),
«линия тени» и «превышение гребня» против ветра; между узлами — билинейно.
1.1 Горизонтальный ветер
u = speed_ref · profile(agl) · altitude_factor(msl)
profile(agl) = min((max(agl, 1 м) / 10 м)^0,14 ; 1,8)
altitude_factor(msl)= clamp(1 + 0,6 · (msl − msl_старта)/1000 ; 0,5 ; 2,0)
направление = всегда направление прогноза (ŵ), одно на весь мир- Профиль по высоте — степенной закон от высоты над землёй под пилотом (agl). Над гребнем на 50 м AGL ветер тот же, что над долиной на 50 м AGL.
altitude_factor— ветер растёт с высотой над морем (над стартом +60 %/км). Это единственное, что делает ветер над вершиной сильнее, чем в долине, — но оно зависит только от абсолютной высоты, а не от формы рельефа.- Направление никогда не меняется рельефом: поток не огибает холм сбоку, не затекает в
лощину, не поворачивает вдоль долины. Ослабление только одно — в подветренной зоне
(
lee.wind_reduction0,6) и обратный поток ротора.
1.2 Склоновый подъём (вертикаль)
shift = min(0,8 · agl ; 400 м) # точка берётся ВПЕРЕДИ по ветру
g = ground.sample(pos + ŵ·shift) # высота и градиент там
slope = ŵ · ∇h(g) # уклон вдоль ветра, безразмерный
agl_s = max(y − h(g), 0) # высота над той точкой
w_ridge = clamp(0,85 · u · slope · exp(−agl_s / 250 м) ; ±6 м/с) · (1 − lee)(configs/atmosphere.json → ridge: efficiency 0,85, decay_height_m 250,
forward_shift_factor 0,8, forward_shift_max_m 400, max_lift_ms 6.)
Смысл: у самой земли воздух идёт вдоль склона, w = U·tg(уклона) (граничное условие), и 85 % этого
приписывается пилоту. С высотой зона подъёма выдвигается против ветра (сдвиг 0,8·agl) и затухает
экспонентой с постоянным масштабом 250 м, одинаковым для любого рельефа.
1.3 Подветренная зона и ротор
Линия тени s = max_d (h(p − ŵd) − d·tg 12°) по отсчётам d = 60…1600 м против ветра. Пилот ниже
неё (и в слое сдвига 60 м над ней) — в зоне силы lee 0..1, умноженной на clamp(r / 60 м), где r
— превышение гребня над землёй под пилотом. В зоне: опускание 0,25…0,7 · u · lee, болтанка
σ = 0,5…0,9 · u · lee, редкие рывки вниз 1,0 · u · lee · g (пятна шума 120 м), обратный поток у
земли −0,9 · u · lee · g · exp(−agl / 0,4r); жёсткость g растёт от ветра 2 до 5 м/с. Подробно —
docs/guide/atmosphere.md, проверка — tests/atmosphere/test_lee_rotor.gd.
Отдельно — подветренные волны (wave_field.gd, линейная теория вдоль ветра со Скорером), по
умолчанию выключены (wave_strength 0 во всех пресетах).
1.4 Турбулентность у склона
σ = √(механика² + конвекция² + край термика² + ротор² + …), механика 0,14 · u · (1 + e^(−agl/150)).
От формы склона механическая болтанка не зависит — только от ветра и высоты над землёй. Поле
шума — «замороженное», переносится ветром одного направления.
1.5 Где это не физично (по пунктам)
Сравнил нашу формулу с линейным потенциальным обтеканием двумерного хребта (профиль Аньези,
H = 300 м, ветер 5 м/с; скрипт — в сессии, воспроизводится за минуту). Максимум w на наветренной
стороне на заданной высоте над землёй:
| agl, м | крутой хребет (L = 300 м, макс. уклон 33°) — у нас / потенц. | пологий (L = 800 м, 14°) — у нас / потенц. | прирост ветра над гребнем (потенц.) крутой / пологий |
|---|---|---|---|
| 20 | 2,7 / 2,9 | 1,0 / 1,2 | +88 % / +36 % |
| 50 | 2,5 / 2,4 | 0,9 / 1,1 | +73 % / +33 % |
| 100 | 2,3 / 1,8 | 0,75 / 0,96 | +56 % / +30 % |
| 200 | 1,8 / 1,2 | 0,54 / 0,78 | +36 % / +24 % |
| 300 | 1,4 / 0,8 | 0,39 / 0,64 | +25 % / +20 % |
| 500 | 0,7 / 0,5 | 0,20 / 0,46 | +14 % / +14 % |
(L — полуширина хребта на половине высоты. Потенциальный поток — верхняя оценка без трения и отрыва; порядок величин подтверждается измерениями, §3.1.)
Выводы:
- Сила подъёма у склона в целом правдоподобна — у земли совпадает с потенциальным потоком в пределах 10–20 %, место максимума тоже (x ≈ −0,6…−0,7 L).
- Высота полосы подъёма не зависит от размера склона. В жизни (и в теории) поле возмущения затухает на масштабе ширины склона L: узкий крутой гребень — подъём низкий, «прижатый»; широкий склон — полоса высокая. У нас всегда 250 м: над узким гребнем подъём тянется слишком высоко (на 300 м AGL — 1,4 вместо 0,8 м/с), над широким склоном гаснет слишком рано (0,39 вместо 0,64).
- Нет ускорения ветра над гребнем. Реально на бровке ветер на 30–90 % сильнее, чем перед склоном (§3.1) — пилот чувствует это как «на бровке встал, не проходишь вперёд», «на верхушке дует». У нас горизонтальный ветер меняется только от высоты над морем.
- Мелкий рельеф бьёт на любой высоте. Уклон берётся в одной точке с базой 60 м. Лощинка
шириной 100 м даёт такой же провал на 100 м AGL, как у земли (только умноженный на общую
экспоненту 250 м). Реально возмущение от детали размером λ затухает с высотой как
exp(−2π z / λ): на высоте ~λ/2 от неё почти ничего не остаётся. Это прямо видно вdocs/guide/atmosphere.md: наtugaya_southиridge_west«рядом, в 50–100 м вдоль гребня, провал такой же силы», что и пик. Возможное следствие — склон «пятнистый», полоса подъёма рваная. (Гипотеза, не проверял:height_at— DSM Copernicus с кронами; ступенька у опушки 10–12 м даёт у нас «склон» ~0,2 на 60 м, т. е. заметный подъём/провал на опушке и на высоте.) - Поток не трёхмерный. Уединённая сопка, отрог («нос») и цирк («чаша») с одинаковым уклоном вдоль ветра дают у нас одинаковый подъём. Реально: сопку воздух частично обтекает с боков (подъём и ускорение слабее, чем у длинного хребта: коэффициент 1,6 против 2,0 в §3.1), в чаше поток сходится — подъём сильнее; на отроге — расходится.
- Угол ветра к хребту учтён только как
cos(скалярное произведение с градиентом). Поток вдоль склона, «скатывание» ветра вдоль хребта и усиление болтанки при косом ветре — нет. - Седловина / перевал («труба») — нет, и даже наоборот. В седловине уклон вдоль ветра обычно положе, а высота над морем ниже → у нас в седловине и подъём, и ветер слабее, чем на соседних вершинах. Сжатия потока в понижении нет вообще (§3.6).
- Нет устойчивости атмосферы. Склоновый поток одинаков в устойчивый и неустойчивый день. В жизни при устойчивой стратификации (инверсия, утро) низкий воздух не переваливает через высокие вершины, а обтекает их и идёт в понижения — «труба» в перевалах сильнее, подъём ниже.
- Масса не сохраняется.
wи горизонталь считаются независимо: над гребнем воздух поднимается, но не ускоряется; приshiftнад самой бровкой пилот уже получает опускание подветренного склона. - Отрыв — только через «линию тени» с фиксированным углом 12°, не зависящим от ветра, шероховатости и формы гребня; наветренного отрыва у подножия крутого обрыва («пузырь») нет.
1.6 Что даёт «чёткие провалы» — не ломать
По отзыву пилота провалы и удары вниз — правильные. Они складываются из:
| Источник | Где | Параметры |
|---|---|---|
| Кольцо опускания вокруг термика | thermal_field.gd, профиль Gedeon | thermal.ring_sink_factor 1,6 |
| Фоновое опускание между термиками | air_velocity_at, _bg_sink | пресет background_sink_ms |
| Опускание и рывки вниз за гребнем | _lee_flow | lee.danger_sink_per_wind, burst_* |
| Вертикальные пульсации (мелкие вихри 45 м) | WindModel.gust_unit, vertical_ratio 0,7 | turbulence.*, mech_per_wind |
| Роторы волн, грозы | wave_field.gd, storm_field.gd | — |
| Отклик крыла и «тела» | FlightModel (три точки забора воздуха → угол атаки → перегрузка), LoadMeter.load_raw, GliderVisual._update_buzz (buzz.kick_m_per_g — толчок трапеции от мгновенной перегрузки) | flight.json → visual.buzz, load_factor.filter_s |
Правила для любых переделок склона:
- заменять только слагаемое
w_ridgeи множитель горизонтального ветра;lee, термики, фон, турбулентность и отклик крыла — не трогать; - механическую болтанку и подветренное опускание считать от ветра без ускорения над гребнем (иначе σ на бровке вырастет на те же 30–90 % — это уже другая болтанка);
- после правки гонять
test_ridge_starts,test_lee_rotor,tools/flight/roll_sway.gdи дать пилоту слетать в тот же день.
2. Реальная физика: итог в числах
| Явление | Типичные значения | Источник |
|---|---|---|
| Ускорение над вершиной (у земли, ~10 м) | ΔS_max ≈ B·H/L: B ≈ 2,0 (длинный хребет), 1,6 (сопка), 0,8 (уступ/обрыв на плато) | Jackson & Hunt 1975; Taylor & Lee 1984 |
| Спад ускорения с высотой | ΔS(z) ≈ ΔS_max · exp(−A·z/L), A ≈ 3 (хребет), 4 (сопка), 2,5 (уступ) | Taylor & Lee 1984, так же в ASCE 7 (K3) |
| Насыщение | при H/L > 0,5 (средний уклон ≳ 14–27°) ускорение больше не растёт — поток отрывается | ASCE 7 (правило «H/Lh ≤ 0,5») |
| Askervein (H = 116 м, уклоны до 20–30 %) | ускорение на вершине на 10 м ≈ +80 % (по сводкам) | Taylor & Teunissen 1987 |
| Седловина (натурные замеры) | на 10 м AGL в седловине +40–60 % к подходу | замеры над седловиной, Boundary-Layer Meteorol. |
| Хребты в горах в синоптический ветер | на гребнях ветер до ×3 к долине | mountainmeteorology.org |
| Где лучший подъём | чуть ниже бровки на наветренной стороне; с набором высоты — дальше вперёд от склона | Condor, York Soaring, Chess in the Air |
| Угол ветра | хорошо ±20° от перпендикуляра; при ≥45° подъём сильно слабее, болтанка больше | Chess in the Air, York Soaring |
| Ветер для парения | работает от ~5 м/с (10 уз), хорошо 7–10 м/с; болтанка ∝ ветру² | Chess in the Air |
| Отрыв за гребнем | начинается при подветренных уклонах порядка 15–20° и круче (зависит от шероховатости) | Wood 1995 и др. |
3. Реальная физика подробнее
3.1 Ускорение над гребнем (линейная теория)
Jackson & Hunt (1975) разделили поток над пологим холмом на тонкий внутренний слой (где трение,
толщина l из l·ln²(l/z0) ≈ 2κ²L — для наших склонов единицы–десятки метров) и внешний
почти невязкий. Почти всё ускорение — во внутреннем слое, максимум — на ~1/10 его толщины.
Практические «правила» Taylor & Lee (1984) (они же в строительной норме ASCE 7, коэффициент
Kzt = (1 + K1·K2·K3)²):
ΔS_max = B · H / L, где H — высота холма, L — расстояние от вершины до половины высоты против ветра;ΔS(z) = ΔS_max · exp(−A · z / L);- вдоль ветра ускорение падает от вершины линейно до нуля на ~1,5 L перед ней (ASCE 7, K2);
- при H/L > 0,5 брать H/L = 0,5 (обтекание с отрывом).
Проверка на Askervein (H = 116 м, L ≈ 250 м): 1,6 · 0,46 ≈ 0,74 против измеренных ≈ 0,8.
Вывод для нас: ускорение над бровкой порядка десятков процентов и затухает на масштабе L — у узкого гребня прижато к земле, у широкого — толще.
3.2 Полоса подъёма
- У земли воздух идёт вдоль склона,
w ≈ U·tg(уклона). - С высотой вертикальная скорость гаснет на масштабе ~L, зона подъёма смещается вперёд (против
ветра): «чем выше — тем дальше от склона» (York Soaring, Condor). Наше смещение
0,8·aglкачественно так же (в потенциальном потоке максимум уходит примерно на 0,3·agl, при круче склоне — дальше). - «Лучший подъём чуть ниже бровки на наветренной стороне; если провалился ниже бровки — обратно не вылезешь» (York Soaring). «Сжатие» линий тока над гребнем — ускорение §3.1.
- Высота полосы — «примерно высота склона», на хорошем хребте — до 1–2 высот над гребнем (для планеров в FSX-моделях — «на 300–600 м выше гребня с убыванием»).
- Чаша/цирк собирает поток и даёт подъём лучше, выпуклый отрог — хуже (поток расходится) (Condor: «bowls and gullies channel the air and give improved lift»; Chess in the Air).
- Устойчивый воздух — ровный предсказуемый подъём, но сильнее опускание и болтанка за гребнем; неустойчивый — подъём рвут термики.
3.3 Отрыв и роторы
- На пологих холмах (Askervein, уклоны < 20 %) поток прилегает почти всегда.
- Отрыв за гребнем начинается при подветренных уклонах порядка 15–20° и круче, раньше — при шероховатой поверхности (лес) и острой бровке (Wood 1995). Зона возвратного течения тянется на несколько высот хребта за гребень.
- У подножия крутого обрыва на наветренной стороне тоже бывает «пузырь» с возвратным течением (наблюдался лидаром на натуре, модели часто его не видят).
- RANS/CFD плохо предсказывают турбулентность в следе даже на Askervein; LES лучше. То есть
подветренная сторона — самое трудное место для любых моделей, и эмпирика (наша
lee) там вполне оправдана.
3.4 Профиль ветра у земли
Логарифмический/степенной профиль (показатель 0,14 — открытое место, лес — больше). Над гребнем профиль «выпрямляется»: максимум ускорения у земли, поэтому на бровке ветер у земли почти такой же, как на 50–100 м — на старте «дует сильнее, чем в долине» и ощущается «ровнее».
3.5 Устойчивость, блокировка
Число Фруда Fr = U / (N·H) (N — частота Брента–Вяйсяля, в конфиге wave.default_stability_n_per_s
0,01 1/с). По Шеппарду воздух ниже высоты Hs = H·(1 − Fr) не переваливает через препятствие, а
обтекает его. Пример: U = 5 м/с, N = 0,01, H = 500 м → Fr = 1, почти всё переваливает; при инверсии
(N = 0,02) Fr = 0,5 — нижняя половина склона «блокирована», воздух уходит в обход и в понижения.
3.6 Седловины, перевалы, ущелья («труба»)
- Малый масштаб (сотни метров – км): сохранение массы — где сечение потока сужается, скорость растёт (эффект Вентури в бытовом смысле). Натурные замеры над седловиной: +40–60 % на 10 м AGL к подходу. Поток в седловине может быть сильнее, чем на соседних (более высоких!) вершинах (mountainmeteorology.org).
- Зависит от устойчивости: при устойчивом воздухе (Fr < 1) низкий воздух не лезет через вершины, а идёт через понижение — «труба» резко усиливается. В неустойчивый день (перемешивание) эффект слабее.
- Зависит от геометрии: чем глубже седловина относительно соседних вершин и чем уже, тем сильнее; долина, выходящая к перевалу по ветру, работает как воронка.
- Мезомасштаб (км – десятки км, gap winds): ускорение уже не «Вентури», а гидравлическое — разность давлений холодного воздуха по обе стороны хребта; максимум скорости на выходе из прохода, а не в самом узком месте; сильный ветер на ~100 м над землёй и болтанка/роторы под ним; спокойный ветер на старте не гарантирует спокойную посадку у выхода ущелья (XC Mag).
- Для пилота это значит: в седловине сильнее встречный (медленнее летишь вперёд), выше подъём на наветренном склоне самой седловины, сильнее болтанка и опускание за ней (ветер быстрее — и подветренная зона злее).
4. Как это делают другие симуляторы и инженеры
| Подход | Что даёт | Цена | Источник |
|---|---|---|---|
| Condor 3 (планерный сим, закрытый) | подъём зависит от расстояния до склона, ветра, высоты, высоты над долиной, угла ветра к хребту; зона лучшего подъёма уходит вперёд к бровке; ускорение над вершиной; чаши и лощины сводят поток; за гребнем турбулентное опускание; волны | формулы не раскрыты | condorsoaring.com |
FSX sim_probe (Forster-Lewis; по памяти, та же схема перенесена во FlightGear ridge_lift) | 5 отсчётов высоты по линии ветра (0, −250, −750, −2000, +100 м), уклоны между ними, нормировка `sin(atan(5· | slope | ^1,7))`, взвешенная сумма × ветер; множитель по высоте: 0–40 м AGL 0,5→1, 40–130 м — 1, выше — экспонента; получается до +6,9 м/с на бровке и −5,4 м/с за гребнем |
| Орнитологи (подъём для хищных птиц, Brandes & Ombalski 2004) | w = v · sin(уклон) · cos(аспект − ветер) — по сути то же, что у нас, на сетке 10 м | тривиально | PMC7434798 |
| Строительные нормы, Taylor & Lee | ускорение над хребтом/сопкой/уступом по формулам §3.1 | тривиально | ASCE 7 §26.8 |
| Линейная теория (Jackson–Hunt, WAsP, MS3DJH) | 3D-поле возмущения через БПФ рельефа; ускорение над вершинами, обтекание сопок, сход в чашах; без отрыва | БПФ сетки один раз на направление ветра | Jackson & Hunt 1975; Hunt 1988 |
| Массосогласованная диагностическая модель (WindNinja, MATHEW) | берём начальный ветер, минимально правим его так, чтобы ∇·V = 0 над рельефом; параметр устойчивости α (сколько потоку «разрешено» подниматься вместо обтекания) → при устойчивом воздухе поток идёт в перевалы и долины; сетка ~100 м, 50×50 км, ~10 с на ПК; отрыва и роторов нет | 3D-сетка, итерационный решатель | WindNinja docs; Wagenbrenner 2016 |
| CFD (RANS/LES, OpenFOAM, WindNinja momentum solver) | отрыв, рециркуляция, всё; LES даже след | часы на направление; объёмные данные | Askervein benchmarks |
Наша модель — это «FSX/орнитологи» (V·∇h с затуханием по высоте) плюс более развитая подветренная часть. Condor делает больше: ускорение над вершиной, чаши, зависимость от высоты над долиной.
5. Варианты для нас — от дешёвого к дорогому
Во всех вариантах результат подключается к air_velocity_at одинаково:
u_h = u · (1 + ΔS(pos)) # ускорение над гребнем / в «трубе»
dir = ŵ повернутое на δ(pos) # (для 3D-вариантов) обтекание сбоку, затекание в понижения
w = w_terrain(pos) · (1 − lee) # вместо w_ridge
mech, lee_sink — от u БЕЗ ускорения # §1.6: провалы не трогаемНовые величины кладутся дополнительными каналами в куски GroundField (_CH 5 → 7–10), чтобы
в air_velocity_at оставалось одно билинейное чтение — стоимость вызова почти прежняя. Кеш
перестраивается при смене ветра (уже так: set_wind_dir).
A. Улучшенная аналитика (дёшево: 2–4 дня с тестами; рантайм ≈ прежний)
- Сглаживание уклона с высотой. Пирамида градиентов (сглаженный рельеф 60 / 120 / 240 / 480 м)
в кеше; на высоте agl брать уровень с радиусом ~agl (интерполяция между уровнями). Это
дешёвая замена
exp(−|k| z)линейной теории: мелкие лощины и опушки перестают давать провалы на 100 м AGL, полоса подъёма становится ровнее. Лечит пункт 4. - Масштаб затухания = ширина склона. По профилю рельефа вдоль ветра (у нас уже есть отсчёты
против ветра для линии тени; добавить по ветру) оценивать H и L локального гребня;
decay = c · Lвместо 250 м. Лечит пункт 2. - Ускорение над гребнем по Taylor–Lee:
ΔS = B · min(H/L, 0,5) · (1 − |x|/(1,5L)) · exp(−A·agl/L), B/A для хребта/сопки по поперечной протяжённости. Лечит пункт 3. - «Труба». Признак седловины: по линии поперёк ветра (±0,5…2 км) рельеф с обеих сторон выше
точки, а вдоль ветра точка — локальный гребень. Глубина понижения D и ширина W → множитель
ветра
1 + k · D/(D + W·c)(калибровать по +40–60 %), с усилением при устойчивом воздухе (Fr изwindиstability_n_per_sпресета). Грубо, но даёт именно то, что описал пилот. - Чаша / отрог: поправка к подъёму по кривизне рельефа поперёк ветра (вогнуто → ×(1+…), выпукло → ×(1−…)).
Плюсы: быстро, ничего нового в архитектуре, всё в GDScript, работает на любых локациях (в том числе загружаемых по координатам). Минусы: набор эвристик, могут конфликтовать; горизонталь и вертикаль не согласованы; в сложном рельефе (несколько гребней подряд) — оценка H/L неоднозначна.
B. Линейная 3D-теория через БПФ (средне: 1–2 недели; расчёт при смене ветра)
Потенциальное (или Jackson–Hunt) возмущение: η̂(k, z) = ĥ(k) · e^(−|k| z),
u' = −U ∂η/∂z, v' и w = U ∂η/∂x — из одного БПФ рельефа вокруг пилота (например, 20×20 км
на сетке 40–80 м → 256²–512²) на 4–6 высот над землёй. Устойчивость можно добавить так же, как
уже сделано в wave_field.gd (там 1D-свёртка вдоль ветра той же природы).
- Даёт согласованно: подъём (с правильной высотой полосы для узких и широких склонов), ускорение над гребнем, обтекание сопок сбоку, сход в чашах, поворот ветра у рельефа; мелочь рельефа сама гаснет с высотой.
- «Труба» в седловине — частично (нейтральная теория даёт сход потока в понижение гребня, но не
блокировку; блокировку можно добавить через «срезание» рельефа выше
Hs = H(1 − Fr)при расчёте — грубый приём). - Отрыва нет — подветренная часть остаётся нашей
lee, как сейчас. - Где считать: БПФ 512² в GDScript — секунды–десятки секунд (в потоке при загрузке/смене ветра — терпимо); лучше — compute shader Godot (RenderingDevice) или маленький GDExtension (C++, FFTW/ pocketfft), тогда доли секунды. Память: 512² × 3 компоненты × 5 высот × float16 ≈ 8 МБ.
- Проверка: Askervein-подобный холм в тесте (+74–80 % на 10 м), наши 10 стартов.
C. Массосогласованное диагностическое поле (WindNinja-подобное) (дорого: 2–4 недели)
3D-сетка по рельефу (например 10×10 км × 1,5 км, 50 м по горизонтали, 20 уровней ≈ 0,8 млн ячеек), начальное поле = наш профиль ветра, решение уравнения Пуассона на поправку (сопряжённые градиенты/многосеточный) с параметром устойчивости α.
- Даёт то же, что B, плюс блокировку и «трубу» в перевалах при устойчивом воздухе естественным образом, и корректное сохранение массы в сложном рельефе (несколько гребней, ущелья).
- Отрыва и роторов нет (WindNinja mass-conserving этого не умеет) —
leeостаётся. - В GDScript — слишком медленно (минуты); нужен C++ (GDExtension) или compute shader, либо офлайн-инструмент для встроенных локаций (можно гонять сам WindNinja — он открытый, CLI; выход — сетки ветра на заданной высоте над землёй, 3D-поле — через VTK; вертикаль можно восстановить из неразрывности). Для локаций «по координатам» — только если решатель есть в рантайме.
- Хранение: поле на направление ветра (8–16 направлений) × несколько высот; для 20×20 км вокруг стартов — десятки МБ на локацию.
D. Офлайн-CFD (RANS/LES) для встроенных локаций (очень дорого: 1–2 месяца на инструментарий)
OpenFOAM или момент-решатель WindNinja, 8–16 направлений на локацию, часы счёта на каждое, нейтральный поток масштабируется по скорости (одно решение на направление).
- Даёт отрыв, реальные роторы, пузыри у обрывов, трубы.
- Минусы: только для 4 встроенных локаций (для «по координатам» не работает), сотни МБ данных, сложная цепочка, и даже CFD плохо даёт турбулентность в следе (Askervein) — то есть самое «ощущаемое» (провалы) всё равно останется эмпирикой. Сломать текущие хорошие провалы тут проще всего.
Сводка
| Высота полосы | Ускорение над бровкой | Мелочь рельефа | Сопка/чаша | «Труба» | Отрыв | Трудоёмкость | Рантайм | |
|---|---|---|---|---|---|---|---|---|
| Сейчас | фикс. 250 м | нет | бьёт на высоте | нет | наоборот (слабее) | линия тени 12° | — | — |
| A | ≈ по L | по формуле | сглажена | эвристика | эвристика | как сейчас | дни | ≈ 0 |
| B | да | да | да | да | частично | как сейчас | 1–2 нед. | секунды при смене ветра |
| C | да | да | да | да | да (с α) | как сейчас | 2–4 нед. + C++ | секунды (C++) |
| D | да | да | да | да | да | да | месяцы | данные с диска |
6. Рекомендация
- Сначала — вопросы пилоту (§7): «не физично» может означать очень разное (полоса слишком высокая/низкая, рваная, нет ветра на бровке, нет трубы). Ответы решают, какие пункты A нужны.
- Затем вариант A, пункты 1–4 (сглаживание по высоте, масштаб = ширина склона, ускорение над
гребнем, «труба» в седловине) — это закрывает почти все найденные расхождения, работает на
любых локациях и не трогает провалы. Горизонтальное ускорение подключить к полёту, но не к
болтанке и не к подветренному опусканию. Прогнать
test_ridge_starts(набор на слабых стартах может измениться — в обе стороны),test_lee_rotor, новый тест «Askervein» и тест седловины. Не шлифовать — дать пилоту слетать. - Вариант B — только если после A пилот всё ещё говорит «воздух течёт не так» про обтекание сопок/чаш и повороты ветра у рельефа. Это самое «физичное за свои деньги» и ложится рядом с уже существующей линейной волновой моделью.
- C и D — не рекомендую сейчас: дорого, D не работает на локациях по координатам, а подветренная сторона (где «провалы» и главное ощущение) у них не лучше нашей эмпирики.
7. Вопросы пилоту — простыми словами
- Когда летаешь вдоль склона — подъём слишком сильный, слишком слабый или нормальный по силе?
- Подъём слишком близко к склону (приходится жаться) или слишком далеко (держит и в стороне от горы)?
- Насколько высоко над бровкой держит? В жизни на таком склоне выше какой высоты подъём заканчивается — примерно столько, сколько высота самого склона, меньше, больше?
- Когда подходишь к бровке и выше — чувствуется ли, что наверху дует сильнее (стоишь на месте, трудно пройти вперёд)? В игре этого не хватает?
- Подъём вдоль склона слишком ровный (одинаковый везде) или наоборот рваный — через каждые сто метров провал? Как в жизни?
- Над выступом горы («носом») и над впадиной («цирком», «чашей») разница есть? В жизни где лучше?
- Если ветер дует наискось к склону — в игре подъём пропадает слишком рано, слишком поздно или как в жизни?
- Седловина / перевал («труба»): насколько там в жизни сильнее ветер — чуть-чуть, в полтора раза, в два? Всегда или в какие дни (утро, вечер, прохладный спокойный день)? Где сильнее всего — в самой низкой точке, перед ней или на выходе за ней? Там болтает сильнее?
- Когда перелетаешь за гребень — провал и болтанка сейчас правильные? (Провалы и «ногами к тросам» — хорошо, это не трогаем.) Не слишком ли рано/поздно начинается опускание, если лететь над самой бровкой?
- Ветер у земли на старте и на посадке — похож на жизнь? На бровке у старта в жизни ветер сильнее, чем внизу у подножия?
- Есть ли конкретное место в игре (старт, склон), где «не физично» заметнее всего? Если можно — при каком ветре.
Источники
- Jackson P.S., Hunt J.C.R. (1975) Turbulent wind flow over a low hill. QJRMS 101, 929–955 — https://rmets.onlinelibrary.wiley.com/doi/10.1002/qj.49710143015
- Hunt J.C.R. et al. (1988) Turbulent shear flows over low hills. QJRMS — https://rmets.onlinelibrary.wiley.com/doi/abs/10.1002/qj.49711448405
- Taylor P.A., Lee R.J. (1984) Simple guidelines for estimating wind speed variations due to small-scale topographic features. Climatol. Bull. 18 (упоминание и применение — https://www.researchgate.net/publication/239352140_Experimental_study_of_topographic_effects_on_gust_wind_speed)
- Askervein: Taylor & Teunissen (1987) — https://link.springer.com/article/10.1007/BF00121863 ; бенчмарк — https://wemep.readthedocs.io/en/latest/windconditions/benchmarks/askervein.html ; ускорение на фиксированных высотах — https://link.springer.com/article/10.1007/BF00128406
- ASCE 7 топографический коэффициент Kzt — https://windload.solutions/topographic-effects-wind-loads (числа B/A/«H/L ≤ 0,5» — по памяти из ASCE 7 §26.8 и Taylor & Lee, сверить при реализации)
- Отрыв за холмами: Wood N. (1995) The onset of separation in neutral, turbulent flow over hills — https://link.springer.com/article/10.1007/BF00710894 ; PIV-измерения отрыва на 2D-холмах — https://link.springer.com/article/10.1007/s10546-013-9806-1 ; «пузырь» у края уступа — https://www.sciencedirect.com/science/article/abs/pii/S016761052100091X
- Блокировка, линия раздела (Шеппард) — https://link.springer.com/article/10.1007/s10546-015-0101-1 , https://glossary.ametsoc.org/wiki/dividing-streamline/
- Седловины и перевалы — https://link.springer.com/article/10.1007/BF00120015 , https://mountainmeteorology.org/articles/wind-speed-elevation-relationship/ , https://xcmag.com/paragliding-techniques-paramotoring-skills/meteorology-mountain-gap-winds/ , https://en.wikipedia.org/wiki/Mountain-gap_wind
- Парение на склоне: https://www.condorsoaring.com/soaring/ , https://yorksoaring.com/wp-content/uploads/coursework/GliderInstructorGSX/ridge_soaring.html , https://chessintheair.com/what-conditions-produce-good-ridge-lift/ , https://en.wikipedia.org/wiki/Ridge_lift ; D. Pagen, «Understanding the Sky» (книга, не читал — https://www.cumulus-soaring.com/store/understanding-the-sky)
- FSX sim_probe (модель склона в симуляторе) — https://xp-soaring.github.io/fsx/dev/sim_probe/sim_probe_paper.html , https://xp-soaring.github.io/fsx/dev/lift.html
- Подъём для птиц (Brandes & Ombalski) — https://pmc.ncbi.nlm.nih.gov/articles/PMC7434798/
- WindNinja — https://research.fs.usda.gov/firelab/products/dataandtools/windninja , https://acp.copernicus.org/articles/16/5229/2016/ , https://ninjastorm.firelab.org/windninja/faq.html ; сравнение с линейной моделью (Blackford Hill) — https://journals.ed.ac.uk/esjs/article/view/12047
8. Ответ пилота (29.09.2026) и что из него следует для модели
Слова пилота:
При обтекании склона чем выше по склону и ближе к нему, тем ветер больше усиливается. Это усиление распространяется на 2 высоты горы от подножия. На 2,5 высоты горы уже ламинарное обтекание. Зависит также от крутизны склона — чем круче, тем больше прирастание силы ветра. В седловине ветер сильнее примерно в 1,5 раза, всегда вдоль седла, даже при косом до 15 градусов. Даже может сдуть за гору. При косом ветре другое обтекание, эффект меньше.
Что это значит для варианта A (формулы):
- Разгон ветра над склоном растёт вверх по склону и ближе к поверхности — максимум у бровки, у самой земли (сходится с Jackson–Hunt / Taylor–Lee). Сейчас разгона нет вовсе (§ «главное»: п. 3).
- Толщина слоя возмущения ≈ 2 H от подножия (H — высота горы над подножием), на 2,5 H — невозмущённый поток. Значит, затухание подъёма и разгона должно масштабироваться высотой горы, а не фиксированными 250 м: множитель вида f(z_над_подножием / H), ≈ 1 у земли → 0 к 2–2,5 H. Нужна оценка H и «подножия» по рельефу против ветра (минимум высоты на 1–3 км против ветра).
- Круче — сильнее разгон: ΔS ∝ H/L (крутизна) — совпадает с Taylor–Lee; ограничить сверху (срыв потока на очень крутых склонах, > ~17–20°, уходит в ротор).
- Седловина: ветер ×1,5 относительно окружающего, направлен вдоль оси седловины (поток «затягивается» в неё) при отклонении ветра до ~15° от оси; течёт через седловину дальше и за гору («может сдуть за гору») — в подветренной стороне за седловиной сильный поток, а не тень. Нужна эвристика: найти седловину (понижение гребня между вершинами поперёк ветра), разгон ×1,5 и поворот вектора к оси седла, затухание с высотой по тому же 2 H.
- Косой ветер: эффект меньше — множитель от угла между ветром и нормалью к склону (порядка cos угла, для седловины — «ловит» только до ~15°).
- Провалы и болтанку не трогать (§ ранее: пилот доволен провалами).
Для нейросетевого варианта (обсуждение 29.09): эти слова пилота — проверочные условия для обученной модели (толщина слоя ≈ 2 H, седловина ×1,5, ослабление при косом ветре).
9. Поле ветра, согласованное по массе, на Rust (обсуждение 29.09.2026)
Альтернатива варианту A: при загрузке места один раз посчитать трёхмерное поле ветра (u, v, w) на сетке так, чтобы воздух не проходил сквозь землю и нигде не накапливался (массово-согласованная диагностическая модель, как WindNinja в простом режиме). В полёте — только трилинейная интерполяция в air_velocity_at.
Что даёт и чего не даёт
- Само, без отдельных правил: разгон над бровкой, «труба» в седловине (поток идёт в понижение и разгоняется, при косом ветре затягивается вдоль седла), трёхмерное обтекание (сопка ≠ отрог ≠ чаша), ослабление при косом ветре. Толщина возмущённого слоя (~2 высоты горы, слова пилота) — через верхнее граничное условие и сетку по высоте.
- Устойчивость воздуха — одно число: отношение «цены» вертикального и горизонтального смещения. Устойчивый воздух обтекает гору сбоку и уходит в седловины, неустойчивый переваливает сверху.
- Не даёт: срыва потока и роторов за крутыми гребнями (модель без инерции) — нынешняя эвристика подветренной стороны остаётся поверх; термики, кольца опускания и болтанка — как сейчас (пилот доволен провалами, §8).
Математика
- Начальное поле u₀ — ветер с профилем по высоте (как сейчас).
- Поправка u = u₀ + W·∇λ, λ — скалярное поле (по числу на ячейку), W — веса (горизонталь «дешёвая», вертикаль «дорогая» — устойчивость).
- Условие ∇·u = 0 → уравнение Пуассона ∇·(W∇λ) = −∇·u₀; у земли — непротекание, на открытых границах λ = 0.
- Дискретно — система A·λ = b: ~10⁶ уравнений (сетка ~100 м × 20–30 уровней на 20×20 км), в каждом 7 неизвестных (ячейка и 6 соседей). A разреженная, симметричная, положительно определённая.
- Решение — итерационное «без матрицы» (A не хранится, A·x — проход по сетке): сопряжённые градиенты с предобуславливателем (~100–300 итераций) или многосеточный метод (5–10 V-циклов). Прямые методы не годятся: плотная матрица 10⁶×10⁶ не помещается, разреженный Холецкий на 3D-сетке даёт гигабайты заполнения.
- Рельеф — сетка по рельефу (σ-координаты: нижний слой на земле, верхние растянуты до потолка) — склон гладкий; маска «под землёй» даёт лесенку.
Главный приём: линейность по ветру (ранг 2)
При фиксированной устойчивости λ линейно зависит от u₀, u₀ — от ветра, поэтому поле для любого направления θ — F(θ) = cos θ · Fₓ + sin θ · F_y (базовые решения для ветра на восток и на север), скорость — множитель. Итог:
- на место — 2 решения на уровень устойчивости; смена ветра в полёте мгновенная, без пересчёта;
- устойчивость нелинейна (веса внутри уравнения) — 3–4 уровня и интерполяция; набор полей по устойчивости сжимается SVD до 2–3 главных компонент;
- для встроенных мест базовые поля можно посчитать заранее и положить в данные игры — одинаковы у всех игроков (сетевая игра) и не стоят ничего при загрузке. Low-rank разложение самой матрицы A не помогает (лапласиан полного ранга; H-матрицы для обратной сложны и не быстрее многосеточного метода).
Реализация: Rust + GDExtension
- Крейт
godot(godot-rust / gdext):cdylibс классом (#[derive(GodotClass)],#[godot_api]), в проекте — файл.gdextensionсо списком библиотек (linux.x86_64 = res://native/bin/libwindfield.so,windows.x86_64 = …/windfield.dll); из GDScript класс виден как встроенный. - Данные —
PackedFloat32Arrayна вход (высоты, параметры) и на выход (поле); внутри — rayon по слоям/кускам. API Godot из рабочих потоков не трогать. Долгий расчёт — изWorkerThreadPool(или фоном внутри Rust), окно не замирает. - Сборка: Linux —
cargo build --release; Windows с Linux —x86_64-pc-windows-gnu(mingw) илиcargo-xwin; шаг вtools/build.shперед экспортом, экспорт кладёт.so/.dllрядом с игрой. Версию крейтаgodotподобрать под API 4.7. - Детерминизм (сетевая игра): скалярные произведения суммировать с фиксированным разбиением на куски и фиксированным порядком сложения — результат одинаков при любом числе потоков и на любой машине. Иначе — поле считает создатель зоны и рассылает (несколько МБ).
- Объём счёта: ~10⁶ ячеек × 7 × сотни итераций ≈ 10⁹ простых операций — доли секунды на всех ядрах; 6–8 решений на место — секунды.
- Своё проще готовых крейтов (
sprs,faer): проход по сетке + сопряжённые градиенты — пара сотен строк.
GPU
- CUDA — нет: только NVIDIA, лишние библиотеки и сборка под Windows, хуже детерминизм.
- Если понадобится GPU — вычислительный шейдер Godot (Vulkan; так уже считаются облака) или wgpu в Rust — работают на любой видеокарте.
- Для расчёта раз на место (и ранг-2 приёма) CPU хватает с запасом.
Нейросеть (обсуждение)
Локальная модель «точка → ветер»: вход — высоты вокруг точки в осях ветра (сетка 7×7 в трёх масштабах 50/200/800 м относительно земли под точкой, ~147 чисел), высота над землёй, число Фруда U/(N·H) (устойчивость); выход — безразмерные u/U, v/U, w/U (+ σ/U болтанки). MLP 150→64→64→4 (~14 тыс. весов) правдоподобно достаточно (линейная теория обтекания почти линейна по рельефу). Данные — решатель (WindNinja или решатель из этого раздела) на тысячах кусков DEM. В игре — прогон по сетке при загрузке (шейдер), дальше интерполяция. Нужна только для произвольных точек с карты; для встроенных мест проще готовые поля.
Сравнение и порядок
| Объём | Что даёт | |
|---|---|---|
| A. Формулы (§8, TODO) | 3–5 дней | разгон, толщина слоя 2H, крутизна, косой ветер; седловина — отдельной эвристикой |
| B’. Поле по массе на Rust | 1–2 недели | всё из A «само» + трёхмерное обтекание, устойчивость; готовые поля для встроенных мест |
| Нейросеть | 2–4 недели | произвольные точки с карты без решателя в игре |
| Если браться за B’, вариант A можно пропустить. |
10. Согласование с термиками/облаками и сетевой игрой (обсуждение 29.09.2026)
Проверено чтением кода (без правок), два вопроса: (1) как вариант A/B’ согласуется с моделью термиков и облаков; (2) как расчёт поля на сетке (§9) согласуется с моделью погоды и сетевой игрой.
10.1 Термики и облака ветер air_velocity_at не видят
Термики (thermal_field.gd) и облака (та же система, «шапки» термиков) не используют
Atmosphere.air_velocity_at(pos) — они напрямую читают WindModel:
update_wind_frame()(thermal_field.gd:159-179) строит сетку «улиц» термиков из глобальногоwind.dir— один азимут на весь мир, без позиции;- снос/наклон термика —
_apply_wind()черезwind.vec2_at()(thermal_field.gd:208-227); - облачные «улицы» —
cloud_layer.gd:440, тоже изatmo.wind.dirнапрямую.
Следствие: локальный разгон и поворот ветра у гребня/в седловине, которые варианты A/B’ добавляют
внутри air_velocity_at, никак не подействуют на рождение/снос термиков и ориентацию облаков —
они продолжат жить по старому, невозмущённому направлению. Термик визуально может «висеть» не там,
куда на самом деле дует воздух в его точке (особенно в седловине, где ось «трубы» способна сильно
отличаться от общего wind.dir). Пилот об этом не жаловался (термики/провалы её устраивают) — можно
сознательно не трогать термики/облака в первом заходе, это отдельная работа уровня варианта B
(нужно тащить позицию в update_wind_frame, сейчас глобальную по конструкции).
10.2 mean_wind_at vs air_velocity_at — ложная турбулентность
Порывистость/болтанка во многих местах считается как разница air_velocity_at(pos) − mean_wind_at(pos) (terrain_wind.gd; тесты test_lee_rotor.gd:98, test_atmosphere.gd:252-253,
test_cloud_suck.gd:91-92), где mean_wind_at — глобальный ветер без поправок рельефа. Если
добавить систематический разгон/поворот только в air_velocity_at, эта разница перестанет быть
чистой турбулентностью на склонах: появится ложная составляющая (трава задёргается сильнее обычного
именно у гребней), и test_lee_rotor.gd:98 («над тенью ветер ≈ mean_wind») может начать падать за
пределами тени.
Вывод: mean_wind_at нужно обновлять той же формулой ΔS(pos)/поворота, что и air_velocity_at
(без шума/lee) — тогда разница снова станет чистой турбулентностью. Дёшево (одна и та же функция
переиспользуется), но требует пересчитать допуски в перечисленных тестах и в
test_ridge_starts.gd (там же меняется decay 250→f(H)).
10.3 Ветер и устойчивость на самом деле константы на полёт — часть §9 упрощается
- Направление/скорость ветра берутся из прогноза один раз при
Atmosphere.set_weather()и не меняются в течение полёта — все мягкие дневные обновления (_apply_day,atmosphere.gd:209-261) явно сохраняютwind_speed_kmh/wind_from_deg. Значит ранг-2 разложение по θ из §9 не нужно ради динамики одного полёта (направление известно и фиксировано на старте) — оно полезно только чтобы не пересчитывать поле заново при заходе на разные старты/локации. - Устойчивость
stability_n_per_sформально пересчитывается по часу внутриWeatherModel.derive(weather_model.gd:167), но фактически замораживается приset_weather()—WaveField.setup()вызывается только оттуда, не из мягких обновлений. На один полёт нужно одно N, без интерполяции между уровнями устойчивости. - Итог: решатель на сетку/полёт можно считать один раз при старте зоны для одного известного направления и одного N — заметно проще, чем «несколько направлений × несколько уровней N», предложенные в §9 с запасом на будущее.
- Прецедент архитектуры уже есть:
GroundFieldиWaveFieldсчитаются лениво, кусками, в памяти, без bake на диск при билде (ground_field.gd,wave_field.gd) — новое поле стоит делать тем же паттерном, а не монолитным расчётом по всей округе при входе в локацию.
10.4 Сетевой детерминизм — GPU-шейдер на самом деле не проблема
Первая гипотеза (детерминизм между клиентами обязателен, значит нужен CPU с фиксированным порядком
суммирования, GPU рискован) — не подтвердилась при проверке кода. Собственная физика полёта в
сетевой модели клиент-авторитетна: NetPilots.set_local_state()/set_local_provider()
(net_pilots.gd:83-89) — каждый клиент считает свой полёт локально и рассылает готовое состояние
(позиция/скорость/ротация), никто его не пересчитывает. Значит, если разные видеокарты дадут чуть
разное поле ветра — это повлияет только на ощущение полёта у самого пилота, других игроков это не
касается вообще (они видят только реплицированную позицию, сравнивать не с чем).
Боты — тоже не проблема: считаются только у ведущего зоны и рассылаются всем на ~10 Гц
(send_bot_state, net_pilots.gd:98-121, комментарий NET-44), а не пересчитываются независимо
каждым клиентом. Единственный тонкий момент — смена ведущего (лидер вышел, подхватывает следующий):
новый ведущий посчитает поле на своей видеокарте, возможен небольшой разовый блип в поведении бота в
момент хендовера, но не постоянное расхождение.
Термики/облака, которые обязаны совпадать у всех (это и есть «тот же мир», ключ — WorldKey,
world_key.gd), как показано в §10.1, вообще не читают это поле — идут из WindModel напрямую.
Вывод: требование «детерминизм ради сети» из §9 (раздел «Детерминизм (сетевая игра)») для конкретно поля ветра излишне строгое — жёсткий фиксированный порядок суммирования на CPU нужен не для сетевой синхронизации, а самое большее — для одинакового ощущения полёта на разных машинах одного и того же человека (не требование продукта) или для воспроизводимости тестов. Вычислительный шейдер Godot (Vulkan, как уже считаются облака) можно использовать без опасений по сети — упрощает выбор в §9/GPU в пользу шейдера, а не обязательно Rust+CPU.
11. Связанная система: ветер, термики, погода (обсуждение 29.09.2026)
Вопрос пользователя: насколько поле ветра на сетке (план docs/archive/plan/wind-field.md) связывает модели
погоды, ветра и термиков — хочется одной связанной системы, а не отдельных моделей. Разбор по коду,
без правок.
11.1 Кто сейчас читает ветер и что даст поле
| Потребитель | Сейчас (код) | С полем |
|---|---|---|
| Полёт, боты, птицы (подъём), дым костра, флюгер | air_velocity_at (glider.gd, bot_pilots.gd:149, bird_flock.gd:255, campfire.gd через update_wind) | сами получают поле — без правок |
| Трава, деревья | mean_wind_at под камерой (terrain_wind.gd) | сразу; по всей земле — WF-10 |
| Снос и наклон термика (и его облака) | wind.vec2_at(span·0,5) / vec2_at(span) — глобальный (thermal_field.gd:208-227, :635) | средний по столбцу ветер поля в точке источника на момент рождения → константа на термик: снос остаётся чистой функцией t, start_at работает |
| Сетка клеток источников, «улицы» | ось _ax = wind.dir на весь мир (update_wind_frame, thermal_field.gd:164; cloud_layer.gd:440) | не трогать: это дискретная сетка (номер клетки → сид термика); локальная ось = другие термики у разных клиентов |
| Выбор источника (лучшая из точек клетки) | _source_at = солнце × покров (thermal_field.gd:~490) | можно добавить множитель «схождения/обтекания» поля (гребни, наветренные склоны) — но выбор дискретный (argmax), разница полей между GPU может перебросить термик на сотни метров |
| Тень облаков на источниках | окно по _ax и wind.vec2_at (:594, :635) | как у сноса (константа на термик) |
| Облачный шум, «пыльные вихри» | cloud_layer.gd:264, dust_devils.gd:119 — vec2_at | поле в точке — только визуал, безопасно |
| Подветренная зона | линия тени по глобальному ветру (ground_field.gd) | остаётся; поле добавляет свой нисходящий поток на склоне (× (1 − lee), как было с w_ridge) |
| Волны | линейная теория вдоль wind.dir (wave_field.gd) | остаётся; позже — направление поля над гребнем |
| Кольца опускания, фон, подсос облака | Gedeon-профиль термика, _bg_sink, cloud_physics.gd | не от ветра — поле их не касается |
11.2 Чего поле не даст
Поле согласовано по массе, без энергии и инерции: нет плавучести — значит, нет самих термиков, их силы, отрыва пузырей, облаков; нет срыва потока и роторов; нет суточного хода. Термики остаются отдельной моделью (источники по солнцу и покрову). Резкие «провалы» — тоже не отсюда: отклик несжимаемого поля на источник массы — широкое слабое опускание ~1/r², а не узкое кольцо Gedeon; кольца, фон и рывки за гребнем остаются эмпирикой.
11.3 Связанная система по этапам
- Поле — ветер для всего (≈ 2–3 дня, это WF-13): снос/наклон термиков, тени, облачный шум, пыльные вихри — из грубого поля 200 м (средний по столбцу 0…кромка ветер у источника в момент рождения). Сетка клеток и «улицы» — на глобальном ветре. Итог: термик в седловине уходит вдоль седла, облако — туда же, куда дует у пилота.
- Термики — источники в том же уравнении (≈ 1–2 недели): вертикальный поток массы термиков как правая часть Пуассона → приток у земли к термику (трава/пыль «тянутся» к нему, схождение) и компенсирующее опускание вокруг. Цена: термики меняются каждую секунду → решение в окне вокруг пилота раз в 1–2 с (МС-PCG ~десятки мс на 4070 SUPER, на слабой AMD — сомнительно) и постоянное чтение с GPU. Кольца Gedeon оставить (иначе пропадут «провалы»); добавка поля — только горизонтальный приток. Отдача мала относительно цены.
- Устойчивость из погодной модели (≈ 2–3 дня): N по часу (
WeatherModel.derive,stability_n_per_s) → вес T, высота инверсии/кромки → «крышка» сетки (устойчивый слой запирает поток — «труба» в перевалах сильнее утром/вечером). Выбор уровня T бесплатный (ранг-2 × уровни); крышка на другой высоте = пересчёт (этап загрузки или фон). Нужно, чтобы мягкие обновления дня перестали «замораживать» N (§10.3).
11.4 Сеть и детерминизм
- Поле у клиентов расходится ≲ 0,01 м/с. Непрерывное использование (снос термика) → за
20 мин жизни термика расхождение ~10 м при радиусе ~100 м — пилоты не заметят, но
test_determinism(допуск 1e-3) не пройдёт → отпечаток мира считать на аналитике (поле off), а в сети проверять отдельный допуск (позиции термиков ≤ 20 м). Можно огрубить снос (направление 2°, скорость 0,1 м/с) — уменьшает, но не убирает расхождение у границы округления. - Дискретные решения (клетки, «улицы», выбор источника, рождение) от поля не брать — там малая разница даёт другой термик. Ключ мира не меняется.
- Этап 2 в сети: окно и термики у каждого своё — горизонтальный приток у всех чуть разный, допустимо (клиент-авторитетная физика, §10.4).
11.5 Риски для «провалов»
Этап 1 провалы не трогает (кольца, фон, lee — прежние). Этап 2 опасен: второе опускание вокруг термика поверх Gedeon — провалы станут «вязкими»/сильнее; только горизонтальный приток. Этап 3 меняет силу «трубы» и подъёма по часу — провалы не трогает, но меняет набор на стартах утром.
11.6 Рекомендация
В план поля включить этап 1 (WF-13) и лёгкую часть этапа 3 — T по N из погоды на момент старта (уже почти так в плане, бесплатно). Крышку по инверсии и этап 2 — «на потом», после полёта пилота на поле.