Skip to content

Commit

Permalink
make a json for the merged dwis
Browse files Browse the repository at this point in the history
  • Loading branch information
mattcieslak committed Mar 4, 2024
1 parent a29109d commit a783eff
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 2 deletions.
24 changes: 23 additions & 1 deletion qsiprep/interfaces/dwi_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,15 @@ class MergeDWIsInputSpec(BaseInterfaceInputSpec):
carpetplot_data = InputMultiObject(
File(exists=True), mandatory=False, desc="list of carpetplot_data files"
)
scan_metadata = traits.Dict(desc="Dict of metadata for the to-be-combined scans")


class MergeDWIsOutputSpec(TraitedSpec):
out_dwi = File(desc="the merged dwi image")
out_bval = File(desc="the merged bval file")
out_bvec = File(desc="the merged bvec file")
original_images = traits.List()
merged_metadata = traits.Dict()
merged_metadata = File(exists=True)
merged_denoising_confounds = File(exists=True)
merged_b0_ref = File(exists=True)
merged_raw_dwi = File(exists=True, mandatory=False)
Expand All @@ -79,6 +80,17 @@ def _run_interface(self, runtime):
self.inputs.harmonize_b0_intensities,
)

# Create a merged metadata json file for
if isdefined(self.inputs.scan_metadata):
combined_metadata = combine_metadata(
self.inputs.dwi_files,
self.inputs.scan_metadata,
)
merged_metadata_file = op.join(runtime.cwd, "merged_metadata.json")
with open(merged_metadata_file, "w") as merged_meta_f:
json.dump(combined_metadata, merged_meta_f, indent=4)
self._results["merged_metadata"] = merged_metadata_file

# Get basic qc / provenance per volume
provenance_df = create_provenance_dataframe(
self.inputs.bids_dwi_files, to_concat, b0_means, corrections
Expand Down Expand Up @@ -151,6 +163,16 @@ def _run_interface(self, runtime):
return runtime


def combine_metadata(scan_list, metadata_dict):
"""Create a merged metadata dictionary.
Most importantly, combine the slice timings in some way. Here the slice
metadata is taken from the first scan.
"""
return metadata_dict[scan_list[0]]


class AveragePEPairsInputSpec(MergeDWIsInputSpec):
original_bvec_files = InputMultiObject(
File(exists=True), mandatory=True, desc="list of original bvec files"
Expand Down
24 changes: 24 additions & 0 deletions qsiprep/interfaces/eddy.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""
import os
import os.path as op
import json

import nibabel as nb
import numpy as np
Expand Down Expand Up @@ -45,6 +46,8 @@ class GatherEddyInputsInputSpec(BaseInterfaceInputSpec):
topup_max_b0s_per_spec = traits.CInt(1, usedefault=True)
topup_requested = traits.Bool(False, usedefault=True)
raw_image_sdc = traits.Bool(True, usedefault=True)
eddy_config = File(exists=True, mandatory=True)
json_file = File(exists=True)


class GatherEddyInputsOutputSpec(TraitedSpec):
Expand All @@ -60,6 +63,8 @@ class GatherEddyInputsOutputSpec(TraitedSpec):
forward_transforms = traits.List()
forward_warps = traits.List()
topup_report = traits.Str(desc="description of where data came from")
json_file = File(exists=True)
multiband_factor = traits.Int()


class GatherEddyInputs(SimpleInterface):
Expand Down Expand Up @@ -125,6 +130,21 @@ def _run_interface(self, runtime):
# these have already had HMC, SDC applied
self._results["forward_transforms"] = []
self._results["forward_warps"] = []

# Based on the eddy config, determine whether to send a json argument
with open(self.inputs.eddy_config, "r") as eddy_cfg_f:
eddy_config = json.load(eddy_cfg_f)
# json file is only allowed if mporder is defined
if "mporder" in eddy_config:
self._results["json_file"] = self.inputs.json_file

# Get the multiband factor from the json file and convert it to an arg
if isdefined(self.inputs.json_file):
with open(self.inputs.json_file) as json_f:
input_sidecar = json.load(json_f)
if "MultibandAccelerationFactor" in input_sidecar:
self._results["multiband_factor"] = input_sidecar["MultibandAccelerationFactor"]

return runtime


Expand Down Expand Up @@ -241,6 +261,10 @@ def _format_arg(self, name, spec, value):
if name == "field":
pth, fname, _ = split_filename(value)
return spec.argstr % op.join(pth, fname)
if name == "json":
if isdefined(self.inputs.mporder):
return spec.argstr % value
return ""
return super(ExtendedEddy, self)._format_arg(name, spec, value)


Expand Down
1 change: 1 addition & 0 deletions qsiprep/workflows/dwi/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ def init_dwi_preproc_wf(
('outputnode.dwi_file', 'inputnode.dwi_file'),
('outputnode.bval_file', 'inputnode.bval_file'),
('outputnode.bvec_file', 'inputnode.bvec_file'),
('outputnode.json_file', 'inputnode.json_file'),
('outputnode.original_files', 'inputnode.original_files')]),
(inputnode, hmc_wf, [
('t1_brain', 'inputnode.t1_brain'),
Expand Down
7 changes: 6 additions & 1 deletion qsiprep/workflows/dwi/fsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ def init_fsl_hmc_wf(
bvec file
bval_file: str
bval file
json_file: str
path to sidecar json file for dwi_file
b0_indices: list
Indexes into ``dwi_files`` that correspond to b=0 volumes
b0_images: list
Expand All @@ -116,6 +118,7 @@ def init_fsl_hmc_wf(
"dwi_file",
"bvec_file",
"bval_file",
"json_file",
"b0_indices",
"b0_images",
"original_files",
Expand Down Expand Up @@ -224,7 +227,9 @@ def init_fsl_hmc_wf(
('outputnode.ref_image_brain', 'dwi_file')]),
(gather_inputs, eddy, [
('eddy_indices', 'in_index'),
('eddy_acqp', 'in_acqp')]),
('eddy_acqp', 'in_acqp'),
('json_file', 'json'),
('multiband_factor', 'multiband_factor')]),
(inputnode, eddy, [
('dwi_file', 'in_file'),
('bval_file', 'in_bval'),
Expand Down
1 change: 1 addition & 0 deletions qsiprep/workflows/dwi/hmc_sdc.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def init_qsiprep_hmcsdc_wf(
"dwi_file",
"bvec_file",
"bval_file",
"json_file",
"rpe_b0",
"t2w_unfatsat",
"original_files",
Expand Down
6 changes: 6 additions & 0 deletions qsiprep/workflows/dwi/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from ...engine import Workflow
from ...interfaces import ConformDwi, DerivativesDataSink
from ...interfaces.bids import get_metadata_for_nifti
from ...interfaces.dipy import Patch2Self
from ...interfaces.dwi_merge import MergeDWIs, PhaseToRad, StackConfounds
from ...interfaces.gradients import ExtractB0s
Expand Down Expand Up @@ -117,6 +118,8 @@ def init_merge_and_denoise_wf(
bvals from merged images
merged_bvec
bvecs from merged images
merged_json
JSON file containing slice timings for slice2vol
noise_image
image(s) created by ``dwidenoise``
original_files
Expand All @@ -133,6 +136,7 @@ def init_merge_and_denoise_wf(
"merged_raw_image",
"merged_bval",
"merged_bvec",
"merged_json",
"noise_images",
"bias_images",
"denoising_confounds",
Expand All @@ -151,6 +155,7 @@ def init_merge_and_denoise_wf(
bids_dwi_files=raw_dwi_files,
b0_threshold=b0_threshold,
harmonize_b0_intensities=not no_b0_harmonization,
scan_metadata={scan: get_metadata_for_nifti(scan) for scan in raw_dwi_files},
),
name="merge_dwis",
n_procs=omp_nthreads,
Expand Down Expand Up @@ -285,6 +290,7 @@ def init_merge_and_denoise_wf(
('original_images', 'original_files'),
('out_bval', 'merged_bval'),
('out_bvec', 'merged_bvec'),
('merged_metadata', 'merged_json')
]),
]) # fmt:skip

Expand Down
7 changes: 7 additions & 0 deletions qsiprep/workflows/dwi/pre_hmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ def init_dwi_pre_hmc_wf(
a bvec file
bval_file
a bval files
sidecar_file
a json sidecar file for the scan data
b0_indices
list of the positions of the b0 images in the dwi series
b0_images
Expand All @@ -121,6 +123,7 @@ def init_dwi_pre_hmc_wf(
"dwi_file",
"bval_file",
"bvec_file",
"json_file",
"original_files",
"denoising_confounds",
"noise_images",
Expand Down Expand Up @@ -296,6 +299,9 @@ def init_dwi_pre_hmc_wf(
(pm_raw_images, raw_rpe_concat, [('out', 'in_files')]),
(raw_rpe_concat, outputnode, [('out_file', 'raw_concatenated')]),

# Send the slice timings from "plus" to the next steps
(merge_plus, outputnode, [('outputnode.merged_json', 'json_file')]),

# Connect to the QC calculator
(raw_rpe_concat, qc_wf, [('out_file', 'inputnode.dwi_file')]),
(rpe_concat, qc_wf, [
Expand Down Expand Up @@ -333,6 +339,7 @@ def init_dwi_pre_hmc_wf(
('outputnode.merged_image', 'dwi_file'),
('outputnode.merged_bval', 'bval_file'),
('outputnode.merged_bvec', 'bvec_file'),
('outputnode.merged_json', 'json_file'),
('outputnode.bias_images', 'bias_images'),
('outputnode.noise_images', 'noise_images'),
('outputnode.validation_reports', 'validation_reports'),
Expand Down

0 comments on commit a783eff

Please sign in to comment.