test_shifted_jets, test_shifted_storage, test_raw_exchange and test_channel_root pass refinements/level_* lists; examples fixed_patch_jet and fixed_periodic_patch pass refinements=[BOUNDS] instead of the positional bounds. Assertions kept; the shifted-storage case base_block-without-fine_block now expects the level-list rule 'blocked refined levels below' (same constraint). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
77 lines
3.7 KiB
Python
77 lines
3.7 KiB
Python
"""Public API demo: small periodic shear, one fixed 2:1 patch, eight coarse steps.
|
|
|
|
From this checkout, after checking the selected physical GPU is idle:
|
|
PYTHONPATH="$PWD/src" CUDA_VISIBLE_DEVICES=0 python examples/fixed_periodic_patch.py
|
|
|
|
This demonstrates initialization/stepping/leaf output, not interface accuracy.
|
|
There are no walls, objects, forces, checkpoint files or plots.
|
|
"""
|
|
from dataclasses import replace
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
|
|
import CelerisLab
|
|
from CelerisLab.config import load_lbm_config
|
|
from CelerisLab.cuda.context import CudaContext
|
|
from CelerisLab.lbm.equilibrium import compute_feq_d2q9, compute_macro_from_ddf
|
|
from CelerisLab.lbm.refinement import ACTIVE
|
|
from CelerisLab.lbm.refinement_stepper import PeriodicPatchStepper
|
|
|
|
|
|
def shear_equilibrium(shape, origin, dx, period):
|
|
"""Sample ux(y)=1e-3*sin(2*pi*y/period) at physical cell centers.
|
|
|
|
Centers are origin + dx*(index+.5); this shear is independent of x.
|
|
Fine origin includes patch offset AND the four-cell halo, with dx=.5.
|
|
Equilibrium is already postcollision G, so no initial collision is needed.
|
|
"""
|
|
y = origin[1] + dx * (np.arange(shape[0]) + .5)
|
|
ux = 1e-3 * np.sin(2*np.pi*y/period)
|
|
rows = np.stack([compute_feq_d2q9(1.0, float(u), 0.0) for u in ux], axis=1)
|
|
return np.repeat(rows[:, :, None], shape[1], axis=2)
|
|
|
|
|
|
def leaf_summary(coarse, fine, coarse_leaf, fine_leaf):
|
|
"""Use the same leaf masks/areas for initial and final mass."""
|
|
c, f = coarse[:, coarse_leaf], fine[:, fine_leaf]
|
|
mass = c.sum(dtype=np.float64) + .25*f.sum(dtype=np.float64)
|
|
macros = np.array([compute_macro_from_ddf(v) for v in np.concatenate((c, f), axis=1).T])
|
|
return mass, macros.min(axis=0), macros.max(axis=0)
|
|
|
|
|
|
def main():
|
|
root = Path(__file__).resolve().parents[1]
|
|
if Path(CelerisLab.__file__).resolve() != root / "src/CelerisLab/__init__.py":
|
|
raise RuntimeError(f"Set PYTHONPATH to {root / 'src'}")
|
|
cfg = replace(load_lbm_config(str(root / "src/CelerisLab/configs/config_lbm.json")),
|
|
nx=16, ny=16, viscosity=.1, velocity=1e-3, rho=1.0,
|
|
lattice_model="D2Q9", collision="SRT", streaming="double_buffer",
|
|
store_precision="FP32", ddf_shifting=False, les_enabled=False)
|
|
with CudaContext(0) as context, PeriodicPatchStepper(cfg, context=context, refinements=[(4, 4, 12, 12)]) as run:
|
|
p = run.patch
|
|
coarse = shear_equilibrium(p.coarse_shape, (0, 0), 1.0, cfg.ny)
|
|
fine = shear_equilibrium(p.fine_shape, p.fine_origin, .5, cfg.ny)
|
|
coarse_leaf = np.ones(p.coarse_shape, dtype=bool)
|
|
x0, y0, x1, y1 = p.bounds
|
|
coarse_leaf[y0:y1, x0:x1] = False
|
|
fine_leaf = p.fine_kind == ACTIVE
|
|
coarse[:, ~coarse_leaf] = np.nan
|
|
fine[:, ~fine_leaf] = np.nan
|
|
run.initialize(coarse, fine)
|
|
initial_mass, _, _ = leaf_summary(*run.download(), coarse_leaf, fine_leaf)
|
|
run.step(8)
|
|
coarse, fine = run.download() # Both levels synchronized, stored postcollision G.
|
|
assert np.isnan(coarse[:, ~coarse_leaf]).all() and np.isnan(fine[:, ~fine_leaf]).all()
|
|
assert np.isfinite(coarse[:, coarse_leaf]).all() and np.isfinite(fine[:, fine_leaf]).all()
|
|
mass, low, high = leaf_summary(coarse, fine, coarse_leaf, fine_leaf)
|
|
print(f"periodic patch API demo: synchronized coarse_steps={run.step_count}, fine_steps={2*run.step_count}")
|
|
print(f"leaf mass: initial={initial_mass:.12g} final={mass:.12g} drift={mass-initial_mass:+.6e}")
|
|
for name, lo, hi in zip(("rho", "ux", "uy"), low, high):
|
|
print(f"leaf {name}: [{lo:.9g}, {hi:.9g}]")
|
|
print("covered coarse / fine halo: NaN; functional demonstration only")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|