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
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
-----------------
......
......@@ -408,6 +408,8 @@
"outputs": [],
"source": [
"import pandas as pd\n",
"from fsl_mrs.utils import quantify\n",
"\n",
"combinationList = [['NAA','NAAG'],\n",
" ['Glu','Gln'],\n",
" ['GPC','PCh'],\n",
......@@ -415,10 +417,18 @@
" ['Glc','Tau']]\n",
"\n",
"res.combine(combinationList)\n",
"res.calculateConcScaling(mrs,waterRefFID=mrs.H2O,\n",
" tissueFractions={'WM':0.4,'GM':0.4,'CSF':0.1},\n",
" TE=11e-3,\n",
" T2='Default')\n",
"\n",
"te = final_data.hdr_ext['EchoTime']\n",
"tr = final_data.hdr_ext['RepetitionTime']\n",
"q_info = quantify.QuantificationInfo(te,\n",
" tr,\n",
" mrs.names,\n",
" mrs.centralFrequency / 1E6)\n",
"q_info.set_fractions({'WM':0.45,'GM':0.45,'CSF':0.1})\n",
" \n",
"res.calculateConcScaling(mrs,\n",
" quant_info=q_info,\n",
" internal_reference=['Cr', 'PCr'])\n",
"\n",
"internal = res.getConc(scaling='internal',function=None).mean().multiply(8)\n",
"molarity = res.getConc(scaling='molarity',function=None).mean()\n",
......@@ -495,9 +505,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.7"
"version": "3.8.8-final"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
}
\ No newline at end of file
%% Cell type:markdown id: tags:
# Example of SVS processing - interactive notebook
%% Cell type:markdown id: tags:
This notebook demos the process of fitting a single voxel scan in an interactive notebook using the underlying python libraries in FSL-MRS.
To view the plots in this notebook in Jupyter please consult the [plotly getting-started guide](https://plotly.com/python/getting-started/#jupyterlab-support-python-35).
### Contents:
1. [File conversion using spec2nii](#1.-File-conversion-using-spec2nii)
2. [Interactive preprocessing](#2.-Interactive-preprocessing)
3. [Fitting of the resultant spectrum](#3.-Fitting)
4. [Display of fitting results in a notebook](#4.-Display)
Will Clarke
June 2020
University of Oxford
%% Cell type:markdown id: tags:
## 1. File conversion using spec2nii
__THIS IS DONE ON THE COMMAND LINE__
Run spec2nii twix -v to establish the file contents, then using this information run spec2nii twix -e with the appropriate flags to extract the required scans. The -q flag suppresses text output.
This dataset uses a modified versions of the CMRR spectro package sequences on a Siemens scanner. It has three sets of water reference scans. The first is tagged as a phase correction, ans is collected at the start of the main suppressed water scan and will be used for eddy current correction.
The second is collected in a separate scan with only the RF portion of the water suppression disabled. This is used for coil combination (and could be used for eddy current correction). The third is collected with the OVS and all aspects of the water suppression disabled. It therefore experiences eddy currents unlike all the other scans. It will be used for final concentration scaling.
%% Cell type:code id: tags:
``` python
%%bash
spec2nii twix -v -q example_data/meas_MID310_STEAM_metab_FID115673.dat
```
%% Cell type:markdown id: tags:
From the final lines of the output of the first cell we can see that this "twix" file contains two groups of data.
The first is tagged as "image" and contains 64 repetitions (sets) of 4096 point FIDs collected on 32 channels.
The second has a single FID on each channel.
We now call spec2nii again specifying the group we want to extract each time. Each call to spec2nii will generate a NIfTI MRS file with a size of 1x1x1x4096x32xNdyn, where Ndyn is the number of dynamics (repeats).
We repeat this for the water reference scans, extracting just the image data.
%% Cell type:code id: tags:
``` python
%%bash
spec2nii twix -e image -f steam_metab_raw -o data -j -q example_data/meas_MID310_STEAM_metab_FID115673.dat
spec2nii twix -e phasecor -f steam_ecc_raw -o data -j -q example_data/meas_MID310_STEAM_metab_FID115673.dat
spec2nii twix -e image -f steam_wref_comb_raw -o data -j -q example_data/meas_MID311_STEAM_wref1_FID115674.dat
spec2nii twix -e image -f steam_wref_quant_raw -o data -j -q example_data/meas_MID312_STEAM_wref3_FID115675.dat
```
%% Cell type:markdown id: tags:
## 2. Interactive preprocessing
In this section we will preprocess the data using functions in the preproc package in fsl_mrs. This example could be used as a template to construct your own preprocessing script in python.
#### Description of steps
0. Load the data
1. Take averages of water references used for combination across files
2. Coil combine the metab data, the ecc data and the quantification data using the "comb" data as the reference.
3. Phase and frequency align the data where there are multiple transients.
4. Combine data across those transients by taking the mean.
5. Run eddy current correction using the appropriate reference.
6. In this data an additional FID point is collected before the echo centre. Remove this.
7. Run HLSVD on the data to remove the residual water in the water suppressed data.
6. Phase the data by a single peak as a crude zero-order phase correction.
%% Cell type:code id: tags:
``` python
import fsl_mrs.utils.mrs_io as mrs_io
```
%% Cell type:markdown id: tags:
#### 0. Load data
Load all the data into lists of data using the mrs_io.read_FID function
%% Cell type:code id: tags:
``` python
# Load the raw metabolite data
supp_data = mrs_io.read_FID('data/steam_metab_raw.nii.gz')
print(f'Loaded water supressed data with shape {supp_data.shape} and dimensions {supp_data.dim_tags}.')
# Load water ref with eddy currents (for coil combination)
ref_data = mrs_io.read_FID('data/steam_wref_comb_raw.nii.gz')
print(f'Loaded unsupressed data with shape {ref_data.shape} and dimensions {ref_data.dim_tags}.')
# Load water ref without eddy currents (for quantification)
quant_data = mrs_io.read_FID('data/steam_wref_quant_raw.nii.gz')
print(f'Loaded unsupressed data with shape {quant_data.shape} and dimensions {quant_data.dim_tags}.')
# Load phasecor scan (for Eddy)
ecc_data = mrs_io.read_FID('data/steam_ecc_raw.nii.gz')
print(f'Loaded unsupressed data with shape {ecc_data.shape} and dimensions {ecc_data.dim_tags}.')
```
%% Cell type:markdown id: tags:
#### 1. Take averages of reference data for coil combination
Each water reference scan cointained two averages. Calculate the average for use as a coil combination reference.
%% Cell type:code id: tags:
``` python
from fsl_mrs.utils.preproc import nifti_mrs_proc as proc
avg_ref_data = proc.average(ref_data, 'DIM_DYN', figure=True)
```
%% Cell type:markdown id: tags:
#### 2. Coil combination
Coil combine the metab data, the ecc data and the quantification data using the "comb" data as the reference.
%% Cell type:code id: tags:
``` python
supp_data = proc.coilcombine(supp_data, reference=avg_ref_data, figure=True)
quant_data = proc.coilcombine(quant_data, reference=avg_ref_data)
ecc_data = proc.coilcombine(ecc_data, reference=avg_ref_data)
```
%% Cell type:markdown id: tags:
#### Additional step to give resonable display phase for metabolites
Phase using single peak (Cr at 3.03 ppm)
%% Cell type:code id: tags:
``` python
supp_data = proc.apply_fixed_phase(supp_data, 180.0, figure=True)
quant_data = proc.apply_fixed_phase(quant_data, 180.0)
ecc_data = proc.apply_fixed_phase(ecc_data, 180.0)
```
%% Cell type:markdown id: tags:
#### 3. Phase and freq alignment
Phase and frequency align the data where there are multiple transients.
%% Cell type:code id: tags:
``` python
supp_data = proc.align(supp_data, 'DIM_DYN', ppmlim=(0, 4.2), figure=True)
# Alignment for water scans
quant_data = proc.align(quant_data, 'DIM_DYN', ppmlim=(0, 8))
```
%% Cell type:markdown id: tags:
#### 4. Combine scans
Combine data across transients by taking the mean.
%% Cell type:code id: tags:
``` python
supp_data = proc.average(supp_data, 'DIM_DYN', figure=True)
quant_data = proc.average(quant_data, 'DIM_DYN')
```
%% Cell type:markdown id: tags:
#### 5. ECC
Run eddy current correction using the appropriate reference.
%% Cell type:code id: tags:
``` python
supp_data = proc.ecc(supp_data, ecc_data, figure=True)
quant_data = proc.ecc(quant_data, quant_data)
```
%% Cell type:markdown id: tags:
#### 6. Truncation
In this data an additional FID point is collected before the echo centre. Remove this point.
%% Cell type:code id: tags:
``` python
supp_data = proc.truncate_or_pad(supp_data, -1, 'first', figure=True)
quant_data = proc.truncate_or_pad(quant_data, -1, 'first')
```
%% Cell type:markdown id: tags:
#### 7. Remove residual water
Run HLSVD on the data to remove the residual water in the water suppressed data.
%% Cell type:code id: tags:
``` python
limits = [-0.15,0.15]
limunits = 'ppm'
supp_data = proc.remove_peaks(supp_data, limits, limit_units=limunits, figure=True)
```
%% Cell type:markdown id: tags:
#### 8. Shift to reference
Ensure peaks appear at correct frequencies after alignment and ecc.
%% Cell type:code id: tags:
``` python
supp_data = proc.shift_to_reference(supp_data, 3.027, (2.9, 3.1), figure=True)
```
%% Cell type:markdown id: tags:
#### 9. Phasing
Phase the data by a single peak as a basic zero-order phase correction.
%% Cell type:code id: tags:
``` python
final_data = proc.phase_correct(supp_data, (2.9, 3.1), figure=True)
final_wref = proc.phase_correct(quant_data, (4.55, 4.7), hlsvd=False, figure=True)
```
%% Cell type:markdown id: tags:
## 3. Fitting
### Load into MRS objects
- Read pre-baked basis file (this one was generated with `fsl_mrs_sim`).
- Create main MRS object.
- Prepare the data for fitting (this does additional checks such as whether the data needs to be conjugated, and scales the data to improve fitting robustness)
%% Cell type:code id: tags:
``` python
import matplotlib.pyplot as plt
# Create main MRS Object
mrs = final_data.mrs(basis_file='example_data/steam_11ms',
ref_data=final_wref)
mrs.processForFitting()
# Quick plots of the Metab and Water spectra
mrs.plot()
plt.show()
mrs.plot_ref()
plt.show()
plt.figure(figsize=(10,10))
mrs.plot_basis()
plt.show()
```
%% Cell type:markdown id: tags:
### Fitting
Here we show a typical model fitting and some of the parameters that can be user-set.
%% Cell type:code id: tags:
``` python
from fsl_mrs.utils import fitting, misc, plotting
# Separate macromolecule from the rest (it will have its own lineshape parameters)
metab_groups = misc.parse_metab_groups(mrs,'Mac')
# Fit with Newton algorithm
Fitargs = {'ppmlim':[0.2,4.2],
'method':'Newton','baseline_order':4,
'metab_groups':metab_groups,
'model':'voigt'}
res = fitting.fit_FSLModel(mrs,**Fitargs)
# Quick sanity-plot of the fit (see further down for interactive plotting)
_ = plotting.plot_fit(mrs,pred=res.pred,baseline=res.baseline)
```
%% Cell type:markdown id: tags:
### Quantification
Internal and water referencing.
Output is a pandas series.
%% 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))
```
%% Cell type:markdown id: tags:
## 4. Display
Results can be displayed with various plotting functions or rendered into an interactive HTML.
### In notebook
%% Cell type:code id: tags:
``` python
fig = plotting.plotly_fit(mrs,res)
fig.show()
```
%% Cell type:markdown id: tags:
### HTML report
%% Cell type:code id: tags:
``` python
from fsl_mrs.utils import report
import os
import datetime
output = '.'
report.create_report(mrs,res,
filename=os.path.join(output,'report.html'),
fidfile='meas_MID310_STEAM_metab_FID115673.dat',
basisfile='example_data/steam_11ms',
h2ofile='meas_MID311_STEAM_wref1_FID115674.dat',
date=datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
import webbrowser
current_path = os.getcwd()
# generate a URL
url = os.path.join('file:///'+current_path,'report.html')
webbrowser.open(url)
```
......
......@@ -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)
......
Supports Markdown
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