From 9fba365cd74dae88b176f4bc14991e28e468a24c Mon Sep 17 00:00:00 2001
From: Jean-Baptiste Keck <Jean-Baptiste.Keck@imag.fr>
Date: Tue, 3 Nov 2020 19:54:02 +0100
Subject: [PATCH] fix fft tests

---
 CMakeLists.txt                                |  1 -
 ci/docker_images/ubuntu/groovy/Dockerfile     | 37 +++++++-------
 ci/scripts/test.sh                            | 48 +++++++++----------
 hysop/backend/device/opencl/clpeak.py         |  3 +-
 .../device/opencl/opencl_array_backend.py     |  2 +-
 hysop/core/checkpoints.py                     |  2 +-
 hysop/numerics/fft/gpyfft_fft.py              | 26 ++++++++++
 hysop/numerics/remesh/kernel_generator.py     |  2 +-
 hysop/numerics/remesh/remesh.py               |  2 +-
 hysop/tools/field_utils.py                    |  4 +-
 hysop/tools/hysop_ls.py                       |  3 +-
 hysop/tools/io_utils.py                       | 12 ++---
 requirements.txt                              |  1 -
 13 files changed, 82 insertions(+), 61 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index eb88db91c..3a7f7df9e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -145,7 +145,6 @@ find_python_module(sympy        REQUIRED)
 find_python_module(psutil       REQUIRED)
 find_python_module(cpuinfo      REQUIRED)
 find_python_module(gmpy2        REQUIRED)
-find_python_module(subprocess32 REQUIRED)
 find_python_module(editdistance REQUIRED)
 find_python_module(portalocker  REQUIRED)
 find_python_module(tee          REQUIRED)
diff --git a/ci/docker_images/ubuntu/groovy/Dockerfile b/ci/docker_images/ubuntu/groovy/Dockerfile
index e2a1f6f42..20099148b 100644
--- a/ci/docker_images/ubuntu/groovy/Dockerfile
+++ b/ci/docker_images/ubuntu/groovy/Dockerfile
@@ -62,13 +62,8 @@ RUN cd /tmp && \
  rm -rf /tmp/hdf5-*
 RUN CC="${MPICC}" HDF5_MPI="ON" HDF5_VERSION="1.10.6" HDF5_DIR="${MPI_ROOT}" pip3.8 install --upgrade --no-binary=h5py h5py
 
-# llvm + numba + llvmlite
-RUN apt-get install -y llvm-8-dev libclang-8-dev clang-8
-ENV LLVM_CONFIG=llvm-config-8
-RUN pip3.8 install --upgrade numba llvmlite
-
 # other python packages (standard primefac package does not support python3)
-RUN pip3.8 install --upgrade scipy sympy matplotlib gmpy2 psutil py-cpuinfo Mako subprocess32 editdistance portalocker colors.py tee pycairo argparse_color_formatter networkx pyvis zarr numcodecs jsonpickle memory-tempfile
+RUN pip3.8 install --upgrade scipy sympy matplotlib gmpy2 psutil py-cpuinfo Mako editdistance portalocker colors.py tee pycairo argparse_color_formatter networkx pyvis zarr numcodecs jsonpickle memory-tempfile
 RUN pip3.8 install git+git://github.com/keckj/primefac-fork@master 
 
 # patchelf
@@ -84,27 +79,35 @@ RUN cd /tmp && \
 
 # Intel experimental OpenCL platform with SYCL support (2020-10)
 # /!\`Newest version 2020.11 does not work 
-ENV LD_LIBRARY_PATH "/opt/intel/oclcpuexp/x64:${LD_LIBRARY_PATH}"
+ENV TBBROOT="/opt/intel/oclcpuexp/x64"
+ENV LD_LIBRARY_PATH "${TBBROOT}:${LD_LIBRARY_PATH}"
 RUN mkdir -p /opt/intel/oclcpuexp && \
  wget https://github.com/intel/llvm/releases/download/2020-06/oclcpuexp-2020.10.6.0.4_rel.tar.gz && \
  tar -xvzf oclcpuexp-*.tar.gz && \
  mv x64/ /opt/intel/oclcpuexp/ && \
  mv clbltfnshared.rtl /opt/intel/oclcpuexp/ && \
- rm -rf *.rtl oclcpuexp-* && \
+ rm -f *.rtl && \
+ rm -rf oclcpuexp-* && \
  wget https://github.com/oneapi-src/oneTBB/releases/download/v2020.3/tbb-2020.3-lin.tgz && \
  tar -xvzf tbb-*.tgz && \
- mv tbb/lib/intel64/gcc4.8/* /opt/intel/oclcpuexp/x64/ && \
+ mv tbb/lib/intel64/gcc4.8/* "${TBBROOT}/" && \
  rm -f /usr/local/lib/libOpenCL.so && \
  rm -f /usr/local/lib/libOpenCL.so && \
  rm -f /usr/local/lib/libOpenCL.so.1 && \
  rm -f /usr/local/lib/libOpenCL.so.2.0 && \
- ln -s /opt/intel/oclcpuexp/x64/libOpenCL.so /usr/local/lib/libOpenCL.so && \
- ln -s /opt/intel/oclcpuexp/x64/libOpenCL.so.1 /usr/local/lib/libOpenCL.so.1 && \
- ln -s /opt/intel/oclcpuexp/x64/libOpenCL.so.2.0 /usr/local/lib/libOpenCL.so.2.0 && \
+ ln -s "${TBBROOT}/libOpenCL.so" /usr/local/lib/libOpenCL.so && \
+ ln -s "${TBBROOT}/libOpenCL.so.1" /usr/local/lib/libOpenCL.so.1 && \
+ ln -s "${TBBROOT}/libOpenCL.so.2.0" /usr/local/lib/libOpenCL.so.2.0 && \
  mkdir -p /etc/OpenCL/vendors && \
- echo /opt/intel/oclcpuexp/x64/libintelocl.so > /etc/OpenCL/vendors/intel_expcpu.icd && \
+ echo "${TBBROOT}/libintelocl.so" > /etc/OpenCL/vendors/intel_expcpu.icd && \
  rm -rf /tmp/tbb*
 
+# llvm + numba + llvmlite
+RUN apt-get update && \
+ apt-get install -y llvm-10-dev libclang-10-dev clang-10
+ENV LLVM_CONFIG=llvm-config-10
+RUN pip3.8 install --upgrade numba llvmlite
+
 # clinfo 2.2.18 (2018)
 RUN cd /tmp && \
  wget https://github.com/Oblomov/clinfo/archive/2.2.18.04.06.tar.gz && \
@@ -134,8 +137,8 @@ RUN cd /tmp && \
  cd pyopencl && \
  git checkout v2020.2.2 && \
  git submodule update --init && \
- CFLAGS='-O0 -g -UNDEBUG' python3.8 configure.py && \
- CFLAGS='-O0 -g -UNDEBUG' make && \
+ python3.8 configure.py && \
+ make && \
  pip3.8 install --upgrade . && \
  cd - && \
  rm -Rf /tmp/pyopencl
@@ -166,10 +169,12 @@ RUN cd /tmp && \
  cd - && \
  rm -Rf /tmp/clFFT
 
-# gpyFFT
+# gpyFFT, we need to fix a segfault on weakref.finalize(plan)
+# clFFT plans are destroyed when atexit(clFFT.teardown) is called
 RUN cd /tmp && \
  git clone https://github.com/geggo/gpyfft.git && \
  cd gpyfft && \
+ sed 's#finalize(self, _destroy_plan, self.plan)##' -i gpyfft/gpyfftlib.pyx && \
  pip3.8 install . && \
  cd - && \
  rm -Rf /tmp/gpyfft
diff --git a/ci/scripts/test.sh b/ci/scripts/test.sh
index 6a72fbdf4..19c9a1029 100755
--- a/ci/scripts/test.sh
+++ b/ci/scripts/test.sh
@@ -68,7 +68,7 @@ fi
 
 export PYTHONPATH="${INSTALL_DIR}/lib/python3.8/site-packages:${INSTALL_DIR}"
 export MPLBACKEND='cairo'
-export HYSOP_VERBOSE=1
+export HYSOP_VERBOSE=0
 export HYSOP_DEBUG=0
 export HYSOP_PROFILE=0
 export HYSOP_KERNEL_DEBUG=0
@@ -115,29 +115,29 @@ example_test() {
 }
 
 if [ "$RUN_TESTS" = true ]; then
-    #hysop_test "core/arrays/tests/test_array.py"
-    #hysop_test "core/graph/tests/test_graph.py"
-    #hysop_test "fields/tests/test_fields.py"
-    #hysop_test "numerics/tests/test_fft.py"
-    #hysop_test "operator/tests/test_analytic.py"
-    #hysop_test "operator/tests/test_transpose.py"
-    #hysop_test "operator/tests/test_fd_derivative.py"
-    #hysop_test "operator/tests/test_absorption.py"
-    #hysop_test "operator/tests/test_penalization.py"
-    #hysop_test "operator/tests/test_velocity_correction.py"
-    #hysop_test "operator/tests/test_restriction_filter.py"
-    #hysop_test "operator/tests/test_directional_advection.py"
-    #hysop_test "operator/tests/test_directional_diffusion.py"
-    #hysop_test "operator/tests/test_directional_stretching.py"
-    #hysop_test "operator/tests/test_custom_symbolic.py"
-    #hysop_test "operator/tests/test_spectral_derivative.py"
-    #hysop_test "operator/tests/test_spectral_curl.py"
-    #hysop_test "operator/tests/test_diffusion.py"
-    #hysop_test "operator/tests/test_poisson.py"
-    #hysop_test "operator/tests/test_solenoidal_projection.py"
-    #hysop_test "operator/tests/test_poisson_curl.py"
-    #${HYSOP_DIR}/fields/tests/test_cartesian.sh
-    ${HYSOP_DIR}/core/tests/test_checkpoint.sh
+    hysop_test "core/arrays/tests/test_array.py"
+    hysop_test "core/graph/tests/test_graph.py"
+    hysop_test "fields/tests/test_fields.py"
+    hysop_test "numerics/tests/test_fft.py"
+    hysop_test "operator/tests/test_analytic.py"
+    hysop_test "operator/tests/test_transpose.py"
+    hysop_test "operator/tests/test_fd_derivative.py"
+    hysop_test "operator/tests/test_absorption.py"
+    hysop_test "operator/tests/test_penalization.py"
+    hysop_test "operator/tests/test_velocity_correction.py"
+    hysop_test "operator/tests/test_restriction_filter.py"
+    hysop_test "operator/tests/test_directional_advection.py"
+    hysop_test "operator/tests/test_directional_diffusion.py"
+    hysop_test "operator/tests/test_directional_stretching.py"
+    hysop_test "operator/tests/test_custom_symbolic.py"
+    hysop_test "operator/tests/test_spectral_derivative.py"
+    hysop_test "operator/tests/test_spectral_curl.py"
+    hysop_test "operator/tests/test_diffusion.py"
+    hysop_test "operator/tests/test_poisson.py"
+    hysop_test "operator/tests/test_solenoidal_projection.py"
+    hysop_test "operator/tests/test_poisson_curl.py"
+    ${HYSOP_DIR}/fields/tests/test_cartesian.sh
+    #${HYSOP_DIR}/core/tests/test_checkpoint.sh
 fi
 
 if [ "${RUN_LONG_TESTS}" = true ]; then
diff --git a/hysop/backend/device/opencl/clpeak.py b/hysop/backend/device/opencl/clpeak.py
index 836d72b4e..f0e5f929b 100644
--- a/hysop/backend/device/opencl/clpeak.py
+++ b/hysop/backend/device/opencl/clpeak.py
@@ -3,8 +3,7 @@ try:
 except:
    import pickle
 
-import tempfile, re, os, warnings, gzip, portalocker
-import subprocess32 as subprocess
+import tempfile, re, os, warnings, gzip, portalocker, subprocess
 from xml.dom import minidom
 from hysop import vprint
 from hysop.tools.decorators import requires_cmd
diff --git a/hysop/backend/device/opencl/opencl_array_backend.py b/hysop/backend/device/opencl/opencl_array_backend.py
index a9c231c03..aafa8cbff 100644
--- a/hysop/backend/device/opencl/opencl_array_backend.py
+++ b/hysop/backend/device/opencl/opencl_array_backend.py
@@ -1564,7 +1564,7 @@ class OpenClArrayBackend(ArrayBackend):
                 a = a.handle
 
             array = self._call(clArray.to_device, queue=queue, ary=a,
-                                    synchronize=synchronize, array_queue=array_queue)
+                                    async_=(not synchronize), array_queue=array_queue)
         else:
             msg='Unknown type to convert from {}.'
             msg=msg.format(acls)
diff --git a/hysop/core/checkpoints.py b/hysop/core/checkpoints.py
index 12e7fd33b..ca69863e7 100644
--- a/hysop/core/checkpoints.py
+++ b/hysop/core/checkpoints.py
@@ -560,7 +560,7 @@ class CheckpointHandler(object):
                 else:
                     assert ((mesh.compute_resolution == array.chunks).all()
                          or (mesh.is_at_right_boundary*(mesh.proc_shape>1)).any())
-                    local_data = dfield.compute_data[0].get()
+                    local_data = dfield.compute_data[0].get().handle
                     global_slices = mesh.global_compute_slices
                     array[global_slices] = local_data # ok, every process writes to an independent data blocks
 
diff --git a/hysop/numerics/fft/gpyfft_fft.py b/hysop/numerics/fft/gpyfft_fft.py
index 5c97c1d15..efa7072b5 100644
--- a/hysop/numerics/fft/gpyfft_fft.py
+++ b/hysop/numerics/fft/gpyfft_fft.py
@@ -34,6 +34,8 @@ from hysop.backend.device.opencl.opencl_kernel_launcher import trace_kernel, pro
 class HysopGpyFftWarning(HysopWarning):
     pass
 
+# fix a weird bug in clfft/gpyfft
+keep_plans_ref = []
 
 class GpyFFTPlan(OpenClFFTPlanI):
     """
@@ -43,6 +45,21 @@ class GpyFFTPlan(OpenClFFTPlanI):
 
     DEBUG=False
 
+    def __new__(cls, cl_env, queue,
+            in_array, out_array, axes,
+            scaling=None, scale_by_size=None,
+            fake_input=None, fake_output=None,
+            callback_kwds=None,
+            direction_forward=True,
+            hardcode_twiddles=False,
+            warn_on_unaligned_output_offset=True,
+            warn_on_allocation=True,
+            error_on_allocation=False,
+            **kwds):
+        obj = super(GpyFFTPlan, cls).__new__(cls)
+        keep_plans_ref.append(obj)
+        return obj
+
     def __init__(self, cl_env, queue,
             in_array, out_array, axes,
             scaling=None, scale_by_size=None,
@@ -699,6 +716,7 @@ Post callback source code:
     def profile(self, events):
         for (i,evt) in enumerate(events):
             profile_kernel(None, evt, self._apply_msg_template.format(i))
+            evt.wait()
         return evt
 
     def enqueue(self, queue=None, wait_for=None):
@@ -723,6 +741,8 @@ Post callback source code:
                                             temp_buffer=self.temp_buffer,
                                             wait_for_events=wait_for)
         else:
+            #print(self.in_array)
+            #print(self.out_array)
             events = self.plan.enqueue_transform((queue,),
                                             (in_data,), (out_data),
                                             direction_forward=direction_forward,
@@ -939,6 +959,7 @@ class GpyR2RPlan(GpyFFTPlan):
 class GpyDCTIPlan(GpyR2RPlan):
 
     def __init__(self, in_array, axes, **kwds):
+        #print('\ncreate DCT-I plan {}'.format(id(self)))
         (dtype, ctype, shape, axis, N) = self.prepare_r2r(in_array, axes)
         rshape = mk_shape(shape, axis, 2*N-2)
         cshape = mk_shape(shape, axis, N)
@@ -947,6 +968,9 @@ class GpyDCTIPlan(GpyR2RPlan):
         super(GpyDCTIPlan, self).__init__(in_array=in_array, axes=axes,
                 fake_input=fake_input, fake_output=fake_output, **kwds)
 
+    #def __del__(self):
+        #print('\ndelete DCT-I plan {}'.format(id(self)))
+
     def pre_offset_callback(self, N, fp, offset_input_pointer, **kwds):
         pre = \
         '''{fp} pre_callback(const __global void* input, const uint offset,
@@ -973,6 +997,8 @@ class GpyDCTIPlan(GpyR2RPlan):
         return post, None
 
 
+
+
 class GpyDCTIIPlan(GpyR2RPlan):
     def __init__(self, in_array, axes, **kwds):
         (dtype, ctype, shape, axis, N) = self.prepare_r2r(in_array, axes)
diff --git a/hysop/numerics/remesh/kernel_generator.py b/hysop/numerics/remesh/kernel_generator.py
index 118a15245..7333e96b2 100644
--- a/hysop/numerics/remesh/kernel_generator.py
+++ b/hysop/numerics/remesh/kernel_generator.py
@@ -308,7 +308,7 @@ class SymmetricKernelGenerator(object):
                 print('False')
                 print('  Building linear system...')
         #polynom symbolic variable
-        x = sm.abc.x
+        x = sm.Symbol('x')
 
         #build Ms*(deg+1) symbolic coefficients (polynomial unknowns)
         coeffs = []
diff --git a/hysop/numerics/remesh/remesh.py b/hysop/numerics/remesh/remesh.py
index 5a96511c9..a53b27952 100644
--- a/hysop/numerics/remesh/remesh.py
+++ b/hysop/numerics/remesh/remesh.py
@@ -44,7 +44,7 @@ class RemeshKernel(Kernel):
             'Only lambda remesh kernels are supported.'
         if remesh in ('M4', 'M8'):
             # given M4 or M8 kernels
-            x = sm.abc.x
+            x = sm.Symbol('x')
             if remesh == 'M4':
                 M4 = (sm.Poly((1/sm.Rational(6))*((2-x)**3-4*(1-x)**3), x),
                       sm.Poly((1/sm.Rational(6))*((2-x)**3), x))
diff --git a/hysop/tools/field_utils.py b/hysop/tools/field_utils.py
index 20e335d20..db2503671 100644
--- a/hysop/tools/field_utils.py
+++ b/hysop/tools/field_utils.py
@@ -185,7 +185,7 @@ ljoin_fn = lambda x: ''.join(to_str(x)) if (x is not None) else ''
 bdivide_fn = lambda x,y: '{}/{}'.format(x,y)
 pdivide_fn = lambda x,y: '{}/{}'.format(*to_str(x,y))
 vdivide_fn = lambda x,y: '{}__{}'.format(x,y)
-ldivide_fn = lambda x,y: '\dfrac<LBRACKET>{}<RBRACKET><LBRACKET>{}<RBRACKET>'.format(x,y)
+ldivide_fn = lambda x,y: r'\dfrac<LBRACKET>{}<RBRACKET><LBRACKET>{}<RBRACKET>'.format(x,y)
 
 
 class DifferentialStringFormatter(object):
@@ -246,7 +246,7 @@ class DifferentialStringFormatter(object):
                             bcomp_fn=bcomp_fn, pcomp_fn=pcomp_fn, vcomp_fn=vcomp_fn, lcomp_fn=lcomp_fn,
                             blp='(', plp='', vlp='', llp='',
                             brp=')', prp='', vrp='',  lrp='',
-                            bd='d', pd=partial, vd='d', ld='<LBRACKET>\partial<RBRACKET>',
+                            bd='d', pd=partial, vd='d', ld=r'<LBRACKET>\partial<RBRACKET>',
                             dpow=1, varpow=1, components=None,
                             trigp=3, fsc=True):
         assert (varpow != 0)
diff --git a/hysop/tools/hysop_ls.py b/hysop/tools/hysop_ls.py
index 60b11a493..7a3fe1838 100755
--- a/hysop/tools/hysop_ls.py
+++ b/hysop/tools/hysop_ls.py
@@ -1,6 +1,5 @@
 
-import sys, os, argparse, tempfile, warnings
-import subprocess32 as subprocess
+import sys, os, argparse, tempfile, warnings, subprocess
 
 # default caching directory
 tmp = tempfile.gettempdir()
diff --git a/hysop/tools/io_utils.py b/hysop/tools/io_utils.py
index 148aabff2..acbb03930 100755
--- a/hysop/tools/io_utils.py
+++ b/hysop/tools/io_utils.py
@@ -8,16 +8,8 @@
 * :class:`~XMF`, tools to prepare/write xmf files.
 
 """
-import os
-import h5py
-import psutil
-import warnings
-import tempfile
-import socket
-import shutil
-import atexit
+import os, sys, psutil, warnings, tempfile, socket, shutil, atexit, subprocess
 import numpy as np
-import subprocess32 as subprocess
 from collections import namedtuple
 from inspect import getouterframes, currentframe
 from re import findall
@@ -149,6 +141,7 @@ class IO(object):
             msg = 'No suitable caching directory was found in {}.'
             msg = msg.format(candidates)
             raise RuntimeError(msg)
+        cpath = '{}/python{}_{}'.format(cpath, sys.version_info.major, sys.version_info.minor)
         if not os.path.exists(cpath):
             try:
                 if mpi.main_rank == 0:
@@ -223,6 +216,7 @@ class IO(object):
         -------
             a list of strings
         """
+        import h5py
         hdf_file = h5py.File(filename, 'r')
         keys = hdf_file.keys()
         hdf_file.close()
diff --git a/requirements.txt b/requirements.txt
index 962592003..cd3fd9be3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,7 +6,6 @@ h5py
 psutil
 py-cpuinfo
 gmpy2
-subprocess32
 editdistance
 portalocker
 tee
-- 
GitLab