test_hdf5scan.py 9.51 KB
Newer Older
payno's avatar
payno committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
"""Unit test for the scan defined at the hdf5 format"""

__authors__ = ["H. Payno"]
__license__ = "MIT"
__date__ = "16/09/2019"

import unittest
import shutil
import os
import tempfile
from tomoscan.test.utils import UtilsTest
36
from tomoscan.esrf.hdf5scan import HDF5TomoScan, ImageKey, Frame
payno's avatar
payno committed
37
from ...unitsystem import metricsystem
38
from silx.io.utils import get_data
payno's avatar
payno committed
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import numpy


class HDF5TestBaseClass(unittest.TestCase):
    """base class for hdf5 unit test"""
    def get_dataset(self, hdf5_dataset_name):
        dataset_file = os.path.join(self.test_dir, hdf5_dataset_name)
        o_dataset_file = UtilsTest.getH5Dataset(folderID=hdf5_dataset_name)
        shutil.copy(src=o_dataset_file, dst=dataset_file)
        return dataset_file

    def setUp(self) -> None:
        self.test_dir = tempfile.mkdtemp()

    def tearDown(self) -> None:
        shutil.rmtree(self.test_dir)


class TestHDF5Scan(HDF5TestBaseClass):
    """Basic test for the hdf5 scan"""
    def setUp(self) -> None:
        super(TestHDF5Scan, self).setUp()
61
62
        self.dataset_file = self.get_dataset('frm_edftomomill_twoentries.nx')
        self.scan = HDF5TomoScan(scan=self.dataset_file)
payno's avatar
payno committed
63
64
65
66
67
68

    def testGeneral(self):
        """some general on the HDF5Scan """
        self.assertEqual(self.scan.master_file, self.dataset_file)
        self.assertEqual(self.scan.path, os.path.dirname(self.dataset_file))
        self.assertEqual(self.scan.type, 'hdf5')
payno's avatar
payno committed
69
        self.assertEqual(self.scan.entry, 'entry0000')
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
        self.assertEqual(len(self.scan.flats), 42)
        self.assertEqual(len(self.scan.darks), 1)
        self.assertEqual(len(self.scan.return_projs), 3)
        proj_angles = self.scan.get_proj_angle_url()
        self.assertEqual(len(proj_angles), 1500 + 3)
        self.assertTrue(90 in proj_angles)
        self.assertTrue(24.0 in proj_angles)
        self.assertTrue('90.0(1)' in proj_angles)
        self.assertTrue('180.0(1)' in proj_angles)
        self.assertTrue(179.88 not in proj_angles)

        url_1 = proj_angles[0]
        self.assertTrue(url_1.is_valid())
        self.assertTrue(url_1.is_absolute())
        self.assertEquals(url_1.scheme(), 'silx')
        # check conversion to dict
payno's avatar
payno committed
86
87
        _dict = self.scan.to_dict()
        scan2 = HDF5TomoScan.from_dict(_dict)
88
        self.assertEqual(scan2.master_file, self.scan.master_file)
89
90
91
92
93
94
95
96
97
98
99
        self.assertEqual(scan2.entry, self.scan.entry)

    def testFrames(self):
        """Check the `frames` property which is massively used under the
        HDF5TomoScan class"""
        frames = self.scan.frames
        # check some projections
        proj_2 = frames[24]
        self.assertTrue(isinstance(proj_2, Frame))
        self.assertEqual(proj_2.index, 24)
        numpy.isclose(proj_2.rotation_angle, 0.24)
100
        self.assertFalse(proj_2.is_control)
101
        self.assertEqual(proj_2.url.file_path(), self.scan.master_file)
payno's avatar
payno committed
102
        self.assertEqual(proj_2.url.data_path(), 'entry0000/instrument/detector/data')
103
104
105
106
107
108
109
110
        self.assertEqual(proj_2.url.data_slice(), 24)
        self.assertEqual(proj_2.image_key, ImageKey.PROJECTION)
        self.assertEqual(get_data(proj_2.url).shape, (20, 20))
        # check last two non-return projection
        for frame_index in (1520, 1542):
            with self.subTest(frame_index=frame_index):
                frame = frames[frame_index]
                self.assertTrue(frame.image_key, ImageKey.PROJECTION)
111
                self.assertFalse(frame.is_control)
112
113
114
115
116

        # check some darks
        dark_0 = frames[0]
        self.assertEqual(dark_0.index, 0)
        numpy.isclose(dark_0.rotation_angle, 0.0)
117
        self.assertFalse(dark_0.is_control)
118
        self.assertEqual(dark_0.url.file_path(), self.scan.master_file)
payno's avatar
payno committed
119
        self.assertEqual(dark_0.url.data_path(), 'entry0000/instrument/detector/data')
120
121
122
123
124
125
126
127
        self.assertEqual(dark_0.url.data_slice(), 0)
        self.assertEqual(dark_0.image_key, ImageKey.DARK_FIELD)
        self.assertEqual(get_data(dark_0.url).shape, (20, 20))

        # check some refs
        ref_1 = frames[2]
        self.assertEqual(ref_1.index, 2)
        numpy.isclose(ref_1.rotation_angle, 0.0)
128
        self.assertFalse(ref_1.is_control)
129
130
        self.assertEqual(ref_1.url.file_path(), self.scan.master_file)
        self.assertEqual(ref_1.url.data_path(),
payno's avatar
payno committed
131
                         'entry0000/instrument/detector/data')
132
133
134
135
136
137
138
139
140
        self.assertEqual(ref_1.url.data_slice(), 2)
        self.assertEqual(ref_1.image_key, ImageKey.FLAT_FIELD)
        self.assertEqual(get_data(ref_1.url).shape, (20, 20))

        # check some return projections
        r_proj_0 = frames[1543]
        self.assertTrue(isinstance(r_proj_0, Frame))
        self.assertEqual(r_proj_0.index, 1543)
        numpy.isclose(r_proj_0.rotation_angle, 180)
141
        self.assertTrue(r_proj_0.is_control)
142
143
        self.assertEqual(r_proj_0.url.file_path(), self.scan.master_file)
        self.assertEqual(r_proj_0.url.data_path(),
payno's avatar
payno committed
144
                         'entry0000/instrument/detector/data')
145
146
147
        self.assertEqual(r_proj_0.url.data_slice(), 1543)
        self.assertEqual(r_proj_0.image_key, ImageKey.PROJECTION)
        self.assertEqual(get_data(r_proj_0.url).shape, (20, 20))
payno's avatar
payno committed
148

149
    def testProjections(self):
150
        """Make sure projections are valid"""
payno's avatar
payno committed
151
        projections = self.scan.projections
152
        self.assertEqual(len(self.scan.projections), 1500)
153
        url_0 = projections[list(projections.keys())[0]]
154
155
156
        self.assertEqual(url_0.file_path(), os.path.join(self.scan.master_file))
        self.assertEqual(url_0.data_slice(), 22)

payno's avatar
payno committed
157
    def testDark(self):
158
159
        """Make sure darks are valid"""
        n_dark = 1
payno's avatar
payno committed
160
        self.assertEqual(self.scan.dark_n, n_dark)
161
162
163
        darks = self.scan.darks
        self.assertEqual(len(darks), 1)
        # TODO check accumulation time
payno's avatar
payno committed
164

payno's avatar
payno committed
165
    def testFlats(self):
166
        """Make sure flats are valid"""
167
168
169
170
        n_flats = 42
        flats = self.scan.flats
        self.assertEqual(len(flats), n_flats)
        self.assertEqual(self.scan.ref_n, n_flats)
payno's avatar
payno committed
171
        with self.assertRaises(NotImplementedError):
172
            self.scan.ff_interval
payno's avatar
payno committed
173

174
175
176
    def testDims(self):
        self.assertEqual(self.scan.dim_1, 20)
        self.assertEqual(self.scan.dim_2, 20)
payno's avatar
payno committed
177
178

    def testAxisUtils(self):
179
180
        self.assertEqual(self.scan.scan_range, 180)
        self.assertEqual(self.scan.tomo_n, 1500)
payno's avatar
payno committed
181

payno's avatar
payno committed
182
        radios_urls_evolution = self.scan.get_proj_angle_url()
183
184
185
        self.assertEquals(len(radios_urls_evolution), 1503)
        self.assertEquals(radios_urls_evolution[0].file_path(), self.scan.master_file)
        self.assertEquals(radios_urls_evolution[0].data_slice(), 22)
payno's avatar
payno committed
186
        self.assertEquals(radios_urls_evolution[0].data_path(), 'entry0000/instrument/detector/data')
payno's avatar
payno committed
187
188

    def testDarkRefUtils(self):
189
        self.assertEqual(self.scan.tomo_n, 1500)
payno's avatar
payno committed
190
191
192
        pixel_size = self.scan.pixel_size
        self.assertTrue(pixel_size is not None)
        self.assertTrue(numpy.isclose(self.scan.pixel_size,
193
194
                                      0.05 * metricsystem.MetricSystem.MILLIMETER.value))
        self.assertTrue(numpy.isclose(self.scan.get_pixel_size(unit='micrometer'), 50))
payno's avatar
payno committed
195
        self.assertTrue(numpy.isclose(self.scan.x_pixel_size,
196
                                      0.05 * metricsystem.MetricSystem.MILLIMETER.value))
payno's avatar
payno committed
197
        self.assertTrue(numpy.isclose(self.scan.y_pixel_size,
198
                                      0.05 * metricsystem.MetricSystem.MILLIMETER.value))
payno's avatar
payno committed
199
200
201
202

    def testNabuUtil(self):
        self.assertTrue(numpy.isclose(self.scan.distance, -19.9735))
        self.assertTrue(numpy.isclose(self.scan.get_distance(unit='cm'), -1997.35))
payno's avatar
payno committed
203
204


205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
    def testCompactedProjs(self):
        projs_compacted = self.scan.projections_compacted
        self.assertTrue(projs_compacted.keys() == self.scan.projections.keys())
        # ~ print(set(map(str, list(projs_compacted.values()))))
        for i in range(22, 1520+1):
            self.assertTrue(
                projs_compacted[i].data_slice() == slice(22, 1521, None)
            )
        for i in range(1542, 1543):
            self.assertTrue(
                projs_compacted[i].data_slice() == slice(1542, 1543, None)
            )



payno's avatar
payno committed
220
221
222
223
224
225
226
227
228
def suite():
    test_suite = unittest.TestSuite()
    for ui in (TestHDF5Scan, ):
        test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(ui))
    return test_suite


if __name__ == '__main__':
    unittest.main(defaultTest="suite")