Начальный коммит: 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>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
# Серия по блокировке: D фиксирован, Ny растёт → β=D/Ny падает; экстраполяция β→0 даёт
|
||||
# прямое сравнение с БЕЗГРАНИЧНОЙ литературой (Re=150: Cd≈1.33, St≈0.183, rms Cl≈0.3)
|
||||
# без ручной поправки (1−β)². Запуск из этой папки:
|
||||
# python run_blockage.py
|
||||
# AMR_NY_LIST=90,128,180 python run_blockage.py # свой список Ny
|
||||
# AMR_STEPS=20000 AMR_NY_LIST=128 python run_blockage.py # смоук
|
||||
# Стоимость прогона ≈ как у run.py: патч L1 (основная работа) от Ny не зависит (высота 4D фикс.).
|
||||
import os, time
|
||||
import numpy as np
|
||||
import config as C
|
||||
import backend as B
|
||||
import solver as S
|
||||
import diagnostics as Diag
|
||||
import visualization as Viz
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
OUT = os.path.join(HERE, "out"); os.makedirs(OUT, exist_ok=True)
|
||||
|
||||
LIT = dict(Cd=1.33, Clrms=0.3, St=0.183) # безграничный цилиндр, Re≈150
|
||||
|
||||
def run_one(Ny):
|
||||
cfg = C.from_env(Ny=Ny, frame_every=0) # серия без кадров/гифок (только ряды)
|
||||
print(f"\n[блокировка] Ny={cfg.Ny} (β={cfg.D/cfg.Ny:.3f}); домен {cfg.Nx}x{cfg.Ny}; "
|
||||
f"патч y=[{cfg.ay1},{cfg.by1}]; steps={cfg.steps}")
|
||||
t0 = time.perf_counter()
|
||||
sim = S.Solver(cfg)
|
||||
res = sim.run(Viz.make_progress(f"Ny={cfg.Ny}"))
|
||||
print(" время:", round(time.perf_counter() - t0, 1), "s")
|
||||
a = Diag.analyze(res, cfg)
|
||||
Diag.print_table(a, cfg)
|
||||
Diag.print_crosscheck(a)
|
||||
Diag.convergence_report(res, cfg)
|
||||
np.savez(os.path.join(OUT, f"probe_blockage_Ny{cfg.Ny}.npz"),
|
||||
St=a["St"], Cd=a["Cd"], Clrms=a["Clrms"], uyrms=a["uyrms"],
|
||||
Cm=a.get("Cm", float("nan")),
|
||||
Cd_st=a.get("Cd_st", float("nan")), Clrms_st=a.get("Clrms_st", float("nan")),
|
||||
Ny=cfg.Ny, beta=cfg.D/cfg.Ny, D=cfg.D, U=cfg.U, Re=cfg.Re, steps=cfg.steps,
|
||||
Cl=a["Cl_s"], uy=a["uy"], rho=B.to_cpu(res["rho"]),
|
||||
Fx=B.to_cpu(res["Fx"]), Fy=B.to_cpu(res["Fy"]), Tz=B.to_cpu(res["Tz"]))
|
||||
row = dict(Ny=cfg.Ny, beta=cfg.D/cfg.Ny, St=a["St"], Cd=a["Cd"], Clrms=a["Clrms"],
|
||||
Cm=a.get("Cm", float("nan")), Cd_st=a.get("Cd_st"))
|
||||
# освободить VRAM перед следующим прогоном (буферы, BC, захваченный CUDA-граф)
|
||||
del sim, res, a
|
||||
B.cp.get_default_memory_pool().free_all_blocks()
|
||||
return row
|
||||
|
||||
def save_extrapolation_figure(rows, fits, path):
|
||||
import matplotlib; matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
betas = np.array([r["beta"] for r in rows]); bb = np.linspace(0, betas.max()*1.05, 100)
|
||||
panels = [("Cd", "⟨Cd⟩", LIT["Cd"], "лит. 1.33"),
|
||||
("Clrms", "rms Cl", LIT["Clrms"], "лит. ~0.3"),
|
||||
("St", "St", LIT["St"], "лит. 0.183")]
|
||||
fig, axs = plt.subplots(1, 3, figsize=(13.5, 4.2), dpi=110)
|
||||
for ax, (key, lab, lit, litlab) in zip(axs, panels):
|
||||
vals = np.array([r[key] for r in rows]); ft = fits[key]
|
||||
ax.plot(betas, vals, "o", ms=7, color="#d32f2f", label="серия (raw)")
|
||||
al, sl = ft["lin"]; aq, sq = ft["quad"]
|
||||
ax.plot(bb, al + sl*bb, "-", lw=1.2, color="#1976d2", label=f"a+b·β → {al:.3f}")
|
||||
ax.plot(bb, aq + sq*bb**2, "--", lw=1.2, color="#388e3c", label=f"a+b·β² → {aq:.3f}")
|
||||
ax.axhline(lit, color="gray", lw=1.0, ls=":", label=litlab)
|
||||
if key == "St": # для St полезен и кинематически поправленный вид
|
||||
ax.plot(betas, vals*(1-betas), "s", ms=6, mfc="none", color="#7b1fa2", label="St·(1−β)")
|
||||
ax.set_xlabel("β = D/Ny"); ax.set_ylabel(lab); ax.set_xlim(0, bb[-1])
|
||||
ax.legend(fontsize=8); ax.set_title(f"{lab}(β): экстраполяция β→0", fontsize=10)
|
||||
fig.suptitle("Серия по блокировке: стеснение каналом — свойство ПОСТАНОВКИ, не считывания силы",
|
||||
fontsize=11)
|
||||
fig.tight_layout(rect=(0, 0, 1, 0.93))
|
||||
fig.savefig(path, bbox_inches="tight"); plt.close(fig)
|
||||
print("saved", os.path.basename(path))
|
||||
|
||||
def main():
|
||||
ny_list = [int(s) for s in os.environ.get("AMR_NY_LIST", "90,128,180").split(",")]
|
||||
print(f"[серия по блокировке] backend={B.BACKEND}; Ny={ny_list}")
|
||||
rows = [run_one(Ny) for Ny in ny_list]
|
||||
if len(rows) < 2:
|
||||
print("\n(одна точка — фит/экстраполяция пропущены)")
|
||||
return
|
||||
betas = [r["beta"] for r in rows]
|
||||
fits = {key: Diag.fit_blockage(betas, [r[key] for r in rows]) for key in ("Cd", "Clrms", "St")}
|
||||
Diag.print_blockage_table(rows, fits)
|
||||
np.savez(os.path.join(OUT, "blockage_summary.npz"),
|
||||
Ny=np.array([r["Ny"] for r in rows]), beta=np.array(betas),
|
||||
St=np.array([r["St"] for r in rows]), Cd=np.array([r["Cd"] for r in rows]),
|
||||
Clrms=np.array([r["Clrms"] for r in rows]), Cm=np.array([r["Cm"] for r in rows]),
|
||||
Cd_st=np.array([r["Cd_st"] if r["Cd_st"] is not None else np.nan for r in rows]),
|
||||
Cd0_lin=fits["Cd"]["lin"][0], Cd0_quad=fits["Cd"]["quad"][0],
|
||||
Cl0_lin=fits["Clrms"]["lin"][0], Cl0_quad=fits["Clrms"]["quad"][0],
|
||||
St0_lin=fits["St"]["lin"][0], St0_quad=fits["St"]["quad"][0],
|
||||
lit_Cd=LIT["Cd"], lit_Clrms=LIT["Clrms"], lit_St=LIT["St"])
|
||||
save_extrapolation_figure(rows, fits, os.path.join(OUT, "blockage_extrapolation.png"))
|
||||
print("DONE (серия по блокировке)")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user