test: add bounded dense-root Jet CV temporal diagnostics
This commit is contained in:
1 parent
9805383f9c
commit
80546a0d95
5 files changed
+430
-25
No files matched your search
@@ -31,6 +31,111 @@ from analyze_jet_cv_continuation import integrate, analyze
|
||||
|
||||
|
||||
class Measurements(unittest.TestCase):
|
||||
def test_budget_failure_preserves_verified_pair(self):
|
||||
from jet_cv_measurements import install_evidence
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp)
|
||||
data = path / "samples.npz"
|
||||
meta = path / "samples.json"
|
||||
data.write_bytes(b"old-data")
|
||||
meta.write_text("old-meta")
|
||||
staged = path / ".samples.pending.npz"
|
||||
staged_meta = path / ".meta.pending"
|
||||
staged.write_bytes(b"x" * 100)
|
||||
staged_meta.write_text("new-meta")
|
||||
with self.assertRaisesRegex(RuntimeError, "last verified files preserved"):
|
||||
install_evidence({data: staged, meta: staged_meta}, limit=20)
|
||||
self.assertEqual(data.read_bytes(), b"old-data")
|
||||
self.assertEqual(meta.read_text(), "old-meta")
|
||||
self.assertEqual(
|
||||
sorted(p.name for p in path.iterdir()), ["samples.json", "samples.npz"]
|
||||
)
|
||||
|
||||
def test_dense_root_and_exact_old_cadence(self):
|
||||
from jet_cv_measurements import old_sample_steps
|
||||
|
||||
for scale, count in ((1, 801), (2, 3201)):
|
||||
c = case(scale, steps=800)
|
||||
c["dense_root"] = True
|
||||
dense = sample_steps(c)
|
||||
old = old_sample_steps(c)
|
||||
self.assertEqual(len(dense), count)
|
||||
self.assertEqual(len(old), 276)
|
||||
np.testing.assert_array_equal(dense, np.arange(800 * scale**2 + 1))
|
||||
self.assertTrue(np.isin(old, dense).all())
|
||||
np.testing.assert_array_equal(old[:101] / scale**2, np.arange(101))
|
||||
np.testing.assert_array_equal(old[101:] / scale**2, np.arange(104, 801, 4))
|
||||
|
||||
def test_root_interval_absolute_net_mass_reversals(self):
|
||||
from jet_cv_measurements import absolute_aperture_interval_mass
|
||||
|
||||
masks = (np.array([True, False]), np.array([False, True]))
|
||||
rows = np.zeros((2, 4))
|
||||
rows[0, 3] = 1
|
||||
first = absolute_aperture_interval_mass(rows, *masks)
|
||||
rows[0, 3] = -1
|
||||
self.assertEqual(first + absolute_aperture_interval_mass(rows, *masks), 2)
|
||||
self.assertEqual(abs(1 - 1), 0)
|
||||
|
||||
def test_dense_offline_oscillation_preserves_ledger(self):
|
||||
import json
|
||||
from jet_cv_measurements import old_sample_steps
|
||||
|
||||
for s in (1, 2):
|
||||
c = case(s, steps=800)
|
||||
c["dense_root"] = True
|
||||
steps = sample_steps(c)
|
||||
t = steps / s**2
|
||||
n = len(t)
|
||||
ridx = old_sample_steps(c)
|
||||
# Nonzero steady reference fluxes cancel exact stock changes.
|
||||
inv = np.zeros((n, 2, 2, 3))
|
||||
inv[..., 0] = (100 - 0.001 * t[:, None, None]) * s**2
|
||||
inv[..., 1] = -t[:, None, None] * 0.002 * s
|
||||
flux = np.zeros_like(inv)
|
||||
flux[..., 0] = 0.001 + 1e-4 * np.cos(np.pi / 2 * t[:, None, None])
|
||||
flux[..., 1] = 0.002 / s
|
||||
raw = np.zeros((n, 2, 5, 4))
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp)
|
||||
(path / f"samples_s{s}.json").write_text(
|
||||
json.dumps(dict(case=c, sample_file="samples.npz"))
|
||||
)
|
||||
np.savez(
|
||||
path / "samples.npz",
|
||||
t_reference=t,
|
||||
cv_inventory=inv,
|
||||
cv_flux=flux,
|
||||
raw_cumulative=raw,
|
||||
ray_sample_indices=ridx,
|
||||
arc_estimates=np.zeros((len(ridx), 2, 2, 2, 2)),
|
||||
arc_absolute_estimates=np.zeros((len(ridx), 2, 2, 2, 2)),
|
||||
raw_absolute_aperture_mass_cumulative=np.broadcast_to(
|
||||
2 * t[:, None] * s**2, (n, 2)
|
||||
),
|
||||
global_mass_reference=np.ones((n, 2)) * 100,
|
||||
level_stats=np.broadcast_to([1, 1, 0, 0.03, 100], (n, 3, 5)),
|
||||
velocity_error=np.zeros(n),
|
||||
)
|
||||
result = analyze(path)
|
||||
w = result["windows"][1]
|
||||
self.assertTrue(result["complete_schedule"])
|
||||
np.testing.assert_allclose(
|
||||
np.array(w["normalized_cv_residual"])[0], 0, atol=1e-11
|
||||
)
|
||||
self.assertGreater(
|
||||
abs(np.array(w["old_cadence_change_from_dense"])[..., 0]).max(),
|
||||
0.005,
|
||||
)
|
||||
np.testing.assert_allclose(
|
||||
w["global_stock_raw_balance_sum_reference"], 0
|
||||
)
|
||||
np.testing.assert_allclose(
|
||||
w["raw_absolute_aperture_net_interval_mass_reference"], 200
|
||||
)
|
||||
np.testing.assert_allclose(w["raw_reaction_coefficient"], 0)
|
||||
|
||||
def test_common_physical_schedule(self):
|
||||
a = sample_steps(case(1, steps=3200))
|
||||
b = sample_steps(case(2, steps=3200))
|
||||
@@ -134,6 +239,57 @@ class Measurements(unittest.TestCase):
|
||||
snap["uniform_velocity_reference"][0][fluid], 0.01, rtol=1e-7
|
||||
)
|
||||
|
||||
def test_dense_recorder_retains_sparse_rays(self):
|
||||
h = 0.5
|
||||
y, x = np.mgrid[:64, :64]
|
||||
x = (x + 0.5) * h
|
||||
y = (y + 0.5) * h
|
||||
fluid = (x - 16) ** 2 + (y - 16) ** 2 > 25
|
||||
fine_leaf = fluid.copy()
|
||||
fine_leaf[:, :4] = False
|
||||
root_leaf = np.zeros((32, 32), bool)
|
||||
root_leaf[:, :2] = True
|
||||
|
||||
def eq(ny, nx):
|
||||
cu = CX[:, None, None] * 0.01
|
||||
return np.broadcast_to(
|
||||
W[:, None, None] * (1 + 3 * cu + 4.5 * cu * cu - 1.5 * 0.01**2),
|
||||
(9, ny, nx),
|
||||
).copy()
|
||||
|
||||
ug = eq(64, 64)
|
||||
levels = [eq(32, 32), ug.copy()]
|
||||
c = dict(
|
||||
scale=1,
|
||||
dense_root=True,
|
||||
steps=800,
|
||||
center=[16, 16],
|
||||
diameter=10,
|
||||
u=0.01,
|
||||
nu=0.0072,
|
||||
contours=[[9, 9, 23, 23], [7, 7, 25, 25]],
|
||||
)
|
||||
data = {
|
||||
name: [cv(ug, mask, (0, 0), r, c["nu"]) for r in c["contours"]]
|
||||
for name, mask in [("uniform_adapter", fluid), ("amr_api", fine_leaf)]
|
||||
}
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
rec = MeasurementRecorder(
|
||||
c, tmp, fluid, [root_leaf, fine_leaf], (0, 0), CX, CY
|
||||
)
|
||||
for step in (0, 101):
|
||||
rec.capture(step, ug, levels, data, {k: np.zeros(2) for k in data}, 0.0)
|
||||
rec.records[-1]["raw_cumulative"] = np.zeros((2, 5, 4))
|
||||
rec.records[-1]["raw_absolute_aperture_mass_cumulative"] = np.zeros(2)
|
||||
rec.flush()
|
||||
a = np.load(Path(tmp) / "samples_s1.npz")
|
||||
np.testing.assert_array_equal(a["step"], [0, 101])
|
||||
np.testing.assert_array_equal(a["ray_sample_indices"], [0])
|
||||
self.assertEqual(a["arc_estimates"].shape, (1, 2, 2, 2, 2))
|
||||
self.assertTrue(
|
||||
np.all(a["arc_absolute_estimates"] >= abs(a["arc_estimates"]) - 1e-14)
|
||||
)
|
||||
|
||||
def test_offline_mass_force_normalization(self):
|
||||
import json
|
||||
|
||||
|
||||
Reference in new issue
Block a user