research: Dütsch analyzer — complete-cycle check only for an explicit horizon

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-10-30 11:55:07 +00:00
co-authored by Claude Opus 5.5
parent 02421ae379
commit 430bcf2fc3
+7 -4
View File
@@ -97,6 +97,8 @@ def hf_component(case, ks):
mean CME waveform over cycles ks minus its two-basis Morison reconstruction, mean CME waveform over cycles ks minus its two-basis Morison reconstruction,
split at 20/T; cycle differencing does not remove it.""" split at 20/T; cycle differencing does not remove it."""
T = case["T"] T = case["T"]
if not ks:
return dict(label="unqualified phase-locked HF force component, not checked", cycles=[])
mean = np.mean([coarse_wave(case, k) for k in ks], axis=0) mean = np.mean([coarse_wave(case, k) for k in ks], axis=0)
c_d, c_i = cycle_morison(case, ks) c_d, c_i = cycle_morison(case, ks)
q = T // 4 q = T // 4
@@ -125,13 +127,13 @@ def main(argv):
if "--reference" in argv: if "--reference" in argv:
i = argv.index("--reference") i = argv.index("--reference")
ref_path, argv = argv[i + 1], argv[:i] + argv[i + 2:] ref_path, argv = argv[i + 1], argv[:i] + argv[i + 2:]
horizon = p.LAST_SCORED # default cap: bit-for-bit the original scoring horizon, explicit = p.LAST_SCORED, "--horizon" in argv # default: original scoring
if "--horizon" in argv: if explicit:
i = argv.index("--horizon") i = argv.index("--horizon")
horizon, argv = int(argv[i + 1]), argv[:i] + argv[i + 2:] horizon, argv = int(argv[i + 1]), argv[:i] + argv[i + 2:]
paths = argv if ref_path is None or ref_path in argv else argv + [ref_path] paths = argv if ref_path is None or ref_path in argv else argv + [ref_path]
cases = [load(path) for path in paths] cases = [load(path) for path in paths]
for c in cases: # every scored cycle must be complete; never pad or shift for c in cases if explicit else (): # complete cycles 1..N; never pad or shift
if c["cycles"] < horizon or len(c["force"]) < round((0.25 + horizon) * c["T"]): if c["cycles"] < horizon or len(c["force"]) < round((0.25 + horizon) * c["T"]):
raise SystemExit(f"{c['path']}: run does not contain complete cycles 1..{horizon}") raise SystemExit(f"{c['path']}: run does not contain complete cycles 1..{horizon}")
ledgers = [ledger(c, horizon) for c in cases] ledgers = [ledger(c, horizon) for c in cases]
@@ -147,7 +149,8 @@ def main(argv):
entry.update(duration_T=case["steps"] / case["T"], K_case=k_case, pairs=pairs, entry.update(duration_T=case["steps"] / case["T"], K_case=k_case, pairs=pairs,
coverage={k: coverage(case, k) for k in sorted(cycle_slices(case)) if k > p.DISCARD}, coverage={k: coverage(case, k) for k in sorted(cycle_slices(case)) if k > p.DISCARD},
no_donor=float(case["diag"][:, 13].sum()), eq_only=float(case["diag"][:, 12].sum()), no_donor=float(case["diag"][:, 13].sum()), eq_only=float(case["diag"][:, 12].sum()),
hf_component=hf_component(case, window or tuple(range(horizon - 2, horizon + 1)))) hf_component=hf_component(case, window or tuple(
[k for k in sorted(cycle_slices(case)) if p.DISCARD < k <= horizon][-3:])))
if window: # residual drift inside the scored window (pairs K..K+2) if window: # residual drift inside the scored window (pairs K..K+2)
entry["window_drift"] = {key: max(pairs[k][key] for k in window) entry["window_drift"] = {key: max(pairs[k][key] for k in window)
for key in ("wave", "profile", "morison")} for key in ("wave", "profile", "morison")}