Add MITC4 drilling diagnostics output and comparison contract

This commit is contained in:
KOKO\Mimi
2026-10-20 09:45:58 +09:00
parent 3d5c296651
commit a73d3fc9ca
31 changed files with 1175 additions and 45 deletions
+85
View File
@@ -349,3 +349,88 @@ def test_cli_writes_json_and_exit_two_for_missing_results(tmp_path, artifacts):
evidence = json.loads(report.read_text())
assert not evidence["precheck"]["passed"]
assert evidence["families"] == []
DRILLING_MODES = ("direct-initial-director-spring", "legacy-corotated-twist")
def drilling_result(tmp_path, artifacts, mode=DRILLING_MODES[0]):
path = changed_result(tmp_path, artifacts)
with h5py.File(path, "r+") as file:
file["metadata"].attrs["mitc4_drilling_formulation"] = mode
file["metadata"].attrs["drilling_diagnostics_version"] = np.uint64(1)
for frame in range(101):
root = file.require_group(f"steps/Step-1/frames/{frame}/global")
raw = np.array([1., 2., 3., 4., 5., 6.], dtype="<f8")
moment = np.array([4., 5., 6.], dtype="<f8")
corrected = raw.copy()
corrected[3:] -= moment
root.create_dataset("equilibrium", data=raw)
root.create_dataset("drilling_moment", data=moment)
root.create_dataset("equilibrium_with_drilling", data=corrected)
return path
@pytest.mark.parametrize("mode", DRILLING_MODES)
def test_drilling_diagnostics_are_precheck_and_report_all_frames(tmp_path, artifacts, mode):
result = comparator.compare(artifacts[0], artifacts[1], drilling_result(tmp_path, artifacts, mode))
assert result["precheck"]["passed"], result["precheck"]
assert result["verdict"] == "passed"
assert len(result["families"]) == 202
diagnostics = result["drilling_diagnostics"]
assert diagnostics["formulation"] == mode
assert diagnostics["version"] == 1
assert [frame["frame_index"] for frame in diagnostics["frames"]] == list(range(101))
assert diagnostics["frames"][0] == {
"storage_step": "Step-1", "frame_index": 0,
"raw_equilibrium": [1., 2., 3., 4., 5., 6.],
"drilling_moment": [4., 5., 6.],
"equilibrium_with_drilling": [1., 2., 3., 0., 0., 0.]}
def test_markerless_drilling_report_is_null(artifacts):
assert comparator.compare(*artifacts)["drilling_diagnostics"] is None
@pytest.mark.parametrize("mutation", ["mode_missing", "version_missing", "unknown_mode", "unknown_version",
"version_type", "mode_type", "initial_missing", "intermediate_missing", "both_missing",
"wrong_shape", "wrong_type", "big_endian", "nan", "inf", "wrong_algebra", "wrong_force"])
def test_drilling_diagnostics_rejected_before_displacement_tolerance(tmp_path, artifacts, mutation):
path = drilling_result(tmp_path, artifacts)
with h5py.File(path, "r+") as file:
metadata = file["metadata"]
root = file["steps/Step-1/frames/50/global"]
if mutation == "mode_missing":
del metadata.attrs["mitc4_drilling_formulation"]
elif mutation == "version_missing":
del metadata.attrs["drilling_diagnostics_version"]
elif mutation == "unknown_mode":
metadata.attrs["mitc4_drilling_formulation"] = "unknown"
elif mutation == "unknown_version":
metadata.attrs["drilling_diagnostics_version"] = np.uint64(2)
elif mutation == "version_type":
del metadata.attrs["drilling_diagnostics_version"]
metadata.attrs["drilling_diagnostics_version"] = np.uint32(1)
elif mutation == "mode_type":
del metadata.attrs["mitc4_drilling_formulation"]
metadata.attrs["mitc4_drilling_formulation"] = np.bytes_(DRILLING_MODES[0])
elif mutation == "initial_missing":
del file["steps/Step-1/frames/0/global/drilling_moment"]
elif mutation == "intermediate_missing":
del root["equilibrium_with_drilling"]
elif mutation == "both_missing":
del root["drilling_moment"]
del root["equilibrium_with_drilling"]
elif mutation in {"wrong_shape", "wrong_type", "big_endian"}:
del root["drilling_moment"]
root.create_dataset("drilling_moment", data=np.zeros(2 if mutation == "wrong_shape" else 3,
dtype=">f8" if mutation == "big_endian" else ("<f4" if mutation == "wrong_type" else "<f8")))
elif mutation == "nan":
root["drilling_moment"][0] = np.nan
elif mutation == "inf":
root["equilibrium"][0] = np.inf
else:
root["equilibrium_with_drilling"][0 if mutation == "wrong_force" else 3] = 1e-100
result = comparator.compare(artifacts[0], artifacts[1], path)
assert not result["precheck"]["passed"]
assert result["families"] == []