test: add opt-in shifted FP32 Jet CV control
This commit is contained in:
@@ -28,6 +28,41 @@ def eq(rho, u, v):
|
||||
|
||||
|
||||
class Host(unittest.TestCase):
|
||||
def test_shifted_storage_receipt_preserves_physical_case(self):
|
||||
for scale in (1, 2):
|
||||
base = case(scale)
|
||||
shifted = case(scale, ddf_shifting=True)
|
||||
self.assertFalse(base.pop("ddf_shifting"))
|
||||
self.assertTrue(shifted.pop("ddf_shifting"))
|
||||
self.assertEqual(base.pop("storage_variant")["name"], "unshifted_fp32")
|
||||
self.assertEqual(shifted.pop("storage_variant")["name"], "shifted_fp32")
|
||||
self.assertEqual(base, shifted)
|
||||
|
||||
def test_shifted_physical_download_roundtrip(self):
|
||||
from CelerisLab.lbm.population_storage import _encode_physical, _decode_stored
|
||||
from run_jet_circle_cv import moments
|
||||
from jet_cv_measurements import primitives
|
||||
|
||||
for speed in (0.03, 0.015):
|
||||
seed = state((9, 48, 64), speed)
|
||||
self.assertEqual(seed.dtype, np.float32)
|
||||
plain = _decode_stored(_encode_physical(seed, False), False)
|
||||
decoded = _decode_stored(_encode_physical(seed, True), True)
|
||||
self.assertEqual(decoded.dtype, np.float64)
|
||||
np.testing.assert_array_equal(plain, seed)
|
||||
# Same FP32 physical seed; only encoding quantization may differ.
|
||||
np.testing.assert_allclose(decoded, seed, rtol=0, atol=3e-10)
|
||||
rho, momentum, velocity = moments(decoded)
|
||||
rho2, velocity2 = primitives(decoded, CX, CY)
|
||||
np.testing.assert_array_equal(rho, rho2)
|
||||
np.testing.assert_array_equal(velocity, velocity2)
|
||||
np.testing.assert_allclose(momentum, rho * velocity, atol=1e-17)
|
||||
fluid = np.ones(seed.shape[1:], bool)
|
||||
inv, flux = cv(decoded, fluid, (0, 0), (5, 4, 25, 20), 0.0072)
|
||||
expected, _ = cv(seed, fluid, (0, 0), (5, 4, 25, 20), 0.0072)
|
||||
np.testing.assert_allclose(inv, expected, rtol=0, atol=1e-6)
|
||||
np.testing.assert_allclose(flux, 0, atol=1e-14)
|
||||
|
||||
def test_descriptor_and_uniform_closed_flux(self):
|
||||
from CelerisLab.lbm.descriptors import D2Q9_EX, D2Q9_EY
|
||||
|
||||
|
||||
@@ -18,11 +18,24 @@ CY = np.array([0, 0, 0, 1, -1, 1, -1, -1, 1])
|
||||
W = np.array([4 / 9] + [1 / 9] * 4 + [1 / 36] * 4)
|
||||
|
||||
|
||||
def case(scale=1, re=100, steps=800):
|
||||
def case(scale=1, re=100, steps=800, ddf_shifting=False):
|
||||
u = 0.03 / scale
|
||||
d = 24.084 * scale
|
||||
return dict(
|
||||
scale=scale,
|
||||
ddf_shifting=bool(ddf_shifting),
|
||||
storage_variant=dict(
|
||||
name="shifted_fp32" if ddf_shifting else "unshifted_fp32",
|
||||
device_populations="g=f-w" if ddf_shifting else "f",
|
||||
device_dtype="float32",
|
||||
equilibrium_path=(
|
||||
"compute_feq_from_momentum" if ddf_shifting else "compute_feq"
|
||||
),
|
||||
initial_physical_seed="historical FP32-rounded equilibrium, identical in both variants",
|
||||
downloaded_populations="physical f, decoded by public stepper.download()",
|
||||
downloaded_dtype="float64" if ddf_shifting else "float32",
|
||||
raw_exchange="physical reaction and mass; no host weight correction",
|
||||
),
|
||||
re_d=re,
|
||||
beta=0.1,
|
||||
nx=192 * scale,
|
||||
@@ -226,7 +239,7 @@ def run_case(c, ctx, output, provenance, continuation=False):
|
||||
collision="SRT",
|
||||
streaming="double_buffer",
|
||||
store_precision="FP32",
|
||||
ddf_shifting=False,
|
||||
ddf_shifting=c.get("ddf_shifting", False),
|
||||
les_enabled=False,
|
||||
)
|
||||
fine_cfg = LBMConfig(
|
||||
@@ -237,7 +250,7 @@ def run_case(c, ctx, output, provenance, continuation=False):
|
||||
collision="SRT",
|
||||
streaming="double_buffer",
|
||||
store_precision="FP32",
|
||||
ddf_shifting=False,
|
||||
ddf_shifting=c.get("ddf_shifting", False),
|
||||
les_enabled=False,
|
||||
)
|
||||
obj = SimObject(
|
||||
@@ -579,8 +592,15 @@ def main():
|
||||
action="store_true",
|
||||
help="Bounded ref0..800 scalar diagnostics at every root interval; sparse rays/fields",
|
||||
)
|
||||
p.add_argument(
|
||||
"--shifted-fp32",
|
||||
action="store_true",
|
||||
help="Opt-in shifted numerical-representation control for --dense-root; historical unshifted default unchanged",
|
||||
)
|
||||
p.add_argument("--plan", action="store_true")
|
||||
a = p.parse_args()
|
||||
if a.shifted_fp32 and not a.dense_root:
|
||||
p.error("--shifted-fp32 requires the bounded --dense-root campaign")
|
||||
if a.steps <= 0 or a.steps > 3200:
|
||||
p.error("steps must be 1..3200")
|
||||
if a.re == 400 and not a.allow_re400:
|
||||
@@ -593,7 +613,7 @@ def main():
|
||||
if a.continuation:
|
||||
if a.scale not in (1, 2) or a.re != 100 or a.steps != 3200:
|
||||
p.error("--continuation requires --re 100 --scale 1/2 --steps 3200")
|
||||
c = case(a.scale, a.re, a.steps)
|
||||
c = case(a.scale, a.re, a.steps, ddf_shifting=a.shifted_fp32)
|
||||
if a.continuation:
|
||||
from jet_cv_measurements import sample_steps, factors
|
||||
|
||||
|
||||
Reference in New Issue
Block a user