Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
850b66862f | ||
|
|
fd8f1da9f5 |
No files matched your search
@@ -1,9 +1,9 @@
|
|||||||
"""Public API demo: fixed 2:1 patch with a stationary, optionally actuated circle.
|
"""Public API demo: fixed 2:1 patch with a stationary, optionally actuated circle.
|
||||||
|
|
||||||
From this checkout, after checking the selected physical GPU is idle:
|
From this checkout, after checking the selected physical GPU is idle:
|
||||||
PYTHONPATH="$PWD/src" CUDA_VISIBLE_DEVICES=0 python examples/fixed_patch_circle.py --fine-block 16 20
|
PYTHONPATH="$PWD/src" CUDA_VISIBLE_DEVICES=0 python examples/fixed_patch_circle.py
|
||||||
... --speed -0.002 --fine-block 16 20 --mode slot_reservoir
|
... --speed -0.002 --mode slot_reservoir
|
||||||
Omit --fine-block for the (equivalent) dense fine storage.
|
Both levels use blocked storage (--base-block, --fine-block tiles).
|
||||||
|
|
||||||
A short smoke run (default 128 coarse steps): it shows setup, stepping and
|
A short smoke run (default 128 coarse steps): it shows setup, stepping and
|
||||||
fluid-only diagnostics, not a developed flow, accuracy or long-time stability.
|
fluid-only diagnostics, not a developed flow, accuracy or long-time stability.
|
||||||
@@ -71,8 +71,10 @@ def main():
|
|||||||
parser.add_argument("--mode", choices=("periodic", "slot_reservoir"), default="periodic")
|
parser.add_argument("--mode", choices=("periodic", "slot_reservoir"), default="periodic")
|
||||||
parser.add_argument("--speed", type=float, default=.002,
|
parser.add_argument("--speed", type=float, default=.002,
|
||||||
help="normal surface velocity, coarse lattice units (+ blows, - sucks, 0 passive)")
|
help="normal surface velocity, coarse lattice units (+ blows, - sucks, 0 passive)")
|
||||||
parser.add_argument("--fine-block", type=int, nargs=2, metavar=("BY", "BX"),
|
parser.add_argument("--base-block", type=int, nargs=2, metavar=("BY", "BX"), default=(12, 8),
|
||||||
help="blocked fine storage; must divide the whole fine allocation (32 x 40 here)")
|
help="root tile; must divide the 24 x 32 root")
|
||||||
|
parser.add_argument("--fine-block", type=int, nargs=2, metavar=("BY", "BX"), default=(16, 20),
|
||||||
|
help="fine tile; must divide the whole fine allocation (32 x 40 here)")
|
||||||
parser.add_argument("--steps", type=int, default=128)
|
parser.add_argument("--steps", type=int, default=128)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if args.steps < 0:
|
if args.steps < 0:
|
||||||
@@ -86,20 +88,20 @@ def main():
|
|||||||
body = SimObject(0, geometry=CircleGeometry(*CENTER, RADIUS), center=CENTER, radius=RADIUS,
|
body = SimObject(0, geometry=CircleGeometry(*CENTER, RADIUS), center=CENTER, radius=RADIUS,
|
||||||
surface_actuation=spec)
|
surface_actuation=spec)
|
||||||
cfg = config(args.mode)
|
cfg = config(args.mode)
|
||||||
fine_block = tuple(args.fine_block) if args.fine_block else None
|
|
||||||
# The caller owns the CUDA context; the stepper must be closed first (the
|
# The caller owns the CUDA context; the stepper must be closed first (the
|
||||||
# nested with-statement does that).
|
# nested with-statement does that).
|
||||||
with CudaContext(0) as context, FixedPatchStepper(
|
with CudaContext(0) as context, FixedPatchStepper(
|
||||||
cfg, context=context, coarse_boundary=args.mode, refinements=[BOUNDS],
|
cfg, context=context, coarse_boundary=args.mode, refinements=[BOUNDS],
|
||||||
level_blocks=[None, fine_block], level_objects=[(), (body,)]) as run:
|
level_blocks=[tuple(args.base_block), tuple(args.fine_block)],
|
||||||
|
level_objects=[(), (body,)]) as run:
|
||||||
p = run.patch
|
p = run.patch
|
||||||
# Rest equilibrium is already postcollision G, so no initial collision is
|
# Rest equilibrium is already postcollision G, so no initial collision is
|
||||||
# needed. Non-leaf entries (covered, ghost, solid) are discarded by initialize.
|
# needed. Non-leaf entries (covered, ghost, solid) are discarded by initialize.
|
||||||
rest = np.asarray(compute_feq_d2q9(1.0, 0.0, 0.0), np.float32)[:, None, None]
|
rest = np.asarray(compute_feq_d2q9(1.0, 0.0, 0.0), np.float32)[:, None, None]
|
||||||
run.initialize(np.broadcast_to(rest, (9, *p.coarse_shape)),
|
run.initialize(np.broadcast_to(rest, (9, *p.coarse_shape)),
|
||||||
np.broadcast_to(rest, (9, *p.fine_shape)))
|
np.broadcast_to(rest, (9, *p.fine_shape)))
|
||||||
storage = f"blocked {fine_block}" if fine_block else "dense"
|
storage = f"blocked root {tuple(args.base_block)} fine {tuple(args.fine_block)}"
|
||||||
print(f"mode={args.mode} fine storage={storage} speed={args.speed:+g} "
|
print(f"mode={args.mode} storage={storage} speed={args.speed:+g} "
|
||||||
f"(fine allocation {p.fine_shape[0]}x{p.fine_shape[1]}, fine origin {p.fine_origin})")
|
f"(fine allocation {p.fine_shape[0]}x{p.fine_shape[1]}, fine origin {p.fine_origin})")
|
||||||
masks = leaf_masks(run, args.mode)
|
masks = leaf_masks(run, args.mode)
|
||||||
start = leaf_diagnostics(*run.download(), masks)
|
start = leaf_diagnostics(*run.download(), masks)
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ from CelerisLab.lbm.refinement import ACTIVE
|
|||||||
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
|
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
|
||||||
|
|
||||||
BOUNDS, AMPLITUDE, WIDTH = (16, 4, 32, 28), .02, 12
|
BOUNDS, AMPLITUDE, WIDTH = (16, 4, 32, 28), .02, 12
|
||||||
|
LEVEL_BLOCKS = [(12, 8), (8, 8)] # blocked storage: 48x48 root, 56x40 fine window
|
||||||
TIMES, MAX_MACH, MAX_SECONDS = (0, 300, 1200), .1, 120
|
TIMES, MAX_MACH, MAX_SECONDS = (0, 300, 1200), .1, 120
|
||||||
|
|
||||||
|
|
||||||
@@ -132,7 +133,8 @@ def main():
|
|||||||
lattice_model='D2Q9', collision='SRT', streaming='double_buffer',
|
lattice_model='D2Q9', collision='SRT', streaming='double_buffer',
|
||||||
store_precision='FP32', ddf_shifting=False, les_enabled=False)
|
store_precision='FP32', ddf_shifting=False, les_enabled=False)
|
||||||
report = dict(config=dict(nx=48, ny=48, bounds=BOUNDS, W=WIDTH, A=AMPLITUDE, nu=.1,
|
report = dict(config=dict(nx=48, ny=48, bounds=BOUNDS, W=WIDTH, A=AMPLITUDE, nu=.1,
|
||||||
rho=1, tau_coarse=.8, tau_fine=1.1, coarse_boundary='slot_reservoir'),
|
rho=1, tau_coarse=.8, tau_fine=1.1, coarse_boundary='slot_reservoir',
|
||||||
|
level_blocks=LEVEL_BLOCKS),
|
||||||
guards=dict(check_every=50, positive_density=True, finite=True,
|
guards=dict(check_every=50, positive_density=True, finite=True,
|
||||||
max_Mach=MAX_MACH, max_seconds=MAX_SECONDS,
|
max_Mach=MAX_MACH, max_seconds=MAX_SECONDS,
|
||||||
timing='cooperative checks, not an exact interruption deadline'),
|
timing='cooperative checks, not an exact interruption deadline'),
|
||||||
@@ -149,7 +151,8 @@ def main():
|
|||||||
start, run = time.monotonic(), None
|
start, run = time.monotonic(), None
|
||||||
try:
|
try:
|
||||||
with CudaContext(0) as context, FixedPatchStepper(cfg, context=context,
|
with CudaContext(0) as context, FixedPatchStepper(cfg, context=context,
|
||||||
coarse_boundary='slot_reservoir', refinements=[BOUNDS]) as run:
|
coarse_boundary='slot_reservoir', refinements=[BOUNDS],
|
||||||
|
level_blocks=LEVEL_BLOCKS) as run:
|
||||||
p = run.patch
|
p = run.patch
|
||||||
masks = [np.ones(p.coarse_shape, bool), p.fine_kind == ACTIVE]
|
masks = [np.ones(p.coarse_shape, bool), p.fine_kind == ACTIVE]
|
||||||
masks[0][[0, -1]] = False
|
masks[0][[0, -1]] = False
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
"""The public examples run all-blocked: their level tiles must reach the device unchanged.
|
||||||
|
|
||||||
|
Host only: a context whose activation raises proves construction (layouts, tables,
|
||||||
|
boundary checks) succeeded up to the first CUDA call.
|
||||||
|
"""
|
||||||
|
import ast
|
||||||
|
from dataclasses import replace
|
||||||
|
from pathlib import Path
|
||||||
|
import unittest
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
from CelerisLab.body.geometry.circle import CircleGeometry
|
||||||
|
from CelerisLab.body.objects import SimObject
|
||||||
|
from CelerisLab.config import LBMConfig
|
||||||
|
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
|
||||||
|
|
||||||
|
EXAMPLES = Path(__file__).resolve().parents[2] / "examples"
|
||||||
|
|
||||||
|
|
||||||
|
def literal(name, constant):
|
||||||
|
"""Module-level literal from an example, read without importing it (no pycuda)."""
|
||||||
|
tree = ast.parse((EXAMPLES / name).read_text())
|
||||||
|
for node in tree.body:
|
||||||
|
if isinstance(node, ast.Assign):
|
||||||
|
for target in node.targets:
|
||||||
|
names = target.elts if isinstance(target, ast.Tuple) else [target]
|
||||||
|
for i, t in enumerate(names):
|
||||||
|
if isinstance(t, ast.Name) and t.id == constant:
|
||||||
|
value = node.value.elts[i] if isinstance(target, ast.Tuple) else node.value
|
||||||
|
return ast.literal_eval(value)
|
||||||
|
raise KeyError(constant)
|
||||||
|
|
||||||
|
|
||||||
|
def forbidden():
|
||||||
|
return Mock(activate=Mock(side_effect=AssertionError("CUDA reached")), sm_arch="sm_70")
|
||||||
|
|
||||||
|
|
||||||
|
class ExampleTiles(unittest.TestCase):
|
||||||
|
def test_fixed_patch_jet_tiles(self):
|
||||||
|
bounds, blocks = literal("fixed_patch_jet.py", "BOUNDS"), literal("fixed_patch_jet.py", "LEVEL_BLOCKS")
|
||||||
|
width, amplitude = literal("fixed_patch_jet.py", "WIDTH"), literal("fixed_patch_jet.py", "AMPLITUDE")
|
||||||
|
cfg = LBMConfig(nx=48, ny=48, viscosity=.1, velocity=0., wall_slot_width=width,
|
||||||
|
wall_normal_velocity=amplitude, y_wall_bc="on_site_velocity",
|
||||||
|
top_wall_bc="reservoir")
|
||||||
|
with self.assertRaisesRegex(AssertionError, "CUDA reached"):
|
||||||
|
FixedPatchStepper(cfg, context=forbidden(), coarse_boundary="slot_reservoir",
|
||||||
|
refinements=[bounds], level_blocks=[tuple(b) for b in blocks])
|
||||||
|
|
||||||
|
def test_fixed_patch_circle_default_tiles(self):
|
||||||
|
bounds = literal("fixed_patch_circle.py", "BOUNDS")
|
||||||
|
nx, ny = literal("fixed_patch_circle.py", "NX"), literal("fixed_patch_circle.py", "NY")
|
||||||
|
center, radius = literal("fixed_patch_circle.py", "CENTER"), literal("fixed_patch_circle.py", "RADIUS")
|
||||||
|
body = SimObject(0, geometry=CircleGeometry(*center, radius), center=center, radius=radius)
|
||||||
|
periodic = LBMConfig(nx=nx, ny=ny, viscosity=.1)
|
||||||
|
slot = replace(periodic, velocity=0, wall_normal_velocity=.001, wall_slot_width=8,
|
||||||
|
y_wall_bc="on_site_velocity", top_wall_bc="reservoir")
|
||||||
|
for mode, cfg in (("periodic", periodic), ("slot_reservoir", slot)):
|
||||||
|
with self.subTest(mode=mode), self.assertRaisesRegex(AssertionError, "CUDA reached"):
|
||||||
|
FixedPatchStepper(cfg, context=forbidden(), coarse_boundary=mode,
|
||||||
|
refinements=[bounds], level_blocks=[(12, 8), (16, 20)],
|
||||||
|
level_objects=[(), (body,)])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in new issue
Block a user