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.
Files changed (53) hide show
  1. orangecontrib/tomwer/tutorials/test_cor.ows +3 -3
  2. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +14 -6
  3. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +2 -4
  4. tomwer/app/axis.py +3 -0
  5. tomwer/app/multipag.py +3 -11
  6. tomwer/core/process/reconstruction/axis/axis.py +736 -27
  7. tomwer/core/process/reconstruction/axis/mode.py +24 -86
  8. tomwer/core/process/reconstruction/axis/params.py +138 -127
  9. tomwer/core/process/reconstruction/nabu/nabuscores.py +22 -19
  10. tomwer/core/process/reconstruction/nabu/nabuslices.py +1 -5
  11. tomwer/core/process/reconstruction/saaxis/saaxis.py +4 -4
  12. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +4 -4
  13. tomwer/core/process/reconstruction/tests/test_axis.py +1 -1
  14. tomwer/core/process/reconstruction/tests/test_utils.py +4 -4
  15. tomwer/core/process/reconstruction/utils/cor.py +4 -8
  16. tomwer/core/process/tests/test_axis.py +231 -0
  17. tomwer/core/process/tests/test_nabu.py +3 -1
  18. tomwer/core/scan/nxtomoscan.py +0 -2
  19. tomwer/core/scan/scanbase.py +4 -4
  20. tomwer/core/scan/tests/test_process_registration.py +18 -0
  21. tomwer/gui/reconstruction/axis/AxisMainWindow.py +9 -20
  22. tomwer/gui/reconstruction/axis/AxisOptionsWidget.py +79 -239
  23. tomwer/gui/reconstruction/axis/AxisSettingsWidget.py +17 -38
  24. tomwer/gui/reconstruction/axis/AxisWidget.py +8 -16
  25. tomwer/gui/reconstruction/axis/CalculationWidget.py +200 -44
  26. tomwer/gui/reconstruction/axis/ControlWidget.py +2 -10
  27. tomwer/gui/reconstruction/axis/InputWidget.py +155 -11
  28. tomwer/gui/reconstruction/saaxis/corrangeselector.py +10 -19
  29. tomwer/gui/reconstruction/scores/scoreplot.py +2 -5
  30. tomwer/gui/reconstruction/tests/test_nabu.py +0 -8
  31. tomwer/gui/stitching/config/axisparams.py +0 -2
  32. tomwer/gui/stitching/z_stitching/fineestimation.py +1 -1
  33. tomwer/gui/tests/test_axis_gui.py +15 -31
  34. tomwer/synctools/stacks/reconstruction/axis.py +23 -5
  35. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +1 -1
  36. tomwer/synctools/stacks/reconstruction/nabu.py +2 -2
  37. tomwer/synctools/stacks/reconstruction/normalization.py +1 -1
  38. tomwer/synctools/stacks/reconstruction/saaxis.py +1 -1
  39. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +1 -1
  40. tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_axis.py +16 -0
  41. tomwer/tests/test_ewoks/test_single_node_execution.py +1 -1
  42. tomwer/tests/test_ewoks/test_workflows.py +1 -1
  43. tomwer/version.py +1 -1
  44. {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/METADATA +3 -3
  45. {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/RECORD +49 -52
  46. tomwer/core/process/reconstruction/axis/side.py +0 -8
  47. tomwer/gui/fonts.py +0 -5
  48. tomwer/gui/reconstruction/axis/EstimatedCORWidget.py +0 -394
  49. tomwer/gui/reconstruction/axis/EstimatedCorComboBox.py +0 -118
  50. {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/LICENSE +0 -0
  51. {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/WHEEL +0 -0
  52. {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/entry_points.txt +0 -0
  53. {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
- Convert relative center of rotation to absolute.
3
+ convert relative center of rotation to absolute
4
4
  """
5
- # Compute the midpoint differently for even and odd widths
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
- Convert absolute center of rotation to relative.
10
+ convert absolute center of rotation to relative
13
11
  """
14
- # Compute the midpoint differently for even and odd widths
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(self.scan._axis_params.relative_cor_value + (self.scan.dim_1 / 2.0)),
405
+ str(
406
+ self.scan._axis_params.relative_cor_value + (self.scan.dim_1 - 1) / 2.0
407
+ ),
406
408
  )
407
409
 
408
410
 
@@ -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")
@@ -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
- return (
325
- AxisResource(radios_with_angle[nearest_c1], angle=nearest_c1),
326
- AxisResource(radios_with_angle[nearest_c2], angle=nearest_c2),
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._settingsWidget._mainWidget.setUpdateXRotationAxisPixelPositionOnNewScan(
132
- value
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 = relative_pos_to_absolute(
158
- relative_pos=relative_value, det_width=self._axis_params.frame_width
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 = absolute_pos_to_relative(
169
- absolute_pos=absolute_value, det_width=self._axis_params.frame_width
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)