Files
CelerisLab/examples/fixed_periodic_patch.py
T
ClaudeandClaude Opus 5.5 5167c79378 P1 (4/n): unit tests and examples use the level-list constructor
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>
2026-10-21 01:46:52 +00:00

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()