test_mrs_io.py 6.63 KB
Newer Older
1
2
3
4
5
6
7
'''FSL-MRS test script

Test io functions

Copyright Will Clarke, University of Oxford, 2021'''


8
import fsl_mrs.utils.mrs_io as mrsio
9
import fsl_mrs.utils.mrs_io.fsl_io as fslio
10
from fsl_mrs.utils.mrs_io.main import _check_datatype
11
12
13
14
15
from fsl_mrs.utils import plotting
import numpy as np
import os.path as op

testsPath = op.dirname(__file__)
16
17
18
19
20
SVSTestData = {'nifti': op.join(testsPath, 'testdata/mrs_io/metab.nii'),
               'raw': op.join(testsPath, 'testdata/mrs_io/metab.RAW'),
               'txt': op.join(testsPath, 'testdata/mrs_io/metab.txt')}

headerReqFields = ['centralFrequency', 'bandwidth', 'dwelltime']
21
22
23
24
25
26
27
28


def test_read_FID_SVS():
    # Test the loading of the three types of data we handle for SVS data
    # nifti + json
    # .raw
    # .txt

29
30
31
    data_nifti = mrsio.read_FID(SVSTestData['nifti'])
    data_raw = mrsio.read_FID(SVSTestData['raw'])
    data_txt = mrsio.read_FID(SVSTestData['txt'])
32
33

    # Check that the data from each of these matches - it should they are all the same bit of data.
34
35
36
    datamean = np.mean([data_nifti.data,
                        data_raw.data,
                        data_txt.data], axis=0)
37

38
39
40
    assert np.isclose(data_nifti.data, datamean).all()
    assert np.isclose(data_raw.data, datamean).all()
    assert np.isclose(data_txt.data, datamean).all()
41

42
43
44
45
46
47
48
49
50
51
    # # Check that the headers each contain the required fields
    # for r in headerReqFields:
    #     assert r in header_nifti
    #     assert r in header_raw
    #     assert r in header_txt

    #     headerMean = np.mean([header_nifti[r], header_raw[r], header_txt[r]])
    #     assert np.isclose(header_nifti[r], headerMean)
    #     assert np.isclose(header_raw[r], headerMean)
    #     assert np.isclose(header_txt[r], headerMean)
52
53
54
55

# TODO: Make MRSI test function (and find data)
# def test_read_FID_MRSI()

56
57
58
59
60
61
62

BasisTestData = {'fsl': op.join(testsPath, 'testdata/mrs_io/basisset_FSL'),
                 'raw': op.join(testsPath, 'testdata/mrs_io/basisset_LCModel_raw'),
                 'txt': op.join(testsPath, 'testdata/mrs_io/basisset_JMRUI'),
                 'lcm': op.join(testsPath, 'testdata/mrs_io/basisset_LCModel.BASIS')}


63
64
65
66
67
68
69
def test_read_Basis():
    # Test the loading of the four types of data we handle for basis specta
    # fsl_mrs - folder of json
    # lcmodel - .basis file
    # lcmodel - folder of .raw
    # jmrui - folder of .txt

70
71
72
73
    basis_fsl, names_fsl, headers_fsl = mrsio.read_basis(BasisTestData['fsl'])
    basis_raw, names_raw, headers_raw = mrsio.read_basis(BasisTestData['raw'])
    basis_txt, names_txt, headers_txt = mrsio.read_basis(BasisTestData['txt'])
    basis_lcm, names_lcm, headers_lcm = mrsio.read_basis(BasisTestData['lcm'])
74

75
76
    # lcm basis file is zeropadded by a factor of 2, remove
    basis_lcm = basis_lcm[:2048, :]
77
78
79
80
81
82
83

    # Test that all contain the same amount of data.
    expectedDataSize = (2048, 21)
    assert basis_fsl.shape == expectedDataSize
    assert basis_raw.shape == expectedDataSize
    assert basis_txt.shape == expectedDataSize
    assert basis_lcm.shape == expectedDataSize
84

85
86
    # Test that the number of names match the amount of data
    numNames = 21
87
88
89
90
91
    assert len(names_fsl) == numNames
    assert len(names_raw) == numNames
    assert len(names_txt) == numNames
    assert len(names_lcm) == numNames

92
93
94
    # Check that the headers each contain the required fields
    # Exclude raw, we know it doesn't contain everything
    for r in headerReqFields:
95
        assert r in headers_fsl[0]
96
97
        assert r in headers_txt[0]
        assert r in headers_lcm[0]
98
99
100
101

        headerMean = np.mean([headers_fsl[0][r],
                              headers_txt[0][r],
                              headers_lcm[0][r]])
102
        if r == 'centralFrequency':
103
104
105
            assert np.isclose(headers_fsl[0][r], headerMean, rtol=2e-01, atol=1e05)
            assert np.isclose(headers_txt[0][r], headerMean, rtol=2e-01, atol=1e05)
            assert np.isclose(headers_lcm[0][r], headerMean, rtol=2e-01, atol=1e05)
106
        else:
107
108
109
110
            assert np.isclose(headers_fsl[0][r], headerMean)
            assert np.isclose(headers_txt[0][r], headerMean)
            assert np.isclose(headers_lcm[0][r], headerMean)

111
112
113
114
    # Conjugate fsl and jMRUI
    basis_fsl = basis_fsl.conj()
    basis_txt = basis_txt.conj()

115
116
    # Test that all contain roughly the same data when scaled.
    metabToCheck = 'Cr'
117
118
119
120
121
122
123
124
125
126
127
128
    checkIdx = names_raw.index(metabToCheck)

    def normAbsSpec(spec):
        return np.abs(spec) / np.max(np.abs(spec))

    def convertToLimitedSpec(fid):
        return normAbsSpec(plotting.FID2Spec(fid)[900:1000])

    meanSpec = np.mean([convertToLimitedSpec(basis_fsl[:, checkIdx]),
                       convertToLimitedSpec(basis_raw[:, checkIdx]),
                       convertToLimitedSpec(basis_txt[:, checkIdx]),
                       convertToLimitedSpec(basis_lcm[:, checkIdx])], axis=0)
129
130
131
132
133
134
135
    # breakpoint()
    # import matplotlib.pyplot as plt
    # plt.plot(convertToLimitedSpec(basis_fsl[:,checkIdx]))
    # plt.plot(convertToLimitedSpec(basis_raw[:,checkIdx]),'--')
    # plt.plot(convertToLimitedSpec(basis_txt[:,checkIdx]),'-.')
    # plt.plot(convertToLimitedSpec(basis_lcm[:,checkIdx]),':')
    # plt.show()
136
137
138
139
140
    assert np.allclose(convertToLimitedSpec(basis_fsl[:, checkIdx]), meanSpec, rtol=2e-01, atol=1e-03)
    assert np.allclose(convertToLimitedSpec(basis_raw[:, checkIdx]), meanSpec, rtol=2e-01, atol=1e-03)
    assert np.allclose(convertToLimitedSpec(basis_txt[:, checkIdx]), meanSpec, rtol=2e-01, atol=1e-03)
    assert np.allclose(convertToLimitedSpec(basis_lcm[:, checkIdx]), meanSpec, rtol=2e-01, atol=1e-03)

141
142

def test_fslBasisRegen():
143
    pointsToGen = 10
144
145
146
147
148
    basis_fsl, names_fsl, headers_fsl = mrsio.read_basis(BasisTestData['fsl'])
    basis_fsl2, names_fsl2, headers_fsl2 = fslio.readFSLBasisFiles(BasisTestData['fsl'],
                                                                   readoutShift=4.65,
                                                                   bandwidth=4000,
                                                                   points=pointsToGen)
149

150
    assert np.allclose(basis_fsl2, basis_fsl[:10, :])
151
152
    assert names_fsl2 == names_fsl
    for r in headerReqFields:
153
        assert headers_fsl[0][r] == headers_fsl2[0][r]
154
155
156
157
158
159
160
161
162
163
164
165
166
167


def test_check_datatype():
    '''Check various paths through _check_datatype'''

    assert _check_datatype('fake/path/test.RAW') == 'RAW'
    assert _check_datatype('fake/path/test.H2O') == 'RAW'

    assert _check_datatype('fake/path/test.txt') == 'TXT'

    assert _check_datatype('fake/path/test.nii') == 'NIFTI'
    assert _check_datatype('fake/path/test.nii.gz') == 'NIFTI'
    assert _check_datatype('fake/path/test.blah.nii.gz') == 'NIFTI'
    assert _check_datatype('fake/path/test.blah.nii') == 'NIFTI'