From 54c05cc4a3d83b16403c34c2dacc7c994eed9448 Mon Sep 17 00:00:00 2001 From: "Gabriel A. Devenyi" Date: Fri, 21 Aug 2026 20:01:15 -0400 Subject: [PATCH] Include PV360's CMN_study_ parameters in the subject metadata group METADATA_GROUPS selected the content of the study's subject file by the single prefix SUBJECT_. ParaVision 360 also writes two CMN_ parameters into that file, and they are study-level facts like everything else there: CMN_study_use_ats, whether the Animal Transport System is used for the study, and CMN_study_bed, the name of the animal bed. The PV360 manual lists both under the SUBJECT_study group, next to SUBJECT_study_operator and SUBJECT_study_instrument_position, and the 360.3.7 standard dataset writes CMN_study_use_ats=Yes in its subject. CMN_study_use_ats is the one that matters downstream: with the ATS in use the coordinate origin is shifted, so a reader that wants to know which frame the geometry is in has to look at it. Anything keyed on the subject group -- report(add_parameters=["subject"]) included -- dropped it silently. Add CMN_study_ as a second prefix of the group. It is narrower than CMN_ on purpose: metadata scans every loaded parameter file, and the study-level pair is the only CMN_ content the subject file is known to carry. They appear as use_ats and bed. PV5.1 and PV6 write neither, so nothing changes for them. Closes #217 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NHhfFXMNZKMuPm3ppdzFXe --- brukerapi/dataset.py | 2 +- test/test_api.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/brukerapi/dataset.py b/brukerapi/dataset.py index 0232022..f2ccbe8 100644 --- a/brukerapi/dataset.py +++ b/brukerapi/dataset.py @@ -244,7 +244,7 @@ "visu_series": (("VisuSeries",), ("VisuExperimentNumber", "VisuProcessingNumber")), "visu_equipment": ((), ("VisuManufacturer", "VisuAcqSoftwareVersion", "VisuInstitution", "VisuStation")), "visu_acq": (("VisuAcq", "VisuAcquisition"), ()), - "subject": (("SUBJECT_",), ()), + "subject": (("SUBJECT_", "CMN_study_"), ()), } # What "could not read this parameter file" looks like. FileNotFoundError is the diff --git a/test/test_api.py b/test/test_api.py index 4d52c4e..7cd2d43 100644 --- a/test/test_api.py +++ b/test/test_api.py @@ -69,6 +69,22 @@ def test_metadata_groups_follow_the_specification(tmp_path): assert "uisition_protocol" not in metadata["visu_acq"] +def test_subject_group_carries_the_pv360_study_level_cmn_parameters(tmp_path): + """PV360 writes two CMN_ parameters into `subject`, next to SUBJECT_study_*. + + `CMN_study_use_ats` says whether the Animal Transport System was in use, + which shifts the coordinate origin; selecting the group by `SUBJECT_` alone + dropped it and `CMN_study_bed` silently. + """ + root = tmp_path / "20200612_094625_study_1_1" + write_jcampdx(root / "subject", {"SUBJECT_id": [""], "SUBJECT_study_nr": 1, "CMN_study_use_ats": "Yes", "CMN_study_bed": [""]}) + dataset = Dataset(write_2dseq(root / "8" / "pdata" / "1"), add_parameters=["subject"], load=LOAD_STAGES["properties"]) + + assert dataset.metadata["subject"]["id"] == "phantom" + assert dataset.metadata["subject"]["use_ats"] == "Yes" + assert dataset.metadata["subject"]["bed"] == "Rat bed" + + def test_metadata_reports_the_same_string_as_the_property_that_reads_it(tmp_path): """`subj_id` and `metadata` read VisuSubjectName; they must agree.