From 6ac6d84f9ae0b63ea2dc43e9d778af4d115b91b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justus=20Sagem=C3=BCller?= Date: Sat, 7 Dec 2024 17:14:37 +0100 Subject: [PATCH 1/2] Workaround for changed normalisation convention in PyFFT>=0.13. In older versions of PyFFT, the `normalise_idft` argument was only relevant for the inverse direction, else ignored. ODLs `pyfftw_call` wrapper was modelled around this behaviour. Starting with PyFFT-0.13, the new NumPy normalisation arguments `norm='forward'` and `norm='backward'` (https://github.com/numpy/numpy/pull/16476) were adopted for the high-level binders (https://github.com/pyFFTW/pyFFTW/pull/308, merged in https://github.com/pyFFTW/pyFFTW/pull/330). They implemented this by pre-matching the `norm` argument and setting `normalise_idft` accordingly. In case of the 'forward' normalisation this involves using `normalise_idft=False` to signal that the normalisation should instead happen in the forward direction, which was previously not even possible. In other words, in PyFFT<0.13 `normalise_idft=False` meant no normalisation at all was used (neither for fft nor ifft, with the consequence that they weren't inverses in this case), and that is the behaviour ODL expected. Explicitly setting `normalise_idft=True` in this specific case restores the desired behaviour, and is backwards-compatible because PyFFT<0.13 ignores the `normalise_idft` argument in the forward direction. --- odl/trafos/backends/pyfftw_bindings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/odl/trafos/backends/pyfftw_bindings.py b/odl/trafos/backends/pyfftw_bindings.py index 0150c754df8..75348a22563 100644 --- a/odl/trafos/backends/pyfftw_bindings.py +++ b/odl/trafos/backends/pyfftw_bindings.py @@ -203,7 +203,10 @@ def pyfftw_call(array_in, array_out, direction='forward', axes=None, else: fftw_plan = fftw_plan_in - fftw_plan(array_in, array_out, normalise_idft=normalise_idft) + if not normalise_idft and direction=='forward': + fftw_plan(array_in, array_out, normalise_idft=True) + else: + fftw_plan(array_in, array_out, normalise_idft=normalise_idft) if wexport: try: From 53499de83b2e0fd8d5662a72f39350f36a067026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justus=20Sagem=C3=BCller?= Date: Sat, 7 Dec 2024 17:51:29 +0100 Subject: [PATCH 2/2] Update comment regarding whether PyFFTW can normalise in forward direction. --- odl/trafos/fourier.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/odl/trafos/fourier.py b/odl/trafos/fourier.py index 03af04f02ff..0ce5a6a982b 100644 --- a/odl/trafos/fourier.py +++ b/odl/trafos/fourier.py @@ -675,7 +675,8 @@ def _call_pyfftw(self, x, out, **kwargs): halfcomplex=self.halfcomplex, planning_effort=effort, fftw_plan=self._fftw_plan, normalise_idft=True) - # Need to normalize for 'forward', no way to force pyfftw + # Need to normalize for 'forward', pyfftw before version 0.13 + # does not offer a way to do this. if self.sign == '-': out /= np.prod(np.take(self.domain.shape, self.axes))