lcmodel-wrapper 0.2.0__tar.gz → 0.3.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.
- lcmodel_wrapper-0.3.1/NOTICE +24 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/PKG-INFO +21 -10
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/README.md +19 -9
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/lcmodel_wrapper/__init__.py +10 -2
- lcmodel_wrapper-0.3.1/lcmodel_wrapper/_version.py +4 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/lcmodel_wrapper/basis.py +5 -5
- lcmodel_wrapper-0.3.1/lcmodel_wrapper/binaries.py +736 -0
- lcmodel_wrapper-0.3.1/lcmodel_wrapper/container.py +163 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/lcmodel_wrapper/control.py +40 -55
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/lcmodel_wrapper/convert.py +18 -25
- lcmodel_wrapper-0.3.1/lcmodel_wrapper/coord.py +115 -0
- lcmodel_wrapper-0.3.1/lcmodel_wrapper/core.py +379 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/lcmodel_wrapper/io.py +96 -87
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/lcmodel_wrapper.egg-info/PKG-INFO +21 -10
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/lcmodel_wrapper.egg-info/SOURCES.txt +5 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/lcmodel_wrapper.egg-info/requires.txt +1 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/pyproject.toml +8 -4
- lcmodel_wrapper-0.3.1/tests/test_binaries.py +470 -0
- lcmodel_wrapper-0.3.1/tests/test_lcm.py +92 -0
- lcmodel_wrapper-0.2.0/NOTICE +0 -34
- lcmodel_wrapper-0.2.0/lcmodel_wrapper/binaries.py +0 -245
- lcmodel_wrapper-0.2.0/lcmodel_wrapper/coord.py +0 -136
- lcmodel_wrapper-0.2.0/lcmodel_wrapper/core.py +0 -271
- lcmodel_wrapper-0.2.0/tests/test_lcm.py +0 -98
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/LICENSE +0 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/LICENSE.lcmodel +0 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/MANIFEST.in +0 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/lcmodel_wrapper.egg-info/dependency_links.txt +0 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/lcmodel_wrapper.egg-info/top_level.txt +0 -0
- {lcmodel_wrapper-0.2.0 → lcmodel_wrapper-0.3.1}/setup.cfg +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
PyLCModel (lcmodel_wrapper)
|
|
2
|
+
Copyright (c) 2024 Julian P. Merkofer and contributors
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (see LICENSE).
|
|
5
|
+
|
|
6
|
+
------------------------------------------------------------------------------
|
|
7
|
+
LCModel
|
|
8
|
+
------------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
LCModel is NOT part of this project's copyright. It is a separate program by
|
|
11
|
+
Dr. Stephen Provencher, distributed under the BSD 3-Clause License
|
|
12
|
+
(Copyright (c) 1992-2021, Stephen Provencher); see LICENSE.lcmodel for the
|
|
13
|
+
full text. Home page: https://s-provencher.com/lcmodel.shtml
|
|
14
|
+
|
|
15
|
+
This wrapper bundles no LCModel code or binary. At run time it may obtain one
|
|
16
|
+
from these sources, and the BSD 3-Clause license applies to every one of them:
|
|
17
|
+
|
|
18
|
+
- the community binary collection at https://github.com/schorschinho/LCModel
|
|
19
|
+
(maintained by Georg Oeltzschner and contributors),
|
|
20
|
+
- binaries and the container image ghcr.io/julianmer/lcmodel built by this
|
|
21
|
+
repository's CI (.github/workflows/lcmodel-binaries.yml) from the pinned
|
|
22
|
+
upstream source, unmodified, using the compilation flags documented there;
|
|
23
|
+
LICENSE.lcmodel and this NOTICE are published alongside them,
|
|
24
|
+
- a local build from the same source via gfortran.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lcmodel_wrapper
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Lightweight Python wrapper for LCModel MRS fitting
|
|
5
5
|
Author-email: Julian Merkofer <j.p.merkofer@tue.nl>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -16,6 +16,7 @@ Requires-Dist: scipy>=1.10
|
|
|
16
16
|
Requires-Dist: nibabel>=4.0
|
|
17
17
|
Requires-Dist: nifti-mrs>=1.0
|
|
18
18
|
Provides-Extra: test
|
|
19
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
19
20
|
Requires-Dist: pandas>=1.4; extra == "test"
|
|
20
21
|
Requires-Dist: openpyxl>=3.0; extra == "test"
|
|
21
22
|
Dynamic: license-file
|
|
@@ -36,7 +37,7 @@ Dynamic: license-file
|
|
|
36
37
|
|
|
37
38
|
## Features
|
|
38
39
|
|
|
39
|
-
- **Zero-setup binaries** — the LCModel executable is resolved automatically (download, build from source, or your own path); nothing is bundled in the wheel.
|
|
40
|
+
- **Zero-setup binaries** — the LCModel executable is resolved automatically (download, container image, build from source, or your own path); nothing is bundled in the wheel.
|
|
40
41
|
- **Flexible input** — NumPy arrays, NIfTI-MRS, jMRUI text, and LCModel `.RAW`, in time or frequency domain.
|
|
41
42
|
- **Automated control files** — generated to match your data, or templated from an existing one.
|
|
42
43
|
- **Basis conversion (experimental)** — jMRUI, FSL-MRS, LCModel `.RAW`, and Osprey/FID-A basis sets to `.basis`.
|
|
@@ -50,7 +51,6 @@ Dynamic: license-file
|
|
|
50
51
|
```bash
|
|
51
52
|
pip install lcmodel-wrapper
|
|
52
53
|
```
|
|
53
|
-
Enter your API token:
|
|
54
54
|
|
|
55
55
|
### From Source
|
|
56
56
|
```bash
|
|
@@ -58,19 +58,28 @@ git clone https://github.com/julianmer/PyLCModel.git
|
|
|
58
58
|
cd PyLCModel
|
|
59
59
|
pip install -e .
|
|
60
60
|
```
|
|
61
|
+
Add `--recursive` to the clone (or run `git submodule update --init`) to also fetch the
|
|
62
|
+
[ISMRM 2016 fitting challenge](https://www.ismrm.org/workshops/Spectroscopy16/mrs_fitting_challenge/)
|
|
63
|
+
example data used by the tests.
|
|
61
64
|
|
|
62
65
|
---
|
|
63
66
|
|
|
64
67
|
## How the LCModel binary is handled
|
|
65
68
|
|
|
66
|
-
|
|
69
|
+
LCModel is **not** shipped in the wheel. On first use it is found in this order, and the first one that works is cached:
|
|
67
70
|
|
|
68
|
-
1.
|
|
69
|
-
2.
|
|
70
|
-
3.
|
|
71
|
-
4.
|
|
71
|
+
1. `path2exec` you pass to `PyLCModel`,
|
|
72
|
+
2. the community binary for your OS/architecture from [schorschinho/LCModel](https://github.com/schorschinho/LCModel),
|
|
73
|
+
3. the binary built by this repository's CI for the installed version ([releases](https://github.com/julianmer/PyLCModel/releases); Linux x86_64/aarch64 and macOS arm64/x86_64, all statically linked),
|
|
74
|
+
4. the container image `ghcr.io/julianmer/lcmodel`, if Docker or podman is running,
|
|
75
|
+
5. a build from source with `gfortran`.
|
|
72
76
|
|
|
73
|
-
|
|
77
|
+
Each candidate is run once before it is accepted, so a binary that cannot run on your machine is skipped rather than cached. Useful switches: `allow_download`, `allow_docker`, `allow_build` on `PyLCModel`, and the `LCMODEL_EXEC` / `LCMODEL_CACHE_DIR` environment variables.
|
|
78
|
+
|
|
79
|
+
With the container, LCModel sees your working directory and your home directory; keep the basis set and any `save_path` under one of them. The image also works on its own:
|
|
80
|
+
```bash
|
|
81
|
+
docker run --rm -i -v "$PWD:$PWD" -w "$PWD" ghcr.io/julianmer/lcmodel < control.file
|
|
82
|
+
```
|
|
74
83
|
|
|
75
84
|
---
|
|
76
85
|
|
|
@@ -130,9 +139,11 @@ This wrapper (the Python code) is released under the **Apache License 2.0** (see
|
|
|
130
139
|
|
|
131
140
|
## Acknowledgements
|
|
132
141
|
|
|
142
|
+
- LCModel source code: created and made [available](https://s-provencher.com/lcmodel.shtml) free of charge (Stephen Provencher).
|
|
133
143
|
- LCModel binaries: [schorschinho/LCModel](https://github.com/schorschinho/LCModel) (Georg Oeltzschner and contributors)
|
|
134
144
|
- Basis conversion reference: [MRS Basis Set Conversion Toolbox](https://github.com/igweckay/MRS-Basis-Set-Conversion-Toolbox) (Kay Igwe)
|
|
135
|
-
- NIfTI-MRS: [spec2nii](https://github.com/wtclarke/spec2nii), [NIfTI-MRS
|
|
145
|
+
- NIfTI-MRS: [spec2nii](https://github.com/wtclarke/spec2nii), [NIfTI-MRS Python tools](https://github.com/wtclarke/nifti_mrs_tools) (Will Clarke)
|
|
146
|
+
- Example data: [ISMRM 2016 MRS Fitting Challenge](https://www.ismrm.org/workshops/Spectroscopy16/mrs_fitting_challenge/) (Małgorzata Marjańska, Dinesh Deelchand, Roland Kreis), mirrored via [wtclarke/mrs_fitting_challenge](https://github.com/wtclarke/mrs_fitting_challenge)
|
|
136
147
|
|
|
137
148
|
---
|
|
138
149
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
## Features
|
|
16
16
|
|
|
17
|
-
- **Zero-setup binaries** — the LCModel executable is resolved automatically (download, build from source, or your own path); nothing is bundled in the wheel.
|
|
17
|
+
- **Zero-setup binaries** — the LCModel executable is resolved automatically (download, container image, build from source, or your own path); nothing is bundled in the wheel.
|
|
18
18
|
- **Flexible input** — NumPy arrays, NIfTI-MRS, jMRUI text, and LCModel `.RAW`, in time or frequency domain.
|
|
19
19
|
- **Automated control files** — generated to match your data, or templated from an existing one.
|
|
20
20
|
- **Basis conversion (experimental)** — jMRUI, FSL-MRS, LCModel `.RAW`, and Osprey/FID-A basis sets to `.basis`.
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
```bash
|
|
29
29
|
pip install lcmodel-wrapper
|
|
30
30
|
```
|
|
31
|
-
Enter your API token:
|
|
32
31
|
|
|
33
32
|
### From Source
|
|
34
33
|
```bash
|
|
@@ -36,19 +35,28 @@ git clone https://github.com/julianmer/PyLCModel.git
|
|
|
36
35
|
cd PyLCModel
|
|
37
36
|
pip install -e .
|
|
38
37
|
```
|
|
38
|
+
Add `--recursive` to the clone (or run `git submodule update --init`) to also fetch the
|
|
39
|
+
[ISMRM 2016 fitting challenge](https://www.ismrm.org/workshops/Spectroscopy16/mrs_fitting_challenge/)
|
|
40
|
+
example data used by the tests.
|
|
39
41
|
|
|
40
42
|
---
|
|
41
43
|
|
|
42
44
|
## How the LCModel binary is handled
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
LCModel is **not** shipped in the wheel. On first use it is found in this order, and the first one that works is cached:
|
|
45
47
|
|
|
46
|
-
1.
|
|
47
|
-
2.
|
|
48
|
-
3.
|
|
49
|
-
4.
|
|
48
|
+
1. `path2exec` you pass to `PyLCModel`,
|
|
49
|
+
2. the community binary for your OS/architecture from [schorschinho/LCModel](https://github.com/schorschinho/LCModel),
|
|
50
|
+
3. the binary built by this repository's CI for the installed version ([releases](https://github.com/julianmer/PyLCModel/releases); Linux x86_64/aarch64 and macOS arm64/x86_64, all statically linked),
|
|
51
|
+
4. the container image `ghcr.io/julianmer/lcmodel`, if Docker or podman is running,
|
|
52
|
+
5. a build from source with `gfortran`.
|
|
50
53
|
|
|
51
|
-
|
|
54
|
+
Each candidate is run once before it is accepted, so a binary that cannot run on your machine is skipped rather than cached. Useful switches: `allow_download`, `allow_docker`, `allow_build` on `PyLCModel`, and the `LCMODEL_EXEC` / `LCMODEL_CACHE_DIR` environment variables.
|
|
55
|
+
|
|
56
|
+
With the container, LCModel sees your working directory and your home directory; keep the basis set and any `save_path` under one of them. The image also works on its own:
|
|
57
|
+
```bash
|
|
58
|
+
docker run --rm -i -v "$PWD:$PWD" -w "$PWD" ghcr.io/julianmer/lcmodel < control.file
|
|
59
|
+
```
|
|
52
60
|
|
|
53
61
|
---
|
|
54
62
|
|
|
@@ -108,9 +116,11 @@ This wrapper (the Python code) is released under the **Apache License 2.0** (see
|
|
|
108
116
|
|
|
109
117
|
## Acknowledgements
|
|
110
118
|
|
|
119
|
+
- LCModel source code: created and made [available](https://s-provencher.com/lcmodel.shtml) free of charge (Stephen Provencher).
|
|
111
120
|
- LCModel binaries: [schorschinho/LCModel](https://github.com/schorschinho/LCModel) (Georg Oeltzschner and contributors)
|
|
112
121
|
- Basis conversion reference: [MRS Basis Set Conversion Toolbox](https://github.com/igweckay/MRS-Basis-Set-Conversion-Toolbox) (Kay Igwe)
|
|
113
|
-
- NIfTI-MRS: [spec2nii](https://github.com/wtclarke/spec2nii), [NIfTI-MRS
|
|
122
|
+
- NIfTI-MRS: [spec2nii](https://github.com/wtclarke/spec2nii), [NIfTI-MRS Python tools](https://github.com/wtclarke/nifti_mrs_tools) (Will Clarke)
|
|
123
|
+
- Example data: [ISMRM 2016 MRS Fitting Challenge](https://www.ismrm.org/workshops/Spectroscopy16/mrs_fitting_challenge/) (Małgorzata Marjańska, Dinesh Deelchand, Roland Kreis), mirrored via [wtclarke/mrs_fitting_challenge](https://github.com/wtclarke/mrs_fitting_challenge)
|
|
114
124
|
|
|
115
125
|
---
|
|
116
126
|
|
|
@@ -4,19 +4,27 @@ LCModel itself is a separate program by Dr. Stephen Provencher, distributed unde
|
|
|
4
4
|
BSD 3-Clause License (see LICENSE.lcmodel). This package only wraps it.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from .
|
|
7
|
+
from ._version import __version__
|
|
8
|
+
from .core import PyLCModel, LCModelError
|
|
8
9
|
from .basis import read_basis, LCModelBasis
|
|
10
|
+
from .binaries import verify_executable
|
|
9
11
|
from .convert import ensure_basis, convert_to_basis, detect_format
|
|
10
|
-
from . import
|
|
12
|
+
from .io import from_nifti_mrs, load_signals
|
|
13
|
+
from . import binaries, container, io, control, coord, convert
|
|
11
14
|
|
|
12
15
|
__all__ = [
|
|
13
16
|
"PyLCModel",
|
|
17
|
+
"LCModelError",
|
|
18
|
+
"verify_executable",
|
|
14
19
|
"read_basis",
|
|
15
20
|
"LCModelBasis",
|
|
16
21
|
"ensure_basis",
|
|
17
22
|
"convert_to_basis",
|
|
18
23
|
"detect_format",
|
|
24
|
+
"from_nifti_mrs",
|
|
25
|
+
"load_signals",
|
|
19
26
|
"binaries",
|
|
27
|
+
"container",
|
|
20
28
|
"io",
|
|
21
29
|
"control",
|
|
22
30
|
"coord",
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# Single source of truth for the package version. pyproject.toml reads it at build time,
|
|
2
|
+
# and binaries.py derives the GitHub release / container image tag ("v<version>") from
|
|
3
|
+
# it, so every wheel pairs with the LCModel artifacts built alongside it.
|
|
4
|
+
__version__ = "0.3.1"
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
# #
|
|
7
7
|
# Created: 26/06/26 #
|
|
8
8
|
# #
|
|
9
|
-
# Purpose: Lightweight parser for LCModel ".basis" files. Replaces the previous dependency on
|
|
9
|
+
# Purpose: Lightweight parser for LCModel ".basis" files. Replaces the previous dependency on #
|
|
10
10
|
# fsl_mrs for reading basis metadata. It extracts only what the wrapper needs to build #
|
|
11
|
-
# control files and to align fitted concentrations: the field strength (HZPPPM), dwell
|
|
11
|
+
# control files and to align fitted concentrations: the field strength (HZPPPM), dwell #
|
|
12
12
|
# time (BADELT), number of points (NDATAB) and the ordered metabolite names (METABO). #
|
|
13
13
|
# #
|
|
14
14
|
####################################################################################################
|
|
@@ -77,14 +77,14 @@ def read_basis(path: str) -> LCModelBasis:
|
|
|
77
77
|
with open(path, "r", errors="ignore") as fh:
|
|
78
78
|
header_lines = []
|
|
79
79
|
for line in fh:
|
|
80
|
-
header_lines
|
|
80
|
+
if len(header_lines) < 200: # scalars live near the top
|
|
81
|
+
header_lines.append(line)
|
|
81
82
|
# "METABO" lines are sparse; keep scanning the whole file for them.
|
|
82
83
|
# Match exactly "METABO =" (not "METABO_CONTAM" / "METABO_SINGLET").
|
|
83
84
|
m = re.match(r"\s*METABO\s*=\s*'(.*?)'", line)
|
|
84
85
|
if m:
|
|
85
86
|
basis.names.append(m.group(1).strip())
|
|
86
|
-
|
|
87
|
-
header = "".join(header_lines[:200]) # scalars live near the top
|
|
87
|
+
header = "".join(header_lines)
|
|
88
88
|
|
|
89
89
|
basis.central_freq = _find_scalar(header, "HZPPPM")
|
|
90
90
|
basis.dwell = _find_scalar(header, "BADELT")
|