diff --git a/tests/fixtures/matlab/README.md b/tests/fixtures/matlab/README.md index ff544a2d..59d56fc5 100644 --- a/tests/fixtures/matlab/README.md +++ b/tests/fixtures/matlab/README.md @@ -54,6 +54,22 @@ That HDF5 is not byte-identical to the current WEC-Sim example; its regular-wave hydrodynamic data still reproduce this source trajectory within the stated per-channel gates. The live paired tests continue to use pinned MATLAB inputs. +## RM3 end-stop force transition + +`rm3_end_stops_force_samples.csv` retains six rows from the successful +[full-duration 0.0125 s R2025b run](https://github.com/cmudrc/wec-sim-python/actions/runs/37698235851) +(`matlab-RM3_END_STOPS_FULL_FINER-baseline` artifact, run commit +`ae9a0a8e0959b95a9489b61ea9c6f161ae184e7e`). The workflow pins core +`0753b2e47f2457c078751dcfe5d251d1767b80ab` and Applications +`d53d4d4c9eda2581f04204f5d394a6ef84bb099e`. Source rows +`0, 5166, 8627, 8948, 22725, 28451` retain CSV columns `0, 3, 9, 15` +as time, stroke, speed, and total PTO force. The source CSV SHA-256 is +`898147eeac1bc62746dfb84a71dec9d640bbcafb9da63129ef9040467398f7d0`; +the compact fixture SHA-256 is +`a409f621d21825366dc1f11b13c12fc9c88f07beb6f86a4670a709253c7f3c20`. +Two selected rows are inside the effective 0.1 mm spring transition and +distinguish the source's smooth force from a sharp stop. + ## Sphere free decay `sphere_free_decay.npz` retains every sample of the five published Sphere diff --git a/tests/fixtures/matlab/rm3_end_stops_force_samples.csv b/tests/fixtures/matlab/rm3_end_stops_force_samples.csv new file mode 100644 index 00000000..c3cb88eb --- /dev/null +++ b/tests/fixtures/matlab/rm3_end_stops_force_samples.csv @@ -0,0 +1,7 @@ +source_row,time_s,stroke_m,speed_m_per_s,total_force_n +0,0,0,0,-4.8784927946264703e-25 +5166,64.575000000000003,0.59986018228918703,-0.00120895311809712,1450.7437417165499 +8627,107.83750000000001,-0.66401256505767803,0.0096621411218380908,6389661.9364213701 +8948,111.84999999999999,0.66414522911501095,0.012065261787550199,-6429001.2256459901 +22725,284.0625,-0.600025582654659,0.41576599328819702,-498502.564619813 +28451,355.63749999999999,-0.60007629978782195,-0.49465971604444098,600139.05699970899 diff --git a/tests/test_rm3_end_stops_standalone.py b/tests/test_rm3_end_stops_standalone.py index aaca9353..4264ee1e 100644 --- a/tests/test_rm3_end_stops_standalone.py +++ b/tests/test_rm3_end_stops_standalone.py @@ -13,6 +13,29 @@ ROOT = Path(__file__).resolve().parents[1] EXAMPLE = ROOT / "examples/rm3.json" HYDRO = ROOT / "examples/data/rm3.h5" +SOURCE_FORCE = (ROOT / "tests/fixtures/matlab" + / "rm3_end_stops_force_samples.csv") + + +def test_published_stop_transition_matches_compact_matlab_source(): + samples = np.loadtxt(SOURCE_FORCE, delimiter=",", skiprows=1) + assert samples.shape == (6, 5) + np.testing.assert_array_equal(samples[:, 0], + [0, 5166, 8627, 8948, 22725, 28451]) + stroke, speed, source_force = samples[:, 2], samples[:, 3], samples[:, 4] + stops = LinearHardStops(-0.6, 0.6, 1e8, 1e8) + predicted = -1_200_000 * speed + stops.force(stroke, speed) + np.testing.assert_allclose(predicted, source_force, rtol=0, atol=1e-5) + + # Two source samples lie inside the 0.1 mm transition. A sharp spring + # misses each logged total PTO force by more than 1 kN there. + transition = (np.abs(stroke) > 0.6) & (np.abs(stroke) < 0.6001) + assert np.count_nonzero(transition) == 2 + sharp_force = (-1_200_000 * speed + + 1e8 * np.maximum(-0.6 - stroke, 0) + - 1e8 * np.maximum(stroke - 0.6, 0)) + assert np.min(np.abs(sharp_force[transition] + - source_force[transition])) > 1000 def test_opt_in_stops_are_step_stable_and_report_the_reaction():