1# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
2# vi: set ft=python sts=4 ts=4 sw=4 et:
3### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
4#
5#   See COPYING file distributed along with the NiBabel package for the
6#   copyright and license terms.
7#
8### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
9from __future__ import with_statement
10
11import os
12
13import numpy as np
14
15from ..py3k import asbytes
16
17from ..volumeutils import native_code, swapped_code
18from ..ecat import EcatHeader, EcatMlist, EcatSubHeader, EcatImage
19
20from unittest import TestCase
21
22from nose.tools import (assert_true, assert_false, assert_equal,
23                        assert_not_equal, assert_raises)
24
25from numpy.testing import assert_array_equal, assert_array_almost_equal
26
27from ..testing import data_path
28from ..tmpdirs import InTemporaryDirectory
29
30ecat_file = os.path.join(data_path, 'tinypet.v')
31
32class TestEcatHeader(TestCase):
33    header_class = EcatHeader
34    example_file = ecat_file
35
36    def test_header_size(self):
37        assert_equal(self.header_class._dtype.itemsize, 512)
38
39    def test_empty(self):
40        hdr = self.header_class()
41        assert_true(len(hdr.binaryblock) == 512)
42        assert_true(hdr['magic_number'] == asbytes('MATRIX72'))
43        assert_true(hdr['sw_version'] == 74)
44        assert_true(hdr['num_frames'] == 0)
45        assert_true(hdr['file_type'] == 0)
46        assert_true(hdr['ecat_calibration_factor'] == 1.0)
47
48    def test_dtype(self):
49        #dtype not specified in header, only in subheaders
50        hdr = self.header_class()
51        assert_raises(NotImplementedError,
52                            hdr.get_data_dtype)
53
54    def test_header_codes(self):
55        fid = open(ecat_file, 'rb')
56        hdr = self.header_class()
57        newhdr = hdr.from_fileobj(fid)
58        fid.close()
59        assert_true(newhdr.get_filetype() == 'ECAT7_VOLUME16')
60        assert_equal(newhdr.get_patient_orient(),
61                           'ECAT7_Unknown_Orientation')
62
63    def test_copy(self):
64        hdr = self.header_class()
65        hdr2 = hdr.copy()
66        assert_true(hdr == hdr2)
67        assert_true(not hdr.binaryblock == hdr2._header_data.byteswap().tostring())
68        assert_true(hdr.keys() == hdr2.keys())
69
70    def test_update(self):
71        hdr = self.header_class()
72        assert_true(hdr['num_frames'] == 0)
73        hdr['num_frames'] = 2
74        assert_true(hdr['num_frames'] == 2)
75
76    def test_endianness(self):
77        # Default constructed header should be native
78        native_hdr = self.header_class()
79        assert_true(native_hdr.endianness == native_code)
80        # Swapped constructed header should be swapped
81        swapped_hdr = self.header_class(endianness=swapped_code)
82        assert_true(swapped_hdr.endianness == swapped_code)
83        # Example header is big-endian
84        fid = open(ecat_file, 'rb')
85        file_hdr = native_hdr.from_fileobj(fid)
86        fid.close()
87        assert_true(file_hdr.endianness == '>')
88
89
90class TestEcatMlist(TestCase):
91    header_class = EcatHeader
92    mlist_class = EcatMlist
93    example_file = ecat_file
94
95    def test_mlist(self):
96        fid = open(self.example_file, 'rb')
97        hdr = self.header_class.from_fileobj(fid)
98        mlist =  self.mlist_class(fid, hdr)
99        fid.seek(0)
100        fid.seek(512)
101        dat=fid.read(128*32)
102        dt = np.dtype([('matlist',np.int32)])
103        dt = dt.newbyteorder('>')
104        mats = np.recarray(shape=(32,4), dtype=dt,  buf=dat)
105        fid.close()
106        #tests
107        assert_true(mats['matlist'][0,0] +  mats['matlist'][0,3] == 31)
108        assert_true(mlist.get_frame_order()[0][0] == 0)
109        assert_true(mlist.get_frame_order()[0][1] == 16842758.0)
110        # test badly ordered mlist
111        badordermlist = mlist
112        badordermlist._mlist = np.array([[  1.68427540e+07,   3.00000000e+00,
113                                            1.20350000e+04,   1.00000000e+00],
114                                         [  1.68427530e+07,   1.20360000e+04,
115                                            2.40680000e+04,   1.00000000e+00],
116                                         [  1.68427550e+07,   2.40690000e+04,
117                                            3.61010000e+04,   1.00000000e+00],
118                                         [  1.68427560e+07,   3.61020000e+04,
119                                            4.81340000e+04,   1.00000000e+00],
120                                         [  1.68427570e+07,   4.81350000e+04,
121                                            6.01670000e+04,   1.00000000e+00],
122                                         [  1.68427580e+07,   6.01680000e+04,
123                                            7.22000000e+04,   1.00000000e+00]])
124        assert_true(badordermlist.get_frame_order()[0][0] == 1)
125
126    def test_mlist_errors(self):
127        fid = open(self.example_file, 'rb')
128        hdr = self.header_class.from_fileobj(fid)
129        hdr['num_frames'] = 6
130        mlist =  self.mlist_class(fid, hdr)
131        mlist._mlist = np.array([[  1.68427540e+07,   3.00000000e+00,
132                                    1.20350000e+04,   1.00000000e+00],
133                                 [  1.68427530e+07,   1.20360000e+04,
134                                    2.40680000e+04,   1.00000000e+00],
135                                 [  1.68427550e+07,   2.40690000e+04,
136                                    3.61010000e+04,   1.00000000e+00],
137                                 [  1.68427560e+07,   3.61020000e+04,
138                                    4.81340000e+04,   1.00000000e+00],
139                                 [  1.68427570e+07,   4.81350000e+04,
140                                    6.01670000e+04,   1.00000000e+00],
141                                 [  1.68427580e+07,   6.01680000e+04,
142                                    7.22000000e+04,   1.00000000e+00]])
143        series_framenumbers = mlist.get_series_framenumbers()
144        # first frame stored was actually 2nd frame acquired
145        assert_true(series_framenumbers[0] == 2)
146        order = [series_framenumbers[x] for x in sorted(series_framenumbers)]
147        # true series order is [2,1,3,4,5,6], note counting starts at 1
148        assert_true(order == [2, 1, 3, 4, 5, 6])
149        mlist._mlist[0,0] = 0
150        frames_order = mlist.get_frame_order()
151        neworder =[frames_order[x][0] for x in sorted(frames_order)]
152        assert_true(neworder == [1, 2, 3, 4, 5])
153        assert_raises(IOError,
154                      mlist.get_series_framenumbers)
155
156
157
158class TestEcatSubHeader(TestCase):
159    header_class = EcatHeader
160    mlist_class = EcatMlist
161    subhdr_class = EcatSubHeader
162    example_file = ecat_file
163    fid = open(example_file, 'rb')
164    hdr = header_class.from_fileobj(fid)
165    mlist =  mlist_class(fid, hdr)
166    subhdr = subhdr_class(hdr, mlist, fid)
167
168    def test_subheader_size(self):
169        assert_equal(self.subhdr_class._subhdrdtype.itemsize, 510)
170
171    def test_subheader(self):
172        assert_equal(self.subhdr.get_shape() , (10,10,3))
173        assert_equal(self.subhdr.get_nframes() , 1)
174        assert_equal(self.subhdr.get_nframes(),
175                     len(self.subhdr.subheaders))
176        assert_equal(self.subhdr._check_affines(), True)
177        assert_array_almost_equal(np.diag(self.subhdr.get_frame_affine()),
178                                  np.array([ 2.20241979, 2.20241979, 3.125,  1.]))
179        assert_equal(self.subhdr.get_zooms()[0], 2.20241978764534)
180        assert_equal(self.subhdr.get_zooms()[2], 3.125)
181        assert_equal(self.subhdr._get_data_dtype(0),np.uint16)
182        #assert_equal(self.subhdr._get_frame_offset(), 1024)
183        assert_equal(self.subhdr._get_frame_offset(), 1536)
184        dat = self.subhdr.raw_data_from_fileobj()
185        assert_equal(dat.shape, self.subhdr.get_shape())
186        scale_factor = self.subhdr.subheaders[0]['scale_factor']
187        assert_equal(self.subhdr.subheaders[0]['scale_factor'].item(),1.0)
188        ecat_calib_factor = self.hdr['ecat_calibration_factor']
189        assert_equal(ecat_calib_factor, 25007614.0)
190
191class TestEcatImage(TestCase):
192    image_class = EcatImage
193    example_file = ecat_file
194    img = image_class.load(example_file)
195
196    def test_file(self):
197        assert_equal(self.img.file_map['header'].filename,
198                     self.example_file)
199        assert_equal(self.img.file_map['image'].filename,
200                     self.example_file)
201
202    def test_save(self):
203        tmp_file = 'tinypet_tmp.v'
204        with InTemporaryDirectory():
205            self.img.to_filename(tmp_file)
206            other = self.image_class.load(tmp_file)
207            assert_equal(self.img.get_data().all(), other.get_data().all())
208            # Delete object holding reference to temporary file to make Windows
209            # happier.
210            del other
211
212    def test_data(self):
213        dat = self.img.get_data()
214        assert_equal(dat.shape, self.img.shape)
215        frame = self.img.get_frame(0)
216        assert_array_equal(frame, dat[:,:,:,0])
217
218    def test_array_proxy(self):
219        # Get the cached data copy
220        dat = self.img.get_data()
221        # Make a new one to test arrayproxy
222        img = self.image_class.load(self.example_file)
223        # Maybe we will promote _data to public, but I know this looks bad
224        secret_data = img._data
225        data2 = np.array(secret_data)
226        assert_array_equal(data2, dat)
227        # Check it rereads
228        data3 = np.array(secret_data)
229        assert_array_equal(data3, dat)
230