test: add one projected x-gap-width shear contrast
This commit is contained in:
1 parent
1f64f7eb11
commit
be8e6d691d
4 files changed
+202
-19
No files matched your search
@@ -459,3 +459,24 @@ What's kept and enforced:
|
|||||||
a 600 kB cap. If invalid it is dropped and an error is recorded, keeping
|
a 600 kB cap. If invalid it is dropped and an error is recorded, keeping
|
||||||
the scalar receipt.
|
the scalar receipt.
|
||||||
- There are no new pass gates; this is a mechanism diagnostic only.
|
- There are no new pass gates; this is a mechanism diagnostic only.
|
||||||
|
|
||||||
|
### Single x-gap-width contrast (`wide_x_shear_n128`)
|
||||||
|
|
||||||
|
This opt-in admits only Re100/N128/projected depth3 with `--probe-trace`.
|
||||||
|
The outer boxes, three grid spacings, viscosities, initialization, five main
|
||||||
|
sample times and trace windows are unchanged. L1→L2 parent-frame rectangles
|
||||||
|
are `[(56,44,96,212),(160,60,200,228)]`: both x-normal middle gaps widen from
|
||||||
|
6 to 12 root cells, while y gaps remain 6. Active leaves are
|
||||||
|
`[7936,20352,53760]`, hops `[2048,4096,8192]`, work 540,016,640 active updates.
|
||||||
|
This also moves the L2 x faces and reduces its volume; it is not a pure
|
||||||
|
travel-distance experiment. No new qualification matrix, assessor, threshold
|
||||||
|
or snapshot is added. Existing scalar screens and all failures stay visible.
|
||||||
|
|
||||||
|
The same 24 targets and actual-center metadata are retained. The horizontal
|
||||||
|
probes stop before the new inner face x = 28: they do not bracket that interface
|
||||||
|
or sample its fine side. The first 8 horizontal L0/L1 probes keep identical
|
||||||
|
centers, and the y-normal x = 38 transect is unchanged. Their temporal residuals
|
||||||
|
can support a descriptive timing contrast, but cannot establish a crossing
|
||||||
|
or reflection coefficient. Changed-level probes must not be treated as
|
||||||
|
collocated samples. `rho-1` remains raw density deviation; do not substitute
|
||||||
|
the 24-probe mean for the global pressure gauge.
|
||||||
@@ -25,6 +25,8 @@ NESTED_SHEAR = "nested_shear_n128" # fixed three-level/two-region shear preset
|
|||||||
SHEAR_NESTED_SHA256 = "fa6cfe87fb4df8c6d732c637c885276833c81973b950c7724d734f8fc350bcb0"
|
SHEAR_NESTED_SHA256 = "fa6cfe87fb4df8c6d732c637c885276833c81973b950c7724d734f8fc350bcb0"
|
||||||
TWIN_SHEAR = "twin_shear_n128" # depth-2 twin: nested L0->L1 boxes without L2
|
TWIN_SHEAR = "twin_shear_n128" # depth-2 twin: nested L0->L1 boxes without L2
|
||||||
SHEAR_TWIN_SHA256 = "1cbf37f18e89aea577581631c4565f51e68d22a3739b698816ef64acbf2b2bb4"
|
SHEAR_TWIN_SHA256 = "1cbf37f18e89aea577581631c4565f51e68d22a3739b698816ef64acbf2b2bb4"
|
||||||
|
WIDE_X_SHEAR = "wide_x_shear_n128" # one projected x-gap-width contrast
|
||||||
|
SHEAR_WIDE_X_SHA256 = "13d16ba355117e2d074edccd9dc5d694c2fc13c673a0abdfca6401f6ed917733"
|
||||||
SHEAR_PROBES_SHA256 = "e2e6490d281cc275f448dc6d6ea7b9b4407cc74a51e9256b86c08c8626b89b76" # signed interface-probe mechanism diagnostic
|
SHEAR_PROBES_SHA256 = "e2e6490d281cc275f448dc6d6ea7b9b4407cc74a51e9256b86c08c8626b89b76" # signed interface-probe mechanism diagnostic
|
||||||
|
|
||||||
|
|
||||||
@@ -121,6 +123,13 @@ def verify_source(repo, revision, flow="taylor_green", probes=False):
|
|||||||
or hashlib.sha256(module.read_bytes()).hexdigest() != SHEAR_PROBES_SHA256):
|
or hashlib.sha256(module.read_bytes()).hexdigest() != SHEAR_PROBES_SHA256):
|
||||||
raise RuntimeError("Wrong shear_probes module checkout or content")
|
raise RuntimeError("Wrong shear_probes module checkout or content")
|
||||||
result["shear_probes_sha256"] = SHEAR_PROBES_SHA256
|
result["shear_probes_sha256"] = SHEAR_PROBES_SHA256
|
||||||
|
if flow == "shear_wide_x":
|
||||||
|
import shear_wide_x
|
||||||
|
module = harness / "shear_wide_x.py"
|
||||||
|
if (Path(shear_wide_x.__file__).resolve() != module
|
||||||
|
or hashlib.sha256(module.read_bytes()).hexdigest() != SHEAR_WIDE_X_SHA256):
|
||||||
|
raise RuntimeError("Wrong shear_wide_x module checkout or content")
|
||||||
|
result["shear_wide_x_sha256"] = SHEAR_WIDE_X_SHA256
|
||||||
if flow == "shear_twin":
|
if flow == "shear_twin":
|
||||||
import shear_twin
|
import shear_twin
|
||||||
module = harness / "shear_twin.py"
|
module = harness / "shear_twin.py"
|
||||||
@@ -128,14 +137,14 @@ def verify_source(repo, revision, flow="taylor_green", probes=False):
|
|||||||
or hashlib.sha256(module.read_bytes()).hexdigest() != SHEAR_TWIN_SHA256):
|
or hashlib.sha256(module.read_bytes()).hexdigest() != SHEAR_TWIN_SHA256):
|
||||||
raise RuntimeError("Wrong shear_twin module checkout or content")
|
raise RuntimeError("Wrong shear_twin module checkout or content")
|
||||||
result["shear_twin_sha256"] = SHEAR_TWIN_SHA256
|
result["shear_twin_sha256"] = SHEAR_TWIN_SHA256
|
||||||
if flow in ("shear_nested", "shear_twin"): # the twin reuses the nested geometry
|
if flow in ("shear_nested", "shear_twin", "shear_wide_x"): # shared nested constants
|
||||||
import shear_nested
|
import shear_nested
|
||||||
module = harness / "shear_nested.py"
|
module = harness / "shear_nested.py"
|
||||||
if (Path(shear_nested.__file__).resolve() != module
|
if (Path(shear_nested.__file__).resolve() != module
|
||||||
or hashlib.sha256(module.read_bytes()).hexdigest() != SHEAR_NESTED_SHA256):
|
or hashlib.sha256(module.read_bytes()).hexdigest() != SHEAR_NESTED_SHA256):
|
||||||
raise RuntimeError("Wrong shear_nested module checkout or content")
|
raise RuntimeError("Wrong shear_nested module checkout or content")
|
||||||
result["shear_nested_sha256"] = SHEAR_NESTED_SHA256
|
result["shear_nested_sha256"] = SHEAR_NESTED_SHA256
|
||||||
if flow in ("shear_wave", "shear_nested", "shear_twin"):
|
if flow in ("shear_wave", "shear_nested", "shear_twin", "shear_wide_x"):
|
||||||
import shear_wave
|
import shear_wave
|
||||||
module = harness / "shear_wave.py"
|
module = harness / "shear_wave.py"
|
||||||
if (Path(shear_wave.__file__).resolve() != module
|
if (Path(shear_wave.__file__).resolve() != module
|
||||||
@@ -209,14 +218,15 @@ def main():
|
|||||||
p.add_argument("--output", type=Path, required=True)
|
p.add_argument("--output", type=Path, required=True)
|
||||||
p.add_argument("--explosion", choices=["constant", "projected_linear"], default="constant")
|
p.add_argument("--explosion", choices=["constant", "projected_linear"], default="constant")
|
||||||
p.add_argument("--diagnostic",
|
p.add_argument("--diagnostic",
|
||||||
choices=[SCALED_DIAGNOSTIC, SCALED_SHEAR, NESTED_SHEAR, TWIN_SHEAR],
|
choices=[SCALED_DIAGNOSTIC, SCALED_SHEAR, NESTED_SHEAR, TWIN_SHEAR, WIDE_X_SHEAR],
|
||||||
help="explicit four-case N256/fine512 same-placement diagnostic "
|
help="explicit four-case N256/fine512 same-placement diagnostic "
|
||||||
"(scaled_n256: Taylor-Green; scaled_shear_n256: shear wave) or the "
|
"(scaled_n256: Taylor-Green; scaled_shear_n256: shear wave) or the "
|
||||||
"fixed three-level/two-region shear preset (nested_shear_n128) "
|
"fixed three-level/two-region shear preset (nested_shear_n128) "
|
||||||
"or its depth-2 twin (twin_shear_n128)")
|
"or its depth-2 twin (twin_shear_n128), or the single projected "
|
||||||
|
"x-gap-width contrast (wide_x_shear_n128)")
|
||||||
p.add_argument("--probe-trace", action="store_true",
|
p.add_argument("--probe-trace", action="store_true",
|
||||||
help="signed interface-probe trace (nested U128/U512/projected d3, "
|
help="signed interface-probe trace (nested U128/U512/projected d3, "
|
||||||
"twin projected d2); mechanism diagnostic, no gates")
|
"twin projected d2, wide-x projected d3); mechanism diagnostic, no gates")
|
||||||
p.add_argument("--final-snapshot", action="store_true",
|
p.add_argument("--final-snapshot", action="store_true",
|
||||||
help="nested_shear_n128 projected depth-3 only: final macro snapshot")
|
help="nested_shear_n128 projected depth-3 only: final macro snapshot")
|
||||||
p.add_argument("--early-pressure", action="store_true",
|
p.add_argument("--early-pressure", action="store_true",
|
||||||
@@ -224,33 +234,38 @@ def main():
|
|||||||
p.add_argument("--flow", choices=["taylor_green", "shear_wave"], default="taylor_green")
|
p.add_argument("--flow", choices=["taylor_green", "shear_wave"], default="taylor_green")
|
||||||
args = p.parse_args()
|
args = p.parse_args()
|
||||||
nested = args.diagnostic == NESTED_SHEAR
|
nested = args.diagnostic == NESTED_SHEAR
|
||||||
if args.flow == "shear_wave" and (args.re != 100 or (args.depth == 3 and not nested)
|
wide_x = args.diagnostic == WIDE_X_SHEAR
|
||||||
|
if wide_x and not args.probe_trace:
|
||||||
|
p.error("wide_x_shear_n128 requires --probe-trace")
|
||||||
|
if args.flow == "shear_wave" and (args.re != 100 or (args.depth == 3 and not (nested or wide_x))
|
||||||
or args.early_pressure):
|
or args.early_pressure):
|
||||||
p.error("shear_wave requires --re 100, depth 1 or 2 and no --early-pressure")
|
p.error("shear_wave requires --re 100, depth 1 or 2 and no --early-pressure")
|
||||||
probe_cases = {(NESTED_SHEAR, 128, 1, "constant"), (NESTED_SHEAR, 512, 1, "constant"),
|
probe_cases = {(NESTED_SHEAR, 128, 1, "constant"), (NESTED_SHEAR, 512, 1, "constant"),
|
||||||
(NESTED_SHEAR, 128, 3, "projected_linear"),
|
(NESTED_SHEAR, 128, 3, "projected_linear"),
|
||||||
(TWIN_SHEAR, 128, 2, "projected_linear")}
|
(TWIN_SHEAR, 128, 2, "projected_linear"),
|
||||||
|
(WIDE_X_SHEAR, 128, 3, "projected_linear")}
|
||||||
if args.probe_trace and (args.final_snapshot or (
|
if args.probe_trace and (args.final_snapshot or (
|
||||||
args.diagnostic, args.n, args.depth, args.explosion) not in probe_cases):
|
args.diagnostic, args.n, args.depth, args.explosion) not in probe_cases):
|
||||||
p.error("--probe-trace requires nested U128/U512/projected depth 3 or twin projected "
|
p.error("--probe-trace requires a fixed nested, twin or wide-x case, "
|
||||||
"depth 2, without --final-snapshot")
|
"without --final-snapshot")
|
||||||
if args.final_snapshot and not (nested and args.depth == 3
|
if args.final_snapshot and not (nested and args.depth == 3
|
||||||
and args.explosion == "projected_linear"):
|
and args.explosion == "projected_linear"):
|
||||||
p.error("--final-snapshot requires nested_shear_n128 projected depth 3")
|
p.error("--final-snapshot requires nested_shear_n128 projected depth 3")
|
||||||
initial, metrics, limits, initialization = flow_functions(args.flow)
|
initial, metrics, limits, initialization = flow_functions(args.flow)
|
||||||
if args.output.exists():
|
if args.output.exists():
|
||||||
p.error("Output already exists; choose a new path to retain prior evidence")
|
p.error("Output already exists; choose a new path to retain prior evidence")
|
||||||
if args.explosion != "constant" and args.depth != 2 and not nested:
|
if args.explosion != "constant" and args.depth != 2 and not (nested or wide_x):
|
||||||
p.error("projected_linear requires depth 2")
|
p.error("projected_linear requires depth 2")
|
||||||
twin = args.diagnostic == TWIN_SHEAR
|
twin = args.diagnostic == TWIN_SHEAR
|
||||||
if nested or twin:
|
if nested or twin or wide_x:
|
||||||
import shear_nested
|
import shear_nested
|
||||||
import shear_twin
|
import shear_twin
|
||||||
preset = shear_nested if nested else shear_twin
|
import shear_wide_x
|
||||||
|
preset = shear_wide_x if wide_x else shear_nested if nested else shear_twin
|
||||||
if args.flow != "shear_wave":
|
if args.flow != "shear_wave":
|
||||||
p.error(f"--diagnostic {args.diagnostic} requires --flow shear_wave")
|
p.error(f"--diagnostic {args.diagnostic} requires --flow shear_wave")
|
||||||
if (args.re, args.n, args.depth, args.explosion) not in preset.CASES:
|
if (args.re, args.n, args.depth, args.explosion) not in preset.CASES:
|
||||||
p.error(f"{args.diagnostic} requires one of its four Re100 cases")
|
p.error(f"{args.diagnostic} requires one of its fixed Re100 cases")
|
||||||
elif args.diagnostic:
|
elif args.diagnostic:
|
||||||
cases = {(256, 1, "constant"), (512, 1, "constant"),
|
cases = {(256, 1, "constant"), (512, 1, "constant"),
|
||||||
(256, 2, "constant"), (256, 2, "projected_linear")}
|
(256, 2, "constant"), (256, 2, "projected_linear")}
|
||||||
@@ -270,9 +285,9 @@ def main():
|
|||||||
p.error("--run-gpu and exactly one explicit CUDA_VISIBLE_DEVICES are required")
|
p.error("--run-gpu and exactly one explicit CUDA_VISIBLE_DEVICES are required")
|
||||||
repo = args.repo.resolve()
|
repo = args.repo.resolve()
|
||||||
sys.path[:0] = [str(repo / "src"), str(repo)]
|
sys.path[:0] = [str(repo / "src"), str(repo)]
|
||||||
source = verify_source(repo, args.expected_revision,
|
source_flow = ("shear_wide_x" if wide_x else "shear_nested" if nested
|
||||||
"shear_nested" if nested else "shear_twin" if twin else args.flow,
|
else "shear_twin" if twin else args.flow)
|
||||||
probes=args.probe_trace)
|
source = verify_source(repo, args.expected_revision, source_flow, probes=args.probe_trace)
|
||||||
runtime = runtime_source(repo)
|
runtime = runtime_source(repo)
|
||||||
if args.dry_run:
|
if args.dry_run:
|
||||||
print(json.dumps(dict(source=source, runtime_source=runtime, dry_run=True,
|
print(json.dumps(dict(source=source, runtime_source=runtime, dry_run=True,
|
||||||
@@ -288,7 +303,7 @@ def main():
|
|||||||
cfg = config(args.n, args.re)
|
cfg = config(args.n, args.re)
|
||||||
if args.depth == 1:
|
if args.depth == 1:
|
||||||
refinements = []
|
refinements = []
|
||||||
elif nested or twin:
|
elif nested or twin or wide_x:
|
||||||
refinements = [list(level) for level in preset.REFINEMENTS]
|
refinements = [list(level) for level in preset.REFINEMENTS]
|
||||||
else:
|
else:
|
||||||
refinements = rectangles(args.n, args.depth)
|
refinements = rectangles(args.n, args.depth)
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
"""One projected x-gap-width diagnostic (opt-in wide_x_shear_n128).
|
||||||
|
|
||||||
|
Keep the nested outer boxes and all three spacings. Shrink only L2 in x,
|
||||||
|
so each x-normal middle gap grows from 6 to 12 root cells; y gaps stay 6.
|
||||||
|
This also reduces L2 volume and moves its x faces. It is a descriptive
|
||||||
|
geometry contrast with no new qualification matrix, assessor or pass gate.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import shear_nested as nested
|
||||||
|
|
||||||
|
ROOT_N = nested.ROOT_N
|
||||||
|
DEPTH = nested.DEPTH
|
||||||
|
REFINEMENTS = [nested.REFINEMENTS[0],
|
||||||
|
[(56, 44, 96, 212), (160, 60, 200, 228)]] # parent L1 coordinates
|
||||||
|
CASES = ((100, ROOT_N, DEPTH, "projected_linear"),)
|
||||||
|
LEAVES = [7936, 20352, 53760]
|
||||||
|
HOPS = nested.HOPS
|
||||||
|
WORK = sum(c * h for c, h in zip(LEAVES, HOPS)) # 540016640 active updates
|
||||||
|
NU = nested.NU
|
||||||
|
TAU = nested.TAU
|
||||||
@@ -1066,11 +1066,13 @@ class ProbeTraceTests(unittest.TestCase):
|
|||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from contextlib import nullcontext
|
from contextlib import nullcontext
|
||||||
arrays = self.exact_arrays(masks, n, 0.0)
|
arrays = self.exact_arrays(masks, n, 0.0)
|
||||||
counts = []
|
counts, selectors = [], []
|
||||||
|
|
||||||
class FakeRun:
|
class FakeRun:
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.step_count = 0
|
self.step_count = 0
|
||||||
|
if "refinements" in kwargs:
|
||||||
|
selectors.append((kwargs["explosion"], kwargs["refinements"]))
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
@@ -1106,7 +1108,11 @@ class ProbeTraceTests(unittest.TestCase):
|
|||||||
patch.object(run_case, "build_capture", return_value=nullcontext()), \
|
patch.object(run_case, "build_capture", return_value=nullcontext()), \
|
||||||
redirect_stdout(io.StringIO()):
|
redirect_stdout(io.StringIO()):
|
||||||
run_case.main()
|
run_case.main()
|
||||||
return json.loads(output.read_text()), counts, sorted(p.name for p in Path(tmp).iterdir())
|
rec = json.loads(output.read_text())
|
||||||
|
expected = ([(scheme, [[tuple(r) for r in level] for level in rec["refinements"]])]
|
||||||
|
if depth > 1 else [])
|
||||||
|
self.assertEqual(selectors, expected)
|
||||||
|
return rec, counts, sorted(p.name for p in Path(tmp).iterdir())
|
||||||
|
|
||||||
def test_mocked_probe_traces(self):
|
def test_mocked_probe_traces(self):
|
||||||
sp = self.probes
|
sp = self.probes
|
||||||
@@ -1162,3 +1168,124 @@ class ProbeTraceTests(unittest.TestCase):
|
|||||||
self.assertTrue(rec["completed"])
|
self.assertTrue(rec["completed"])
|
||||||
self.assertEqual(rec["rows"], baseline["rows"])
|
self.assertEqual(rec["rows"], baseline["rows"])
|
||||||
self.assertIn("exceeds", rec["probe_trace"]["error"])
|
self.assertIn("exceeds", rec["probe_trace"]["error"])
|
||||||
|
|
||||||
|
|
||||||
|
class WideXDiagnosticTests(unittest.TestCase):
|
||||||
|
"""One width contrast; historical qualification matrices remain unchanged."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
import shear_nested
|
||||||
|
import shear_probes
|
||||||
|
import shear_wide_x
|
||||||
|
from CelerisLab.lbm.hierarchy import build_hierarchy
|
||||||
|
self.wide, self.nested, self.probes = shear_wide_x, shear_nested, shear_probes
|
||||||
|
self.h = build_hierarchy(run_case.config(128, 100), self.wide.REFINEMENTS)
|
||||||
|
|
||||||
|
def test_geometry_counts_and_legal_pair_tables(self):
|
||||||
|
from CelerisLab.lbm.blocks import BlockLayout2D
|
||||||
|
from CelerisLab.lbm.hierarchy import build_hierarchy, leaf_partition
|
||||||
|
from CelerisLab.lbm.refinement import ACTIVE
|
||||||
|
from CelerisLab.lbm.refinement_tables import projected_explosion_tables
|
||||||
|
wide, h = self.wide, self.h
|
||||||
|
self.assertEqual(wide.REFINEMENTS[0], self.nested.REFINEMENTS[0])
|
||||||
|
self.assertEqual(wide.REFINEMENTS[1], [(56, 44, 96, 212), (160, 60, 200, 228)])
|
||||||
|
for outer, inner in zip(wide.REFINEMENTS[0], wide.REFINEMENTS[1]):
|
||||||
|
x0, y0, x1, y1 = (v / 2 for v in inner)
|
||||||
|
self.assertEqual((x0 - outer[0], outer[2] - x1), (12, 12))
|
||||||
|
self.assertEqual((y0 - outer[1], outer[3] - y1), (6, 6))
|
||||||
|
# Independent physical rectangle masks at each native spacing.
|
||||||
|
masks = []
|
||||||
|
for level, kind in enumerate(h.kinds):
|
||||||
|
x, y = centers(kind.shape, level)
|
||||||
|
outer = ((x >= 16) & (x < 60) & (y >= 16) & (y < 112)
|
||||||
|
| (x >= 68) & (x < 112) & (y >= 24) & (y < 120))
|
||||||
|
inner = ((x >= 28) & (x < 48) & (y >= 22) & (y < 106)
|
||||||
|
| (x >= 80) & (x < 100) & (y >= 30) & (y < 114))
|
||||||
|
masks.append(~outer if level == 0 else outer & ~inner if level == 1 else inner)
|
||||||
|
np.testing.assert_array_equal(kind == ACTIVE, masks[-1])
|
||||||
|
self.assertEqual([int(m.sum()) for m in masks], [7936, 20352, 53760])
|
||||||
|
np.testing.assert_array_equal(leaf_partition(h), np.ones((128, 128)))
|
||||||
|
self.assertEqual(run_case.workload(masks, 2048)["active_collision_updates"], 540016640)
|
||||||
|
self.assertEqual(wide.LEAVES, [7936, 20352, 53760])
|
||||||
|
self.assertEqual(wide.HOPS, [2048, 4096, 8192])
|
||||||
|
self.assertEqual(wide.WORK, 540016640)
|
||||||
|
np.testing.assert_allclose([c.viscosity for c in h.configs], wide.NU, rtol=0, atol=0)
|
||||||
|
np.testing.assert_allclose([1 / c.omega for c in h.configs], wide.TAU, rtol=1e-15)
|
||||||
|
old = build_hierarchy(run_case.config(128, 100), self.nested.REFINEMENTS)
|
||||||
|
for name in ("ghost_coarse", "ghost_fine", "coalesce_coarse", "coalesce_fine"):
|
||||||
|
np.testing.assert_array_equal(getattr(h.pairs[0], name), getattr(old.pairs[0], name))
|
||||||
|
root = BlockLayout2D.build(128, 128, 8, 8, periodic=(True, True))
|
||||||
|
for level, pair in enumerate(h.pairs):
|
||||||
|
layout = root if level == 0 else h.pairs[level - 1].fine_layout((8, 8))
|
||||||
|
neighbors, offsets = projected_explosion_tables(pair, layout, h.kinds[level])
|
||||||
|
legal = np.unique(pair.ghost_coarse)
|
||||||
|
legal = legal[(h.kinds[level].ravel()[legal] == ACTIVE) & ~pair.covered.ravel()[legal]]
|
||||||
|
self.assertTrue(np.isin(neighbors, layout.owner.ravel()[legal]).all())
|
||||||
|
self.assertEqual(neighbors.shape, (len(pair.ghost_fine), 4))
|
||||||
|
self.assertEqual(len(np.unique(pair.ghost_fine)), len(pair.ghost_fine))
|
||||||
|
self.assertTrue((np.abs(offsets) == .25).all())
|
||||||
|
if level == 0:
|
||||||
|
expected = projected_explosion_tables(old.pairs[0], root, old.kinds[0])
|
||||||
|
for a, b in zip((neighbors, offsets), expected):
|
||||||
|
np.testing.assert_array_equal(a, b)
|
||||||
|
|
||||||
|
def test_fixed_probes_and_complete_runner_schedule(self):
|
||||||
|
from CelerisLab.lbm.refinement import ACTIVE
|
||||||
|
masks = [k == ACTIVE for k in self.h.kinds]
|
||||||
|
probes = self.probes.select(masks)
|
||||||
|
old = self.probes.select(self.nested.leaf_masks())
|
||||||
|
self.assertEqual([p["level"] for p in probes[:12]], [0] * 3 + [1] * 9)
|
||||||
|
self.assertLess(max(p["center"][0] for p in probes[:12]), 28)
|
||||||
|
self.assertEqual(probes[:8], old[:8]) # identical-center old L0/L1 probes
|
||||||
|
self.assertEqual(probes[12:], old[12:]) # unchanged y-normal transect
|
||||||
|
helper = ProbeTraceTests()
|
||||||
|
helper.setUp()
|
||||||
|
rec, counts, files = helper.run_mocked(128, 3, run_case.WIDE_X_SHEAR,
|
||||||
|
"projected_linear", masks)
|
||||||
|
self.assertTrue(rec["completed"])
|
||||||
|
self.assertEqual(rec["refinements"], [[list(r) for r in level] for level in self.wide.REFINEMENTS])
|
||||||
|
self.assertEqual(rec["workload"]["active_cells_by_level"], self.wide.LEAVES)
|
||||||
|
self.assertEqual(rec["workload"]["active_collision_updates"], self.wide.WORK)
|
||||||
|
self.assertEqual([r["step"] for r in rec["rows"]], [0, 512, 1024, 1536, 2048])
|
||||||
|
self.assertEqual(rec["probe_trace"]["steps"], list(self.probes.STEPS))
|
||||||
|
self.assertEqual(rec["probe_trace"]["probes"], probes)
|
||||||
|
self.assertEqual(counts[-1], 2048)
|
||||||
|
self.assertEqual(files, ["probe.json"])
|
||||||
|
self.assertNotIn("final_snapshot", rec)
|
||||||
|
|
||||||
|
def test_one_case_admission_and_pin(self):
|
||||||
|
self.assertEqual(run_case.SHEAR_WIDE_X_SHA256,
|
||||||
|
hashlib.sha256((HERE / "shear_wide_x.py").read_bytes()).hexdigest())
|
||||||
|
repo = HERE.parents[2]
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
base = ["run_case.py", "--repo", str(repo), "--expected-revision", "f" * 40,
|
||||||
|
"--output", str(Path(tmp) / "case.json"), "--dry-run", "--re", "100",
|
||||||
|
"--flow", "shear_wave", "--diagnostic", run_case.WIDE_X_SHEAR,
|
||||||
|
"--n", "128", "--depth", "3", "--explosion", "projected_linear", "--probe-trace"]
|
||||||
|
for extra in ([], ["--n", "512"], ["--depth", "2"], ["--explosion", "constant"],
|
||||||
|
["--re", "1000"], ["--flow", "taylor_green"], ["--final-snapshot"],
|
||||||
|
["--early-pressure"]):
|
||||||
|
with self.subTest(extra=extra), patch.object(sys, "argv", base + extra), \
|
||||||
|
patch.object(run_case, "verify_source", return_value={}) as verify, \
|
||||||
|
patch.object(run_case, "runtime_source", return_value={}), \
|
||||||
|
redirect_stdout(io.StringIO()), patch("sys.stderr", io.StringIO()):
|
||||||
|
if not extra:
|
||||||
|
self.assertEqual(run_case.main(), 0)
|
||||||
|
verify.assert_called_once_with(repo, "f" * 40, "shear_wide_x", probes=True)
|
||||||
|
else:
|
||||||
|
with self.assertRaises(SystemExit):
|
||||||
|
run_case.main()
|
||||||
|
verify.assert_not_called()
|
||||||
|
with patch.object(sys, "argv", base[:-1]), patch("sys.stderr", io.StringIO()):
|
||||||
|
with self.assertRaises(SystemExit):
|
||||||
|
run_case.main()
|
||||||
|
|
||||||
|
def test_historical_matrix_rejects_width_case(self):
|
||||||
|
helper = NestedPresetTests()
|
||||||
|
helper.setUp()
|
||||||
|
records = helper.nested_set()
|
||||||
|
self.assertTrue(helper.mod.assess_nested(records, "r")["passed"])
|
||||||
|
records[-1].update(diagnostic=run_case.WIDE_X_SHEAR,
|
||||||
|
refinements=self.wide.REFINEMENTS)
|
||||||
|
self.assertEqual(helper.mod.assess_nested(records, "r")["status"], "INVALID_SET")
|
||||||
|
self.assertNotIn(run_case.WIDE_X_SHEAR, helper.mod.PRESETS)
|
||||||
Reference in new issue
Block a user