diff --git a/.all-contributorsrc b/.all-contributorsrc index 548754c1b..a2dcc5a68 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -170,7 +170,7 @@ }, { "login": "yyang1234", - "name": "YingYang", + "name": "Ying Yang", "avatar_url": "https://avatars.githubusercontent.com/u/59220868?v=4", "profile": "https://github.com/yyang1234", "contributions": [ diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f71fe8f56..a6e5ac886 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -40,7 +40,6 @@ body: - type: textarea attributes: label: Operating system version - render: markdown value: | - Linux Ubuntu 18.04 "bionic beaver" - Mac OS Version 12 "monterey" @@ -68,8 +67,7 @@ body: - type: textarea attributes: label: Platform version - render: markdown - placeholder: | + value: | - MATLAB 2017a - Octave 4.2.2 @@ -85,6 +83,7 @@ body: Or check the content of CITATION.cff. options: + - v2.3.0 - v2.2.0 - v2.1.0 - v2.0.0 @@ -134,7 +133,7 @@ body: Describe what you got instead. If possible paste below the error message you encountered. Also add the error.log that might have been generated. - placeholder: | + value: | ```matlab % this is the error I got diff --git a/.gitignore b/.gitignore index 22fd1dddc..7fb94e1a6 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,7 @@ tmp error_logs *_report.md src/batches/cfg -options_task*[0-9][0-9].json +options_*[0-9][0-9].json skipped_roi_*.tsv # created by tests diff --git a/bidspm.m b/bidspm.m index 81b40982f..65eb97bc3 100644 --- a/bidspm.m +++ b/bidspm.m @@ -381,6 +381,7 @@ function initBidspm(dev) for i = 1:numel(libList) BIDSPM_PATHS = cat(2, BIDSPM_PATHS, ... + pathSep, ... genpath(fullfile(thisDirectory, 'lib', libList{i}))); end diff --git a/demos/MoAE/README.md b/demos/MoAE/README.md index 7a5a6da05..275d4b29d 100644 --- a/demos/MoAE/README.md +++ b/demos/MoAE/README.md @@ -9,3 +9,48 @@ In the `models` shows the BIDS statistical model used to run the GLM of this demo. You can use the makefile to run all the main scripts with `make all` + +## CLI commands + +### Create model + +```bash +bidspm \ + /home/remi/github/bidspm/demos/MoAE/inputs/raw \ + /home/remi/github/bidspm/demos/MoAE/outputs/derivatives \ + dataset \ + --action default_model \ + --space IXI549Space \ + --task auditory \ + --verbosity 0 \ + --ignore transformations +``` + +### Preprocessing + +```bash +bidspm \ + /home/remi/github/bidspm/demos/MoAE/inputs/raw \ + /home/remi/github/bidspm/demos/MoAE/outputs/derivatives \ + subject \ + --action preprocess \ + --participant_label 01 \ + --space individual IXI549Space \ + --task auditory \ + --verbosity 2 \ + --fwhm 6 \ + --ignore unwarp slicetiming +``` + +### GLM + +```bash +bidspm \ + /home/remi/github/bidspm/demos/MoAE/inputs/raw \ + /home/remi/github/bidspm/demos/MoAE/outputs/derivatives \ + subject \ + --action stats \ + --preproc_dir /home/remi/github/bidspm/demos/MoAE/outputs/derivatives/bidspm-preproc \ + --model_file /home/remi/github/bidspm/demos/MoAE/models/model-MoAE_smdl.json \ + --fwhm 6 +``` diff --git a/demos/face_repetition/README.md b/demos/face_repetition/README.md new file mode 100644 index 000000000..aa59b619d --- /dev/null +++ b/demos/face_repetition/README.md @@ -0,0 +1,29 @@ +# Face repetition demo + +## CLI commands + +### Preprocessing + +```bash +bidspm \ + /home/remi/github/bidspm/demos/face_repetition/outputs/raw \ + /home/remi/github/bidspm/demos/face_repetition/outputs/derivatives \ + subject \ + --action preprocess \ + --participant_label 01 \ + --space individual IXI549Space \ + --task facerepetition \ + --skip_validation \ + --dummy_scans 5 +``` + +```bash +bidspm \ + /home/remi/github/bidspm/demos/face_repetition/outputs/raw \ + /home/remi/github/bidspm/demos/face_repetition/outputs/derivatives \ + subject \ + --action preprocess \ + --space individual IXI549Space \ + --anat_only \ + --skip_validation +``` diff --git a/demos/face_repetition/face_rep_01_anat_only.m b/demos/face_repetition/face_rep_01_anat_only.m index 101cd0111..03da81c13 100644 --- a/demos/face_repetition/face_rep_01_anat_only.m +++ b/demos/face_repetition/face_rep_01_anat_only.m @@ -42,4 +42,5 @@ bidspm(bids_dir, output_dir, 'subject', ... 'action', 'preprocess', ... 'space', {'individual', 'IXI549Space'}, ... - 'anat_only', true); + 'anat_only', true, ... + 'skip_validation', true); diff --git a/demos/openneuro/Makefile b/demos/openneuro/Makefile index 4b9617900..edb5fc0ef 100644 --- a/demos/openneuro/Makefile +++ b/demos/openneuro/Makefile @@ -17,21 +17,21 @@ data: data_ds000001 data_ds000114 data_ds001168 data_ds000001: mkdir -p inputs cd inputs && datalad install ///openneuro/ds000001 - datalad -d inputs/ds000001 get inputs/ds000001/sub-0[12] + cd inputs/ds000001 && datalad get sub-0[12] data_ds000114: mkdir -p inputs cd inputs && datalad install ///openneuro/ds000114 - datalad -d inputs/ds000114 get inputs/ds000114/sub-0[12] + cd inputs/ds000114 && datalad get sub-0[12] data_ds001168: datalad install ///openneuro/ds001168 inputs/ds001168 - datalad -d inputs/ds001168 get inputs/ds001168/sub-0[12] + cd inputs/ds001168 && datalad get ds001168/sub-0[12] data_ds002799: datalad install ///openneuro/ds002799 inputs/ds002799 cd inputs/ds002799/derivatives/fmriprep - datalad -d get sub-292/*/func/*MNI152NLin2009cAsym* + datalad get sub-292/*/func/*MNI152NLin2009cAsym* datalad get sub-292/*/func/*tsv datalad get sub-30[27]/*/func/*MNI152NLin2009cAsym* datalad get sub-30[27]/*/func/*tsv diff --git a/lib/bids-matlab b/lib/bids-matlab index 16c3c988d..048c319bf 160000 --- a/lib/bids-matlab +++ b/lib/bids-matlab @@ -1 +1 @@ -Subproject commit 16c3c988dc18f4f53ffed7d44848b0e9c420eace +Subproject commit 048c319bf54430d9475535d9bec88cb5aa26d17c diff --git a/lib/spmup b/lib/spmup index 2279d8276..d362daed2 160000 --- a/lib/spmup +++ b/lib/spmup @@ -1 +1 @@ -Subproject commit 2279d8276d580ee2cba0ae3dd61ff03b3e47a712 +Subproject commit d362daed23d938c09088aa6e18bd60dd396f6839 diff --git a/setup.cfg b/setup.cfg index 6d686f677..1d6bbf837 100644 --- a/setup.cfg +++ b/setup.cfg @@ -31,11 +31,7 @@ zip_safe = False [options.entry_points] console_scripts = - bidspm = src.cli:main - bidspm_low = src.cli:low - bidspm_preproc = src.cli:preproc - bidspm_stats = src.cli:stats - bidspm_default_model = src.cli:default_model + bidspm = src.bidspm:cli validate_model = src.validate:main [options.extras_require] diff --git a/src/QA/anatomicalQA.m b/src/QA/anatomicalQA.m index 625882138..0ede2996f 100644 --- a/src/QA/anatomicalQA.m +++ b/src/QA/anatomicalQA.m @@ -18,7 +18,8 @@ function anatomicalQA(opt) % (C) Copyright 2020 bidspm developers if isOctave() - warning('\nanatomicalQA is not yet supported on Octave. This step will be skipped.'); + fprintf('\n'); + warning('anatomicalQA is not yet supported on Octave. This step will be skipped.'); opt.QA.anat.do = false; end diff --git a/src/bids/validate.m b/src/bids/validate.m index 4b91e0d05..d82f76e08 100644 --- a/src/bids/validate.m +++ b/src/bids/validate.m @@ -15,8 +15,8 @@ function validate(args) pathToPrint(args.Results.bids_dir))); [sts_data, msg_data] = bids.validate(args.Results.bids_dir); - if sts_data == 1 && ~startsWith(msg_data, 'Require') - msg_data = sprintf('\nBIDS validation of %s failed:\n\n%s\n\nCheck with\n: %s\n\n', ... + if sts_data == 1 && ~bids.internal.starts_with(msg_data, 'Require') + msg_data = sprintf('\nBIDS validation of %s failed:\n\n%s\n\nCheck with:\n %s\n\n', ... args.Results.bids_dir, ... msg_data, ... 'https://bids-standard.github.io/bids-validator/'); diff --git a/src/bidspm.py b/src/bidspm.py new file mode 100755 index 000000000..edc0df6d4 --- /dev/null +++ b/src/bidspm.py @@ -0,0 +1,307 @@ +#!/usr/bin/env python3 +import os +import subprocess +import sys +from pathlib import Path + +from rich import print + +from src.parsers import common_parser +from src.utils import root_dir + +new_line = ", ...\n\t " + + +def default_model( + bids_dir, + output_dir, + analysis_level="dataset", + verbosity=2, + space=None, + task=None, + ignore=None, +) -> None: + + task = "{ '" + "', '".join(task) + "' }" if task is not None else None + # TODO check only one space + space = "{ '" + "', '".join(space) + "' }" if space is not None else None + ignore = "{ '" + "', '".join(ignore) + "' }" if ignore is not None else None + + octave_cmd = " bidspm();" + octave_cmd += f" bidspm('{bids_dir}'{new_line}'{output_dir}'{new_line}'dataset'{new_line}'action', 'default_model'" + if verbosity: + octave_cmd += f"{new_line}'verbosity', {verbosity}" + if space: + octave_cmd += f"{new_line}'space', {space}" + if task: + octave_cmd += f"{new_line}'task', {task}" + if ignore: + octave_cmd += f"{new_line}'ignore', {ignore}" + + octave_cmd += "); exit;" + + run_octave_command(octave_cmd) + + +def preprocess( + bids_dir, + output_dir, + verbosity=2, + participant_label=None, + fwhm=6, + dummy_scans=None, + space=None, + task=None, + ignore=None, + anat_only=False, + skip_validation=False, + bids_filter_file=None, + dry_run=False, +) -> None: + + task = "{ '" + "', '".join(task) + "' }" if task is not None else None + space = "{ '" + "', '".join(space) + "' }" if space is not None else None + ignore = "{ '" + "', '".join(ignore) + "' }" if ignore is not None else None + participant_label = ( + "{ '" + "', '".join(participant_label) + "' }" + if participant_label is not None + else None + ) + + octave_cmd = " bidspm();" + octave_cmd += f" bidspm('{bids_dir}'{new_line}'{output_dir}'{new_line}'subject'{new_line}'action', 'preprocess'" + octave_cmd += f"{new_line}'fwhm', {fwhm}" + if verbosity: + octave_cmd += f"{new_line}'verbosity', {verbosity}" + if space: + octave_cmd += f"{new_line}'space', {space}" + if task: + octave_cmd += f"{new_line}'task', {task}" + if participant_label: + octave_cmd += f"{new_line}'participant_label', {participant_label}" + if ignore: + octave_cmd += f"{new_line}'ignore', {ignore}" + if skip_validation: + octave_cmd += f"{new_line}'skip_validation', true" + if anat_only: + octave_cmd += f"{new_line}'anat_only', true" + if dry_run: + octave_cmd += f"{new_line}'dry_run', true" + if dummy_scans: + octave_cmd += f"{new_line}'dummy_scans', {dummy_scans}" + if bids_filter_file: + octave_cmd += f"{new_line}'bids_filter_file', '{bids_filter_file}'" + + octave_cmd += "); exit();" + + run_octave_command(octave_cmd) + + +def stats( + bids_dir, + output_dir, + action, + preproc_dir, + model_file, + verbosity=2, + participant_label=None, + fwhm=6, + space=None, + task=None, + ignore=None, + skip_validation=False, + bids_filter_file=None, + dry_run=False, + roi_based=False, + concatenate=False, + design_only=False, +): + + task = "{ '" + "', '".join(task) + "' }" if task is not None else None + space = "{ '" + "', '".join(space) + "' }" if space is not None else None + ignore = "{ '" + "', '".join(ignore) + "' }" if ignore is not None else None + participant_label = ( + "{ '" + "', '".join(participant_label) + "' }" + if participant_label is not None + else None + ) + + octave_cmd = " bidspm();" + octave_cmd += f" bidspm('{bids_dir}'{new_line}'{output_dir}'{new_line}'subject'{new_line}'action', '{action}'" + octave_cmd += f"{new_line}'preproc_dir', '{preproc_dir}'" + octave_cmd += f"{new_line}'model_file', '{model_file}'" + octave_cmd += f"{new_line}'fwhm', {fwhm}" + if verbosity: + octave_cmd += f"{new_line}'verbosity', {verbosity}" + if space: + octave_cmd += f"{new_line}'space', {space}" + if task: + octave_cmd += f"{new_line}'task', {task}" + if participant_label: + octave_cmd += f"{new_line}'participant_label', {participant_label}" + if ignore: + octave_cmd += f"{new_line}'ignore', {ignore}" + if skip_validation: + octave_cmd += f"{new_line}'skip_validation', true" + if dry_run: + octave_cmd += f"{new_line}'dry_run', true" + if roi_based: + octave_cmd += f"{new_line}'roi_based', true" + if concatenate: + octave_cmd += f"{new_line}'concatenate', true" + if design_only: + octave_cmd += f"{new_line}'design_only', true" + if bids_filter_file: + octave_cmd += f"{new_line}'bids_filter_file', '{bids_filter_file}'" + + octave_cmd += "); exit();" + + run_octave_command(octave_cmd) + + +def cli(argv=sys.argv) -> None: + + parser = common_parser() + + args, unknowns = parser.parse_known_args(argv[1:]) + + os.chdir(root_dir()) + + bids_dir = Path(args.bids_dir[0]).resolve() + output_dir = Path(args.output_dir[0]).resolve() + analysis_level = args.analysis_level[0] + action = args.action[0] + task = args.task + space = args.space + verbosity = args.verbosity + ignore = args.ignore + fwhm = args.fwhm + bids_filter_file = ( + Path(args.bids_filter_file[0]).resolve() + if args.bids_filter_file is not None + else None + ) + skip_validation = args.skip_validation + dry_run = args.dry_run + dummy_scans = args.dummy_scans + anat_only = args.anat_only + preproc_dir = ( + Path(args.preproc_dir[0]).resolve() if args.preproc_dir is not None else None + ) + model_file = ( + Path(args.model_file[0]).resolve() if args.model_file is not None else None + ) + roi_based = args.roi_based + concatenate = args.concatenate + design_only = args.design_only + + bidspm( + bids_dir, + output_dir, + analysis_level, + action=action, + verbosity=verbosity, + task=task, + space=space, + ignore=ignore, + fwhm=fwhm, + bids_filter_file=bids_filter_file, + dummy_scans=dummy_scans, + anat_only=anat_only, + skip_validation=skip_validation, + dry_run=dry_run, + preproc_dir=preproc_dir, + model_file=model_file, + roi_based=roi_based, + concatenate=concatenate, + design_only=design_only, + ) + + +def bidspm( + bids_dir, + output_dir, + analysis_level, + action=None, + verbosity=2, + task=None, + space=None, + ignore=None, + fwhm=None, + bids_filter_file=None, + dummy_scans=0, + anat_only=False, + skip_validation=False, + dry_run=False, + preproc_dir=None, + model_file=None, + roi_based=False, + concatenate=False, + design_only=False, +) -> None: + + if action == "default_model": + default_model( + bids_dir=bids_dir, + output_dir=output_dir, + analysis_level=analysis_level, + verbosity=verbosity, + task=task, + space=space, + ignore=ignore, + ) + + elif action == "preprocess": + preprocess( + bids_dir=bids_dir, + output_dir=output_dir, + verbosity=verbosity, + task=task, + space=space, + ignore=ignore, + fwhm=fwhm, + dummy_scans=dummy_scans, + skip_validation=skip_validation, + anat_only=anat_only, + bids_filter_file=bids_filter_file, + dry_run=dry_run, + ) + elif action in ["stats", "contrasts", "results"]: + stats( + bids_dir=bids_dir, + output_dir=output_dir, + action=action, + preproc_dir=preproc_dir, + model_file=model_file, + verbosity=verbosity, + task=task, + space=space, + ignore=ignore, + fwhm=fwhm, + skip_validation=skip_validation, + bids_filter_file=bids_filter_file, + dry_run=dry_run, + roi_based=roi_based, + concatenate=concatenate, + design_only=design_only, + ) + else: + print(f"\nunknown action: {action}") + + +def run_octave_command(octave_cmd: str): + + print("\nRunning the following command:\n") + print(octave_cmd.replace(";", ";\n")) + print() + + subprocess.run( + [ + "octave", + "--no-gui", + "--no-window-system", + "--silent", + "--eval", + f"{octave_cmd}", + ] + ) diff --git a/src/cli.py b/src/cli.py deleted file mode 100755 index 93c6f3ac9..000000000 --- a/src/cli.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -import sys - -from src.parsers import default_model_parser -from src.parsers import low_parser -from src.parsers import preproc_parser -from src.parsers import stats_parser - - -def low(argv=sys.argv) -> None: - - parser = low_parser() - - args = parser.parse_args(argv[1:]) - - -def default_model(argv=sys.argv) -> None: - - parser = default_model_parser() - - args = parser.parse_args(argv[1:]) - - -def stats(argv=sys.argv) -> None: - - parser = stats_parser() - - args = parser.parse_args(argv[1:]) - - -def preproc(argv=sys.argv) -> None: - - parser = preproc_parser() - - args = parser.parse_args(argv[1:]) - - -def main(argv=sys.argv) -> None: - - parser = preproc_parser() - - args = parser.parse_args(argv[1:]) - - -if __name__ == "__main__": - main() diff --git a/src/defaults/checkOptions.m b/src/defaults/checkOptions.m index 527266943..9fb9f4571 100644 --- a/src/defaults/checkOptions.m +++ b/src/defaults/checkOptions.m @@ -316,6 +316,8 @@ %% General options for functional data fieldsToSet.funcVolToSelect = []; + fieldsToSet.dummy_scans = 0; + %% Options for slice time correction % all in seconds fieldsToSet.stc.referenceSlice = []; diff --git a/src/parsers.py b/src/parsers.py index b61f5dd7a..e365ae901 100644 --- a/src/parsers.py +++ b/src/parsers.py @@ -1,5 +1,6 @@ import argparse import logging +from pathlib import Path from typing import IO from typing import Optional @@ -8,8 +9,10 @@ log = logging.getLogger("bidspm") +version_file = Path(__file__).parent.parent.joinpath("version.txt") -__version__ = "v2.2.0" +with open(version_file) as f: + __version__ = f.read().strip() def bidspm_log(name: str = "bidspm") -> logging.Logger: @@ -31,7 +34,7 @@ def _print_message(self, message: str, file: Optional[IO[str]] = None) -> None: rich.print(message, file=file) -def base_parser(): +def common_parser(): parser = MuhParser( description="bidspm is a SPM base BIDS app", @@ -50,42 +53,10 @@ def base_parser(): action="version", version=f"{__version__}", ) - - return parser - - -def low_parser(): - - parser = base_parser() - - parser.add_argument( - "--action", - help=""" - Low level action to perform. - - - ``init``: initialise (add relevant folders to MATLAB path). - - ``dev``: initialise and also adds folder for testing to the path. - - ``uninit``: uninitialise (remove relevant folders from MATLAB path) - - ``update``: tries to update the current branch from the upstream repository - - ``run_tests``: tries to update the current branch from the upstream repository - """, - choices=["init", "dev", "uninit", "update", "run_tests"], - required=True, - type=str, - nargs=1, - ) - - return parser - - -def common_parser(): - - parser = base_parser() - parser.add_argument( "bids_dir", help=""" - The directory with the input dataset + Fullpath to the directory with the input dataset formatted according to the BIDS standard. """, nargs=1, @@ -93,7 +64,7 @@ def common_parser(): parser.add_argument( "output_dir", help=""" - The directory where the output files will be stored. + Fullpath to the directory where the output files will be stored. If you are running group level analysis this folder should be prepopulated with the results of the participant level analysis. """, @@ -111,35 +82,22 @@ def common_parser(): nargs=1, ) parser.add_argument( - "--participant_label", - help=""" - The label(s) of the participant(s) that should be analyzed. - The label corresponds to sub- from the BIDS spec - (so it does not include "sub-"). - If this parameter is not provided all subjects should be analyzed. - Multiple participants can be specified with a space separated list. - Can be a regular expression. - Example: ``'01', '03', '08'``. - """, - nargs="+", - ) - parser.add_argument( - "--dry_run", + "--action", help=""" - When set to ``true`` this will generate and save the SPM batches, - but not actually run them. + Action to perform. + + - ``preprocess`` + - ``default_model`` + - ``stats``: runs model specification / estimation, contrast computation, display results + - ``contrasts``: contrast computation, display results + - ``results``: display results """, - choices=[True, False], - default=False, - type=bool, + choices=["preprocess", "default_model", "stats", "contrasts", "results"], + required=True, + type=str, nargs=1, ) - parser.add_argument( - "--bids_filter_file", - help=""" - A JSON file describing custom BIDS input filters. - """, - ) + parser.add_argument( "--verbosity", help=""" @@ -150,29 +108,6 @@ def common_parser(): type=int, nargs=1, ) - parser.add_argument( - "--options", - help=""" - Path to JSON file containing bidspm options. - """, - ) - - return parser - - -def default_model_parser(): - - parser = common_parser() - - parser.add_argument( - "--action", - choices=[ - "default_model", - ], - required=True, - type=str, - nargs=1, - ) parser.add_argument( "--task", help=""" @@ -186,160 +121,136 @@ def default_model_parser(): help=""" Space of the input data. """, - default=["individual", "IXI549Space"], - nargs=1, + default=["IXI549Space"], + type=str, + nargs="+", ) - - return parser - - -def stats_parser(): - - parser = common_parser() - parser.add_argument( - "--action", + "--ignore", help=""" - Level of the analysis that will be performed. - Multiple participant level analyses can be run independently - (in parallel) using the same output_dir. - - - ``stats``: runs model specification / estimation, contrast computation, display results - - ``contrasts``: contrast computation, display results - - ``results``: display results + If preprocessing should be done only on anatomical data. """, choices=[ - "stats", "contrasts", - "results", + "transformations", + "qa", + "fieldmaps", + "slicetiming", + "unwarp", ], - required=True, - type=str, - nargs=1, - ) - parser.add_argument( - "--preproc_dir", - help=""" - Path to preprocessed data. - """, - nargs=1, + nargs="+", ) + parser.add_argument( - "--task", + "--participant_label", help=""" - Tasks of the input data. + The label(s) of the participant(s) that should be analyzed. + The label corresponds to sub- from the BIDS spec + (so it does not include "sub-"). + If this parameter is not provided all subjects should be analyzed. + Multiple participants can be specified with a space separated list. + Can be a regular expression. + Example: ``'01', '03', '08'``. """, - type=str, nargs="+", ) parser.add_argument( - "--space", + "--dry_run", help=""" - Space of the input data. + When set to ``true`` this will generate and save the SPM batches, + but not actually run them. """, - default=["individual", "IXI549Space"], - nargs=1, + action="store_true", + default=False, ) parser.add_argument( - "--model_file", + "--bids_filter_file", help=""" - Path to BIDS stats model. + Fullpath to a JSON file describing custom BIDS input filters. """, + type=str, nargs=1, ) parser.add_argument( "--fwhm", help=""" - Full width at half maximum of the gaussian kernel of the input data. + The full width at half maximum of the gaussian kernel to apply to the preprocessed data + or to use as inputs for the statistical analysis. """, type=float, nargs=1, default=6.0, ) parser.add_argument( - "--roi_based", + "--options", help=""" - To run stats only in regions of interests. + Path to JSON file containing bidspm options. """, - choices=[True, False], - default=False, - type=bool, - nargs=1, ) - - return parser - - -def preproc_parser(): - - parser = common_parser() - parser.add_argument( - "--action", + "--skip_validation", help=""" - Level of the analysis that will be performed. - Multiple participant level analyses can be run independently - (in parallel) using the same output_dir. + To skip BIDS dataset and BIDS stats model validation. """, - choices=[ - "preprocess", - ], - required=True, - type=str, - nargs=1, + action="store_true", + default=False, ) parser.add_argument( - "--space", + "--preproc_dir", help=""" - Space to normalize to generate output in for ``preprocess``. + Fullpath to the directory with the preprocessed data. """, - default=["individual", "IXI549Space"], - nargs="+", + type=str, + nargs=1, ) parser.add_argument( - "--task", + "--model_file", help=""" - Tasks to ``preprocess``. - Only one value allowed. + Path to BIDS stats model. """, type=str, nargs=1, ) parser.add_argument( - "--dummy_scans", + "--roi_based", help=""" - Number of dummy scans to remove. + To run stats only in regions of interests. """, - type=int, - nargs=1, - default=0, + action="store_true", + default=False, ) parser.add_argument( - "--anat_only", + "--design_only", help=""" - If preprocessing should be done only on anatomical data. + To only specify the GLM without estimating it. """, - choices=[True, False], + action="store_true", default=False, - type=bool, - nargs=1, ) parser.add_argument( - "--ignore", + "--concatenate", help=""" - If preprocessing should be done only on anatomical data. + To create 4D image of all the beta images from the conditions of interest. """, - choices=["fieldmaps", "slicetiming", "unwarp"], - nargs="+", + action="store_true", + default=False, ) parser.add_argument( - "--fwhm", + "--dummy_scans", help=""" - The full width at half maximum of the gaussian kernel to apply to the preprocessed data. + Number of dummy scans to remove. """, - type=float, + type=int, nargs=1, - default=6.0, + default=0, + ) + parser.add_argument( + "--anat_only", + help=""" + If preprocessing should be done only on anatomical data. + """, + action="store_true", + default=False, ) return parser diff --git a/src/reports/boilerplate.m b/src/reports/boilerplate.m index e6f61df8c..dbd013042 100644 --- a/src/reports/boilerplate.m +++ b/src/reports/boilerplate.m @@ -73,6 +73,12 @@ if strcmp(pipelineType, 'preproc') + if opt.dummy_scans == 0 + opt.dummy_scans = false; + else + opt.dummy_scans = struct('nb', opt.dummy_scans); + end + opt.normalization = false; if ismember('IXI549Space', opt.space) opt.normalization = true; @@ -91,6 +97,7 @@ elseif strcmp(pipelineType, 'stats') opt.smoothing = true; + if opt.fwhm.contrast == 0 opt.smoothing = false; end diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 000000000..fb4d73a3c --- /dev/null +++ b/src/utils.py @@ -0,0 +1,5 @@ +from pathlib import Path + + +def root_dir() -> Path: + return Path(__file__).parent.parent.resolve() diff --git a/src/utils/removeDummies.m b/src/utils/removeDummies.m index 38e82cecf..0fe9b9ee7 100644 --- a/src/utils/removeDummies.m +++ b/src/utils/removeDummies.m @@ -79,6 +79,12 @@ function removeDummies(varargin) volumeSplicing(inputFile, 1:numberOfVolumeToDiscard); + if verbose + msg = sprintf('\nRemoved %i volumes from file:\n%s', ... + numberOfVolumeToDiscard, inputFile); + printToScreen(msg); + end + if isZipped(inputFile) inputFile = spm_file(inputFile, 'ext', ''); end diff --git a/tests/tests_reports/test_boilerplate.m b/tests/tests_reports/test_boilerplate.m index a2338cc30..a21037cc8 100644 --- a/tests/tests_reports/test_boilerplate.m +++ b/tests/tests_reports/test_boilerplate.m @@ -23,8 +23,7 @@ function test_boilerplate_spatial_preproc() opt.stc.referenceSlice = 32; - % opt.dummy_scans = false; - opt.dummy_scans.nb = 4; + opt.dummy_scans = 4; % opt.space = {'individual'}; diff --git a/tests/utils/defaultOptions.m b/tests/utils/defaultOptions.m index ffeb5668b..8d5bc9425 100644 --- a/tests/utils/defaultOptions.m +++ b/tests/utils/defaultOptions.m @@ -33,6 +33,8 @@ expectedOptions.fwhm.func = 6; expectedOptions.fwhm.contrast = 0; + expectedOptions.dummy_scans = 0; + expectedOptions.stc.sliceOrder = []; expectedOptions.stc.referenceSlice = []; expectedOptions.stc.skip = false;