Состояние на момент заведения репозитория. 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>
48 lines
2.4 KiB
Python
48 lines
2.4 KiB
Python
# Геометрия: маски тела/стенок и знаковое поле расстояний (SDF) для L0 и патча L1.
|
||
# Чистый CuPy. Соглашение по SDF: phi>0 в жидкости, phi<0 в теле; |phi| ≈ расстоянию до границы.
|
||
import backend as B
|
||
import lattice as L
|
||
import amr
|
||
|
||
cp = B.cp; xp = B.xp; DTYPE = B.DTYPE
|
||
|
||
def _cmask(NX, NY, ccx, ccy, R):
|
||
"""Булева маска круга радиуса R (центр ccx,ccy) на сетке (NY,NX)."""
|
||
Y, X = cp.meshgrid(cp.arange(NY), cp.arange(NX), indexing="ij")
|
||
return (X - ccx)**2 + (Y - ccy)**2 <= R*R
|
||
|
||
def _csdf(NX, NY, ccx, ccy, R):
|
||
"""SDF круга: sqrt((x−ccx)²+(y−ccy)²) − R (отрицательно внутри)."""
|
||
Y, X = cp.meshgrid(cp.arange(NY), cp.arange(NX), indexing="ij")
|
||
return cp.sqrt((X - ccx).astype(DTYPE)**2 + (Y - ccy).astype(DTYPE)**2) - R
|
||
|
||
class Geometry:
|
||
"""Контейнер масок/SDF/патча. Поля *_np — host-копии для визуализации."""
|
||
pass
|
||
|
||
def build(cfg):
|
||
Nx, Ny, D, cx, cy = cfg.Nx, cfg.Ny, cfg.D, cfg.cx, cfg.cy
|
||
r = cfg.refine
|
||
ax1, bx1, ay1, by1 = cfg.ax1, cfg.bx1, cfg.ay1, cfg.by1
|
||
g = Geometry()
|
||
|
||
# --- L0: только цилиндр как твёрдое тело (стенки канала верх/низ — free-slip, не solid) ---
|
||
g.cyl0 = _cmask(Nx, Ny, cx, cy, D/2.0)
|
||
g.solid0 = g.cyl0 # стенки обрабатываются specular-отражением, см. boundary.free_slip_walls
|
||
g.phi0 = _csdf(Nx, Ny, cx, cy, D/2.0) # SDF только цилиндра (для Bouzidi тела)
|
||
|
||
# --- патч L1 (измельчение r) над областью [ax1,bx1]×[ay1,by1] ---
|
||
g.P1 = amr.patch(Nx, Ny, ax1, bx1, ay1, by1, r)
|
||
Nfx, Nfy = g.P1["Nfx"], g.P1["Nfy"]
|
||
# цилиндр на L1: центр и радиус масштабируются на r (диаметр r·D → радиус r·D/2)
|
||
R1 = r * D / 2.0
|
||
g.solid1 = _cmask(Nfx, Nfy, (cx - ax1)*r, (cy - ay1)*r, R1)
|
||
g.phi1 = _csdf(Nfx, Nfy, (cx - ax1)*r, (cy - ay1)*r, R1)
|
||
|
||
# маска жидких узлов для рестрикции L1→L0 (внутренняя часть патча на L0)
|
||
g.fl1 = ~g.solid0[ay1+1:by1, ax1+1:bx1]
|
||
|
||
# host-копии для визуализации
|
||
g.solid0_np = B.to_cpu(g.solid0); g.solid1_np = B.to_cpu(g.solid1)
|
||
return g
|