mrsuite 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mrsuite-0.0.1/LICENSE +21 -0
- mrsuite-0.0.1/PKG-INFO +161 -0
- mrsuite-0.0.1/README.md +121 -0
- mrsuite-0.0.1/mrsuite/__init__.py +54 -0
- mrsuite-0.0.1/mrsuite/basic_driver.py +112 -0
- mrsuite-0.0.1/mrsuite/benchmark/__init__.py +24 -0
- mrsuite-0.0.1/mrsuite/benchmark/radar.py +247 -0
- mrsuite-0.0.1/mrsuite/benchmark/scoring.py +554 -0
- mrsuite-0.0.1/mrsuite/bridges/__init__.py +21 -0
- mrsuite-0.0.1/mrsuite/bridges/augmentrum.py +165 -0
- mrsuite-0.0.1/mrsuite/bridges/base.py +349 -0
- mrsuite-0.0.1/mrsuite/bridges/fid_a.py +861 -0
- mrsuite-0.0.1/mrsuite/bridges/fsl_mrs.py +604 -0
- mrsuite-0.0.1/mrsuite/bridges/lcmodel.py +177 -0
- mrsuite-0.0.1/mrsuite/bridges/mrspeclab.py +386 -0
- mrsuite-0.0.1/mrsuite/bridges/mrspeclab_driver.py +141 -0
- mrsuite-0.0.1/mrsuite/bridges/nifti_mrs.py +99 -0
- mrsuite-0.0.1/mrsuite/bridges/osprey.py +558 -0
- mrsuite-0.0.1/mrsuite/bridges/pyamares.py +315 -0
- mrsuite-0.0.1/mrsuite/bridges/spant.py +383 -0
- mrsuite-0.0.1/mrsuite/bridges/suspect.py +331 -0
- mrsuite-0.0.1/mrsuite/bridges/tarquin.py +211 -0
- mrsuite-0.0.1/mrsuite/bridges/vespa.py +259 -0
- mrsuite-0.0.1/mrsuite/collect.py +364 -0
- mrsuite-0.0.1/mrsuite/core/__init__.py +0 -0
- mrsuite-0.0.1/mrsuite/core/basis.py +230 -0
- mrsuite-0.0.1/mrsuite/core/method.py +370 -0
- mrsuite-0.0.1/mrsuite/core/parallel.py +158 -0
- mrsuite-0.0.1/mrsuite/core/pipeline.py +613 -0
- mrsuite-0.0.1/mrsuite/core/provenance.py +226 -0
- mrsuite-0.0.1/mrsuite/core/result.py +243 -0
- mrsuite-0.0.1/mrsuite/datasets/__init__.py +13 -0
- mrsuite-0.0.1/mrsuite/datasets/agnostic.py +126 -0
- mrsuite-0.0.1/mrsuite/datasets/challenge2016.py +501 -0
- mrsuite-0.0.1/mrsuite/datasets/mr_science_lab.py +149 -0
- mrsuite-0.0.1/mrsuite/datasets/mrsi_challenge.py +624 -0
- mrsuite-0.0.1/mrsuite/datasets/openneuro.py +195 -0
- mrsuite-0.0.1/mrsuite/externals.py +236 -0
- mrsuite-0.0.1/mrsuite/gui/__init__.py +13 -0
- mrsuite-0.0.1/mrsuite/gui/__main__.py +107 -0
- mrsuite-0.0.1/mrsuite/gui/app.py +1872 -0
- mrsuite-0.0.1/mrsuite/gui/blocks.py +947 -0
- mrsuite-0.0.1/mrsuite/gui/canvas.js +183 -0
- mrsuite-0.0.1/mrsuite/gui/canvas.py +134 -0
- mrsuite-0.0.1/mrsuite/gui/catalog.py +203 -0
- mrsuite-0.0.1/mrsuite/gui/files.py +135 -0
- mrsuite-0.0.1/mrsuite/gui/graph.py +1257 -0
- mrsuite-0.0.1/mrsuite/gui/static/logo.png +0 -0
- mrsuite-0.0.1/mrsuite/gui/static/mrsuite.css +237 -0
- mrsuite-0.0.1/mrsuite/gui/vendor/vue-flow-background/LICENSE +20 -0
- mrsuite-0.0.1/mrsuite/gui/vendor/vue-flow-background/index.js +126 -0
- mrsuite-0.0.1/mrsuite/gui/vendor/vue-flow-core/LICENSE +20 -0
- mrsuite-0.0.1/mrsuite/gui/vendor/vue-flow-core/index.js +10186 -0
- mrsuite-0.0.1/mrsuite/gui/vendor/vue-flow-core/style.css +248 -0
- mrsuite-0.0.1/mrsuite/gui/vendor/vue-flow-core/theme-default.css +143 -0
- mrsuite-0.0.1/mrsuite/io.py +426 -0
- mrsuite-0.0.1/mrsuite/models/__init__.py +97 -0
- mrsuite-0.0.1/mrsuite/models/base.py +515 -0
- mrsuite-0.0.1/mrsuite/models/convert.py +109 -0
- mrsuite-0.0.1/mrsuite/models/mlp.py +223 -0
- mrsuite-0.0.1/mrsuite/models/pytorch.py +89 -0
- mrsuite-0.0.1/mrsuite/models/reference.py +116 -0
- mrsuite-0.0.1/mrsuite/models/wand.py +263 -0
- mrsuite-0.0.1/mrsuite/mrsi.py +167 -0
- mrsuite-0.0.1/mrsuite/octave/__init__.py +285 -0
- mrsuite-0.0.1/mrsuite/octave/docker.py +194 -0
- mrsuite-0.0.1/mrsuite/octave/dockerfile +42 -0
- mrsuite-0.0.1/mrsuite/octave/matlab.py +172 -0
- mrsuite-0.0.1/mrsuite/octave/sessions.py +91 -0
- mrsuite-0.0.1/mrsuite/octave/shims/contains.m +42 -0
- mrsuite-0.0.1/mrsuite/octave/shims/fftshift.m +52 -0
- mrsuite-0.0.1/mrsuite/octave/shims/hilbert.m +42 -0
- mrsuite-0.0.1/mrsuite/octave/shims/lbfgsb.m +200 -0
- mrsuite-0.0.1/mrsuite/octave/shims/lsqcurvefit.m +22 -0
- mrsuite-0.0.1/mrsuite/octave/shims/lsqnonlin.m +45 -0
- mrsuite-0.0.1/mrsuite/octave/shims/mrsuite_lm.m +99 -0
- mrsuite-0.0.1/mrsuite/octave/shims/nanmedian.m +16 -0
- mrsuite-0.0.1/mrsuite/octave/shims/nlinfit.m +132 -0
- mrsuite-0.0.1/mrsuite/octave/shims/optimoptions.m +11 -0
- mrsuite-0.0.1/mrsuite/octave/shims/optimset.m +39 -0
- mrsuite-0.0.1/mrsuite/octave/shims/padarray.m +47 -0
- mrsuite-0.0.1/mrsuite/octave/shims/sscanf.m +59 -0
- mrsuite-0.0.1/mrsuite/octave/shims/statset.m +56 -0
- mrsuite-0.0.1/mrsuite/octave/src/lbfgsb_quadratic.c +208 -0
- mrsuite-0.0.1/mrsuite/r/__init__.py +135 -0
- mrsuite-0.0.1/mrsuite/r/dockerfile +22 -0
- mrsuite-0.0.1/mrsuite/r/driver.R +135 -0
- mrsuite-0.0.1/mrsuite/simulators/__init__.py +13 -0
- mrsuite-0.0.1/mrsuite/simulators/bases.py +251 -0
- mrsuite-0.0.1/mrsuite/simulators/digital_phantom.py +111 -0
- mrsuite-0.0.1/mrsuite/simulators/digital_phantom_driver.py +60 -0
- mrsuite-0.0.1/mrsuite/simulators/mrs_sim.py +636 -0
- mrsuite-0.0.1/mrsuite/simulators/mrs_sim_driver.py +202 -0
- mrsuite-0.0.1/mrsuite/simulators/mrsandbox.py +426 -0
- mrsuite-0.0.1/mrsuite/simulators/pulses.py +86 -0
- mrsuite-0.0.1/mrsuite/simulators/synthetic.py +143 -0
- mrsuite-0.0.1/mrsuite/testing.py +217 -0
- mrsuite-0.0.1/mrsuite/training/__init__.py +21 -0
- mrsuite-0.0.1/mrsuite/training/loop.py +177 -0
- mrsuite-0.0.1/mrsuite/training/recipe.py +198 -0
- mrsuite-0.0.1/mrsuite/training/source.py +151 -0
- mrsuite-0.0.1/mrsuite.egg-info/PKG-INFO +161 -0
- mrsuite-0.0.1/mrsuite.egg-info/SOURCES.txt +114 -0
- mrsuite-0.0.1/mrsuite.egg-info/dependency_links.txt +1 -0
- mrsuite-0.0.1/mrsuite.egg-info/entry_points.txt +2 -0
- mrsuite-0.0.1/mrsuite.egg-info/requires.txt +24 -0
- mrsuite-0.0.1/mrsuite.egg-info/top_level.txt +1 -0
- mrsuite-0.0.1/pyproject.toml +70 -0
- mrsuite-0.0.1/setup.cfg +4 -0
- mrsuite-0.0.1/tests/test_benchmark_run.py +476 -0
- mrsuite-0.0.1/tests/test_collect.py +273 -0
- mrsuite-0.0.1/tests/test_conformance.py +173 -0
- mrsuite-0.0.1/tests/test_externals.py +297 -0
- mrsuite-0.0.1/tests/test_io.py +699 -0
- mrsuite-0.0.1/tests/test_mrsi.py +77 -0
- mrsuite-0.0.1/tests/test_optional.py +98 -0
mrsuite-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Julian P. Merkofer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
mrsuite-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mrsuite
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: MRS Processing, Analysis, AI Model Integration, and Benchmarking
|
|
5
|
+
Author-email: "Julian P. Merkofer" <j.p.merkofer@tue.nl>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/julianmer/MRSuite
|
|
8
|
+
Keywords: MRS,magnetic resonance spectroscopy,NIfTI-MRS,fitting
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
13
|
+
Requires-Python: >=3.11
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: numpy
|
|
17
|
+
Requires-Dist: pandas
|
|
18
|
+
Requires-Dist: openpyxl
|
|
19
|
+
Requires-Dist: nifti-mrs
|
|
20
|
+
Requires-Dist: nifti-mrs-plus>=0.2.0
|
|
21
|
+
Requires-Dist: spec2nii
|
|
22
|
+
Requires-Dist: oct2py
|
|
23
|
+
Requires-Dist: lcmodel-wrapper>=0.3
|
|
24
|
+
Requires-Dist: tarquin-wrapper>=0.1
|
|
25
|
+
Requires-Dist: h5py
|
|
26
|
+
Requires-Dist: torch
|
|
27
|
+
Requires-Dist: huggingface_hub
|
|
28
|
+
Requires-Dist: safetensors
|
|
29
|
+
Requires-Dist: ssqueezepy>=0.6.6
|
|
30
|
+
Requires-Dist: keras>=3.0
|
|
31
|
+
Requires-Dist: nicegui[native,plotly]<4,>=3.17
|
|
32
|
+
Requires-Dist: suspect
|
|
33
|
+
Requires-Dist: pyAMARES
|
|
34
|
+
Requires-Dist: pypulseq
|
|
35
|
+
Requires-Dist: mrsandbox>=0.1.0
|
|
36
|
+
Requires-Dist: augmentrum>=0.0.3
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: pytest; extra == "dev"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
<div align="center">
|
|
42
|
+
<img src="https://raw.githubusercontent.com/julianmer/MRSuite/main/assets/logo/logo.png" alt="MRSuite Logo" width="130" style="margin-bottom: -5px;"/>
|
|
43
|
+
<h1 style="margin-top: 5px; margin-bottom: 5px;">MRSuite</h1>
|
|
44
|
+
<p style="margin-top: 0px;"><em>MRS Processing, Analysis, AI Model Integration, and Benchmarking</em></p>
|
|
45
|
+
|
|
46
|
+
[](https://www.python.org/)
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
The MRSuite project is an open-source, modular framework for magnetic resonance spectroscopy (MRS) that brings together tools for data handling, signal processing, machine learning, and reproducible reporting in a modular and extensible ecosystem.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Overview
|
|
56
|
+
|
|
57
|
+
MRSuite is designed to support the full MRS workflow, from raw data processing to advanced analysis. It is built around the following core principles:
|
|
58
|
+
- **Modularity**: Each processing and analysis step is encapsulated in reusable, interchangeable modules.
|
|
59
|
+
- **Flexibility**: Custom algorithms, models, and external-language tools can be easily integrated.
|
|
60
|
+
- **Scalability**: Capable of handling large datasets and computationally intensive workflows.
|
|
61
|
+
- **Extensibility**: New modules and features can be added by following a consistent interface.
|
|
62
|
+
- **Reproducibility**: Standardized interfaces and reporting tools ensure transparent, consistent documentation.
|
|
63
|
+
- **Benchmarking**: Built-in tools allow for systematic evaluation across datasets and methods.
|
|
64
|
+
- **Community-Driven**: Open-source development encourages contributions and collaboration.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
MRSuite needs Python 3.11 or newer:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install mrsuite
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The toolboxes MRSuite drives come in as you use them: what pip cannot install (Octave or
|
|
76
|
+
MATLAB, R, FSL-MRS) is named when a step first needs it, and everything else is fetched on
|
|
77
|
+
first use, each under its own licence (FSL-MRS, for one, is for non-commercial use only).
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
## Python
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from mrsuite import fsl_mrs, io, lcmodel
|
|
84
|
+
from mrsuite.benchmark import scoring
|
|
85
|
+
from mrsuite.core.pipeline import Pipeline
|
|
86
|
+
from mrsuite.datasets import challenge2016
|
|
87
|
+
|
|
88
|
+
spectra, water, truth = challenge2016.load() # fetched on first use
|
|
89
|
+
basis = io.basis(challenge2016.BASIS)
|
|
90
|
+
fits = {"LCModel": Pipeline([lcmodel.step.fit(basis=basis)]).run(spectra),
|
|
91
|
+
"FSL-MRS": Pipeline([fsl_mrs.step.fit(basis=basis)]).run(spectra)}
|
|
92
|
+
scores = scoring.score(fits, truth, references=["optimal"], metrics={"mosae": scoring.mae})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
A step is any toolbox's function: `fid_a.step.op_alignAverages(0.2, 'n')`,
|
|
96
|
+
`spant.step.hsvd_filt()`, `osprey.step.op_eccKlose(water)`. Swap one for another and the
|
|
97
|
+
rest of the chain stands. Scoring runs on
|
|
98
|
+
[MRSValidate](https://github.com/JohnLaMaster/MRSValidate), which is not on PyPI yet:
|
|
99
|
+
`pip install git+https://github.com/JohnLaMaster/MRSValidate.git`.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
## Key Components
|
|
103
|
+
|
|
104
|
+
### Processing Pipeline
|
|
105
|
+
A modular pipeline for preprocessing MRS data, including:
|
|
106
|
+
- **Data Import**: Load data from various formats.
|
|
107
|
+
- **Processing**: Choose from a collection of processing steps or add your own.
|
|
108
|
+
- **Provenance**: Every step is recorded in the data's own processing history (NIfTI-MRS): the
|
|
109
|
+
toolbox, its exact version and every argument.
|
|
110
|
+
|
|
111
|
+
### AI Model Zoo
|
|
112
|
+
A collection of (pre-trained) AI models for MRS analysis, including:
|
|
113
|
+
- **Interface**: A standardized interface for integrating AI models into the processing pipeline.
|
|
114
|
+
- **Training**: Train or retrain a model in MRSuite (`model.learn`, one Keras 3 loop, on the CPU,
|
|
115
|
+
CUDA or Apple's MPS), its recipe recorded with it.
|
|
116
|
+
- **Sharing**: Push a model to the Hugging Face Hub and load anyone's by its name.
|
|
117
|
+
|
|
118
|
+
### Benchmarking Suite
|
|
119
|
+
A suite of tools for benchmarking MRS processing and analysis methods, including:
|
|
120
|
+
- **Accuracy and agreement**: MRSuite's own errors (MAE, MOSAE) and every analysis of
|
|
121
|
+
[MRSValidate](https://github.com/JohnLaMaster/MRSValidate) that compares fits with the truth:
|
|
122
|
+
errors, Lin's CCC, regression, Bland-Altman, normality; per metabolite and pooled.
|
|
123
|
+
- **Comparative Analysis**: Compare different methods and configurations on the same data.
|
|
124
|
+
- **Score tables**: One table per measure, by method, reference and metabolite.
|
|
125
|
+
- **Visualization**: A radar of the methods, a corner per aspect, and MRSValidate's plots.
|
|
126
|
+
|
|
127
|
+
### Graphical Interface
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
mrsuite-gui
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Wire blocks on a canvas. One block per step, each offering every toolbox that does it, and
|
|
134
|
+
every function of every toolbox besides. Each block shows what it made, exports it, and
|
|
135
|
+
reads out its NIfTI-MRS header and history. The graph is written out as the Python that
|
|
136
|
+
makes it again.
|
|
137
|
+
|
|
138
|
+

|
|
139
|
+
|
|
140
|
+
*In vivo processing: coils, alignment, outliers, averaging, eddy currents, water, referencing
|
|
141
|
+
and phasing by four toolboxes, then LCModel with the water reference.*
|
|
142
|
+
|
|
143
|
+

|
|
144
|
+
|
|
145
|
+
*A benchmark: the 2016 fitting challenge into four fitters, scored on five aspects against
|
|
146
|
+
the truth and drawn on a radar.*
|
|
147
|
+
|
|
148
|
+

|
|
149
|
+
|
|
150
|
+
*The same processing as the Python it writes.*
|
|
151
|
+
|
|
152
|
+
### Reporting Standards
|
|
153
|
+
A set of standards for generating reproducible reports, including:
|
|
154
|
+
- **Documentation**: Each step of the processing pipeline is documented automatically, in the
|
|
155
|
+
data's history.
|
|
156
|
+
- **Training recipes**: A trained model carries how its training spectra were made, reported as
|
|
157
|
+
the MRSsynMRS minimum standard for synthetic data.
|
|
158
|
+
- **Contribution Guidelines**:
|
|
159
|
+
[CONTRIBUTING.md](https://github.com/julianmer/MRSuite/blob/main/CONTRIBUTING.md) says how to
|
|
160
|
+
add a method, check it, and share a trained model.
|
|
161
|
+
|
mrsuite-0.0.1/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/julianmer/MRSuite/main/assets/logo/logo.png" alt="MRSuite Logo" width="130" style="margin-bottom: -5px;"/>
|
|
3
|
+
<h1 style="margin-top: 5px; margin-bottom: 5px;">MRSuite</h1>
|
|
4
|
+
<p style="margin-top: 0px;"><em>MRS Processing, Analysis, AI Model Integration, and Benchmarking</em></p>
|
|
5
|
+
|
|
6
|
+
[](https://www.python.org/)
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
The MRSuite project is an open-source, modular framework for magnetic resonance spectroscopy (MRS) that brings together tools for data handling, signal processing, machine learning, and reproducible reporting in a modular and extensible ecosystem.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
MRSuite is designed to support the full MRS workflow, from raw data processing to advanced analysis. It is built around the following core principles:
|
|
18
|
+
- **Modularity**: Each processing and analysis step is encapsulated in reusable, interchangeable modules.
|
|
19
|
+
- **Flexibility**: Custom algorithms, models, and external-language tools can be easily integrated.
|
|
20
|
+
- **Scalability**: Capable of handling large datasets and computationally intensive workflows.
|
|
21
|
+
- **Extensibility**: New modules and features can be added by following a consistent interface.
|
|
22
|
+
- **Reproducibility**: Standardized interfaces and reporting tools ensure transparent, consistent documentation.
|
|
23
|
+
- **Benchmarking**: Built-in tools allow for systematic evaluation across datasets and methods.
|
|
24
|
+
- **Community-Driven**: Open-source development encourages contributions and collaboration.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
MRSuite needs Python 3.11 or newer:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install mrsuite
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The toolboxes MRSuite drives come in as you use them: what pip cannot install (Octave or
|
|
36
|
+
MATLAB, R, FSL-MRS) is named when a step first needs it, and everything else is fetched on
|
|
37
|
+
first use, each under its own licence (FSL-MRS, for one, is for non-commercial use only).
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## Python
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from mrsuite import fsl_mrs, io, lcmodel
|
|
44
|
+
from mrsuite.benchmark import scoring
|
|
45
|
+
from mrsuite.core.pipeline import Pipeline
|
|
46
|
+
from mrsuite.datasets import challenge2016
|
|
47
|
+
|
|
48
|
+
spectra, water, truth = challenge2016.load() # fetched on first use
|
|
49
|
+
basis = io.basis(challenge2016.BASIS)
|
|
50
|
+
fits = {"LCModel": Pipeline([lcmodel.step.fit(basis=basis)]).run(spectra),
|
|
51
|
+
"FSL-MRS": Pipeline([fsl_mrs.step.fit(basis=basis)]).run(spectra)}
|
|
52
|
+
scores = scoring.score(fits, truth, references=["optimal"], metrics={"mosae": scoring.mae})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
A step is any toolbox's function: `fid_a.step.op_alignAverages(0.2, 'n')`,
|
|
56
|
+
`spant.step.hsvd_filt()`, `osprey.step.op_eccKlose(water)`. Swap one for another and the
|
|
57
|
+
rest of the chain stands. Scoring runs on
|
|
58
|
+
[MRSValidate](https://github.com/JohnLaMaster/MRSValidate), which is not on PyPI yet:
|
|
59
|
+
`pip install git+https://github.com/JohnLaMaster/MRSValidate.git`.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
## Key Components
|
|
63
|
+
|
|
64
|
+
### Processing Pipeline
|
|
65
|
+
A modular pipeline for preprocessing MRS data, including:
|
|
66
|
+
- **Data Import**: Load data from various formats.
|
|
67
|
+
- **Processing**: Choose from a collection of processing steps or add your own.
|
|
68
|
+
- **Provenance**: Every step is recorded in the data's own processing history (NIfTI-MRS): the
|
|
69
|
+
toolbox, its exact version and every argument.
|
|
70
|
+
|
|
71
|
+
### AI Model Zoo
|
|
72
|
+
A collection of (pre-trained) AI models for MRS analysis, including:
|
|
73
|
+
- **Interface**: A standardized interface for integrating AI models into the processing pipeline.
|
|
74
|
+
- **Training**: Train or retrain a model in MRSuite (`model.learn`, one Keras 3 loop, on the CPU,
|
|
75
|
+
CUDA or Apple's MPS), its recipe recorded with it.
|
|
76
|
+
- **Sharing**: Push a model to the Hugging Face Hub and load anyone's by its name.
|
|
77
|
+
|
|
78
|
+
### Benchmarking Suite
|
|
79
|
+
A suite of tools for benchmarking MRS processing and analysis methods, including:
|
|
80
|
+
- **Accuracy and agreement**: MRSuite's own errors (MAE, MOSAE) and every analysis of
|
|
81
|
+
[MRSValidate](https://github.com/JohnLaMaster/MRSValidate) that compares fits with the truth:
|
|
82
|
+
errors, Lin's CCC, regression, Bland-Altman, normality; per metabolite and pooled.
|
|
83
|
+
- **Comparative Analysis**: Compare different methods and configurations on the same data.
|
|
84
|
+
- **Score tables**: One table per measure, by method, reference and metabolite.
|
|
85
|
+
- **Visualization**: A radar of the methods, a corner per aspect, and MRSValidate's plots.
|
|
86
|
+
|
|
87
|
+
### Graphical Interface
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
mrsuite-gui
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Wire blocks on a canvas. One block per step, each offering every toolbox that does it, and
|
|
94
|
+
every function of every toolbox besides. Each block shows what it made, exports it, and
|
|
95
|
+
reads out its NIfTI-MRS header and history. The graph is written out as the Python that
|
|
96
|
+
makes it again.
|
|
97
|
+
|
|
98
|
+

|
|
99
|
+
|
|
100
|
+
*In vivo processing: coils, alignment, outliers, averaging, eddy currents, water, referencing
|
|
101
|
+
and phasing by four toolboxes, then LCModel with the water reference.*
|
|
102
|
+
|
|
103
|
+

|
|
104
|
+
|
|
105
|
+
*A benchmark: the 2016 fitting challenge into four fitters, scored on five aspects against
|
|
106
|
+
the truth and drawn on a radar.*
|
|
107
|
+
|
|
108
|
+

|
|
109
|
+
|
|
110
|
+
*The same processing as the Python it writes.*
|
|
111
|
+
|
|
112
|
+
### Reporting Standards
|
|
113
|
+
A set of standards for generating reproducible reports, including:
|
|
114
|
+
- **Documentation**: Each step of the processing pipeline is documented automatically, in the
|
|
115
|
+
data's history.
|
|
116
|
+
- **Training recipes**: A trained model carries how its training spectra were made, reported as
|
|
117
|
+
the MRSsynMRS minimum standard for synthetic data.
|
|
118
|
+
- **Contribution Guidelines**:
|
|
119
|
+
[CONTRIBUTING.md](https://github.com/julianmer/MRSuite/blob/main/CONTRIBUTING.md) says how to
|
|
120
|
+
add a method, check it, and share a trained model.
|
|
121
|
+
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
# __init__.py #
|
|
3
|
+
####################################################################################################
|
|
4
|
+
# #
|
|
5
|
+
# Authors: J. P. Merkofer (j.p.merkofer@tue.nl) #
|
|
6
|
+
# #
|
|
7
|
+
# Created: 2026-08-08 #
|
|
8
|
+
# #
|
|
9
|
+
# Purpose: Package entry point. Exposes the toolbox bridges directly (mrsuite.fid_a, #
|
|
10
|
+
# mrsuite.fsl_mrs, mrsuite.osprey, mrsuite.lcmodel) and mrsuite.method, which makes #
|
|
11
|
+
# a function of your own a method, and stamps the shared NIfTI-MRS+ provenance. #
|
|
12
|
+
# Bridges are imported lazily: resolving an Octave-backed one would start a #
|
|
13
|
+
# session, and the FSL-MRS one pulls in the whole FSL-MRS stack, neither of which #
|
|
14
|
+
# a caller who only wants the pipeline should pay for. #
|
|
15
|
+
# #
|
|
16
|
+
####################################################################################################
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
#*************#
|
|
20
|
+
# imports #
|
|
21
|
+
#*************#
|
|
22
|
+
import importlib
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
import nifti_mrs_plus
|
|
26
|
+
|
|
27
|
+
from mrsuite.core.method import Method, method
|
|
28
|
+
|
|
29
|
+
__version__ = "0.0.1"
|
|
30
|
+
|
|
31
|
+
# Same pattern as Augmentrum: stamp the shared wrapper's provenance metadata so
|
|
32
|
+
# processed data records which toolbox touched it.
|
|
33
|
+
nifti_mrs_plus.set_provenance("MRSuite", __version__)
|
|
34
|
+
|
|
35
|
+
_BRIDGES = {"augmentrum", "fid_a", "fsl_mrs", "lcmodel", "mrspeclab", "nifti_mrs", "osprey",
|
|
36
|
+
"pyamares", "spant", "suspect", "tarquin", "vespa"}
|
|
37
|
+
|
|
38
|
+
__all__ = ["__version__", "Method", "method", *sorted(_BRIDGES)]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
#*************#
|
|
42
|
+
# getattr #
|
|
43
|
+
#*************#
|
|
44
|
+
def __getattr__(name: str) -> Any:
|
|
45
|
+
if name in _BRIDGES:
|
|
46
|
+
return importlib.import_module(f"mrsuite.bridges.{name}")
|
|
47
|
+
raise AttributeError(f"module 'mrsuite' has no attribute '{name}'")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
#*********#
|
|
51
|
+
# dir #
|
|
52
|
+
#*********#
|
|
53
|
+
def __dir__():
|
|
54
|
+
return sorted(set(globals()) | _BRIDGES)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
# basic_driver.py #
|
|
3
|
+
####################################################################################################
|
|
4
|
+
# #
|
|
5
|
+
# Authors: J. P. Merkofer (j.p.merkofer@tue.nl) #
|
|
6
|
+
# #
|
|
7
|
+
# Created: 2026-10-09 #
|
|
8
|
+
# #
|
|
9
|
+
# Purpose: Reads and writes basis sets with BasiC, for mrsuite.io. Not imported by MRSuite: BasiC #
|
|
10
|
+
# is a folder of scripts importing each other as top-level modules (core, readers, #
|
|
11
|
+
# writers), so it runs in a process of its own. FIDs come and go as .npz; what BasiC #
|
|
12
|
+
# prints goes to stderr; the job's answer goes to stdout, as JSON; a failure ends it #
|
|
13
|
+
# with one line saying why. #
|
|
14
|
+
# #
|
|
15
|
+
# Usage: python basic_driver.py '<job as JSON>' #
|
|
16
|
+
# #
|
|
17
|
+
####################################################################################################
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
#*************#
|
|
21
|
+
# imports #
|
|
22
|
+
#*************#
|
|
23
|
+
import contextlib
|
|
24
|
+
import json
|
|
25
|
+
import sys
|
|
26
|
+
|
|
27
|
+
import numpy as np
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
#**********#
|
|
31
|
+
# fail #
|
|
32
|
+
#**********#
|
|
33
|
+
def fail(message):
|
|
34
|
+
sys.exit(" ".join(str(message).split()))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
#**********#
|
|
38
|
+
# read #
|
|
39
|
+
#**********#
|
|
40
|
+
def read(job):
|
|
41
|
+
"""The files in the format given or detected, with the parameters given where they state
|
|
42
|
+
none, as one array of FIDs (to ``result``) and what is said of them; the echo time and
|
|
43
|
+
sequence as the basis functions hold them (a reader gives 0 for an echo time not
|
|
44
|
+
stated), else as given."""
|
|
45
|
+
from core.detect import detect_format
|
|
46
|
+
from core.load import fill_missing, load_basis
|
|
47
|
+
|
|
48
|
+
found = detect_format(job["files"])
|
|
49
|
+
fmt = job["format"]
|
|
50
|
+
if fmt == "auto":
|
|
51
|
+
if found["status"] == "ambiguous":
|
|
52
|
+
fail(f"{found['message']} Choose one as format: "
|
|
53
|
+
+ ", ".join(map(repr, found["ambiguous_options"])))
|
|
54
|
+
if found["status"] == "failed":
|
|
55
|
+
fail(found["message"])
|
|
56
|
+
fmt = found["format"]
|
|
57
|
+
stated = found["data"]
|
|
58
|
+
given = {k: job[k] for k in ("sw", "sf", "te")}
|
|
59
|
+
basis = load_basis(job["files"], fmt, sw=stated.get("sw") or given["sw"],
|
|
60
|
+
sf=stated.get("sf") or given["sf"])
|
|
61
|
+
if not basis:
|
|
62
|
+
fail("it found no basis functions in the files")
|
|
63
|
+
fill_missing(basis, given)
|
|
64
|
+
lacking = [k for k in ("sw", "sf") if not all(b.get(k) for b in basis)]
|
|
65
|
+
if lacking:
|
|
66
|
+
fail(f"the files do not state {' or '.join(lacking)}: give "
|
|
67
|
+
+ ", ".join(f"{k}=" for k in lacking))
|
|
68
|
+
if len({len(np.ravel(b["fid"])) for b in basis}) > 1:
|
|
69
|
+
fail("its basis functions differ in length")
|
|
70
|
+
np.savez(job["result"], fids=np.array([np.ravel(b["fid"]) for b in basis]))
|
|
71
|
+
first = basis[0]
|
|
72
|
+
return {"names": [b["name"] for b in basis], "bandwidth": float(first["sw"]),
|
|
73
|
+
"frequency": float(first["sf"]), "centre": first.get("centerFreq"),
|
|
74
|
+
"te": first.get("te") or given["te"], "seq": first.get("seq"), "format": fmt}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
#***********#
|
|
78
|
+
# write #
|
|
79
|
+
#***********#
|
|
80
|
+
def write(job):
|
|
81
|
+
"""The job's basis set (FIDs from ``fids``) written for a tool BasiC writes for; the
|
|
82
|
+
files written."""
|
|
83
|
+
from core.formats import ALL_TOOLS
|
|
84
|
+
from core.write import write_basis
|
|
85
|
+
|
|
86
|
+
tools = {t["id"]: [f["id"] for f in t["formats"]] for t in ALL_TOOLS if not t["dimmed"]}
|
|
87
|
+
if job["tool"] not in tools:
|
|
88
|
+
fail(f"no tool {job['tool']!r}; one of: {', '.join(tools)}")
|
|
89
|
+
outputs = tools[job["tool"]]
|
|
90
|
+
if job["output"] != "default" and job["output"] not in outputs:
|
|
91
|
+
fail(f"{job['tool']} writes output 'default'"
|
|
92
|
+
+ "".join(f", {o!r}" for o in outputs) + f", not {job['output']!r}")
|
|
93
|
+
fids = np.load(job["fids"])["fids"]
|
|
94
|
+
basis = [{"fid": fid, "name": name, "n": len(fid), "sw": job["bandwidth"],
|
|
95
|
+
"sf": job["frequency"], "centerFreq": job["centre"], "te": job["te"],
|
|
96
|
+
"seq": job["seq"]} for name, fid in zip(job["names"], fids)]
|
|
97
|
+
written = write_basis(basis, job["tool"], job["output"], job["folder"], te=job["te"],
|
|
98
|
+
seq=job["seq"])
|
|
99
|
+
if not written: # its writers go on without what they fail
|
|
100
|
+
fail("it wrote nothing")
|
|
101
|
+
return written
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
if __name__ == "__main__":
|
|
105
|
+
try:
|
|
106
|
+
with contextlib.redirect_stdout(sys.stderr):
|
|
107
|
+
job = json.loads(sys.argv[1])
|
|
108
|
+
sys.path.insert(0, job["root"])
|
|
109
|
+
answer = {"read": read, "write": write}[job["task"]](job)
|
|
110
|
+
except Exception as err: # noqa: BLE001 - said, in one line
|
|
111
|
+
fail(f"{type(err).__name__}: {err}")
|
|
112
|
+
print(json.dumps(answer))
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
# __init__.py #
|
|
3
|
+
####################################################################################################
|
|
4
|
+
# #
|
|
5
|
+
# Authors: J. P. Merkofer (j.p.merkofer@tue.nl) #
|
|
6
|
+
# #
|
|
7
|
+
# Created: 2026-10-01 #
|
|
8
|
+
# #
|
|
9
|
+
# Purpose: Benchmarking on MRSValidate. Fits and ground truth become its ObservationSets on a #
|
|
10
|
+
# reference the caller names (water, tCr, the optimal scale or none), every metric runs #
|
|
11
|
+
# as a step of its analysis plan, and radar draws the resulting scores. #
|
|
12
|
+
# #
|
|
13
|
+
####################################################################################################
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
#*************#
|
|
17
|
+
# imports #
|
|
18
|
+
#*************#
|
|
19
|
+
from mrsuite.benchmark.radar import plot_scores, radar
|
|
20
|
+
from mrsuite.benchmark.scoring import (REFERENCES, analyses, bias, coverage, figure, mae,
|
|
21
|
+
observations, optimal_scale, score)
|
|
22
|
+
|
|
23
|
+
__all__ = ["REFERENCES", "observations", "optimal_scale", "score", "analyses", "figure",
|
|
24
|
+
"coverage", "mae", "bias", "radar", "plot_scores"]
|