Files
CFDManager/docs/theory/solver_2x_sdf/collision.py
T
NotBigGhostandClaude Opus 5 11ff7b79b4 Начальный коммит: Vulkan-редактор SimVulcan + исследование KBC-LBM
Состояние на момент заведения репозитория.

C++ приложение (src/, shaders/, tests/) — минимальный редактор 3D-моделей
на Vulkan 1.3: орбитальная камера, три опорные сетки через начало координат,
загрузка .obj с режимами отображения. Весь Vulkan изолирован в src/vk/.

Исследование (docs/) — оригинальные статьи по KBC (docs/origins) и
Python-решатель D2Q9 KBC-N1 с AMR 2x и SDF+Bouzidi (docs/theory).

В решателе перед коммитом исправлены дефекты, найденные сверкой с
первоисточниками: относительный порог знаменателя энтропийного стабилизатора
(абсолютный вырождал KBC в LBGK на 77-99% узлов), заворот вход/выход в углах
домена, диагностика средней плотности по фиктивным узлам тела, зашитый
refine=2. Подробности — docs/theory/solver_2x_sdf/README.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 16:37:38 +03:00

43 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Оператор СТОЛКНОВЕНИЯ — KBC-N1 (энтропийный), единственный оператор модели.
#
# KBC-N1 (Karlin/Bösch/Chikatamarla 2014):
# Δ = f − feq (неравновесная часть)
# Δs = Ps·Δ (проекция на сдвиг-моменты {cx²−cy², cxcy})
# Δh = Δ − Δs (остальная часть)
# γ = 1/β − (2 − 1/β)·⟨Δs,Δh⟩ / ⟨Δh,Δh⟩, ⟨a,b⟩ = Σ_i a_i b_i / feq_i (H-теорема)
# f_post = f − β(2Δs + γΔh), β = 1/(2τ)
# γ — энтропийный стабилизатор: подстраивает диссипацию неhydro-мод под энтропийное ограничение
# (поэтому KBC устойчив при τ→1/2). Сдвиг-моменты (вязкость) релаксируют с правильным 2β = 1/τ,
# то есть физическая вязкость задаётся только τ — стабилизатор её не меняет.
#
# Порядок шагов дословно совпадает с алгоритмом статьи (Bösch/Chikatamarla/Karlin, PRE 92,
# 043309 (2015), разд. III, листинг после ур.39): ρ,u → feq → Δs → Δh = f − feq − Δs → γ → релаксация.
# Вырожденный случай ⟨Δh|Δh⟩→0 отсекается ОТНОСИТЕЛЬНЫМ порогом B.GREL (см. backend.py):
# абсолютный порог здесь недопустим — den квадратична по неравновесию и физически мала.
import backend as B
import lattice as L
cp = B.cp; xp = B.xp
Q = L.Q; Ps = L.Ps; GREL = B.GREL; ONE = B.ONE; TWO = B.TWO
def _project_shift(dfn):
"""Δs = Ps·Δ без cuBLAS (gemm при CUDA-graph capture тащит alpha/beta host→device).
Реализовано как Σ_k Ps[i,k]·Δ[k] через broadcast+редукцию — только обычные ядра."""
dfn2d = dfn.reshape(Q, -1) # (Q, N)
return (Ps[:, :, None] * dfn2d[None]).sum(1).reshape(dfn.shape)
def kbc_collide(f, fe, beta):
dfn = f - fe
ds = _project_shift(dfn)
dh = dfn - ds; inv = 1.0 / fe
num = (ds*dh*inv).sum(0); den = (dh*dh*inv).sum(0)
nrm = (dfn*dfn*inv).sum(0) # ‖Δ‖² — масштаб неравновесия узла
ok = den > GREL*nrm # относительный порог, не абсолютный
den_safe = xp.where(ok, den, ONE) # избегаем 0/0 (обе ветки where считаются)
binv = 1.0 / beta
g = xp.where(ok, binv - (2.0 - binv)*num/den_safe, TWO)
return f - beta*(2.0*ds + g[None]*dh)
# единственный оператор столкновения модели
collide = kbc_collide