tomwer 1.4.0__py3-none-any.whl → 1.4.0rc0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orangecontrib/tomwer/tutorials/test_cor.ows +3 -3
- orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +14 -6
- orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +2 -4
- tomwer/app/axis.py +3 -0
- tomwer/app/multipag.py +3 -11
- tomwer/core/process/reconstruction/axis/axis.py +736 -27
- tomwer/core/process/reconstruction/axis/mode.py +24 -86
- tomwer/core/process/reconstruction/axis/params.py +138 -127
- tomwer/core/process/reconstruction/nabu/nabuscores.py +22 -19
- tomwer/core/process/reconstruction/nabu/nabuslices.py +1 -5
- tomwer/core/process/reconstruction/saaxis/saaxis.py +4 -4
- tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +4 -4
- tomwer/core/process/reconstruction/tests/test_axis.py +1 -1
- tomwer/core/process/reconstruction/tests/test_utils.py +4 -4
- tomwer/core/process/reconstruction/utils/cor.py +4 -8
- tomwer/core/process/tests/test_axis.py +231 -0
- tomwer/core/process/tests/test_nabu.py +3 -1
- tomwer/core/scan/nxtomoscan.py +0 -2
- tomwer/core/scan/scanbase.py +4 -4
- tomwer/core/scan/tests/test_process_registration.py +18 -0
- tomwer/gui/reconstruction/axis/AxisMainWindow.py +9 -20
- tomwer/gui/reconstruction/axis/AxisOptionsWidget.py +79 -239
- tomwer/gui/reconstruction/axis/AxisSettingsWidget.py +17 -38
- tomwer/gui/reconstruction/axis/AxisWidget.py +8 -16
- tomwer/gui/reconstruction/axis/CalculationWidget.py +200 -44
- tomwer/gui/reconstruction/axis/ControlWidget.py +2 -10
- tomwer/gui/reconstruction/axis/InputWidget.py +155 -11
- tomwer/gui/reconstruction/saaxis/corrangeselector.py +10 -19
- tomwer/gui/reconstruction/scores/scoreplot.py +2 -5
- tomwer/gui/reconstruction/tests/test_nabu.py +0 -8
- tomwer/gui/stitching/config/axisparams.py +0 -2
- tomwer/gui/stitching/z_stitching/fineestimation.py +1 -1
- tomwer/gui/tests/test_axis_gui.py +15 -31
- tomwer/synctools/stacks/reconstruction/axis.py +23 -5
- tomwer/synctools/stacks/reconstruction/dkrefcopy.py +1 -1
- tomwer/synctools/stacks/reconstruction/nabu.py +2 -2
- tomwer/synctools/stacks/reconstruction/normalization.py +1 -1
- tomwer/synctools/stacks/reconstruction/saaxis.py +1 -1
- tomwer/synctools/stacks/reconstruction/sadeltabeta.py +1 -1
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_axis.py +16 -0
- tomwer/tests/test_ewoks/test_single_node_execution.py +1 -1
- tomwer/tests/test_ewoks/test_workflows.py +1 -1
- tomwer/version.py +1 -1
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/METADATA +3 -3
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/RECORD +49 -52
- tomwer/core/process/reconstruction/axis/side.py +0 -8
- tomwer/gui/fonts.py +0 -5
- tomwer/gui/reconstruction/axis/EstimatedCORWidget.py +0 -394
- tomwer/gui/reconstruction/axis/EstimatedCorComboBox.py +0 -118
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/LICENSE +0 -0
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/WHEEL +0 -0
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/entry_points.txt +0 -0
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/top_level.txt +0 -0
@@ -1,16 +1,12 @@
|
|
1
1
|
def relative_pos_to_absolute(relative_pos: float, det_width: int):
|
2
2
|
"""
|
3
|
-
|
3
|
+
convert relative center of rotation to absolute
|
4
4
|
"""
|
5
|
-
|
6
|
-
midpoint = det_width / 2.0
|
7
|
-
return relative_pos + midpoint
|
5
|
+
return relative_pos + (det_width - 1) / 2.0
|
8
6
|
|
9
7
|
|
10
8
|
def absolute_pos_to_relative(absolute_pos: float, det_width: int):
|
11
9
|
"""
|
12
|
-
|
10
|
+
convert absolute center of rotation to relative
|
13
11
|
"""
|
14
|
-
|
15
|
-
midpoint = det_width / 2.0
|
16
|
-
return absolute_pos - midpoint
|
12
|
+
return absolute_pos - (det_width - 1) / 2.0
|
@@ -0,0 +1,231 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
from __future__ import annotations
|
3
|
+
|
4
|
+
import os
|
5
|
+
import shutil
|
6
|
+
import tempfile
|
7
|
+
import unittest
|
8
|
+
|
9
|
+
import h5py
|
10
|
+
from tomoscan.io import get_swmr_mode
|
11
|
+
import numpy
|
12
|
+
from silx.io.utils import h5py_read_dataset
|
13
|
+
|
14
|
+
from tomwer.core.process.reconstruction.axis.mode import AxisMode
|
15
|
+
from tomwer.core.process.reconstruction.axis.params import AxisRP
|
16
|
+
from tomwer.core.process.task import Task
|
17
|
+
from tomwer.core.scan.edfscan import EDFTomoScan
|
18
|
+
from tomwer.core.scan.scanbase import TomwerScanBase
|
19
|
+
from tomwer.core.utils.scanutils import MockEDF, MockNXtomo
|
20
|
+
|
21
|
+
from ..reconstruction.axis.axis import AxisTask
|
22
|
+
|
23
|
+
|
24
|
+
class TestAxisIO(unittest.TestCase):
|
25
|
+
"""Test inputs and outputs types of the handler functions"""
|
26
|
+
|
27
|
+
@staticmethod
|
28
|
+
def _random_calc(scan):
|
29
|
+
return numpy.random.random()
|
30
|
+
|
31
|
+
def setUp(self):
|
32
|
+
self.scan_folder = tempfile.mkdtemp()
|
33
|
+
|
34
|
+
self.scan = MockEDF.mockScan(
|
35
|
+
scanID=self.scan_folder, nRadio=10, nRecons=1, nPagRecons=4, dim=10
|
36
|
+
)
|
37
|
+
self.recons_params = AxisRP()
|
38
|
+
|
39
|
+
# set the axis url to be used
|
40
|
+
projections = self.scan.projections
|
41
|
+
urls = list(projections.values())
|
42
|
+
self.scan.axis_params = AxisRP()
|
43
|
+
self.scan.axis_params.axis_url_1 = urls[0]
|
44
|
+
self.scan.axis_params.axis_url_2 = urls[1]
|
45
|
+
|
46
|
+
def tearDown(self):
|
47
|
+
shutil.rmtree(self.scan_folder)
|
48
|
+
|
49
|
+
def testInputOutput(self):
|
50
|
+
"""Test that io using TomoBase instance work"""
|
51
|
+
for input_type in (dict, TomwerScanBase):
|
52
|
+
for serialize_output_data in (True, False):
|
53
|
+
with self.subTest(
|
54
|
+
serialize_output_data=serialize_output_data,
|
55
|
+
input_type=input_type,
|
56
|
+
):
|
57
|
+
input_obj = self.scan
|
58
|
+
if input_obj is dict:
|
59
|
+
input_obj = input_obj.to_dict()
|
60
|
+
axis_process = AxisTask(
|
61
|
+
inputs={
|
62
|
+
"axis_params": self.recons_params,
|
63
|
+
"data": input_obj,
|
64
|
+
"serialize_output_data": serialize_output_data,
|
65
|
+
}
|
66
|
+
)
|
67
|
+
|
68
|
+
# patch the axis process
|
69
|
+
axis_process._CALCULATIONS_METHODS[AxisMode.centered] = (
|
70
|
+
TestAxisIO._random_calc
|
71
|
+
)
|
72
|
+
|
73
|
+
axis_process.run()
|
74
|
+
out = axis_process.outputs.data
|
75
|
+
if serialize_output_data:
|
76
|
+
self.assertTrue(isinstance(out, dict))
|
77
|
+
else:
|
78
|
+
self.assertTrue(isinstance(out, TomwerScanBase))
|
79
|
+
|
80
|
+
|
81
|
+
class TestAxis(unittest.TestCase):
|
82
|
+
"""Test the axis process"""
|
83
|
+
|
84
|
+
def setUp(self):
|
85
|
+
self.recons_params = AxisRP()
|
86
|
+
self.recons_params.mode = "centered"
|
87
|
+
|
88
|
+
def test_process_saved_edf(self):
|
89
|
+
"""Test that if process is called, the tomwer.h5 file is created
|
90
|
+
and is correctly saving information regarding the center of position
|
91
|
+
"""
|
92
|
+
self.tempdir = tempfile.mkdtemp()
|
93
|
+
mock = MockEDF(scan_path=self.tempdir, n_radio=10, n_ini_radio=10)
|
94
|
+
scan = EDFTomoScan(mock.scan_path)
|
95
|
+
self.recons_params.mode = "centered"
|
96
|
+
axis_process = AxisTask(
|
97
|
+
inputs={
|
98
|
+
"data": scan,
|
99
|
+
"axis_params": self.recons_params,
|
100
|
+
"serialize_output_data": False,
|
101
|
+
}
|
102
|
+
)
|
103
|
+
|
104
|
+
axis_process.run()
|
105
|
+
self.assertTrue(os.path.exists(scan.process_file))
|
106
|
+
|
107
|
+
with h5py.File(scan.process_file, "r", swmr=get_swmr_mode()) as h5f:
|
108
|
+
self.assertTrue("entry" in h5f)
|
109
|
+
self.assertTrue("tomwer_process_0" in h5f["entry"])
|
110
|
+
group_axis = h5f["entry"]["tomwer_process_0"]
|
111
|
+
self.assertTrue("configuration" in group_axis)
|
112
|
+
self.assertTrue("program" in group_axis)
|
113
|
+
self.assertTrue("results" in group_axis)
|
114
|
+
self.assertTrue("center_of_rotation" in group_axis["results"])
|
115
|
+
axis_value = h5py_read_dataset(group_axis["results"]["center_of_rotation"])
|
116
|
+
|
117
|
+
processes = Task.get_processes_frm_type(
|
118
|
+
process_file=scan.process_file, process_type=AxisTask, entry="entry"
|
119
|
+
)
|
120
|
+
self.assertEqual(len(processes), 1)
|
121
|
+
self.assertEqual(processes[0].results["center_of_rotation"], axis_value)
|
122
|
+
|
123
|
+
def test_process_saved_hdf5(self):
|
124
|
+
"""Test that if process is called, the tomwer.h5 file is created
|
125
|
+
and is correctly saving information regarding the center of position
|
126
|
+
"""
|
127
|
+
self.tempdir = tempfile.mkdtemp()
|
128
|
+
dim = 10
|
129
|
+
mock = MockNXtomo(
|
130
|
+
scan_path=self.tempdir, n_proj=10, n_ini_proj=10, scan_range=180, dim=dim
|
131
|
+
)
|
132
|
+
mock.add_alignment_radio(index=10, angle=90)
|
133
|
+
mock.add_alignment_radio(index=10, angle=0)
|
134
|
+
scan = mock.scan
|
135
|
+
self.recons_params.mode = "centered"
|
136
|
+
|
137
|
+
# check data url take
|
138
|
+
axis_process = AxisTask(
|
139
|
+
inputs={
|
140
|
+
"data": scan,
|
141
|
+
"axis_params": self.recons_params,
|
142
|
+
"serialize_output_data": False,
|
143
|
+
}
|
144
|
+
)
|
145
|
+
axis_process.run()
|
146
|
+
# make sure center of position has been computed
|
147
|
+
self.assertTrue(os.path.exists(scan.process_file))
|
148
|
+
|
149
|
+
with h5py.File(scan.process_file, "r", swmr=get_swmr_mode()) as h5f:
|
150
|
+
self.assertTrue("entry" in h5f)
|
151
|
+
self.assertTrue("tomwer_process_0" in h5f["entry"])
|
152
|
+
group_axis = h5f["entry"]["tomwer_process_0"]
|
153
|
+
self.assertTrue("configuration" in group_axis)
|
154
|
+
self.assertTrue("program" in group_axis)
|
155
|
+
self.assertTrue("results" in group_axis)
|
156
|
+
self.assertTrue("center_of_rotation" in group_axis["results"])
|
157
|
+
axis_value = h5py_read_dataset(group_axis["results"]["center_of_rotation"])
|
158
|
+
self.assertTrue(-dim / 2 <= axis_value <= dim / 2)
|
159
|
+
processes = Task.get_processes_frm_type(
|
160
|
+
process_file=scan.process_file, process_type=AxisTask
|
161
|
+
)
|
162
|
+
self.assertEqual(len(processes), 1)
|
163
|
+
self.assertEqual(processes[0].results["center_of_rotation"], axis_value)
|
164
|
+
|
165
|
+
|
166
|
+
class TestAxisRP(unittest.TestCase):
|
167
|
+
"""Test the class used for AxisProcess configuration"""
|
168
|
+
|
169
|
+
def setUp(self):
|
170
|
+
self.axis_rp = AxisRP()
|
171
|
+
self.tmp_folder = tempfile.mkdtemp()
|
172
|
+
|
173
|
+
def tearDown(self):
|
174
|
+
shutil.rmtree(self.tmp_folder)
|
175
|
+
|
176
|
+
|
177
|
+
class TestSinogramAlgorithm(unittest.TestCase):
|
178
|
+
def setUp(self) -> None:
|
179
|
+
self.tmp_folder = tempfile.mkdtemp()
|
180
|
+
dim = 512
|
181
|
+
self.scan = MockNXtomo(
|
182
|
+
scan_path=self.tmp_folder,
|
183
|
+
n_proj=10,
|
184
|
+
n_ini_proj=10,
|
185
|
+
create_ini_dark=True,
|
186
|
+
create_final_flat=True,
|
187
|
+
scan_range=360,
|
188
|
+
dim=dim,
|
189
|
+
).scan
|
190
|
+
|
191
|
+
def tearDown(self):
|
192
|
+
shutil.rmtree(self.tmp_folder)
|
193
|
+
|
194
|
+
def test_growing_window_sinogram(self):
|
195
|
+
recons_params = AxisRP()
|
196
|
+
axis_process = AxisTask(
|
197
|
+
inputs={"axis_params": recons_params, "data": self.scan}
|
198
|
+
)
|
199
|
+
recons_params.mode = AxisMode.growing_window_sinogram
|
200
|
+
recons_params.use_sinogram = True
|
201
|
+
recons_params.sinogram_subsampling = 1
|
202
|
+
axis_process.run()
|
203
|
+
|
204
|
+
def test_sliding_window(self):
|
205
|
+
recons_params = AxisRP()
|
206
|
+
axis_process = AxisTask(
|
207
|
+
inputs={
|
208
|
+
"axis_params": recons_params,
|
209
|
+
"data": self.scan,
|
210
|
+
"serialize_output_data": False,
|
211
|
+
}
|
212
|
+
)
|
213
|
+
recons_params.mode = AxisMode.sliding_window_sinogram
|
214
|
+
recons_params.side = "left"
|
215
|
+
recons_params.sinogram_subsampling = 1
|
216
|
+
recons_params.use_sinogram = True
|
217
|
+
axis_process.run()
|
218
|
+
|
219
|
+
def test_sino_coarse_to_fine(self):
|
220
|
+
recons_params = AxisRP()
|
221
|
+
axis_process = AxisTask(
|
222
|
+
inputs={
|
223
|
+
"axis_params": recons_params,
|
224
|
+
"data": self.scan,
|
225
|
+
"serialize_output_data": False,
|
226
|
+
}
|
227
|
+
)
|
228
|
+
recons_params.mode = AxisMode.sino_coarse_to_fine
|
229
|
+
recons_params.sinogram_subsampling = 1
|
230
|
+
recons_params.sinogram_line = 2
|
231
|
+
axis_process.run()
|
@@ -402,7 +402,9 @@ class TestNabuAndAxis(unittest.TestCase):
|
|
402
402
|
nabu_rotation_axis_value = self.get_saved_rotation_axis(nabu_conf_files[0])
|
403
403
|
self.assertEqual(
|
404
404
|
nabu_rotation_axis_value,
|
405
|
-
str(
|
405
|
+
str(
|
406
|
+
self.scan._axis_params.relative_cor_value + (self.scan.dim_1 - 1) / 2.0
|
407
|
+
),
|
406
408
|
)
|
407
409
|
|
408
410
|
|
tomwer/core/scan/nxtomoscan.py
CHANGED
@@ -18,7 +18,6 @@ from tomoscan.esrf.identifier.hdf5Identifier import (
|
|
18
18
|
)
|
19
19
|
from tomoscan.esrf.identifier.url_utils import UrlSettings, split_path, split_query
|
20
20
|
from tomoscan.esrf.scan.nxtomoscan import NXtomoScan as _tsNXtomoScan
|
21
|
-
from tomoscan.utils.io import filter_esrf_mounting_points
|
22
21
|
from nxtomo.nxobject.nxdetector import ImageKey
|
23
22
|
from nxtomo.paths.nxtomo import get_paths as _get_nexus_paths
|
24
23
|
|
@@ -488,7 +487,6 @@ class NXtomoScan(_tsNXtomoScan, TomwerScanBase):
|
|
488
487
|
bliss_raw_data_files[0] if len(bliss_raw_data_files) > 0 else None
|
489
488
|
)
|
490
489
|
if bliss_raw_data_file is not None:
|
491
|
-
bliss_raw_data_file = filter_esrf_mounting_points(bliss_raw_data_file)
|
492
490
|
strips = bliss_raw_data_file.lstrip("/").split("/")
|
493
491
|
if len(strips) > 2 and bliss_raw_data_file.startswith(
|
494
492
|
("/data/visitor", "/data/visitor")
|
tomwer/core/scan/scanbase.py
CHANGED
@@ -279,6 +279,7 @@ class TomwerScanBase(TomwerObject):
|
|
279
279
|
def get_opposite_projections(self, mode) -> tuple:
|
280
280
|
"""
|
281
281
|
Return the two best opposite projections for the required mode.
|
282
|
+
|
282
283
|
"""
|
283
284
|
radios_with_angle = self.projections_with_angle()
|
284
285
|
angles = numpy.array(
|
@@ -321,10 +322,9 @@ class TomwerScanBase(TomwerObject):
|
|
321
322
|
nearest_c1 = find_nearest(angles=angles, angle=couples[0])
|
322
323
|
nearest_c2 = find_nearest(angles=angles, angle=couples[1])
|
323
324
|
if nearest_c1 is not None and nearest_c2 is not None:
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
)
|
325
|
+
radio_0 = AxisResource(radios_with_angle[nearest_c1])
|
326
|
+
radio_1 = AxisResource(radios_with_angle[nearest_c2])
|
327
|
+
return radio_0, radio_1
|
328
328
|
else:
|
329
329
|
return None, None
|
330
330
|
|
@@ -40,6 +40,24 @@ class TestProcessRegistration(unittest.TestCase):
|
|
40
40
|
def tearDown(self):
|
41
41
|
shutil.rmtree(self.tmp_dir)
|
42
42
|
|
43
|
+
def testGetCorValues(self):
|
44
|
+
from tomwer.core.process.reconstruction.axis import AxisTask
|
45
|
+
|
46
|
+
for i in range(20):
|
47
|
+
results = {"center_of_rotation": i}
|
48
|
+
Task._register_process(
|
49
|
+
self.scan.process_file,
|
50
|
+
process=AxisTask,
|
51
|
+
entry=self.scan.entry,
|
52
|
+
configuration=None,
|
53
|
+
results=results,
|
54
|
+
process_index=i,
|
55
|
+
)
|
56
|
+
cor_value = AxisTask.get_cor_frm_process_file(
|
57
|
+
self.scan.process_file, entry=self.scan.entry
|
58
|
+
)
|
59
|
+
self.assertEqual(cor_value, 19)
|
60
|
+
|
43
61
|
def testGetProcessNodes(self):
|
44
62
|
"""insure it return the last dark process based on the processing index"""
|
45
63
|
|
@@ -10,10 +10,6 @@ from silx.gui import qt
|
|
10
10
|
from tomwer.gui.utils.qt_utils import block_signals
|
11
11
|
|
12
12
|
from tomwer.core.process.reconstruction.axis.mode import AxisMode
|
13
|
-
from tomwer.core.process.reconstruction.utils.cor import (
|
14
|
-
absolute_pos_to_relative,
|
15
|
-
relative_pos_to_absolute,
|
16
|
-
)
|
17
13
|
from tomwer.core.scan.scanbase import TomwerScanBase
|
18
14
|
|
19
15
|
from ...utils.scandescription import ScanNameLabelAndShape
|
@@ -128,15 +124,17 @@ class AxisMainWindow(qt.QMainWindow):
|
|
128
124
|
)
|
129
125
|
|
130
126
|
def setAutoUpdateEstimatedCor(self, value):
|
131
|
-
self._axisWidget.
|
132
|
-
|
133
|
-
|
127
|
+
self._axisWidget.setUpdateAutomaticallyEstimatedCor(value)
|
128
|
+
|
129
|
+
def getAutoUpdateEstimatedCor(self):
|
130
|
+
return self._axisWidget.updateAutomaticallyEstimatedCor()
|
134
131
|
|
135
132
|
def manual_uses_full_image(self, value):
|
136
133
|
self._axisWidget.manual_uses_full_image(value)
|
137
134
|
|
138
135
|
def _modeChanged(self):
|
139
136
|
self.getAxisParams().mode = self.getMode()
|
137
|
+
self.getAxisParams().use_sinogram = self.useSinogram()
|
140
138
|
|
141
139
|
def _CORValueLocked(self, lock):
|
142
140
|
if lock:
|
@@ -154,8 +152,8 @@ class AxisMainWindow(qt.QMainWindow):
|
|
154
152
|
and relative_value is not None
|
155
153
|
):
|
156
154
|
try:
|
157
|
-
absolute_value =
|
158
|
-
|
155
|
+
absolute_value = (
|
156
|
+
relative_value + (self._axis_params.frame_width - 1) / 2.0
|
159
157
|
)
|
160
158
|
except TypeError:
|
161
159
|
absolute_value = None
|
@@ -165,8 +163,8 @@ class AxisMainWindow(qt.QMainWindow):
|
|
165
163
|
and absolute_value is not None
|
166
164
|
):
|
167
165
|
try:
|
168
|
-
relative_value =
|
169
|
-
|
166
|
+
relative_value = (
|
167
|
+
absolute_value - (self._axis_params.frame_width - 1) / 2.0
|
170
168
|
)
|
171
169
|
except TypeError:
|
172
170
|
relative_value = None
|
@@ -264,12 +262,3 @@ class AxisMainWindow(qt.QMainWindow):
|
|
264
262
|
|
265
263
|
def setEstimatedCor(self, value: float):
|
266
264
|
self._axisWidget.setEstimatedCor(value=value)
|
267
|
-
|
268
|
-
def getAutoUpdateEstimatedCor(self):
|
269
|
-
return self._axisWidget.updateXRotationAxisPixelPositionOnNewScan()
|
270
|
-
|
271
|
-
def isYAxisInverted(self) -> bool:
|
272
|
-
return self._axisWidget.isYAxisInverted()
|
273
|
-
|
274
|
-
def setYAxisInverted(self, checked: bool):
|
275
|
-
return self._axisWidget.setYAxisInverted(checked=checked)
|