Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial CLI implementation
Browse files Browse the repository at this point in the history
maestroque committed Aug 28, 2024
1 parent d347bba commit 7180576
Showing 5 changed files with 292 additions and 146 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -129,3 +129,4 @@ dmypy.json
# Test Data
phys2denoise/tests/test_output_data/
phys2denoise/tests/data/fake_phys.phys
exports/
163 changes: 153 additions & 10 deletions phys2denoise/cli/run.py
Original file line number Diff line number Diff line change
@@ -3,15 +3,28 @@


import argparse
import logging
import sys

from phys2denoise import __version__
from phys2denoise.metrics.cardiac import heart_beat_interval, heart_rate_variability
import numpy as np
import pydra
from loguru import logger

from phys2denoise import __version__, tasks, workflow
from phys2denoise.metrics.cardiac import (
cardiac_phase,
heart_beat_interval,
heart_rate,
heart_rate_variability,
)
from phys2denoise.metrics.chest_belt import (
env,
respiratory_pattern_variability,
respiratory_phase,
respiratory_variance,
respiratory_variance_time,
)
from phys2denoise.metrics.multimodal import retroicor
from phys2denoise.metrics.responses import crf, icrf, rrf


@@ -50,11 +63,19 @@ def _get_parser():
"physiological data, with or without extension.",
required=True,
)
required.add_argument(
"-md",
"--mode",
dest="mode",
type=str,
help="Format of the input physiological data. Options are: "
"physio or bids. Default is physio.",
)

# Important optional arguments
optional = parser.add_argument_group("Optional arguments")
optional.add_argument(
"-outdir",
"-out",
"--output-dir",
dest="outdir",
type=str,
@@ -89,7 +110,7 @@ def _get_parser():
"--respiratory-variance",
dest="metrics",
action="append_const",
const=respiratory_variance,
const="respiratory_variance",
help="Respiratory variance. Requires the following inputs: "
"sample-rate, window and lags. If the input file "
"not a .phys file, it also requires peaks and troughs",
@@ -100,7 +121,7 @@ def _get_parser():
"--respiratory-variance-per-time",
dest="metrics",
action="append_const",
const=respiratory_variance_time,
const="respiratory_variance_time",
help="Respiratory volume-per-time. Requires the following inputs: "
"sample-rate, window, lags, peaks and troughs.",
default=[],
@@ -122,7 +143,7 @@ def _get_parser():
"--heart-rate-variability",
dest="metrics",
action="append_const",
const=heart_rate_variability,
const="heart_rate_variability",
help="Computes heart rate variability. Requires the following "
"inputs: peaks, samplerate, window and central measure operator.",
default=[],
@@ -132,7 +153,7 @@ def _get_parser():
"--heart-beat-interval",
dest="metrics",
action="append_const",
const=heart_beat_interval,
const="heart_beat_interval",
help="Computes heart beat interval. Requires the following "
"inputs: peaks, samplerate, window and central measure operator.",
default=[],
@@ -180,6 +201,17 @@ def _get_parser():
default=[],
)

export_met = parser.add_argument_group("Export metrics")
export_met.add_argument(
"-e",
"--exported-metrics",
dest="metrics_to_export",
nargs="+",
type=str,
help="Full path and filename of the list with the metrics to export.",
default=None,
)

rfs = parser.add_argument_group("Response Functions")
rfs.add_argument(
"-crf",
@@ -251,7 +283,7 @@ def _get_parser():
metric_arg.add_argument(
"-tr",
"--tr",
dest="tr",
dest="t_r",
type=float,
help="TR of sequence in seconds.",
default=None,
@@ -276,7 +308,7 @@ def _get_parser():
metric_arg.add_argument(
"-nscans",
"--number-scans",
dest="nscans",
dest="n_scans",
type=int,
help="Number of timepoints in the imaging data. "
"Also called sub-bricks, TRs, scans, volumes."
@@ -291,6 +323,66 @@ def _get_parser():
help="Number of harmonics.",
default=None,
)
metric_arg.add_argument(
"-sl",
"--slice-timings",
dest="slice_timings",
nargs="*",
type=float,
help="Slice timings in seconds.",
default=None,
)

# BIDS arguments
bids = parser.add_argument_group("BIDS Arguments")
bids.add_argument(
"-sub",
"--subject",
dest="subject",
type=str,
help="Subject ID in BIDS format.",
default=None,
)
bids.add_argument(
"-ses",
"--session",
dest="session",
type=str,
help="Session ID in BIDS format.",
default=None,
)
bids.add_argument(
"-task",
"--task",
dest="task",
type=str,
help="Task ID in BIDS format.",
default=None,
)
bids.add_argument(
"-run",
"--run",
dest="run",
type=str,
help="Run ID in BIDS format.",
default=None,
)
bids.add_argument(
"-rec",
"--recording",
dest="recording",
type=str,
help="Recording ID in BIDS format.",
default=None,
)
bids.add_argument(
"-ch",
"--channel",
dest="bids_channel",
type=str,
help="Physiological signal channel ID in BIDS format.",
default=None,
)

# Logging style
log_style_group = parser.add_argument_group(
@@ -335,8 +427,59 @@ def main():
"""
parser = _get_parser()
args = parser.parse_args()
LGR = logging.getLogger(__name__)
LGR.setLevel(logging.DEBUG)

logger.add(sys.stderr, level="DEBUG")

logger.info(f"Running phys2denoise version: {__version__}")

LGR.debug(f"Arguments: {args}")
LGR.debug(f"Metrics to export: {args.metrics_to_export}")

if args.metrics_to_export is None or args.metrics_to_export == "all":
args.metrics_to_export = "all"

bids_parameters = {
"subject": args.subject,
"session": args.session,
"task": args.task,
"run": args.run,
"recording": args.recording,
}

# Conversions
args.slice_timings = (
np.array(args.slice_timings) if args.slice_timings is not None else None
)

metric_args = dict()
for metric in args.metrics:
metric_args[metric] = tasks.select_input_args(globals()[metric], vars(args))

logger.debug(f"Metric args: {metric_args}")

wf = workflow.build(
input_file=args.filename,
export_directory=args.outdir,
metrics=args.metrics,
metric_args=metric_args,
metrics_to_export=args.metrics_to_export,
mode=args.mode,
fs=args.sample_rate,
bids_parameters=bids_parameters,
bids_channel=args.bids_channel,
tr=args.t_r,
debug=args.debug,
quiet=args.quiet,
)

with pydra.Submitter(plugin="cf") as sub:
sub(wf)

wf()

return args
return wf.result().output.result


if __name__ == "__main__":
1 change: 1 addition & 0 deletions phys2denoise/tasks.py
Original file line number Diff line number Diff line change
@@ -104,6 +104,7 @@ def compute_metrics(phys: Physio, metrics: Union[list, str], args: dict) -> Phys
else:
metric_args = args[metric]

LGR.debug(f"Arguments for {metric}: {metric_args}")
input_args = select_input_args(locals()[metric], metric_args)
phys = locals()[metric](phys, **input_args)
return phys
Binary file modified phys2denoise/tests/data/fake_phys.phys
Binary file not shown.
Loading

0 comments on commit 7180576

Please sign in to comment.