WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 934d0da

Browse files
authored
fix temperamental notebook progress thread errors (#2241)
- fixes TomographicImaging/CIL-Demos#260
1 parent 1cf8472 commit 934d0da

File tree

4 files changed

+39
-38
lines changed

4 files changed

+39
-38
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- `PaganinProcessor` now correctly applies scaling with magnification for cone-beam geometry (#2225)
77
- Dependencies:
88
- olefile and dxchange are optional dependencies, instead of required (#2209)
9+
- improve `tqdm` notebook support (#2241)
910
- Documentation:
1011
- Render the user showcase notebooks in the documentation (#2189)
1112

Wrappers/Python/cil/optimisation/utilities/callbacks.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
from tqdm.std import tqdm as tqdm_std
2525
import numpy as np
2626

27+
tqdm_std.monitor_interval = 0 # disable background monitoring thread
28+
2729

2830
class Callback(ABC):
2931
'''Base Callback to inherit from for use in :code:`Algorithm.run(callbacks: list[Callback])`.
@@ -154,56 +156,54 @@ class LogfileCallback(TextProgressCallback):
154156
def __init__(self, log_file, mode='a', **kwargs):
155157
self.fd = open(log_file, mode=mode)
156158
super().__init__(file=self.fd, **kwargs)
157-
159+
158160
class EarlyStoppingObjectiveValue(Callback):
159161
'''Callback that stops iterations if the change in the objective value is less than a provided threshold value.
160162
161163
Parameters
162164
----------
163-
threshold: float, default 1e-6
165+
threshold: float, default 1e-6
164166
165167
Note
166168
-----
167169
This callback only compares the last two calculated objective values. If `update_objective_interval` is greater than 1, the objective value is not calculated at each iteration (which is the default behaviour), only every `update_objective_interval` iterations.
168-
170+
169171
'''
170172
def __init__(self, threshold=1e-6):
171173
self.threshold=threshold
172-
173-
174+
175+
174176
def __call__(self, algorithm):
175177
if len(algorithm.loss)>=2:
176178
if np.abs(algorithm.loss[-1]-algorithm.loss[-2])<self.threshold:
177179
raise StopIteration
178-
180+
179181
class CGLSEarlyStopping(Callback):
180-
'''Callback to work with CGLS. It causes the algorithm to terminate if :math:`||A^T(Ax-b)||_2 < \epsilon||A^T(Ax_0-b)||_2` where `epsilon` is set to default as '1e-6', :math:`x` is the current iterate and :math:`x_0` is the initial value.
181-
It will also terminate if the algorithm begins to diverge i.e. if :math:`||x||_2> \omega`, where `omega` is set to default as 1e6.
182-
182+
'''Callback to work with CGLS. It causes the algorithm to terminate if :math:`||A^T(Ax-b)||_2 < \epsilon||A^T(Ax_0-b)||_2` where `epsilon` is set to default as '1e-6', :math:`x` is the current iterate and :math:`x_0` is the initial value.
183+
It will also terminate if the algorithm begins to diverge i.e. if :math:`||x||_2> \omega`, where `omega` is set to default as 1e6.
184+
183185
Parameters
184186
----------
185-
epsilon: float, default 1e-6
187+
epsilon: float, default 1e-6
186188
Usually a small number: the algorithm to terminate if :math:`||A^T(Ax-b)||_2 < \epsilon||A^T(Ax_0-b)||_2`
187-
omega: float, default 1e6
189+
omega: float, default 1e6
188190
Usually a large number: the algorithm will terminate if :math:`||x||_2> \omega`
189-
191+
190192
Note
191193
-----
192-
This callback is implemented to replicate the automatic behaviour of CGLS in CIL versions <=24. It also replicates the behaviour of https://web.stanford.edu/group/SOL/software/cgls/.
194+
This callback is implemented to replicate the automatic behaviour of CGLS in CIL versions <=24. It also replicates the behaviour of https://web.stanford.edu/group/SOL/software/cgls/.
193195
'''
194196
def __init__(self, epsilon=1e-6, omega=1e6):
195197
self.epsilon=epsilon
196198
self.omega=omega
197-
198-
199+
200+
199201
def __call__(self, algorithm):
200-
202+
201203
if (algorithm.norms <= algorithm.norms0 * self.epsilon):
202204
print('The norm of the residual is less than {} times the norm of the initial residual and so the algorithm is terminated'.format(self.epsilon))
203205
raise StopIteration
204206
self.normx = algorithm.x.norm()
205207
if algorithm.normx >= self.omega:
206208
print('The norm of the solution is greater than {} and so the algorithm is terminated'.format(self.omega))
207209
raise StopIteration
208-
209-

Wrappers/Python/cil/processors/PaganinProcessor.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from scipy.fft import ifft2
2626
from scipy.fft import ifftshift
2727
from scipy import constants
28-
from tqdm import tqdm
28+
from tqdm.auto import tqdm
2929
import logging
3030

3131
log = logging.getLogger(__name__)
@@ -116,12 +116,12 @@ class PaganinProcessor(Processor):
116116
- :math:`T`, is the sample thickness,
117117
- :math:`\mu = \frac{4\pi\beta}{\lambda}` is the material linear
118118
attenuation coefficient where :math:`\beta` is the complex part of the
119-
material refractive index [2] and :math:`\lambda=\frac{hc}{E}` is the
119+
material refractive index [2] and :math:`\lambda=\frac{hc}{E}` is the
120120
probe wavelength,
121121
- :math:`I_{norm}` is the input image which is expected to be the
122122
normalised transmission data,
123-
- :math:`\Delta` is the propagation distance. In cone-beam geometry,
124-
:math:`\Delta` is scaled by the magnification :math:`M` as described
123+
- :math:`\Delta` is the propagation distance. In cone-beam geometry,
124+
:math:`\Delta` is scaled by the magnification :math:`M` as described
125125
in [1],
126126
- :math:`\alpha = \frac{\Delta\delta}{\mu}` is a parameter determining
127127
the strength of the filter to be applied in Fourier space where
@@ -203,22 +203,22 @@ def __init__(self, delta=1, beta=1e-2, energy=40000,
203203
def check_input(self, data):
204204
if not isinstance(data, (AcquisitionData)):
205205
raise TypeError('Processor only supports AcquisitionData')
206-
206+
207207
if data.geometry.geom_type & AcquisitionType.CONE_FLEX:
208208
raise NotImplementedError("Processor not implemented for CONE_FLEX geometry.")
209-
209+
210210
if data.dtype!=np.float32:
211211
raise TypeError('Processor only support dtype=float32')
212-
212+
213213
cil_order = tuple(AcquisitionDimension.get_order_for_engine('cil',data.geometry))
214214
if data.dimension_labels != cil_order:
215215
raise ValueError("This processor requires CIL data order, consider using `data.reorder('cil')`")
216-
216+
217217
return True
218218

219219
def process(self, out=None):
220220

221-
data = self.get_input()
221+
data = self.get_input()
222222
# set the geometry parameters to use from data.geometry unless the
223223
# geometry is overridden with an override_geometry
224224
self._set_geometry(data.geometry, self.override_geometry)
@@ -229,12 +229,12 @@ def process(self, out=None):
229229
target_shape = (
230230
data.get_dimension_size('channel') if 'channel' in data.dimension_labels else 1,
231231
data.geometry.num_projections,
232-
data.get_dimension_size('vertical') if 'vertical' in data.dimension_labels else 1,
232+
data.get_dimension_size('vertical') if 'vertical' in data.dimension_labels else 1,
233233
data.get_dimension_size('horizontal') if 'horizontal' in data.dimension_labels else 1)
234-
234+
235235
data.array = np.reshape(data.array, target_shape)
236236
out.array = np.reshape(out.array, target_shape)
237-
237+
238238
# create a filter based on the shape of the data
239239
proj_shape = data.array.shape[-2:]
240240
self.filter_Nx = proj_shape[0]+self.pad*2
@@ -243,12 +243,12 @@ def process(self, out=None):
243243

244244
# allocate padded buffer
245245
padded_buffer = np.zeros((self.filter_Nx, self.filter_Ny), dtype=data.dtype)
246-
buffer_slice = (slice(self.pad, self.pad + proj_shape[0]),
246+
buffer_slice = (slice(self.pad, self.pad + proj_shape[0]),
247247
slice(self.pad, self.pad + proj_shape[1]))
248-
248+
249249
# pre-calculate the scaling factor
250250
scaling_factor = -(1/self.mu)
251-
251+
252252
# loop over the channels
253253
for j in range(data.geometry.channels):
254254
# loop over the projections
@@ -266,9 +266,9 @@ def process(self, out=None):
266266
# apply the filter in fourier space
267267
fI = fft2(padded_buffer)
268268
padded_buffer[:] = ifft2(fI*self.filter).real
269-
269+
270270
out.array[j, i, :, :] = padded_buffer[buffer_slice]
271-
271+
272272
data.array = np.squeeze(data.array)
273273
out.array = np.squeeze(out.array)
274274
return out
@@ -469,7 +469,7 @@ def _create_filter(self, override_filter=None):
469469
self.alpha = override_filter['alpha']
470470
else:
471471
self._calculate_alpha()
472-
472+
473473
# calculate pixel size at sample plane, used for defining fourier mesh
474474
pixel_size_dmag = self.pixel_size/self.magnification
475475

Wrappers/Python/cil/recon/FBP.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
import numpy as np
2525
import ctypes
26-
from tqdm import tqdm
26+
from tqdm.auto import tqdm
2727

2828
c_float_p = ctypes.POINTER(ctypes.c_float)
2929
c_double_p = ctypes.POINTER(ctypes.c_double)
@@ -488,7 +488,7 @@ def __init__ (self, input, image_geometry=None, filter='ram-lak', backend='tigre
488488

489489
if not AcquisitionType.PARALLEL & input.geometry.geom_type:
490490
raise TypeError("This reconstructor is for parallel-beam data only.")
491-
491+
492492
super().__init__(input, image_geometry, filter, backend)
493493
self.set_split_processing(False)
494494

0 commit comments

Comments
 (0)