Skip to content

Commit

Permalink
Add (working) DCE_deltaCt rule
Browse files Browse the repository at this point in the history
  • Loading branch information
martinherrerias committed Oct 12, 2023
1 parent cd9d9c9 commit 1c840e6
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 98 deletions.
6 changes: 3 additions & 3 deletions config/DCE_deltaCt.config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

# General (previously Qbi.runner options)
#data_dir: null
output_dir: logs/qMRI_processes
# data_dir: null
# no_audit: True # -- this is a madym option

# Inputs
Expand All @@ -10,7 +9,7 @@ T1_path: madym_output/T1_VFA/T1.nii.gz

dce_im_ext: .nii.gz
dce_meta_ext: .json
#roi_path: null
roi_path: null

# Parameters
dce_limits: [2, 9, 11, 15]
Expand All @@ -21,6 +20,7 @@ equal_var: True

# Output
maps_dir: DCE_output_maps
output_dir: logs/qMRI_processes/DCE_deltaCt.log



Expand Down
25 changes: 25 additions & 0 deletions workflow/Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,28 @@
# Please follow the best practices:
# https://snakemake.readthedocs.io/en/stable/snakefiles/best_practices.html,
# in particular regarding the standardized folder structure mentioned there.

from snakemake.utils import min_version
min_version("6.15")

# workdir: "path/to/workdir"

# # Preprocessing
# include: "rules/OE_IR_T1_mapping.smk"
# include: "rules/DCE_VFA_T1_mapping.smk"
# include: "rules/OE_deltaR1.smk"

include: "rules/DCE_deltaCt.smk"

# include: "rules/DCE_ETM.smk"
# # include: "rules/OE_DCE_hypoxia_mapping.smk"

# # Postprocessing
# include: "OE_DCE_summary.smk"

rule all:
input:
expand("{maps_dir}/{key}{ext}",
maps_dir = data_path("maps_dir"),
key = ['C_t', 'delta_C', 'C_baseline', 'C_enhancing', 'C_p_vals', 'S_p_vals'],
ext = ".nii.gz"),
40 changes: 40 additions & 0 deletions workflow/rules/DCE_deltaCt.smk
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'''
Wrapper for PreclinicalMRI.dynamic.compute_dataset_delta_Ct
'''
import os
from snakemake.utils import validate

configfile: workflow.source_path("../../config/DCE_deltaCt.config.yaml")
validate(config, workflow.source_path("../schemas/DCE_deltaCt.schema.yaml"))

data_dir = config.get("data_dir")
assert os.path.exists(data_dir), f"The folder {data_dir} does not exist"
workdir: data_dir

def data_path(path_key):
rel_path = config.get(path_key)
return rel_path if rel_path is not None else []

rule DCE_deltaCt:
conda:
"../envs/conda_env.yml"
input:
images = f"{data_path('dce_path')}{config['dce_im_ext']}",
metadata = f"{data_path('dce_path')}{config['dce_meta_ext']}",
T1_path = data_path('T1_path'),
roi_path = data_path('roi_path')
output:
expand("{maps_dir}/{key}{ext}",
maps_dir = data_path("maps_dir"),
key = ['C_t', 'delta_C', 'C_baseline', 'C_enhancing', 'C_p_vals', 'S_p_vals'],
ext = ".nii.gz"),
params:
dce_limits = config["dce_limits"],
relax_coeff = config["relax_coeff"],
average_fun = config["average_fun"],
alternative = config["alternative"],
equal_var = config["equal_var"]
log:
config["output_dir"]
script:
"../scripts/DCE_deltaCt.py"
10 changes: 7 additions & 3 deletions workflow/schemas/DCE_deltaCt.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ properties:
data_dir:
type: string
description: 'Base data path'
default: './test'

roi_path:
type: ["null", string]
Expand All @@ -17,14 +16,19 @@ properties:
#Output dir
maps_dir:
type: string
description: 'Location of saved output maps, relative to data_dir'
description: 'Relative path to output maps'
default: 'DCE_output_maps'

output_dir:
type: string
description: 'Relative path to log file'
default: logs/qMRI_processes/DCE_deltaCt.log

#DCE input options
dce_path:
type: string
description: 'Relative path to DCE 4D-image volumes'
default: 'dynamic'
default: 'dce/dce_dyn_echo1'

dce_im_ext:
type: string
Expand Down
124 changes: 32 additions & 92 deletions workflow/scripts/DCE_deltaCt.py
Original file line number Diff line number Diff line change
@@ -1,100 +1,40 @@
'''
_summary_
Wrapper for PreclinicalMRI.dynamic.compute_dataset_delta_Ct
'''
import os
import numpy as np
from contextlib import redirect_stdout, redirect_stderr

from QbiPy.tools.runner import QbiRunner, bool_option
from QbiPy.image_io.analyze_format import write_nifti_img
from PreclinicalMRI.dynamic import dce

#---------------------------------------------------------
def add_options(runner):
parser = runner.parser

#General input arguments
parser.add('--roi_path', type=str, nargs='?', default=None,
help='Relative path to roi mask file')

#DCE input options
parser.add('--dce_path', type=str, nargs='?', default='dynamic',
help='Relative path to DCE 4D-image volumes')
parser.add('--dce_im_ext', type=str, nargs='?', default='.nii.gz',
help='File extension of the DCE volumes')
parser.add('--dce_meta_ext', type=str, nargs='?', default='.json',
help='File extension of the DCE volumes meta-info')
parser.add('--dce_limits', type=int, nargs=4, required=True,
help='Limits for the DCE volumes, 4 element integer list')
parser.add('--T1_path', type=str, nargs='?', default='madym_output/T1_VFA/T1.nii.gz',
help='Relative path to T1 image')
parser.add('--relax_coeff', type=float, nargs='?', default=3.4,
help='Relaxivity constant for contrast agent - units... ')

#Summary stats options
parser.add('--average_fun', type=str, nargs='?', default='median',
help='Method used for temporal average {median, mean}.')
parser.add('--alternative', type=str, nargs='?', default='less',
help='Apply 1-sided or 2-sided t-test: less = baseline lower than enhancing. Use "two-sided" for 2-sided.')
parser.add('--equal_var', type=bool_option, nargs='?', default=True,
const = True, help='Assume equal variance in pre/post enhancing periods')

# TODO: Unused?
# parser.add('--sig_level', type=float, nargs='?', default=0.05,
# help='Significance level for p-value map thresholds')

#Output dir
parser.add('--maps_dir', type=str, nargs='?', default='DCE_output_maps',
help='Location of saved output maps, relative to data_dir')

#---------------------------------------------------------
def run_DCE_deltaCt(
data_dir:str,
dce_limits:np.array,
dce_path:str,
dce_im_ext:str,
dce_meta_ext:str,
T1_path:str,
roi_path:str,
relax_coeff:float,
average_fun:str,
alternative:str,
equal_var:bool,
maps_dir:str
):
print('Running DCE_deltaCt')
dce_data = dce.compute_dataset_delta_Ct(
data_dir,
dce_limits,
dce_path = dce_path,
dce_im_ext = dce_im_ext,
dce_meta_ext = dce_meta_ext,
T1_path = T1_path,
roi_path = roi_path,
relax_coeff = relax_coeff,
average_fun = average_fun,
alternative = alternative,
equal_var = equal_var,
debug = 0)

maps_dir = os.path.join(data_dir, maps_dir)
os.makedirs(maps_dir, exist_ok = True)

for key,value in dce_data.items():
print(f'{key} has shape {value.shape}')
nii_filepath = os.path.join(maps_dir, key + '.nii.gz')
write_nifti_img(
img_data = value,
filename = nii_filepath,
sform_matrix=np.eye(4),
scale = 1.0,
dtype = None)

#---------------------------------------------------------
def main(args = None):
runner = QbiRunner()
add_options(runner)
runner.run(run_DCE_deltaCt, args)

#----------------------------------------------------------
if __name__ == '__main__':
main()
with open(snakemake.log[0], "w") as log:
with redirect_stderr(log), redirect_stdout(log):

print('Running DCE_deltaCt')
dce_data = dce.compute_dataset_delta_Ct(
snakemake.config["data_dir"],
snakemake.config["dce_limits"],
dce_path = snakemake.config["dce_path"],
dce_im_ext = snakemake.config["dce_im_ext"],
dce_meta_ext = snakemake.config["dce_meta_ext"],
T1_path = snakemake.config["T1_path"],
roi_path = snakemake.config["roi_path"],
relax_coeff = snakemake.config["relax_coeff"],
average_fun = snakemake.config["average_fun"],
alternative = snakemake.config["alternative"],
equal_var = snakemake.config["equal_var"],
debug = 0)

maps_dir = os.path.join(snakemake.config["data_dir"], snakemake.config["maps_dir"])
os.makedirs(maps_dir, exist_ok = True)

for key,value in dce_data.items():
print(f'{key} has shape {value.shape}')
nii_filepath = os.path.join(maps_dir, key + '.nii.gz')
write_nifti_img(
img_data = value,
filename = nii_filepath,
sform_matrix=np.eye(4),
scale = 1.0,
dtype = None)

0 comments on commit 1c840e6

Please sign in to comment.