Total Readout Time Not Defined

Summary of what happened:

I have one magnitude and one phasediff image. The images appear to be detected but are not applied to the EPI images (error in unwarp_wf). I’ve referenced these images in the “IntendedFor” field in both the magnitude and phasediff JSON files. My understanding is that no further fields need to be added with the newer versions of fMRIPREP.

Any advice on how to get unwarping of the EPI images to work?

Command used (and if a helper script was used, a link to the helper script or the command generated):

singularity run --cleanenv /u/project/CCN/apps/fmriprep/rh7/23.1.3/23.1.3-fmriprep.sif /u/project/data/mri/crave/BIDS /u/project/data/mri/crave/BIDS/derivatives --skip_bids_validation --fs-subjects-dir /u/project/data/mri/crave/BIDS/derivatives/freesurfer --participant_label sub-102 -t label -w /u/project/data/mri/crave/tmp_fmriprep --output-spaces MNI152NLin2009cAsym func --nthreads 4 --omp-nthreads 4 --mem-mb 32000 --fs-license-file /u/project/CCN/apps/freesurfer/rh7/7.1.1/license.txt participant

Version:

fMRIPrep-23.1.4

Environment (Docker, Singularity / Apptainer, custom installation):

Singularity

Data formatted according to a validatable standard? Please provide the output of the validator:

bids_validate.py

Relevant log outputs (up to 20 lines):

	 [Node] Setting-up "fmriprep_23_1_wf.single_subject_102_wf.func_preproc_task_label_run_1_wf.unwarp_wf.rotime" in "/u/project/data/mri/crave/tmp_fmriprep/fmriprep_23_1_wf/single_subject_102_wf/func_preproc_task_label_run_1_wf/unwarp_wf/roti
me".
240529-14:40:24,806 nipype.workflow INFO:
	 [Node] Executing "rotime" <sdcflows.interfaces.epi.GetReadoutTime>
240529-14:40:24,816 nipype.workflow INFO:
	 [Node] Finished "rotime", elapsed time 0.009167s.
240529-14:40:24,816 nipype.workflow WARNING:
	 Storing result file without outputs
240529-14:40:24,819 nipype.workflow WARNING:
	 [Node] Error on "fmriprep_23_1_wf.single_subject_102_wf.func_preproc_task_label_run_1_wf.unwarp_wf.rotime" (/u/project/data/mri/crave/tmp_fmriprep/fmriprep_23_1_wf/single_subject_102_wf/func_preproc_task_label_run_1_wf/unwarp_wf/rotime)
240529-14:40:25,620 nipype.workflow INFO:
	 [Node] Finished "bold_split", elapsed time 5.101312s.
240529-14:40:26,352 nipype.workflow ERROR:
	 Node rotime failed to run on host n1965.
240529-14:40:26,641 nipype.workflow ERROR:
	 Saving crash info to /u/project/data/mri/crave/BIDS/derivatives/sub-102/log/20240529-143518_5188c716-c2a9
-49bc-a0b4-c3ed4d547952/crash-20240529-144026-darag-rotime-d1e1f7d8-d1e2-4717-b48d-5d416a0d5d9e.txt
Traceback (most recent call last):
  File "/opt/conda/envs/fmriprep/lib/python3.10/site-packages/nipype/pipeline/plugins/multiproc.py", line 67, in run_node
    result["result"] = node.run(updatehash=updatehash)
  File "/opt/conda/envs/fmriprep/lib/python3.10/site-packages/nipype/pipeline/engine/nodes.py", line 527, in run
    result = self._run_interface(execute=True)
  File "/opt/conda/envs/fmriprep/lib/python3.10/site-packages/nipype/pipeline/engine/nodes.py", line 645, in _run_interface
    return self._run_command(execute)
  File "/opt/conda/envs/fmriprep/lib/python3.10/site-packages/nipype/pipeline/engine/nodes.py", line 771, in _run_command
    raise NodeExecutionError(msg)
nipype.pipeline.engine.nodes.NodeExecutionError: Exception raised while executing Node rotime.

Traceback:
	Traceback (most recent call last):
	  File "/opt/conda/envs/fmriprep/lib/python3.10/site-packages/nipype/interfaces/base/core.py", line 397, in run
	    runtime = self._run_interface(runtime)
	  File "/opt/conda/envs/fmriprep/lib/python3.10/site-packages/sdcflows/interfaces/epi.py", line 57, in _run_interface
	    self._results["readout_time"] = get_trt(
	  File "/opt/conda/envs/fmriprep/lib/python3.10/site-packages/sdcflows/utils/epimanip.py", line 228, in get_trt
	    raise ValueError("Unknown total-readout time specification")
	ValueError: Unknown total-readout time specification

Screenshots / relevant information:


Hi @Darag,

You should return the full output of the validator next time. You can get that by not including --skip-bids-validation.

TotalReadoutTime is probably not defined in your BOLD JSON files. The BIDS validator may indicate that other important metadata is missing as well. If you are using Phillips dicoms I don’t have a good solution besides referring back to your scanner protocol for this value or asking your institution’s MRI technician. Otherwise, using a recent dcm2niix conversion should get the proper metadata from Siemens and GE dicoms.

Best,
Steven

Thanks Steven.

I validate bids separately using bids_validate.py because, when I try to validate within fMRIPREP (i.e., removing --skip-bids-validation), I get a memory error (“JavaScript heap out of memory” - similar to what has been noted here, even when I raise the memory allocation to 36GBs).

As you thought, TotalReadoutTime is not included in the BOLD JSON files and not in the DICOM header. I’m using version 20230411 of dcm2niix (just FYI).

Of note, the data come from an older Siemens scanner (Allegra). Could that be the problem?
I’m not sure we have access to the scanner protocol as the data are quite old. Is it possible to compute TotalReadoutTime from other available scan parameters?

Best, Dara

Hi @Darag,

It would help to see the contents of your BOLD json to see if there is enough information to calculate it manually, for example Total Readout Time=Echo Spacing×(Number of Echoes−1).

Best,
Steven

Hi Steven,

I’m including sample BOLD JSON text below.

We don’t have an Echo Spacing variable in the JSON. Maybe we could use one of the calculations listed here? (JISCMail - FSL Archives):

Effective Echo Spacing (s) = 1/(BandwidthPerPixelPhaseEncode * MatrixSizePhase)

as we have the following:

“PixelBandwidth”: 2695
“ReconMatrixPE”: 64,

Thanks, Dara

{
    "InPlanePhaseEncodingDirectionDICOM": "COL", 
    "ProcedureStepDescription": "Routine", 
    "DeviceSerialNumber": "20411", 
    "AcquisitionMatrixPE": 64, 
    "NonlinearGradientCorrection": false, 
    "ImageOrientationPatientDICOM": [
        1, 
        0, 
        2.77556e-17, 
        0, 
        0.884581, 
        -0.466387
    ], 
    "ManufacturersModelName": "Allegra", 
    "ProtocolName": "ep2d_bold_label1", 
    "PhaseEncodingDirection": "j", 
    "RepetitionTime": 2, 
    "SeriesNumber": 13, 
    "PhaseEncodingSteps": 64, 
    "MRAcquisitionType": "2D", 
    "CoilString": "HE", 
    "SliceThickness": 3.2, 
    "AcquisitionNumber": 1, 
    "InstitutionName": "X", 
    "ConversionSoftware": "dcm2niix", 
    "TxRefAmp": 150.286, 
    "SAR": 0.0435412, 
    "PulseSequenceDetails": "%SiemensSeq%\\ep2d_bold", 
    "ScanningSequence": "EP\\SE\\EP", 
    "Manufacturer": "Siemens", 
    "MatrixCoilMode": "SENSE", 
    "PercentPhaseFOV": 100, 
    "ReconMatrixPE": 64, 
    "FlipAngle": 79, 
    "ConversionSoftwareVersion": "v1.0.20230411", 
    "SeriesDescription": "ep2d_bold_label1", 
    "PartialFourier": 1, 
    "InstitutionAddress": "US", 
    "ShimSetting": [
        -33, 
        -42, 
        79, 
        467, 
        392, 
        263, 
        94, 
        286
    ], 
    "PatientPosition": "HFS", 
    "SequenceName": "*epfid2d1_64", 
    "MagneticFieldStrength": 3, 
    "TaskName": "label", 
    "PercentSampling": 100, 
    "SpacingBetweenSlices": 3.2, 
    "ImageType": [
        "ORIGINAL", 
        "PRIMARY", 
        "M", 
        "ND", 
        "MOSAIC"
    ], 
    "ReceiveCoilName": "Head_3T", 
    "EchoTime": 0.028, 
    "SequenceVariant": "SK", 
    "SliceTiming": [
        0, 
        0.0588235, 
        0.117647, 
        0.176471, 
        0.235294, 
        0.294118, 
        0.352941, 
        0.411765, 
        0.470588, 
        0.529412, 
        0.588235, 
        0.647059, 
        0.705882, 
        0.764706, 
        0.823529, 
        0.882353, 
        0.941176, 
        1, 
        1.05882, 
        1.11765, 
        1.17647, 
        1.23529, 
        1.29412, 
        1.35294, 
        1.41176, 
        1.47059, 
        1.52941, 
        1.58824, 
        1.64706, 
        1.70588, 
        1.76471, 
        1.82353, 
        1.88235, 
        1.94118
    ], 
    "ImagingFrequency": 123.255421, 
    "ImageOrientationText": "Tra>Cor(-27.8)", 
    "BaseResolution": 64, 
    "PixelBandwidth": 2695, 
    "ScanOptions": "FS", 
    "PhaseResolution": 1, 
    "SoftwareVersions": "syngo MR A30 4VA30A", 
    "StationName": "MRC", 
    "Modality": "MR", 
    "AcquisitionTime": "18:23:3.967510"
}

Hi @Darag

Maybe you’ll find this thread helpful?: What is the TotalReadoutTime of HCP dwi data?

But an important take away is that as long as the readout times are identical (assuming the acquisition parameters were the same across subjects and scans) and within a reasonable range, you should be good for SDC.

Best,
Steven

Dara,

I notice your data is from Siemens VA30. Siemens started adding in a lot of sequence details with VB11, which I think was released in the year 2005. Therefore, the DICOM images from these devices is impoverished, and this limits what dcm2niix can extract. While the Allegra was a ground breaking scanner for its day, there have been a lot of improvements over the last two decades.

If you do want to use these, take heart that for FSL tools If your readout time is identical for all acquisitions you don't neccessarily have to specify a valid value in this column (you can e.g. just set it to 1), but if you do specify correct values the estimated field will be correctly scaled in Hz, which may be a useful sanity check. Presumably, your readout time is identical across sequences, so just inset a plausible value, e.g. "TotalReadoutTime": 0.018,

You should also be aware that you are trying to remove the geometric distortions in a gradient echo EPI scan. The typical ways to do this are to either:

  • fieldmap method: Acquire a gradient echo fieldmap and use a tool like FUGUE.
  • pepolar method: Acquire a pair of spin echo EPI data with the same slice centers and angulation as your gradient echo EPI and estimate the distortion with a tool like TOPUP, applying the warp fields to your gradient echo data.

As discussed previously the BIDS specification explicitly requires pepolar to be Spin Echo. The issue is that gradient echo has both spatial distortion and signal loss, while the spin-echo should recover the signal (so the image is distorted, but the signal is moved and either compressed or rarefied). While some people do apply TOPUP and similar tools to gradient echo pepolar data, I think you need to be realistic about the performance and visually inspect each dataset.

Thank you Chris and Steven for your help on this, and for your thorough explanation, Chris. Just to followup, after adding TotalReadoutTime to the func json files, the correction was applied without errors, but the results were not very good. In most cases, the corrected image is more distorted than the uncorrected.

I tried automated estimation (using --nofieldmaps and --use-syn-sdc), but this produced very distorted images.

These problems are likely due to the age of the data (older scanner and sequence used).

For now, I will forego any kind of distortion correction.

Thanks again for your help.