Skip to content

Commit

Permalink
BF: Correct Universal editing sequence HERMES conditions and tests fo…
Browse files Browse the repository at this point in the history
…r XA50 twix and RDA (#130)

* Fix issues in un tested lines of the universal editing special case

* Fix issue in mgs_svs_ed special casing. Add xa50 test data.
  • Loading branch information
wtclarke authored Mar 6, 2024
1 parent 40c2e10 commit 475c60b
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 13 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ This document contains the Spec2nii release history in reverse chronological ord
-----------
- Siemens .rda format now had corrected and validated orientations (tested on VE11 baseline).
- Siemens .rda format now handles MRSI/CSI data and matches DICOM output. Validated on VE11 baseline data.
- Fixes in Siemens Twix special case for universal editing sequence (HERMES conditions).
- Added handling of custom Bruker sequences `mt_sLASER`, `mt_MEGA_sLASER_V35` and `cl_STELASER_PA360_b`.

0.7.2 (Thursday 7th December 2023)
----------------------------------
Expand Down
25 changes: 13 additions & 12 deletions spec2nii/Siemens/twix_special_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,24 +142,24 @@ def mgs_svs_ed_twix(twixObj, reord_data, meta_obj, dim_tags):
"OFF": {"PulseOffset": edit_pulse_off, "PulseDuration": pulse_length}}
elif seq_mode == 1.0:
# HERMES GABA GSH (3 edit, 1 ctrl condition)
edit_cases = 3
edit_cases = 4
dim_info = "HERMES j-difference editing, GABA GSH, four conditions"
dim_header = {"EditCondition": ["A", "B", "C", "D"]}
edit_pulse_val = {
"A": {"PulseOffset": edit_pulse_1, "PulseDuration": 0.02},
"B": {"PulseOffset": None, "PulseDuration": None},
"C": {"PulseOffset": edit_pulse_off, "PulseDuration": 0.02},
"D": {"PulseOffset": [edit_pulse_1, edit_pulse_off], "PulseDuration": 0.02}}
"B": {"PulseOffset": edit_pulse_off, "PulseDuration": 0.02},
"C": {"PulseOffset": edit_pulse_2, "PulseDuration": 0.02},
"D": {"PulseOffset": [edit_pulse_1, edit_pulse_2], "PulseDuration": 0.02}}
elif seq_mode == 2.0:
# HERMES GABA GSH EtOH (3 edit, 1 ctrl condition)
edit_cases = 4
dim_info = "HERMES j-difference editing, GABA GSH EtOH, four conditions"
dim_header = {"EditCondition": ["A", "B", "C", "D"]}
edit_pulse_val = {
"A": {"PulseOffset": [edit_pulse_1, edit_pulse_2], "PulseDuration": 0.02},
"B": {"PulseOffset": [edit_pulse_3, edit_pulse_2], "PulseDuration": None},
"C": {"PulseOffset": [edit_pulse_1, edit_pulse_3], "PulseDuration": 0.02},
"D": {"PulseOffset": None, "PulseDuration": None}}
"A": {"PulseOffset": [edit_pulse_1, edit_pulse_3], "PulseDuration": 0.02},
"B": {"PulseOffset": edit_pulse_off, "PulseDuration": 0.02},
"C": {"PulseOffset": [edit_pulse_2, edit_pulse_3], "PulseDuration": 0.02},
"D": {"PulseOffset": [edit_pulse_1, edit_pulse_2], "PulseDuration": 0.02}}
elif seq_mode == 3.0:
# HERCULES (4 edit conditions)
edit_cases = 4
Expand All @@ -170,16 +170,17 @@ def mgs_svs_ed_twix(twixObj, reord_data, meta_obj, dim_tags):
"B": {"PulseOffset": [edit_pulse_off, edit_pulse_2], "PulseDuration": 0.02},
"C": {"PulseOffset": edit_pulse_1, "PulseDuration": 0.02},
"D": {"PulseOffset": edit_pulse_off, "PulseDuration": 0.02}}
elif seq_mode == 3.0:
elif seq_mode == 4.0:
# This is possibly only a condition for smm_svs_herc as not present in VE11c version.
# HERMES GABA LAC (3 edit 1 ctrl conditions)
edit_cases = 4
dim_info = "HERMES j-difference editing, GABA LAC, four conditions"
dim_header = {"EditCondition": ["A", "B", "C", "D"]}
edit_pulse_val = {
"A": {"PulseOffset": edit_pulse_1, "PulseDuration": 0.02},
"B": {"PulseOffset": None, "PulseDuration": None},
"C": {"PulseOffset": edit_pulse_off, "PulseDuration": 0.02},
"D": {"PulseOffset": [edit_pulse_1, edit_pulse_off], "PulseDuration": 0.02}}
"B": {"PulseOffset": edit_pulse_off, "PulseDuration": 0.02},
"C": {"PulseOffset": edit_pulse_2, "PulseDuration": 0.02},
"D": {"PulseOffset": [edit_pulse_1, edit_pulse_2], "PulseDuration": 0.02}}
else:
raise ValueError('Unknown sequence mode in mgs_svs_ed sequence.')

Expand Down
2 changes: 1 addition & 1 deletion tests/spec2nii_test_data
Submodule spec2nii_test_data updated from 9322e3 to d300d5
20 changes: 20 additions & 0 deletions tests/test_siemens_rda.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

xa20_svs_path = siemens_path / 'XAData' / 'XA20/rda/spct_002.MR.MRI-LAB Test_Dir.5.1.114540.rda'
xa31_locale_svs_path = siemens_path / 'XAData' / 'XA31/rda/locale_XA31.rda'
xa50_path = siemens_path / 'XAData' / 'XA50' / 'Phantom_20240129.MR.10.1.155227.rda'

latin1_encoding = siemens_path / 'rda' / 'latin1.rda'

Expand Down Expand Up @@ -147,6 +148,25 @@ def test_xa31_locale_svs(tmp_path):
assert np.iscomplexobj(img_t.dataobj)


def test_xa50_svs(tmp_path):

subprocess.run([
'spec2nii', 'rda',
'-f', 'xa50_svs',
'-o', tmp_path,
'-j', xa50_path])

img_t = read_nifti_mrs(tmp_path / 'xa50_svs.nii.gz')

hdr_ext_codes = img_t.header.extensions.get_codes()
hdr_ext = json.loads(img_t.header.extensions[hdr_ext_codes.index(44)].get_content())

hdr_ext['ResonantNucleus'] = ['1H', ]

assert img_t.shape == (1, 1, 1, 2048)
assert np.iscomplexobj(img_t.dataobj)


def test_latin_encoding(tmp_path):

subprocess.check_call(['spec2nii', 'rda',
Expand Down
22 changes: 22 additions & 0 deletions tests/test_twix.py → tests/test_siemens_twix.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
# Special cased data
hercules_ve = siemens_path / 'HERCULES' / 'Siemens_TIEMO_HERC.dat'
hercules_xa30 = siemens_path / 'HERCULES' / 'meas_MID02595_FID60346_HERC.dat'
hermes_xa50 = siemens_path / 'XAData' / 'XA50' / 'smm_svs_herc_v2_hermes.dat'


def test_VB(tmp_path):
Expand Down Expand Up @@ -202,6 +203,27 @@ def test_XA_HERCULES(tmp_path):
assert hdr_ext['dim_7'] == 'DIM_DYN'


def test_XA_HERMES(tmp_path):

subprocess.check_call(['spec2nii', 'twix',
'-e', 'image',
'-f', 'hermes_xa',
'-o', tmp_path,
'-j', str(hermes_xa50)])

img_t = read_nifti_mrs(tmp_path / 'hermes_xa.nii.gz')

hdr_ext_codes = img_t.header.extensions.get_codes()
hdr_ext = json.loads(img_t.header.extensions[hdr_ext_codes.index(44)].get_content())

assert img_t.shape == (1, 1, 1, 4096, 42, 4, 80)
assert np.iscomplexobj(img_t.dataobj)

assert hdr_ext['dim_5'] == 'DIM_COIL'
assert hdr_ext['dim_6'] == 'DIM_EDIT'
assert hdr_ext['dim_7'] == 'DIM_DYN'


def test_twix_mrsi_orientation(tmp_path):
'''Test that the (empty) mrsi has information matching the twix equivalent.'''

Expand Down

0 comments on commit 475c60b

Please sign in to comment.