96 lines
4.3 KiB
Python
96 lines
4.3 KiB
Python
"""J1 actual-header moments and bounded host capability contracts."""
|
|
import json
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
import h5py
|
|
import numpy as np
|
|
import pytest
|
|
|
|
import CelerisLab
|
|
from CelerisLab.config import LBMConfig, load_lbm_config
|
|
from CelerisLab.cuda import compiler_v2 as compiler
|
|
from CelerisLab.common.checkpoint import save_checkpoint, load_checkpoint
|
|
from .test_numerical_operators import compile_run
|
|
from .test_state_regressions import device, make_field, manager
|
|
|
|
|
|
def test_planar_helper_moments_and_known_populations(tmp_path):
|
|
root = Path(__file__).resolve().parents[2]
|
|
assert Path(CelerisLab.__file__).resolve() == root/'src/CelerisLab/__init__.py'
|
|
assert Path(compiler.kernel_path('kernel_v2.cu')).resolve() == root/'src/CelerisLab/lbm/kernels/kernel_v2.cu'
|
|
lines = compile_run(tmp_path, 'planar_velocity.cpp', dict(WALL_NORMAL_VELOCITY='0.0f'))
|
|
cx = np.array([0,1,-1,0,0,1,-1,1,-1])
|
|
cy = np.array([0,0,0,1,-1,1,-1,-1,1])
|
|
w = np.array([4/9]+[1/9]*4+[1/36]*4)
|
|
for start in range(0, len(lines), 3):
|
|
top, rho, u, v, neq = np.fromstring(lines[start], sep=' ')
|
|
before, after = [np.fromstring(s, sep=' ') for s in lines[start+1:start+3]]
|
|
known = cy != (-1 if top else 1)
|
|
np.testing.assert_array_equal(after[known], before[known])
|
|
density = after.sum()
|
|
np.testing.assert_allclose([after@cx, after@cy], density*np.array([u,v]), atol=3e-7, rtol=0)
|
|
if not neq:
|
|
cu = cx*u+cy*v
|
|
expected = w*rho*(1+3*cu+4.5*cu**2-1.5*(u*u+v*v))
|
|
np.testing.assert_allclose(after, expected, atol=3e-7, rtol=0)
|
|
assert abs(density-rho) <= 3e-7
|
|
|
|
|
|
@pytest.mark.parametrize('override', [
|
|
dict(collision='TRT'), dict(collision='MRT'), dict(streaming='esopull'),
|
|
dict(store_precision='FP16S'), dict(ddf_shifting=True), dict(les_enabled=True),
|
|
dict(lattice_model='D3Q19'), dict(wall_normal_velocity=1.),
|
|
dict(wall_normal_velocity=float('nan')),
|
|
])
|
|
def test_planar_unsupported_configuration(override):
|
|
with pytest.raises(ValueError):
|
|
LBMConfig(y_wall_bc='on_site_velocity', **override).validate_runtime()
|
|
|
|
|
|
def test_planar_config_roundtrip_and_fixed_targets(tmp_path):
|
|
path = Path(__file__).resolve().parents[2]/'src/CelerisLab/configs/config_lbm.json'
|
|
data = json.loads(path.read_text())
|
|
data['method'].update(y_wall_bc='on_site_velocity', wall_normal_velocity=-.01,
|
|
collision='SRT', streaming='double_buffer',
|
|
store_precision='FP32', ddf_shifting=False)
|
|
data['method']['les']['enabled'] = False
|
|
path = tmp_path/'config.json'
|
|
path.write_text(json.dumps(data))
|
|
cfg = load_lbm_config(str(path))
|
|
assert float(cfg.to_macros()['WALL_NORMAL_VELOCITY'][:-1]) == -.01
|
|
with pytest.raises(ValueError, match='object-free'):
|
|
compiler.generate_config(cfg, n_objects=1, build_root=tmp_path)
|
|
before = cfg.allocation_signature()
|
|
cfg.wall_normal_velocity = .01
|
|
assert cfg.allocation_signature() != before
|
|
|
|
|
|
def test_planar_force_rejected_before_state_change(device):
|
|
field = make_field(device, y_wall_bc='on_site_velocity')
|
|
before, writes = field._runtime_params.copy(), device.writes
|
|
with pytest.raises(ValueError, match='body forces'):
|
|
field.update_params(fx=.001)
|
|
assert field._runtime_params == before and device.writes == writes
|
|
|
|
|
|
@pytest.mark.parametrize('damage', ['target', 'mode', 'force'])
|
|
def test_planar_checkpoint_contract_before_writes(device, tmp_path, damage):
|
|
field = make_field(device, y_wall_bc='on_site_velocity')
|
|
bodies = manager(field)
|
|
bodies.sync_to_gpu(field)
|
|
path = save_checkpoint(field, SimpleNamespace(step_count=3), field.cfg, bodies,
|
|
str(tmp_path/'plane.h5'))
|
|
with h5py.File(path, 'a') as hf:
|
|
if damage == 'force':
|
|
hf.attrs['runtime_params_json'] = '{"fx":0.001}'
|
|
else:
|
|
cfg = json.loads(hf.attrs['config_json'])
|
|
cfg['wall_normal_velocity' if damage == 'target' else 'y_wall_bc'] = (
|
|
.01 if damage == 'target' else 'bounce_back')
|
|
hf.attrs['config_json'] = json.dumps(cfg)
|
|
writes = device.writes
|
|
with pytest.raises(ValueError):
|
|
load_checkpoint(path, field, SimpleNamespace(_step_count=0), field.cfg, bodies)
|
|
assert device.writes == writes
|