httomolibgpu 5.0__tar.gz → 5.2__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.
- {httomolibgpu-5.0/httomolibgpu.egg-info → httomolibgpu-5.2}/PKG-INFO +2 -1
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/__init__.py +1 -0
- httomolibgpu-5.2/httomolibgpu/cuda_kernels/remove_stripe_fw.cu +155 -0
- httomolibgpu-5.2/httomolibgpu/memory_estimator_helpers.py +24 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/prep/phase.py +110 -22
- httomolibgpu-5.2/httomolibgpu/prep/stripe.py +1038 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/recon/_phase_cross_correlation.py +9 -25
- {httomolibgpu-5.0 → httomolibgpu-5.2/httomolibgpu.egg-info}/PKG-INFO +2 -1
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu.egg-info/SOURCES.txt +2 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu.egg-info/requires.txt +1 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/pyproject.toml +1 -0
- httomolibgpu-5.0/httomolibgpu/prep/stripe.py +0 -437
- {httomolibgpu-5.0 → httomolibgpu-5.2}/LICENSE +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/MANIFEST.in +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/README.rst +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/cuda_kernels/__init__.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/cuda_kernels/calc_metrics.cu +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/cuda_kernels/center_360_shifts.cu +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/cuda_kernels/generate_mask.cu +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/cuda_kernels/median_kernel.cu +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/cuda_kernels/raven_filter.cu +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/cuda_kernels/remove_nan_inf.cu +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/cupywrapper.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/misc/__init__.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/misc/corr.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/misc/denoise.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/misc/morph.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/misc/rescale.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/misc/utils.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/prep/__init__.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/prep/alignment.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/prep/normalize.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/recon/__init__.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/recon/algorithm.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu/recon/rotation.py +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu.egg-info/dependency_links.txt +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/httomolibgpu.egg-info/top_level.txt +0 -0
- {httomolibgpu-5.0 → httomolibgpu-5.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: httomolibgpu
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.2
|
|
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
|
|
@@ -19,6 +19,7 @@ Requires-Dist: scipy
|
|
|
19
19
|
Requires-Dist: pillow
|
|
20
20
|
Requires-Dist: scikit-image
|
|
21
21
|
Requires-Dist: tomobar
|
|
22
|
+
Requires-Dist: PyWavelets
|
|
22
23
|
Provides-Extra: dev
|
|
23
24
|
Requires-Dist: pytest; extra == "dev"
|
|
24
25
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -9,6 +9,7 @@ from httomolibgpu.prep.normalize import dark_flat_field_correction, minus_log
|
|
|
9
9
|
from httomolibgpu.prep.phase import paganin_filter, paganin_filter_savu_legacy
|
|
10
10
|
from httomolibgpu.prep.stripe import (
|
|
11
11
|
remove_stripe_based_sorting,
|
|
12
|
+
remove_stripe_fw,
|
|
12
13
|
remove_stripe_ti,
|
|
13
14
|
remove_all_stripe,
|
|
14
15
|
raven_filter,
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
template<int WSize>
|
|
2
|
+
__global__ void grouped_convolution_x(
|
|
3
|
+
int dim_x,
|
|
4
|
+
int dim_y,
|
|
5
|
+
int dim_z,
|
|
6
|
+
const float* in,
|
|
7
|
+
int in_stride_x,
|
|
8
|
+
int in_stride_y,
|
|
9
|
+
int in_stride_z,
|
|
10
|
+
float* out,
|
|
11
|
+
int out_stride_z,
|
|
12
|
+
int out_stride_group,
|
|
13
|
+
const float* w
|
|
14
|
+
)
|
|
15
|
+
{
|
|
16
|
+
const int g_thd_x = blockDim.x * blockIdx.x + threadIdx.x;
|
|
17
|
+
const int g_thd_y = blockDim.y * blockIdx.y + threadIdx.y;
|
|
18
|
+
const int g_thd_z = blockDim.z * blockIdx.z + threadIdx.z;
|
|
19
|
+
if (g_thd_x >= dim_x || g_thd_y >= dim_y || g_thd_z >= dim_z)
|
|
20
|
+
{
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
constexpr int out_groups = 2;
|
|
25
|
+
for (int i = 0; i < out_groups; ++i)
|
|
26
|
+
{
|
|
27
|
+
float acc = 0.F;
|
|
28
|
+
for (int j = 0; j < WSize; ++j)
|
|
29
|
+
{
|
|
30
|
+
const int w_idx = i * WSize + j;
|
|
31
|
+
const int in_idx = (g_thd_x * in_stride_x + j) + g_thd_y * in_stride_y + g_thd_z * in_stride_z;
|
|
32
|
+
acc += w[w_idx] * in[in_idx];
|
|
33
|
+
}
|
|
34
|
+
const int out_idx = g_thd_x + g_thd_y * dim_x + g_thd_z * out_stride_z + i * out_stride_group;
|
|
35
|
+
out[out_idx] = acc;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
template<int WSize>
|
|
40
|
+
__global__ void grouped_convolution_y(
|
|
41
|
+
int dim_x,
|
|
42
|
+
int dim_y,
|
|
43
|
+
int dim_z,
|
|
44
|
+
const float* in,
|
|
45
|
+
int in_stride_x,
|
|
46
|
+
int in_stride_y,
|
|
47
|
+
int in_stride_z,
|
|
48
|
+
int in_stride_group,
|
|
49
|
+
float* out,
|
|
50
|
+
int out_stride_z,
|
|
51
|
+
int out_stride_group,
|
|
52
|
+
const float* w
|
|
53
|
+
)
|
|
54
|
+
{
|
|
55
|
+
const int g_thd_x = blockDim.x * blockIdx.x + threadIdx.x;
|
|
56
|
+
const int g_thd_y = blockDim.y * blockIdx.y + threadIdx.y;
|
|
57
|
+
const int g_thd_z = blockDim.z * blockIdx.z + threadIdx.z;
|
|
58
|
+
if (g_thd_x >= dim_x || g_thd_y >= dim_y || g_thd_z >= dim_z)
|
|
59
|
+
{
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
constexpr int in_groups = 2;
|
|
64
|
+
constexpr int out_groups = 2;
|
|
65
|
+
constexpr int item_stride_y = 2;
|
|
66
|
+
for (int group = 0; group < in_groups; ++group)
|
|
67
|
+
{
|
|
68
|
+
for (int i = 0; i < out_groups; ++i)
|
|
69
|
+
{
|
|
70
|
+
float acc = 0.F;
|
|
71
|
+
for (int j = 0; j < WSize; ++j)
|
|
72
|
+
{
|
|
73
|
+
const int w_idx = (out_groups * group + i) * WSize + j;
|
|
74
|
+
const int in_idx = g_thd_x * in_stride_x + (item_stride_y * g_thd_y + j) * in_stride_y + group * in_stride_group + g_thd_z * in_stride_z;
|
|
75
|
+
acc += w[w_idx] * in[in_idx];
|
|
76
|
+
}
|
|
77
|
+
const int out_idx = g_thd_x + g_thd_y * dim_x + g_thd_z * out_stride_z + (out_groups * group + i) * out_stride_group;
|
|
78
|
+
out[out_idx] = acc;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
template<int WSize>
|
|
84
|
+
__global__ void transposed_convolution_x(
|
|
85
|
+
int dim_x,
|
|
86
|
+
int dim_y,
|
|
87
|
+
int dim_z,
|
|
88
|
+
const float* in,
|
|
89
|
+
int in_dim_x,
|
|
90
|
+
int in_stride_y,
|
|
91
|
+
int in_stride_z,
|
|
92
|
+
const float* w,
|
|
93
|
+
float* out
|
|
94
|
+
)
|
|
95
|
+
{
|
|
96
|
+
const int g_thd_x = blockDim.x * blockIdx.x + threadIdx.x;
|
|
97
|
+
const int g_thd_y = blockDim.y * blockIdx.y + threadIdx.y;
|
|
98
|
+
const int g_thd_z = blockDim.z * blockIdx.z + threadIdx.z;
|
|
99
|
+
if (g_thd_x >= dim_x || g_thd_y >= dim_y || g_thd_z >= dim_z)
|
|
100
|
+
{
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
constexpr int item_out_stride = 2;
|
|
105
|
+
float acc = 0.F;
|
|
106
|
+
for (int i = 0; i < WSize; ++i)
|
|
107
|
+
{
|
|
108
|
+
const int in_x = (g_thd_x - i) / item_out_stride;
|
|
109
|
+
const int in_x_mod = (g_thd_x - i) % item_out_stride;
|
|
110
|
+
if (in_x_mod == 0 && in_x >= 0 && in_x < in_dim_x)
|
|
111
|
+
{
|
|
112
|
+
const int in_idx = in_x + g_thd_y * in_stride_y + g_thd_z * in_stride_z;
|
|
113
|
+
acc += in[in_idx] * w[i];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const int out_idx = g_thd_x + dim_x * g_thd_y + dim_x * dim_y * g_thd_z;
|
|
117
|
+
out[out_idx] = acc;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
template<int WSize>
|
|
121
|
+
__global__ void transposed_convolution_y(
|
|
122
|
+
int dim_x,
|
|
123
|
+
int dim_y,
|
|
124
|
+
int dim_z,
|
|
125
|
+
const float* in,
|
|
126
|
+
int in_dim_y,
|
|
127
|
+
int in_stride_y,
|
|
128
|
+
int in_stride_z,
|
|
129
|
+
const float* w,
|
|
130
|
+
float* out
|
|
131
|
+
)
|
|
132
|
+
{
|
|
133
|
+
const int g_thd_x = blockDim.x * blockIdx.x + threadIdx.x;
|
|
134
|
+
const int g_thd_y = blockDim.y * blockIdx.y + threadIdx.y;
|
|
135
|
+
const int g_thd_z = blockDim.z * blockIdx.z + threadIdx.z;
|
|
136
|
+
if (g_thd_x >= dim_x || g_thd_y >= dim_y || g_thd_z >= dim_z)
|
|
137
|
+
{
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
constexpr int item_out_stride = 2;
|
|
142
|
+
float acc = 0.F;
|
|
143
|
+
for (int i = 0; i < WSize; ++i)
|
|
144
|
+
{
|
|
145
|
+
const int in_y = (g_thd_y - i) / item_out_stride;
|
|
146
|
+
const int in_y_mod = (g_thd_y - i) % item_out_stride;
|
|
147
|
+
if (in_y_mod == 0 && in_y >= 0 && in_y < in_dim_y)
|
|
148
|
+
{
|
|
149
|
+
const int in_idx = g_thd_x + in_y * in_stride_y + g_thd_z * in_stride_z;
|
|
150
|
+
acc += in[in_idx] * w[i];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const int out_idx = g_thd_x + dim_x * g_thd_y + dim_x * dim_y * g_thd_z;
|
|
154
|
+
out[out_idx] = acc;
|
|
155
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
ALLOCATION_UNIT_SIZE = 512
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class _DeviceMemStack:
|
|
5
|
+
def __init__(self) -> None:
|
|
6
|
+
self.allocations = []
|
|
7
|
+
self.current = 0
|
|
8
|
+
self.highwater = 0
|
|
9
|
+
|
|
10
|
+
def malloc(self, bytes):
|
|
11
|
+
self.allocations.append(bytes)
|
|
12
|
+
allocated = self._round_up(bytes)
|
|
13
|
+
self.current += allocated
|
|
14
|
+
self.highwater = max(self.current, self.highwater)
|
|
15
|
+
|
|
16
|
+
def free(self, bytes):
|
|
17
|
+
assert bytes in self.allocations
|
|
18
|
+
self.allocations.remove(bytes)
|
|
19
|
+
self.current -= self._round_up(bytes)
|
|
20
|
+
assert self.current >= 0
|
|
21
|
+
|
|
22
|
+
def _round_up(self, size):
|
|
23
|
+
size = (size + ALLOCATION_UNIT_SIZE - 1) // ALLOCATION_UNIT_SIZE
|
|
24
|
+
return size * ALLOCATION_UNIT_SIZE
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import numpy as np
|
|
24
24
|
from httomolibgpu import cupywrapper
|
|
25
|
+
from httomolibgpu.memory_estimator_helpers import _DeviceMemStack
|
|
25
26
|
|
|
26
27
|
cp = cupywrapper.cp
|
|
27
28
|
cupy_run = cupywrapper.cupy_run
|
|
@@ -30,13 +31,14 @@ from unittest.mock import Mock
|
|
|
30
31
|
|
|
31
32
|
if cupy_run:
|
|
32
33
|
from cupyx.scipy.fft import fft2, ifft2, fftshift
|
|
34
|
+
from cupyx.scipy.fftpack import get_fft_plan
|
|
33
35
|
else:
|
|
34
36
|
fft2 = Mock()
|
|
35
37
|
ifft2 = Mock()
|
|
36
38
|
fftshift = Mock()
|
|
37
39
|
|
|
38
40
|
from numpy import float32
|
|
39
|
-
from typing import Tuple
|
|
41
|
+
from typing import Optional, Tuple
|
|
40
42
|
import math
|
|
41
43
|
|
|
42
44
|
__all__ = [
|
|
@@ -54,6 +56,7 @@ def paganin_filter(
|
|
|
54
56
|
distance: float = 1.0,
|
|
55
57
|
energy: float = 53.0,
|
|
56
58
|
ratio_delta_beta: float = 250,
|
|
59
|
+
calc_peak_gpu_mem: bool = False,
|
|
57
60
|
) -> cp.ndarray:
|
|
58
61
|
"""
|
|
59
62
|
Perform single-material phase retrieval from flats/darks corrected tomographic measurements. For more detailed information, see :ref:`phase_contrast_module`.
|
|
@@ -71,30 +74,50 @@ def paganin_filter(
|
|
|
71
74
|
Beam energy in keV.
|
|
72
75
|
ratio_delta_beta : float
|
|
73
76
|
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.
|
|
77
|
+
calc_peak_gpu_mem: bool
|
|
78
|
+
Parameter to support memory estimation in HTTomo. Irrelevant to the method itself and can be ignored by user.
|
|
74
79
|
|
|
75
80
|
Returns
|
|
76
81
|
-------
|
|
77
82
|
cp.ndarray
|
|
78
83
|
The 3D array of Paganin phase-filtered projection images.
|
|
79
84
|
"""
|
|
85
|
+
mem_stack = _DeviceMemStack() if calc_peak_gpu_mem else None
|
|
80
86
|
# Check the input data is valid
|
|
81
|
-
if tomo.ndim != 3:
|
|
87
|
+
if not mem_stack and tomo.ndim != 3:
|
|
82
88
|
raise ValueError(
|
|
83
89
|
f"Invalid number of dimensions in data: {tomo.ndim},"
|
|
84
90
|
" please provide a stack of 2D projections."
|
|
85
91
|
)
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
if mem_stack:
|
|
93
|
+
mem_stack.malloc(np.prod(tomo) * np.float32().itemsize)
|
|
94
|
+
dz_orig, dy_orig, dx_orig = tomo.shape if not mem_stack else tomo
|
|
88
95
|
|
|
89
96
|
# Perform padding to the power of 2 as FFT is O(n*log(n)) complexity
|
|
90
97
|
# TODO: adding other options of padding?
|
|
91
|
-
padded_tomo, pad_tup = _pad_projections_to_second_power(tomo)
|
|
98
|
+
padded_tomo, pad_tup = _pad_projections_to_second_power(tomo, mem_stack)
|
|
92
99
|
|
|
93
|
-
dz, dy, dx = padded_tomo.shape
|
|
100
|
+
dz, dy, dx = padded_tomo.shape if not mem_stack else padded_tomo
|
|
94
101
|
|
|
95
102
|
# 3D FFT of tomo data
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
if mem_stack:
|
|
104
|
+
mem_stack.malloc(np.prod(padded_tomo) * np.complex64().itemsize)
|
|
105
|
+
mem_stack.free(np.prod(padded_tomo) * np.float32().itemsize)
|
|
106
|
+
fft_input = cp.empty(padded_tomo, dtype=cp.complex64)
|
|
107
|
+
else:
|
|
108
|
+
padded_tomo = cp.asarray(padded_tomo, dtype=cp.complex64)
|
|
109
|
+
fft_input = padded_tomo
|
|
110
|
+
|
|
111
|
+
fft_plan = get_fft_plan(fft_input, axes=(-2, -1))
|
|
112
|
+
if mem_stack:
|
|
113
|
+
mem_stack.malloc(fft_plan.work_area.mem.size)
|
|
114
|
+
mem_stack.free(fft_plan.work_area.mem.size)
|
|
115
|
+
else:
|
|
116
|
+
with fft_plan:
|
|
117
|
+
fft_tomo = fft2(padded_tomo, axes=(-2, -1), overwrite_x=True)
|
|
118
|
+
del padded_tomo
|
|
119
|
+
del fft_input
|
|
120
|
+
del fft_plan
|
|
98
121
|
|
|
99
122
|
# calculate alpha constant
|
|
100
123
|
alpha = _calculate_alpha(energy, distance / 1e-6, ratio_delta_beta)
|
|
@@ -103,18 +126,56 @@ def paganin_filter(
|
|
|
103
126
|
indx = _reciprocal_coord(pixel_size, dy)
|
|
104
127
|
indy = _reciprocal_coord(pixel_size, dx)
|
|
105
128
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
129
|
+
if mem_stack:
|
|
130
|
+
mem_stack.malloc(indx.size * indx.dtype.itemsize) # cp.asarray(indx)
|
|
131
|
+
mem_stack.malloc(indx.size * indx.dtype.itemsize) # cp.square
|
|
132
|
+
mem_stack.free(indx.size * indx.dtype.itemsize) # cp.asarray(indx)
|
|
133
|
+
mem_stack.malloc(indy.size * indy.dtype.itemsize) # cp.asarray(indy)
|
|
134
|
+
mem_stack.malloc(indy.size * indy.dtype.itemsize) # cp.square
|
|
135
|
+
mem_stack.free(indy.size * indy.dtype.itemsize) # cp.asarray(indy)
|
|
136
|
+
|
|
137
|
+
mem_stack.malloc(indx.size * indy.size * indx.dtype.itemsize) # cp.add.outer
|
|
138
|
+
mem_stack.free(indx.size * indx.dtype.itemsize) # cp.square
|
|
139
|
+
mem_stack.free(indy.size * indy.dtype.itemsize) # cp.square
|
|
140
|
+
mem_stack.malloc(indx.size * indy.size * indx.dtype.itemsize) # phase_filter
|
|
141
|
+
mem_stack.free(indx.size * indy.size * indx.dtype.itemsize) # cp.add.outer
|
|
142
|
+
mem_stack.free(indx.size * indy.size * indx.dtype.itemsize) # phase_filter
|
|
143
|
+
|
|
144
|
+
else:
|
|
145
|
+
# Build Lorentzian-type filter
|
|
146
|
+
phase_filter = fftshift(
|
|
147
|
+
1.0
|
|
148
|
+
/ (
|
|
149
|
+
1.0
|
|
150
|
+
+ alpha
|
|
151
|
+
* (
|
|
152
|
+
cp.add.outer(
|
|
153
|
+
cp.square(cp.asarray(indx)), cp.square(cp.asarray(indy))
|
|
154
|
+
)
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
)
|
|
110
158
|
|
|
111
|
-
|
|
159
|
+
phase_filter = phase_filter / phase_filter.max() # normalisation
|
|
112
160
|
|
|
113
|
-
|
|
114
|
-
|
|
161
|
+
# Filter projections
|
|
162
|
+
fft_tomo *= phase_filter
|
|
163
|
+
del phase_filter
|
|
115
164
|
|
|
116
165
|
# Apply filter and take inverse FFT
|
|
117
|
-
|
|
166
|
+
ifft_input = (
|
|
167
|
+
fft_tomo if not mem_stack else cp.empty(padded_tomo, dtype=cp.complex64)
|
|
168
|
+
)
|
|
169
|
+
ifft_plan = get_fft_plan(ifft_input, axes=(-2, -1))
|
|
170
|
+
if mem_stack:
|
|
171
|
+
mem_stack.malloc(ifft_plan.work_area.mem.size)
|
|
172
|
+
mem_stack.free(ifft_plan.work_area.mem.size)
|
|
173
|
+
else:
|
|
174
|
+
with ifft_plan:
|
|
175
|
+
ifft_filtered_tomo = ifft2(fft_tomo, axes=(-2, -1), overwrite_x=True).real
|
|
176
|
+
del fft_tomo
|
|
177
|
+
del ifft_plan
|
|
178
|
+
del ifft_input
|
|
118
179
|
|
|
119
180
|
# slicing indices for cropping
|
|
120
181
|
slc_indices = (
|
|
@@ -123,8 +184,19 @@ def paganin_filter(
|
|
|
123
184
|
slice(pad_tup[2][0], pad_tup[2][0] + dx_orig, 1),
|
|
124
185
|
)
|
|
125
186
|
|
|
187
|
+
if mem_stack:
|
|
188
|
+
mem_stack.malloc(np.prod(tomo) * np.float32().itemsize) # astype(cp.float32)
|
|
189
|
+
mem_stack.free(
|
|
190
|
+
np.prod(padded_tomo) * np.complex64().itemsize
|
|
191
|
+
) # ifft_filtered_tomo
|
|
192
|
+
mem_stack.malloc(
|
|
193
|
+
np.prod(tomo) * np.float32().itemsize
|
|
194
|
+
) # return _log_kernel(tomo)
|
|
195
|
+
return mem_stack.highwater
|
|
196
|
+
|
|
126
197
|
# crop the padded filtered data:
|
|
127
198
|
tomo = ifft_filtered_tomo[slc_indices].astype(cp.float32)
|
|
199
|
+
del ifft_filtered_tomo
|
|
128
200
|
|
|
129
201
|
# taking the negative log
|
|
130
202
|
_log_kernel = cp.ElementwiseKernel(
|
|
@@ -177,7 +249,7 @@ def _calculate_pad_size(datashape: tuple) -> list:
|
|
|
177
249
|
|
|
178
250
|
|
|
179
251
|
def _pad_projections_to_second_power(
|
|
180
|
-
tomo: cp.ndarray,
|
|
252
|
+
tomo: cp.ndarray, mem_stack: Optional[_DeviceMemStack]
|
|
181
253
|
) -> Tuple[cp.ndarray, Tuple[int, int]]:
|
|
182
254
|
"""
|
|
183
255
|
Performs padding of each projection to the next power of 2.
|
|
@@ -194,11 +266,17 @@ def _pad_projections_to_second_power(
|
|
|
194
266
|
ndarray: padded 3d projection data
|
|
195
267
|
tuple: a tuple with padding dimensions
|
|
196
268
|
"""
|
|
197
|
-
full_shape_tomo = cp.shape(tomo)
|
|
269
|
+
full_shape_tomo = cp.shape(tomo) if not mem_stack else tomo
|
|
198
270
|
|
|
199
271
|
pad_list = _calculate_pad_size(full_shape_tomo)
|
|
200
272
|
|
|
201
|
-
|
|
273
|
+
if mem_stack:
|
|
274
|
+
padded_tomo = [
|
|
275
|
+
sh + pad[0] + pad[1] for sh, pad in zip(full_shape_tomo, pad_list)
|
|
276
|
+
]
|
|
277
|
+
mem_stack.malloc(np.prod(padded_tomo) * np.float32().itemsize)
|
|
278
|
+
else:
|
|
279
|
+
padded_tomo = cp.pad(tomo, tuple(pad_list), "edge")
|
|
202
280
|
|
|
203
281
|
return padded_tomo, tuple(pad_list)
|
|
204
282
|
|
|
@@ -209,7 +287,7 @@ def _wavelength_micron(energy: float) -> float:
|
|
|
209
287
|
return 2 * math.pi * PLANCK_CONSTANT * SPEED_OF_LIGHT / energy
|
|
210
288
|
|
|
211
289
|
|
|
212
|
-
def _reciprocal_coord(pixel_size: float, num_grid: int) ->
|
|
290
|
+
def _reciprocal_coord(pixel_size: float, num_grid: int) -> np.ndarray:
|
|
213
291
|
"""
|
|
214
292
|
Calculate reciprocal grid coordinates for a given pixel size
|
|
215
293
|
and discretization.
|
|
@@ -227,7 +305,7 @@ def _reciprocal_coord(pixel_size: float, num_grid: int) -> cp.ndarray:
|
|
|
227
305
|
Grid coordinates.
|
|
228
306
|
"""
|
|
229
307
|
n = num_grid - 1
|
|
230
|
-
rc =
|
|
308
|
+
rc = np.arange(-n, num_grid, 2, dtype=cp.float32)
|
|
231
309
|
rc *= 2 * math.pi / (n * pixel_size)
|
|
232
310
|
return rc
|
|
233
311
|
|
|
@@ -238,6 +316,7 @@ def paganin_filter_savu_legacy(
|
|
|
238
316
|
distance: float = 1.0,
|
|
239
317
|
energy: float = 53.0,
|
|
240
318
|
ratio_delta_beta: float = 250,
|
|
319
|
+
calc_peak_gpu_mem: bool = False,
|
|
241
320
|
) -> cp.ndarray:
|
|
242
321
|
"""
|
|
243
322
|
Perform single-material phase retrieval from flats/darks corrected tomographic measurements. For more detailed information, see :ref:`phase_contrast_module`.
|
|
@@ -256,6 +335,8 @@ def paganin_filter_savu_legacy(
|
|
|
256
335
|
Beam energy in keV.
|
|
257
336
|
ratio_delta_beta : float
|
|
258
337
|
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.
|
|
338
|
+
calc_peak_gpu_mem: bool
|
|
339
|
+
Parameter to support memory estimation in HTTomo. Irrelevant to the method itself and can be ignored by user.
|
|
259
340
|
|
|
260
341
|
Returns
|
|
261
342
|
-------
|
|
@@ -263,4 +344,11 @@ def paganin_filter_savu_legacy(
|
|
|
263
344
|
The 3D array of Paganin phase-filtered projection images.
|
|
264
345
|
"""
|
|
265
346
|
|
|
266
|
-
return paganin_filter(
|
|
347
|
+
return paganin_filter(
|
|
348
|
+
tomo,
|
|
349
|
+
pixel_size,
|
|
350
|
+
distance,
|
|
351
|
+
energy,
|
|
352
|
+
ratio_delta_beta / 4,
|
|
353
|
+
calc_peak_gpu_mem=calc_peak_gpu_mem,
|
|
354
|
+
)
|