-
-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨Feature/update pixdim4 for the final *bold outputs #2154
base: develop
Are you sure you want to change the base?
Changes from all commits
a442aea
e848147
853aad4
b2605bf
615888f
06e72cc
8860e37
d370d88
a778584
c341f2f
d078863
6680c32
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,13 +17,143 @@ | |
"""C-PAC pipeline engine utilities.""" | ||
|
||
from itertools import chain | ||
import os | ||
import subprocess | ||
|
||
import nibabel as nib | ||
|
||
from CPAC.func_preproc.func_motion import motion_estimate_filter | ||
from CPAC.utils.bids_utils import insert_entity | ||
from CPAC.utils.monitoring import IFLOGGER | ||
|
||
MOVEMENT_FILTER_KEYS = motion_estimate_filter.outputs | ||
|
||
|
||
def find_pixdim4(file_path): | ||
"""Find the pixdim4 value of a NIfTI file. | ||
|
||
Parameters | ||
---------- | ||
file_path : str | ||
Path to the NIfTI file. | ||
|
||
Returns | ||
------- | ||
float | ||
The pixdim4 value of the NIfTI file. | ||
|
||
Raises | ||
------ | ||
FileNotFoundError | ||
If the file does not exist. | ||
nibabel.filebasedimages.ImageFileError | ||
If there is an error loading the NIfTI file. | ||
IndexError | ||
If pixdim4 is not found in the header. | ||
""" | ||
if not os.path.isfile(file_path): | ||
error_message = f"File not found: {file_path}" | ||
raise FileNotFoundError(file_path) | ||
|
||
try: | ||
nii = nib.load(file_path) | ||
header = nii.header | ||
pixdim = header.get_zooms() | ||
return pixdim[3] | ||
except nib.filebasedimages.ImageFileError as e: | ||
error_message = f"Error loading the NIfTI file: {e}" | ||
raise nib.filebasedimages.ImageFileError(error_message) | ||
except IndexError as e: | ||
error_message = f"pixdim4 not found in the header: {e}" | ||
raise IndexError(error_message) | ||
|
||
|
||
def update_pixdim4(file_path, new_pixdim4): | ||
"""Update the pixdim4 value of a NIfTI file using 3drefit. | ||
|
||
Parameters | ||
---------- | ||
file_path : str | ||
Path to the NIfTI file. | ||
new_pixdim4 : float | ||
New pixdim4 value to update the NIfTI file with. | ||
|
||
Raises | ||
------ | ||
FileNotFoundError | ||
If the file does not exist. | ||
subprocess.CalledProcessError | ||
If there is an error running the subprocess. | ||
|
||
Notes | ||
----- | ||
The pixdim4 value is the Repetition Time (TR) of the NIfTI file. | ||
|
||
""" | ||
if not os.path.isfile(file_path): | ||
error_message = f"File not found: {file_path}" | ||
raise FileNotFoundError(error_message) | ||
|
||
# Print the current pixdim4 value for verification | ||
IFLOGGER.info(f"Updating {file_path} with new pixdim[4] value: {new_pixdim4}") | ||
|
||
# Construct the command to update the pixdim4 value using 3drefit | ||
command = ["3drefit", "-TR", str(new_pixdim4), file_path] | ||
|
||
try: | ||
subprocess.run(command, check=True) | ||
IFLOGGER.info(f"Successfully updated TR to {new_pixdim4} seconds.") | ||
except subprocess.CalledProcessError as e: | ||
error_message = f"Error occurred while updating the file: {e}" | ||
raise subprocess.CalledProcessError(error_message) | ||
|
||
|
||
def validate_outputs(input_bold, RawSource_bold): | ||
"""Match pixdim4/TR of the input_bold with RawSource_bold. | ||
|
||
Parameters | ||
---------- | ||
input_bold : str | ||
Path to the input BOLD file. | ||
RawSource_bold : str | ||
Path to the RawSource BOLD file. | ||
|
||
Returns | ||
------- | ||
output_bold : str | ||
Path to the output BOLD file. | ||
|
||
Raises | ||
------ | ||
Exception | ||
If there is an error in finding or updating pixdim4. | ||
""" | ||
try: | ||
output_bold = input_bold | ||
output_pixdim4 = find_pixdim4(output_bold) | ||
source_pixdim4 = find_pixdim4(RawSource_bold) | ||
|
||
if output_pixdim4 != source_pixdim4: | ||
IFLOGGER.info( | ||
"TR mismatch detected between output_bold and RawSource_bold." | ||
) | ||
IFLOGGER.info(f"output_bold TR: {output_pixdim4} seconds") | ||
IFLOGGER.info(f"RawSource_bold TR: {source_pixdim4} seconds") | ||
IFLOGGER.info( | ||
"Attempting to update the TR of output_bold to match RawSource_bold." | ||
) | ||
update_pixdim4(output_bold, source_pixdim4) | ||
else: | ||
IFLOGGER.debug("TR match detected between output_bold and RawSource_bold.") | ||
IFLOGGER.debug(f"output_bold TR: {output_pixdim4} seconds") | ||
IFLOGGER.debug(f"RawSource_bold TR: {source_pixdim4} seconds") | ||
return output_bold | ||
except Exception as e: | ||
error_message = f"Error in validating outputs: {e}" | ||
IFLOGGER.error(error_message) | ||
return output_bold | ||
Comment on lines
+152
to
+154
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to raise an exception here instead of (log an error message and return the path to the bold file)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, I am not sure if we want to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. or probably add a swtich to the config to allow choosing between
|
||
|
||
|
||
def name_fork(resource_idx, cfg, json_info, out_dct): | ||
"""Create and insert entities for forkpoints. | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have to worry about
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure about this one. May be @sgiavasis could advise on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason to use AFNI
3drefit
instead ofnibabel
is to change theTime step
in3dinfo
as well along withpixdim4