2121import subprocess
2222from typing import Optional , TYPE_CHECKING
2323
24+ import nibabel as nib
25+
2426from CPAC .func_preproc .func_motion import motion_estimate_filter
2527from CPAC .utils .bids_utils import insert_entity
28+ from CPAC .utils .monitoring import IFLOGGER
2629
2730if TYPE_CHECKING :
2831 from CPAC .pipeline .nodeblock import POOL_RESOURCE_MAPPING
@@ -44,6 +47,131 @@ def get_shell() -> str:
4447 return shell
4548
4649
50+ def find_pixdim4 (file_path ):
51+ """Find the pixdim4 value of a NIfTI file.
52+
53+ Parameters
54+ ----------
55+ file_path : str
56+ Path to the NIfTI file.
57+
58+ Returns
59+ -------
60+ float
61+ The pixdim4 value of the NIfTI file.
62+
63+ Raises
64+ ------
65+ FileNotFoundError
66+ If the file does not exist.
67+ nibabel.filebasedimages.ImageFileError
68+ If there is an error loading the NIfTI file.
69+ IndexError
70+ If pixdim4 is not found in the header.
71+ """
72+ if not os .path .isfile (file_path ):
73+ error_message = f"File not found: { file_path } "
74+ raise FileNotFoundError (file_path )
75+
76+ try :
77+ nii = nib .load (file_path )
78+ header = nii .header
79+ pixdim = header .get_zooms ()
80+ return pixdim [3 ]
81+ except nib .filebasedimages .ImageFileError as e :
82+ error_message = f"Error loading the NIfTI file: { e } "
83+ raise nib .filebasedimages .ImageFileError (error_message )
84+ except IndexError as e :
85+ error_message = f"pixdim4 not found in the header: { e } "
86+ raise IndexError (error_message )
87+
88+
89+ def update_pixdim4 (file_path , new_pixdim4 ):
90+ """Update the pixdim4 value of a NIfTI file using 3drefit.
91+
92+ Parameters
93+ ----------
94+ file_path : str
95+ Path to the NIfTI file.
96+ new_pixdim4 : float
97+ New pixdim4 value to update the NIfTI file with.
98+
99+ Raises
100+ ------
101+ FileNotFoundError
102+ If the file does not exist.
103+ subprocess.CalledProcessError
104+ If there is an error running the subprocess.
105+
106+ Notes
107+ -----
108+ The pixdim4 value is the Repetition Time (TR) of the NIfTI file.
109+
110+ """
111+ if not os .path .isfile (file_path ):
112+ error_message = f"File not found: { file_path } "
113+ raise FileNotFoundError (error_message )
114+
115+ # Print the current pixdim4 value for verification
116+ IFLOGGER .info (f"Updating { file_path } with new pixdim[4] value: { new_pixdim4 } " )
117+
118+ # Construct the command to update the pixdim4 value using 3drefit
119+ command = ["3drefit" , "-TR" , str (new_pixdim4 ), file_path ]
120+
121+ try :
122+ subprocess .run (command , check = True )
123+ IFLOGGER .info (f"Successfully updated TR to { new_pixdim4 } seconds." )
124+ except subprocess .CalledProcessError as e :
125+ error_message = f"Error occurred while updating the file: { e } "
126+ raise subprocess .CalledProcessError (error_message )
127+
128+
129+ def validate_outputs (input_bold , RawSource_bold ):
130+ """Match pixdim4/TR of the input_bold with RawSource_bold.
131+
132+ Parameters
133+ ----------
134+ input_bold : str
135+ Path to the input BOLD file.
136+ RawSource_bold : str
137+ Path to the RawSource BOLD file.
138+
139+ Returns
140+ -------
141+ output_bold : str
142+ Path to the output BOLD file.
143+
144+ Raises
145+ ------
146+ Exception
147+ If there is an error in finding or updating pixdim4.
148+ """
149+ try :
150+ output_bold = input_bold
151+ output_pixdim4 = find_pixdim4 (output_bold )
152+ source_pixdim4 = find_pixdim4 (RawSource_bold )
153+
154+ if output_pixdim4 != source_pixdim4 :
155+ IFLOGGER .info (
156+ "TR mismatch detected between output_bold and RawSource_bold."
157+ )
158+ IFLOGGER .info (f"output_bold TR: { output_pixdim4 } seconds" )
159+ IFLOGGER .info (f"RawSource_bold TR: { source_pixdim4 } seconds" )
160+ IFLOGGER .info (
161+ "Attempting to update the TR of output_bold to match RawSource_bold."
162+ )
163+ update_pixdim4 (output_bold , source_pixdim4 )
164+ else :
165+ IFLOGGER .debug ("TR match detected between output_bold and RawSource_bold." )
166+ IFLOGGER .debug (f"output_bold TR: { output_pixdim4 } seconds" )
167+ IFLOGGER .debug (f"RawSource_bold TR: { source_pixdim4 } seconds" )
168+ return output_bold
169+ except Exception as e :
170+ error_message = f"Error in validating outputs: { e } "
171+ IFLOGGER .error (error_message )
172+ return output_bold
173+
174+
47175def name_fork (resource_idx , cfg , json_info , out_dct ):
48176 """Create and insert entities for forkpoints.
49177
0 commit comments