httomolibgpu 3.1.1__tar.gz → 5.0__tar.gz

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 (36) hide show
  1. {httomolibgpu-3.1.1/httomolibgpu.egg-info → httomolibgpu-5.0}/PKG-INFO +1 -1
  2. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/__init__.py +4 -2
  3. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/misc/corr.py +0 -6
  4. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/misc/denoise.py +0 -6
  5. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/misc/morph.py +0 -6
  6. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/misc/rescale.py +0 -4
  7. httomolibgpu-5.0/httomolibgpu/misc/utils.py +146 -0
  8. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/prep/alignment.py +0 -6
  9. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/prep/normalize.py +22 -31
  10. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/prep/phase.py +72 -57
  11. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/prep/stripe.py +0 -8
  12. httomolibgpu-5.0/httomolibgpu/recon/_phase_cross_correlation.py +418 -0
  13. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/recon/algorithm.py +11 -65
  14. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/recon/rotation.py +27 -11
  15. {httomolibgpu-3.1.1 → httomolibgpu-5.0/httomolibgpu.egg-info}/PKG-INFO +1 -1
  16. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu.egg-info/SOURCES.txt +2 -1
  17. httomolibgpu-3.1.1/httomolibgpu/misc/supp_func.py +0 -192
  18. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/LICENSE +0 -0
  19. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/MANIFEST.in +0 -0
  20. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/README.rst +0 -0
  21. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/cuda_kernels/__init__.py +0 -0
  22. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/cuda_kernels/calc_metrics.cu +0 -0
  23. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/cuda_kernels/center_360_shifts.cu +0 -0
  24. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/cuda_kernels/generate_mask.cu +0 -0
  25. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/cuda_kernels/median_kernel.cu +0 -0
  26. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/cuda_kernels/raven_filter.cu +0 -0
  27. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/cuda_kernels/remove_nan_inf.cu +0 -0
  28. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/cupywrapper.py +0 -0
  29. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/misc/__init__.py +0 -0
  30. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/prep/__init__.py +0 -0
  31. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu/recon/__init__.py +0 -0
  32. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu.egg-info/dependency_links.txt +0 -0
  33. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu.egg-info/requires.txt +0 -0
  34. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/httomolibgpu.egg-info/top_level.txt +0 -0
  35. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/pyproject.toml +0 -0
  36. {httomolibgpu-3.1.1 → httomolibgpu-5.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: httomolibgpu
3
- Version: 3.1.1
3
+ Version: 5.0
4
4
  Summary: Commonly used tomography data processing methods at DLS.
5
5
  Author-email: Daniil Kazantsev <daniil.kazantsev@diamond.ac.uk>, Yousef Moazzam <yousef.moazzam@diamond.ac.uk>, Naman Gera <naman.gera@diamond.ac.uk>
6
6
  License: BSD-3-Clause
@@ -1,10 +1,12 @@
1
+ from httomolibgpu.misc.utils import data_checker
2
+
1
3
  from httomolibgpu.misc.corr import median_filter, remove_outlier
2
4
  from httomolibgpu.misc.denoise import total_variation_ROF, total_variation_PD
3
5
  from httomolibgpu.misc.morph import sino_360_to_180, data_resampler
4
6
  from httomolibgpu.misc.rescale import rescale_to_int
5
7
  from httomolibgpu.prep.alignment import distortion_correction_proj_discorpy
6
- from httomolibgpu.prep.normalize import normalize
7
- from httomolibgpu.prep.phase import paganin_filter_tomopy
8
+ from httomolibgpu.prep.normalize import dark_flat_field_correction, minus_log
9
+ from httomolibgpu.prep.phase import paganin_filter, paganin_filter_savu_legacy
8
10
  from httomolibgpu.prep.stripe import (
9
11
  remove_stripe_based_sorting,
10
12
  remove_stripe_ti,
@@ -36,8 +36,6 @@ if cupy_run:
36
36
  else:
37
37
  load_cuda_module = Mock()
38
38
 
39
- from httomolibgpu.misc.supp_func import data_checker
40
-
41
39
  __all__ = [
42
40
  "median_filter",
43
41
  "remove_outlier",
@@ -82,10 +80,6 @@ def median_filter(
82
80
  else:
83
81
  raise ValueError("The input array must be a 3D array")
84
82
 
85
- data = data_checker(
86
- data, verbosity=True, method_name="median_filter_or_remove_outlier"
87
- )
88
-
89
83
  if kernel_size not in [3, 5, 7, 9, 11, 13]:
90
84
  raise ValueError("Please select a correct kernel size: 3, 5, 7, 9, 11, 13")
91
85
 
@@ -29,8 +29,6 @@ cupy_run = cupywrapper.cupy_run
29
29
 
30
30
  from unittest.mock import Mock
31
31
 
32
- from httomolibgpu.misc.supp_func import data_checker
33
-
34
32
  if cupy_run:
35
33
  from tomobar.regularisersCuPy import ROF_TV_cupy, PD_TV_cupy
36
34
  else:
@@ -84,8 +82,6 @@ def total_variation_ROF(
84
82
  If the input array is not float32 data type.
85
83
  """
86
84
 
87
- data = data_checker(data, verbosity=True, method_name="total_variation_ROF")
88
-
89
85
  return ROF_TV_cupy(
90
86
  data,
91
87
  regularisation_parameter,
@@ -139,8 +135,6 @@ def total_variation_PD(
139
135
  If the input array is not float32 data type.
140
136
  """
141
137
 
142
- data_checker(data, verbosity=True, method_name="total_variation_PD")
143
-
144
138
  methodTV = 0
145
139
  if not isotropic:
146
140
  methodTV = 1
@@ -35,8 +35,6 @@ else:
35
35
 
36
36
  from typing import Literal
37
37
 
38
- from httomolibgpu.misc.supp_func import data_checker
39
-
40
38
  __all__ = [
41
39
  "sino_360_to_180",
42
40
  "data_resampler",
@@ -68,8 +66,6 @@ def sino_360_to_180(
68
66
  if data.ndim != 3:
69
67
  raise ValueError("only 3D data is supported")
70
68
 
71
- data = data_checker(data, verbosity=True, method_name="sino_360_to_180")
72
-
73
69
  dx, dy, dz = data.shape
74
70
 
75
71
  overlap = int(np.round(overlap))
@@ -142,8 +138,6 @@ def data_resampler(
142
138
  data = cp.expand_dims(data, 1)
143
139
  axis = 1
144
140
 
145
- data = data_checker(data, verbosity=True, method_name="data_resampler")
146
-
147
141
  N, M, Z = cp.shape(data)
148
142
 
149
143
  if axis == 0:
@@ -27,8 +27,6 @@ cp = cupywrapper.cp
27
27
 
28
28
  from typing import Literal, Optional, Tuple, Union
29
29
 
30
- from httomolibgpu.misc.supp_func import data_checker
31
-
32
30
 
33
31
  __all__ = [
34
32
  "rescale_to_int",
@@ -80,8 +78,6 @@ def rescale_to_int(
80
78
  else:
81
79
  output_dtype = np.uint32
82
80
 
83
- data = data_checker(data, verbosity=True, method_name="rescale_to_int")
84
-
85
81
  # get the min and max integer values of the output type
86
82
  output_min = cp.iinfo(output_dtype).min
87
83
  output_max = cp.iinfo(output_dtype).max
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ---------------------------------------------------------------------------
4
+ # Copyright 2022 Diamond Light Source Ltd.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ---------------------------------------------------------------------------
18
+ # Created By : Tomography Team at DLS <scientificsoftware@diamond.ac.uk>
19
+ # Created Date: 02/June/2025
20
+ # ---------------------------------------------------------------------------
21
+ """Various utilities for data inspection and correction"""
22
+
23
+ from httomolibgpu import cupywrapper
24
+ from typing import Optional
25
+
26
+ cp = cupywrapper.cp
27
+ cupy_run = cupywrapper.cupy_run
28
+
29
+ from unittest.mock import Mock
30
+
31
+ if cupy_run:
32
+ from httomolibgpu.cuda_kernels import load_cuda_module
33
+ else:
34
+ load_cuda_module = Mock()
35
+
36
+
37
+ __all__ = [
38
+ "data_checker",
39
+ ]
40
+
41
+
42
+ def data_checker(
43
+ data: cp.ndarray,
44
+ infsnans_correct: bool = True,
45
+ zeros_warning: bool = False,
46
+ data_to_method_name: Optional[str] = None,
47
+ verbosity: bool = True,
48
+ ) -> cp.ndarray:
49
+ """Function that performs checks on input data to ensure its validity, performs corrections and prints the warnings.
50
+ Currently it checks for the presence of Infs and NaNs in the data and corrects them.
51
+
52
+ Parameters
53
+ ----------
54
+ data : cp.ndarray
55
+ CuPy array either float32 or uint16 data type.
56
+ infsnans_correct: bool
57
+ Perform correction of NaNs and Infs if they are present in the data.
58
+ zeros_warning: bool
59
+ Count the number of zeros in the data and produce a warning if more half of the data are zeros.
60
+ verbosity : bool
61
+ Print the warnings.
62
+ data_to_method_name : str, optional.
63
+ Method's name the output of which is tested. This is tailored for printing purposes when the method runs in HTTomo.
64
+
65
+ Returns
66
+ -------
67
+ cp.ndarray
68
+ Returns corrected CuPy array.
69
+ """
70
+ if data.dtype not in ["uint16", "float32"]:
71
+ raise ValueError(
72
+ "The input data of `uint16` and `float32` data types is accepted only."
73
+ )
74
+
75
+ if infsnans_correct:
76
+ data = __naninfs_check(
77
+ data, verbosity=verbosity, method_name=data_to_method_name
78
+ )
79
+ # TODO
80
+ # if zeros_warning:
81
+ # __zeros_check(data, verbosity=verbosity, percentage_threshold = 50, method_name=data_to_method_name)
82
+
83
+ return data
84
+
85
+
86
+ def __naninfs_check(
87
+ data: cp.ndarray,
88
+ verbosity: bool = True,
89
+ method_name: Optional[str] = None,
90
+ ) -> cp.ndarray:
91
+ """
92
+ This function finds NaN's, +-Inf's in the input data and then prints the warnings and correct the data if correction is enabled.
93
+
94
+ Parameters
95
+ ----------
96
+ data : cp.ndarray
97
+ Input CuPy or Numpy array either float32 or uint16 data type.
98
+ verbosity : bool
99
+ If enabled, then the printing of the warning happens when data contains infs or nans
100
+ method_name : str, optional.
101
+ Method's name for which the output data is tested.
102
+
103
+ Returns
104
+ -------
105
+ ndarray
106
+ Uncorrected or corrected (nans and infs converted to zeros) input array.
107
+ """
108
+ present_nans_infs_b = False
109
+
110
+ input_type = data.dtype
111
+ if len(data.shape) == 2:
112
+ dy, dx = data.shape
113
+ dz = 1
114
+ else:
115
+ dz, dy, dx = data.shape
116
+
117
+ present_nans_infs = cp.zeros(shape=(1)).astype(cp.uint8)
118
+
119
+ block_x = 128
120
+ # setting grid/block parameters
121
+ block_dims = (block_x, 1, 1)
122
+ grid_x = (dx + block_x - 1) // block_x
123
+ grid_y = dy
124
+ grid_z = dz
125
+ grid_dims = (grid_x, grid_y, grid_z)
126
+ params = (data, dz, dy, dx, present_nans_infs)
127
+
128
+ kernel_args = "remove_nan_inf<{0}>".format(
129
+ "float" if input_type == "float32" else "unsigned short"
130
+ )
131
+
132
+ module = load_cuda_module("remove_nan_inf", name_expressions=[kernel_args])
133
+ remove_nan_inf_kernel = module.get_function(kernel_args)
134
+ remove_nan_inf_kernel(grid_dims, block_dims, params)
135
+
136
+ if present_nans_infs[0].get() == 1:
137
+ present_nans_infs_b = True
138
+
139
+ if present_nans_infs_b:
140
+ if verbosity:
141
+ print(
142
+ "Warning! Output data of the \033[31m{}\033[0m method contains Inf's or/and NaN's. Corrected to zeros.".format(
143
+ method_name
144
+ )
145
+ )
146
+ return data
@@ -35,8 +35,6 @@ else:
35
35
 
36
36
  from typing import Dict, List, Tuple
37
37
 
38
- from httomolibgpu.misc.supp_func import data_checker
39
-
40
38
  __all__ = [
41
39
  "distortion_correction_proj_discorpy",
42
40
  ]
@@ -88,10 +86,6 @@ def distortion_correction_proj_discorpy(
88
86
  if len(data.shape) == 2:
89
87
  data = cp.expand_dims(data, axis=0)
90
88
 
91
- data = data_checker(
92
- data, verbosity=True, method_name="distortion_correction_proj_discorpy"
93
- )
94
-
95
89
  # Get info from metadata txt file
96
90
  xcenter, ycenter, list_fact = _load_metadata_txt(metadata_path)
97
91
 
@@ -20,7 +20,6 @@
20
20
  # ---------------------------------------------------------------------------
21
21
  """Modules for raw projection data normalization"""
22
22
 
23
- import numpy as np
24
23
  from httomolibgpu import cupywrapper
25
24
 
26
25
  cp = cupywrapper.cp
@@ -34,27 +33,21 @@ else:
34
33
  mean = Mock()
35
34
 
36
35
  from numpy import float32
37
- from typing import Tuple
38
36
 
39
- from httomolibgpu.misc.supp_func import data_checker
40
37
 
41
- __all__ = ["normalize"]
38
+ __all__ = ["dark_flat_field_correction", "minus_log"]
42
39
 
43
40
 
44
- def normalize(
41
+ def dark_flat_field_correction(
45
42
  data: cp.ndarray,
46
43
  flats: cp.ndarray,
47
44
  darks: cp.ndarray,
48
45
  flats_multiplier: float = 1.0,
49
46
  darks_multiplier: float = 1.0,
50
47
  cutoff: float = 10.0,
51
- minus_log: bool = True,
52
- nonnegativity: bool = False,
53
- remove_nans: bool = False,
54
48
  ) -> cp.ndarray:
55
49
  """
56
50
  Normalize raw projection data using the flat and dark field projections.
57
- This is a raw CUDA kernel implementation with CuPy wrappers.
58
51
 
59
52
  Parameters
60
53
  ----------
@@ -70,17 +63,11 @@ def normalize(
70
63
  A multiplier to apply to darks, can work as an intensity compensation constant.
71
64
  cutoff : float
72
65
  Permitted maximum value for the normalised data.
73
- minus_log : bool
74
- Apply negative log to the normalised data.
75
- nonnegativity : bool
76
- Remove negative values in the normalised data.
77
- remove_nans : bool
78
- Remove NaN and Inf values in the normalised data.
79
66
 
80
- Returns
67
+ Returns
81
68
  -------
82
69
  cp.ndarray
83
- Normalised 3D tomographic data as a CuPy array.
70
+ Normalised by dark/flat fields 3D tomographic data as a CuPy array.
84
71
  """
85
72
  _check_valid_input_normalise(data, flats, darks)
86
73
 
@@ -101,16 +88,6 @@ def normalize(
101
88
  }
102
89
  float v = (float(data) - float(darks))/denom;
103
90
  """
104
- if minus_log:
105
- kernel += "v = -log(v);\n"
106
- kernel_name += "_mlog"
107
- if nonnegativity:
108
- kernel += "if (v < 0.0f) v = 0.0f;\n"
109
- kernel_name += "_nneg"
110
- if remove_nans:
111
- kernel += "if (isnan(v)) v = 0.0f;\n"
112
- kernel += "if (isinf(v)) v = 0.0f;\n"
113
- kernel_name += "_remnan"
114
91
  kernel += "if (v > cutoff) v = cutoff;\n"
115
92
  kernel += "if (v < -cutoff) v = cutoff;\n"
116
93
  kernel += "out = v;\n"
@@ -130,6 +107,24 @@ def normalize(
130
107
  return out
131
108
 
132
109
 
110
+ def minus_log(data: cp.ndarray) -> cp.ndarray:
111
+ """
112
+ Apply -log(data) operation
113
+
114
+ Parameters
115
+ ----------
116
+ data : cp.ndarray
117
+ Data as a CuPy array.
118
+
119
+ Returns
120
+ -------
121
+ cp.ndarray
122
+ data after -log(data)
123
+ """
124
+
125
+ return -cp.log(data)
126
+
127
+
133
128
  def _check_valid_input_normalise(data, flats, darks) -> None:
134
129
  """Helper function to check the validity of inputs to normalisation functions"""
135
130
  if data.ndim != 3:
@@ -145,7 +140,3 @@ def _check_valid_input_normalise(data, flats, darks) -> None:
145
140
  flats = flats[cp.newaxis, :, :]
146
141
  if darks.ndim == 2:
147
142
  darks = darks[cp.newaxis, :, :]
148
-
149
- data_checker(data, verbosity=True, method_name="normalize_data")
150
- data_checker(flats, verbosity=True, method_name="normalize_flats")
151
- data_checker(darks, verbosity=True, method_name="normalize_darks")
@@ -18,7 +18,7 @@
18
18
  # Created By : Tomography Team at DLS <scientificsoftware@diamond.ac.uk>
19
19
  # Created Date: 01 November 2022
20
20
  # ---------------------------------------------------------------------------
21
- """Modules for phase retrieval and phase-contrast enhancement"""
21
+ """Modules for phase retrieval and phase-contrast enhancement. For more detailed information, see :ref:`phase_contrast_module`."""
22
22
 
23
23
  import numpy as np
24
24
  from httomolibgpu import cupywrapper
@@ -39,38 +39,38 @@ from numpy import float32
39
39
  from typing import Tuple
40
40
  import math
41
41
 
42
- from httomolibgpu.misc.supp_func import data_checker
43
-
44
42
  __all__ = [
45
- "paganin_filter_tomopy",
43
+ "paganin_filter",
44
+ "paganin_filter_savu_legacy",
46
45
  ]
47
46
 
48
47
 
49
- ##-------------------------------------------------------------##
50
- # Adaptation of retrieve_phase (Paganin filter) from TomoPy
51
- def paganin_filter_tomopy(
48
+ # This implementation originated from the TomoPy version. It has been modified to conform
49
+ # different unit standards and also control of the filter driven by 'delta/beta' ratio
50
+ # as opposed to 'alpha' in the TomoPy's implementation.
51
+ def paganin_filter(
52
52
  tomo: cp.ndarray,
53
- pixel_size: float = 1e-4,
54
- dist: float = 50.0,
53
+ pixel_size: float = 1.28,
54
+ distance: float = 1.0,
55
55
  energy: float = 53.0,
56
- alpha: float = 1e-3,
56
+ ratio_delta_beta: float = 250,
57
57
  ) -> cp.ndarray:
58
58
  """
59
- Perform single-material phase retrieval from flats/darks corrected tomographic measurements. See
60
- :cite:`Paganin02` for a reference.
59
+ Perform single-material phase retrieval from flats/darks corrected tomographic measurements. For more detailed information, see :ref:`phase_contrast_module`.
60
+ Also see :cite:`Paganin02` and :cite:`paganin2020boosting` for references.
61
61
 
62
62
  Parameters
63
63
  ----------
64
64
  tomo : cp.ndarray
65
65
  3D array of f/d corrected tomographic projections.
66
- pixel_size : float, optional
67
- Detector pixel size in cm.
68
- dist : float, optional
69
- Propagation distance of the wavefront in cm.
70
- energy : float, optional
71
- Energy of incident wave in keV.
72
- alpha : float, optional
73
- Regularization parameter, the ratio of delta/beta. Smaller values lead to less noise and more blur.
66
+ pixel_size : float
67
+ Detector pixel size (resolution) in micron units.
68
+ distance : float
69
+ Propagation distance of the wavefront from sample to detector in metre units.
70
+ energy : float
71
+ Beam energy in keV.
72
+ ratio_delta_beta : float
73
+ The ratio of delta/beta, where delta is the phase shift and real part of the complex material refractive index and beta is the absorption.
74
74
 
75
75
  Returns
76
76
  -------
@@ -84,8 +84,6 @@ def paganin_filter_tomopy(
84
84
  " please provide a stack of 2D projections."
85
85
  )
86
86
 
87
- tomo = data_checker(tomo, verbosity=True, method_name="paganin_filter_tomopy")
88
-
89
87
  dz_orig, dy_orig, dx_orig = tomo.shape
90
88
 
91
89
  # Perform padding to the power of 2 as FFT is O(n*log(n)) complexity
@@ -98,11 +96,18 @@ def paganin_filter_tomopy(
98
96
  padded_tomo = cp.asarray(padded_tomo, dtype=cp.complex64)
99
97
  fft_tomo = fft2(padded_tomo, axes=(-2, -1), overwrite_x=True)
100
98
 
101
- # Compute the reciprocal grid.
102
- w2 = _reciprocal_grid(pixel_size, (dy, dx))
99
+ # calculate alpha constant
100
+ alpha = _calculate_alpha(energy, distance / 1e-6, ratio_delta_beta)
101
+
102
+ # Compute the reciprocal grid
103
+ indx = _reciprocal_coord(pixel_size, dy)
104
+ indy = _reciprocal_coord(pixel_size, dx)
105
+
106
+ # Build Lorentzian-type filter
107
+ phase_filter = fftshift(
108
+ 1.0 / (1.0 + alpha * (cp.add.outer(cp.square(indx), cp.square(indy))))
109
+ )
103
110
 
104
- # Build filter in the Fourier space.
105
- phase_filter = fftshift(_paganin_filter_factor2(energy, dist, alpha, w2))
106
111
  phase_filter = phase_filter / phase_filter.max() # normalisation
107
112
 
108
113
  # Filter projections
@@ -132,6 +137,12 @@ def paganin_filter_tomopy(
132
137
  return _log_kernel(tomo)
133
138
 
134
139
 
140
+ def _calculate_alpha(energy, distance_micron, ratio_delta_beta):
141
+ return (
142
+ _wavelength_micron(energy) * distance_micron / (4 * math.pi)
143
+ ) * ratio_delta_beta
144
+
145
+
135
146
  def _shift_bit_length(x: int) -> int:
136
147
  return 1 << (x - 1).bit_length()
137
148
 
@@ -192,60 +203,64 @@ def _pad_projections_to_second_power(
192
203
  return padded_tomo, tuple(pad_list)
193
204
 
194
205
 
195
- def _paganin_filter_factor2(energy, dist, alpha, w2):
196
- # Alpha represents the ratio of delta/beta.
197
- return 1 / (_wavelength(energy) * dist * w2 / (4 * math.pi) + alpha)
198
-
199
-
200
- def _wavelength(energy: float) -> float:
201
- SPEED_OF_LIGHT = 299792458e2 # [cm/s]
206
+ def _wavelength_micron(energy: float) -> float:
207
+ SPEED_OF_LIGHT = 299792458e2 * 10000.0 # [microns/s]
202
208
  PLANCK_CONSTANT = 6.58211928e-19 # [keV*s]
203
209
  return 2 * math.pi * PLANCK_CONSTANT * SPEED_OF_LIGHT / energy
204
210
 
205
211
 
206
- def _reciprocal_grid(pixel_size: float, shape_proj: tuple) -> cp.ndarray:
212
+ def _reciprocal_coord(pixel_size: float, num_grid: int) -> cp.ndarray:
207
213
  """
208
- Calculate reciprocal grid.
214
+ Calculate reciprocal grid coordinates for a given pixel size
215
+ and discretization.
209
216
 
210
217
  Parameters
211
218
  ----------
212
219
  pixel_size : float
213
- Detector pixel size in cm.
214
- shape_proj : tuple
215
- Shape of the reciprocal grid along x and y axes.
220
+ Detector pixel size in microns.
221
+ num_grid : int
222
+ Size of the reciprocal grid.
216
223
 
217
224
  Returns
218
225
  -------
219
226
  ndarray
220
227
  Grid coordinates.
221
228
  """
222
- # Sampling in reciprocal space.
223
- indx = _reciprocal_coord(pixel_size, shape_proj[0])
224
- indy = _reciprocal_coord(pixel_size, shape_proj[1])
225
- indx_sq = cp.square(indx)
226
- indy_sq = cp.square(indy)
227
-
228
- return cp.add.outer(indx_sq, indy_sq)
229
+ n = num_grid - 1
230
+ rc = cp.arange(-n, num_grid, 2, dtype=cp.float32)
231
+ rc *= 2 * math.pi / (n * pixel_size)
232
+ return rc
229
233
 
230
234
 
231
- def _reciprocal_coord(pixel_size: float, num_grid: int) -> cp.ndarray:
235
+ def paganin_filter_savu_legacy(
236
+ tomo: cp.ndarray,
237
+ pixel_size: float = 1.28,
238
+ distance: float = 1.0,
239
+ energy: float = 53.0,
240
+ ratio_delta_beta: float = 250,
241
+ ) -> cp.ndarray:
232
242
  """
233
- Calculate reciprocal grid coordinates for a given pixel size
234
- and discretization.
243
+ Perform single-material phase retrieval from flats/darks corrected tomographic measurements. For more detailed information, see :ref:`phase_contrast_module`.
244
+ Also see :cite:`Paganin02` and :cite:`paganin2020boosting` for references. The ratio_delta_beta parameter here follows implementation in Savu software.
245
+ The module will be retired in future in favour of paganin_filter. One can rescale parameter ratio_delta_beta / 4 to achieve the same effect in paganin_filter.
235
246
 
236
247
  Parameters
237
248
  ----------
249
+ tomo : cp.ndarray
250
+ 3D array of f/d corrected tomographic projections.
238
251
  pixel_size : float
239
- Detector pixel size in cm.
240
- num_grid : int
241
- Size of the reciprocal grid.
252
+ Detector pixel size (resolution) in micron units.
253
+ distance : float
254
+ Propagation distance of the wavefront from sample to detector in metre units.
255
+ energy : float
256
+ Beam energy in keV.
257
+ ratio_delta_beta : float
258
+ The ratio of delta/beta, where delta is the phase shift and real part of the complex material refractive index and beta is the absorption.
242
259
 
243
260
  Returns
244
261
  -------
245
- ndarray
246
- Grid coordinates.
262
+ cp.ndarray
263
+ The 3D array of Paganin phase-filtered projection images.
247
264
  """
248
- n = num_grid - 1
249
- rc = cp.arange(-n, num_grid, 2, dtype=cp.float32)
250
- rc *= 2 * math.pi / (n * pixel_size)
251
- return rc
265
+
266
+ return paganin_filter(tomo, pixel_size, distance, energy, ratio_delta_beta / 4)
@@ -43,8 +43,6 @@ else:
43
43
 
44
44
  from typing import Union
45
45
 
46
- from httomolibgpu.misc.supp_func import data_checker
47
-
48
46
  __all__ = [
49
47
  "remove_stripe_based_sorting",
50
48
  "remove_stripe_ti",
@@ -83,8 +81,6 @@ def remove_stripe_based_sorting(
83
81
 
84
82
  """
85
83
 
86
- data = data_checker(data, verbosity=True, method_name="remove_stripe_based_sorting")
87
-
88
84
  if size is None:
89
85
  if data.shape[2] > 2000:
90
86
  size = 21
@@ -139,7 +135,6 @@ def remove_stripe_ti(
139
135
  ndarray
140
136
  3D array of de-striped projections.
141
137
  """
142
- data = data_checker(data, verbosity=True, method_name="remove_stripe_ti")
143
138
 
144
139
  _, _, dx_orig = data.shape
145
140
  if (dx_orig % 2) != 0:
@@ -216,7 +211,6 @@ def remove_all_stripe(
216
211
  Corrected 3D tomographic data as a CuPy or NumPy array.
217
212
 
218
213
  """
219
- data = data_checker(data, verbosity=True, method_name="remove_all_stripe")
220
214
 
221
215
  matindex = _create_matindex(data.shape[2], data.shape[0])
222
216
  for m in range(data.shape[1]):
@@ -392,8 +386,6 @@ def raven_filter(
392
386
  if data.dtype != cp.float32:
393
387
  raise ValueError("The input data should be float32 data type")
394
388
 
395
- data = data_checker(data, verbosity=True, method_name="raven_filter")
396
-
397
389
  # Padding of the sinogram
398
390
  data = cp.pad(data, ((pad_y, pad_y), (0, 0), (pad_x, pad_x)), mode=pad_method)
399
391