nabu 2024.2.0rc1__py3-none-any.whl → 2024.2.0rc3__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.
nabu/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "2024.2.0-rc1"
1
+ __version__ = "2024.2.0-rc3"
2
2
  __nabu_modules__ = [
3
3
  "app",
4
4
  "cuda",
nabu/estimation/cor.py CHANGED
@@ -1114,11 +1114,6 @@ class CenterOfRotationOctaveAccurate(CenterOfRotation):
1114
1114
  # ---
1115
1115
  self._check_img_pair_sizes(img_1, img_2)
1116
1116
 
1117
- if side != "center":
1118
- msg = "This method cannot handle half acquisition"
1119
- self.logger.fatal(msg)
1120
- raise ValueError(msg)
1121
-
1122
1117
  img_shape = img_2.shape
1123
1118
  roi_yxhw = self._determine_roi(img_shape, roi_yxhw)
1124
1119
 
@@ -91,7 +91,7 @@ class SinoCor:
91
91
  imax = i
92
92
  self.cor_abs = self.sx - (imax + window_width + 1.0) / 2.0
93
93
  self.cor_rel = self.sx / 2 - (imax + window_width + 1.0) / 2.0
94
- else:
94
+ elif side == "left":
95
95
  for i in nr:
96
96
  imout = self.data1[:, i : i + window_width] - self.data2[:, self.sx - window_width : self.sx]
97
97
  diff = imout.max() - imout.min()
@@ -100,6 +100,8 @@ class SinoCor:
100
100
  imax = i
101
101
  self.cor_abs = (imax + window_width - 1.0) / 2
102
102
  self.cor_rel = self.cor_abs - self.sx / 2.0 - 1
103
+ else:
104
+ raise ValueError(f"Invalid side given ({side}). should be 'left' or 'right'")
103
105
  if imax < 1:
104
106
  self.logger.warning("sliding width %d seems too large!" % window_width)
105
107
  self.rcor_abs = round(self.cor_abs)
@@ -31,6 +31,21 @@ from .params import cor_methods, tilt_methods
31
31
 
32
32
 
33
33
  def estimate_cor(method, dataset_info, do_flatfield=True, cor_options=None, logger=None):
34
+ """
35
+ High level function to compute the center of rotation (COR)
36
+
37
+ Parameters
38
+ ----------
39
+ method: name of the method to be used for computing the center of rotation
40
+ dataset_info: `nabu.resources.dataset_analyzer.DatasetAnalyzer`
41
+ Dataset information structure
42
+ do_flatfield: If True apply flat field to compute the center of rotation
43
+ cor_options: optional dictionary that can contain the following keys:
44
+ * slice_idx: index of the slice to use for computing the sinogram (for sinogram based algorithms)
45
+ * subsampling subsampling
46
+ * radio_angles: angles of the radios to use (for radio based algorithms)
47
+ logger: logging object
48
+ """
34
49
  logger = LoggerOrPrint(logger)
35
50
  cor_options = cor_options or {}
36
51
  check_supported(method, list(cor_methods.keys()), "COR estimation method")
@@ -56,6 +71,7 @@ def estimate_cor(method, dataset_info, do_flatfield=True, cor_options=None, logg
56
71
  dataset_info,
57
72
  do_flatfield=do_flatfield,
58
73
  cor_options=cor_options,
74
+ radio_angles=cor_options.get("radio_angles", (0.0, np.pi)),
59
75
  logger=logger,
60
76
  )
61
77
  estimated_cor = cor_finder.find_cor()
@@ -66,6 +82,7 @@ def estimate_cor(method, dataset_info, do_flatfield=True, cor_options=None, logg
66
82
  slice_idx=cor_options.get("slice_idx", "middle"),
67
83
  subsampling=cor_options.get("subsampling", 10),
68
84
  do_flatfield=do_flatfield,
85
+ take_log=cor_options.get("take_log", True),
69
86
  cor_options=cor_options,
70
87
  logger=logger,
71
88
  )
@@ -180,6 +197,12 @@ class CORFinder(CORFinderBase):
180
197
  self._init_radios()
181
198
  self._apply_flatfield()
182
199
  self._apply_tilt()
200
+ # octave-accurate does not support half-acquisition scans,
201
+ # but information on field of view is only known here with the "dataset_info" object.
202
+ # Do the check here.
203
+ if self.dataset_info.is_halftomo and method == "octave-accurate":
204
+ raise ValueError("The CoR estimator 'octave-accurate' does not support half-acquisition scans")
205
+ #
183
206
 
184
207
  def _init_radios(self):
185
208
  self.radios, self._radios_indices = get_radio_pair(
@@ -220,6 +243,13 @@ class CORFinder(CORFinderBase):
220
243
  # All find_shift() methods in self.search_methods have the same API with "img_1" and "img_2"
221
244
  cor_exec_kwargs = update_func_kwargs(self.cor_finder.find_shift, self.cor_options)
222
245
  cor_exec_kwargs["return_relative_to_middle"] = False
246
+ # FIXME
247
+ # 'self.cor_options' can contain 'side="from_file"', and we should not modify it directly
248
+ # because it's entered by the user.
249
+ # Either make a copy of self.cor_options, or change the inspect() mechanism
250
+ if cor_exec_kwargs["side"] == "from_file":
251
+ cor_exec_kwargs["side"] = self._lookup_side or "center"
252
+ #
223
253
  if self._lookup_side is not None:
224
254
  cor_exec_kwargs["side"] = self._lookup_side
225
255
  self.logger.debug("%s.find_shift(%s)" % (self.cor_finder.__class__.__name__, str(cor_exec_kwargs)))
@@ -359,7 +389,13 @@ class SinoCORFinder(CORFinderBase):
359
389
 
360
390
  cor_exec_kwargs = update_func_kwargs(self.cor_finder.find_shift, self.cor_options)
361
391
  cor_exec_kwargs["return_relative_to_middle"] = False
362
-
392
+ # FIXME
393
+ # 'self.cor_options' can contain 'side="from_file"', and we should not modify it directly
394
+ # because it's entered by the user.
395
+ # Either make a copy of self.cor_options, or change the inspect() mechanism
396
+ if cor_exec_kwargs["side"] == "from_file":
397
+ cor_exec_kwargs["side"] = self._lookup_side or "center"
398
+ #
363
399
  if self._lookup_side is not None:
364
400
  cor_exec_kwargs["side"] = self._lookup_side
365
401
 
@@ -454,7 +490,7 @@ class CompositeCORFinder(CORFinderBase):
454
490
  if (self.angle_max - self.angle_min) < 1.2 * np.pi:
455
491
  useful_span = None
456
492
  raise ValueError(
457
- f"""Sinogram-based Center of Rotation estimation can only be used for scans over more than 180 degrees.
493
+ f"""Sinogram-based Center of Rotation estimation can only be used for scans over more than 180 degrees.
458
494
  Your angular span was barely above 180 degrees, it was in fact {((self.angle_max - self.angle_min)/np.pi):.2f} x 180
459
495
  and it is not considered to be enough by the discriminating condition which requires at least 1.2 half-turns
460
496
  """
@@ -84,13 +84,17 @@ class TestCorNearPos:
84
84
 
85
85
  def test_cor_fourier_angles_standard(self):
86
86
  cor_options = extract_parameters(self.conf_std["reconstruction"].get("cor_options", None), sep=";")
87
+ # TODO modify test files
88
+ if "near_pos" in cor_options and "near" in cor_options.get("side", "") == "near":
89
+ cor_options["side"] = cor_options["near_pos"]
90
+ #
87
91
  for side in [None, "from_file", "center"]:
88
92
  if side is not None:
89
93
  cor_options.update({"side": side})
90
94
  finder = SinoCORFinder("fourier-angles", self.ds_std, do_flatfield=True, cor_options=cor_options)
91
95
  cor = finder.find_cor()
92
96
  message = f"Computed CoR {cor} and expected CoR {self.true_cor} do not coincide. Near_pos options was set to {cor_options.get('near_pos',None)}."
93
- assert np.isclose(self.true_cor, cor, atol=self.abs_tol), message
97
+ assert np.isclose(self.true_cor + 0.5, cor, atol=self.abs_tol), message
94
98
 
95
99
  def test_cor_sliding_bliss(self):
96
100
  cor_options = extract_parameters(self.conf_bliss["reconstruction"].get("cor_options", None), sep=";")
@@ -114,4 +118,4 @@ class TestCorNearPos:
114
118
  finder = SinoCORFinder("fourier-angles", self.ds_bliss, do_flatfield=True, cor_options=cor_options)
115
119
  cor = finder.find_cor()
116
120
  message = f"Computed CoR {cor} and expected CoR {self.true_cor} do not coincide. Near_pos options was set to {cor_options.get('near_pos',None)}."
117
- assert np.isclose(self.true_cor, cor, atol=self.abs_tol), message
121
+ assert np.isclose(self.true_cor + 0.5, cor, atol=self.abs_tol), message
@@ -302,7 +302,7 @@ class EDFDatasetAnalyzer(DatasetAnalyzer):
302
302
  return np.deg2rad(self.dataset_scanner.rotation_angle())
303
303
 
304
304
  def get_reduced_flats(self, **reader_kwargs):
305
- if self.flats in [None, {}]:
305
+ if self.raw_flats in [None, {}]:
306
306
  raise FileNotFoundError("No reduced flat ('refHST') found in %s" % self.location)
307
307
  # A few notes:
308
308
  # (1) In principle we could do the reduction (mean/median) from raw frames (ref_xxxx_yyyy)
@@ -311,15 +311,15 @@ class EDFDatasetAnalyzer(DatasetAnalyzer):
311
311
  # (eg. subsampling, binning, distortion correction...)
312
312
  # (3) The following spawns one reader instance per file, which is not elegant,
313
313
  # but in principle there are typically 1-2 reduced flats in a scan
314
- readers = {k: EDFStackReader([self.flats[k].file_path()], **reader_kwargs) for k in self.flats.keys()}
315
- return {k: readers[k].load_data()[0] for k in self.flats.keys()}
314
+ readers = {k: EDFStackReader([self.raw_flats[k].file_path()], **reader_kwargs) for k in self.raw_flats.keys()}
315
+ return {k: readers[k].load_data()[0] for k in self.raw_flats.keys()}
316
316
 
317
317
  def get_reduced_darks(self, **reader_kwargs):
318
318
  # See notes in get_reduced_flats() above
319
- if self.darks in [None, {}]:
319
+ if self.raw_darks in [None, {}]:
320
320
  raise FileNotFoundError("No reduced dark ('darkend.edf' or 'dark.edf') found in %s" % self.location)
321
- readers = {k: EDFStackReader([self.darks[k].file_path()], **reader_kwargs) for k in self.darks.keys()}
322
- return {k: readers[k].load_data()[0] for k in self.darks.keys()}
321
+ readers = {k: EDFStackReader([self.raw_darks[k].file_path()], **reader_kwargs) for k in self.raw_darks.keys()}
322
+ return {k: readers[k].load_data()[0] for k in self.raw_darks.keys()}
323
323
 
324
324
  @property
325
325
  def files(self):
@@ -365,10 +365,10 @@ class HDF5DatasetAnalyzer(DatasetAnalyzer):
365
365
  def _get_dataset_hdf5_url(self):
366
366
  if len(self.projections) > 0:
367
367
  frames_to_take = self.projections
368
- elif len(self.flats) > 0:
369
- frames_to_take = self.flats
370
- elif len(self.darks) > 0:
371
- frames_to_take = self.darks
368
+ elif len(self.raw_flats) > 0:
369
+ frames_to_take = self.raw_flats
370
+ elif len(self.raw_darks) > 0:
371
+ frames_to_take = self.raw_darks
372
372
  else:
373
373
  raise ValueError("No projections, no flats and no darks ?!")
374
374
  first_proj_idx = sorted(frames_to_take.keys())[0]
@@ -409,8 +409,13 @@ class HDF5DatasetAnalyzer(DatasetAnalyzer):
409
409
  slices: list of slice
410
410
  A list where each item is a slice.
411
411
  """
412
- check_supported(what, ["projections", "flats", "darks"], "image type")
413
- images = getattr(self, what) # dict
412
+ name_to_attr = {
413
+ "projections": self.projections,
414
+ "flats": self.raw_flats,
415
+ "darks": self.raw_darks,
416
+ }
417
+ check_supported(what, name_to_attr.keys(), "image type")
418
+ images = name_to_attr[what] # dict
414
419
  # we can't directly use set() on slice() object (unhashable). Use tuples
415
420
  slices = set()
416
421
  for du in get_compacted_dataslices(images).values():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nabu
3
- Version: 2024.2.0rc1
3
+ Version: 2024.2.0rc3
4
4
  Summary: Nabu - Tomography software
5
5
  Author-email: Pierre Paleo <pierre.paleo@esrf.fr>, Henri Payno <henri.payno@esrf.fr>, Alessandro Mirone <mirone@esrf.fr>, Jérôme Lesaint <jerome.lesaint@esrf.fr>
6
6
  Maintainer-email: Pierre Paleo <pierre.paleo@esrf.fr>
@@ -53,7 +53,7 @@ Requires-Dist: numpy <2,>1.9.0
53
53
  Requires-Dist: scipy
54
54
  Requires-Dist: h5py >=3.0
55
55
  Requires-Dist: silx >=0.15.0
56
- Requires-Dist: tomoscan >=2.1.0a14
56
+ Requires-Dist: tomoscan >=2.1.0
57
57
  Requires-Dist: psutil
58
58
  Requires-Dist: pytest
59
59
  Requires-Dist: tifffile
@@ -1,7 +1,7 @@
1
1
  doc/conf.py,sha256=3xtCarCHrXPr50GbeRDuH-o3Jzojw7mpr7vpGfZPLAE,3787
2
2
  doc/create_conf_doc.py,sha256=IVOdP70KvbW9WS_UQu3Iyd0YfS60E2fJ5IDtQ_s4cDw,1143
3
3
  doc/get_mathjax.py,sha256=VIvKRCdDuF2VoY8JD3mSey9XX13AZMmwTJBHdt1tUs4,1012
4
- nabu/__init__.py,sha256=IjlfSehTIFckwK0pXQs5uRXr89VhP7Fm7q30c7f4tFk,274
4
+ nabu/__init__.py,sha256=nj3TOWBu8oPUoBNHU2H_cND8gzxtol3hSVTR0ewGpTM,274
5
5
  nabu/tests.py,sha256=cew9OY2uTyncHI_HM32W8CP6B1GTGKaOW65XtMEqs7o,1417
6
6
  nabu/testutils.py,sha256=VkSL9tbY0XEH49Z5OjDFFhzkSxrCv4UIuvSVFgegSUY,7632
7
7
  nabu/utils.py,sha256=V1B_sD54XGNKn5pORa2yNCATyswOzybey3sv8BuIYWY,26355
@@ -64,8 +64,8 @@ nabu/cuda/src/transpose.cu,sha256=Enim7vLxTCFZbK3BmYdQ6ZatA_FLp6601VOSl8iGFjg,47
64
64
  nabu/cuda/tests/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
65
65
  nabu/estimation/__init__.py,sha256=HWE3ivArjlJx4FjFh2Q73VmpIyzod80KTmXvFo1AP1s,379
66
66
  nabu/estimation/alignment.py,sha256=DWe4PBLsAOt95m_UEinVXUhXyYDmV0NOHW-oHpVEjVk,21185
67
- nabu/estimation/cor.py,sha256=Vdrne_fyvOlJuuBHpxmJLZbgPa6jx4VUqM-_91KtD5U,50577
68
- nabu/estimation/cor_sino.py,sha256=ArVpZeCPsGwo8PR63MUBonel6U5s7TK_S2jU_qPLV1M,18997
67
+ nabu/estimation/cor.py,sha256=b8dv047g8AYL9mV6vAAkIloSgNeN3w2bozZY1ox7bII,50415
68
+ nabu/estimation/cor_sino.py,sha256=Wh0t8Ak6h8kf3rn5azD1XqD4e0Xa90oZUy90n9Ory8c,19116
69
69
  nabu/estimation/distortion.py,sha256=DEXizQpgHBXmrhbQ0kuEchicxmiDgmU2qrh8bCgSezg,4701
70
70
  nabu/estimation/focus.py,sha256=I2B5ODmGToE0-Y-B_6v1zJv7XcWdkXPZzrs2uYpiPlc,18029
71
71
  nabu/estimation/tilt.py,sha256=AaBBOzM2bVlScphCdORbfEi_mJjyuwkYvvDmr2Fosvg,8723
@@ -131,7 +131,7 @@ nabu/pipeline/config_validators.py,sha256=ocAKB26iRjm5qs1Ay4B_rgGcg8aZjAP34XpEZR
131
131
  nabu/pipeline/datadump.py,sha256=lK36YlsVSeE4fdkD7cgVCl4RKn-Wa9KYgOw4DNtH8Ow,6982
132
132
  nabu/pipeline/dataset_validator.py,sha256=etQw9NC_YGsdWCgjsn8aJ3WfvcRuJlLVZlWoqhvvo-8,9263
133
133
  nabu/pipeline/detector_distortion_provider.py,sha256=ru1AxbcuO-FA8FYooPBWgp1lzdSDUtzFUC1A_sS8jME,920
134
- nabu/pipeline/estimators.py,sha256=x2SLCDrpLFAmyDN6YNEmhfTdnEZIp92Odu2bhnweq6U,38324
134
+ nabu/pipeline/estimators.py,sha256=a-6ISR6ii8J7xMvr6oKFJO8yMFT_QzO7L5kMcg4RJmw,40269
135
135
  nabu/pipeline/params.py,sha256=EoovjCUTUXmj5HQ3qE0RhP7XD3cndaiT21TdvjTIhE8,3746
136
136
  nabu/pipeline/processconfig.py,sha256=3xx2Lc8uEzPAqSMwUncr4RCiCtKn2c7wnXXbPSn8GNo,7719
137
137
  nabu/pipeline/reader.py,sha256=wkxPHYOi_C8dHNc7kddB8AMtFuW7GjsP_tm6SJeHlEY,4792
@@ -159,7 +159,7 @@ nabu/pipeline/helical/processconfig.py,sha256=IlCfKkiclBmDDdT6Ail3aSj9Q7zV38YpFm
159
159
  nabu/pipeline/helical/span_strategy.py,sha256=7zV_Oo_liFiuv6m70o08XyoEIo_7QYs7MV7qtHFTgbc,25044
160
160
  nabu/pipeline/helical/weight_balancer.py,sha256=j0TGe50tbbsilQvml9CgMxeSy83CNaifHj-xuMGl8uE,3981
161
161
  nabu/pipeline/helical/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
162
- nabu/pipeline/tests/test_estimators.py,sha256=kU7R90b5dFMvXMzX8TsAGV61QKUzvws4kkMR_nEdlJs,5943
162
+ nabu/pipeline/tests/test_estimators.py,sha256=usi2Rp0zry5ADJV9k8nHhCqdDBSuHguZvyH-jkg-F48,6146
163
163
  nabu/pipeline/xrdct/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
164
164
  nabu/preproc/__init__.py,sha256=dKxvZvWZXjKS3iPRaSXiUeM2dNGIOyTlirq5pdAWY0Y,284
165
165
  nabu/preproc/alignment.py,sha256=WDSPIlogwPfQDTqEyRH_ovaQ7vCpnR6XE_Ycif1wP0I,379
@@ -250,7 +250,7 @@ nabu/reconstruction/tests/test_reconstructor.py,sha256=3p2Wk_OqgZqkNOkhK_NJWlHkO
250
250
  nabu/reconstruction/tests/test_sino_normalization.py,sha256=fGv5Dlidxgm8ZC70Nk6oqVgpY2jzOW9NJaGlo44IJOo,3692
251
251
  nabu/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
252
252
  nabu/resources/cor.py,sha256=-mcrTbj3G7o4PP5E_gIRo2j6_-ADmMkkOc_0CyQv84c,170
253
- nabu/resources/dataset_analyzer.py,sha256=BSU03X-G8dBt_82OrNu83GYKL9Aj0hVD_JGPzbYpYeo,18379
253
+ nabu/resources/dataset_analyzer.py,sha256=I79-QEFrWG7Zc6O6134sLfNpj3_VmAei-1Io-zuPCts,18566
254
254
  nabu/resources/gpu.py,sha256=GgpMb5umRQAUsEDEAefb4wSA5qm4JSMhkWmCEpW3X9g,5702
255
255
  nabu/resources/logger.py,sha256=-lOzhN_sU4R3BIfC69aMj2O8S_ocsvXsmwkhWlcxVEc,3758
256
256
  nabu/resources/nxflatfield.py,sha256=XlhLYj1TmSQ4s36W48kn0lNTvqXlFCuZxKHfTveltow,9225
@@ -311,9 +311,9 @@ nabu/thirdparty/pore3d_deringer_munch.py,sha256=o4bisnFc-wMjuohWBT8wgWmfNehPQGtC
311
311
  nabu/thirdparty/tomocupy_remove_stripe.py,sha256=Khe4zFf0kRzu65Yxnvq58gt1ljOztqJGdMDhVAiM7lM,24363
312
312
  nabu/thirdparty/tomopy_phase.py,sha256=hK4oPpkogLOhv23XzzEXQY2u3r8fJvASY_bINVs6ERE,8634
313
313
  nabu/thirdparty/tomwer_load_flats_darks.py,sha256=ZNoVAinUb_wGYbfvs_4BVnWsjsQmNxSvCh1bWhR2WWg,5611
314
- nabu-2024.2.0rc1.dist-info/LICENSE,sha256=1eAIPSnEsnSFNUODnLtNtQTs76exG3ZxJ1DJR6zoUBA,1066
315
- nabu-2024.2.0rc1.dist-info/METADATA,sha256=bGcyrOw9Xc9slZP_dMGa8JCNBlrwvSzNXpv4kenxTPY,5544
316
- nabu-2024.2.0rc1.dist-info/WHEEL,sha256=5sUXSg9e4bi7lTLOHcm6QEYwO5TIF1TNbTSVFVjcJcc,92
317
- nabu-2024.2.0rc1.dist-info/entry_points.txt,sha256=cJKGkBeykVL7uK3E4R0RLRqMXifTL2qdO573syPAvJc,1288
318
- nabu-2024.2.0rc1.dist-info/top_level.txt,sha256=fsm_N3eXLRZk2QXF9OSKPNDPFXOz8FAQjHh5avT3dok,9
319
- nabu-2024.2.0rc1.dist-info/RECORD,,
314
+ nabu-2024.2.0rc3.dist-info/LICENSE,sha256=1eAIPSnEsnSFNUODnLtNtQTs76exG3ZxJ1DJR6zoUBA,1066
315
+ nabu-2024.2.0rc3.dist-info/METADATA,sha256=DtswpBFRHCRI-w--UzSZ9Mp1Zc8R-xBjBfcCYRzCJPs,5541
316
+ nabu-2024.2.0rc3.dist-info/WHEEL,sha256=5sUXSg9e4bi7lTLOHcm6QEYwO5TIF1TNbTSVFVjcJcc,92
317
+ nabu-2024.2.0rc3.dist-info/entry_points.txt,sha256=cJKGkBeykVL7uK3E4R0RLRqMXifTL2qdO573syPAvJc,1288
318
+ nabu-2024.2.0rc3.dist-info/top_level.txt,sha256=fsm_N3eXLRZk2QXF9OSKPNDPFXOz8FAQjHh5avT3dok,9
319
+ nabu-2024.2.0rc3.dist-info/RECORD,,