From 0ba6ad0cdf3fc852585438e6d1e01b359e97c171 Mon Sep 17 00:00:00 2001 From: Aaron Gudmundson Date: Fri, 21 Jul 2023 11:41:44 -0400 Subject: [PATCH 01/10] Update ge_pfile.py --- spec2nii/GE/ge_pfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec2nii/GE/ge_pfile.py b/spec2nii/GE/ge_pfile.py index 74a9c00..e9b5d20 100644 --- a/spec2nii/GE/ge_pfile.py +++ b/spec2nii/GE/ge_pfile.py @@ -97,7 +97,7 @@ def _process_svs_pfile(pfile): data, meta, dwelltime, fname_suffix = _process_oslaser(pfile) elif psd in ('slaser'): data, meta, dwelltime, fname_suffix = _process_slaser(pfile) - elif psd == 'gaba': + elif psd in ['gaba', 'hbcd']: data, meta, dwelltime, fname_suffix = _process_gaba(pfile) elif 'jpress_ac' in psd: # Bergen patch data, meta, dwelltime, fname_suffix = _process_gaba(pfile) From 7dad34af0fe8e28c49d0d27b93959ce97ead41d9 Mon Sep 17 00:00:00 2001 From: Aaron Gudmundson Date: Fri, 21 Jul 2023 11:41:48 -0400 Subject: [PATCH 02/10] Update ge_read_pfile.py --- spec2nii/GE/ge_read_pfile.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec2nii/GE/ge_read_pfile.py b/spec2nii/GE/ge_read_pfile.py index 9038f8b..9223c3f 100644 --- a/spec2nii/GE/ge_read_pfile.py +++ b/spec2nii/GE/ge_read_pfile.py @@ -199,6 +199,9 @@ def get_mapper(self): elif psd == 'gaba': # wtc - added for Nottingham MEGA-PRESS sequence. mapper = PfileMapperGaba + elif psd == 'hbcd': + # ATG - added HBCD - reuse GABA mapper + mapper = PfileMapperGaba elif psd == 'probe-sl': # wtc - added for CSI sequence from Manchester. mapper = PfileMapperProbeSL @@ -1247,7 +1250,7 @@ def read_data(self): if (dataframes + refframes) != nframes: mult = 1 dataframes *= nex - refframes = nframes - dataframes + refframes = int(nframes - dataframes) else: mult = 1.0 / nex From 3e2e36ff155226da9eb07ee4ff60c59d73021c2f Mon Sep 17 00:00:00 2001 From: Aaron Gudmundson Date: Fri, 4 Aug 2023 11:50:23 -0400 Subject: [PATCH 03/10] Update "Dim_" Updated functionality to correctly handle "Dim_" across each sub experiment. --- spec2nii/Siemens/twix_special_case.py | 10 +++++----- spec2nii/Siemens/twixfunctions.py | 17 ++++------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/spec2nii/Siemens/twix_special_case.py b/spec2nii/Siemens/twix_special_case.py index 9172cfd..cc79332 100644 --- a/spec2nii/Siemens/twix_special_case.py +++ b/spec2nii/Siemens/twix_special_case.py @@ -103,11 +103,11 @@ def smm_svs_herc_hyper(twixObj, reord_data, meta_obj, dim_tags, subseq, subseq_n dim_tags.insert(len(orig_shape) - 3, 'DIM_EDIT') # Update Dimensions - for idx, dt in enumerate(dim_tags): # Iterate Dimensions - if dt == 'DIM_EDIT': - meta_obj.set_dim_info(idx, dt, dim_info, dim_header) # Set Dimension - else: - meta_obj.set_dim_info(idx, dt) # Set Dimension + for idx, dt in enumerate(dim_tags): # Iterate Dimensions + if dt == 'DIM_EDIT': + meta_obj.set_dim_info(idx, dt, dim_info, dim_header) # Set Dimension + else: + meta_obj.set_dim_info(idx, dt) # Set Dimension print(f'{subseq:3d} {subseq_name:<20} - Completed - Final Array Size: ', reord_data.shape) diff --git a/spec2nii/Siemens/twixfunctions.py b/spec2nii/Siemens/twixfunctions.py index d0d5323..744ea85 100644 --- a/spec2nii/Siemens/twixfunctions.py +++ b/spec2nii/Siemens/twixfunctions.py @@ -383,10 +383,6 @@ def process_svs(twixObj, base_name_out, name_in, dataKey, dim_overrides, remove_ '80ms HERCULES'] # Hyper Subscan Names hyp_suffix = ['ref_short_te', 'ref_edited', 'short_te', 'edited'] # Hyper Suffixes - reord_list = [] # List of Reord Data - meta_list = [] # List of Meta Objects - dim_list = [] # List of Dimensions - # Reording the Data & Adjusting the Header Appropriately for ii in range(len(hyp_names)): # Iterate over Subscans print(f'{ii:3d} {hyp_names[ii]:<20}', end='\r') @@ -397,17 +393,12 @@ def process_svs(twixObj, base_name_out, name_in, dataKey, dim_overrides, remove_ subseq=ii, subseq_name=hyp_names[ii]) - reord_list.append(reord_data_) # Current Scan Data - meta_list.append(meta_obj_) # Current Scan Metadata - dim_list.append(dim_tags_) # Current Scan Dimensions - - for ii in range(len(hyp_names)): - if reord_list[ii].ndim <= 4: # 4 or less Dims - newshape = (1, 1, 1) + reord_list[ii].shape # Pad 3 singleton dims - nifit_mrs_out.append(assemble_nifti_mrs(reord_list[ii].reshape(newshape), + if reord_data_.ndim <= 4: # 4 or less Dims + newshape = (1, 1, 1) + reord_data_.shape # Pad 3 singleton dims + nifit_mrs_out.append(assemble_nifti_mrs(reord_data_.reshape(newshape), dwellTime, orientation, - meta_list[ii])) + meta_obj_)) filename_out.append(f'{mainStr}_{hyp_suffix[ii]}') return nifit_mrs_out, filename_out From 01fbbbd80e29347b475f5b4f879fc587dc2586f6 Mon Sep 17 00:00:00 2001 From: Aaron Gudmundson Date: Fri, 4 Aug 2023 14:59:49 -0400 Subject: [PATCH 04/10] Hyper Echo Time for Long TE Added Hyper Echo Time for Long TE --- spec2nii/Siemens/twix_special_case.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec2nii/Siemens/twix_special_case.py b/spec2nii/Siemens/twix_special_case.py index cc79332..b9086b3 100644 --- a/spec2nii/Siemens/twix_special_case.py +++ b/spec2nii/Siemens/twix_special_case.py @@ -63,6 +63,7 @@ def smm_svs_herc_hyper(twixObj, reord_data, meta_obj, dim_tags, subseq, subseq_n elif subseq == 1: # Long TE Water Ref reord_data = reord_data[:, :, 0::66] # Long TE Water Refs + meta_obj.set_standard_def('EchoTime', 0.080) # Echo Time meta_obj.set_standard_def('WaterSuppressed', False) # Water Suppression elif subseq == 2: # Short TE PRESS @@ -71,6 +72,7 @@ def smm_svs_herc_hyper(twixObj, reord_data, meta_obj, dim_tags, subseq, subseq_n reord_data = reord_data[:, :, 1:33] # Isolated PRESS elif subseq == 3: # Long TE HERCULES + meta_obj.set_standard_def('EchoTime', 0.080) # Echo Time meta_obj.set_standard_def('WaterSuppressed', True) # Water Suppression reord_mask = np.ones(reord_data.shape[-1], dtype=bool) # Create a Mask From dfd39ebe0415b2e4e9c7e72ff9ca1bb0aa1d3e97 Mon Sep 17 00:00:00 2001 From: Aaron Gudmundson Date: Fri, 4 Aug 2023 15:14:04 -0400 Subject: [PATCH 05/10] Update twix_special_case.py --- spec2nii/Siemens/twix_special_case.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec2nii/Siemens/twix_special_case.py b/spec2nii/Siemens/twix_special_case.py index b9086b3..63ec0cd 100644 --- a/spec2nii/Siemens/twix_special_case.py +++ b/spec2nii/Siemens/twix_special_case.py @@ -105,6 +105,8 @@ def smm_svs_herc_hyper(twixObj, reord_data, meta_obj, dim_tags, subseq, subseq_n dim_tags.insert(len(orig_shape) - 3, 'DIM_EDIT') # Update Dimensions + meta_obj.set_standard_def('TxOffset', 0.0) # Transmitter Frequency + for idx, dt in enumerate(dim_tags): # Iterate Dimensions if dt == 'DIM_EDIT': meta_obj.set_dim_info(idx, dt, dim_info, dim_header) # Set Dimension From d8220c521d3b05600ee7279051a59b88f45db229 Mon Sep 17 00:00:00 2001 From: Aaron Gudmundson Date: Fri, 4 Aug 2023 15:22:35 -0400 Subject: [PATCH 06/10] Update twix_special_case.py --- spec2nii/Siemens/twix_special_case.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec2nii/Siemens/twix_special_case.py b/spec2nii/Siemens/twix_special_case.py index 63ec0cd..31b0ebb 100644 --- a/spec2nii/Siemens/twix_special_case.py +++ b/spec2nii/Siemens/twix_special_case.py @@ -60,20 +60,24 @@ def smm_svs_herc_hyper(twixObj, reord_data, meta_obj, dim_tags, subseq, subseq_n reord_data = reord_data[:, :, 33::66] # Short TE Water Refs meta_obj.set_standard_def('EchoTime', short_TE) # Echo Time meta_obj.set_standard_def('WaterSuppressed', False) # Water Suppression + meta_obj.set_standard_def('TxOffset', 0.0) # Transmitter Frequency elif subseq == 1: # Long TE Water Ref reord_data = reord_data[:, :, 0::66] # Long TE Water Refs meta_obj.set_standard_def('EchoTime', 0.080) # Echo Time meta_obj.set_standard_def('WaterSuppressed', False) # Water Suppression + meta_obj.set_standard_def('TxOffset', 0.0) # Transmitter Frequency elif subseq == 2: # Short TE PRESS meta_obj.set_standard_def('EchoTime', short_TE) # Echo Time meta_obj.set_standard_def('WaterSuppressed', True) # Water Suppression + meta_obj.set_standard_def('TxOffset', -1.7) # Transmitter Frequency reord_data = reord_data[:, :, 1:33] # Isolated PRESS elif subseq == 3: # Long TE HERCULES meta_obj.set_standard_def('EchoTime', 0.080) # Echo Time meta_obj.set_standard_def('WaterSuppressed', True) # Water Suppression + meta_obj.set_standard_def('TxOffset', -1.7) # Transmitter Frequency reord_mask = np.ones(reord_data.shape[-1], dtype=bool) # Create a Mask reord_mask[::33] = False # Remove Water Refs @@ -105,8 +109,6 @@ def smm_svs_herc_hyper(twixObj, reord_data, meta_obj, dim_tags, subseq, subseq_n dim_tags.insert(len(orig_shape) - 3, 'DIM_EDIT') # Update Dimensions - meta_obj.set_standard_def('TxOffset', 0.0) # Transmitter Frequency - for idx, dt in enumerate(dim_tags): # Iterate Dimensions if dt == 'DIM_EDIT': meta_obj.set_dim_info(idx, dt, dim_info, dim_header) # Set Dimension From 92956f242d9219e40185627c358793e10c22dddd Mon Sep 17 00:00:00 2001 From: Aaron Gudmundson Date: Wed, 22 May 2024 13:02:54 -0400 Subject: [PATCH 07/10] GE ISTHMUS/Hyper Sequence Adding functionality to handle GE ISTHMUS/Hyper data. A new custom (_process_hbcd) function for handling the data has been added to the ge_pfile.py. I've also included version 30.x into the get_hdr_fields.py. --- spec2nii/GE/ge_hdr_fields.py | 2 +- spec2nii/GE/ge_pfile.py | 146 ++++++++++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 2 deletions(-) diff --git a/spec2nii/GE/ge_hdr_fields.py b/spec2nii/GE/ge_hdr_fields.py index 7f109ed..89365c2 100644 --- a/spec2nii/GE/ge_hdr_fields.py +++ b/spec2nii/GE/ge_hdr_fields.py @@ -2303,7 +2303,7 @@ def get_pfile_hdr_fields(version): plist.append(('pad_xx', ct.c_char * 51)) plist.append(('rhi_image_uid', ct.c_char * 32)) - elif version_major in (26, 27, 28): + elif version_major in (26, 27, 28, 30): plist.append(('rhr_rh_rdbm_rev', ct.c_float)) plist.append(('rhr_rdb_hdr_off_data', ct.c_int)) plist.append(('pad_xx', ct.c_char * 84)) diff --git a/spec2nii/GE/ge_pfile.py b/spec2nii/GE/ge_pfile.py index e9b5d20..8cefa43 100644 --- a/spec2nii/GE/ge_pfile.py +++ b/spec2nii/GE/ge_pfile.py @@ -97,12 +97,14 @@ def _process_svs_pfile(pfile): data, meta, dwelltime, fname_suffix = _process_oslaser(pfile) elif psd in ('slaser'): data, meta, dwelltime, fname_suffix = _process_slaser(pfile) - elif psd in ['gaba', 'hbcd']: + elif psd in ['gaba']: data, meta, dwelltime, fname_suffix = _process_gaba(pfile) elif 'jpress_ac' in psd: # Bergen patch data, meta, dwelltime, fname_suffix = _process_gaba(pfile) elif psd == 'jpress': data, meta, dwelltime, fname_suffix = _process_gaba(pfile) + elif psd in ['hbcd']: # ATG + data, meta, dwelltime, fname_suffix = _process_hbcd(pfile) # ATG else: raise UnsupportedPulseSequenceError(f'Unrecognised sequence {psd}.') @@ -230,6 +232,148 @@ def _process_gaba(pfile): return [metab, water], [meta, meta_ref], dwelltime, ['', '_ref'] +def _process_hbcd(pfile): + """ + Input: + Pfile Object + + Output: + List of NumPy Data Arrays + List of File Name Suffixes + + Details: + Hyper/ISTHMUS Sequence + + The Integrated Short-TE and Hadamard-edited Multi-Sequence (ISTHMUS) + incorporates a Short TE (35ms) PRESS, Long-TE (80ms) HERCULES, and + a water reference for each. + + Data is organized within the file as follows: + ( 1) Long TE Reference : 80ms Unsupressed Water + (32) Long TE Edited : 80ms Water Suppressed HERCULES + ( 1) Short TE Reference : 35ms Unsupressed Water + (32) Short TE Unedited : 35ms Water Suppressed PRESS + ( 1) Long TE Reference : 80ms Unsupressed Water + (32) Short TE Unedited : 35ms Water Suppressed PRESS + ( 1) Short TE Reference : 35ms Unsupressed Water + (32) Short TE Unedited : 35ms Water Suppressed PRESS + ( 1) Long TE Reference : 80ms Unsupressed Water + (32) Short TE Unedited : 35ms Water Suppressed PRESS + ( 1) Short TE Reference : 35ms Unsupressed Water + (32) Short TE Unedited : 35ms Water Suppressed PRESS + ( 1) Long TE Reference : 80ms Unsupressed Water + (32) Short TE Unedited : 35ms Water Suppressed PRESS + ( 1) Short TE Reference : 35ms Unsupressed Water + (32) Short TE Unedited : 35ms Water Suppressed PRESS + + Data is directly separated from the raw data (pfile.map.raw_data) where the data + mapper (GABA mapper) is simply used to populate in the raw data. + + Author : Aaron Gudmundson, Johns Hopkins University, 2024 + Contact: agudmun2@jhmi.edu + """ + + ## Additional Imports + import copy + + ## Editing Parameters + edit_cases = 4 # 4 Editing Conditions + edit_pulse_1 = 4.58 # 4.58 ppm + edit_pulse_2 = 1.90 # 1.90 ppm + edit_pulse_4 = 4.18 # 4.18 ppm + pulse_length = 0.02 # Edit Pulse 20 ms + + dim_header = {'EditCondition': ['A', 'B', 'C', 'D']} # 4 Subscans + edit_pulse_val = {'A': {'PulseOffset': [edit_pulse_1, edit_pulse_2], 'PulseDuration': pulse_length}, + 'B': {'PulseOffset': [edit_pulse_4, edit_pulse_2], 'PulseDuration': pulse_length}, + 'C': {'PulseOffset': edit_pulse_1,'PulseDuration': pulse_length}, + 'D': {'PulseOffset': edit_pulse_4,'PulseDuration': pulse_length}} + + + ## All Data (Skip 1st Transient - GE automatically has historically included a 'noise' transient) + raw_data = pfile.map.raw_data[:,:,:,:,1:,:] # Raw Data from Mapper + + + ## Long TE HERCULES Metabolite Data + lTE_metab = copy.deepcopy(raw_data) # Long TE Metab + lTE_mask = np.ones(lTE_metab.shape[4], dtype=bool) # Create a Mask + lTE_mask[::33] = False # Remove Water Refs + lTE_mask[: 33] = False # Remove PRESS + lTE_metab = lTE_metab[:,:,:,:,lTE_mask,:] # Isolated HERCULES + + # Handle Incomplete + if lTE_mask.shape[-1] % 4 != 0: # Incomplete Acquisition + old_num_avgs = lTE_mask.shape[-1] # Old Total Averages + new_num_avgs = (lTE_mask.shape[-1] // 4) * 4 # New Total Averages + lTE_metab = lTE_metab[:,:,:,:, :new_num_avgs,:] # Remove Incomplete + + notestring = f'{subseq:3d} {subseq_name:<20}' # Note Incomplete Data + notestring = f'{notestring} - Correcting - Incomplete Averages' # Note Incomplete Data + notestring = f'{notestring} {old_num_avgs} --> {new_num_avgs}' # Note Incomplete Data + print(f'{notestring} \t Corrected**') # Note Incomplete Data + + bef_shape = list(lTE_metab.shape) # Remove Averages Dim + bef_shape[4] = bef_shape[4]//4 # Closest multiple of 4 + bef_shape.append(edit_cases) # Include Subscans + lTE_metab = lTE_metab.reshape(bef_shape) # With Subscan Dim + + + lTE_metab_meta = _populate_metadata(pfile, water_suppressed=True) # Acquisition Information + lTE_metab_meta.set_standard_def('EchoTime', 0.080) # TE + lTE_metab_meta.set_standard_def('WaterSuppressed', True) # Water Suppression + lTE_metab_meta.set_standard_def('EditPulse', edit_pulse_val) # Header Edit Info + + lTE_metab_meta.set_dim_info(0, 'DIM_DYN') # Dimension Info + lTE_metab_meta.set_dim_info(1, 'DIM_COIL') # Dimension Info + lTE_metab_meta.set_dim_info(2, 'DIM_EDIT') # Dimension Info + + + ## Short TE HERCULES Metabolite Data + sTE_metab = copy.deepcopy(raw_data[:,:,:,:,1:33,:]) + + sTE_metab_meta = _populate_metadata(pfile, water_suppressed=True) # Acquisition Information + sTE_metab_meta.set_standard_def('EchoTime', 0.035) # TE + sTE_metab_meta.set_standard_def('WaterSuppressed', True) # Water Suppression + + sTE_metab_meta.set_dim_info(0, 'DIM_DYN') # Dimension Info + sTE_metab_meta.set_dim_info(1, 'DIM_COIL') # Dimension Info + + + ## Long TE Reference Water Data + lTE_water = copy.deepcopy(raw_data[:,:,:,:,0::66,:]) + + lTE_water_meta = _populate_metadata(pfile, water_suppressed=False) # Acquisition Information + lTE_water_meta.set_standard_def('EchoTime', 0.080) # TE + lTE_water_meta.set_standard_def('WaterSuppressed', False) # Water Suppression + + lTE_water_meta.set_dim_info(0, 'DIM_DYN') # Dimension Info + lTE_water_meta.set_dim_info(1, 'DIM_COIL') # Dimension Info + + + ## Short TE Reference Water Data + sTE_water = copy.deepcopy(raw_data[:,:,:,:,33::66,:]) + + sTE_water_meta = _populate_metadata(pfile, water_suppressed=False) # Acquisition Information + sTE_water_meta.set_standard_def('EchoTime', 0.035) # TE + sTE_water_meta.set_standard_def('WaterSuppressed', False) # Water Suppression + + sTE_water_meta.set_dim_info(0, 'DIM_DYN') # Dimension Info + sTE_water_meta.set_dim_info(1, 'DIM_COIL') # Dimension Info + + ## Dwell Time + dwelltime = 1 / pfile.hdr.rhr_spectral_width + + data = [lTE_metab, sTE_metab, lTE_water, sTE_water] # ISTHMUS Data + meta = [lTE_metab_meta, sTE_metab_meta, lTE_water_meta, sTE_water_meta] # ISTHMUS Header + ref_names = ['_edited', '_short_te', '_ref_edited', '_ref_short_te'] # ISTHMUS Naming + + print('Returning ISTHMUS Data:') + for ii in range(len(data)): + print(' {:02d} {:<14} '.format(ii, ref_names[ii]), data[ii].shape) + print(' ') + + return data, meta, dwelltime, ref_names + def _process_mrsi_pfile(pfile): '''Handle MRSI data From fa2f60b215dab4ba36d6fd56cc3f501358f4afda Mon Sep 17 00:00:00 2001 From: William T Clarke Date: Thu, 27 Jun 2024 14:25:29 +0100 Subject: [PATCH 08/10] Update ge_hdr_fields.py Remove added line --- spec2nii/GE/ge_hdr_fields.py | 1 - 1 file changed, 1 deletion(-) diff --git a/spec2nii/GE/ge_hdr_fields.py b/spec2nii/GE/ge_hdr_fields.py index 5b64f66..ec24d08 100644 --- a/spec2nii/GE/ge_hdr_fields.py +++ b/spec2nii/GE/ge_hdr_fields.py @@ -2321,7 +2321,6 @@ def get_pfile_hdr_fields(version): plist.append(('pad_xx', ct.c_char * 51)) plist.append(('rhi_image_uid', ct.c_char * 32)) - elif version_major in (26, 27, 28, 29, 30): plist.append(('rhr_rh_rdbm_rev', ct.c_float)) plist.append(('rhr_rdb_hdr_off_data', ct.c_int)) From 7d9155ae961e51e374075b3c8ea632f3ef83b8c8 Mon Sep 17 00:00:00 2001 From: wtclarke Date: Thu, 27 Jun 2024 14:42:40 +0100 Subject: [PATCH 09/10] Fix linting, line 349 still has undefined variables on. --- spec2nii/GE/ge_pfile.py | 51 +++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/spec2nii/GE/ge_pfile.py b/spec2nii/GE/ge_pfile.py index 2e3aa1a..557d5e0 100644 --- a/spec2nii/GE/ge_pfile.py +++ b/spec2nii/GE/ge_pfile.py @@ -308,16 +308,16 @@ def _process_hbcd(pfile): (32) Short TE Unedited : 35ms Water Suppressed PRESS Data is directly separated from the raw data (pfile.map.raw_data) where the data - mapper (GABA mapper) is simply used to populate in the raw data. + mapper (GABA mapper) is simply used to populate in the raw data. Author : Aaron Gudmundson, Johns Hopkins University, 2024 Contact: agudmun2@jhmi.edu """ - ## Additional Imports + # Additional Imports import copy - ## Editing Parameters + # Editing Parameters edit_cases = 4 # 4 Editing Conditions edit_pulse_1 = 4.58 # 4.58 ppm edit_pulse_2 = 1.90 # 1.90 ppm @@ -327,26 +327,24 @@ def _process_hbcd(pfile): dim_header = {'EditCondition': ['A', 'B', 'C', 'D']} # 4 Subscans edit_pulse_val = {'A': {'PulseOffset': [edit_pulse_1, edit_pulse_2], 'PulseDuration': pulse_length}, 'B': {'PulseOffset': [edit_pulse_4, edit_pulse_2], 'PulseDuration': pulse_length}, - 'C': {'PulseOffset': edit_pulse_1,'PulseDuration': pulse_length}, - 'D': {'PulseOffset': edit_pulse_4,'PulseDuration': pulse_length}} + 'C': {'PulseOffset': edit_pulse_1, 'PulseDuration': pulse_length}, + 'D': {'PulseOffset': edit_pulse_4, 'PulseDuration': pulse_length}} + # All Data (Skip 1st Transient - GE automatically has historically included a 'noise' transient) + raw_data = pfile.map.raw_data[:, :, :, :, 1:, :] # Raw Data from Mapper - ## All Data (Skip 1st Transient - GE automatically has historically included a 'noise' transient) - raw_data = pfile.map.raw_data[:,:,:,:,1:,:] # Raw Data from Mapper - - - ## Long TE HERCULES Metabolite Data + # Long TE HERCULES Metabolite Data lTE_metab = copy.deepcopy(raw_data) # Long TE Metab lTE_mask = np.ones(lTE_metab.shape[4], dtype=bool) # Create a Mask lTE_mask[::33] = False # Remove Water Refs lTE_mask[: 33] = False # Remove PRESS - lTE_metab = lTE_metab[:,:,:,:,lTE_mask,:] # Isolated HERCULES - - # Handle Incomplete + lTE_metab = lTE_metab[:, :, :, :, lTE_mask, :] # Isolated HERCULES + + # Handle Incomplete if lTE_mask.shape[-1] % 4 != 0: # Incomplete Acquisition old_num_avgs = lTE_mask.shape[-1] # Old Total Averages new_num_avgs = (lTE_mask.shape[-1] // 4) * 4 # New Total Averages - lTE_metab = lTE_metab[:,:,:,:, :new_num_avgs,:] # Remove Incomplete + lTE_metab = lTE_metab[:, :, :, :, :new_num_avgs, :] # Remove Incomplete notestring = f'{subseq:3d} {subseq_name:<20}' # Note Incomplete Data notestring = f'{notestring} - Correcting - Incomplete Averages' # Note Incomplete Data @@ -354,11 +352,10 @@ def _process_hbcd(pfile): print(f'{notestring} \t Corrected**') # Note Incomplete Data bef_shape = list(lTE_metab.shape) # Remove Averages Dim - bef_shape[4] = bef_shape[4]//4 # Closest multiple of 4 + bef_shape[4] = bef_shape[4] // 4 # Closest multiple of 4 bef_shape.append(edit_cases) # Include Subscans lTE_metab = lTE_metab.reshape(bef_shape) # With Subscan Dim - lTE_metab_meta = _populate_metadata(pfile, water_suppressed=True) # Acquisition Information lTE_metab_meta.set_standard_def('EchoTime', 0.080) # TE lTE_metab_meta.set_standard_def('WaterSuppressed', True) # Water Suppression @@ -366,12 +363,11 @@ def _process_hbcd(pfile): lTE_metab_meta.set_dim_info(0, 'DIM_DYN') # Dimension Info lTE_metab_meta.set_dim_info(1, 'DIM_COIL') # Dimension Info - lTE_metab_meta.set_dim_info(2, 'DIM_EDIT') # Dimension Info + lTE_metab_meta.set_dim_info(2, 'DIM_EDIT', hdr=dim_header) # Dimension Info + # Short TE HERCULES Metabolite Data + sTE_metab = copy.deepcopy(raw_data[:, :, :, :, 1:33, :]) - ## Short TE HERCULES Metabolite Data - sTE_metab = copy.deepcopy(raw_data[:,:,:,:,1:33,:]) - sTE_metab_meta = _populate_metadata(pfile, water_suppressed=True) # Acquisition Information sTE_metab_meta.set_standard_def('EchoTime', 0.035) # TE sTE_metab_meta.set_standard_def('WaterSuppressed', True) # Water Suppression @@ -379,21 +375,19 @@ def _process_hbcd(pfile): sTE_metab_meta.set_dim_info(0, 'DIM_DYN') # Dimension Info sTE_metab_meta.set_dim_info(1, 'DIM_COIL') # Dimension Info + # Long TE Reference Water Data + lTE_water = copy.deepcopy(raw_data[:, :, :, :, 0::66, :]) - ## Long TE Reference Water Data - lTE_water = copy.deepcopy(raw_data[:,:,:,:,0::66,:]) - lTE_water_meta = _populate_metadata(pfile, water_suppressed=False) # Acquisition Information lTE_water_meta.set_standard_def('EchoTime', 0.080) # TE lTE_water_meta.set_standard_def('WaterSuppressed', False) # Water Suppression - + lTE_water_meta.set_dim_info(0, 'DIM_DYN') # Dimension Info lTE_water_meta.set_dim_info(1, 'DIM_COIL') # Dimension Info + # Short TE Reference Water Data + sTE_water = copy.deepcopy(raw_data[:, :, :, :, 33::66, :]) - ## Short TE Reference Water Data - sTE_water = copy.deepcopy(raw_data[:,:,:,:,33::66,:]) - sTE_water_meta = _populate_metadata(pfile, water_suppressed=False) # Acquisition Information sTE_water_meta.set_standard_def('EchoTime', 0.035) # TE sTE_water_meta.set_standard_def('WaterSuppressed', False) # Water Suppression @@ -401,7 +395,7 @@ def _process_hbcd(pfile): sTE_water_meta.set_dim_info(0, 'DIM_DYN') # Dimension Info sTE_water_meta.set_dim_info(1, 'DIM_COIL') # Dimension Info - ## Dwell Time + # Dwell Time dwelltime = 1 / pfile.hdr.rhr_spectral_width data = [lTE_metab, sTE_metab, lTE_water, sTE_water] # ISTHMUS Data @@ -415,6 +409,7 @@ def _process_hbcd(pfile): return data, meta, dwelltime, ref_names + def _process_mrsi_pfile(pfile): """Handle MRSI data From a320f50292a53ef94c49b738c11377c788c6d9f6 Mon Sep 17 00:00:00 2001 From: wtclarke Date: Thu, 27 Jun 2024 14:58:02 +0100 Subject: [PATCH 10/10] Fix up leftover strings from twix special handling --- spec2nii/GE/ge_pfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec2nii/GE/ge_pfile.py b/spec2nii/GE/ge_pfile.py index 557d5e0..04ab448 100644 --- a/spec2nii/GE/ge_pfile.py +++ b/spec2nii/GE/ge_pfile.py @@ -346,7 +346,7 @@ def _process_hbcd(pfile): new_num_avgs = (lTE_mask.shape[-1] // 4) * 4 # New Total Averages lTE_metab = lTE_metab[:, :, :, :, :new_num_avgs, :] # Remove Incomplete - notestring = f'{subseq:3d} {subseq_name:<20}' # Note Incomplete Data + notestring = '80ms HERCULES' # Note Incomplete Data notestring = f'{notestring} - Correcting - Incomplete Averages' # Note Incomplete Data notestring = f'{notestring} {old_num_avgs} --> {new_num_avgs}' # Note Incomplete Data print(f'{notestring} \t Corrected**') # Note Incomplete Data