diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..5d67802
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,28 @@
+[run]
+branch = True
+omit = */tests/*
+ _*.py
+ plotting.py
+
+[report]
+; Regexes for lines to exclude from consideration
+exclude_also =
+ ; Don't complain about missing debug-only code:
+ def __repr__
+ if self\.debug
+
+ ; Don't complain if tests don't hit defensive assertion code:
+ raise AssertionError
+ raise NotImplementedError
+
+ ; Don't complain if non-runnable code isn't run:
+ if 0:
+ if __name__ == .__main__.:
+
+ ; Don't complain about abstract methods, they aren't run:
+ @(abc\.)?abstractmethod
+
+ignore_errors = True
+
+[html]
+directory = htmlcov
diff --git a/.editorconfig b/.editorconfig
index d4a2c44..66de818 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -19,3 +19,6 @@ insert_final_newline = false
[Makefile]
indent_style = tab
+
+[*.py]
+max_line_length = 80
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
new file mode 100644
index 0000000..08894d5
--- /dev/null
+++ b/.github/workflows/continuous-integration.yml
@@ -0,0 +1,41 @@
+# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
+
+name: tests
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version: [ "3.8" ]
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v3
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install git+https://github.com/sinhaharsh/protocol.git#egg=protocol
+ pip install git+https://github.com/sinhaharsh/MRdataset.git#egg=MRdataset
+ if [ -f requirements_dev.txt ]; then pip install -r requirements_dev.txt; fi
+ pip install .
+ - name: Lint with flake8
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
+ # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
+ flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
+ - name: Test with pytest
+ run: |
+ pytest
diff --git a/.gitignore b/.gitignore
index feebfba..3e25d06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -104,3 +104,6 @@ ENV/
.vscode/
.idea/
/update_today.txt
+
+# codacy
+results.sarif
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index a5ab97d..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-# Config file for automatic testing at travis-ci.com
-
-language: python
-python:
- - 3.8
- - 3.7
- - 3.6
-
-# Command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
-install: pip install -U tox-travis
-
-# Command to run tests, e.g. python setup.py test
-script: tox
-
-# Assuming you have installed the travis-ci CLI tool, after you
-# create the Github repo and add it to Travis, run the
-# following command to finish PyPI deployment setup:
-# $ travis encrypt --add deploy.password
-deploy:
- provider: pypi
- distributions: sdist bdist_wheel
- user: sinhaharsh
- password:
- secure: PLEASE_REPLACE_ME
- on:
- tags: true
- repo: sinhaharsh/mrQA
- python: 3.8
diff --git a/MANIFEST.in b/MANIFEST.in
index dae47eb..45a6a35 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,7 +4,11 @@ include HISTORY.rst
include LICENSE
include README.rst
-recursive-include tests *
+graft mrQA/tests
+prune mrQA/tests/htmlcov
+prune mrQA/tests/.hypothesis
+graft mrQA/scripts
+graft mrQA/resources
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
diff --git a/Makefile b/Makefile
index bbfffac..6049484 100644
--- a/Makefile
+++ b/Makefile
@@ -48,7 +48,7 @@ clean-test: ## remove test and coverage artifacts
rm -fr .pytest_cache
lint/flake8: ## check style with flake8
- flake8 mrQA tests
+ flake8 mrQA
lint: lint/flake8 ## check style
@@ -59,18 +59,15 @@ test-all: ## run tests on every Python version with tox
tox
coverage: ## check code coverage quickly with the default Python
- coverage run --source mrQA -m pytest
+ coverage run --rcfile=.coveragerc --source mrQA -m pytest
coverage report -m
coverage html
$(BROWSER) htmlcov/index.html
docs: ## generate Sphinx HTML documentation, including API docs
- rm -f docs/mrQA.rst
- rm -f docs/modules.rst
- sphinx-apidoc -o docs/ mrQA
$(MAKE) -C docs clean
$(MAKE) -C docs html
- $(BROWSER) docs/_build/html/index.html
+ $(BROWSER) docs/build/html/index.html
servedocs: docs ## compile the docs watching for changes
watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
diff --git a/README.rst b/README.rst
index 3bc95cb..5053413 100644
--- a/README.rst
+++ b/README.rst
@@ -4,8 +4,12 @@ mrQA : automatic protocol compliance checks on MR datasets
.. image:: https://img.shields.io/pypi/v/mrQA.svg
:target: https://pypi.python.org/pypi/mrQA
-.. image:: https://img.shields.io/travis/Open-Minds-Lab/mrQA.svg
- :target: https://travis-ci.com/Open-Minds-Lab/mrQA
+.. image:: https://app.codacy.com/project/badge/Grade/8cd263e1eaa0480d8fac50eba0094401
+ :target: https://app.codacy.com/gh/sinhaharsh/mrQA/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade
+
+.. image:: https://github.com/sinhaharsh/mrQA/actions/workflows/continuos-integration.yml/badge.svg
+ :target: https://github.com/sinhaharsh/mrQA/actions/workflows/continuos-integration.yml
+
.. image:: https://raw.githubusercontent.com/jupyter/design/master/logos/Badges/nbviewer_badge.svg
:target: https://nbviewer.org/github/Open-Minds-Lab/mrQA/blob/master/examples/usage.ipynb
diff --git a/docs/cli.rst b/docs/cli.rst
new file mode 100644
index 0000000..b018c49
--- /dev/null
+++ b/docs/cli.rst
@@ -0,0 +1,7 @@
+Command Line
+============
+
+.. argparse::
+ :module: mrQA.cli
+ :func: get_parser
+ :prog: mrQA
diff --git a/docs/conf.py b/docs/conf.py
index bf5fb78..0a7f4a9 100755
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -34,7 +34,8 @@
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.viewcode',
- 'sphinx.ext.napoleon']
+ 'sphinx.ext.napoleon',
+ 'sphinxarg.ext']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
diff --git a/docs/usage.rst b/docs/usage.rst
index c5b4a39..acd0279 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -4,15 +4,23 @@ CLI usage
A protocol compliance report can be generated directly from the command line
interface. The following is an example of generating a protocol compliance report
-For a DICOM dataset::
+For a DICOM dataset
+
+.. code:: bash
mrqa --data-source /path/to/dataset --format dicom --name my_dataset
-For a BIDS dataset::
+For a BIDS dataset
+
+.. code:: bash
mrqa --data-source /path/to/dataset --format bids --name my_dataset
+.. toctree::
+ :maxdepth: 1
+
+ cli
API Tutorial
------------
diff --git a/examples/check_status.py b/examples/check_status.py
new file mode 100644
index 0000000..59c71a7
--- /dev/null
+++ b/examples/check_status.py
@@ -0,0 +1,37 @@
+from pathlib import Path
+from mrQA import monitor
+import tempfile
+import shutil
+
+from mrQA.tests.test_utils import copy2dest
+
+
+def run(folder_path):
+ folder_path = Path(folder_path).resolve()
+ config_path = Path('./mri-config.json').resolve()
+ # make a temporary output folder using tempfile
+ with tempfile.TemporaryDirectory() as tmpdirname:
+ output_dir = Path(tmpdirname) / 'output'
+ input_dir = Path(tmpdirname) / 'input'
+ output_dir.mkdir(exist_ok=True, parents=True)
+ input_dir.mkdir(exist_ok=True, parents=True)
+ i = 0
+ # copy a folder from folder_path to tmpdirname
+ for folder in folder_path.iterdir():
+ if folder.is_dir():
+ copy2dest(folder, folder_path, input_dir)
+
+ # Run monitor on the temporary folder
+ monitor(name='dummy_dataset',
+ data_source=input_dir,
+ output_dir=output_dir,
+ decimals=2,
+ config_path=config_path,
+ verbose=False,
+ reference_path='./wpc-6106.xml'
+ )
+ copy2dest(output_dir, tmpdirname, '/tmp')
+ print('simulation-over')
+
+
+run('/home/sinhah/scan_data/WPC-6106')
diff --git a/examples/example-protocol.json b/examples/example-protocol.json
new file mode 100644
index 0000000..786d675
--- /dev/null
+++ b/examples/example-protocol.json
@@ -0,0 +1,2675 @@
+{
+ "wpc-6106_22": {
+ "ncanda-localizer-v1": {
+ "name": "ncanda-localizer-v1 *",
+ "Id": "152425e7-a021-486e-9e5d-57a2a7bcd58e",
+ "header_property": "TA: 0:15 PM: REF Voxel size: 0.6\u00d70.6\u00d710.0 mmPAT: Off Rel. SNR: 1.00 : fl ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "On",
+ "Load images to graphic segments": "On",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "On",
+ "Wait for user to start": "Off",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 3,
+ "Slices": 3,
+ "Dist. factor": 50,
+ "Position": "Isocenter",
+ "Orientation": "Coronal",
+ "Phase enc. dir.": "R >> L",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 300,
+ "FoV phase": 100.0,
+ "Slice thickness": 10.0,
+ "TR": 8.6,
+ "TE": 4.0,
+ "Averages": 1,
+ "Concatenations": 9,
+ "Filter": "Elliptical filter",
+ "Coil elements": "HE1-4;NE1,2"
+ },
+ "Contrast - Common": {
+ "TR": 8.6,
+ "TE": 4.0,
+ "TD": 0,
+ "MTC": "Off",
+ "Magn. preparation": "None",
+ "Flip angle": 20,
+ "Fat suppr.": "None",
+ "Water suppr.": "None",
+ "SWI": "Off"
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Short term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 1,
+ "Multiple series": "Each measurement"
+ },
+ "Resolution - Common": {
+ "FoV read": 300,
+ "FoV phase": 100.0,
+ "Slice thickness": 10.0,
+ "Base resolution": 256,
+ "Phase resolution": 70,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "On"
+ },
+ "Resolution - iPAT": {
+ "PAT mode": "None"
+ },
+ "Resolution - Filter Image": {
+ "Image Filter": "Off",
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "Off",
+ "Normalize": "Off",
+ "B1 filter": "Off"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "Off",
+ "Elliptical filter": "On"
+ },
+ "Geometry - Common": {
+ "Slice group": 3,
+ "Slices": 3,
+ "Dist. factor": 50,
+ "Position": "Isocenter",
+ "Orientation": "Coronal",
+ "Phase enc. dir.": "R >> L",
+ "FoV read": 300,
+ "FoV phase": 100.0,
+ "Slice thickness": 10.0,
+ "TR": 8.6,
+ "Multi-slice mode": "Sequential",
+ "Series": "Interleaved",
+ "Concatenations": 9
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 3,
+ "Position": "Isocenter",
+ "Orientation": "Coronal",
+ "Phase enc. dir.": "R >> L",
+ "AutoAlign": "---",
+ "Initial Position": "Isocenter",
+ "L": 0.0,
+ "P": 0.0,
+ "H": 0.0,
+ "Initial Rotation": 0.0,
+ "Initial Orientation": "Sagittal"
+ },
+ "Geometry - Saturation": {
+ "Saturation mode": "Standard",
+ "Fat suppr.": "None",
+ "Water suppr.": "None",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "REF",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "A >> P",
+ "Transversal": "F >> H",
+ "Coil Combine Mode": "Adaptive Combine",
+ "Save uncombined": "Off",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "Default"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Tune up",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "Isocenter",
+ "Orientation": "Transversal",
+ "Rotation": 0.0,
+ "A >> P": 263,
+ "R >> L": 350,
+ "F >> H": 350,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Slice-sel."
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 8.6,
+ "Concatenations": 9,
+ "Segments": 1
+ },
+ "Physio - Cardiac": {
+ "Tagging": "None",
+ "Magn. preparation": "None",
+ "Fat suppr.": "None",
+ "Dark blood": "Off",
+ "FoV read": 300,
+ "FoV phase": 100.0,
+ "Phase resolution": 70
+ },
+ "Physio - PACE": {
+ "Resp. control": "Off",
+ "Concatenations": 9
+ },
+ "Inline - Common": {
+ "Subtract": "Off",
+ "Measurements": 1,
+ "StdDev": "Off",
+ "Liver registration": "Off",
+ "Save original images": "On"
+ },
+ "Inline - MIP": {
+ "MIP-Sag": "Off",
+ "MIP-Cor": "Off",
+ "MIP-Tra": "Off",
+ "MIP-Time": "Off",
+ "Save original images": "On"
+ },
+ "Inline - Soft Tissue": {
+ "Wash - In": "Off",
+ "Wash - Out": "Off",
+ "TTP": "Off",
+ "PEI": "Off",
+ "MIP - time": "Off",
+ "Measurements": 1
+ },
+ "Inline - Composing": {
+ "Distortion Corr.": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "On",
+ "Dimension": "2D",
+ "Phase stabilisation": "Off",
+ "Asymmetric echo": "Allowed",
+ "Contrasts": 1,
+ "Flow comp.": "No",
+ "Multi-slice mode": "Sequential",
+ "Bandwidth": 320
+ },
+ "Sequence - Part 2": {
+ "Segments": 1,
+ "Acoustic noise reduction": "None",
+ "RF pulse type": "Normal",
+ "Gradient mode": "Normal",
+ "Excitation": "Slice-sel.",
+ "RF spoiling": "On"
+ },
+ "Sequence - Assistant": {
+ "Mode": "Off",
+ "Allowed delay": "0 s"
+ }
+ },
+ "ncanda-t2fse-v1": {
+ "name": "ncanda-t2fse-v1 *",
+ "Id": "71b69d4c-a115-4b00-96f8-d7a3674b4620",
+ "header_property": "TA: 4:21 PM: FIX Voxel size: 0.5\u00d70.5\u00d71.2 mmPAT: 2 Rel. SNR: 1.00 : spc ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slab group": 1,
+ "Slabs": 1,
+ "Position": "L2.2 A23.3 F19.0",
+ "Orientation": "Sagittal",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "Slice oversampling": 0.0,
+ "Slices per slab": 160,
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 1.2,
+ "TR": 3200,
+ "TE": 404,
+ "Averages": 1.0,
+ "Concatenations": 1,
+ "Filter": "Raw filter, Prescan Normalize",
+ "Coil elements": "HE1-4;NE1,2"
+ },
+ "Contrast - Common": {
+ "TR": 3200,
+ "TE": 404,
+ "MTC": "Off",
+ "Magn. preparation": "None",
+ "Fat suppr.": "None",
+ "Blood suppr.": "Off",
+ "Restore magn.": "Off"
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1.0,
+ "Reconstruction": "Magnitude",
+ "Measurements": 1,
+ "Multiple series": "Each measurement"
+ },
+ "Resolution - Common": {
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 1.2,
+ "Base resolution": 256,
+ "Phase resolution": 101,
+ "Slice resolution": 100,
+ "Phase partial Fourier": "Allowed",
+ "Slice partial Fourier": "Off",
+ "Interpolation": "On"
+ },
+ "Resolution - iPAT": {
+ "PAT mode": "GRAPPA",
+ "Accel. factor PE": 2,
+ "Ref. lines PE": 24,
+ "Accel. factor 3D": 1,
+ "Reference scan mode": "Integrated"
+ },
+ "Resolution - Filter Image": {
+ "Image Filter": "Off",
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "On",
+ "Unfiltered images": "Off",
+ "Normalize": "Off",
+ "B1 filter": "Off"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "On",
+ "Elliptical filter": "Off"
+ },
+ "Geometry - Common": {
+ "Slab group": 1,
+ "Slabs": 1,
+ "Position": "L2.2 A23.3 F19.0",
+ "Orientation": "Sagittal",
+ "Phase enc. dir.": "A >> P",
+ "Slice oversampling": 0.0,
+ "Slices per slab": 160,
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 1.2,
+ "TR": 3200,
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slab group": 1,
+ "Position": "L2.2 A23.3 F19.0",
+ "Orientation": "Sagittal",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Initial Position": "L2.2 A23.3 F19.0",
+ "L": 2.2,
+ "A": 23.3,
+ "F": 19.0,
+ "Initial Rotation": 0.0,
+ "Initial Orientation": "Sagittal"
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "None",
+ "Restore magn.": "Off",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "A >> P",
+ "Transversal": "F >> H",
+ "Coil Combine Mode": "Adaptive Combine",
+ "Save uncombined": "Off",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Standard",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L2.2 A23.3 F19.0",
+ "Orientation": "Sagittal",
+ "Rotation": 0.0,
+ "A >> P": 240,
+ "F >> H": 240,
+ "R >> L": 192,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Non-sel."
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "Trigger delay": 0,
+ "TR": 3200,
+ "Concatenations": 1
+ },
+ "Physio - Cardiac": {
+ "Magn. preparation": "None",
+ "Fat suppr.": "None",
+ "Dark blood": "Off",
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Phase resolution": 101
+ },
+ "Physio - PACE": {
+ "Resp. control": "Off",
+ "Concatenations": 1
+ },
+ "Inline - Common": {
+ "Subtract": "Off",
+ "Measurements": 1,
+ "StdDev": "Off",
+ "Save original images": "On"
+ },
+ "Inline - MIP": {
+ "MIP-Sag": "Off",
+ "MIP-Cor": "Off",
+ "MIP-Tra": "Off",
+ "MIP-Time": "Off",
+ "Save original images": "On"
+ },
+ "Inline - Composing": {
+ "Distortion Corr.": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "On",
+ "Dimension": "3D",
+ "Elliptical scanning": "Off",
+ "Reordering": "Linear",
+ "Flow comp.": "No",
+ "Echo spacing": 3.54,
+ "Adiabatic-mode": "Off",
+ "Bandwidth": 751
+ },
+ "Sequence - Part 2": {
+ "Echo train duration": 899,
+ "RF pulse type": "Normal",
+ "Gradient mode": "Fast",
+ "Excitation": "Non-sel.",
+ "Flip angle mode": "T2 var",
+ "Turbo factor": 282
+ },
+ "Sequence - Assistant": {
+ "Allowed delay": "30 s"
+ }
+ },
+ "ncanda-mprage-v1": {
+ "name": "ncanda-mprage-v1 *",
+ "Id": "41a635b2-04bc-4671-a380-87f7326913fe",
+ "header_property": "TA: 8:08 PM: FIX Voxel size: 0.9\u00d70.9\u00d71.2 mmPAT: Off Rel. SNR: 1.00 : tfl ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slab group": 1,
+ "Slabs": 1,
+ "Dist. factor": 50,
+ "Position": "L2.2 A23.3 F19.0",
+ "Orientation": "Sagittal",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "Slice oversampling": 20.0,
+ "Slices per slab": 160,
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 1.2,
+ "TR": 1900.0,
+ "TE": 2.92,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "Prescan Normalize",
+ "Coil elements": "HE1-4;NE1,2"
+ },
+ "Contrast - Common": {
+ "TR": 1900.0,
+ "TE": 2.92,
+ "Magn. preparation": "Non-sel. IR",
+ "TI": 900,
+ "Flip angle": 9,
+ "Fat suppr.": "None",
+ "Water suppr.": "None"
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 1,
+ "Multiple series": "Each measurement"
+ },
+ "Resolution - Common": {
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 1.2,
+ "Base resolution": 256,
+ "Phase resolution": 100,
+ "Slice resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Slice partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - iPAT": {
+ "PAT mode": "None"
+ },
+ "Resolution - Filter Image": {
+ "Image Filter": "Off",
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "On",
+ "Unfiltered images": "Off",
+ "Normalize": "Off",
+ "B1 filter": "Off"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "Off",
+ "Elliptical filter": "Off"
+ },
+ "Geometry - Common": {
+ "Slab group": 1,
+ "Slabs": 1,
+ "Dist. factor": 50,
+ "Position": "L2.2 A23.3 F19.0",
+ "Orientation": "Sagittal",
+ "Phase enc. dir.": "A >> P",
+ "Slice oversampling": 20.0,
+ "Slices per slab": 160,
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 1.2,
+ "TR": 1900.0,
+ "Multi-slice mode": "Single shot",
+ "Series": "Ascending",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slab group": 1,
+ "Position": "L2.2 A23.3 F19.0",
+ "Orientation": "Sagittal",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Initial Position": "L2.2 A23.3 F19.0",
+ "L": 2.2,
+ "A": 23.3,
+ "F": 19.0,
+ "Initial Rotation": 0.0,
+ "Initial Orientation": "Sagittal"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "A >> P",
+ "Transversal": "F >> H",
+ "Coil Combine Mode": "Adaptive Combine",
+ "Save uncombined": "Off",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Standard",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "On",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L2.2 A23.3 F19.0",
+ "Orientation": "Sagittal",
+ "Rotation": 0.0,
+ "A >> P": 240,
+ "F >> H": 240,
+ "R >> L": 192,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Non-sel."
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "Low",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 1900.0,
+ "Concatenations": 1
+ },
+ "Physio - Cardiac": {
+ "Magn. preparation": "Non-sel. IR",
+ "TI": 900,
+ "Fat suppr.": "None",
+ "Dark blood": "Off",
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Phase resolution": 100
+ },
+ "Physio - PACE": {
+ "Resp. control": "Off",
+ "Concatenations": 1
+ },
+ "Inline - Common": {
+ "Subtract": "Off",
+ "Measurements": 1,
+ "StdDev": "Off",
+ "Save original images": "On"
+ },
+ "Inline - MIP": {
+ "MIP-Sag": "Off",
+ "MIP-Cor": "Off",
+ "MIP-Tra": "Off",
+ "MIP-Time": "Off",
+ "Save original images": "On"
+ },
+ "Inline - Composing": {
+ "Distortion Corr.": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "On",
+ "Dimension": "3D",
+ "Elliptical scanning": "Off",
+ "Reordering": "Linear",
+ "Asymmetric echo": "Allowed",
+ "Flow comp.": "No",
+ "Multi-slice mode": "Single shot",
+ "Echo spacing": 8.7,
+ "Bandwidth": 140
+ },
+ "Sequence - Part 2": {
+ "RF pulse type": "Normal",
+ "Gradient mode": "Normal",
+ "Excitation": "Non-sel.",
+ "RF spoiling": "On",
+ "Incr. Gradient spoiling": "Off",
+ "Turbo factor": 192
+ },
+ "Sequence - Assistant": {
+ "Mode": "Off"
+ }
+ },
+ "ncanda-dti6b500pepolar-v1": {
+ "name": "ncanda-dti6b500pepolar-v1 *",
+ "Id": "169569d5-55eb-40e1-9ca1-25ac8bfe21ff",
+ "header_property": "TA: 1:22 PM: FIX Voxel size: 2.5\u00d72.5\u00d72.5 mmPAT: 2 Rel. SNR: 1.00 : epse ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 1,
+ "Slices": 64,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "TR": 8000,
+ "TE": 89.0,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "Raw filter",
+ "Coil elements": "HE1-4"
+ },
+ "Contrast - Common": {
+ "TR": 8000,
+ "TE": 89.0,
+ "MTC": "Off",
+ "Magn. preparation": "None",
+ "Fat suppr.": "Fat sat.",
+ "Fat sat. mode": "Weak"
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 1,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Resolution - Common": {
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "Base resolution": 96,
+ "Phase resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - iPAT": {
+ "Accel. mode": "GRAPPA",
+ "Accel. factor PE": 2,
+ "Ref. lines PE": 38,
+ "Reference scan mode": "EPI/separate"
+ },
+ "Resolution - Filter Image": {
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "Off",
+ "Dynamic Field Corr.": "Off"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "On",
+ "Elliptical filter": "Off"
+ },
+ "Geometry - Common": {
+ "Slice group": 1,
+ "Slices": 64,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "A >> P",
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "TR": 8000,
+ "Multi-slice mode": "Interleaved",
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 1,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Initial Position": "L0.7 A21.9 F2.6",
+ "L": 0.7,
+ "A": 21.9,
+ "F": 2.6,
+ "Initial Rotation": 0.0,
+ "Initial Orientation": "Transversal"
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "Fat sat.",
+ "Fat sat. mode": "Weak",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "A >> P",
+ "Transversal": "F >> H",
+ "Coil Combine Mode": "Adaptive Combine",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Advanced",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Rotation": 0.0,
+ "A >> P": 240,
+ "R >> L": 240,
+ "F >> H": 160,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Standard"
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 8000,
+ "Concatenations": 1
+ },
+ "Physio - PACE": {
+ "Resp. control": "Off",
+ "Concatenations": 1
+ },
+ "Diff - Neuro": {
+ "Diffusion mode": "MDDW",
+ "Diff. directions": 6,
+ "Diffusion Scheme": "Bipolar",
+ "Diff. weightings": 2,
+ "b-value 1": 1,
+ "b-value 2": 1,
+ "Diff. weighted images": "On",
+ "Trace weighted images": "On",
+ "ADC maps": "Off",
+ "FA maps": "Off",
+ "Mosaic": "On",
+ "Tensor": "Off",
+ "Noise level": 40
+ },
+ "Diff - Body": {
+ "Diffusion mode": "MDDW",
+ "Diff. directions": 6,
+ "Diffusion Scheme": "Bipolar",
+ "Diff. weightings": 2,
+ "b-value 1": 1,
+ "b-value 2": 1,
+ "Diff. weighted images": "On",
+ "Trace weighted images": "On",
+ "ADC maps": "Off",
+ "Exponential ADC Maps": "Off",
+ "FA maps": "Off",
+ "Invert Gray Scale": "Off",
+ "Calculated Image": "Off",
+ "b-Value >=": "0 s/mm\u00b2",
+ "Noise level": 40
+ },
+ "Diff - Composing": {
+ "Distortion Corr.": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "On",
+ "Optimization": "None",
+ "Multi-slice mode": "Interleaved",
+ "Free echo spacing": "Off",
+ "Echo spacing": 0.62,
+ "Bandwidth": 1860
+ },
+ "Sequence - Part 2": {
+ "EPI factor": 96,
+ "RF pulse type": "Normal",
+ "Gradient mode": "Fast",
+ "Excitation": "Standard"
+ }
+ },
+ "ncanda-dti60b1000-v1": {
+ "name": "ncanda-dti60b1000-v1 *",
+ "Id": "e7a4335c-8a0a-42fa-8ba5-e18fa22dc0d1",
+ "header_property": "TA: 8:42 PM: FIX Voxel size: 2.5\u00d72.5\u00d72.5 mmPAT: 2 Rel. SNR: 1.00 : epse ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 1,
+ "Slices": 64,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "TR": 8000,
+ "TE": 89.0,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "Raw filter",
+ "Coil elements": "HE1-4"
+ },
+ "Contrast - Common": {
+ "TR": 8000,
+ "TE": 89.0,
+ "MTC": "Off",
+ "Magn. preparation": "None",
+ "Fat suppr.": "Fat sat.",
+ "Fat sat. mode": "Weak"
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 1,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Resolution - Common": {
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "Base resolution": 96,
+ "Phase resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - iPAT": {
+ "Accel. mode": "GRAPPA",
+ "Accel. factor PE": 2,
+ "Ref. lines PE": 38,
+ "Reference scan mode": "EPI/separate"
+ },
+ "Resolution - Filter Image": {
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "Off",
+ "Dynamic Field Corr.": "Off"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "On",
+ "Elliptical filter": "Off"
+ },
+ "Geometry - Common": {
+ "Slice group": 1,
+ "Slices": 64,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "TR": 8000,
+ "Multi-slice mode": "Interleaved",
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 1,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "AutoAlign": "---",
+ "Initial Position": "L0.7 A21.9 F2.6",
+ "L": 0.7,
+ "A": 21.9,
+ "F": 2.6,
+ "Initial Rotation": -180.0,
+ "Initial Orientation": "Transversal"
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "Fat sat.",
+ "Fat sat. mode": "Weak",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "A >> P",
+ "Transversal": "F >> H",
+ "Coil Combine Mode": "Adaptive Combine",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Advanced",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Rotation": 180.0,
+ "A >> P": 240,
+ "R >> L": 240,
+ "F >> H": 160,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Standard"
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 8000,
+ "Concatenations": 1
+ },
+ "Physio - PACE": {
+ "Resp. control": "Off",
+ "Concatenations": 1
+ },
+ "Diff - Neuro": {
+ "Diffusion mode": "Free",
+ "Diff. directions": 61,
+ "Diffusion Scheme": "Bipolar",
+ "Diff. weightings": 2,
+ "b-value 1": 1,
+ "b-value 2": 1,
+ "Diff. weighted images": "On",
+ "Trace weighted images": "On",
+ "ADC maps": "On",
+ "FA maps": "On",
+ "Mosaic": "On",
+ "Tensor": "On",
+ "Noise level": 40
+ },
+ "Diff - Body": {
+ "Diffusion mode": "Free",
+ "Diff. directions": 61,
+ "Diffusion Scheme": "Bipolar",
+ "Diff. weightings": 2,
+ "b-value 1": 1,
+ "b-value 2": 1,
+ "Diff. weighted images": "On",
+ "Trace weighted images": "On",
+ "ADC maps": "On",
+ "Exponential ADC Maps": "Off",
+ "FA maps": "On",
+ "Invert Gray Scale": "Off",
+ "Calculated Image": "Off",
+ "b-Value >=": "0 s/mm\u00b2",
+ "Noise level": 40
+ },
+ "Diff - Composing": {
+ "Distortion Corr.": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "On",
+ "Optimization": "None",
+ "Multi-slice mode": "Interleaved",
+ "Free echo spacing": "Off",
+ "Echo spacing": 0.62,
+ "Bandwidth": 1860
+ },
+ "Sequence - Part 2": {
+ "EPI factor": 96,
+ "RF pulse type": "Normal",
+ "Gradient mode": "Fast",
+ "Excitation": "Standard"
+ }
+ },
+ "ncanda-dti30b400-v1": {
+ "name": "ncanda-dti30b400-v1 *",
+ "Id": "5ea94598-904e-4b51-8c79-6238a9e2beb6",
+ "header_property": "TA: 4:42 PM: FIX Voxel size: 2.5\u00d72.5\u00d72.5 mmPAT: 2 Rel. SNR: 1.00 : epse ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 1,
+ "Slices": 64,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "TR": 8000,
+ "TE": 89.0,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "Raw filter",
+ "Coil elements": "HE1-4"
+ },
+ "Contrast - Common": {
+ "TR": 8000,
+ "TE": 89.0,
+ "MTC": "Off",
+ "Magn. preparation": "None",
+ "Fat suppr.": "Fat sat.",
+ "Fat sat. mode": "Weak"
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 1,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Resolution - Common": {
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "Base resolution": 96,
+ "Phase resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - iPAT": {
+ "Accel. mode": "GRAPPA",
+ "Accel. factor PE": 2,
+ "Ref. lines PE": 38,
+ "Reference scan mode": "EPI/separate"
+ },
+ "Resolution - Filter Image": {
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "Off",
+ "Dynamic Field Corr.": "Off"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "On",
+ "Elliptical filter": "Off"
+ },
+ "Geometry - Common": {
+ "Slice group": 1,
+ "Slices": 64,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "TR": 8000,
+ "Multi-slice mode": "Interleaved",
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 1,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "AutoAlign": "---",
+ "Initial Position": "L0.7 A21.9 F2.6",
+ "L": 0.7,
+ "A": 21.9,
+ "F": 2.6,
+ "Initial Rotation": -180.0,
+ "Initial Orientation": "Transversal"
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "Fat sat.",
+ "Fat sat. mode": "Weak",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "A >> P",
+ "Transversal": "F >> H",
+ "Coil Combine Mode": "Adaptive Combine",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Advanced",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Rotation": 180.0,
+ "A >> P": 240,
+ "R >> L": 240,
+ "F >> H": 160,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Standard"
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 8000,
+ "Concatenations": 1
+ },
+ "Physio - PACE": {
+ "Resp. control": "Off",
+ "Concatenations": 1
+ },
+ "Diff - Neuro": {
+ "Diffusion mode": "Free",
+ "Diff. directions": 31,
+ "Diffusion Scheme": "Bipolar",
+ "Diff. weightings": 2,
+ "b-value 1": 1,
+ "b-value 2": 1,
+ "Diff. weighted images": "On",
+ "Trace weighted images": "On",
+ "ADC maps": "On",
+ "FA maps": "On",
+ "Mosaic": "On",
+ "Tensor": "On",
+ "Noise level": 40
+ },
+ "Diff - Body": {
+ "Diffusion mode": "Free",
+ "Diff. directions": 31,
+ "Diffusion Scheme": "Bipolar",
+ "Diff. weightings": 2,
+ "b-value 1": 1,
+ "b-value 2": 1,
+ "Diff. weighted images": "On",
+ "Trace weighted images": "On",
+ "ADC maps": "On",
+ "Exponential ADC Maps": "Off",
+ "FA maps": "On",
+ "Invert Gray Scale": "Off",
+ "Calculated Image": "Off",
+ "b-Value >=": "0 s/mm\u00b2",
+ "Noise level": 40
+ },
+ "Diff - Composing": {
+ "Distortion Corr.": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "On",
+ "Optimization": "None",
+ "Multi-slice mode": "Interleaved",
+ "Free echo spacing": "Off",
+ "Echo spacing": 0.62,
+ "Bandwidth": 1860
+ },
+ "Sequence - Part 2": {
+ "EPI factor": 96,
+ "RF pulse type": "Normal",
+ "Gradient mode": "Fast",
+ "Excitation": "Standard"
+ }
+ },
+ "ncanda-grefieldmap-v1": {
+ "name": "ncanda-grefieldmap-v1 *",
+ "Id": "085ebe03-a8f3-4906-a572-d443167d1ff8",
+ "header_property": "TA: 2:26 PM: FIX Voxel size: 2.5\u00d72.5\u00d72.5 mmRel. SNR: 1.00 : fm_r ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 1,
+ "Slices": 64,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "TR": 752.0,
+ "TE 1": 5.68,
+ "TE 2": 8.14,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "None",
+ "Coil elements": "HE1-4"
+ },
+ "Contrast - Common": {
+ "TR": 752.0,
+ "TE 1": 5.68,
+ "TE 2": 8.14,
+ "MTC": "Off",
+ "Flip angle": 60,
+ "Fat suppr.": "None"
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magn./Phase",
+ "Measurements": 1,
+ "Multiple series": "Off"
+ },
+ "Resolution - Common": {
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "Base resolution": 96,
+ "Phase resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - Filter Image": {
+ "Image Filter": "Off",
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "Off",
+ "Normalize": "Off",
+ "B1 filter": "Off"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "Off",
+ "Elliptical filter": "Off"
+ },
+ "Geometry - Common": {
+ "Slice group": 1,
+ "Slices": 64,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 2.5,
+ "TR": 752.0,
+ "Multi-slice mode": "Interleaved",
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 1,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "AutoAlign": "---",
+ "Initial Position": "L0.7 A21.9 F2.6",
+ "L": 0.7,
+ "A": 21.9,
+ "F": 2.6,
+ "Initial Rotation": -180.0,
+ "Initial Orientation": "Transversal"
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "None",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "A >> P",
+ "Transversal": "F >> H",
+ "Coil Combine Mode": "Sum of Squares",
+ "Save uncombined": "Off",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Advanced",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "! Position": "L0.7 A21.9 F2.6",
+ "! Orientation": "Transversal",
+ "! Rotation": 180.0,
+ "! A >> P": 240,
+ "! R >> L": 240,
+ "! F >> H": 160,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm"
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "Off",
+ "Dimension": "2D",
+ "Asymmetric echo": "Off",
+ "Contrasts": 2,
+ "Flow comp.": "Yes",
+ "Multi-slice mode": "Interleaved",
+ "Bandwidth": 266
+ },
+ "Sequence - Part 2": {
+ "RF pulse type": "Normal",
+ "Gradient mode": "Normal",
+ "RF spoiling": "On"
+ },
+ "Sequence - Assistant": {
+ "Mode": "Off"
+ }
+ },
+ "ncanda-rsfmri-v1": {
+ "name": "ncanda-rsfmri-v1 *",
+ "Id": "44597b9a-f741-4998-8716-43937802e15c",
+ "header_property": "TA: 12:13 PM: FIX Voxel size: 3.8\u00d73.8\u00d75.0 mmPAT: 2 Rel. SNR: 1.00 : epfid ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 1,
+ "Slices": 32,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 5.0,
+ "TR": 2200,
+ "TE": 30.0,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "Prescan Normalize",
+ "Coil elements": "HE1-4"
+ },
+ "Contrast - Common": {
+ "TR": 2200,
+ "TE": 30.0,
+ "MTC": "Off",
+ "Flip angle": 79,
+ "Fat suppr.": "Fat sat."
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 330,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Resolution - Common": {
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 5.0,
+ "Base resolution": 64,
+ "Phase resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - iPAT": {
+ "Accel. mode": "GRAPPA",
+ "Accel. factor PE": 2,
+ "Ref. lines PE": 24,
+ "Reference scan mode": "EPI/separate"
+ },
+ "Resolution - Filter Image": {
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "On"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "Off",
+ "Elliptical filter": "Off",
+ "Hamming": "Off"
+ },
+ "Geometry - Common": {
+ "Slice group": 1,
+ "Slices": 32,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 5.0,
+ "TR": 2200,
+ "Multi-slice mode": "Interleaved",
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 1,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "AutoAlign": "---",
+ "Initial Position": "L0.7 A21.9 F2.6",
+ "L": 0.7,
+ "A": 21.9,
+ "F": 2.6,
+ "Initial Rotation": -180.0,
+ "Initial Orientation": "Transversal"
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "Fat sat.",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "A >> P",
+ "Transversal": "F >> H",
+ "Coil Combine Mode": "Sum of Squares",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Advanced",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Rotation": 180.0,
+ "A >> P": 240,
+ "R >> L": 240,
+ "F >> H": 160,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Standard"
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 2200,
+ "Concatenations": 1
+ },
+ "BOLD": {
+ "GLM Statistics": "Off",
+ "Dynamic t-maps": "Off",
+ "Ignore meas. at start": 0,
+ "Ignore after transition": 0,
+ "Model transition states": "On",
+ "Temp. highpass filter": "On",
+ "Threshold": 4.0,
+ "Paradigm size": 3,
+ "Meas[1]": "Baseline",
+ "Meas[2]": "Baseline",
+ "Meas[3]": "Active",
+ "Motion correction": "On",
+ "Spatial filter": "Off",
+ "Measurements": 330,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "Off",
+ "Multi-slice mode": "Interleaved",
+ "Free echo spacing": "Off",
+ "Echo spacing": 0.55,
+ "Bandwidth": 2170
+ },
+ "Sequence - Part 2": {
+ "EPI factor": 64,
+ "RF pulse type": "Normal",
+ "Gradient mode": "Fast*",
+ "Excitation": "Standard"
+ }
+ },
+ "ncanda-fmri-ringrewards-v1": {
+ "name": "ncanda-fmri-ringrewards-v1 *",
+ "Id": "ce4f59a6-862b-4957-a986-170f2c19f731",
+ "header_property": "TA: 5:12 PM: FIX Voxel size: 3.1\u00d73.1\u00d73.2 mmPAT: 2 Rel. SNR: 1.00 : epfid ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 1,
+ "Slices": 29,
+ "Dist. factor": 0,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "TR": 1520,
+ "TE": 28.0,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "Prescan Normalize",
+ "Coil elements": "HE1-4"
+ },
+ "Contrast - Common": {
+ "TR": 1520,
+ "TE": 28.0,
+ "MTC": "Off",
+ "Flip angle": 73,
+ "Fat suppr.": "Fat sat."
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 202,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Resolution - Common": {
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "Base resolution": 64,
+ "Phase resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - iPAT": {
+ "Accel. mode": "GRAPPA",
+ "Accel. factor PE": 2,
+ "Ref. lines PE": 24,
+ "Reference scan mode": "EPI/separate"
+ },
+ "Resolution - Filter Image": {
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "On"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "Off",
+ "Elliptical filter": "Off",
+ "Hamming": "Off"
+ },
+ "Geometry - Common": {
+ "Slice group": 1,
+ "Slices": 29,
+ "Dist. factor": 0,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "TR": 1520,
+ "Multi-slice mode": "Interleaved",
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 1,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Initial Position": "L0.0 A12.6 H18.8",
+ "L": 0.0,
+ "A": 12.6,
+ "H": 18.8,
+ "Initial Rotation": 0.0,
+ "Initial Orientation": "T > C",
+ "T > C": -2.3,
+ "> S": 0.0
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "Fat sat.",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "P >> A",
+ "Transversal": "H >> F",
+ "Coil Combine Mode": "Sum of Squares",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Advanced",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Rotation": 0.0,
+ "A >> P": 200,
+ "R >> L": 200,
+ "F >> H": 93,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Standard"
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 1520,
+ "Concatenations": 1
+ },
+ "BOLD": {
+ "GLM Statistics": "Off",
+ "Dynamic t-maps": "Off",
+ "Ignore meas. at start": 0,
+ "Ignore after transition": 0,
+ "Model transition states": "On",
+ "Temp. highpass filter": "On",
+ "Threshold": 4.0,
+ "Paradigm size": 30,
+ "Meas[1]": "Active",
+ "Meas[2]": "Active",
+ "Meas[3]": "Active",
+ "Meas[4]": "Active",
+ "Meas[5]": "Active",
+ "Meas[6]": "Active",
+ "Meas[7]": "Active",
+ "Meas[8]": "Active",
+ "Meas[9]": "Active",
+ "Meas[10]": "Active",
+ "Meas[11]": "Active",
+ "Meas[12]": "Active",
+ "Meas[13]": "Active",
+ "Meas[14]": "Active",
+ "Meas[15]": "Active",
+ "Meas[16]": "Baseline",
+ "Meas[17]": "Baseline",
+ "Meas[18]": "Baseline",
+ "Meas[19]": "Baseline",
+ "Meas[20]": "Baseline",
+ "Meas[21]": "Baseline",
+ "Meas[22]": "Baseline",
+ "Meas[23]": "Baseline",
+ "Meas[24]": "Baseline",
+ "Meas[25]": "Baseline",
+ "Meas[26]": "Baseline",
+ "Meas[27]": "Baseline",
+ "Meas[28]": "Baseline",
+ "Meas[29]": "Baseline",
+ "Meas[30]": "Baseline",
+ "Motion correction": "On",
+ "Spatial filter": "Off",
+ "Measurements": 202,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "Off",
+ "Multi-slice mode": "Interleaved",
+ "Free echo spacing": "Off",
+ "Echo spacing": 0.55,
+ "Bandwidth": 2170
+ },
+ "Sequence - Part 2": {
+ "EPI factor": 64,
+ "RF pulse type": "Normal",
+ "Gradient mode": "Fast*",
+ "Excitation": "Standard"
+ }
+ },
+ "ncanda-fmri-ringrewards-v2": {
+ "name": "ncanda-fmri-ringrewards-v2 *",
+ "Id": "351278bb-2e68-4d31-a815-57f3c2c5b7f7",
+ "header_property": "TA: 5:12 PM: FIX Voxel size: 3.1\u00d73.1\u00d73.2 mmPAT: 2 Rel. SNR: 1.00 : epfid ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 1,
+ "Slices": 29,
+ "Dist. factor": 0,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "TR": 1520,
+ "TE": 28.0,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "Prescan Normalize",
+ "Coil elements": "HE1-4"
+ },
+ "Contrast - Common": {
+ "TR": 1520,
+ "TE": 28.0,
+ "MTC": "Off",
+ "Flip angle": 73,
+ "Fat suppr.": "Fat sat."
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 202,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Resolution - Common": {
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "Base resolution": 64,
+ "Phase resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - iPAT": {
+ "Accel. mode": "GRAPPA",
+ "Accel. factor PE": 2,
+ "Ref. lines PE": 24,
+ "Reference scan mode": "EPI/separate"
+ },
+ "Resolution - Filter Image": {
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "On"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "Off",
+ "Elliptical filter": "Off",
+ "Hamming": "Off"
+ },
+ "Geometry - Common": {
+ "Slice group": 1,
+ "Slices": 29,
+ "Dist. factor": 0,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "TR": 1520,
+ "Multi-slice mode": "Interleaved",
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 1,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Initial Position": "L0.0 A12.6 H18.8",
+ "L": 0.0,
+ "A": 12.6,
+ "H": 18.8,
+ "Initial Rotation": 0.0,
+ "Initial Orientation": "T > C",
+ "T > C": -2.3,
+ "> S": 0.0
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "Fat sat.",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "P >> A",
+ "Transversal": "H >> F",
+ "Coil Combine Mode": "Sum of Squares",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Advanced",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Rotation": 0.0,
+ "A >> P": 200,
+ "R >> L": 200,
+ "F >> H": 93,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Standard"
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 1520,
+ "Concatenations": 1
+ },
+ "BOLD": {
+ "GLM Statistics": "Off",
+ "Dynamic t-maps": "Off",
+ "Ignore meas. at start": 0,
+ "Ignore after transition": 0,
+ "Model transition states": "On",
+ "Temp. highpass filter": "On",
+ "Threshold": 4.0,
+ "Paradigm size": 30,
+ "Meas[1]": "Active",
+ "Meas[2]": "Active",
+ "Meas[3]": "Active",
+ "Meas[4]": "Active",
+ "Meas[5]": "Active",
+ "Meas[6]": "Active",
+ "Meas[7]": "Active",
+ "Meas[8]": "Active",
+ "Meas[9]": "Active",
+ "Meas[10]": "Active",
+ "Meas[11]": "Active",
+ "Meas[12]": "Active",
+ "Meas[13]": "Active",
+ "Meas[14]": "Active",
+ "Meas[15]": "Active",
+ "Meas[16]": "Baseline",
+ "Meas[17]": "Baseline",
+ "Meas[18]": "Baseline",
+ "Meas[19]": "Baseline",
+ "Meas[20]": "Baseline",
+ "Meas[21]": "Baseline",
+ "Meas[22]": "Baseline",
+ "Meas[23]": "Baseline",
+ "Meas[24]": "Baseline",
+ "Meas[25]": "Baseline",
+ "Meas[26]": "Baseline",
+ "Meas[27]": "Baseline",
+ "Meas[28]": "Baseline",
+ "Meas[29]": "Baseline",
+ "Meas[30]": "Baseline",
+ "Motion correction": "On",
+ "Spatial filter": "Off",
+ "Measurements": 202,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "Off",
+ "Multi-slice mode": "Interleaved",
+ "Free echo spacing": "Off",
+ "Echo spacing": 0.55,
+ "Bandwidth": 2170
+ },
+ "Sequence - Part 2": {
+ "EPI factor": 64,
+ "RF pulse type": "Normal",
+ "Gradient mode": "Fast*",
+ "Excitation": "Standard"
+ }
+ },
+ "ncanda-fmri-ringrewards-v3": {
+ "name": "ncanda-fmri-ringrewards-v3 *",
+ "Id": "60970f18-de0a-4925-893c-c03bd70e923f",
+ "header_property": "TA: 5:12 PM: FIX Voxel size: 3.1\u00d73.1\u00d73.2 mmPAT: 2 Rel. SNR: 1.00 : epfid ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 1,
+ "Slices": 29,
+ "Dist. factor": 0,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "TR": 1520,
+ "TE": 28.0,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "Prescan Normalize",
+ "Coil elements": "HE1-4"
+ },
+ "Contrast - Common": {
+ "TR": 1520,
+ "TE": 28.0,
+ "MTC": "Off",
+ "Flip angle": 73,
+ "Fat suppr.": "Fat sat."
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 202,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Resolution - Common": {
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "Base resolution": 64,
+ "Phase resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - iPAT": {
+ "Accel. mode": "GRAPPA",
+ "Accel. factor PE": 2,
+ "Ref. lines PE": 24,
+ "Reference scan mode": "EPI/separate"
+ },
+ "Resolution - Filter Image": {
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "On"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "Off",
+ "Elliptical filter": "Off",
+ "Hamming": "Off"
+ },
+ "Geometry - Common": {
+ "Slice group": 1,
+ "Slices": 29,
+ "Dist. factor": 0,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "TR": 1520,
+ "Multi-slice mode": "Interleaved",
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 1,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Initial Position": "L0.0 A12.6 H18.8",
+ "L": 0.0,
+ "A": 12.6,
+ "H": 18.8,
+ "Initial Rotation": 0.0,
+ "Initial Orientation": "T > C",
+ "T > C": -2.3,
+ "> S": 0.0
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "Fat sat.",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "P >> A",
+ "Transversal": "H >> F",
+ "Coil Combine Mode": "Sum of Squares",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Advanced",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Rotation": 0.0,
+ "A >> P": 200,
+ "R >> L": 200,
+ "F >> H": 93,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Standard"
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 1520,
+ "Concatenations": 1
+ },
+ "BOLD": {
+ "GLM Statistics": "Off",
+ "Dynamic t-maps": "Off",
+ "Ignore meas. at start": 0,
+ "Ignore after transition": 0,
+ "Model transition states": "On",
+ "Temp. highpass filter": "On",
+ "Threshold": 4.0,
+ "Paradigm size": 30,
+ "Meas[1]": "Active",
+ "Meas[2]": "Active",
+ "Meas[3]": "Active",
+ "Meas[4]": "Active",
+ "Meas[5]": "Active",
+ "Meas[6]": "Active",
+ "Meas[7]": "Active",
+ "Meas[8]": "Active",
+ "Meas[9]": "Active",
+ "Meas[10]": "Active",
+ "Meas[11]": "Active",
+ "Meas[12]": "Active",
+ "Meas[13]": "Active",
+ "Meas[14]": "Active",
+ "Meas[15]": "Active",
+ "Meas[16]": "Baseline",
+ "Meas[17]": "Baseline",
+ "Meas[18]": "Baseline",
+ "Meas[19]": "Baseline",
+ "Meas[20]": "Baseline",
+ "Meas[21]": "Baseline",
+ "Meas[22]": "Baseline",
+ "Meas[23]": "Baseline",
+ "Meas[24]": "Baseline",
+ "Meas[25]": "Baseline",
+ "Meas[26]": "Baseline",
+ "Meas[27]": "Baseline",
+ "Meas[28]": "Baseline",
+ "Meas[29]": "Baseline",
+ "Meas[30]": "Baseline",
+ "Motion correction": "On",
+ "Spatial filter": "Off",
+ "Measurements": 202,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "Off",
+ "Multi-slice mode": "Interleaved",
+ "Free echo spacing": "Off",
+ "Echo spacing": 0.55,
+ "Bandwidth": 2170
+ },
+ "Sequence - Part 2": {
+ "EPI factor": 64,
+ "RF pulse type": "Normal",
+ "Gradient mode": "Fast*",
+ "Excitation": "Standard"
+ }
+ },
+ "ncanda-fmri-ringrewards-v4": {
+ "name": "ncanda-fmri-ringrewards-v4 *",
+ "Id": "33428fda-9313-4dd2-868a-31f924864840",
+ "header_property": "TA: 5:12 PM: FIX Voxel size: 3.1\u00d73.1\u00d73.2 mmPAT: 2 Rel. SNR: 1.00 : epfid ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 1,
+ "Slices": 29,
+ "Dist. factor": 0,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "TR": 1520,
+ "TE": 28.0,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "Prescan Normalize",
+ "Coil elements": "HE1-4"
+ },
+ "Contrast - Common": {
+ "TR": 1520,
+ "TE": 28.0,
+ "MTC": "Off",
+ "Flip angle": 73,
+ "Fat suppr.": "Fat sat."
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 202,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Resolution - Common": {
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "Base resolution": 64,
+ "Phase resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - iPAT": {
+ "Accel. mode": "GRAPPA",
+ "Accel. factor PE": 2,
+ "Ref. lines PE": 24,
+ "Reference scan mode": "EPI/separate"
+ },
+ "Resolution - Filter Image": {
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "On"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "Off",
+ "Elliptical filter": "Off",
+ "Hamming": "Off"
+ },
+ "Geometry - Common": {
+ "Slice group": 1,
+ "Slices": 29,
+ "Dist. factor": 0,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "FoV read": 200,
+ "FoV phase": 100.0,
+ "Slice thickness": 3.2,
+ "TR": 1520,
+ "Multi-slice mode": "Interleaved",
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 1,
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Phase enc. dir.": "A >> P",
+ "AutoAlign": "---",
+ "Initial Position": "L0.0 A12.6 H18.8",
+ "L": 0.0,
+ "A": 12.6,
+ "H": 18.8,
+ "Initial Rotation": 0.0,
+ "Initial Orientation": "T > C",
+ "T > C": -2.3,
+ "> S": 0.0
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "Fat sat.",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "P >> A",
+ "Transversal": "H >> F",
+ "Coil Combine Mode": "Sum of Squares",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Advanced",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L0.0 A12.6 H18.8",
+ "Orientation": "T > C-2.3",
+ "Rotation": 0.0,
+ "A >> P": 200,
+ "R >> L": 200,
+ "F >> H": 93,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Standard"
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 1520,
+ "Concatenations": 1
+ },
+ "BOLD": {
+ "GLM Statistics": "Off",
+ "Dynamic t-maps": "Off",
+ "Ignore meas. at start": 0,
+ "Ignore after transition": 0,
+ "Model transition states": "On",
+ "Temp. highpass filter": "On",
+ "Threshold": 4.0,
+ "Paradigm size": 30,
+ "Meas[1]": "Active",
+ "Meas[2]": "Active",
+ "Meas[3]": "Active",
+ "Meas[4]": "Active",
+ "Meas[5]": "Active",
+ "Meas[6]": "Active",
+ "Meas[7]": "Active",
+ "Meas[8]": "Active",
+ "Meas[9]": "Active",
+ "Meas[10]": "Active",
+ "Meas[11]": "Active",
+ "Meas[12]": "Active",
+ "Meas[13]": "Active",
+ "Meas[14]": "Active",
+ "Meas[15]": "Active",
+ "Meas[16]": "Baseline",
+ "Meas[17]": "Baseline",
+ "Meas[18]": "Baseline",
+ "Meas[19]": "Baseline",
+ "Meas[20]": "Baseline",
+ "Meas[21]": "Baseline",
+ "Meas[22]": "Baseline",
+ "Meas[23]": "Baseline",
+ "Meas[24]": "Baseline",
+ "Meas[25]": "Baseline",
+ "Meas[26]": "Baseline",
+ "Meas[27]": "Baseline",
+ "Meas[28]": "Baseline",
+ "Meas[29]": "Baseline",
+ "Meas[30]": "Baseline",
+ "Motion correction": "On",
+ "Spatial filter": "Off",
+ "Measurements": 202,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "Off",
+ "Multi-slice mode": "Interleaved",
+ "Free echo spacing": "Off",
+ "Echo spacing": 0.55,
+ "Bandwidth": 2170
+ },
+ "Sequence - Part 2": {
+ "EPI factor": 64,
+ "RF pulse type": "Normal",
+ "Gradient mode": "Fast*",
+ "Excitation": "Standard"
+ }
+ },
+ "ncanda-alcpic-v1": {
+ "name": "ncanda-alcpic-v1 *",
+ "Id": "93dd8d6a-f858-491b-b515-b26004eb1f0b",
+ "header_property": "TA: 12:06 PM: FIX Voxel size: 3.8\u00d73.8\u00d75.0 mmPAT: 2 Rel. SNR: 1.00 : epfid ",
+ "Properties": {
+ "Prio recon": "Off",
+ "Load images to viewer": "On",
+ "Inline movie": "Off",
+ "Auto store images": "On",
+ "Load images to stamp segments": "Off",
+ "Load images to graphic segments": "Off",
+ "Auto open inline display": "Off",
+ "Auto close inline display": "Off",
+ "Start measurement without further preparation": "Off",
+ "Wait for user to start": "On",
+ "Start measurements": "Single measurement"
+ },
+ "Routine": {
+ "Slice group": 1,
+ "Slices": 32,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "AutoAlign": "---",
+ "Phase oversampling": 0,
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 5.0,
+ "TR": 2000,
+ "TE": 30.0,
+ "Averages": 1,
+ "Concatenations": 1,
+ "Filter": "Prescan Normalize",
+ "Coil elements": "HE1-4"
+ },
+ "Contrast - Common": {
+ "TR": 2000,
+ "TE": 30.0,
+ "MTC": "Off",
+ "Flip angle": 79,
+ "Fat suppr.": "Fat sat."
+ },
+ "Contrast - Dynamic": {
+ "Averages": 1,
+ "Averaging mode": "Long term",
+ "Reconstruction": "Magnitude",
+ "Measurements": 360,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Resolution - Common": {
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 5.0,
+ "Base resolution": 64,
+ "Phase resolution": 100,
+ "Phase partial Fourier": "Off",
+ "Interpolation": "Off"
+ },
+ "Resolution - iPAT": {
+ "Accel. mode": "GRAPPA",
+ "Accel. factor PE": 2,
+ "Ref. lines PE": 24,
+ "Reference scan mode": "EPI/separate"
+ },
+ "Resolution - Filter Image": {
+ "Distortion Corr.": "Off",
+ "Prescan Normalize": "On"
+ },
+ "Resolution - Filter Rawdata": {
+ "Raw filter": "Off",
+ "Elliptical filter": "Off",
+ "Hamming": "Off"
+ },
+ "Geometry - Common": {
+ "Slice group": 1,
+ "Slices": 32,
+ "Dist. factor": 0,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "FoV read": 240,
+ "FoV phase": 100.0,
+ "Slice thickness": 5.0,
+ "TR": 2000,
+ "Multi-slice mode": "Interleaved",
+ "Series": "Interleaved",
+ "Concatenations": 1
+ },
+ "Geometry - AutoAlign": {
+ "Slice group": 1,
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Phase enc. dir.": "P >> A",
+ "AutoAlign": "---",
+ "Initial Position": "L0.7 A21.9 F2.6",
+ "L": 0.7,
+ "A": 21.9,
+ "F": 2.6,
+ "Initial Rotation": -180.0,
+ "Initial Orientation": "Transversal"
+ },
+ "Geometry - Saturation": {
+ "Fat suppr.": "Fat sat.",
+ "Special sat.": "None"
+ },
+ "System - Miscellaneous": {
+ "Positioning mode": "FIX",
+ "Table position": 0,
+ "MSMA": "S - C - T",
+ "Sagittal": "R >> L",
+ "Coronal": "A >> P",
+ "Transversal": "F >> H",
+ "Coil Combine Mode": "Sum of Squares",
+ "Matrix Optimization": "Off",
+ "AutoAlign": "---",
+ "Coil Select Mode": "On - AutoCoilSelect"
+ },
+ "System - Adjustments": {
+ "B0 Shim mode": "Advanced",
+ "B1 Shim mode": "TrueForm",
+ "Adjust with body coil": "Off",
+ "Confirm freq. adjustment": "Off",
+ "Assume Dominant Fat": "Off",
+ "Assume Silicone": "Off",
+ "Adjustment Tolerance": "Auto"
+ },
+ "System - Adjust Volume": {
+ "Position": "L0.7 A21.9 F2.6",
+ "Orientation": "Transversal",
+ "Rotation": 180.0,
+ "A >> P": 240,
+ "R >> L": 240,
+ "F >> H": 160,
+ "Reset": "Off"
+ },
+ "System - pTx Volumes": {
+ "B1 Shim mode": "TrueForm",
+ "Excitation": "Standard"
+ },
+ "System - Tx/Rx": {
+ "Frequency 1H": "123.160045 MHz",
+ "Correction factor": 1,
+ "Gain": "High",
+ "Img. Scale Cor.": 1.0,
+ "Reset": "Off",
+ "? Ref. amplitude 1H": "0.000 V"
+ },
+ "Physio - Signal1": {
+ "1st Signal/Mode": "None",
+ "TR": 2000,
+ "Concatenations": 1
+ },
+ "BOLD": {
+ "GLM Statistics": "Off",
+ "Dynamic t-maps": "Off",
+ "Ignore meas. at start": 0,
+ "Ignore after transition": 0,
+ "Model transition states": "On",
+ "Temp. highpass filter": "On",
+ "Threshold": 4.0,
+ "Paradigm size": 3,
+ "Meas[1]": "Baseline",
+ "Meas[2]": "Baseline",
+ "Meas[3]": "Active",
+ "Motion correction": "On",
+ "Spatial filter": "Off",
+ "Measurements": 360,
+ "Delay in TR": 0,
+ "Multiple series": "Off"
+ },
+ "Sequence - Part 1": {
+ "Introduction": "Off",
+ "Multi-slice mode": "Interleaved",
+ "Free echo spacing": "Off",
+ "Echo spacing": 0.55,
+ "Bandwidth": 2170
+ },
+ "Sequence - Part 2": {
+ "EPI factor": 64,
+ "RF pulse type": "Normal",
+ "Gradient mode": "Fast*",
+ "Excitation": "Standard"
+ }
+ }
+ }
+}
diff --git a/examples/monitor_project.py b/examples/monitor_project.py
index 164815a..30edc13 100644
--- a/examples/monitor_project.py
+++ b/examples/monitor_project.py
@@ -1,13 +1,10 @@
import argparse
-import os.path
-import sys
+import multiprocessing as mp
from pathlib import Path
-from mrQA import monitor
-from mrQA.utils import txt2list
-from MRdataset.log import logger
-from MRdataset.utils import valid_dirs
-from MRdataset.config import DatasetEmptyException
+from MRdataset import DatasetEmptyException, valid_dirs, load_mr_dataset
+from mrQA import monitor, logger, check_compliance
+from mrQA.utils import txt2list, filter_epi_fmap_pairs
def main():
@@ -21,36 +18,126 @@ def main():
optional = parser.add_argument_group('optional arguments')
# Add help
- required.add_argument('-d', '--datasets-txt', type=str, required=True,
- help='A txt file which contains a list of projects'
+ required.add_argument('-d', '--data-root', type=str, required=True,
+ help='A folder which contains projects'
'to process')
+ optional.add_argument('-t', '--task', type=str,
+ help='specify the task to be performed, one of'
+ ' [monitor, compile]', default='monitor')
+ optional.add_argument('-a', '--audit', type=str,
+ help='specify the audit type if compiling reports. '
+ 'Choose one of [hz, vt]. Required if task is '
+ 'compile',
+ default='vt')
optional.add_argument('-o', '--output-dir', type=str,
default='/home/mrqa/mrqa_reports/',
help='specify the directory where the report'
- ' would be saved. By default, the --data_source '
- 'directory will be used to save reports')
+ ' would be saved')
+ optional.add_argument('-x', '--exclude-fpath', type=str,
+ help='A txt file containing a'
+ 'list of folders to be skipped while'
+ 'monitoring')
+ required.add_argument('--config', type=str,
+ help='path to config file')
args = parser.parse_args()
- if Path(args.datasets_txt).exists():
- datasets_path = txt2list(args.datasets_txt)
+ if Path(args.data_root).exists():
+ data_root = Path(args.data_root)
+ non_empty_folders = []
+ for folder in data_root.iterdir():
+ if folder.is_dir() and any(folder.iterdir()):
+ non_empty_folders.append(folder)
else:
- raise ValueError("Need a valid path to a txt file, which consists of "
- f"names of projects to process. "
- f"Got {args.datasets_txt}")
- dirs = valid_dirs(datasets_path)
-
- for folder_path in dirs:
- name = Path(folder_path).stem
- print(f"\nProcessing {name}\n")
- output_folder = Path(args.output_dir) / name
- try:
- monitor(name=name,
- data_source=folder_path,
- output_dir=output_folder,
- decimals=2,
- )
- except DatasetEmptyException as e:
- logger.warning(f'{e}: Folder {name} has no DICOM files.')
+ raise ValueError("Need a valid path to a folder, which consists of "
+ f"projects to process. "
+ f"Got {args.data_root}")
+
+ dirs = valid_dirs(non_empty_folders)
+
+ if len(non_empty_folders) < 2:
+ dirs = [dirs]
+ if args.exclude_fpath is not None:
+ if not Path(args.exclude_fpath).exists():
+ raise FileNotFoundError("Need a valid filepath to the exclude list")
+ exclude_filepath = Path(args.exclude_fpath).resolve()
+ skip_list = [Path(i).resolve() for i in txt2list(exclude_filepath)]
+
+ for fpath in dirs:
+ if Path(fpath).resolve() in skip_list:
+ dirs.remove(fpath)
+ if args.task == 'monitor':
+ pool = mp.Pool(processes=10)
+ arguments = [(f, args.output_dir, args.config) for f in dirs]
+ pool.starmap(run, arguments)
+ elif args.task == 'compile':
+ compile_reports(args.data_root, args.output_dir, args.config,
+ args.audit)
+ else:
+ raise NotImplementedError(f"Task {args.task} not implemented. Choose "
+ "one of [monitor, compile]")
+
+
+def run(folder_path, output_dir, config_path):
+ name = Path(folder_path).stem
+ print(f"\nProcessing {name}\n")
+ output_folder = Path(output_dir) / name
+ try:
+ monitor(name=name,
+ data_source=folder_path,
+ output_dir=output_folder,
+ decimals=2,
+ verbose=False,
+ ds_format='dicom',
+ tolerance=0,
+ config_path=config_path,
+ )
+ except DatasetEmptyException as e:
+ logger.warning(f'{e}: Folder {name} has no DICOM files.')
+
+
+def compile_reports(folder_path, output_dir, config_path, audit='vt'):
+ output_dir = Path(output_dir)
+ complete_log = []
+ # Look for all mrds.pkl file in the output_dir. For ex, mrqa_reports
+ # Collect mrds.pkl files for all projects
+ mrds_files = list(Path(folder_path).rglob('*.mrds.pkl'))
+ if not mrds_files:
+ raise FileNotFoundError(f"No .mrds.pkl files found in {folder_path}")
+
+ for mrds in mrds_files:
+ ds = load_mr_dataset(mrds)
+ # TODO : check compliance, but maybe its better is to save
+ # compliance results which can be re-used here
+ hz, vt = check_compliance(
+ ds,
+ output_dir=output_dir / 'compiled_reports',
+ config_path=config_path,
+ )
+ if audit == 'hz':
+ non_compliant_ds = hz['non_compliant']
+ filter_fn = None
+ nc_params = ['ReceiveCoilActiveElements']
+ supplementary_params = ['BodyPartExamined']
+ elif audit == 'vt':
+ non_compliant_ds = vt['non_compliant']
+ nc_params = ['ShimSetting', 'PixelSpacing']
+ supplementary_params = []
+ # TODO: discuss what parameters can be compared between anatomical
+ # and functional scans
+ # after checking compliance just look for epi-fmap pairs for now
+ filter_fn = filter_epi_fmap_pairs
+ else:
+ raise ValueError(f"Invalid audit type {audit}. Choose one of "
+ f"[hz, vt]")
+
+ nc_log = non_compliant_ds.generate_nc_log(
+ parameters=nc_params,
+ suppl_params=supplementary_params,
+ filter_fn=filter_fn,
+ output_dir=output_dir,
+ audit=audit,
+ verbosity=4)
+
if __name__ == "__main__":
diff --git a/examples/mri-config-abcd.json b/examples/mri-config-abcd.json
new file mode 100644
index 0000000..81254af
--- /dev/null
+++ b/examples/mri-config-abcd.json
@@ -0,0 +1,107 @@
+{
+ "begin": "03_12_2024",
+ "end": "03_12_2000",
+ "include_sequence": {
+ "phantom": false,
+ "nifti_header": false,
+ "moco": false,
+ "sbref": false,
+ "derived": false
+ },
+ "use_echonumbers": true,
+ "vertical_audit": {
+ "stratify_by": null,
+ "sequences": [
+ [
+ "ABCD-DTI_SIEMENS_mosaic_original_baseline_year_1_arm_1",
+ "ABCD-Diffusion-FM-AP_SIEMENS_original_baseline_year_1_arm_1"
+ ],
+ [
+ "ABCD-DTI_SIEMENS_mosaic_original_baseline_year_1_arm_1",
+ "ABCD-Diffusion-FM-PA_SIEMENS_original_baseline_year_1_arm_1"
+ ],
+ [
+ "ABCD-fMRI-FM-AP_SIEMENS_original_baseline_year_1_arm_1",
+ "ABCD-rsfMRI_SIEMENS_mosaic_original_baseline_year_1_arm_1"
+ ],
+ [
+ "ABCD-fMRI-FM-PA_SIEMENS_original_baseline_year_1_arm_1",
+ "ABCD-rsfMRI_SIEMENS_mosaic_original_baseline_year_1_arm_1"
+ ],
+ [
+ "ABCD-fMRI-FM_GE_original_baseline_year_1_arm_1",
+ "ABCD-rsfMRI_GE_original_baseline_year_1_arm_1"
+ ],
+ [
+ "ABCD-DTI_PHILIPS_original_baseline_year_1_arm_1",
+ "ABCD-Diffusion-FM-AP_PHILIPS_original_baseline_year_1_arm_1"
+ ],
+ [
+ "ABCD-DTI_PHILIPS_original_baseline_year_1_arm_1",
+ "ABCD-Diffusion-FM-PA_PHILIPS_original_baseline_year_1_arm_1"
+ ],
+ [
+ "ABCD-fMRI-FM-AP_PHILIPS_original_baseline_year_1_arm_1",
+ "ABCD-rsfMRI_PHILIPS_original_baseline_year_1_arm_1"
+ ],
+ [
+ "ABCD-fMRI-FM-PA_PHILIPS_original_baseline_year_1_arm_1",
+ "ABCD-rsfMRI_PHILIPS_original_baseline_year_1_arm_1"
+ ]
+ ],
+ "include_parameters": [
+ "FieldOfView",
+ "PixelSpacing",
+ "PhaseEncodingDirection",
+ "ShimMode",
+ "ShimSetting"
+ ]
+ },
+ "horizontal_audit": {
+ "stratify_by": null,
+ "skip_sequences": [
+ "coil_error",
+ "qa",
+ "fmri"
+ ],
+ "include_parameters": [
+ "PixelSpacing",
+ "Rows",
+ "Columns",
+ "AcquisitionMatrix",
+ "Manufacturer",
+ "MagneticFieldStrength",
+ "ScanningSequence",
+ "SequenceVariant",
+ "SequenceName",
+ "NonLinearGradientCorrection",
+ "MRAcquisitionType",
+ "PhaseEncodingDirection",
+ "EchoTime",
+ "InversionTime",
+ "DwellTime",
+ "RepetitionTime",
+ "FlipAngle",
+ "BodyPartExamined",
+ "EchoTrainLength",
+ "PixelBandwidth",
+ "PhaseEncodingSteps",
+ "EchoNumber",
+ "SliceThickness",
+ "PercentPhaseFOV",
+ "PercentSampling",
+ "VariableFlipAngleFlag",
+ "ImageOrientationPatient",
+ "NumberOfAverages",
+ "ShimMode",
+ "FieldOfView"
+ ]
+ },
+ "plots": {
+ "include_parameters": [
+ "ManufacturerAndModel",
+ "ManufacturerAndVersion",
+ "Site"
+ ]
+ }
+}
diff --git a/examples/mri-config-full.json b/examples/mri-config-full.json
new file mode 100644
index 0000000..e746748
--- /dev/null
+++ b/examples/mri-config-full.json
@@ -0,0 +1,66 @@
+{
+ "begin": "03_12_2024",
+ "end": "03_12_2000",
+ "include_sequence": {
+ "phantom": false,
+ "nifti_header": false,
+ "moco": false,
+ "sbref": false,
+ "derived": false
+ },
+ "use_echonumbers": true,
+ "exclude_subjects": [
+ "210098",
+ "210078"
+ ],
+ "vertical_audit": {
+ "stratify_by": "series_number",
+ "include_parameters": [
+ "Rows",
+ "Columns",
+ "AcquisitionMatrix",
+ "PixelSpacing",
+ "PhaseEncodingDirection",
+ "ShimMode",
+ "ShimSetting"
+ ]
+ },
+ "horizontal_audit": {
+ "stratify_by": "series_number",
+ "include_parameters": [
+ "PixelSpacing",
+ "Rows",
+ "Columns",
+ "AcquisitionMatrix",
+ "Manufacturer",
+ "ManufacturersModelName",
+ "SoftwareVersions",
+ "MagneticFieldStrength",
+ "ReceiveCoilActiveElements",
+ "ScanningSequence",
+ "SequenceVariant",
+ "ScanOptions",
+ "SequenceName",
+ "NonLinearGradientCorrection",
+ "MRAcquisitionType",
+ "PhaseEncodingDirection",
+ "EchoTime",
+ "InversionTime",
+ "DwellTime",
+ "RepetitionTime",
+ "FlipAngle",
+ "BodyPartExamined",
+ "EchoTrainLength",
+ "PixelBandwidth",
+ "PhaseEncodingSteps",
+ "EchoNumber",
+ "SliceThickness",
+ "PercentPhaseFOV",
+ "PercentSampling",
+ "VariableFlipAngleFlag",
+ "ImageOrientationPatient",
+ "NumberOfAverages",
+ "ShimMode"
+ ]
+ }
+}
diff --git a/examples/mri-config-project.json b/examples/mri-config-project.json
new file mode 100644
index 0000000..f39aba6
--- /dev/null
+++ b/examples/mri-config-project.json
@@ -0,0 +1,60 @@
+{
+ "begin": "03_12_2024",
+ "end": "03_12_2000",
+ "include_sequence": {
+ "phantom": false,
+ "nifti_header": false,
+ "moco": false,
+ "sbref": false,
+ "derived": false
+ },
+ "use_echonumbers": true,
+ "vertical_audit": {
+ "stratify_by": "series_number",
+ "include_parameters": [
+ "AcquisitionMatrix",
+ "PixelSpacing",
+ "PhaseEncodingDirection",
+ "ShimMode",
+ "ShimSetting"
+ ]
+ },
+ "horizontal_audit": {
+ "stratify_by": "series_number",
+ "include_parameters": [
+ "PixelSpacing",
+ "Rows",
+ "Columns",
+ "AcquisitionMatrix",
+ "Manufacturer",
+ "ManufacturersModelName",
+ "SoftwareVersions",
+ "MagneticFieldStrength",
+ "ReceiveCoilActiveElements",
+ "ScanningSequence",
+ "SequenceVariant",
+ "ScanOptions",
+ "SequenceName",
+ "NonLinearGradientCorrection",
+ "MRAcquisitionType",
+ "PhaseEncodingDirection",
+ "EchoTime",
+ "InversionTime",
+ "DwellTime",
+ "RepetitionTime",
+ "FlipAngle",
+ "BodyPartExamined",
+ "EchoTrainLength",
+ "PixelBandwidth",
+ "PhaseEncodingSteps",
+ "SliceThickness",
+ "PercentPhaseFOV",
+ "PercentSampling",
+ "VariableFlipAngleFlag",
+ "ImageOrientationPatient",
+ "NumberOfAverages",
+ "ShimMode",
+ "FieldOfView"
+ ]
+ }
+}
diff --git a/examples/mri-config.json b/examples/mri-config.json
new file mode 100644
index 0000000..92f3ab1
--- /dev/null
+++ b/examples/mri-config.json
@@ -0,0 +1,75 @@
+{
+ "begin": "2014-03-12T13:37:27+00:00",
+ "end": "2017-03-12T13:37:27+00:00",
+ "include_sequence": {
+ "phantom": false,
+ "nifti_header": false,
+ "moco": false,
+ "sbref": false,
+ "derived": false
+ },
+ "use_echonumbers": true,
+ "horizontal_audit": {
+ "stratify_by": "series_number",
+ "include_parameters": [
+ "EchoTrainLength",
+ "ParallelAcquisitionTechnique",
+ "MagneticFieldStrength",
+ "MRAcquisitionType",
+ "MultiSliceMode",
+ "PhasePolarity",
+ "PhaseEncodingSteps",
+ "PixelBandwidth",
+ "ScanningSequence",
+ "SequenceVariant",
+ "RepetitionTime",
+ "EchoTime",
+ "FlipAngle",
+ "PhaseEncodingDirection",
+ "ShimMode",
+ "Rows",
+ "Columns",
+ "AcquisitionMatrix"
+ ]
+ },
+ "vertical_audit": {
+ "stratify_by": "series_number",
+ "sequences": [
+ [
+ "ncanda-rsfmri-v1",
+ "ncanda-grefieldmap-v1"
+ ],
+ [
+ "ncanda-dti30b400-v1",
+ "ncanda-grefieldmap-v1"
+ ],
+ [
+ "ncanda-dti60b1000-v1",
+ "ncanda-grefieldmap-v1"
+ ]
+ ],
+ "include_parameters": [
+ "Rows",
+ "Columns",
+ "AcquisitionMatrix",
+ "PhaseEncodingDirection",
+ "ShimMode",
+ "ShimSetting"
+ ]
+ },
+ "plots": {
+ "include_parameters": [
+ "ContentDate",
+ "PatientSex",
+ "PatientAge",
+ "PatientWeight",
+ "OperatorsName",
+ "InstitutionName",
+ "Manufacturer"
+ ]
+ },
+ "exclude_subjects": [
+ "210098",
+ "210078"
+ ]
+}
diff --git a/examples/plot.py b/examples/plot.py
new file mode 100644
index 0000000..f12cfe2
--- /dev/null
+++ b/examples/plot.py
@@ -0,0 +1,12 @@
+import pickle
+from mrQA.project import plot_patterns
+
+dict_ = pickle.load(open(
+ '/home/sinhah/scan_data/vertical_abcd_mrqa_files/abcd-fmap-baseline-non-recommended_hz.adt.pkl', 'rb')
+)
+
+config_path = '/home/sinhah/github/mrQA/examples/mri-config-abcd.json'
+
+plot_patterns(non_compliant_ds=dict_['non_compliant'],
+ complete_ds=dict_['complete_ds'],
+ config_path=config_path)
diff --git a/examples/process_abcd_T1w.py b/examples/process_abcd_T1w.py
index 9d0888b..6b2b702 100644
--- a/examples/process_abcd_T1w.py
+++ b/examples/process_abcd_T1w.py
@@ -39,7 +39,7 @@ def main():
if args.task == 'create_script':
# Create scripts but do not submit jobs
create_script(data_source=DATA_ROOT,
- subjects_per_job=50,
+ folders_per_job=50,
conda_env='mrqa',
conda_dist='miniconda3',
hpc=True,
diff --git a/examples/process_abcd_local.py b/examples/process_abcd_local.py
index 614d337..ad91d68 100644
--- a/examples/process_abcd_local.py
+++ b/examples/process_abcd_local.py
@@ -4,7 +4,6 @@
from MRdataset import load_mr_dataset
from MRdataset.config import MRDS_EXT
-
from mrQA import check_compliance
from mrQA.run_merge import check_and_merge
from mrQA.run_parallel import create_script, submit_job
@@ -29,25 +28,33 @@ def main():
# Required arguments
required.add_argument('-t', '--task', type=str, required=False,
- help='[submit_job|merge|report]',
- default='submit_job')
-
+ help='[create_script|submit_job|merge|report]',
+ default='report')
+ optional.add_argument('-ref', '--ref-protocol-path', type=str,
+ help='XML file containing desired protocol. If not '
+ 'provided, the protocol will be inferred from '
+ 'the dataset.')
+ required.add_argument('--config', type=str,
+ help='path to config file',
+ default='/home/sinhah/github/mrQA/examples/mri-config-abcd.json')
# Parse arguments
args = parser.parse_args()
# Set constants
- DATA_ROOT = Path('/media/sinhah/extremessd/ABCD-375/dicom-baseline')
+ DATA_ROOT = Path('/home/sinhah/scan_data/vertical_abcd')
OUTPUT_DIR = DATA_ROOT.parent / (DATA_ROOT.stem + '_mrqa_files')
# OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
- name = 'abcd-375'
+ name = 'abcd-vertical'
# Choose a task, one of [debug|submit_job|merge|report]
if args.task == 'create_script':
# note that it will generate scripts only
create_script(data_source=DATA_ROOT,
- subjects_per_job=50,
+ folders_per_job=5,
conda_env='mrcheck',
conda_dist='anaconda3',
hpc=False,
+ config_path=args.config,
+ output_dir=OUTPUT_DIR,
)
elif args.task == 'submit_job':
# Generate slurm scripts and submit jobs, for local parallel processing
@@ -68,10 +75,13 @@ def main():
)
elif args.task == 'report':
# Generate a report for the merged dataset
- dataset = load_mr_dataset(OUTPUT_DIR / (name + MRDS_EXT), ds_format='dicom')
+ dataset = load_mr_dataset(OUTPUT_DIR / (name + MRDS_EXT))
check_compliance(dataset=dataset,
- output_dir=OUTPUT_DIR/'reports',
- decimals=1)
+ output_dir=OUTPUT_DIR,
+ decimals=2,
+ tolerance=0,
+ config_path=args.config,
+ reference_path=args.ref_protocol_path,)
else:
# Invalid task
raise NotImplementedError(f"Expected one of [submit_job|merge|report], "
diff --git a/mrQA/__compliance__.py b/mrQA/__compliance__.py
index 42f8ceb..19b76d6 100644
--- a/mrQA/__compliance__.py
+++ b/mrQA/__compliance__.py
@@ -1,7 +1,7 @@
from sys import version_info
if version_info.major > 2:
- from mrQA import cli
+ from mrQA.cli import cli
else:
raise NotImplementedError('Protocol Compliance requires Python 3 or higher.'
'Upgrade to Python 3+ or use environments.')
@@ -9,7 +9,7 @@
def main():
"""Entry point."""
- cli.main()
+ cli()
if __name__ == '__main__':
diff --git a/mrQA/__init__.py b/mrQA/__init__.py
index c8a4fbb..bda5021 100644
--- a/mrQA/__init__.py
+++ b/mrQA/__init__.py
@@ -2,10 +2,17 @@
__author__ = """Harsh Sinha"""
__email__ = 'harsh.sinha@pitt.edu'
-__version__ = '0.1.0'
+# __version__ = '0.1.0'
-from mrQA.project import check_compliance
-from mrQA.monitor import monitor
+import logging
-from . import _version
-__version__ = _version.get_versions()['version']
+from mrQA.config import configure_logger
+
+logger = logging.getLogger(__name__)
+logger = configure_logger(logger, output_dir=None, mode='w')
+
+from mrQA.monitor import monitor # noqa
+from mrQA.project import check_compliance # noqa
+from . import _version # noqa
+
+__version__ = _version.get_versions()['version'] # noqa
diff --git a/mrQA/_version.py b/mrQA/_version.py
index 663e817..87f472d 100644
--- a/mrQA/_version.py
+++ b/mrQA/_version.py
@@ -198,7 +198,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
# expansion behaves like git log --decorate=short and strips out the
# refs/heads/ and refs/tags/ prefixes that would let us distinguish
# between branches and tags. By ignoring refnames without digits, we
- # filter out many common branch names like "release" and
+ # filter_fn out many common branch names like "release" and
# "stabilization", as well as "HEAD" and "master".
tags = {r for r in refs if re.search(r'\d', r)}
if verbose:
diff --git a/mrQA/base.py b/mrQA/base.py
new file mode 100644
index 0000000..9174011
--- /dev/null
+++ b/mrQA/base.py
@@ -0,0 +1,640 @@
+import json
+import tempfile
+from abc import ABC, abstractmethod
+from typing import List
+
+from MRdataset import valid_dirs
+from MRdataset.base import BaseDataset
+from bokeh.palettes import turbo, d3
+from protocol import BaseSequence
+
+
+class CompliantDataset(BaseDataset):
+ """
+ Container to manage properties of sequences that are compliant with the
+ reference protocol. It is a subclass of BaseDataset, and inherits all
+ its properties and methods.
+
+ Parameters
+ ----------
+ name: str
+ Name of the dataset
+ data_source: Path | List | str
+ Path to the dataset
+ ds_format: str
+ Format of the dataset, one of ['dicom']
+ """
+
+ def __init__(self, name=None, data_source=None, ds_format=None):
+ # BaseDataset checks if data_source is valid, and if not,
+ # it raises an error.
+ # It is very likely that data is processed by MRdataset on a
+ # different machine, and the processed data is then transferred to
+ # another machine for audit. In such cases, the data_source of
+ # original dataset will be invalid on the machine where audit is
+ # performed. Hence, we set data_source in super() to temp dir.
+ try:
+ data_source = valid_dirs(data_source)
+ except (OSError, ValueError):
+ data_source = tempfile.gettempdir()
+
+ super().__init__(name=name, data_source=data_source,
+ ds_format=ds_format)
+
+ # If the sequence name was modified, then we need to keep track of
+ # the original sequence name as well. For example, if the sequence
+ # name was modified from T1w to T1w_modified, then we need to keep
+ # track of the original sequence name T1w as well. Why is modification
+ # of sequence name required? For example, if the sequence name is
+ # same, but the sequence is acquired twice, then we need to modify
+ # the sequence name to distinguish between the two sequences.
+ self._org2mod_seq_names = {}
+ self._mod2org_seq_names = {}
+
+ def get_modified_seq_name(self, seq_name):
+ """Get the modified sequence name"""
+ return self._org2mod_seq_names[seq_name]
+
+ def _get_original_seq_name(self, seq_name):
+ """Get the original sequence name"""
+ return self._mod2org_seq_names[seq_name]
+
+ def set_modified_seq_name(self, original, modified):
+ """Set the modified sequence name"""
+ self._org2mod_seq_names[original] = modified
+ self._mod2org_seq_names[modified] = original
+
+ def load(self):
+ pass
+
+
+class UndeterminedDataset(BaseDataset):
+ """
+ Container to manage properties of sequences whose reference protocol could
+ not be determined. Reasons could be:
+ 1. No reference protocol was found
+ 2. Multiple reference protocols were found
+ 3. Reference protocol was not valid
+
+ Parameters
+ ----------
+ name: str
+ Name of the dataset
+ data_source: Path | List | str
+ Path to the dataset
+ ds_format: str
+ Format of the dataset, one of ['dicom']
+ """
+
+ def __init__(self, name=None, data_source=None, ds_format=None):
+ # BaseDataset checks if data_source is valid, and if not,
+ # it raises an error.
+ # It is very likely that data is processed by MRdataset on a
+ # different machine, and the processed data is then transferred to
+ # another machine for audit. In such cases, the data_source of
+ # original dataset will be invalid on the machine where audit is
+ # performed. Hence, we set data_source in super() to None.
+ try:
+ data_source = valid_dirs(data_source)
+ except (OSError, ValueError):
+ data_source = tempfile.gettempdir()
+
+ super().__init__(name=name, data_source=data_source,
+ ds_format=ds_format)
+
+ # If the sequence name was modified, then we need to keep track of
+ # the original sequence name as well. For example, if the sequence
+ # name was modified from T1w to T1w_modified, then we need to keep
+ # track of the original sequence name T1w as well. Why is modification
+ # of sequence name required? For example, if the sequence name is
+ # same, but the sequence is acquired twice, then we need to modify
+ # the sequence name to distinguish between the two sequences.
+
+ self._org2mod_seq_names = {}
+ self._mod2org_seq_names = {}
+
+ def get_modified_seq_name(self, seq_name):
+ """Get the modified sequence name"""
+ return self._org2mod_seq_names[seq_name]
+
+ def get_original_seq_name(self, seq_name):
+ """Get the original sequence name"""
+ return self._mod2org_seq_names[seq_name]
+
+ def set_modified_seq_name(self, original, modified):
+ """Set the modified sequence name"""
+ self._org2mod_seq_names[original] = modified
+ self._mod2org_seq_names[modified] = original
+
+ def load(self):
+ pass
+
+
+class NonCompliantDataset(BaseDataset):
+ """
+ Container to manage properties of sequences that are non-compliant with the
+ reference protocol. It is a subclass of BaseDataset, and inherits all
+ its properties and methods.
+
+ Parameters
+ ----------
+ name: str
+ Name of the dataset
+ data_source: Path | List | str
+ Path to the dataset
+ ds_format: str
+ Format of the dataset, one of ['dicom']
+ """
+
+ def __init__(self, name=None, data_source=None, ds_format=None):
+ # BaseDataset checks if data_source is valid, and if not,
+ # it raises an error.
+ # It is very likely that data is processed by MRdataset on a
+ # different machine, and the processed data is then transferred to
+ # another machine for audit. In such cases, the data_source of
+ # original dataset will be invalid on the machine where audit is
+ # performed. Hence, we set data_source in super() to None.
+ try:
+ data_source = valid_dirs(data_source)
+ except (OSError, ValueError):
+ data_source = tempfile.gettempdir()
+
+ super().__init__(name=name, data_source=data_source,
+ ds_format=ds_format)
+
+ # Dictionary to store all non-compliant parameters
+ self._nc_flat_map = {}
+ self._nc_tree_map = {}
+ self._nc_params_map = {}
+
+ # Set to store all sequence pairs that were checked for vertical audit
+ self._vt_sequences = set()
+
+ # If the sequence name was modified, then we need to keep track of
+ # the original sequence name as well. For example, if the sequence
+ # name was modified from T1w to T1w_modified, then we need to keep
+ # track of the original sequence name T1w as well. Why is modification
+ # of sequence name required? For example, if the sequence name is
+ # same, but the sequence is acquired twice, then we need to modify
+ # the sequence name to distinguish between the two sequences.
+ self._org2mod_seq_names = {}
+ self._mod2org_seq_names = {}
+
+ def get_modified_seq_name(self, seq_name):
+ """Get the modified sequence name"""
+ try:
+ return self._org2mod_seq_names[seq_name]
+ except KeyError:
+ return seq_name
+
+ def get_original_seq_name(self, seq_name):
+ """Get the original sequence name"""
+ try:
+ return self._mod2org_seq_names[seq_name]
+ except KeyError:
+ return seq_name
+
+ def set_modified_seq_name(self, original, modified):
+ """Set the modified sequence name"""
+ self._org2mod_seq_names[original] = modified
+ self._mod2org_seq_names[modified] = original
+
+ def get_vt_sequences(self) -> List:
+ """
+ Returns a list of all sequences that were checked for vertical
+ audit.
+ """
+ return list(self._vt_sequences)
+
+ def add_sequence_pair_names(self, list_seqs):
+ """
+ Add a sequence to the list of sequences that were checked for
+ vertical audit.
+ """
+ self._vt_sequences.add(list_seqs)
+
+ def generate_hz_log(self, parameters, suppl_params, filter_fn=None,
+ verbosity=1):
+ sequences = self.get_sequence_ids()
+ nc_log = {}
+ for seq_id in sequences:
+ for param_name in parameters:
+ for param_tupl, sub, path, seq in self.get_nc_param_values(
+ seq_id, param_name):
+ if param_name not in nc_log: # empty
+ nc_log[param_name] = []
+
+ nc_dict = {}
+ nc_dict['subject'] = sub
+ nc_dict['sequence_name'] = seq_id
+
+ # if additional parameters have to be included in the log
+ if suppl_params:
+ for i in suppl_params:
+ nc_dict[i] = seq[i].get_value()
+
+ if verbosity > 1:
+ nc_dict['values'] = [p.get_value() for p in param_tupl]
+ if verbosity > 2:
+ nc_dict['path'] = str(path)
+
+ nc_log[param_name].append(nc_dict)
+ return nc_log
+
+ def generate_nc_log(self, parameters, filter_fn=None, output_dir=None,
+ suppl_params=None, audit='vt', verbosity=1):
+ """
+ Generate a log of all non-compliant parameters in the dataset.
+ Apart from returning the log, it also dumps the log as a json file
+ """
+ nc_log = {}
+ if audit == 'hz':
+ nc_log = self.generate_hz_log(parameters, suppl_params,
+ filter_fn, verbosity)
+ filename = self.name + '_hz_log.json'
+ elif audit == 'vt':
+ nc_log = self.generate_vt_log(parameters, suppl_params,
+ filter_fn, verbosity)
+ filename = self.name + '_vt_log.json'
+ if audit not in ['vt', 'hz']:
+ raise ValueError('Expected one of [vt, hz], got {}'.format(audit))
+
+ # if output_dir is provided, dump it as a json file
+ if nc_log and output_dir is not None:
+ with open(output_dir / filename, 'w') as f:
+ json.dump(nc_log, f, indent=4)
+
+ return nc_log
+
+ def generate_vt_log(self, parameters, suppl_params, filter_fn=None,
+ verbosity=1):
+
+ nc_log = {}
+ sequence_pairs = self.get_vt_sequences()
+
+ # Don't create the log for all sequence pairs. For example, we only
+ # want to highlight the issues in field-map and epi sequences.
+ for pair in filter(filter_fn, sequence_pairs):
+ for param_name in parameters:
+ for param_tupl, sub, path, seq in self.get_vt_param_values(
+ pair, param_name):
+ if param_name not in nc_log: # empty
+ nc_log[param_name] = []
+
+ nc_dict = {}
+ nc_dict['subject'] = sub
+ nc_dict['sequence_names'] = pair
+
+ if verbosity > 1:
+ nc_dict['values'] = [p.get_value() for p in param_tupl]
+ if verbosity > 2:
+ nc_dict['path'] = str(path)
+
+ nc_log[param_name].append(nc_dict)
+
+ return nc_log
+
+ def get_nc_param_ids(self, seq_id):
+ """
+ Returns a list of all non-compliant parameter names for a given
+ sequence id.
+
+ Parameters
+ ----------
+ seq_id: str
+ Name of the sequence, e.g. T1w, T2w etc.
+ """
+ if seq_id not in self._nc_params_map:
+ return []
+ else:
+ return list(self._nc_params_map[seq_id])
+
+ def get_nc_param_values(self, seq_id, param_name, ref_seq=None):
+ """
+ Returns a list of all non-compliant parameter values for a given
+ sequence id and parameter name.
+
+ Parameters
+ ----------
+ seq_id: str
+ Name of the sequence, e.g. rs-fMRI etc.
+ param_name: str
+ Name of the parameter, e.g. RepetitionTime, EchoTime etc.
+ ref_seq: str
+ Name of the reference sequence, e.g. field-map
+
+ Returns
+ -------
+ Iterator
+ All non-compliant parameter values
+
+ .. note:: It is recommended to also use the name of sequence used as
+ the reference protocol. For horizontal audit,
+ this is not essential, as each sequence is compared against its own
+ reference protocol. However, in case of vertical audit, it is
+ essential to provide the name of the sequence used as the
+ reference protocol.
+ For example, if field map and the rs-fMRI sequence are compared,
+ then the seq_id can be rs-fMRI, and ref_seq can be field map.
+ This will return only those values that are non-compliant with
+ the field map sequence. If ref_seq is provided, it returns only
+ those values that are non-compliant with the reference protocol.
+
+ """
+ if ref_seq is None:
+ ref_seq = '__NOT_SPECIFIED__'
+ if param_name in self._nc_params_map[seq_id]:
+ if seq_id in self._nc_tree_map[param_name]:
+ for subject_id in self._nc_tree_map[param_name][seq_id]:
+ for session_id in (
+ self._nc_tree_map[param_name][seq_id][subject_id]):
+ if ref_seq in \
+ self._nc_tree_map[param_name][seq_id][subject_id][
+ session_id]:
+ yield from self._get_all_nc_param_values(
+ seq_id=seq_id, param_name=param_name,
+ subject_id=subject_id, session_id=session_id,
+ ref_seq=ref_seq)
+
+ def _get_all_nc_param_values(self, seq_id, param_name, subject_id,
+ session_id, ref_seq=None):
+ """
+ Returns a list of all non-compliant parameter values for a given
+ sequence id, subject_id, session_id and parameter name.
+ """
+ for run_id in self._nc_tree_map[param_name][seq_id][
+ subject_id][session_id][ref_seq]:
+ param_tupl = self._nc_tree_map[param_name][seq_id][
+ subject_id][session_id][ref_seq][run_id] # noqa
+ path = self.get_path(subject_id, session_id,
+ seq_id, run_id)
+ seq = self.get(subject_id, session_id, seq_id, run_id)
+ yield param_tupl, subject_id, path, seq
+
+ def get_vt_param_values(self, seq_pair, param_name):
+ """Wrapper around get_nc_param_values() for vertical audit"""
+ seq1, seq2 = seq_pair
+ if seq1 not in self._nc_params_map:
+ return
+ yield from self.get_nc_param_values(seq1, param_name, seq2)
+
+ def get_nc_subject_ids(self, seq_id, param_name, ref_seq=None):
+ """
+ Returns a list of all non-compliant subject ids for a given
+ sequence id and parameter name. Created for vertical audit report
+ as we are not listing any parameter values or paths in the report, just
+ the subject ids.
+ """
+ if ref_seq is None:
+ ref_seq = '__NOT_SPECIFIED__'
+ if seq_id not in self._nc_params_map:
+ # return empty generator
+ return
+ if param_name in self._nc_params_map[seq_id]:
+ if seq_id in self._nc_tree_map[param_name]:
+ for subject_id in self._nc_tree_map[param_name][seq_id]:
+ for session_id in (
+ self._nc_tree_map[param_name][seq_id][subject_id]):
+ if ref_seq in \
+ self._nc_tree_map[param_name][seq_id][subject_id][
+ session_id]:
+ yield subject_id
+
+ def total_nc_subjects_by_sequence(self, seq_id, ref_seq=None):
+ """
+ Returns the total number of non-compliant subjects for a given
+ sequence id and parameter name.
+ """
+ subject_ids = set()
+ for parameter in self.get_nc_param_ids(seq_id=seq_id):
+ for subject_id in self.get_nc_subject_ids(
+ seq_id=seq_id,
+ param_name=parameter,
+ ref_seq=ref_seq):
+ subject_ids.add(subject_id)
+ return len(subject_ids)
+
+ def total_nc_subjects_by_parameter(self, param_name):
+ """
+ Returns the total number of non-compliant subjects for a given
+ sequence id and parameter name.
+ """
+ total_subjects = set()
+ for seq_id, ref_seq in self.get_vt_sequences():
+ if seq_id in self._nc_params_map:
+ subjects = list(self.get_nc_subject_ids(seq_id=seq_id,
+ param_name=param_name,
+ ref_seq=ref_seq))
+ total_subjects.update(subjects)
+ return len(total_subjects)
+
+ def get_nc_params(self, subject_id, session_id, seq_id, run_id):
+ """
+ A generator that returns all non-compliant parameters for a given
+ subject, session, sequence and run.
+
+ Parameters
+ ----------
+ subject_id: str
+ Subject ID e.g. sub-01
+ session_id: str
+ Session ID e.g. ses-01
+ seq_id: str
+ Sequence ID e.g. T1w, T2w etc.
+ run_id: str
+ Run ID e.g. run-01
+
+ Returns
+ -------
+ Iterator
+ All non-compliant parameters
+ """
+ for param_name in self._nc_tree_map:
+ yield self._nc_tree_map[param_name][subject_id][session_id][seq_id][
+ run_id]
+
+ def get_path(self, subject_id, session_id, seq_id, run_id):
+ """
+ Returns the path to the folder where DICOM files for a
+ given subject, session, sequence and run are stored.
+
+ Parameters
+ ----------
+ subject_id: str
+ Subject ID e.g. sub-01
+ session_id: str
+ Session ID e.g. ses-01
+ seq_id: str
+ Sequence ID e.g. T1w, T2w etc.
+ run_id: str
+ Run ID e.g. run-01
+
+ Returns
+ -------
+ str
+ Path to the folder where DICOM files are stored
+ """
+ # Get image sequence for the given subject, session, sequence and run
+ img_sequence = self._tree_map[subject_id][session_id][seq_id][run_id]
+ return img_sequence.path
+
+ def add_nc_params(self, subject_id, session_id, seq_id, run_id,
+ non_compliant_params, ref_seq=None):
+ """
+ Add non-compliant parameters to the dataset. This is a helper function
+ that is used by the (horizontal/vertical) audit to add non-compliant
+ parameters to the dataset.
+
+ Parameters
+ ----------
+ subject_id: str
+ Subject ID e.g. sub-01
+ session_id: str
+ Session ID e.g. ses-01
+ seq_id: str
+ Sequence ID e.g. T1w, T2w etc.
+ run_id: str
+ Run ID e.g. run-01
+ non_compliant_params: List[Tuple]
+ List of non-compliant parameters. Each tuple contains
+ non-compliant parameter and the reference parameter.
+ ref_seq: str
+ Name of the reference sequence, e.g. field-map
+ """
+ if ref_seq is None:
+ ref_seq = '__NOT_SPECIFIED__'
+
+ if not isinstance(non_compliant_params, list):
+ raise TypeError(
+ 'Expected list of BaseParameter, got {}'.format(
+ type(non_compliant_params)))
+
+ if isinstance(seq_id, BaseSequence):
+ raise TypeError("Expected str, got BaseSequence. Use "
+ ".name attribute to get the name of the sequence")
+
+ if not isinstance(seq_id, str):
+ raise TypeError(
+ 'Expected str, got {}'.format(type(seq_id)))
+
+ if not isinstance(ref_seq, str):
+ raise TypeError(
+ 'Expected str, got {}'.format(type(ref_seq)))
+
+ for param_tupl in non_compliant_params:
+ # if not isinstance(param_tupl, BaseParameter):
+ # raise TypeError(
+ # 'Expected BaseParameter, got {}'.format(type(param_tupl)))
+
+ param_name = param_tupl[0].name
+ self._nc_flat_map[
+ (param_name, subject_id, session_id, seq_id, ref_seq,
+ run_id)] = param_tupl
+ self._nc_tree_add_node(subject_id=subject_id, session_id=session_id,
+ seq_id=seq_id, run_id=run_id,
+ param=param_tupl, param_name=param_name,
+ ref_seq=ref_seq)
+ if seq_id not in self._nc_params_map:
+ self._nc_params_map[seq_id] = set()
+ self._nc_params_map[seq_id].add(param_name)
+
+ def _nc_tree_add_node(self, subject_id, session_id, seq_id, run_id,
+ param, param_name, ref_seq=None):
+ """
+ Add a node to the tree map. This is a private function that is used by
+ the (horizontal/vertical) audit to add non-compliant parameters to the
+ dataset.
+
+ Parameters
+ ----------
+ subject_id: str
+ Subject ID e.g. sub-01
+ session_id: str
+ Session ID e.g. ses-01
+ seq_id: str
+ Sequence ID e.g. T1w, T2w etc.
+ run_id: str
+ Run ID e.g. run-01
+ ref_seq: Optional[str]
+ Name of the reference sequence, e.g. field-map
+ """
+ # TODO: improve it later
+ if ref_seq is None:
+ ref_seq = '__NOT_SPECIFIED__'
+
+ if param_name not in self._nc_tree_map:
+ self._nc_tree_map[param_name] = dict()
+
+ if seq_id not in self._nc_tree_map[param_name]:
+ self._nc_tree_map[param_name][seq_id] = dict()
+
+ if subject_id not in self._nc_tree_map[param_name][seq_id]:
+ self._nc_tree_map[param_name][seq_id][subject_id] = dict()
+
+ if session_id not in self._nc_tree_map[param_name][seq_id][subject_id]:
+ self._nc_tree_map[param_name][seq_id][subject_id][
+ session_id] = dict()
+
+ if ref_seq not in (
+ self._nc_tree_map[param_name][seq_id][subject_id][session_id]):
+ self._nc_tree_map[param_name][seq_id][subject_id][session_id][
+ ref_seq] = dict()
+
+ if run_id not in \
+ self._nc_tree_map[param_name][seq_id][subject_id][session_id][
+ ref_seq]:
+ self._nc_tree_map[param_name][seq_id][subject_id][session_id][
+ ref_seq][run_id] = dict()
+
+ self._nc_tree_map[param_name][seq_id][subject_id][session_id][ref_seq][
+ run_id] = param
+
+ def load(self):
+ pass
+
+
+class BasePlot(ABC):
+ _name = None
+
+ def __init__(self, name=None):
+ if name is not None:
+ self._name = name
+ self.div = None
+ self.script = None
+ self.plot_height = None
+ self.plot_width = None
+ self.title = None
+ self.x_axis_label = None
+ self.y_axis_label = None
+ self.x_range = None
+ self.label = None
+ self.legend_label = None
+ self.colors = None
+
+ @abstractmethod
+ def plot(self, non_compliant_ds, complete_ds, parameters):
+ """Creates a plot for the given data"""
+
+ @abstractmethod
+ def compute_counts(self, non_compliant_ds, complete_ds, parameters):
+ """Computes the counts for the given dataset and parameters."""
+
+ @abstractmethod
+ def get_plot_components(self, data):
+ """getter method for plotting components"""
+
+ @abstractmethod
+ def get_counter(self, dataset, parameters):
+ """getter method for counter"""
+
+ def set_cmap(self, length):
+ """Sets the color map for the plot"""
+ if length > 10:
+ colors = turbo(length)
+ else:
+ palette = d3['Category10']
+ if length > 3:
+ colors = palette[length]
+ else:
+ colors = palette[10][:length]
+ self.colors = colors
diff --git a/mrQA/cli.py b/mrQA/cli.py
index ec2f468..7fe4f58 100644
--- a/mrQA/cli.py
+++ b/mrQA/cli.py
@@ -3,16 +3,17 @@
import sys
from pathlib import Path
-from MRdataset import import_dataset
-from MRdataset.utils import is_writable, valid_dirs
-from MRdataset.log import logger
+from MRdataset import import_dataset, load_mr_dataset, valid_dirs, \
+ DatasetEmptyException
from mrQA import check_compliance
+from mrQA import logger
from mrQA.config import PATH_CONFIG
+from mrQA.utils import is_writable
def get_parser():
- """Console script for mrQA."""
+ """Parser for command line interface."""
parser = argparse.ArgumentParser(
description='Protocol Compliance of MRI scans',
add_help=False
@@ -25,12 +26,14 @@ def get_parser():
required.add_argument('-d', '--data-source', nargs='+', required=True,
help='directory containing downloaded dataset with '
'dicom files, supports nested hierarchies')
+ required.add_argument('--config', type=str,
+ help='path to config file')
optional.add_argument('-o', '--output-dir', type=str,
help='specify the directory where the report'
' would be saved. By default, the --data_source '
'directory will be used to save reports')
optional.add_argument('-f', '--format', type=str, default='dicom',
- help='type of dataset, one of [dicom|bids|pybids]')
+ help='type of dataset, one of [dicom|bids]')
optional.add_argument('-n', '--name', type=str,
help='provide a identifier/name for the dataset')
optional.add_argument('-h', '--help', action='help',
@@ -43,27 +46,17 @@ def get_parser():
'of the decimal point.')
optional.add_argument('-t', '--tolerance', type=float, default=0,
help='tolerance for checking against reference '
- 'protocol. Default is 0.1')
+ 'protocol. Default is 0')
# TODO: use this flag to store cache
optional.add_argument('-v', '--verbose', action='store_true',
help='allow verbose output on console')
- optional.add_argument('-ref', '--reference_path', type=str,
- help='.yaml file containing protocol specification')
- optional.add_argument('--strategy', type=str, default='majority',
- help='how to examine parameters [majority|reference].'
- '--reference_path required if using reference')
- optional.add_argument('--include-phantom', action='store_true',
- help='whether to include phantom, localizer, '
- 'aahead_scout')
- optional.add_argument('--include-nifti-header', action='store_true',
- help='whether to check nifti headers for compliance,'
- 'only used when --format==bids')
- # Experimental features, not implemented yet.
- optional.add_argument('-l', '--logging', type=int, default=40,
- help='set logging to appropriate level')
- optional.add_argument('--skip', nargs='+',
- help='skip these parameters')
-
+ optional.add_argument('-ref', '--ref-protocol-path', type=str,
+ help='XML file containing desired protocol. If not '
+ 'provided, the protocol will be inferred from '
+ 'the dataset.')
+ optional.add_argument('-pkl', '--mrds-pkl-path', type=str,
+ help='.mrds.pkl file can be provided to facilitate '
+ 'faster re-runs.')
if len(sys.argv) < 2:
logger.critical('Too few arguments!')
parser.print_help()
@@ -72,33 +65,47 @@ def get_parser():
return parser
-def main():
+def cli():
+ """
+ Console script for mrQA.
+ """
args = parse_args()
-
- dataset = import_dataset(data_source=args.data_source,
- ds_format=args.format,
- name=args.name,
- verbose=args.verbose,
- include_phantom=args.include_phantom,
- include_nifti_header=args.include_nifti_header)
-
- check_compliance(dataset=dataset,
- strategy=args.strategy,
- output_dir=args.output_dir,
- decimals=args.decimals,
- verbose=args.verbose,
- tolerance=args.tolerance,)
+ if args.mrds_pkl_path:
+ dataset = load_mr_dataset(args.mrds_pkl_path)
+ else:
+ dataset = import_dataset(data_source=args.data_source,
+ ds_format=args.format,
+ name=args.name,
+ verbose=args.verbose,
+ config_path=args.config,
+ output_dir=args.output_dir)
+
+ try:
+ check_compliance(dataset=dataset,
+ output_dir=args.output_dir,
+ decimals=args.decimals,
+ verbose=args.verbose,
+ tolerance=args.tolerance,
+ config_path=args.config,
+ reference_path=args.ref_protocol_path, )
+ except DatasetEmptyException:
+ logger.error("Cannot check compliance if the dataset doesn't have "
+ "any scans. Please check the dataset.")
+ except NotADirectoryError:
+ logger.error('Provided output directory for saving reports is invalid.'
+ 'Either it is not a directory or it does not exist. ')
return 0
def parse_args():
+ """Validates command line arguments and returns parsed arguments"""
parser = get_parser()
args = parser.parse_args()
if args.verbose:
- logger.setLevel('INFO')
- else:
logger.setLevel('WARNING')
+ else:
+ logger.setLevel('ERROR')
if not valid_dirs(args.data_source):
raise OSError('Expected valid directory for --data_source argument, '
@@ -114,12 +121,26 @@ def parse_args():
try:
Path(args.output_dir).mkdir(parents=True, exist_ok=True)
except OSError as exc:
+ logger.error(f'Unable to create folder {args.output_dir} for '
+ f'saving reports')
raise exc
if not is_writable(args.output_dir):
raise OSError(f'Output Folder {args.output_dir} is not writable')
+
+ check_path(args.config, '--config')
+ check_path(args.ref_protocol_path, '--ref-protocol-path')
+ check_path(args.mrds_pkl_path, '--mrds-pkl-path')
return args
+def check_path(path, arg_name):
+ """Validates if the path is a valid file"""
+ if path is not None:
+ if not Path(path).is_file():
+ raise OSError(
+ f'Expected valid file for {arg_name} argument, Got {path}')
+
+
if __name__ == "__main__":
- sys.exit(main()) # pragma: no cover
+ cli()
diff --git a/mrQA/common.py b/mrQA/common.py
deleted file mode 100644
index e8054ba..0000000
--- a/mrQA/common.py
+++ /dev/null
@@ -1,16 +0,0 @@
-import logging
-
-from pathlib import Path
-
-
-def set_logging(name):
- format_string = '%(asctime)s - %(levelname)s - %(message)s'
- formatter = logging.Formatter(fmt=format_string)
- handler = logging.StreamHandler()
- # dup_filter = DuplicateFilter()
- logger = logging.getLogger(name)
- logger.setLevel(logging.DEBUG)
- # handler.addFilter(dup_filter)
- handler.setFormatter(formatter)
- logger.addHandler(handler)
- return logger
diff --git a/mrQA/config.py b/mrQA/config.py
index 7935175..715fc22 100644
--- a/mrQA/config.py
+++ b/mrQA/config.py
@@ -1,20 +1,65 @@
+import logging
+import tempfile
from pathlib import Path
+
from MRdataset import MRDS_EXT
from MRdataset.config import MRException
+from protocol import UnspecifiedType
-STRATEGIES_ALLOWED = ['majority', ]
+def configure_logger(log, output_dir, mode='w', level='WARNING'):
+ """
+ Initiate log files.
+
+ Parameters
+ ----------
+ log : logging.Logger
+ The logger object.
+ mode : str, (``'w'``, ``'a'``)
+ The writing mode to the log files.
+ Defaults to ``'w'``, overwrites previous files.
+ output_dir : str or Path
+ The path to the output directory.
+ level : str,
+ The level of logging to the console. One of ['WARNING', 'ERROR']
+ """
-PARAMETER_NAMES = [
- 'Manufacturer',
- 'BodyPartExamined',
- 'RepetitionTime',
- 'MagneticFieldStrength',
- 'FlipAngle',
- 'EchoTrainLength',
- 'PixelBandwidth',
- 'NumberOfPhaseEncodingSteps',
- ]
+ console_handler = logging.StreamHandler() # creates the handler
+ warn_formatter = ('%(filename)s:%(name)s:%(funcName)s:%(lineno)d:'
+ ' %(message)s')
+ error_formatter = '%(asctime)s - %(levelname)s - %(message)s'
+ if output_dir is None:
+ output_dir = tempfile.gettempdir()
+ output_dir = Path(output_dir) / '.mrdataset'
+ output_dir.mkdir(parents=True, exist_ok=True)
+
+ options = {
+ "warn": {
+ 'level': logging.WARN,
+ 'file': output_dir / 'warn.log',
+ 'formatter': warn_formatter
+ },
+ "error": {
+ 'level': logging.ERROR,
+ 'file': output_dir / 'error.log',
+ 'formatter': error_formatter
+ }
+ }
+
+ if level == 'ERROR':
+ config = options['error']
+ else:
+ config = options['warn']
+
+ file_handler = logging.FileHandler(config['file'], mode=mode)
+ file_handler.setLevel(config['level'])
+ file_handler.setFormatter(logging.Formatter(config['formatter']))
+ log.addHandler(file_handler)
+
+ console_handler.setLevel(config['level']) # sets the handler info
+ console_handler.setFormatter(logging.Formatter(config['formatter']))
+ log.addHandler(console_handler)
+ return log
PATH_CONFIG = {
@@ -23,83 +68,110 @@
}
DATE_SEPARATOR = '_DATE_'
+ATTRIBUTE_SEPARATOR = '_ATTR_'
+
+Unspecified = UnspecifiedType()
def past_records_fpath(folder):
- return Path(folder/'past_record.txt')
+ """Constructs the path to the past record file"""
+ return Path(folder / 'past_record.txt')
+
+
+def status_fpath(folder):
+ """Constructs the path to the status file"""
+ return Path(folder / 'non_compliance_log.txt')
def report_fpath(folder_path, fname):
+ """Constructs the path to the report file"""
return folder_path / f'{fname}.html'
def mrds_fpath(folder_path, fname):
+ """Constructs the path to the MRDS file"""
return folder_path / f'{fname}{MRDS_EXT}'
def subject_list_dir(folder_path, fname):
+ """Constructs the path to the folder containing subject list files"""
return folder_path / f'{fname}_files'
class CannotComputeMajority(MRException):
"""Custom error that is raised when majority cannot be computed."""
- def __init__(self, name, te):
- super().__init__(
- f"Could not compute majority for {name} with echo time {te}")
-
-
-class ReferenceNotSetForModality(MRException):
- """Custom error that is raised when majority cannot be computed."""
-
def __init__(self, name):
super().__init__(
- f"Cannot compute delta for runs in modality {name}"
- f"as not reference protocol doesn't exist.")
-
-
-class ReferenceNotSetForEchoTime(MRException):
- """Custom error that is raised when majority cannot be computed."""
-
- def __init__(self, name, echo_time):
- super().__init__(
- f"Cannot compute delta for runs in modality {name} "
- f"with TE {echo_time}"
- f" as not reference protocol is not set.")
-
-
-class ComplianceException(Exception):
- """
- Custom error that is raised when some critical properties are not
- found in dicom file
- """
- def __init__(self, message, **kwargs):
- super().__init__(message)
-
-
-class EmptySubject(ComplianceException):
- """"""
- pass
-
-
-class NonCompliantSubject(ComplianceException):
- """"""
- pass
-
-
-class ChangingParamsinSeries(ComplianceException):
- """
- Custom error that is raised when parameter values are different for
- different slices even though the SeriesInstanceUID is same.
- """
-
-
- def __init__(self, filepath):
- super().__init__("Expected all dicom slices to have same parameters. "
- "Got changing parameters : {}".format(filepath))
-
-
-class ComplianceWarning(Warning):
- """Library specific exception"""
-
- pass
+ f"Could not compute majority for {name}")
+
+#
+# class ReferenceNotSetForModality(MRException):
+# """Custom error that is raised when majority cannot be computed."""
+#
+# def __init__(self, name):
+# super().__init__(
+# f"Cannot compute delta for runs in modality {name}"
+# f"as not reference protocol doesn't exist.")
+#
+#
+# class ReferenceNotSetForEchoTime(MRException):
+# """Custom error that is raised when majority cannot be computed."""
+#
+# def __init__(self, name, echo_time):
+# super().__init__(
+# f"Cannot compute delta for runs in modality {name} "
+# f"with TE {echo_time}"
+# f" as not reference protocol is not set.")
+#
+#
+# class ComplianceException(Exception):
+# """
+# Custom error that is raised when some critical properties are not
+# found in dicom file
+# """
+#
+# def __init__(self, message, **kwargs):
+# super().__init__(message)
+#
+#
+# class EmptySubject(ComplianceException):
+# """"""
+# pass
+#
+#
+# class NonCompliantSubject(ComplianceException):
+# """"""
+# pass
+#
+#
+# class ChangingParamsinSeries(ComplianceException):
+# """
+# Custom error that is raised when parameter values are different for
+# different slices even though the SeriesInstanceUID is same.
+# """
+#
+# def __init__(self, filepath):
+# super().__init__("Expected all dicom slices to have same parameters. "
+# "Got changing parameters : {}".format(filepath))
+#
+#
+# class ComplianceWarning(Warning):
+# """Library specific exception"""
+#
+# pass
+
+
+class EqualCountType(UnspecifiedType):
+
+ def __init__(self):
+ super().__init__()
+
+ def __str__(self):
+ return 'EqualCount'
+
+ def __repr__(self):
+ return 'EqualCount'
+
+
+EqualCount = EqualCountType()
diff --git a/mrQA/criteria.yaml b/mrQA/criteria.yaml
deleted file mode 100644
index a600913..0000000
--- a/mrQA/criteria.yaml
+++ /dev/null
@@ -1,60 +0,0 @@
-manufacturer:
- enabled: true
- mode: single
- value: siemens
-organ:
- enabled: true
- mode: single
- value: brain
-te:
- enabled: true
- mode: range
- value: None
-tr:
- enabled: true
- mode: range
- value: None
-b0:
- enabled: true
- mode: single
- value: None
-flip_angle:
- enabled: true
- mode: range
- value: None
-bwpx:
- enabled: true
- mode: range
- value: None
-comments:
- enabled: false
- mode: single
- value: None
-scanning_sequence:
- enabled: true
- mode: single
- value: None
-sequence_variant:
- enabled: true
- mode: single
- value: None
-mr_acquisition_type:
- enabled: true
- mode: single
- value: None
-phase_encoding_lines:
- enabled: true
- mode: multiple
- value: ['ROW', 'COL']
-bwp_phase_encode:
- enabled: true
- mode: single
- value: None
-echo_train_length:
- enabled: true
- mode: single
- value: None
-phase_encoding_direction:
- enabled: true
- mode: single
- value: None
diff --git a/mrQA/formatter.py b/mrQA/formatter.py
index ea37728..b811063 100644
--- a/mrQA/formatter.py
+++ b/mrQA/formatter.py
@@ -1,12 +1,15 @@
+import importlib
import smtplib
import ssl
from abc import ABC, abstractmethod
from email import encoders
from email.mime import base, multipart, text
from pathlib import Path
-import importlib
+
import jinja2
+from mrQA import logger
+
class Formatter(ABC):
def __init__(self):
@@ -94,19 +97,160 @@ def render(self, *args, **kwargs):
class HtmlFormatter(BaseFormatter):
- def __init__(self, filepath, params, render=True):
+ """
+ Class to create an HTML report for compliance evaluation.
+
+ Parameters
+ ----------
+ filepath : str
+ Path to the html file to be created
+ render : bool
+ If True, the report is rendered immediately. Otherwise, the render
+ method needs to be called explicitly.
+ """
+
+ def __init__(self, filepath, render=False):
super(HtmlFormatter, self).__init__(filepath)
self.template_folder = Path(__file__).resolve().parent
- self.params = params
+ self.hz_audit = None
+ self.vt_audit = None
+ self.plots = {}
+ self.complete_ds = None
+
+ self.skip_hz_report = False
+ self.skip_vt_report = False
+ self.skip_plots = True
if render:
self.render()
+ def collect_hz_audit_results(self,
+ compliant_ds,
+ non_compliant_ds,
+ undetermined_ds,
+ subject_lists_by_seq,
+ complete_ds,
+ ref_protocol,
+ **kwargs):
+ """
+ Collects results from horizontal audit and stores them. The
+ dictionary is then passed to the jinja2 template for rendering.
+
+ Parameters
+ ----------
+ compliant_ds : BaseDataset
+ Dataset containing compliant sequences
+ non_compliant_ds : BaseDataset
+ Dataset containing non-compliant sequences
+ undetermined_ds : BaseDataset
+ Dataset containing sequences that could not be determined
+ subject_lists_by_seq : dict
+ Dictionary containing subject lists for each sequence
+ complete_ds : BaseDataset
+ Dataset containing all sequences
+ ref_protocol : dict
+ Reference protocol
+ kwargs : dict
+ Additional arguments to pass to the jinja2 template
+ """
+ if not complete_ds.get_sequence_ids():
+ logger.error('No sequences found in dataset. Cannot generate'
+ 'report')
+ self.skip_hz_report = True
+ if not ref_protocol:
+ logger.error('Reference protocol is empty. Cannot generate'
+ ' report for horizontal audit.')
+ self.skip_hz_report = True
+ if not (compliant_ds.get_sequence_ids() or
+ non_compliant_ds.get_sequence_ids() or
+ undetermined_ds.get_sequence_ids()):
+ logger.error('It seems the dataset has not been checked for '
+ 'horizontal audit. Skipping horizontal audit report')
+ self.skip_hz_report = True
+
+ self.hz_audit = {
+ 'protocol': ref_protocol,
+ 'compliant_ds': compliant_ds,
+ 'non_compliant_ds': non_compliant_ds,
+ 'undetermined_ds': undetermined_ds,
+ 'sub_lists_by_seq': subject_lists_by_seq,
+ }
+
+ # add any additional kwargs to the hz_audit dict
+ for key, value in kwargs.items():
+ self.hz_audit[key] = value
+
+ self.complete_ds = complete_ds
+
+ def collect_vt_audit_results(self,
+ compliant_ds,
+ non_compliant_ds,
+ sequence_pairs,
+ complete_ds,
+ parameters,
+ **kwargs):
+ """
+ Collects results from horizontal audit and stores them. The
+ dictionary is then passed to the jinja2 template for rendering.
+
+ Parameters
+ ----------
+ compliant_ds : BaseDataset
+ Dataset containing compliant sequences
+ non_compliant_ds : BaseDataset
+ Dataset containing non-compliant sequences
+ complete_ds : BaseDataset
+ Dataset containing all sequences
+ sequence_pairs : list
+ Sequence pairs compared for vertical audit. For ex.
+ [('gre-field-mapping', 'rs-fMRI'), ('T1w', 'T2w')]
+ parameters : list
+ Parameters used for vertical audit.
+ For ex. ['ShimSetting, 'FlipAngle']
+ kwargs : dict
+ Additional arguments to pass to the jinja2 template
+ """
+
+ if not complete_ds.get_sequence_ids():
+ logger.error('No sequences found in dataset. Cannot generate'
+ 'report')
+ self.skip_vt_report = True
+ if not (compliant_ds.get_sequence_ids() or
+ non_compliant_ds.get_sequence_ids()):
+ logger.error('It seems the dataset has not been checked for '
+ 'vertical audit. Skipping vertical audit report')
+ self.skip_vt_report = True
+
+ self.vt_audit = {
+ 'complete_ds': complete_ds,
+ 'compliant_ds': compliant_ds,
+ 'non_compliant_ds': non_compliant_ds,
+ 'sequence_pairs': sequence_pairs,
+ 'parameters': parameters
+ }
+
+ # add any additional kwargs to the vt_audit dict
+ for key, value in kwargs.items():
+ self.vt_audit[key] = value
+
+ self.complete_ds = complete_ds
+
+ def collect_plots(self, **kwargs):
+ for key, value in kwargs.items():
+ self.plots[key] = value
+
+ if not self.plots:
+ logger.error('No plots found. Skipping plots section in report')
+ self.skip_plots = True
+
def render(self):
"""
- Render html page using jinja2
- :param
- :return:
+ Renders the html report using jinja2 template. It will skip horizontal
+ or vertical audit report if the corresponding audit was not performed.
"""
+ if self.skip_hz_report and self.skip_vt_report:
+ logger.error('Cannot generate report. See error log for details')
+ return
+
fs_loader = jinja2.FileSystemLoader(searchpath=self.template_folder)
extn = ['jinja2.ext.loopcontrols']
template_env = jinja2.Environment(loader=fs_loader, extensions=extn)
@@ -115,20 +259,14 @@ def render(self):
template = template_env.get_template(template_file)
output_text = template.render(
- dataset=self.params['ds'],
- sub_lists_by_modality=self.params['sub_lists_by_modality'],
- # time=self.params['time'],
+ hz=self.hz_audit,
+ vt=self.vt_audit,
+ plots=self.plots,
+ skip_hz_report=self.skip_hz_report,
+ skip_vt_report=self.skip_vt_report,
+ skip_plots=self.skip_plots,
+ complete_ds=self.complete_ds,
imp0rt=importlib.import_module
)
- # self.output = weasyprint.HTML(string=output_text)
f = open(self.filepath, 'w')
f.write(output_text)
-
-
-class PdfFormatter(HtmlFormatter):
- def __init__(self, filepath, params):
- super().__init__(filepath, params)
- # self.output = super(PdfFormatter, self).render(params)
-
- def render(self):
- return self.output.write_pdf(self.filepath)
diff --git a/mrQA/layout.html b/mrQA/layout.html
index 700b41a..6cd5196 100644
--- a/mrQA/layout.html
+++ b/mrQA/layout.html
@@ -4,7 +4,32 @@
+
+
+
+
{{ title }}
@@ -68,129 +101,163 @@
{% set utils = imp0rt('mrQA.utils') %}
-Summary of non-compliance:
-List of non-compliant modalities
- - {{ dataset.non_compliant_modality_names|length }}
-
-
-
- Modality |
- # non-compliant (%) |
- Non-compliant subjects |
- Parameters |
- # compliant (%) |
- # subjects |
- {# # Echo-Times | #}
+Summary of non-compliance: {{ hz['compliant_ds'].name }}
+{% if not skip_plots %}
+ {% for key in plots %}
+
+ {{ plots[key].div | safe }}
+ {{ plots[key].script | safe }}
+
+ {% endfor %}
+{% endif %}
- {# errors | #}
-
-
-
- {% for modality in dataset.modalities|sort %}
- {% if not modality.compliant %}
- {% if modality.subjects|length > 2 %}
+{% if not skip_hz_report %}
+
+ Horizontal Audit
+ Reference Protocol Type : {{ hz['protocol'].type.name }}
+ List of non-compliant modalities
+ - {{ hz['non_compliant_ds'].get_sequence_ids()|length }}
+
+
+
+ Modality |
+ # non-compliant (%) |
+ Non-compliant subjects |
+ Parameters |
+ # compliant (%) |
+ # subjects |
+
+
+
+ {% for seq_id in hz['non_compliant_ds'].get_sequence_ids()|sort %}
+ {% set ncomp_sub_ids = hz['non_compliant_ds'].get_subject_ids(seq_id) %}
+ {% set seq_name_wo_tag = seq_id.split('_ATTR_') %}
+ {% set total_subjects = complete_ds.get_subject_ids(seq_name_wo_tag[0]) |
+ length %}
+ {% set comp_subject_count = total_subjects - ncomp_sub_ids|length %}
+ {% set non_compliant_params =
+ hz['non_compliant_ds'].get_nc_param_ids(seq_id) %}
+ {% if hz['non_compliant_ds'].get_subject_ids(seq_id) %}{#
+ |length > 2 #}
- {{ modality.name }} |
- {% set percent_non_compliant = 100 * modality.non_compliant_subject_names|length|float / modality.subjects|length|float %}
- {% set percent_compliant = 100 * modality.compliant_subject_names|length|float / modality.subjects|length|float %}
+ {{ seq_id }} |
+ {% set percent_non_compliant = 100 * ncomp_sub_ids|length|float /
+ total_subjects %}
+ {% set percent_compliant = 100 * comp_subject_count|float /
+ total_subjects %}
- {{ modality.non_compliant_subject_names|length }}
+ {{ ncomp_sub_ids | length }}
({{ percent_non_compliant|round(2, 'floor') }} %)
|
- {% if modality.non_compliant_subject_names|length < 50 %}
- {% for name in modality.non_compliant_subject_names|sort %}
+ {% if ncomp_sub_ids|length < 50 %}
+ {% for name in ncomp_sub_ids|sort %}
{{ name }},
{% endfor %}
{% else %}
Too many to fit here. Click
- here
+ here
for full list.
{% endif %}
|
- {% for parameter in modality.non_compliant_params()|sort %}
+ {% for parameter in
+ hz['non_compliant_ds'].get_nc_param_ids(seq_id)|sort %}
{{ parameter }},
{% endfor %}
|
- {{ modality.compliant_subject_names|length }}
+ {{ comp_subject_count }}
( {{ percent_compliant|round(2, 'floor') }} %)
|
- {{ modality.subjects|length }}
+ {{ total_subjects }}
|
- {# #}
- {# {{ modality.get_echo_times() | length }}#}
- {# | #}
- {# #}
- {# {{ mode.error_children|length }}#}
- {# | #}
{% endif %}
- {% endif %}
- {% endfor %}
-
-
- List of fully compliant modalities
- : {{ dataset.compliant_modality_names | length }}
-
- {% set cols = 4 %}
- {% set rows = (dataset.compliant_modality_names|length // cols) + 1 %}
-
- {% for i in range(rows) %}
-
- {% for j in range(cols) %}
- {% set index = i * cols + j %}
- {% if index < dataset.compliant_modality_names|length %}
-
- {{ dataset.compliant_modality_names[index] }}
- |
- {% endif %}
- {% endfor %}
-
- {% endfor %}
-
-
-
-
-{% for modality in dataset.modalities|sort %}
-
- {% if not modality.compliant %}
- {% if modality.get_echo_times() %}
- Modality : {{ modality.name }}
- {% endif %}
- {% for echo_time in modality.get_echo_times()|sort %}
- {% set te = echo_time %}
- {% set reference = modality.get_reference(echo_time) %}
- {% set runs_by_echo = utils._get_runs_by_echo(modality, 3) %}
- Reference {{ loop.index }} | Number of Runs
- : {{ runs_by_echo[te]|length }}
+ {% endfor %}
+
+
-
-
+ {% set comp_sequences = hz['compliant_ds'].get_sequence_ids() %}
+ Fully compliant modalities
+ : {{ comp_sequences | length }}
+ {% if comp_sequences|length > 0 %}
+
+ {% set cols = 4 %}
+ {% set rows = (comp_sequences |length // cols) + 1 %}
+
+ {% for i in range(rows) %}
- {% for key in reference.keys()|sort %}
- {{ key }} |
+ {% for j in range(cols) %}
+ {% set index = i * cols + j %}
+ {% if index < comp_sequences |length %}
+
+ {{ comp_sequences[index] }}
+ |
+ {% endif %}
{% endfor %}
+ {% endfor %}
+
+
+ {% endif %}
-
-
+ {% set und_sequences = hz['undetermined_ds'].get_sequence_ids() %}
+ {% if und_sequences|length > 0 %}
+ Modalities for which compliance could not be determined
+ : {{ und_sequences | length }}
+
+ {% set cols = 4 %}
+ {% set rows = (und_sequences |length // cols) + 1 %}
+
+ {% for i in range(rows) %}
- {% for key in reference.keys()|sort %}
- {{ reference[key] }} |
+ {% for j in range(cols) %}
+ {% set index = i * cols + j %}
+ {% if index < und_sequences |length %}
+
+ {{ und_sequences[index] }}
+ |
+ {% endif %}
{% endfor %}
-
-
- {% if modality.non_compliant_params(te).any() %}
-
+ {% endif %}
+
+ {% for seq_id in hz['non_compliant_ds'].get_sequence_ids()|sort %}
+ Sequence : {{ seq_id }}
+ {% set ref = hz['protocol'][seq_id] %}
+ Reference
+
+
+
+ {% for param in ref|sort %}
+ {{ param }} |
+ {% endfor %}
+
+
+
+
+ {% for param in ref|sort %}
+ {{ ref[param].get_value() }} |
+ {% endfor %}
+
+
+
+ {% set non_compliant_params =
+hz['non_compliant_ds'].get_nc_param_ids(seq_id) %}
+ {% if non_compliant_params|length %}
+
Reference {{ loop.index }} | Number of Runs
colspan="4">Found
|
Subject_Session
+ colspan="4">Subject
|
- {% endif %}
- {% for parameter in modality.non_compliant_params(te)|sort %}
- {# {% set reasons = modality.query_by_param(parameter, te) %}#}
-
- {{ parameter }} |
-
- {% for value in modality.query_by_param(parameter, te, 'ref_value') %}
- {{ value }},
- {% endfor %}
- |
-
- {% for value in modality.query_by_param(parameter, te, 'new_value') %}
- {{ value }},
- {% endfor %}
- |
-
- {% for subject in modality.query_by_param(parameter, te, 'subjects') %}
- {{ subject }},
+ {% for parameter in non_compliant_params|sort %}
+ {% set nc_data = hz['non_compliant_ds'].get_nc_param_values(seq_id,
+ parameter)|list %}
+ {% set nc_dict = utils.tuples2dict(nc_data) %}
+ |
+
+ {{ parameter }}
+ |
+
+ {{ ref[parameter].get_value() }}
+ |
+
+ {% for nc_param, tuples in nc_dict.items() %}
+
+
+ {{ nc_param.get_value() }},
+ |
+
+ {% for sub, path in tuples %}
+ {{ sub }},
+ {% endfor %}
+ |
+
{% endfor %}
-
-
- {% endfor %}
-
-
- {% endfor %}
- {% if modality.error_subject_names() %}
-
-
-
- Error
- |
- Subject_Session
- |
-
-
-
-
- Could not compute
- non-compliance
- |
-
- {% for entry in modality.error_subject_names() %}
- {{ entry }},
- {% endfor %}
- |
-
+ {% endfor %}
{% endif %}
- {% endif %}
-{% endfor %}
+ {% endfor %}
+ {% for seq_id in hz['compliant_ds'].get_sequence_ids()|sort %}
+ Sequence : {{ seq_id }}
+ {% set ref = hz['protocol'][seq_id] %}
+
-{% for modality in dataset.modalities|sort %}
- {% if modality.compliant %}
- Modality : {{ modality.name }}
- {% if not modality.get_echo_times() %}
- Warning : Could not compute
- reference
- {% endif %}
- {% for echo_time in modality.get_echo_times()|sort %}
- {% set te = echo_time %}
- {% set reference = modality.get_reference(echo_time) %}
- {% set runs_by_echo = utils._get_runs_by_echo(modality, 3) %}
- {# {% if modality.is_multi_echo() %}#}
- Reference {{ loop.index }} | Number of Runs
- : {{ runs_by_echo[te]|length }}
- {# {% else %}#}
- {# Reference
#}
- {# {% endif %}#}
-
-
-
- {% for key in reference.keys()|sort %}
- {{ key }} |
- {% endfor %}
-
-
-
-
-
- {% for key in reference.keys()|sort %}
- {{ reference[key] }} |
- {% endfor %}
-
-
-
- {% endfor %}
- {% if modality.error_subject_names() %}
-
-
-
- Error
- |
- Subject_Session
- |
-
-
-
-
- Could not compute
- non-compliance
- |
-
- {% for entry in modality.error_subject_names() %}
- {{ entry }},
- {% endfor %}
+
+
+
+ {% for param in ref|sort %}
+ {{ param }} |
+ {% endfor %}
+
+
+
+
+ {% for param in ref|sort %}
+ {{ ref[param].get_value() }}
|
-
-
-
- {% endif %}
- {% endif %}
-{% endfor %}
+ {% endfor %}
+ |
+
+
+ {% endfor %}
+{% endif %}
+{% if not skip_vt_report %}
+ Vertical Audit
+
+
+
+ Parameters |
+ # non-compliant (%) |
+ {% for pair in vt['sequence_pairs'] %}
+ {{ pair[0] }}, {{ pair[1] }}
+ |
+ {% endfor %}
+
+
+
+ {% for param in vt['parameters'] %}
+
+ {{ param }} |
+
+ {% set total_subjects = vt['complete_ds'].subjects() | length | float %}
+ {% set nc_subjects = vt['non_compliant_ds'].total_nc_subjects_by_parameter(param) | float %}
+ {% set percent_non_comp = 100 * nc_subjects/total_subjects %}
+ {{ nc_subjects }}
+ ({{ percent_non_comp| round(2, 'floor') }} %)
+ |
+ {% for pair in vt['sequence_pairs'] %}
+
+ {% if param in vt['non_compliant_ds'].get_nc_param_ids(pair[0]) %}
+ {% set val = vt['non_compliant_ds'].get_nc_subject_ids(pair[0], param, pair[1]) %}
+ {% for sub in val %}
+ {{ sub }},
+ {% endfor %}
+ {% endif %} |
+ {% endfor %}
+ {% endfor %}
+
+ # non-compliant (%) |
+ |
+ {% for pair in vt['sequence_pairs'] %}
+
+ {# {% if param in vt['nc_ds'].get_nc_param_ids(pair[0]) %}#}
+ {% set nc_subjects = vt['non_compliant_ds'].total_nc_subjects_by_sequence(pair[0], ref_seq=pair[1]) %}
+ {% set original_seq_name = vt['non_compliant_ds'].get_original_seq_name(pair[0]) %}
+ {% set total_subjects = vt['complete_ds'].get_subject_ids(original_seq_name) | length | float %}
+ {% set percent_non_comp = 100 * nc_subjects/total_subjects %}
+ {{ nc_subjects }} ({{ percent_non_comp| round(2, 'floor') }} %)
+ {# {% endif %}#}
+ |
+ {% endfor %}
+
+
+
+{% endif %}