research: Dütsch analyzer — horizon-limited coverage/events, Parseval HF weights
Coverage and no_donor/eq_only totals now stop at the horizon; HF energy uses one-sided Parseval weights (interior bins x2, DC/Nyquist x1). Focused regressions for both. run.py, src and thresholds unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
430bcf2fc3
commit
dd37883d3c
2 files changed
+58
-3
No files matched your search
@@ -108,3 +108,45 @@ def test_generated_config_passes_the_real_loader(tmp_path):
|
||||
assert cfg.collision == "MRT" and cfg.streaming == "double_buffer" and not cfg.ddf_shifting
|
||||
assert cfg.velocity == 0.0 and cfg.viscosity == pytest.approx(u_max * 20 / 100)
|
||||
assert cfg.y_wall_bc == "bounce_back"
|
||||
|
||||
|
||||
def _analyze():
|
||||
import sys
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "research/duetsch_re100_kc5"))
|
||||
try:
|
||||
import analyze
|
||||
finally:
|
||||
sys.path.pop(0)
|
||||
return analyze
|
||||
|
||||
|
||||
def test_hf_energy_is_parseval_weighted():
|
||||
a = _analyze()
|
||||
n = 360
|
||||
t = np.arange(n)
|
||||
x = 1.0 + np.cos(2 * np.pi * 5 * t / n) + 2.0 * np.cos(2 * np.pi * 30 * t / n) + 0.5 * np.cos(np.pi * t)
|
||||
e = a.one_sided_energy(np.fft.rfft(x), n) / n
|
||||
assert e.sum() == pytest.approx(np.sum(x ** 2)) # Parseval
|
||||
expected = (2.0 ** 2 / 2 + 0.5 ** 2) / np.mean(x ** 2) # bins >= 21 (30 and Nyquist)
|
||||
assert e[21:].sum() / e.sum() == pytest.approx(expected)
|
||||
|
||||
|
||||
def test_horizon_excludes_future_coverage_and_events(monkeypatch):
|
||||
a = _analyze()
|
||||
T, horizon = 360, 4
|
||||
steps = round((0.25 + 6) * T) # cycles 1..6 recorded
|
||||
diag = np.zeros((steps, 15))
|
||||
diag[round((0.25 + horizon) * T):, 13] = 1.0 # synthetic future no_donor
|
||||
rows = [(s, p.cycle(s, T), 180.0, 0.0, 0.0, 0.1, 0.0, 1.0) for s in range(steps)
|
||||
if p.bin_phase(s, T) is not None and p.cycle(s, T) > p.DISCARD]
|
||||
case = dict(path="c", D=20, T=T, box=10, n=200, u_max=.04, nu=.008, tau=.524, A=1.0,
|
||||
steps=steps, cycles=6, F_ref=1.0, force=np.zeros((steps, 2)), diag=diag,
|
||||
samples=np.asarray(rows, float))
|
||||
monkeypatch.setattr(a, "load", lambda path: case)
|
||||
out = []
|
||||
monkeypatch.setattr("builtins.print", lambda text: out.append(text))
|
||||
a.main(["c", "--horizon", str(horizon)])
|
||||
import json
|
||||
entry = json.loads(out[0])["cases"][0]
|
||||
assert sorted(int(k) for k in entry["coverage"]) == [3, 4] # nothing from cycles 5, 6
|
||||
assert entry["no_donor"] == 0.0
|
||||
Reference in new issue
Block a user