Commit c8afdfee authored by William Clarke's avatar William Clarke
Browse files

Merge branch 'master' into 'master'

Merge for V1.1.2

See merge request !19
parents c79ceb9c 25a017a2
Pipeline #8396 failed with stages
in 2 minutes and 32 seconds
This document contains the FSL-MRS release history in reverse chronological order.
1.1.2 (Friday 16th April 2021)
------------------------------
- Added 2H information
- Bug fixes
- Added documentation around installation from conda
1.1.1 (Monday 15th March 2021)
------------------------------
- SNR measurements should cope with negative peak amplitudes correctly
......
# FSL-MRS
### Description
## Description
FSL-MRS is a collection of python modules and wrapper scripts for pre-processing and model fitting of Magnetic Resonance Spectroscopy (MRS) data.
---
### Installation
## Installation
#### Conda package
The primary installation method is via _conda_. After installing conda and creating or activating a suitable [environment](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html) you can install FSL-MRS from the FSL conda channel.
### Conda package
The primary installation method is via _conda_. First you should install conda and creating a suitable [environment](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html). For example, in the base conda environment execute:
conda install -c conda-forge \
conda create --name fsl_mrs -c conda-forge python=3.8
Then activate the environment:
conda activate fsl_mrs
Finally install FSL-MRS and its dependencies from the FSL conda channel.
conda install -c conda-forge -c defaults \
-c https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/channel/ \
fsl_mrs
#### Source code
### Source code
To get the source code with the packaged example data, make sure [git-lfs](https://git-lfs.github.com/) is installed.
git clone --recurse-submodules https://git.fmrib.ox.ac.uk/saad/fsl_mrs.git
git clone --recurse-submodules https://git.fmrib.ox.ac.uk/fsl/fsl_mrs.git
cd fsl_mrs
pip install .
#### Dependencies
The spec2nii package can be installed to convert data to NIfTI format.
conda install -c conda-forge spec2nii
or
pip install spec2nii
After installation see the [quick start guide](https://open.win.ox.ac.uk/pages/fsl/fsl_mrs/quick_start.html).
---
### Content
## Content
#### Scripts:
### Scripts:
- **fsl\_mrs**
: fit a single voxel spectroscopy (SVS) spectrum
......@@ -53,13 +54,13 @@ After installation see the [quick start guide](https://open.win.ox.ac.uk/pages/f
- **mrs_vis**
: quick visualisation of the spectra or basis spectra
- **mrs_info**
: quick information on NIfTI MRS file
: quick information on a NIfTI-MRS file
- **svs_segment & mrsi_segment**
: Run tissue segmentation for SVS/MRSI from T1 image.
---
### Documentation
## Documentation
Documentation can be found online on the [WIN open science website](https://open.win.ox.ac.uk/pages/fsl/fsl_mrs/).
......@@ -67,23 +68,27 @@ For each of the wrapper scripts above, simply type `<name_of_script> --help` to
Example command-line usage is demonstrated in the packaged [Jupyter Notebook](https://git.fmrib.ox.ac.uk/saad/fsl_mrs/-/blob/master/example_usage/Example%20SVS%20processing%20-%20command-line.ipynb.).
### File types
## Getting help
Please seek help via the [FSL JISC email list](mailto:FSL@JISCMAIL.AC.UK) or by submitting an issue on the [FSL-MRS Github mirror](https://github.com/wexeee/fsl_mrs/issues).
FSL-MRS accepts FID data in NIfTI + JSON format. Some scripts can also read .RAW (LCModel) and text (jMRUI).
## File types
Conversion to NIfTI is provided by [spec2nii](https://github.com/wexeee/spec2nii).
FSL-MRS accepts FID data in NIfTI-MRS format. Some scripts can also read .RAW (LCModel) and text (jMRUI).
### Working in python
Conversion to NIfTI-MRS is provided by [spec2nii](https://github.com/wexeee/spec2nii).
## Working in python
If you don't want to use the wrapper scripts, you can use the python modules directly in your own python scripts/programs. Or in an interactive Python environment (see example [notebook](https://git.fmrib.ox.ac.uk/saad/fsl_mrs/-/blob/master/example_usage/Example%20SVS%20processing%20-%20interactive%20notebook.ipynb))
---
### Permissions and citations
## Permissions and citations
If you use FSL-MRS in your research please cite:
Clarke WT, Stagg CJ, Jbabdi S. FSL-MRS: An end-to-end spectroscopy analysis package. Biorxiv 2020
Clarke WT, Stagg CJ, Jbabdi S. FSL-MRS: An end-to-end spectroscopy analysis package. Magnetic Resonance in Medicine 2021;85:2950–2964 doi: https://doi.org/10.1002/mrm.28630.
Please see the [LICENSE](https://git.fmrib.ox.ac.uk/saad/fsl_mrs/-/blob/master/LICENSE) file for licensing information.
......
......@@ -12,7 +12,7 @@ This is a short guide on setting up conda for the first time.
::
conda create --name fsl_mrs python=3.7
conda create --name fsl_mrs -c conda-forge python=3.7
3. Activate the enviroment.
......@@ -20,11 +20,11 @@ This is a short guide on setting up conda for the first time.
conda activate fsl_mrs
4. Optionally install Jupyter notebooks. This is required to run the example Jupyter notebooks.
4. Optionally install JupyterLab to access notebooks. This is required to run the example Jupyter notebooks.
::
conda install -c conda-forge notebook
conda install -c conda-forge jupyterlab
5. Follow the FSL-MRS & spec2nii install instructions on the :ref:`Installation
<install>` page.
......
......@@ -44,7 +44,7 @@ rst_epilog = """
.. _fslmrs_github_tracker: https://github.com/wexeee/fsl_mrs/issues
.. |fslmrs_pkg_data| replace:: FSL-MRS example data
.. _fslmrs_pkg_data: https://users.fmrib.ox.ac.uk/~wclarke/fsl_mrs/example_usage.zip
.. _fslmrs_pkg_data: https://git.fmrib.ox.ac.uk/fsl/fsl_mrs/-/archive/master/fsl_mrs-master.zip?path=example_usage/example_data
.. |dev_email| replace:: developers
.. _dev_email: mailto:william.clarke@ndcn.ox.ac.uk,saad@fmrib.ox.ac.uk
......
......@@ -23,7 +23,7 @@ The primary installation method is via *conda*. After installing conda and creat
::
conda install -c conda-forge \
conda install -c conda-forge -c defaults \
-c https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/channel/ \
fsl_mrs
......@@ -32,15 +32,6 @@ Example data with conda
Installation with conda is easy, but you won't get the packaged example data and notebooks. This can be downloaded separately here: |fslmrs_pkg_data|_.
spec2nii
~~~~~~~~
To convert data to NIfTI install the spec2nii program from conda.
::
conda install -c conda-forge spec2nii
Operating systems
~~~~~~~~~~~~~~~~~
FSL-MRS has been tested thoroughly on Mac and Linux operating systems. FSL-MRS dependencies and FSL-MRS is available on native Windows installations, but has not currently been tested. `Windows Subsytem for Linux <https://docs.microsoft.com/en-us/windows/wsl/install-win10>`_ (or WSL2) offers a Linux interface on Windows. FSL-MRS has been tested on WSL.
\ No newline at end of file
FSL-MRS has been tested thoroughly on Mac and Linux operating systems. FSL-MRS dependencies and FSL-MRS is available on native Windows installations, but has not currently been tested. `Windows Subsystem for Linux <https://docs.microsoft.com/en-us/windows/wsl/install-win10>`_ (or WSL2) offers a Linux interface on Windows. FSL-MRS has been tested on WSL.
\ No newline at end of file
......@@ -30,6 +30,8 @@ For more information on coherence filters see this `reference <https://www.ncbi.
For a description of the sequence file parameters see the :ref:`sequence file <seq_file_params>` page. Alternatively see the examples in the simulator package (examplePRESS.json & exampleSTEAM.json).
Please note that delays in the sequence description file do not include the duration of the pulse. I.e., the time from the centroid to the start/end of the RF pulse must be added to the delay to calculate the time between pulse centroids.
Using fsl_mrs_sim
-----------------
......
......@@ -301,21 +301,31 @@
%% Cell type:code id: tags:
``` python
import pandas as pd
from fsl_mrs.utils import quantify
combinationList = [['NAA','NAAG'],
['Glu','Gln'],
['GPC','PCh'],
['Cr','PCr'],
['Glc','Tau']]
res.combine(combinationList)
res.calculateConcScaling(mrs,waterRefFID=mrs.H2O,
tissueFractions={'WM':0.4,'GM':0.4,'CSF':0.1},
TE=11e-3,
T2='Default')
te = final_data.hdr_ext['EchoTime']
tr = final_data.hdr_ext['RepetitionTime']
q_info = quantify.QuantificationInfo(te,
tr,
mrs.names,
mrs.centralFrequency / 1E6)
q_info.set_fractions({'WM':0.45,'GM':0.45,'CSF':0.1})
res.calculateConcScaling(mrs,
quant_info=q_info,
internal_reference=['Cr', 'PCr'])
internal = res.getConc(scaling='internal',function=None).mean().multiply(8)
molarity = res.getConc(scaling='molarity',function=None).mean()
print(pd.concat([internal.rename('/Cr+PCr',inplace=True), molarity.rename('molarity (mM)',inplace=True)], axis=1))
```
......
......@@ -15,6 +15,10 @@ from fsl_mrs.utils.constants import GYRO_MAG_RATIO, PPM_SHIFT, PPM_RANGE
import numpy as np
class BasisHasInsufficentCoverage(Exception):
pass
class MRS(object):
"""
MRS Class - container for FID, Basis, and sequence info
......@@ -242,11 +246,21 @@ class MRS(object):
Usually the basis is simulated using different
timings and/or number of points.
This interpolates the basis to match the FID
This only works if the basis has greater time-domain
coverage than the FID.
"""
self.basis = misc.ts_to_ts(self.basis,
self.basis_dwellTime,
self.dwellTime,
self.numPoints)
try:
self.basis = misc.ts_to_ts(self.basis,
self.basis_dwellTime,
self.dwellTime,
self.numPoints)
except misc.InsufficentTimeCoverageError:
raise BasisHasInsufficentCoverage('The basis spectra covers too little time. '
'Please provide a basis with time-domain coverage '
'greater than the input data. Alternatively truncate '
'your input data.')
self.basis_dwellTime = self.dwellTime
self.basis_bandwidth = 1 / self.dwellTime
self.numBasisPoints = self.numPoints
......
......@@ -3,7 +3,7 @@
# fsl_mrs - wrapper script for MRS fitting
#
# Author: Saad Jbabdi <saad@fmrib.ox.ac.uk>
# William Carke <william.clarke@ndcn.ox.ac.uk>
# William Clarke <william.clarke@ndcn.ox.ac.uk>
#
# Copyright (C) 2019 University of Oxford
# SHBASECOPYRIGHT
......
......@@ -103,6 +103,8 @@ def main():
optional.add_argument('--ref_int_limits', type=float, default=None, nargs=2,
help='Reference spectrum integration limits (low, high).'
' No effect without setting --wref_metabolite.')
optional.add_argument('--h2o_scale', type=float, default=1.0,
help='Additional scaling modifier for external water referencing.')
optional.add_argument('--report', action="store_true",
help='output html report')
optional.add_argument('--verbose', action="store_true",
......@@ -210,7 +212,7 @@ def main():
if ppmlim is not None:
ppmlim = (ppmlim[0], ppmlim[1])
# Store info in disctionaries to be passed to MRS and fitting
# Store info in dictionaries to be passed to MRS and fitting
Fitargs = {'ppmlim': ppmlim, 'method': args.algo,
'baseline_order': args.baseline_order}
if args.lorentzian:
......
......@@ -6,10 +6,13 @@ Copyright Will Clarke, University of Oxford, 2021'''
from pathlib import Path
from fsl_mrs.core import MRS, mrs_from_files
import pytest
from fsl_mrs.utils import synthetic as syn
import numpy as np
from fsl_mrs.core import MRS, mrs_from_files
from fsl_mrs.core.mrs import BasisHasInsufficentCoverage
from fsl_mrs.utils import synthetic as syn
from fsl_mrs.utils.misc import FIDToSpec, hz2ppm
from fsl_mrs.utils.constants import GYRO_MAG_RATIO
......@@ -195,3 +198,16 @@ def test_nucleus_identification():
header=hdr)
assert mrs.nucleus == nuc
def test_basis_size(synth_data):
fid, hdr, basis, names, bheader, axes = synth_data
# Truncate basis to test error reporting
basis = basis[:, :512]
with pytest.raises(BasisHasInsufficentCoverage):
MRS(FID=fid,
header=hdr,
basis=basis,
names=names,
basis_hdr=bheader[0])
......@@ -27,6 +27,7 @@ def test_fsl_mrsi(tmp_path):
'--output', str(tmp_path / 'fit_out'),
'--h2o', data['water'],
'--TE', '30',
'--TR', '2.0',
'--add_MM',
'--mask', data['mask'],
'--tissue_frac',
......@@ -42,6 +43,7 @@ def test_fsl_mrsi(tmp_path):
assert (tmp_path / 'fit_out/concs').exists()
assert (tmp_path / 'fit_out/concs/raw/NAA.nii.gz').exists()
assert (tmp_path / 'fit_out/concs/molality/NAA.nii.gz').exists()
assert (tmp_path / 'fit_out/uncertainties/NAA_sd.nii.gz').exists()
assert (tmp_path / 'fit_out/qc/NAA_snr.nii.gz').exists()
assert (tmp_path / 'fit_out/fit/fit.nii.gz').exists()
......@@ -13,15 +13,18 @@
# MHz/tesla
H1_gamma = 42.576
GYRO_MAG_RATIO = {'1H': H1_gamma,
'2H': 6.536,
'13C': 10.7084,
'31P': 17.235}
H2O_PPM_TO_TMS = 4.65 # Shift of water to Tetramethylsilane
PPM_SHIFT = {'1H': H2O_PPM_TO_TMS,
'2H': H2O_PPM_TO_TMS, # Placeholder
'13C': 0.0,
'31P': 0.0}
PPM_RANGE = {'1H': (0.2, 4.2),
'2H': (0.0, 6),
'13C': (10, 100),
'31P': (-20, 10)}
......
......@@ -161,6 +161,10 @@ def filter(mrs, FID, ppmlim, filter_type='bandpass'):
return y
class InsufficentTimeCoverageError(Exception):
pass
def ts_to_ts(old_ts, old_dt, new_dt, new_n):
"""Temporal resampling where the new time series has a smaller number of points
......@@ -174,6 +178,10 @@ def ts_to_ts(old_ts, old_dt, new_dt, new_n):
old_t = np.linspace(old_dt, old_dt * old_n, old_n) - old_dt
new_t = np.linspace(new_dt, new_dt * new_n, new_n) - new_dt
if new_t[-1] > old_t[-1]:
raise InsufficentTimeCoverageError('Input data covers less time than is requested by interpolation.'
' Change interpolation points or dwell time.')
f = interp1d(old_t, old_ts, axis=0)
new_ts = f(new_t)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment