/ proof-of-concept / cymsim
Sign in
proof-of-concept / cymsim
cymsim / tests / test_simulate.py
81 lines · 3.6 KBBlameHistoryRaw
1import copy
3import numpy as np
4import pytest
6from cymsim.config import ForceExciter, Hit, MalletExciter, StickExciter
7from cymsim.exciter import build_patch
8from cymsim.simulate import Simulator
11@pytest.fixture(scope="module")
12def result(coarse_config):
13 return Simulator(coarse_config).run()
16def test_single_hit_run(result, coarse_config):
17 n_out = int(coarse_config.numerics.fs * coarse_config.numerics.duration)
18 assert result.pressure_rayleigh.shape == (n_out,)
19 assert np.isfinite(result.pressure_unbaffled).all()
20 assert np.abs(result.pressure_unbaffled).max() > 0.1 # a 9.6 J stroke is loud
21 (h,) = result.hits
22 assert h.peak_force > 100 and 0.5e-3 < h.contact_time < 20e-3
23 assert 0 < h.rebound_velocity < coarse_config.hits[0].velocity
24 assert h.energy_out < h.energy_in
25 for e in result.energy_log:
26 assert e.total <= h.energy_in * 1.01 # energy only leaves through damping
27 assert result.energy_log[-1].max_w_over_h > 1 # this stroke is clearly nonlinear
30def test_linear_reference_run_is_less_energetic_at_high_frequency(coarse_config):
31 cfg = copy.deepcopy(coarse_config)
32 cfg.numerics.nonlinear = False
33 lin = Simulator(cfg).run()
34 assert np.isfinite(lin.pressure_unbaffled).all()
37def test_two_hits(coarse_config):
38 cfg = copy.deepcopy(coarse_config)
39 cfg.numerics.duration = 0.03
40 cfg.hits = [Hit(time=0.0, r=0.137, phi=0.3, velocity=8.0, exciter=MalletExciter()),
41 Hit(time=0.015, r=0.19, phi=2.0, velocity=7.0, exciter=StickExciter(patch_points=5))]
42 sim = Simulator(cfg)
43 assert sim.schedule.n_hits == 2 and sim.schedule.n_points == 7 # padded to the mallet's 7
44 res = sim.run()
45 assert len(res.hits) == 2
46 assert res.hits[1].kind == "stick" and res.hits[1].peak_force > 0
47 assert 0 < res.hits[1].contact_time < 5e-3
48 assert res.hits[0].rebound_velocity > 0 and res.hits[1].rebound_velocity > 0
51def test_contact_patch_geometry(coarse_config):
52 sim = Simulator(coarse_config)
53 stick = build_patch(Hit(r=0.19, phi=0.5, velocity=7.0, exciter=StickExciter()), sim.mesh, sim.profile)
54 assert stick.n_points == 7 and np.isclose(np.hypot(stick.x[3], stick.y[3]), 0.19)
55 assert np.allclose(stick.weights.sum(1), 1.0)
56 assert np.isclose(stick.free_contact_time(), 2.94 * stick.max_compression() / 7.0, rtol=1e-2)
57 mallet = build_patch(Hit(r=0.137, phi=0.3, velocity=8.0, exciter=MalletExciter()), sim.mesh, sim.profile)
58 assert np.isclose(mallet.max_compression(), MalletExciter.compression)
59 assert abs(mallet.offsets.max()) < 5e-3
62def test_prescribed_force_and_probes(coarse_config):
63 cfg = copy.deepcopy(coarse_config)
64 cfg.hits = [Hit(time=0.002, r=0.15, phi=0.7, exciter=ForceExciter(peak=50.0, duration=2e-3))]
65 cfg.output.record_acceleration = True
66 sim = Simulator(cfg)
67 node = int(np.argmin(np.hypot(sim.mesh.xy[:, 0] - 0.1, sim.mesh.xy[:, 1] - 0.05)))
68 cfg.output.probes = [tuple(sim.mesh.xy[node]), (0.05, -0.12)]
69 res = Simulator(cfg).run()
70 (h,) = res.hits
71 assert h.kind == "force"
72 assert np.isclose(h.peak_force, 50.0, rtol=1e-3)
73 assert np.isclose(h.contact_time, 2e-3, rtol=1e-2)
74 assert h.energy_in == 0 and h.rebound_velocity == 0
75 a = res.probe_acceleration
76 n_out = int(cfg.numerics.fs * cfg.numerics.duration)
77 assert a.shape == (n_out, 2) and np.isfinite(a).all()
78 assert np.abs(a[: int(0.002 * cfg.numerics.fs) - 16]).max() < 1e-6 * np.abs(a).max() # nothing before the hit
79 # a probe on a node sees that node's acceleration (same decimation kernel; int16 record)
80 rec = res.acceleration.as_float()[:, node]
81 assert np.abs(a[:, 0] - rec).max() < 1e-3 * np.abs(rec).max()
↑↓ move↵openescclose