"""Refresh the run-dependent parts of cymsimweb's Python reference fixture. Usage: python tools/make_web_fixture.py ../cymsimweb/tests/fixtures/python_reference.json The fixture's configuration (a coarse, dent-free profile) is kept; the ``config``, ``timestep``, ``run`` and ``run_linear`` entries are rewritten from a fresh run of this package, including the recorded normal acceleration of a few nodes and a sample of the decimation taps, which the web tests compare against their own implementation. The mesh, shell, DKT and patch entries do not depend on the time loop and are left as they are. """ from __future__ import annotations import dataclasses import json import sys import numpy as np from cymsim.config import SimulationConfig from cymsim.simulate import Simulator ACC_NODES = [0, 50, 120] def run_entry(cfg: SimulationConfig) -> dict: sim = Simulator(cfg) res = sim.run() a = res.acceleration.as_float() return { "hits": [dataclasses.asdict(h) for h in res.hits], "energy_log": [[e.time, e.kinetic, e.membrane, e.bending, e.exciters, e.max_w_over_h] for e in res.energy_log], "pressure_rayleigh": res.pressure_rayleigh.tolist(), "pressure_unbaffled": res.pressure_unbaffled.tolist(), "fs": res.fs, "acceleration_nodes": ACC_NODES, "acceleration": [a[:, i].astype(float).tolist() for i in ACC_NODES], "n_steps": sim.n_steps, }, sim def main(path: str) -> None: with open(path) as f: fx = json.load(f) cfg = SimulationConfig.from_dict(fx["config"]) cfg.output.record_acceleration = True cfg.output.displacement_rate = 0.0 sim0 = Simulator(cfg) # whole blocks must end on an audio sample so that the web loop can stop at the same time m = sim0.substeps if cfg.numerics.steps_per_block % m: cfg.numerics.steps_per_block = m * max(1, cfg.numerics.steps_per_block // m) fx["config"] = cfg.to_dict() run, sim = run_entry(cfg) lin_cfg = SimulationConfig.from_dict(cfg.to_dict()) lin_cfg.numerics.nonlinear = False run_linear, _ = run_entry(lin_cfg) fx["timestep"] = {"dt": sim.dt, "substeps": sim.substeps, "omega_global": sim.shell.omega_global, "omega_global_iterations": sim.shell.omega_global_iterations} fx["run"], fx["run_linear"] = run, run_linear taps = sim.taps fx["decimation"] = {"span": taps.shape[0], "substeps": taps.shape[1], "taps_sample": [[int(w), int(k), float(taps[w, k])] for w, k in [(0, 0), (15, 0), (15, m - 1), (16, 0), (31, m - 1), (7, m // 2)]], "normal_first3": sim.shell.normal_node[:3].tolist()} with open(path, "w") as f: json.dump(fx, f) print(f"wrote {path}: {len(run['pressure_unbaffled'])} samples, {sim.n_steps} steps, m = {m}") if __name__ == "__main__": main(sys.argv[1])