# HG changeset patch
# User paugier <pierre.augier@ens-lyon.org>
# Date 1524553977 -7200
#      Tue Apr 24 09:12:57 2018 +0200
# Node ID a2ca4a0019fd8de3b52ff08a4c472b7433635144
# Parent  d75b3a04d8c0e274b666f62c7a4185ec6a323178
Prepare fluidfft/microbench

diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -18,6 +18,8 @@
 *.bbl
 *.blg
 
+*.so
+
 */*.pstats
 
 */.ipynb_checkpoints
diff --git a/fluidfft/microbench/Makefile b/fluidfft/microbench/Makefile
new file mode 100644
--- /dev/null
+++ b/fluidfft/microbench/Makefile
@@ -0,0 +1,56 @@
+
+perf: perfpythran
+
+
+clean: cleanfortran
+	rm -f *.so
+
+cleanfortran:
+	rm -f bench_proj_fortran.out
+
+code = 'func(c0, c1, c2, a0, a1, a2, a3)'
+end=as func, c0, c1, c2, a0, a1, a2, a3
+
+perfnumpy: proj_pythran.so
+	# numpy proj
+	@python -m perf timeit -s 'from bench import proj0 $(end)' $(code)
+	@# python -m perf timeit -s 'from bench import proj_loop0 $(end)' $(code)
+	# numpy proj_inplace
+	@python -m perf timeit -s 'from bench import proj_inplace0 $(end)' $(code)
+	@# python -m perf timeit -s 'from bench import proj_inplace_loop0 $(end)' $(code)
+
+perfpythran: proj_pythran.so
+	# pythran proj_loop
+	@python -m perf timeit -s 'from bench import proj_loop $(end)' $(code)
+	# pythran proj_inplace_loop
+	@python -m perf timeit -s 'from bench import proj_inplace_loop $(end)' $(code)
+	# pythran proj
+	@python -m perf timeit -s 'from bench import proj $(end)' $(code)
+	# pythran proj_inplace
+	@python -m perf timeit -s 'from bench import proj_inplace $(end)' $(code)
+
+
+perfnumba:
+	# numba proj
+	@python -m perf timeit -s 'from bench import proj_numba $(end)' $(code)
+	# numba proj_inplace
+	@python -m perf timeit -s 'from bench import proj_inplace_numba $(end)' $(code)
+	# numba proj_loop
+	@python -m perf timeit -s 'from bench import proj_loop_numba $(end)' $(code)
+	# numba proj_inplace_loop
+	@python -m perf timeit -s 'from bench import proj_inplace_loop_numba $(end)' $(code)
+
+
+proj_pythran.so: proj.py
+	pythran -v proj.py -march=native -o proj_pythran.so
+
+
+perffortran: bench_proj_fortran.out bench_proj_fortran_inplace.out
+	./bench_proj_fortran.out
+	./bench_proj_fortran_inplace.out
+
+bench_proj_fortran.out: bench_proj_fortran.f90
+	gfortran bench_proj_fortran.f90 -O3 -o bench_proj_fortran.out
+
+bench_proj_fortran_inplace.out: bench_proj_fortran_inplace.f90
+	gfortran bench_proj_fortran_inplace.f90 -O3 -o bench_proj_fortran_inplace.out
diff --git a/fluidfft/microbench/README.md b/fluidfft/microbench/README.md
new file mode 100644
--- /dev/null
+++ b/fluidfft/microbench/README.md
@@ -0,0 +1,52 @@
+
+Done on my (pa) laptop (see sys_info_laptop-pierre-kth.xml).
+
+I used:
+
+```
+sudo python -m perf system tune
+```
+
+## outplace
+
+### fortran with allocate/deallocate
+Mean Time = 22.1 ms
+
+### fortran without allocate/deallocate
+Mean Time = 11.3 ms
+
+### numpy proj
+Mean +- std dev: 66.6 ms +- 0.7 ms
+
+### pythran proj
+Mean +- std dev: 38.8 ms +- 3.1 ms
+
+### pythran proj_loop
+Mean +- std dev: 19.8 ms +- 1.4 ms
+
+### numba proj
+Mean +- std dev: 78.3 ms +- 2.0 ms
+
+### numba proj_loop
+Mean +- std dev: 26.5 ms +- 2.5 ms
+
+
+## inplace
+
+### fortran inplace
+Mean Time = 9.0 ms
+
+### numpy proj_inplace
+Mean +- std dev: 54.2 ms +- 2.4 ms
+
+### pythran proj_inplace
+Mean +- std dev: 18.7 ms +- 0.8 ms
+
+### pythran proj_inplace_loop
+Mean +- std dev: 8.60 ms +- 0.08 ms
+
+### numba proj_inplace
+Mean +- std dev: 65.9 ms +- 1.2 ms
+
+### numba proj_inplace_loop
+Mean +- std dev: 16.3 ms +- 1.5 ms
diff --git a/fluidfft/microbench/bench.py b/fluidfft/microbench/bench.py
new file mode 100644
--- /dev/null
+++ b/fluidfft/microbench/bench.py
@@ -0,0 +1,64 @@
+
+import numpy as np
+
+from proj import (
+    proj as proj0,
+    proj_loop as proj_loop0,
+    proj_inplace as proj_inplace0,
+    proj_inplace_loop as proj_inplace_loop0
+)
+
+from proj_pythran import (
+    proj,
+    proj_loop,
+    proj_inplace,
+    proj_inplace_loop
+)
+
+import proj_pythran
+
+from proj_numba import (
+    proj as proj_numba,
+    proj_loop as proj_loop_numba,
+    proj_inplace as proj_inplace_numba,
+    proj_inplace_loop as proj_inplace_loop_numba
+)
+
+
+assert hasattr(proj_pythran, '__pythran__')
+
+__all__ = [
+    'proj0',
+    'proj_loop0',
+    'proj_inplace0',
+    'proj_inplace_loop0',
+    'proj',
+    'proj_loop',
+    'proj_inplace',
+    'proj_inplace_loop',
+    'proj_numba',
+    'proj_loop_numba',
+    'proj_inplace_numba',
+    'proj_inplace_loop_numba',
+]
+
+
+n0 = n1 = n2 = 128
+
+shape = (n0, n1, n2//2+1)
+
+c0 = 1.3j + np.ones(shape, dtype=np.complex128)
+c1 = 2.3j + np.ones(shape, dtype=np.complex128)
+c2 = 3.3j + np.ones(shape, dtype=np.complex128)
+
+a0 = np.ones(shape)
+a1 = np.ones(shape)
+a2 = np.ones(shape)
+a3 = np.ones(shape)
+
+# JIT compiler
+for func in (proj_numba,
+             proj_loop_numba,
+             proj_inplace_numba,
+             proj_inplace_loop_numba):
+    func(c0, c1, c2, a0, a1, a2, a3)
diff --git a/fluidfft/microbench/bench_proj_fortran.f90 b/fluidfft/microbench/bench_proj_fortran.f90
new file mode 100644
--- /dev/null
+++ b/fluidfft/microbench/bench_proj_fortran.f90
@@ -0,0 +1,86 @@
+! benchmark of the function proj
+
+program benchmark_proj
+  implicit none
+  integer, parameter :: N0=128, N1=128, N2=64, N=100
+  double precision, allocatable :: vx(:,:,:,:), vy(:,:,:,:), vz(:,:,:,:)
+  double precision, allocatable :: kx(:,:,:), ky(:,:,:), kz(:,:,:)
+  double precision, allocatable :: inv_k_square_nozero(:,:,:)
+  double precision, allocatable :: res(:,:,:,:,:)
+  real :: start, finish, cumtime
+  integer :: i
+
+  allocate(vx(2, N2, N1, N0), vy(2, N2, N1, N0), vz(2, N2, N1, N0))
+  allocate(kx(N2, N1, N0), ky(N2, N1, N0), kz(N2, N1, N0))
+  allocate(inv_k_square_nozero(N2, N1, N0))
+
+  call random_number(vx)
+  call random_number(vy)
+  call random_number(vz)
+  call random_number(kx)
+  call random_number(ky)
+  call random_number(kz)
+  call random_number(inv_k_square_nozero)
+
+  cumtime = 0
+
+  print*, "This program make some calculations."
+  do i = 1, N
+     call cpu_time(start)
+     allocate(res(2, 3, N2, N1, N0))
+     call proj(res, vx, vy, vz, kx, ky, kz, inv_k_square_nozero, N0, N1, N2)
+     deallocate(res)
+     call cpu_time(finish)
+     cumtime = cumtime + finish - start
+  enddo
+  print '("Mean Time = ",f6.3," ms")', 1000*cumtime/N
+
+  cumtime = 0
+
+  print*, "without allocate/deallocate."
+  allocate(res(2, 3, N2, N1, N0))
+  do i = 1, N
+     call cpu_time(start)
+     call proj(res, vx, vy, vz, kx, ky, kz, inv_k_square_nozero, N0, N1, N2)
+     call cpu_time(finish)
+     cumtime = cumtime + finish - start
+  enddo
+  print '("Mean Time = ",f6.3," ms")', 1000*cumtime/N
+  deallocate(res)
+
+  deallocate(vx, vy, vz)
+  deallocate(kx, ky, kz)
+  deallocate(inv_k_square_nozero)
+end program benchmark_proj
+
+
+subroutine proj(res, vx, vy, vz, kx, ky, kz, inv_k_square_nozero, N0, N1, N2)
+
+  implicit none
+
+  ! Input/Output
+  integer, intent(in) :: N0, N1, N2
+  double precision, intent(in) :: vx(2, N2, N1, N0), vy(2, N2, N1, N0), vz(2, N2, N1, N0)
+  double precision, intent(in) :: kx(N2, N1, N0), ky(N2, N1, N0), kz(N2, N1, N0)
+  double precision, intent(in) :: inv_k_square_nozero(N2, N1, N0)
+  double precision, intent(out) :: res(2, 3, N2, N1, N0)
+
+  ! Locals
+  double precision :: tmp(2)
+  integer:: i, j, k
+
+  do k = 1, N0
+     do j = 1, N1
+        do i = 1, N2
+           tmp(1:2) = (kx(i,j,k) * vx(1:2,i,j,k) &
+                + ky(i,j,k) * vy(1:2,i,j,k) &
+                + kz(i,j,k) * vz(1:2,i,j,k)) * inv_k_square_nozero(i,j,k)
+
+           res(1:2,1,i,j,k) = vx(1:2,i,j,k) - kx(i,j,k) * tmp(1:2)
+           res(1:2,2,i,j,k) = vy(1:2,i,j,k) - ky(i,j,k) * tmp(1:2)
+           res(1:2,3,i,j,k) = vz(1:2,i,j,k) - kz(i,j,k) * tmp(1:2)
+        enddo
+     enddo
+  enddo
+
+end subroutine proj
diff --git a/fluidfft/microbench/bench_proj_fortran_inplace.f90 b/fluidfft/microbench/bench_proj_fortran_inplace.f90
new file mode 100644
--- /dev/null
+++ b/fluidfft/microbench/bench_proj_fortran_inplace.f90
@@ -0,0 +1,71 @@
+! benchmark of the function proj
+
+program benchmark_proj
+  implicit none
+  integer, parameter :: N0=128, N1=128, N2=64, N=100
+  double precision, allocatable :: vx(:,:,:,:), vy(:,:,:,:), vz(:,:,:,:)
+  double precision, allocatable :: kx(:,:,:), ky(:,:,:), kz(:,:,:)
+  double precision, allocatable :: inv_k_square_nozero(:,:,:)
+  real :: start, finish, cumtime
+  integer :: i
+
+  allocate(vx(2, N2, N1, N0), vy(2, N2, N1, N0), vz(2, N2, N1, N0))
+  allocate(kx(N2, N1, N0), ky(N2, N1, N0), kz(N2, N1, N0))
+  allocate(inv_k_square_nozero(N2, N1, N0))
+
+  call random_number(vx)
+  call random_number(vy)
+  call random_number(vz)
+  call random_number(kx)
+  call random_number(ky)
+  call random_number(kz)
+  call random_number(inv_k_square_nozero)
+
+  cumtime = 0
+
+  print*, "This program make some calculations."
+  do i = 1, N
+     call cpu_time(start)
+     call proj(vx, vy, vz, kx, ky, kz, inv_k_square_nozero, N0, N1, N2)
+     call cpu_time(finish)
+     cumtime = cumtime + finish - start
+  enddo
+  print '("Mean Time = ",f6.3," ms")', 1000*cumtime/N
+
+
+  deallocate(vx, vy, vz)
+  deallocate(kx, ky, kz)
+  deallocate(inv_k_square_nozero)
+end program benchmark_proj
+
+
+subroutine proj(vx, vy, vz, kx, ky, kz, inv_k_square_nozero, N0, N1, N2)
+
+  implicit none
+
+  ! Input/Output
+  integer, intent(in) :: N0, N1, N2
+  double precision, intent(inout) :: vx(2, N2, N1, N0), vy(2, N2, N1, N0), vz(2, N2, N1, N0)
+  double precision, intent(in) :: kx(N2, N1, N0), ky(N2, N1, N0), kz(N2, N1, N0)
+  double precision, intent(in) :: inv_k_square_nozero(N2, N1, N0)
+
+  ! Locals
+  double precision :: tmp(2)
+  integer:: i, j, k
+
+  do k = 1, N0
+     do j = 1, N1
+        do i = 1, N2
+           tmp(1:2) = (kx(i,j,k) * vx(1:2,i,j,k) &
+                       + ky(i,j,k) * vy(1:2,i,j,k) &
+                       + kz(i,j,k) * vz(1:2,i,j,k) &
+                      ) * inv_k_square_nozero(i,j,k)
+
+           vx(1:2,i,j,k) = vx(1:2,i,j,k) - kx(i,j,k) * tmp
+           vy(1:2,i,j,k) = vy(1:2,i,j,k) - ky(i,j,k) * tmp
+           vz(1:2,i,j,k) = vz(1:2,i,j,k) - kz(i,j,k) * tmp
+        enddo
+     enddo
+  enddo
+
+end subroutine proj
diff --git a/fluidfft/microbench/proj.py b/fluidfft/microbench/proj.py
new file mode 100644
--- /dev/null
+++ b/fluidfft/microbench/proj.py
@@ -0,0 +1,75 @@
+
+import numpy as np
+
+# pythran export proj(
+#     complex128[][][], complex128[][][], complex128[][][],
+#     float64[][][], float64[][][], float64[][][], float64[][][])
+
+def proj(vx, vy, vz, kx, ky, kz, inv_k_square_nozero):
+    tmp = (kx * vx + ky * vy + kz * vz) * inv_k_square_nozero
+
+    return (vx - kx * tmp,
+            vy - ky * tmp,
+            vz - kz * tmp)
+
+# pythran export proj_loop(
+#     complex128[][][], complex128[][][], complex128[][][],
+#     float64[][][], float64[][][], float64[][][], float64[][][])
+
+
+def proj_loop(vx, vy, vz, kx, ky, kz, inv_k_square_nozero):
+
+    rx = np.empty_like(vx)
+    ry = np.empty_like(vx)
+    rz = np.empty_like(vx)
+
+    n0, n1, n2 = kx.shape
+
+    for i0 in range(n0):
+        for i1 in range(n1):
+            for i2 in range(n2):
+                tmp = (kx[i0, i1, i2] * vx[i0, i1, i2]
+                       + ky[i0, i1, i2] * vy[i0, i1, i2]
+                       + kz[i0, i1, i2] * vz[i0, i1, i2]
+                ) * inv_k_square_nozero[i0, i1, i2]
+
+                rx[i0, i1, i2] = vx[i0, i1, i2] - kx[i0, i1, i2] * tmp
+                ry[i0, i1, i2] = vz[i0, i1, i2] - kx[i0, i1, i2] * tmp
+                rz[i0, i1, i2] = vy[i0, i1, i2] - kx[i0, i1, i2] * tmp
+
+    return rx, ry, rz
+
+
+# pythran export proj_inplace(
+#     complex128[][][], complex128[][][], complex128[][][],
+#     float64[][][], float64[][][], float64[][][], float64[][][])
+
+
+def proj_inplace(vx, vy, vz, kx, ky, kz, inv_k_square_nozero):
+    tmp = (kx * vx + ky * vy + kz * vz) * inv_k_square_nozero
+
+    vx -= kx * tmp
+    vy -= ky * tmp
+    vz -= kz * tmp
+
+
+# pythran export proj_inplace_loop(
+#     complex128[][][], complex128[][][], complex128[][][],
+#     float64[][][], float64[][][], float64[][][], float64[][][])
+
+
+def proj_inplace_loop(vx, vy, vz, kx, ky, kz, inv_k_square_nozero):
+
+    n0, n1, n2 = kx.shape
+
+    for i0 in range(n0):
+        for i1 in range(n1):
+                for i2 in range(n2):
+                    tmp = (kx[i0, i1, i2] * vx[i0, i1, i2]
+                           + ky[i0, i1, i2] * vy[i0, i1, i2]
+                           + kz[i0, i1, i2] * vz[i0, i1, i2]
+                    ) * inv_k_square_nozero[i0, i1, i2]
+
+                    vx[i0, i1, i2] -= kx[i0, i1, i2] * tmp
+                    vy[i0, i1, i2] -= ky[i0, i1, i2] * tmp
+                    vz[i0, i1, i2] -= kz[i0, i1, i2] * tmp
diff --git a/fluidfft/microbench/proj_numba.py b/fluidfft/microbench/proj_numba.py
new file mode 100644
--- /dev/null
+++ b/fluidfft/microbench/proj_numba.py
@@ -0,0 +1,63 @@
+
+import numpy as np
+
+from numba import jit
+
+@jit
+def proj(vx, vy, vz, kx, ky, kz, inv_k_square_nozero):
+    tmp = (kx * vx + ky * vy + kz * vz) * inv_k_square_nozero
+
+    return (vx - kx * tmp,
+            vy - ky * tmp,
+            vz - kz * tmp)
+
+
+@jit
+def proj_loop(vx, vy, vz, kx, ky, kz, inv_k_square_nozero):
+
+    rx = np.empty_like(vx)
+    ry = np.empty_like(vx)
+    rz = np.empty_like(vx)
+
+    n0, n1, n2 = kx.shape
+
+    for i0 in range(n0):
+        for i1 in range(n1):
+            for i2 in range(n2):
+                tmp = (kx[i0, i1, i2] * vx[i0, i1, i2]
+                       + ky[i0, i1, i2] * vy[i0, i1, i2]
+                       + kz[i0, i1, i2] * vz[i0, i1, i2]
+                ) * inv_k_square_nozero[i0, i1, i2]
+
+                rx[i0, i1, i2] = vx[i0, i1, i2] - kx[i0, i1, i2] * tmp
+                ry[i0, i1, i2] = vz[i0, i1, i2] - kx[i0, i1, i2] * tmp
+                rz[i0, i1, i2] = vy[i0, i1, i2] - kx[i0, i1, i2] * tmp
+
+    return rx, ry, rz
+
+
+@jit
+def proj_inplace(vx, vy, vz, kx, ky, kz, inv_k_square_nozero):
+    tmp = (kx * vx + ky * vy + kz * vz) * inv_k_square_nozero
+
+    vx -= kx * tmp
+    vy -= ky * tmp
+    vz -= kz * tmp
+
+
+@jit
+def proj_inplace_loop(vx, vy, vz, kx, ky, kz, inv_k_square_nozero):
+
+    n0, n1, n2 = kx.shape
+
+    for i0 in range(n0):
+        for i1 in range(n1):
+                for i2 in range(n2):
+                    tmp = (kx[i0, i1, i2] * vx[i0, i1, i2]
+                           + ky[i0, i1, i2] * vy[i0, i1, i2]
+                           + kz[i0, i1, i2] * vz[i0, i1, i2]
+                    ) * inv_k_square_nozero[i0, i1, i2]
+
+                    vx[i0, i1, i2] -= kx[i0, i1, i2] * tmp
+                    vy[i0, i1, i2] -= ky[i0, i1, i2] * tmp
+                    vz[i0, i1, i2] -= kz[i0, i1, i2] * tmp
diff --git a/fluidfft/microbench/sys_info_laptop-pierre-kth.xml b/fluidfft/microbench/sys_info_laptop-pierre-kth.xml
new file mode 100644
--- /dev/null
+++ b/fluidfft/microbench/sys_info_laptop-pierre-kth.xml
@@ -0,0 +1,112 @@
+<sys_info>
+  <software CC="gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609" MPI="mpirun
+            (Open MPI) 1.10.2" distro="Ubuntu 16.04 Xenial Xerus"
+            hostname="pierre-KTH" kernel="4.4.0-119-generic" system="Linux"/>  
+
+  <hardware address_sizes="36 bits physical, 48 bits virtual" arch="x86_64"
+            bogomips="5388.02" cache_size="4096 KB" cpu_MHz_actual="[3363.187,
+            3341.144, 3340.617, 3334.289]" cpu_MHz_current="3344.809"
+            cpu_MHz_max="3400.000" cpu_MHz_min="3400.000" cpu_name="Intel(R)
+            Core(TM) i7-2620M CPU @ 2.70GHz" nb_cores="2" nb_procs="4"
+            nb_siblings="4"/>  
+
+  <python compiler="GCC 4.8.2 20140120 (Red Hat 4.8.2-15)"
+          implementation="CPython" version="3.6.4">
+    <fluiddyn installed="True" local_path="/home/pierre/Dev/fluiddyn"
+              remote_path="https://paugier@bitbucket.org/fluiddyn/fluiddyn"
+              version="0.2.2"/>  
+
+    <fluidsim installed="True" local_path="/home/pierre/Dev/fluidsim"
+              remote_path="calpe = https://paugier@bitbucket.org/calpe/fluidsim"
+              version="0.1.1"/>  
+
+    <fluidlab installed="True" local_path="/home/pierre/Dev/fluidlab"
+              remote_path="https://paugier@bitbucket.org/fluiddyn/fluidlab"
+              version="0.0.3"/>  
+
+    <fluidimage installed="True" local_path="/home/pierre/Dev/fluidimage"
+                remote_path="https://paugier@bitbucket.org/fluiddyn/fluidimage"
+                version="0.0.2"/>  
+
+    <fluidfft installed="True" local_path="/home/pierre/Dev/fluidfft"
+              remote_path="https://paugier@bitbucket.org/fluiddyn/fluidfft"
+              version="0.2.2"/>  
+
+    <fluidcoriolis installed="True" local_path="/home/pierre/Dev/fluidcoriolis"
+                   remote_path="https://paugier@bitbucket.org/antcampagne/fluidcoriolis"
+                   version="0.0.0a0"/>  
+
+    <fluiddevops installed="False" local_path="" remote_path="" version=""/>  
+
+    <numpy installed="True"
+           local_path="/home/pierre/opt/miniconda3/lib/python3.6/site-packages/numpy"
+           remote_path="" version="1.13.3">
+      <system>
+        <lapack_opt define_macros="[('SCIPY_MKL_H', None), ('HAVE_CBLAS',
+                    None)]"
+                    include_dirs="['/home/pierre/opt/miniconda3/include']"
+                    libraries="['mkl_rt', 'pthread']"
+                    library_dirs="['/home/pierre/opt/miniconda3/lib']"/>  
+
+        <blas_opt define_macros="[('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]"
+                  include_dirs="['/home/pierre/opt/miniconda3/include']"
+                  libraries="['mkl_rt', 'pthread']"
+                  library_dirs="['/home/pierre/opt/miniconda3/lib']"/>  
+
+        <fftw/>  
+
+      </system>
+
+      <build>
+        <lapack_opt define_macros="[('HAVE_CBLAS', None)]" language="c"
+                    libraries="['openblas', 'openblas']"
+                    library_dirs="['/home/pierre/opt/miniconda3/lib']"/>  
+
+        <blas_opt define_macros="[('HAVE_CBLAS', None)]" language="c"
+                  libraries="['openblas', 'openblas']"
+                  library_dirs="['/home/pierre/opt/miniconda3/lib']"/>  
+
+      </build>
+
+    </numpy>
+
+    <cython installed="True"
+            local_path="/home/pierre/opt/miniconda3/lib/python3.6/site-packages"
+            remote_path="" version="0.26"/>  
+
+    <mpi4py installed="True"
+            local_path="/home/pierre/opt/miniconda3/lib/python3.6/site-packages/mpi4py"
+            remote_path="" version="3.0.0"/>  
+
+    <pythran installed="True" local_path="/home/pierre/Dev/pythran"
+             remote_path="git@github.com:fluiddyn/pythran.git"
+             version="0.8.4post0"/>  
+
+    <pyfftw installed="True"
+            local_path="/home/pierre/opt/miniconda3/lib/python3.6/site-packages/pyfftw"
+            remote_path="" version="0.10.3.dev0+e827cb5"/>  
+
+    <matplotlib installed="True"
+                local_path="/home/pierre/opt/miniconda3/lib/python3.6/site-packages/matplotlib"
+                remote_path="" version="2.1.1"/>  
+
+    <scipy installed="True"
+           local_path="/home/pierre/opt/miniconda3/lib/python3.6/site-packages/scipy"
+           remote_path="" version="0.19.1"/>  
+
+    <skimage installed="True"
+             local_path="/home/pierre/opt/miniconda3/lib/python3.6/site-packages/skimage"
+             remote_path="" version="0.13.0"/>  
+
+    <h5py installed="True"
+          local_path="/home/pierre/opt/miniconda3/lib/python3.6/site-packages/h5py"
+          remote_path="" version="2.7.1">
+      <config HDF5_version="1.10.1" MPI_enabled="False"
+              single_writer_multiple_reader_available="True"
+              virtual_dataset_available="True"/>  
+
+    </h5py>
+
+  </python>
+
+</sys_info>