Расчётный движок: heatnet и отличия от десктопа
> Кратко. Веб считает сеть движком heatnet — переписанным sety десктопного ТГИД с теми же формулами и таблицами
результатов. В режиме «fixed» исправлены ошибки sety, поэтому в отдельных местах числа отличаются от десктопа; ниже — где именно и почему.
Как устроен расчёт
Кнопка «Расчёт» ставит задачу в очередь своего города. Расчёт идёт на сервере, а не в браузере; ход виден в окне
«Протокол». Движок читает сеть фрагмента из базы города: узлы, участки, потребителей, источники, оборудование
внутренних схем. Затем он решает гидравлику (расходы и напоры), считает тепло (температуры и потери) и пишет
результаты в те же таблицы, что десктоп: us_out — узлы, ut_out — участки, pt_out — потребители, ns_out — насосы,
rs_out — регуляторы, zd_out — задвижки, dr_out — дроссели. Поэтому расчёт, сделанный в вебе, виден в десктопе
(подписи, пьезометр, отчёты), и наоборот.
Формулы гидравлики и тепла описаны на страницах Гидравлическая модель, Расчётные расходы потребителей и Тепловой расчёт.
Два профиля: legacy и fixed
- legacy — побайтно как sety: те же числа и те же ошибки. Нужен для сверки с десктопом.
- fixed — с исправлениями. На проде все города считаются в профиле fixed (с 01.11.2026).
Что меняется для пользователя в профиле fixed:
| Было в sety (и в десктопе) | Стало в вебе (fixed) |
|---|---|
| Ошибка в данных одного потребителя (нет шаблона внутренней схемы, нет нагрузки ГВС, не задано состояние задвижки) прерывает весь расчёт | Потребитель исключается, в протоколе — причина и «Потребитель … исключён из расчёта», расчёт идёт дальше |
| Незаполненный коэффициент вариации Kv обнуляет нагрузку потребителя | Пустой Kv = 1 |
| Обобщённый потребитель, сохранённый расчётом распределительной сети, получал нагрузки уже с Kv, и Kv применялся второй раз | Хранятся проектные нагрузки, Kv — один раз |
| Сходимость гидравлики проверялась по сумме поправок (зависит от размера сети); «не сошлось» не сообщалось | Проверяются шаг и невязка; если за 100 итераций не сошлось — красное сообщение в протоколе с подсетью |
| Обратка потребителя при малом расходе могла уйти ниже температуры воздуха в помещении (до −177 °C) | Обратка не ниже tв, отданное тепло G·(t1 − tв) |
| Подпитка всегда шла в подающий узел; у узла «обратная» терялась | Подпитка — в линию узла по его признаку: подача → подача, обратка и общая → обратка |
| Потребитель без заданного состояния считался выключенным (обобщённый — включённым) | Оба — включены; проверка данных предупреждает о пустом состоянии |
| «Не известен источник для узла с заданным напором» без причины | Причина: нет связи с магистралью, узел магистрали не найден или не рассчитан, нет графика |
| Узлы-стоки (вода втекает, не вытекает) получали «мусорную» температуру до 10¹⁴ °C | Температура смешения втекающих потоков |
| «Последний расчёт магистрали» — последний по номеру, даже неудачный или свой | Только расчёт с результатами и другого фрагмента: результат не зависит от истории |
| Выбор «Температура расчёта тепловых потерь» в окне расчёта не действовал: нормы потерь всегда при расчётной tн отопления | Выбор действует: при среднесезонной tн нормативные потери участков примерно вдвое ниже, подача у потребителей теплее |
| Коэффициент β местных тепловых потерь: 1,15 только у канальной прокладки с диаметром ≥ 150 мм, у остальных 1,2 (справочник 30 не читался) | β по справочнику 30: бесканальная 1,15; канальная и надземная 1,15 при диаметре ≥ 150 мм, иначе 1,2. Подача у потребителей теплее до +0,2…+1,9 °C |
Сверка на эталонах Алматы (фрагменты 74, 72, 1) и Шатуры: в плановом режиме отпуск тепла меняется на сотые доли процента (579,75 → 579,71 Гкал/ч у фрагмента 72), больше 0,1 °C меняется у единиц потребителей. Это те, у кого раньше была заведомо неверная температура.
Скорость
Тяжёлые части расчёта выполняет ядро на Rust: тепловую матрицу, нагрузки потребителей и расходы. Если ядро недоступно, движок сам переходит на Python с теми же числами. Типичное время на проде: фрагмент 74 Алматы — около 6 с (было 16 с), большой фрагмент Астаны с температурным графиком — около 16 с (было до 2 мин).
Если не получается
- Расчёт долго не начинается — очередь города занята другими расчётами. Состояние и ход расчёта видны в «Протоколе», отменить можно кнопкой «Остановить».
- Числа отличаются от десктопа — сначала проверьте, что сравниваете расчёты одного режима и одной температуры. Распределительная сеть берёт напоры из последнего расчёта магистрали: если последним был летний расчёт магистрали, отпуск тепла распределительной сети упадёт почти вдвое у обоих движков. Остальные расхождения — в таблице выше.
Для администратора
- Движок выбирается переменной
SETY_ENGINEворкера города:legacy— старыйsety/ww.py,heatnet—python -m heatnet.cli. Профиль —HEATNET_PROFILE(legacy|fixed), ядро —HEATNET_CORE(rust|python|check— оба и сверка). Переменные читаются при старте воркера: после смены — перезапуск службы воркера. - Скрипты выкатки:
set-tgid-sety-engine.cmd(heatnet, как sety),set-tgid-sety-engine-fixed.cmd, откат —set-tgid-sety-engine-legacy.cmd. Параллельность воркера —set-tgid-worker-pool.ps1 -City -Concurrency. - Расчёты идут в очередь
tgid.<город>(Celery + Redis): по 4 воркера на продtgid-worker-multi-1..4. Протоколы хранятсяCALC_PROTOCOL_KEEP_DAYSдней.
Для разработчика
- Пакет
heatnet(itwin-api):options/compat(параметры и профили) →io(чтение и запись базы) →model(сеть) →physics(формулы:resistance.py,consumption*.py,temp_graph.py,heat_loss_norms.py,consumers_heat/) →solve(hydraulic.py— Ньютон,thermal.py,regulators.py,subnet.py) →pipeline(стадии) →report(протокол). Ядро Rust —native/heatnet_core, обёрткаheatnet/native.py. - Особенности sety — члены
compat.Quirk; профиль fixed =LEGACY − FIXED. Каждое исправление описано с отчётом «было/стало» вitwin-api/docs/heatnet-corrections.md. - Сверка движков:
scripts/golden/engine_parity.py(--base heatnet --new heatnet --new-quirks-off ИМЯ), эталоны sety —run_reference.py check, замеры —scripts/golden/bench_heatnet.py. Тесты —tests/heatnet/,tests/golden/(нужны копии баз иSETY_GOLDEN*).
