tomwer 1.4.0rc5__py3-none-any.whl → 1.4.1__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/simple_volume_to_slurm_reconstruction.ows +2 -2
- orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +19 -47
- orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +8 -3
- orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +4 -6
- orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +8 -4
- orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +0 -4
- orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +1 -13
- tomwer/app/axis.py +0 -1
- tomwer/app/intensitynormalization.py +0 -14
- tomwer/app/multicor.py +1 -33
- tomwer/app/multipag.py +1 -31
- tomwer/app/nabuapp.py +0 -1
- tomwer/app/patchrawdarkflat.py +0 -3
- tomwer/app/reducedarkflat.py +0 -1
- tomwer/core/process/control/datalistener/datalistener.py +0 -232
- tomwer/core/process/control/datawatcher/datawatcher.py +0 -5
- tomwer/core/process/control/scantransfer.py +3 -60
- tomwer/core/process/edit/darkflatpatch.py +0 -8
- tomwer/core/process/edit/imagekeyeditor.py +2 -19
- tomwer/core/process/reconstruction/axis/axis.py +0 -13
- tomwer/core/process/reconstruction/darkref/darkrefs.py +0 -59
- tomwer/core/process/reconstruction/nabu/nabuslices.py +0 -88
- tomwer/core/process/reconstruction/nabu/nabuvolume.py +0 -10
- tomwer/core/process/reconstruction/params_cache.py +36 -0
- tomwer/core/process/reconstruction/saaxis/saaxis.py +80 -88
- tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +78 -86
- tomwer/core/process/reconstruction/tests/test_params_cache.py +37 -0
- tomwer/core/process/script/python.py +0 -19
- tomwer/core/process/task.py +0 -290
- tomwer/core/process/tests/test_dark_and_flat.py +0 -6
- tomwer/core/process/tests/test_data_transfer.py +0 -1
- tomwer/core/process/tests/test_data_watcher.py +6 -23
- tomwer/core/scan/edfscan.py +0 -11
- tomwer/core/scan/nxtomoscan.py +0 -12
- tomwer/core/scan/scanbase.py +0 -81
- tomwer/gui/reconstruction/axis/CalculationWidget.py +3 -5
- tomwer/gui/reconstruction/tests/test_saaxis.py +2 -2
- tomwer/gui/reconstruction/tests/test_sadeltabeta.py +2 -2
- tomwer/gui/stitching/config/axisparams.py +2 -0
- tomwer/synctools/stacks/reconstruction/axis.py +0 -18
- tomwer/synctools/tests/test_foldertransfer.py +2 -19
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_i_norm.py +0 -10
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_sa_delta_beta.py +103 -153
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_saaxis.py +117 -152
- tomwer/tests/orangecontrib/tomwer/widgets/{tests/test_darkref.py → test_darkref.py} +0 -9
- tomwer/tests/orangecontrib/tomwer/widgets/{tests/test_foldertransfert.py → test_foldertransfert.py} +1 -1
- tomwer/tests/test_ewoks/test_workflows.py +0 -4
- tomwer/version.py +3 -3
- {tomwer-1.4.0rc5.dist-info → tomwer-1.4.1.dist-info}/METADATA +2 -3
- {tomwer-1.4.0rc5.dist-info → tomwer-1.4.1.dist-info}/RECORD +55 -56
- tomwer/core/scan/tests/test_process_registration.py +0 -64
- tomwer/core/utils/Singleton.py +0 -36
- tomwer/core/utils/locker.py +0 -58
- /tomwer/tests/orangecontrib/tomwer/widgets/{tests/test_conditions.py → test_conditions.py} +0 -0
- {tomwer-1.4.0rc5.dist-info → tomwer-1.4.1.dist-info}/LICENSE +0 -0
- {tomwer-1.4.0rc5.dist-info → tomwer-1.4.1.dist-info}/WHEEL +0 -0
- {tomwer-1.4.0rc5.dist-info → tomwer-1.4.1.dist-info}/entry_points.txt +0 -0
- {tomwer-1.4.0rc5.dist-info → tomwer-1.4.1.dist-info}/top_level.txt +0 -0
tomwer/core/process/task.py
CHANGED
@@ -8,17 +8,9 @@ from __future__ import annotations
|
|
8
8
|
|
9
9
|
import logging
|
10
10
|
from collections import namedtuple
|
11
|
-
from datetime import datetime
|
12
11
|
|
13
|
-
import h5py
|
14
|
-
import numpy
|
15
12
|
from ewokscore.task import Task as _EwoksTask
|
16
13
|
from ewokscore.taskwithprogress import TaskWithProgress as _EwoksTaskWithProgress
|
17
|
-
from silx.io.dictdump import dicttoh5, h5todict
|
18
|
-
from silx.io.utils import h5py_read_dataset
|
19
|
-
from silx.io.utils import open as open_hdf5
|
20
|
-
from tomoscan.io import HDF5File
|
21
|
-
from tomwer.core.utils.locker import FileLockerManager
|
22
14
|
|
23
15
|
|
24
16
|
_logger = logging.getLogger(__name__)
|
@@ -31,15 +23,10 @@ _process_desc = namedtuple(
|
|
31
23
|
class BaseProcessInfo:
|
32
24
|
"""Tomwer base process class"""
|
33
25
|
|
34
|
-
_output_values = {}
|
35
|
-
# TODO: look at this: not sure this is needed anymore
|
36
|
-
|
37
26
|
def __init__(self, inputs=None):
|
38
27
|
"""
|
39
28
|
:param return_dict: if True serialize (to_dict / from_dict functions) between each task
|
40
29
|
"""
|
41
|
-
if inputs is None:
|
42
|
-
inputs = {}
|
43
30
|
|
44
31
|
self._scheme_title = (
|
45
32
|
"scheme_title" # TODO: have a look, this must be get somewhere and reused ?
|
@@ -60,29 +47,6 @@ class BaseProcessInfo:
|
|
60
47
|
# TODO: use argsparse instead of this dict ?
|
61
48
|
raise NotImplementedError("BaseProcess is an abstract class")
|
62
49
|
|
63
|
-
def get_output_value(self, key):
|
64
|
-
"""
|
65
|
-
|
66
|
-
:param key:
|
67
|
-
:return:
|
68
|
-
"""
|
69
|
-
assert type(key) is str
|
70
|
-
if key in self._output_values:
|
71
|
-
return self._output_values[key]
|
72
|
-
else:
|
73
|
-
return None
|
74
|
-
|
75
|
-
def clear_output_values(self):
|
76
|
-
self._output_values.clear()
|
77
|
-
|
78
|
-
def register_output(self, key, value):
|
79
|
-
"""
|
80
|
-
|
81
|
-
:param key: name of the output
|
82
|
-
:param value: value of the output
|
83
|
-
"""
|
84
|
-
self._output_values[key] = value
|
85
|
-
|
86
50
|
@staticmethod
|
87
51
|
def program_name():
|
88
52
|
"""Name of the program used for this processing"""
|
@@ -113,260 +77,6 @@ class BaseProcessInfo:
|
|
113
77
|
def set_configuration(self, configuration: dict) -> None:
|
114
78
|
self._settings = configuration
|
115
79
|
|
116
|
-
def register_process(
|
117
|
-
self,
|
118
|
-
process_file: str,
|
119
|
-
entry: str,
|
120
|
-
configuration: dict | None,
|
121
|
-
results: dict | None,
|
122
|
-
process_index: int,
|
123
|
-
interpretations: dict | None = None,
|
124
|
-
overwrite: bool = True,
|
125
|
-
) -> None:
|
126
|
-
"""
|
127
|
-
Store the current process in the linked h5 file if any,
|
128
|
-
output data stored will be the one defined by the data_keys
|
129
|
-
|
130
|
-
:param process_file: where to store the processing information
|
131
|
-
:param entry: entry process
|
132
|
-
:param configuration: configuration of the process
|
133
|
-
:param results: result of the processing
|
134
|
-
:param process_index: index of the process
|
135
|
-
:param overwrite: if True then overwrite the process if already
|
136
|
-
exists
|
137
|
-
:paramerpretations: for each result we can add a flag
|
138
|
-
'interpretation'
|
139
|
-
"""
|
140
|
-
assert process_file is not None
|
141
|
-
with FileLockerManager().get_lock(file_name=process_file):
|
142
|
-
try:
|
143
|
-
self._register_process(
|
144
|
-
process_file=process_file,
|
145
|
-
entry=entry,
|
146
|
-
process=self,
|
147
|
-
configuration=configuration,
|
148
|
-
results=results,
|
149
|
-
process_index=process_index,
|
150
|
-
interpretations=interpretations,
|
151
|
-
overwrite=overwrite,
|
152
|
-
)
|
153
|
-
except IOError as e:
|
154
|
-
_logger.error(e)
|
155
|
-
|
156
|
-
@staticmethod
|
157
|
-
def _register_process(
|
158
|
-
process_file: str,
|
159
|
-
process,
|
160
|
-
entry: str | None,
|
161
|
-
configuration: dict | None,
|
162
|
-
results: dict | None,
|
163
|
-
process_index: int,
|
164
|
-
interpretations: dict | None = None,
|
165
|
-
overwrite: bool = True,
|
166
|
-
) -> None:
|
167
|
-
"""
|
168
|
-
Store the current process in the linked h5 file if any,
|
169
|
-
output data stored will be the one defined by the data_keys
|
170
|
-
|
171
|
-
:param process: process to record
|
172
|
-
:param process_file: where to store the processing information
|
173
|
-
:param entry: entry process
|
174
|
-
:param configuration: configuration of the process
|
175
|
-
:param results: result of the processing
|
176
|
-
:param process_index: index of the process
|
177
|
-
:param overwrite: if True then overwrite the process if already
|
178
|
-
exists
|
179
|
-
:paramerpretations: for each result we can add a flag
|
180
|
-
'interpretation'
|
181
|
-
"""
|
182
|
-
assert process_file is not None, "The process file should be defined"
|
183
|
-
if interpretations is None:
|
184
|
-
interpretations = {}
|
185
|
-
process_name = "tomwer_process_" + str(process_index)
|
186
|
-
|
187
|
-
def get_process_path():
|
188
|
-
return "/".join((entry or "entry", process_name))
|
189
|
-
|
190
|
-
# save it to the file (lock should be handled upper)
|
191
|
-
with HDF5File(process_file, mode="a") as h5f:
|
192
|
-
nx_process = h5f.require_group(get_process_path())
|
193
|
-
if "NX_class" not in nx_process.attrs:
|
194
|
-
nx_process.attrs["NX_class"] = "NXprocess"
|
195
|
-
if overwrite:
|
196
|
-
for key in (
|
197
|
-
"program",
|
198
|
-
"results",
|
199
|
-
"version",
|
200
|
-
"date",
|
201
|
-
"sequence_index",
|
202
|
-
"class_instance",
|
203
|
-
"configuration",
|
204
|
-
):
|
205
|
-
if key in nx_process:
|
206
|
-
del nx_process[key]
|
207
|
-
|
208
|
-
# write process information
|
209
|
-
nx_process["program"] = process.program_name()
|
210
|
-
nx_process["version"] = process.program_version()
|
211
|
-
nx_process["date"] = datetime.now().replace(microsecond=0).isoformat()
|
212
|
-
nx_process["sequence_index"] = numpy.int32(process_index)
|
213
|
-
_class = process.__class__
|
214
|
-
nx_process["class_instance"] = ".".join(
|
215
|
-
(_class.__module__, _class.__name__)
|
216
|
-
)
|
217
|
-
|
218
|
-
# dump result
|
219
|
-
if results is not None:
|
220
|
-
h5path = "/".join((get_process_path(), "results"))
|
221
|
-
dicttoh5(
|
222
|
-
results,
|
223
|
-
h5file=process_file,
|
224
|
-
h5path=h5path,
|
225
|
-
update_mode="modify",
|
226
|
-
mode="a",
|
227
|
-
)
|
228
|
-
for interpretation_key, interpretation in interpretations.items():
|
229
|
-
try:
|
230
|
-
with HDF5File(process_file, mode="a") as h5f:
|
231
|
-
node = h5f["/".join((get_process_path(), "results"))]
|
232
|
-
node[interpretation_key].attrs[
|
233
|
-
"interpretation"
|
234
|
-
] = interpretation
|
235
|
-
except KeyError:
|
236
|
-
_logger.warning(
|
237
|
-
"Invalid interpretation - no result store"
|
238
|
-
" for %s" % interpretation_key
|
239
|
-
)
|
240
|
-
|
241
|
-
# dump configuration
|
242
|
-
if configuration is not None:
|
243
|
-
h5path = "/".join((get_process_path(), "configuration"))
|
244
|
-
dicttoh5(
|
245
|
-
configuration,
|
246
|
-
h5file=process_file,
|
247
|
-
h5path=h5path,
|
248
|
-
update_mode="modify",
|
249
|
-
mode="a",
|
250
|
-
)
|
251
|
-
|
252
|
-
with HDF5File(process_file, mode="a") as h5f:
|
253
|
-
nx_process = h5f.require_group(get_process_path())
|
254
|
-
nx_process["configuration"].attrs["NX_class"] = "NXcollection"
|
255
|
-
|
256
|
-
@staticmethod
|
257
|
-
def _get_process_nodes(
|
258
|
-
root_node: h5py.Group, process, version: str = None, depth: int = 2
|
259
|
-
) -> dict:
|
260
|
-
"""
|
261
|
-
|
262
|
-
:param root_node:
|
263
|
-
:param version: version to look for (ignored for now)
|
264
|
-
:return: list of process nodes [as h5py.Group]. Key is node name,
|
265
|
-
value is the process index
|
266
|
-
"""
|
267
|
-
|
268
|
-
def is_process_node(node):
|
269
|
-
if node is None:
|
270
|
-
return False
|
271
|
-
return (
|
272
|
-
node.name.split("/")[-1].startswith("tomwer_process_")
|
273
|
-
and "NX_class" in node.attrs
|
274
|
-
and node.attrs["NX_class"] == "NXprocess"
|
275
|
-
and "program" in node
|
276
|
-
and (
|
277
|
-
process is None
|
278
|
-
or h5py_read_dataset(node["program"]) == process.program_name()
|
279
|
-
)
|
280
|
-
and "version" in node
|
281
|
-
and "sequence_index" in node
|
282
|
-
)
|
283
|
-
|
284
|
-
if isinstance(root_node, h5py.Dataset):
|
285
|
-
return {}
|
286
|
-
res = {}
|
287
|
-
if is_process_node(root_node):
|
288
|
-
res[root_node.name] = int(h5py_read_dataset(root_node["sequence_index"]))
|
289
|
-
|
290
|
-
if root_node is not None:
|
291
|
-
for _, node in root_node.items():
|
292
|
-
if depth >= 1:
|
293
|
-
res.update(
|
294
|
-
Task._get_process_nodes(
|
295
|
-
process=process,
|
296
|
-
root_node=node,
|
297
|
-
depth=depth,
|
298
|
-
version=version,
|
299
|
-
)
|
300
|
-
)
|
301
|
-
return res
|
302
|
-
|
303
|
-
@staticmethod
|
304
|
-
def get_most_recent_process(
|
305
|
-
root_node: h5py.Group, process, version: str = None
|
306
|
-
) -> h5py.Group | None:
|
307
|
-
nodes = Task._get_process_nodes(
|
308
|
-
root_node=root_node, process=process, version=version, depth=1
|
309
|
-
)
|
310
|
-
nodes_with_time = []
|
311
|
-
nodes_time = []
|
312
|
-
import datetime
|
313
|
-
|
314
|
-
for node_name in nodes:
|
315
|
-
node = root_node[node_name]
|
316
|
-
assert isinstance(node, h5py.Group), "node should be a h5py.Group"
|
317
|
-
if "date" in node:
|
318
|
-
nodes_with_time.append(node)
|
319
|
-
nodes_time.append(
|
320
|
-
datetime.datetime.fromisoformat(h5py_read_dataset(node["date"]))
|
321
|
-
)
|
322
|
-
if len(nodes_with_time) == 0:
|
323
|
-
return None
|
324
|
-
else:
|
325
|
-
st = numpy.argmax(nodes_time)
|
326
|
-
return nodes_with_time[st]
|
327
|
-
|
328
|
-
@staticmethod
|
329
|
-
def get_processes_frm_type(process_file: str, process_type, entry=None) -> list:
|
330
|
-
"""
|
331
|
-
|
332
|
-
:param process_file: file to read
|
333
|
-
:param process_type: process type we are looking for
|
334
|
-
:return: list of _process_desc(sequence_index, configuration, results)
|
335
|
-
"""
|
336
|
-
# retrieve process to load
|
337
|
-
with open_hdf5(process_file) as h5f:
|
338
|
-
if entry is None:
|
339
|
-
if len(h5f.keys()) > 0:
|
340
|
-
root = h5f[list(h5f.keys())[0]]
|
341
|
-
else:
|
342
|
-
_logger.warning("no process find")
|
343
|
-
return []
|
344
|
-
else:
|
345
|
-
root = h5f[entry]
|
346
|
-
|
347
|
-
processes_to_load = {}
|
348
|
-
for process in root.keys():
|
349
|
-
nx_process = root[process]
|
350
|
-
if (
|
351
|
-
h5py_read_dataset(nx_process["program"])
|
352
|
-
== process_type.program_name()
|
353
|
-
):
|
354
|
-
processes_to_load[nx_process.name] = h5py_read_dataset(
|
355
|
-
nx_process["sequence_index"]
|
356
|
-
)
|
357
|
-
|
358
|
-
# load process
|
359
|
-
processes = []
|
360
|
-
for process_name, p_order in processes_to_load.items():
|
361
|
-
config = h5todict(process_file, "/".join((process_name, "configuration")))
|
362
|
-
results = h5todict(process_file, "/".join((process_name, "results")))
|
363
|
-
processes.append(
|
364
|
-
_process_desc(
|
365
|
-
process_order=p_order, configuration=config, results=results
|
366
|
-
)
|
367
|
-
)
|
368
|
-
return processes
|
369
|
-
|
370
80
|
|
371
81
|
class TaskWithProgress(_EwoksTaskWithProgress, BaseProcessInfo):
|
372
82
|
"""Class from which all tomwer process should inherit
|
@@ -146,7 +146,6 @@ class TestDarkRefEdf(unittest.TestCase):
|
|
146
146
|
self.recons_params = DKRFRP()
|
147
147
|
self.recons_params.overwrite_dark = True
|
148
148
|
self.recons_params.overwrite_ref = True
|
149
|
-
self.assertFalse(os.path.exists(self.scan.process_file))
|
150
149
|
|
151
150
|
def tearDown(self) -> None:
|
152
151
|
shutil.rmtree(self.scan_folder)
|
@@ -169,8 +168,6 @@ class TestDarkRefEdf(unittest.TestCase):
|
|
169
168
|
)
|
170
169
|
for method, th_res in zip(method_to_test, th_results):
|
171
170
|
with self.subTest(method=method):
|
172
|
-
if os.path.exists(self.scan.process_file):
|
173
|
-
os.remove(self.scan.process_file)
|
174
171
|
process = DarkRefsTask(
|
175
172
|
inputs={
|
176
173
|
"dark_ref_params": self.recons_params,
|
@@ -204,8 +201,6 @@ class TestDarkRefEdf(unittest.TestCase):
|
|
204
201
|
)
|
205
202
|
for method, th_res in zip(method_to_test, th_results):
|
206
203
|
with self.subTest(method=method):
|
207
|
-
if os.path.exists(self.scan.process_file):
|
208
|
-
os.remove(self.scan.process_file)
|
209
204
|
self.recons_params.dark_calc_method = cMethod.NONE
|
210
205
|
self.recons_params.flat_calc_method = method
|
211
206
|
process = DarkRefsTask(
|
@@ -236,7 +231,6 @@ class TestDarkRefNx(unittest.TestCase):
|
|
236
231
|
dst=self._file_path,
|
237
232
|
)
|
238
233
|
self.scan = NXtomoScan(scan=self._file_path, entry="entry0000")
|
239
|
-
self.assertFalse(os.path.exists(self.scan.process_file))
|
240
234
|
self.recons_params = DKRFRP()
|
241
235
|
self.recons_params.overwrite_dark = True
|
242
236
|
self.recons_params.overwrite_ref = True
|
@@ -26,31 +26,14 @@ def test_data_watcher_io(tmp_path, det_method):
|
|
26
26
|
scanID=str(scan_folder), nRadio=10, nRecons=1, nPagRecons=4, dim=10
|
27
27
|
)
|
28
28
|
data_watcher_process.setFolderObserved(str(tmp_path / "folder"))
|
29
|
-
data_watcher_process.clear_output_values()
|
30
29
|
data_watcher_process.set_serialize_output_data(True)
|
31
30
|
LoopThread.quitEvent.clear()
|
32
31
|
data_watcher_process.start()
|
32
|
+
time.sleep(0.5)
|
33
33
|
|
34
|
-
|
34
|
+
data_watcher_process.stop()
|
35
|
+
data_watcher_process.waitForObservationFinished()
|
36
|
+
import gc
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
-
_delta = 0.5
|
39
|
-
time.sleep(_delta)
|
40
|
-
timeout -= _delta
|
41
|
-
|
42
|
-
def quit_test():
|
43
|
-
data_watcher_process.stop()
|
44
|
-
data_watcher_process.waitForObservationFinished()
|
45
|
-
import gc
|
46
|
-
|
47
|
-
gc.collect()
|
48
|
-
LoopThread.quitEvent.clear()
|
49
|
-
|
50
|
-
if timeout <= 0:
|
51
|
-
quit_test()
|
52
|
-
raise TimeoutError("timeout expire")
|
53
|
-
|
54
|
-
out = data_watcher_process.get_output_value("data")
|
55
|
-
assert isinstance(out, dict)
|
56
|
-
quit_test()
|
38
|
+
gc.collect()
|
39
|
+
LoopThread.quitEvent.clear()
|
tomwer/core/scan/edfscan.py
CHANGED
@@ -75,8 +75,6 @@ class EDFTomoScan(_tsEDFTomoScan, TomwerScanBase):
|
|
75
75
|
self.add_reconstruction_path(self.path)
|
76
76
|
|
77
77
|
self._dark = None
|
78
|
-
self._process_file = self.get_process_file_name(self)
|
79
|
-
self._init_index_process_file(overwrite_proc_file=overwrite_proc_file)
|
80
78
|
|
81
79
|
if scan is not None and update:
|
82
80
|
try:
|
@@ -129,15 +127,6 @@ class EDFTomoScan(_tsEDFTomoScan, TomwerScanBase):
|
|
129
127
|
)
|
130
128
|
return EDFTomoScan(scan=identifier.folder)
|
131
129
|
|
132
|
-
@staticmethod
|
133
|
-
def get_process_file_name(scan):
|
134
|
-
if scan.path is not None:
|
135
|
-
basename = os.path.basename(scan.path)
|
136
|
-
basename = "_".join((basename, "tomwer_processes.h5"))
|
137
|
-
return os.path.join(scan.path, basename)
|
138
|
-
else:
|
139
|
-
return None
|
140
|
-
|
141
130
|
def clear_caches(self):
|
142
131
|
_tsEDFTomoScan.clear_caches(self)
|
143
132
|
TomwerScanBase.clear_caches(self)
|
tomwer/core/scan/nxtomoscan.py
CHANGED
@@ -101,8 +101,6 @@ class NXtomoScan(_tsNXtomoScan, TomwerScanBase):
|
|
101
101
|
|
102
102
|
self._reconstruction_urls = None
|
103
103
|
self._projections_with_angles = None
|
104
|
-
self._process_file = self.get_process_file_name(self)
|
105
|
-
self._init_index_process_file(overwrite_proc_file=overwrite_proc_file)
|
106
104
|
try:
|
107
105
|
reduced_darks, metadata = self.load_reduced_darks(return_info=True)
|
108
106
|
except (KeyError, OSError, ValueError):
|
@@ -159,16 +157,6 @@ class NXtomoScan(_tsNXtomoScan, TomwerScanBase):
|
|
159
157
|
},
|
160
158
|
)
|
161
159
|
|
162
|
-
@staticmethod
|
163
|
-
def get_process_file_name(scan):
|
164
|
-
if scan.path is not None:
|
165
|
-
basename, _ = os.path.splitext(scan.master_file)
|
166
|
-
basename = os.path.basename(basename)
|
167
|
-
basename = "_".join((basename, "tomwer_processes.h5"))
|
168
|
-
return os.path.join(scan.path, basename)
|
169
|
-
else:
|
170
|
-
return None
|
171
|
-
|
172
160
|
@staticmethod
|
173
161
|
def directory_contains_scan(directory, src_pattern=None, dest_pattern=None):
|
174
162
|
"""
|
tomwer/core/scan/scanbase.py
CHANGED
@@ -11,7 +11,6 @@ from typing import Iterable
|
|
11
11
|
import numpy
|
12
12
|
from silx.io.url import DataUrl
|
13
13
|
from silx.utils.enum import Enum as _Enum
|
14
|
-
from silx.io.utils import open as open_hdf5
|
15
14
|
|
16
15
|
from tomoscan.identifier import VolumeIdentifier
|
17
16
|
from tomoscan.normalization import IntensityNormalization
|
@@ -21,7 +20,6 @@ from tomoscan.esrf.volume.utils import guess_volumes
|
|
21
20
|
|
22
21
|
from tomwer.core.tomwer_object import TomwerObject
|
23
22
|
from tomwer.core.utils.ftseriesutils import orderFileByLastLastModification
|
24
|
-
from tomwer.core.utils.locker import FileLockerManager
|
25
23
|
from tomwer.io.utils.raw_and_processed_data import (
|
26
24
|
to_raw_data_path,
|
27
25
|
to_processed_data_path,
|
@@ -46,8 +44,6 @@ class TomwerScanBase(TomwerObject):
|
|
46
44
|
|
47
45
|
_DICT_SA_DELTA_BETA_KEYS = "sa_delta_beta_params"
|
48
46
|
|
49
|
-
_DICT_PROCESS_INDEX_KEY = "next_process_index"
|
50
|
-
|
51
47
|
_DICT_NORMALIZATION_KEY = "norm_params"
|
52
48
|
|
53
49
|
VALID_RECONS_EXTENSION = ".edf", ".npy", ".npz", ".hdf5", ".tiff", ".jp2", ".vol"
|
@@ -67,9 +63,6 @@ class TomwerScanBase(TomwerObject):
|
|
67
63
|
"""Information regarding sa_delta_beta_params"""
|
68
64
|
self._dark_ref_params = None
|
69
65
|
"""Information regarding dark - ref reconstruction"""
|
70
|
-
self._process_file = None
|
71
|
-
"""file storing processes applied on the scan, with their configuration
|
72
|
-
and result"""
|
73
66
|
self._cache_proj_urls = None
|
74
67
|
"""cache for the projection urls"""
|
75
68
|
self._cache_radio_axis = {}
|
@@ -99,26 +92,11 @@ class TomwerScanBase(TomwerObject):
|
|
99
92
|
"""
|
100
93
|
raise NotImplementedError("Base class")
|
101
94
|
|
102
|
-
def _init_index_process_file(self, overwrite_proc_file=False):
|
103
|
-
if (
|
104
|
-
not overwrite_proc_file
|
105
|
-
and self.process_file is not None
|
106
|
-
and os.path.exists(self.process_file)
|
107
|
-
):
|
108
|
-
with open_hdf5(self.process_file) as h5s:
|
109
|
-
self._process_index = len(h5s.items())
|
110
|
-
else:
|
111
|
-
self._process_index = 0
|
112
|
-
|
113
95
|
def clear_caches(self):
|
114
96
|
self._cache_proj_urls = None
|
115
97
|
self._notify_ffc_rsc_missing = True
|
116
98
|
super().clear_caches()
|
117
99
|
|
118
|
-
@staticmethod
|
119
|
-
def get_process_file_name(scan):
|
120
|
-
raise NotImplementedError("Base class")
|
121
|
-
|
122
100
|
def _flat_field_correction(
|
123
101
|
self,
|
124
102
|
data,
|
@@ -195,13 +173,6 @@ class TomwerScanBase(TomwerObject):
|
|
195
173
|
div[div == 0] = 1
|
196
174
|
return (data - dark) / div
|
197
175
|
|
198
|
-
def acquire_process_file_lock(self):
|
199
|
-
"""create a FileLocker context manager to insure safe write to the
|
200
|
-
process file"""
|
201
|
-
if self.process_file is None:
|
202
|
-
raise ValueError("No processing file defined")
|
203
|
-
return FileLockerManager().get_lock(file_name=self.process_file)
|
204
|
-
|
205
176
|
@property
|
206
177
|
def reconstructions(self):
|
207
178
|
"""list of reconstruction files"""
|
@@ -269,12 +240,6 @@ class TomwerScanBase(TomwerObject):
|
|
269
240
|
"""return parent basename of the directory containing the acquisition"""
|
270
241
|
raise NotImplementedError("Base class")
|
271
242
|
|
272
|
-
def pop_process_index(self) -> int:
|
273
|
-
"""Return and lock the next free process index"""
|
274
|
-
process_index = self._process_index
|
275
|
-
self._process_index += 1
|
276
|
-
return process_index
|
277
|
-
|
278
243
|
@functools.lru_cache(maxsize=3)
|
279
244
|
def get_opposite_projections(self, mode) -> tuple:
|
280
245
|
"""
|
@@ -340,23 +305,6 @@ class TomwerScanBase(TomwerObject):
|
|
340
305
|
"""
|
341
306
|
raise NotImplementedError("Base class")
|
342
307
|
|
343
|
-
@property
|
344
|
-
def process_file(self) -> str:
|
345
|
-
"""
|
346
|
-
|
347
|
-
:return: file used to store the processes launch by tomwer
|
348
|
-
"""
|
349
|
-
return self._process_file
|
350
|
-
|
351
|
-
@property
|
352
|
-
def process_file_url(self) -> DataUrl:
|
353
|
-
"""
|
354
|
-
|
355
|
-
:return: DataUrl of the process file
|
356
|
-
"""
|
357
|
-
entry = self.entry if hasattr(self, "entry") else "entry"
|
358
|
-
return DataUrl(file_path=self._process_file, data_path=entry, scheme="silx")
|
359
|
-
|
360
308
|
def to_dict(self):
|
361
309
|
res = {}
|
362
310
|
# nabu reconstruction parameters
|
@@ -393,8 +341,6 @@ class TomwerScanBase(TomwerObject):
|
|
393
341
|
res[self._DICT_NORMALIZATION_KEY] = None
|
394
342
|
else:
|
395
343
|
res[self._DICT_NORMALIZATION_KEY] = self.intensity_normalization.to_dict()
|
396
|
-
# process index
|
397
|
-
res[self._DICT_PROCESS_INDEX_KEY] = self._process_index
|
398
344
|
|
399
345
|
return res
|
400
346
|
|
@@ -450,8 +396,6 @@ class TomwerScanBase(TomwerObject):
|
|
450
396
|
sa_delta_beta_params
|
451
397
|
)
|
452
398
|
|
453
|
-
self._process_index = data[self._DICT_PROCESS_INDEX_KEY]
|
454
|
-
|
455
399
|
def equal(self, other):
|
456
400
|
"""
|
457
401
|
|
@@ -720,31 +664,6 @@ class TomwerScanBase(TomwerObject):
|
|
720
664
|
else:
|
721
665
|
return None
|
722
666
|
|
723
|
-
def set_process_index_frm_tomwer_process_file(self):
|
724
|
-
"""
|
725
|
-
Set the process_index to the last index find in the tomwer_process_file
|
726
|
-
+ 1
|
727
|
-
"""
|
728
|
-
from tomwer.core.process.task import Task
|
729
|
-
|
730
|
-
if os.path.exists(self.process_file):
|
731
|
-
with open_hdf5(self.process_file) as h5s:
|
732
|
-
if not hasattr(self, "entry"):
|
733
|
-
entry = "entry"
|
734
|
-
else:
|
735
|
-
entry = self.entry
|
736
|
-
if entry in h5s:
|
737
|
-
node = h5s[entry]
|
738
|
-
pn = Task._get_process_nodes(
|
739
|
-
root_node=node, process=None, version=None
|
740
|
-
)
|
741
|
-
indexes = pn.values()
|
742
|
-
if len(indexes) > 0:
|
743
|
-
self._process_index = max(indexes) + 1
|
744
|
-
logger.debug(
|
745
|
-
f"set process_index from tomwer process file to {self._process_index}"
|
746
|
-
)
|
747
|
-
|
748
667
|
def get_nabu_dataset_info(self, binning=1, binning_z=1, proj_subsampling=1) -> dict:
|
749
668
|
"""
|
750
669
|
|
@@ -180,10 +180,6 @@ class CalculationWidget(qt.QWidget):
|
|
180
180
|
return axis_mode.AxisMode.from_value(self._qcbPosition.currentText())
|
181
181
|
|
182
182
|
def setMode(self, mode: axis_mode.AxisMode):
|
183
|
-
if mode == self.getMode():
|
184
|
-
# when set mode the estimated cor might changed.
|
185
|
-
# that we want to avoid.
|
186
|
-
return
|
187
183
|
with block_signals(self._qcbPosition):
|
188
184
|
index = self._qcbPosition.findText(mode.value)
|
189
185
|
if index >= 0:
|
@@ -211,7 +207,9 @@ class CalculationWidget(qt.QWidget):
|
|
211
207
|
self._axis_params_changed()
|
212
208
|
|
213
209
|
def _axis_params_changed(self, *args, **kwargs):
|
214
|
-
self.
|
210
|
+
if self._axis_params.mode != self.getMode():
|
211
|
+
# setMode will force to update visible side. So avoid to reset it if not necessary
|
212
|
+
self.setMode(self._axis_params.mode)
|
215
213
|
|
216
214
|
def setScan(self, scan: TomwerScanBase | None):
|
217
215
|
self._estimatedCorWidget.setPixelSize(pixel_size_m=scan.x_pixel_size)
|
@@ -140,7 +140,7 @@ class TestSAAxisWindow(TestCaseQt):
|
|
140
140
|
conf = SAAxisParams.from_dict(conf)
|
141
141
|
self.assertEqual(conf.slice_indexes, "middle")
|
142
142
|
self.assertEqual(conf.file_format, "hdf5")
|
143
|
-
self.assertTrue(isinstance(conf.
|
143
|
+
self.assertTrue(isinstance(conf.nabu_recons_params, dict))
|
144
144
|
for key in (
|
145
145
|
"preproc",
|
146
146
|
"reconstruction",
|
@@ -150,7 +150,7 @@ class TestSAAxisWindow(TestCaseQt):
|
|
150
150
|
"phase",
|
151
151
|
):
|
152
152
|
with self.subTest(key=key):
|
153
|
-
self.assertTrue(key in conf.
|
153
|
+
self.assertTrue(key in conf.nabu_recons_params)
|
154
154
|
self.assertEqual(conf._dry_run, False)
|
155
155
|
self.assertEqual(conf.mode, ReconstructionMode.VERTICAL)
|
156
156
|
self.assertEqual(conf.score_method, ScoreMethod.TV_INVERSE)
|
@@ -72,7 +72,7 @@ class TestSADeltaBetaWindow(TestCaseQt):
|
|
72
72
|
# the configuration should be convertible to
|
73
73
|
conf = SADeltaBetaParams.from_dict(conf)
|
74
74
|
self.assertEqual(conf.slice_indexes, "middle")
|
75
|
-
self.assertTrue(isinstance(conf.
|
75
|
+
self.assertTrue(isinstance(conf.nabu_recons_params, dict))
|
76
76
|
for key in (
|
77
77
|
"preproc",
|
78
78
|
"reconstruction",
|
@@ -82,7 +82,7 @@ class TestSADeltaBetaWindow(TestCaseQt):
|
|
82
82
|
"phase",
|
83
83
|
):
|
84
84
|
with self.subTest(key=key):
|
85
|
-
self.assertTrue(key in conf.
|
85
|
+
self.assertTrue(key in conf.nabu_recons_params)
|
86
86
|
self.assertEqual(conf._dry_run, False)
|
87
87
|
self.assertEqual(conf.score_method, ScoreMethod.TV_INVERSE)
|
88
88
|
self.assertEqual(conf.output_dir, None)
|
@@ -119,6 +119,8 @@ class StitcherAxisParams(qt.QWidget):
|
|
119
119
|
for option in options:
|
120
120
|
clean_option = option.rstrip(" ").lstrip(" ")
|
121
121
|
opt_name, opt_value = clean_option.split("=")
|
122
|
+
if opt_value == "":
|
123
|
+
continue
|
122
124
|
if opt_name == stitching_config.KEY_IMG_REG_METHOD:
|
123
125
|
self.setShiftSearchMethod(opt_value)
|
124
126
|
elif opt_name == stitching_config.KEY_WINDOW_SIZE:
|