diff --git a/ci/docker_images/ubuntu/groovy/Dockerfile b/ci/docker_images/ubuntu/groovy/Dockerfile
index a9083f89809d79dedff7a4bc416f8e82483496a6..e2a1f6f425703182b06d4cde3217af466d0e99bd 100644
--- a/ci/docker_images/ubuntu/groovy/Dockerfile
+++ b/ci/docker_images/ubuntu/groovy/Dockerfile
@@ -54,7 +54,7 @@ RUN cd /tmp && \
 RUN cd /tmp && \
  wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.10/hdf5-1.10.6/src/hdf5-1.10.6.tar.gz && \
  tar -xvzf hdf5-*.tar.gz && \
- rm -rf hdf5-*.tar.gz && \
+ rm -f hdf5-*.tar.gz && \
  cd hdf5-* && \
  CC="${MPICC}" ./configure --prefix="${MPI_ROOT}" --enable-parallel --enable-shared=yes --enable-static=no && \
  make && \
@@ -207,16 +207,11 @@ RUN cd /tmp && \
  rm -f fftw-*.tar.gz && \
  cd fftw-* && \
  ./configure --enable-openmp --enable-threads --enable-mpi --enable-static --with-pic --prefix="${FFTW_ROOT}" --enable-single && \
- make && \
- make install && \
- make clean && \
+ make && make install && make clean && \
  ./configure --enable-openmp --enable-threads --enable-mpi --enable-static --with-pic --prefix="${FFTW_ROOT}" && \
- make && \
- make install && \
- make clean && \
+ make && make install && make clean && \
  ./configure --enable-openmp --enable-threads --enable-mpi --enable-static --with-pic --prefix="${FFTW_ROOT}" --enable-long-double && \
- make && \
- make install && \
+ make && make install && make clean && \
  rm -rf /tmp/fftw-*
 
 RUN cd /tmp && \ 
diff --git a/ci/utils/build_docker_image.sh b/ci/utils/build_docker_image.sh
index 5722a9b78d340a131a25a01feb7abec641d1c632..68d7a3dff8d887ef6d2cda0d268faf1e1f8d5bdf 100755
--- a/ci/utils/build_docker_image.sh
+++ b/ci/utils/build_docker_image.sh
@@ -2,6 +2,6 @@
 set -feu -o pipefail
 SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
 NTHREADS="$(nproc)"
-UBUNTU_RELEASE=${1:-focal}
+UBUNTU_RELEASE=${1:-groovy}
 
 docker build --rm=true --build-arg "NTHREADS=$NTHREADS" -t "keckj/hysop:${UBUNTU_RELEASE}" -f "${SCRIPT_DIR}/../docker_images/ubuntu/${UBUNTU_RELEASE}/Dockerfile" "${SCRIPT_DIR}/../.."
diff --git a/ci/utils/pull_docker_image.sh b/ci/utils/pull_docker_image.sh
index e73e452de24bad3f050af715fb8c875c74324d53..3545b0bad044031421b6c2a8850ee2b0f7efd327 100755
--- a/ci/utils/pull_docker_image.sh
+++ b/ci/utils/pull_docker_image.sh
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
 set -euf -o pipefail
-UBUNTU_RELEASE=${1:-focal}
+UBUNTU_RELEASE=${1:-groovy}
 docker logout
 docker pull "keckj/hysop:${UBUNTU_RELEASE}"
diff --git a/ci/utils/push_docker_image.sh b/ci/utils/push_docker_image.sh
index b36ade258042775cae7990aadb763c5b7a1747d1..1c697b5c77575d53baadb7e14819ff4e3db9a30d 100755
--- a/ci/utils/push_docker_image.sh
+++ b/ci/utils/push_docker_image.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 set -euf -o pipefail
-UBUNTU_RELEASE=${1:-focal}
+UBUNTU_RELEASE=${1:-groovy}
 docker login
 docker push "keckj/hysop:${UBUNTU_RELEASE}"
 docker logout
diff --git a/ci/utils/run_ci.sh b/ci/utils/run_ci.sh
index 0706ebb1251c5fd7e95d4d84bc7039de875bc957..a1a6191cd1d402d82bbb1dd529763371f869380f 100755
--- a/ci/utils/run_ci.sh
+++ b/ci/utils/run_ci.sh
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 set -feu -o pipefail
 SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
-UBUNTU_RELEASE=${1:-focal}
+UBUNTU_RELEASE=${1:-groovy}
 DOCKER_IMG="keckj/hysop:${UBUNTU_RELEASE}"
 CONTAINER_ID='hysop_build_and_test'
 
diff --git a/ci/utils/run_debug.sh b/ci/utils/run_debug.sh
index 39b1b64a914b06922a4175735c46a8413953f9e9..8c168dd4beaadbc5ba4026d8d09d91d46a00b154 100755
--- a/ci/utils/run_debug.sh
+++ b/ci/utils/run_debug.sh
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 set -feu -o pipefail
 SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
-UBUNTU_RELEASE=${1:-focal}
+UBUNTU_RELEASE=${1:-groovy}
 DOCKER_IMG="keckj/hysop:${UBUNTU_RELEASE}"
 CONTAINER_ID='hysop_build_and_debug'
 
diff --git a/ci/utils/run_docker_image.sh b/ci/utils/run_docker_image.sh
index 05cd63e1ae16fdcfaff076dcd3604cdac73a8381..4ca3ab273d323f34eb54b2209ab68cf9c5342d4a 100755
--- a/ci/utils/run_docker_image.sh
+++ b/ci/utils/run_docker_image.sh
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
 set -feu -o pipefail
 SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
-UBUNTU_RELEASE=${1:-focal}
+UBUNTU_RELEASE=${1:-groovy}
 docker run -it -v "${SCRIPT_DIR}/../..:/hysop:ro" "keckj/hysop:${UBUNTU_RELEASE}"
diff --git a/hysop/backend/device/opencl/opencl_array.py b/hysop/backend/device/opencl/opencl_array.py
index 41044931e5e26c538a067ef8cb88a283ca58debd..c6030546c176b45f2bb34cdeafef0af7c0421e4b 100644
--- a/hysop/backend/device/opencl/opencl_array.py
+++ b/hysop/backend/device/opencl/opencl_array.py
@@ -137,7 +137,7 @@ class OpenClArray(Array):
 
 
     def get(self, handle=False,
-            queue=None, ary=None, synchronize=True):
+            queue=None, ary=None):
         """
         Returns a HostArray, view or copy of this array.
         """
@@ -145,11 +145,10 @@ class OpenClArray(Array):
         if self.size==0:
             return None
         elif self.flags.forc:
-            host_array = self._call('get', queue=queue, ary=ary, synchronize=synchronize)
+                host_array = self._call('get', queue=queue, ary=ary)
         else:
             from hysop.backend.device.opencl.opencl_copy_kernel_launchers import \
                     OpenClCopyBufferRectLauncher
-            assert synchronize
             if (ary is not None):
                 host_array = ary
             else:
@@ -283,7 +282,7 @@ class OpenClArray(Array):
                 evt.wait()
                 return out.copy()
             else:
-                return evt
+                return (evt, out)
         else:
             super(OpenClArray, self).min(self, axis=axis, out=out,
                     queue=queue, synchronize=synchronize, **kwds)
@@ -305,7 +304,7 @@ class OpenClArray(Array):
                 evt.wait()
                 return out.copy()
             else:
-                return evt
+                return (evt, out)
         else:
             super(OpenClArray, self).max(self, axis=axis, out=out,
                     queue=queue, synchronize=synchronize, **kwds)
@@ -327,7 +326,7 @@ class OpenClArray(Array):
                 evt.wait()
                 return out.copy()
             else:
-                return evt
+                return (evt, out)
         else:
             super(OpenClArray, self).nanmin(self, axis=axis, out=out,
                     queue=queue, synchronize=synchronize, **kwds)
@@ -349,7 +348,7 @@ class OpenClArray(Array):
                 evt.wait()
                 return out.copy()
             else:
-                return evt
+                return (evt, out)
         else:
             super(OpenClArray, self).nanmax(self, axis=axis, out=out,
                     queue=queue, synchronize=synchronize, **kwds)
@@ -371,7 +370,7 @@ class OpenClArray(Array):
                 evt.wait()
                 return out.copy()
             else:
-                return evt
+                return (evt, out)
         else:
             super(OpenClArray, self).sum(self, axis=axis, out=out,
                     queue=queue, synchronize=synchronize, **kwds)
diff --git a/hysop/backend/device/opencl/opencl_array_backend.py b/hysop/backend/device/opencl/opencl_array_backend.py
index f69a94776ae6dc7ec043f618bfd10d7093a83d48..a9c231c03614d57cf78845cb4eb3558f86cfbabf 100644
--- a/hysop/backend/device/opencl/opencl_array_backend.py
+++ b/hysop/backend/device/opencl/opencl_array_backend.py
@@ -496,19 +496,20 @@ class OpenClArrayBackend(ArrayBackend):
             kl = OpenClCopyBufferRectLauncher.from_slices('buffer',
                     src=src, dst=dst)
             evt = kl(queue=queue)
-            if synchronize:
-                evt.wait()
-            else:
-                return evt
         elif isinstance(dst, Array):
-            return src.handle.get(queue=queue, ary=dst.handle, synchronize=synchronize)
+            (_, evt) = src.handle.get_async(queue=queue, ary=dst.handle)
         elif isinstance(dst, np.ndarray):
-            return src.handle.get(queue=queue, ary=dst, synchronize=synchronize)
+            (_, evt) = src.handle.get_async(queue=queue, ary=dst)
         else:
             msg = 'Unknown type to copy to ({}) for array of type {}.'
             msg = msg.format(dst.__class__.__name__, src.__class__.__name__)
             raise TypeError(msg)
 
+        if synchronize:
+            evt.wait()
+        else:
+            return evt
+
 
 # HELPER FUNCTIONS #
 ####################
@@ -851,10 +852,10 @@ class OpenClArrayBackend(ArrayBackend):
         Call and events:
             wait_for specify a list a event to wait prior applying the kernel.
 
-            If syncrhonize is set, this is a blocking opencl call and this functions returns
+            If synchronize is set, this is a blocking opencl call and this functions returns
             output arguments okargs as a tuple unless there is only one output.
 
-            If syncrhonize not set, this is a non blocking call and an event is returned in
+            If synchronize not set, this is a non blocking call and an event is returned in
             addition to the outputs as last argument.
 
             The returned event may not be used for profiling purposes, because it only
diff --git a/hysop/backend/device/opencl/operator/integrate.py b/hysop/backend/device/opencl/operator/integrate.py
index 8e0e76cbed3f50228ae8fb3d91d28e989e7415e0..6dd22e861b4ac622e4d480d63a396750a6d28cfc 100644
--- a/hysop/backend/device/opencl/operator/integrate.py
+++ b/hysop/backend/device/opencl/operator/integrate.py
@@ -17,10 +17,9 @@ class OpenClIntegrate(IntegrateBase, OpenClOperator):
     @debug
     def setup(self, work):
         super(OpenClIntegrate, self).setup(work)
-        if self.expr is None:
+        if (self.expr is None):
             self.sum_kernels = tuple(
-                self.dF.backend.sum(a=self.dF.data[i],
-                                    build_kernel_launcher=True, synchronize=False)
+                self.dF.backend.sum(a=self.dF.data[i], build_kernel_launcher=True, synchronize=False)
                 for i in range(self.dF.nb_components))
         else:
             from hysop.backend.device.codegen.base.variables import dtype_to_ctype
diff --git a/hysop/backend/host/host_array_backend.py b/hysop/backend/host/host_array_backend.py
index eaeee1e3605b6a97688118e54888d94642289ebf..4da33873efb5a94305d30d7fd63de905559aca40 100644
--- a/hysop/backend/host/host_array_backend.py
+++ b/hysop/backend/host/host_array_backend.py
@@ -161,8 +161,7 @@ class HostArrayBackend(ArrayBackend):
             queue = first_not_None(queue, dst.default_queue)
             from hysop.backend.device.opencl.opencl_copy_kernel_launchers \
                     import OpenClCopyBufferRectLauncher
-            kl = OpenClCopyBufferRectLauncher.from_slices('copyto',
-                    src=src, dst=dst)
+            kl = OpenClCopyBufferRectLauncher.from_slices('copyto', src=src, dst=dst)
             evt = kl(queue=queue)
             if synchronize:
                 evt.wait()
diff --git a/hysop/backend/host/python/operator/solenoidal_projection.py b/hysop/backend/host/python/operator/solenoidal_projection.py
index cd7ced9795b19c58ec81d6415f5f249aa4d46340..b635f1ca6152b7620dddc213e4bf76627713061c 100644
--- a/hysop/backend/host/python/operator/solenoidal_projection.py
+++ b/hysop/backend/host/python/operator/solenoidal_projection.py
@@ -11,80 +11,81 @@ from hysop.core.graph.graph import op_apply
 from hysop.operator.base.solenoidal_projection import SolenoidalProjectionOperatorBase
 from hysop.tools.numba_utils import make_numba_signature, prange
 
+def build_projection_filter(FIN, FOUT, K, KK, target=__DEFAULT_NUMBA_TARGET__):
+    assert len(FIN)==len(FOUT)==3
+    assert len(K)==len(KK)==9
+    args = FIN+K+KK+FOUT
+
+    signature, _ = make_numba_signature(*args)
+    layout =  '(m,n,p),(m,n,p),(m,n,p), '
+    layout += '(m),(n),(p), (m),(n),(p), (m),(n),(p), '
+    layout += '(m),(n),(p), (m),(n),(p), (m),(n),(p) '
+    layout += '-> (m,n,p),(m,n,p),(m,n,p)'
+
+    @nb.guvectorize([signature], layout,
+        target=target, nopython=True, cache=True)
+    def filter_projection_3d(Fin0, Fin1, Fin2,
+                             K00, K01, K02,
+                             K10, K11, K12,
+                             K20, K21, K22,
+                             KK00, KK01, KK02,
+                             KK10, KK11, KK12,
+                             KK20, KK21, KK22,
+                             Fout0, Fout1, Fout2):
+        for i in prange(0, Fin0.shape[0]):
+            for j in prange(0, Fin0.shape[1]):
+                for k in range(0, Fin0.shape[2]):
+                    F0 = Fin0[i,j,k]
+                    F1 = Fin1[i,j,k]
+                    F2 = Fin2[i,j,k]
+                    G0 = K00[i]*F0
+                    G1 = K11[j]*F1
+                    G2 = K22[k]*F2
+                    L0 = KK00[i]*F0
+                    L1 = KK11[j]*F1
+                    L2 = KK22[k]*F2
+                    if ((i!=0) or (j!=0) or (k!=0)):
+                        C0 = ((L0        + K10[i]*G1 + K20[i]*G2) / (KK00[i] + KK01[j] + KK02[k]))
+                        C1 = ((K01[j]*G0 + L1        + K21[j]*G2) / (KK10[i] + KK11[j] + KK12[k]))
+                        C2 = ((K02[k]*G0 + K12[k]*G1 + L2       ) / (KK20[i] + KK21[j] + KK22[k]))
+                    else:
+                        C0 = 0
+                        C1 = 0
+                        C2 = 0
+                    Fout0[i,j,k] = Fin0[i,j,k] - C0
+                    Fout1[i,j,k] = Fin1[i,j,k] - C1
+                    Fout2[i,j,k] = Fin2[i,j,k] - C2
+
+    return functools.partial(filter_projection_3d, *args)
+
+
+def make_div_filter(target, *args):
+    signature, _ = make_numba_signature(*args)
+    layout =  '(m,n,p), (m,n,p), (m,n,p), (m),(n),(p) -> (m,n,p)'
+
+    @nb.guvectorize([signature], layout,
+        target=target, nopython=True, cache=True)
+    def compute_div_3d(Fin0, Fin1, Fin2, K0, K1, K2, Fout):
+        for i in prange(0, Fin0.shape[0]):
+            for j in prange(0, Fin0.shape[1]):
+                for k in range(0, Fin0.shape[2]):
+                    Fout[i,j,k] = (K0[i]*Fin0[i,j,k] + K1[j]*Fin1[i,j,k] + K2[k]*Fin2[i,j,k])
+
+    return functools.partial(compute_div_3d, *args)
+
+
 class PythonSolenoidalProjection(SolenoidalProjectionOperatorBase, OpenClMappable, HostOperator):
     """
     Solves solenoidal projection (project a 3d field F such that div(F)=0),
     using spectral methods.
     """
 
-    @classmethod
-    def build_projection_filter(cls, FIN, FOUT, K, KK, target=__DEFAULT_NUMBA_TARGET__):
-        assert len(FIN)==len(FOUT)==3
-        assert len(K)==len(KK)==9
-        args = FIN+K+KK+FOUT
-
-        signature, _ = make_numba_signature(*args)
-        layout =  '(m,n,p),(m,n,p),(m,n,p), '
-        layout += '(m),(n),(p), (m),(n),(p), (m),(n),(p), '
-        layout += '(m),(n),(p), (m),(n),(p), (m),(n),(p) '
-        layout += '-> (m,n,p),(m,n,p),(m,n,p)'
-
-        @nb.guvectorize([signature], layout,
-            target=target, nopython=True, cache=True)
-        def filter_projection_3d(Fin0, Fin1, Fin2,
-                                 K00, K01, K02,
-                                 K10, K11, K12,
-                                 K20, K21, K22,
-                                 KK00, KK01, KK02,
-                                 KK10, KK11, KK12,
-                                 KK20, KK21, KK22,
-                                 Fout0, Fout1, Fout2):
-            for i in prange(0, Fin0.shape[0]):
-                for j in prange(0, Fin0.shape[1]):
-                    for k in range(0, Fin0.shape[2]):
-                        F0 = Fin0[i,j,k]
-                        F1 = Fin1[i,j,k]
-                        F2 = Fin2[i,j,k]
-                        G0 = K00[i]*F0
-                        G1 = K11[j]*F1
-                        G2 = K22[k]*F2
-                        L0 = KK00[i]*F0
-                        L1 = KK11[j]*F1
-                        L2 = KK22[k]*F2
-                        if ((i!=0) or (j!=0) or (k!=0)):
-                            C0 = ((L0        + K10[i]*G1 + K20[i]*G2) / (KK00[i] + KK01[j] + KK02[k]))
-                            C1 = ((K01[j]*G0 + L1        + K21[j]*G2) / (KK10[i] + KK11[j] + KK12[k]))
-                            C2 = ((K02[k]*G0 + K12[k]*G1 + L2       ) / (KK20[i] + KK21[j] + KK22[k]))
-                        else:
-                            C0 = 0
-                            C1 = 0
-                            C2 = 0
-                        Fout0[i,j,k] = Fin0[i,j,k] - C0
-                        Fout1[i,j,k] = Fin1[i,j,k] - C1
-                        Fout2[i,j,k] = Fin2[i,j,k] - C2
-
-        return functools.partial(filter_projection_3d, *args)
-
     def build_divergence_filters(self, target=__DEFAULT_NUMBA_TARGET__):
-        def make_div_filter(*args):
-            signature, _ = make_numba_signature(*args)
-            layout =  '(m,n,p), (m,n,p), (m,n,p), (m),(n),(p) -> (m,n,p)'
-
-            @nb.guvectorize([signature], layout,
-                target=target, nopython=True, cache=True)
-            def compute_div_3d(Fin0, Fin1, Fin2, K0, K1, K2, Fout):
-                for i in prange(0, Fin0.shape[0]):
-                    for j in prange(0, Fin0.shape[1]):
-                        for k in range(0, Fin0.shape[2]):
-                            Fout[i,j,k] = (K0[i]*Fin0[i,j,k] + K1[j]*Fin1[i,j,k] + K2[k]*Fin2[i,j,k])
-
-            return functools.partial(compute_div_3d, *args)
-
         if self.compute_divFin:
             FIN, K, DIV_IN = self.FIN, self.K, self.DIV_IN
             K = (K[0], K[4], K[8])
             args = FIN+K+DIV_IN
-            self.pre_filter_div = make_div_filter(*args)
+            self.pre_filter_div = make_div_filter(target, *args)
         else:
             self.pre_filter_div = None
 
@@ -92,7 +93,7 @@ class PythonSolenoidalProjection(SolenoidalProjectionOperatorBase, OpenClMappabl
             FOUT, K, DIV_OUT = self.FOUT, self.K, self.DIV_OUT
             K = (K[0], K[4], K[8])
             args = FOUT+K+DIV_OUT
-            self.post_filter_div = make_div_filter(*args)
+            self.post_filter_div = make_div_filter(target, *args)
         else:
             self.post_filter_div = None
 
@@ -101,7 +102,7 @@ class PythonSolenoidalProjection(SolenoidalProjectionOperatorBase, OpenClMappabl
         super(PythonSolenoidalProjection, self).setup(work=work)
         FIN, FOUT = self.FIN, self.FOUT
         K, KK = self.K, self.KK
-        self.filter_projection = self.build_projection_filter(FIN, FOUT, K, KK)
+        self.filter_projection = build_projection_filter(FIN, FOUT, K, KK)
         self.build_divergence_filters()
 
     @op_apply
diff --git a/hysop/core/arrays/array_backend.py b/hysop/core/arrays/array_backend.py
index 2d732eb89058097a3ccda8b01e7d2cb37f23169c..a349765ef0899bc8ebeb18a66c2d1aa7a39cd26f 100644
--- a/hysop/core/arrays/array_backend.py
+++ b/hysop/core/arrays/array_backend.py
@@ -223,8 +223,9 @@ class ArrayBackend(TaggedObject, metaclass=ABCMeta):
             args[i]  = self._arg(arg)
         for k,arg in kargs.items():
             kargs[k] = self._arg(arg)
-        if 'synchronize' in kargs:
-            kargs['async'] = not kargs.pop('synchronize')
+        if ('synchronize' in kargs):
+            msg='synchronize cannot be an argument to pyopencl.'
+            raise RuntimeError(msg)
         return tuple(args), kargs
 
     def _return(self, ret, **kargs):
diff --git a/hysop/numerics/fft/gpyfft_fft.py b/hysop/numerics/fft/gpyfft_fft.py
index abf665291be1bbe068306f78bc82658e1ea5a97a..da2466212090c2333cc90c4ee0a508d8f0c58a46 100644
--- a/hysop/numerics/fft/gpyfft_fft.py
+++ b/hysop/numerics/fft/gpyfft_fft.py
@@ -41,7 +41,7 @@ class GpyFFTPlan(OpenClFFTPlanI):
     Emit warnings when transform output has an unaligned buffer offset.
     """
 
-    DEBUG=False
+    DEBUG=True
 
     def __init__(self, cl_env, queue,
             in_array, out_array, axes,
@@ -361,11 +361,11 @@ Post callback source code:
             fake_output.shape, fake_output.dtype, estrides(fake_output),
             t_distance_in, t_distance_out, t_axes_in, t_axes_out, t_batchsize_in, t_batchsize_out,
             t_shape_in, t_shape_out, t_strides_in, t_strides_out,
-            plan.inplace, plan.precision, plan.layouts[0], plan.layouts[1],
+            plan.inplace, None, plan.layouts[0], plan.layouts[1],
             plan.shape, plan.strides_in, plan.strides_out, plan.batch_size,
             plan.distances[0], plan.distances[1],
             plan.scale_forward, plan.scale_backward,
-            self.pre_callback_src, self.post_callback_src)
+            self.pre_callback_src.decode(), self.post_callback_src.decode())
             print(msg)
 
         if (scaling == 'DEFAULT'):
@@ -416,8 +416,8 @@ Post callback source code:
         # Keep a reference to callback source code to prevent dangling const char* pointers.
         # Do not remove because clfft only get the pointer and gpyfft does not increase the
         # refcount of those strings, resulting in random code injection into the fft kernels.
-        pre_src  = pre_src.encode('ascii')
-        post_src = post_src.encode('ascii')
+        pre_src  = pre_src.encode('utf-8')
+        post_src = post_src.encode('utf-8')
         self.pre_callback_src  = pre_src
         self.post_callback_src = post_src
         # ***********************************************************************************
@@ -729,6 +729,7 @@ Post callback source code:
                                             temp_buffer=self.temp_buffer,
                                             wait_for_events=wait_for)
         evt = self.profile(events)
+        evt.wait()
         return evt
 
     def enqueue_arrays(self, *args, **kwds):
diff --git a/hysop/operator/poisson.py b/hysop/operator/poisson.py
index 2ab5a674f0c85ab1e76ea428c3426ce6637702db..8f4e995a915aad11c1d0aba37283f0ea57acefa7 100644
--- a/hysop/operator/poisson.py
+++ b/hysop/operator/poisson.py
@@ -3,7 +3,7 @@
 Poisson solver frontend.
 """
 from hysop.constants         import Implementation
-from hysop.tools.types       import check_instance
+from hysop.tools.types       import check_instance, first_not_None
 from hysop.tools.enum        import EnumFactory
 from hysop.tools.decorators  import debug
 from hysop.fields.continuous_field import Field
diff --git a/hysop/operator/solenoidal_projection.py b/hysop/operator/solenoidal_projection.py
index 9241414cb62228a55beafb6c359e0010568434d2..a60cec0765b0f972d8287ad55bbbf5f4a1f6b13c 100644
--- a/hysop/operator/solenoidal_projection.py
+++ b/hysop/operator/solenoidal_projection.py
@@ -4,7 +4,7 @@
 SolenoidalProjection solver frontend.
 """
 from hysop.constants         import Implementation
-from hysop.tools.types       import check_instance
+from hysop.tools.types       import check_instance, first_not_None
 from hysop.tools.enum        import EnumFactory
 from hysop.tools.decorators  import debug
 from hysop.fields.continuous_field import Field
diff --git a/hysop/operator/tests/test_solenoidal_projection.py b/hysop/operator/tests/test_solenoidal_projection.py
index a6ac30a8b69a11bfd43358e8af9e08445a0c026b..95274b94a165449c9af4fefab9f2081dcc087cd9 100644
--- a/hysop/operator/tests/test_solenoidal_projection.py
+++ b/hysop/operator/tests/test_solenoidal_projection.py
@@ -231,7 +231,7 @@ class TestSolenoidalProjectionOperator(object):
                              name='projection_{}'.format(str(impl).lower()))
             if impl is Implementation.PYTHON:
                 msg='   *Python FFTW: '
-                print(msg)
+                print(msg, end=' ')
                 yield SolenoidalProjection(**base_kwds)
             elif impl is Implementation.OPENCL:
                 msg='   *OpenCl CLFFT: '
@@ -239,7 +239,7 @@ class TestSolenoidalProjectionOperator(object):
                 for cl_env in iter_clenv():
                     msg='     |platform {}, device {}'.format(cl_env.platform.name.strip(),
                                                           cl_env.device.name.strip())
-                    print(msg)
+                    print(msg, end=' ')
                     yield SolenoidalProjection(cl_env=cl_env, **base_kwds)
                 msg='   *OpenCl FFTW: '
                 print(msg)
@@ -248,7 +248,7 @@ class TestSolenoidalProjectionOperator(object):
                     for cl_env in cpu_envs:
                         msg='     |platform {}, device {}'.format(cl_env.platform.name.strip(),
                                                                   cl_env.device.name.strip())
-                        print(msg)
+                        print(msg, end=' ')
                         yield SolenoidalProjection(cl_env=cl_env, enforce_implementation=False, **base_kwds)
             else:
                 msg='Unknown implementation to test {}.'.format(impl)
@@ -330,7 +330,7 @@ class TestSolenoidalProjectionOperator(object):
         for (out_buffers, ref_buffers, name) in zip((Uout, U0out, divUout, divU0out),
                                                     (Uref, U0ref, divUref, divU0ref),
                                                     ('U', 'U0', 'divU', 'divU0')):
-            print('| {}=('.format(name))
+            print('     | {}=('.format(name), end=' ')
             for i, (fout,fref) in enumerate(zip(out_buffers, ref_buffers)):
                 iname = '{}{}'.format(name,i)
                 assert fout.dtype == fref.dtype, iname
diff --git a/hysop/operator/tests/test_spectral_curl.py b/hysop/operator/tests/test_spectral_curl.py
index 59a2fac03f9cfd880954ad45a833881f91d147f6..1bc46c03ca48ec6cc368e5b9a9d300b3613cb501 100644
--- a/hysop/operator/tests/test_spectral_curl.py
+++ b/hysop/operator/tests/test_spectral_curl.py
@@ -166,10 +166,10 @@ class TestSpectralCurl(object):
         print(msg)
         print(' >Input analytic field is (truncated):')
         for (fin, fins) in zip(Fin.fields, analytic_expressions['Fin']):
-            print('  *{}(x) = {}'.format(fin.pretty_name, format_expr(fins)))
+            print('   *{}(x) = {}'.format(fin.pretty_name, format_expr(fins)))
         print(' >Expected output analytic field is:')
         for (fout, fouts) in zip(Fout.fields, analytic_expressions['Fout']):
-            print('  *{}(x) = {}'.format(fout.pretty_name, format_expr(fouts)))
+            print('   *{}(x) = {}'.format(fout.pretty_name, format_expr(fouts)))
         print(' >Testing all implementations:')
 
         implementations = SpectralCurl.implementations().keys()
@@ -181,15 +181,15 @@ class TestSpectralCurl(object):
                              name='curl_{}'.format(str(impl).lower()))
             if impl is Implementation.PYTHON:
                 msg = '   *Python FFTW: '
-                print(msg)
+                print(msg, end=' ')
                 yield SpectralCurl(**base_kwds)
             elif impl is Implementation.OPENCL:
                 msg = '   *OpenCl CLFFT: '
                 print(msg)
                 for cl_env in iter_clenv():
-                    msg = '     |platform {}, device {}'.format(cl_env.platform.name.strip(),
+                    msg = '     |platform {}, device {}:'.format(cl_env.platform.name.strip(),
                                                                 cl_env.device.name.strip())
-                    print(msg)
+                    print(msg, end=' ')
                     yield SpectralCurl(cl_env=cl_env, **base_kwds)
             else:
                 msg = 'Unknown implementation to test {}.'.format(impl)
@@ -269,7 +269,7 @@ class TestSpectralCurl(object):
                     except:
                         deps = 'inf'
                 if (deps < 10000):
-                    print('{}eps, '.format(deps),)
+                    print('{}eps, '.format(deps), end=' ')
                     continue
 
                 print()
diff --git a/hysop/operator/tests/test_spectral_derivative.py b/hysop/operator/tests/test_spectral_derivative.py
index 9fd43df963370bd024fed8188e1a3c6d13ad01ed..39a5236c52b02401ba6cb0c85c4777ab884265be 100644
--- a/hysop/operator/tests/test_spectral_derivative.py
+++ b/hysop/operator/tests/test_spectral_derivative.py
@@ -3,7 +3,7 @@ Test gradient of fields.
 """
 import random
 import itertools as it
-import sympt as sm
+import sympy as sm
 
 from hysop.constants import HYSOP_REAL, Backend, BoundaryCondition, BoxBoundaryCondition
 from hysop.methods import SpaceDiscretization
@@ -202,7 +202,7 @@ class TestSpectralDerivative(object):
                                  testing=True)
                 if impl is Implementation.PYTHON:
                     msg = '     |Python: '
-                    print(msg)
+                    print(msg, end=' ')
                     op = SpectralSpaceDerivative(**base_kwds)
                     yield op.to_graph()
                     print()
@@ -213,7 +213,7 @@ class TestSpectralDerivative(object):
                         msg = '        >platform {}, device {}:'.format(
                             cl_env.platform.name.strip(),
                             cl_env.device.name.strip())
-                        print(msg)
+                        print(msg, end=' ')
                         op = SpectralSpaceDerivative(cl_env=cl_env, **base_kwds)
                         yield op.to_graph()
                         print()
@@ -279,9 +279,9 @@ class TestSpectralDerivative(object):
                         deps = np.inf
                     if (deps <= 5*10**(nidx+2)):
                         if (j == 1):
-                            print('{}eps ({})'.format(deps, dinf))
+                            print('{}eps ({})'.format(deps, dinf), end=' ')
                         else:
-                            print('{}eps, '.format(deps))
+                            print('{}eps, '.format(deps), end=' ')
                         continue
 
                 print()
diff --git a/hysop/tools/handle.py b/hysop/tools/handle.py
index 072c78604a81e8ba73651cde9d961e9f0b11fc0f..ee553ede71a4aff924bec96de218b2da4e3d9e94 100644
--- a/hysop/tools/handle.py
+++ b/hysop/tools/handle.py
@@ -96,9 +96,6 @@ class TaggedObject(object, metaclass=ABCMeta):
         assert (tag_formatter is None) or callable(tag_formatter)
         tagged_cls = first_not_None(tagged_cls, cls)
 
-        if kwds:
-            print('\n  ' + '\n  '.join(map(str,cls.__mro__)))
-            print(kwds)
         obj = super(TaggedObject, cls).__new__(cls, **kwds)
         if tagged_cls in TaggedObject.__ids:
             obj.__tag_id = TaggedObject.__ids[tagged_cls]