diff --git a/python/SConscript b/python/SConscript
index 355cd311..a90bc7b8 100644
--- a/python/SConscript
+++ b/python/SConscript
@@ -1,59 +1,58 @@
 from os.path import abspath
 from distutils.version import StrictVersion
 from subprocess import check_output, STDOUT
 
 Import('main_env')
 
 env_swig = main_env.Clone(
     tools=['swig'],
-    SWIG='swig3.0',
     SHLIBPREFIX='',
 )
 
 if env_swig['SWIGVERSION'] is None:
     print "Could not find swig version"
     print env_swig.Dictionary()
     print env_swig.Environment
     Exit(1)
 
 if StrictVersion(env_swig['SWIGVERSION']) < StrictVersion("3.0"):
     print "Swig version {} is not supported by tamaas".format(env_swig['SWIGVERSION'])
     Exit(1)
 
 # Check user's prefered version
 version_out = check_output([main_env['py_exec'], "--version"], stderr=STDOUT).split(' ')
 version = StrictVersion(version_out[-1])
 python3 = version >= StrictVersion("3.0")
 print("Building wrapper for python version {}".format(version))
 
 # Run code below to get versions from user preference and not scons
 versions_script = """
 from __future__ import print_function
 import distutils.sysconfig as dsys
 from numpy.distutils.misc_util import get_numpy_include_dirs as numpy_dirs
 
 print(dsys.get_python_inc())
 for d in numpy_dirs():
     print(d)"""
 
 includes = check_output([main_env['py_exec'], "-c", versions_script]).split('\n')
 
 env_swig.AppendUnique(CPPPATH=includes)
 env_swig.AppendUnique(SWIGPATH=['$CPPPATH'])
 env_swig.AppendUnique(SWIGFLAGS=['-python', '-c++'])
 
 if python3:
     env_swig.AppendUnique(SWIGFLAGS=['-py3'])
 
 verbose = main_env['verbose']
 if not verbose:
     env_swig.AppendUnique(SWIGFLAGS=['-w325', '-w315'])
     env_swig.AppendUnique(CXXFLAGS=['-Wno-maybe-uninitialized'])  # for some warning in wrapper code
 
 
 env_swig.SharedLibrary(
     target='_tamaas.so',
     source=['tamaas.i'],
     LIBS=['Tamaas'],
     RPATH=[abspath('../src')]
 )
diff --git a/site_scons/site_init.py b/site_scons/site_init.py
index 2c4de46d..4b09fcb0 100644
--- a/site_scons/site_init.py
+++ b/site_scons/site_init.py
@@ -1,42 +1,101 @@
+from SCons.Script import *
+from os.path import *
+
+import os
+
+
 def fftw(env):
-   """A Tool to search for fftw headers and libraries"""
-
-   if env.GetOption('clean'): return
-   env.SetDefault(FFTW_VERSION='3')
-   env.SetDefault(FFTW_LIBRARY_WISH=[])
-
-   print("Building for fftw version {}".format(env['FFTW_VERSION']))
-
-   if 'FFTW_INCLUDE_DIR' in env:
-      env.AppendUnique(CPPPATH=env['FFTW_INCLUDE_DIR'])
-
-   if 'FFTW_LIBRARY_DIR' in env:
-      env.AppendUnique(LIBPATH=env['FFTW_LIBRARY_DIR'])
-
-   version = env['FFTW_VERSION']
-   if version == "2":
-      lib_names = {'main':'fftw'}
-      inc_names = ['fftw.h']
-   else:
-      lib_names = {'main':'fftw3','thread':'fftw3_threads','omp':'fftw3_omp'}
-      inc_names = ['fftw3.h']
-
-   try:
-      libs = [lib_names[i] for i in env['FFTW_LIBRARY_WISH']]
-   except:
-      raise SCons.Errors.StopError(
-         'Incompatible wishlist {0} from version {1}'.format(
-            env['FFTW_LIBRARY_WISH'], env['FFTW_VERSION']))
-
-   env.AppendUnique(LIBS=libs)
-   if version == "2":
-      env.Append(LIBS='m')
-
-   conf = Configure(env)
-   if not conf.CheckLibWithHeader(libs, inc_names, 'c++'):
-      raise SCons.Errors.StopError(
-         'Failed to find libraries {0} or '
-         'headers {1}.'.format(str(lib_names), str(inc_names)))
-   
-   env = conf.Finish()
-   
+    """A Tool to search for fftw headers and libraries"""
+
+    if env.GetOption('clean'):
+        return
+    env.SetDefault(FFTW_VERSION='3')
+    env.SetDefault(FFTW_LIBRARY_WISH=[])
+
+    print("Building for fftw version {}".format(env['FFTW_VERSION']))
+
+    if 'FFTW_INCLUDE_DIR' in env:
+        env.AppendUnique(CPPPATH=env['FFTW_INCLUDE_DIR'])
+
+    if 'FFTW_LIBRARY_DIR' in env:
+        env.AppendUnique(LIBPATH=env['FFTW_LIBRARY_DIR'])
+
+    version = env['FFTW_VERSION']
+    if version == "2":
+        lib_names = {'main': 'fftw'}
+        inc_names = ['fftw.h']
+    else:
+        lib_names = {'main': 'fftw3',
+                     'thread': 'fftw3_threads',
+                     'omp': 'fftw3_omp'}
+        inc_names = ['fftw3.h']
+
+    try:
+        libs = [lib_names[i] for i in env['FFTW_LIBRARY_WISH']]
+    except:
+        raise SCons.Errors.StopError(
+           'Incompatible wishlist {0} from version {1}'.format(
+             env['FFTW_LIBRARY_WISH'], env['FFTW_VERSION']))
+
+    env.AppendUnique(LIBS=libs)
+    if version == "2":
+        env.Append(LIBS='m')
+
+    conf = Configure(env)
+    if not conf.CheckLibWithHeader(libs, inc_names, 'c++'):
+        raise SCons.Errors.StopError(
+           'Failed to find libraries {0} or '
+           'headers {1}.'.format(str(lib_names), str(inc_names)))
+
+    env = conf.Finish()
+
+
+def criterion(env):
+    """A tool to configure for Criterion (test suite)"""
+    if env.GetOption('clean'):
+        return
+
+    env.AppendUnique(CPPPATH=[Dir("#third-party/Criterion/include")],
+                     LIBPATH=[abspath(str(Dir("#third-party/Criterion/build")))])
+    conf = Configure(env)
+    if not conf.CheckLibWithHeader('criterion',
+                                   'criterion/criterion.h',
+                                   'c++'):
+        raise SCons.Errors.StopError(
+            'Failed to find library Criterion or criterion.h header in third-party')
+    env = conf.Finish()
+
+
+def tamaas(env):
+    """Sets correct environement variables for Tamaas.
+    - 'TAMAAS_PATH' is list of potential tamaas repositories
+    - 'TAMAAS_BUILD_TYPE' is the build type of tamaas (release, debug, profiling)"""
+    if env.GetOption("clean"):
+        return
+
+    try:
+        build_type = env['TAMAAS_BUILD_TYPE']
+    except:
+        build_type = "release"
+
+    if 'TAMAAS_PATH' not in env:
+        print "Please set the 'TAMAAS_PATH' variable in your scons environment"
+        Exit(1)
+
+    tm_path = env['TAMAAS_PATH']
+    include_dir = tm_path + '/src'
+    subdirs = "core model bem surface".split(" ")
+    include_dirs = [abspath(join(include_dir, x)) for x in subdirs]
+    lib_dir = join(tm_path, 'build-{}/src'.format(build_type))
+
+    env.AppendUnique(CPPPATH = include_dirs)
+    env.AppendUnique(LIBPATH = [abspath(lib_dir)])
+    env.AppendUnique(RPATH   = [abspath(lib_dir)])
+    env.AppendUnique(CXXFLAGS = ["-std=c++14"])
+
+    conf = Configure(env)
+    if not conf.CheckLibWithHeader("Tamaas", "tamaas.hh", language="CXX"):
+        raise SCons.Errors.StopError(
+            "Tamaas ({}) not found in {}".format(build_type, abspath(tm_path)))
+    env['TAMAAS_PATH'] = abspath(tm_path)
+    env = conf.Finish()
diff --git a/src/core/iterator.hh b/src/core/iterator.hh
index 6f864d0f..8ac90bdd 100644
--- a/src/core/iterator.hh
+++ b/src/core/iterator.hh
@@ -1,190 +1,192 @@
 /**
  *
  * @author Lucas Frérot <lucas.frerot@epfl.ch>
  *
  * @section LICENSE
  *
  * Copyright (©)  2016 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Tamaas is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Tamaas is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Tamaas. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #ifndef __ITERATOR_HH__
 #define __ITERATOR_HH__
 /* -------------------------------------------------------------------------- */
 #include "tamaas.hh"
 #include <vector>
 #include <utility>
+#include <iterator>
 #include <cstddef>
 /* -------------------------------------------------------------------------- */
 __BEGIN_TAMAAS__
 
 namespace iterator_ {
 
 template <typename T>
 class iterator {
 public:
   typedef T value_type;
   typedef std::ptrdiff_t difference_type;
   typedef T * pointer;
   typedef T & reference;
+  typedef std::random_access_iterator_tag iterator_category;
 
 /* -------------------------------------------------------------------------- */
 /* Constructors/Destructors                                                   */
 /* -------------------------------------------------------------------------- */
   /// constructor
   iterator(pointer data,
 	   std::size_t start,
 	   ptrdiff_t offset):
     data(data),
     index(start),
     step(offset),
     access_offset(0) {}
   /// copy constructor
   iterator(const iterator & o):
     data(o.data),
     index(o.index),
     step(o.step),
     access_offset(o.access_offset) {}
   /// destructor
   ~iterator() {}
   /// copy operator
   iterator & operator=(const iterator & o) {
     data = o.data;
     index = o.index;
     step = o.step;
     access_offset = o.access_offset;
     return *this;
   }
 
 protected:
   /// Compute access offset for data from index
   inline void computeAccessOffset() {
     access_offset = index;
   }
 
 public:
   /// dereference iterator
   inline reference operator*() {
     return data[access_offset];
   }
 
   /// increment with given offset
   inline iterator & operator+=(difference_type a) {
     index += a*step;
     computeAccessOffset();
     return *this;
   }
 
   /// increment iterator
   inline iterator & operator++() {
     *this += 1;
     return *this;
   }
 
   /// comparison
   inline bool operator<(const iterator & a) const {
     return index < a.index;
   }
 
   /// inequality
   inline bool operator!=(const iterator & a) const {
     return index != a.index;
   }
 
   /// equality
   inline bool operator==(const iterator & a) const {
     return index == a.index;
   }
 
   /// needed for OpenMP range calculations
   inline difference_type operator-(const iterator & a) const {
     return (index - a.index)/step;
   }
 
 protected:
   T * data;
   std::size_t index;
   difference_type step;
   difference_type access_offset;
 };
 
 
 template <typename T>
 class iterator_view : iterator<T> {
 public:
   typedef T value_type;
   typedef std::ptrdiff_t difference_type;
   typedef T * pointer;
   typedef T & reference;
 
   /// Constructor
   iterator_view(pointer data,
 		std::size_t start,
 		ptrdiff_t offset,
 		std::vector<UInt> strides,
 		std::vector<UInt> sizes):
     iterator<T>(data, start, offset),
     strides(strides),
     n(sizes),
     tuple(strides.size()) {}
 
   iterator_view(const iterator_view & o):
     iterator<T>(o),
     strides(o.strides),
     n(o.n),
     tuple(o.tuple) {}
 
   iterator_view & operator=(const iterator_view & o) {
     iterator<T>::operator=(o);
     strides = o.strides;
     n = o.n;
     tuple = o.tuple;
   }
 
 protected:
   void computeAccessOffset() {
     UInt index_copy = this->index;
 
     this->tuple.back() = index_copy % this->n.back();
     index_copy -= this->tuple.back();
     index_copy /= this->n.back();
 
     /// Computing tuple from index
     for (UInt d = this->tuple.size()-2 ; d > 0 ; d--) {
       this->tuple[d] = index_copy % this->n[d];
       index_copy -= this->tuple[d];
       index_copy /= this->n[d];
     }
 
     this->tuple[0] = index_copy;
 
     this->access_offset = 0;
     for (UInt i = 0 ; i < this->tuple.size() ; ++i)
       this->access_offset += this->tuple[i] * this->strides[i];
   }
 
   std::vector<UInt> strides;
   std::vector<UInt> n;
   std::vector<UInt> tuple;
 };
 
 } // end namespace iterator_
 
 __END_TAMAAS__
 /* -------------------------------------------------------------------------- */
 #endif // __ITERATOR_HH__
diff --git a/tests/SConscript b/tests/SConscript
index 844950bd..b02e9f83 100644
--- a/tests/SConscript
+++ b/tests/SConscript
@@ -1,30 +1,44 @@
 from __future__ import print_function
-from os.path import join
+from os.path import join, abspath
 
 
 Import('main_env')
 
-test_env = main_env.Clone(PRINT_CMD_LINE_FUNC=main_env['gen_print']("Copying", "red", main_env))
+print("Environment for tests")
+test_env = main_env.Clone(
+    tools=[criterion],
+    PRINT_CMD_LINE_FUNC=main_env['gen_print']("Copying", "red", main_env))
 
 test_files = Split("""
 run_tests.sh
 test_hertz_pressure.py
 test_westergaard.py
 test_patch_westergaard.py
 test_surface.py
 test_autocorrelation.py
 test_hertz_disp.py
 test_hertz_kato.py
 test_hertz_adhesion.py
 test_saturated_pressure.py
 test_fftransform.py
 test_bem_grid.py
 test_flood_fill.py
 """)
 
 src_dir = "#/tests"
 build_dir = 'build-' + main_env['build_type'] + '/tests'
 
 for file in test_files:
     source = join(src_dir, file)
     test_env.Command(file, source, Copy("$TARGET", "$SOURCE"))
+
+
+test_env.AppendUnique(LIBS=['Tamaas'],
+                      LIBPATH=[abspath('build-' + main_env['build_type'] + '/src')])
+
+cpp_test_files = Split("""
+test_grid.cpp
+""")
+
+for file in cpp_test_files:
+    test_env.Program(file)
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index f00f38b9..8bffa35c 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1,70 +1,96 @@
 #!/bin/bash
 
 #########################################################################
 
 function test_output {
   name=$( basename $1 .verified )
   echo "Testing $name output"
   echo -n "------------ "
   diff $name.out $name.verified >/dev/null 2>&1
   return $?
 }
 
 #########################################################################
 
 function test_return {
   name=$( basename $1 .py )
   echo "Testing $name.py"
   echo -n "------------ "
   PYTHONPATH=../python python $name.py >$name.out 2>$name.err
   return $?
 }
 
 #########################################################################
 
+function test_exec {
+  echo "Testing $1"
+  echo -n "------------ "
+  ./$1 >/dev/null 2>&1
+  return $?
+}
+#########################################################################
+
 tamaas_path=$(PYTHONPATH=../python python -c 'import tamaas; print(tamaas)' | cut -d "'" -f 4 )
 tamaas_lib_path=$(ldd ../python/_tamaas.so | grep -e 'libTamaas.so' | cut -d " " -f 3)
 
 echo "Tamaas test suite"
 echo "================="
 echo ""
 echo "importing tamaas from $tamaas_path"
 echo "importing library from $tamaas_lib_path"
 echo ""
 
 n_tests=0
 passed_tests=0
+
+for test_file in test_*; do
+    # Filtering files with an extension
+    if [[ ! $test_file =~ test_[^\.]+$ ]]; then
+	continue
+    fi
+
+    ((n_tests++))
+    test_exec $test_file
+    result=$?
+    if [ $result -ne 0 ]; then
+        echo "failure"
+    else
+        echo "success"
+        ((passed_tests++))
+    fi
+done
+
 for test_file in test_*.py; do
     ((n_tests++))
     test_return $test_file
     result=$?
     if [ $result -ne 0 ]; then
         echo "failure"
     else
         echo "success"
         ((passed_tests++))
     fi
 done
 
 for test_file in test_*.verified; do
   # In case no .verified files exist
   if [ $test_file = "test_*.verified" ]; then
     break
   fi
 
   ((n_tests++))
   test_output $test_file
   result=$?
   if [ $result -ne 0 ]; then
     echo "failure"
   else
     echo "success"
     ((passed_tests++))
   fi
 done
 
 failed_tests=$((n_tests - passed_tests))
 echo ""
 echo "Test results :"
 echo "    - passed $passed_tests/$n_tests"
 echo "    - failed $failed_tests/$n_tests"
diff --git a/tests/test_grid.cpp b/tests/test_grid.cpp
new file mode 100644
index 00000000..a3cf2d0b
--- /dev/null
+++ b/tests/test_grid.cpp
@@ -0,0 +1,147 @@
+/**
+ *
+ * @author Lucas Frérot <lucas.frerot@epfl.ch>
+ *
+ * @section LICENSE
+ *
+ * Copyright (©)  2016 EPFL  (Ecole Polytechnique  Fédérale de
+ * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
+ * Solides)
+ *
+ * Tamaas is free  software: you can redistribute it and/or  modify it under the
+ * terms  of the  GNU Lesser  General Public  License as  published by  the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * Tamaas is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
+ * details.
+ *
+ * You should  have received  a copy  of the GNU  Lesser General  Public License
+ * along with Tamaas. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+/* -------------------------------------------------------------------------- */
+#include <array>
+#include <algorithm>
+#include <numeric>
+#include <criterion/criterion.h>
+#include "grid.hh"
+
+using namespace tamaas;
+
+void tamaas_init() {
+  initialize();
+}
+
+void tamaas_teardown() {
+  finalize();
+}
+
+/* -------------------------------------------------------------------------- */
+
+TestSuite(grid_creation, .init = tamaas_init, .fini = tamaas_teardown);
+
+// Testing 1D creation
+Test(grid_creation, creation_1d) {
+  Grid<Real, 1> grid({5}, 2);
+  std::array<UInt, 1> correct_size = {5};
+  cr_assert(grid.sizes() == correct_size, "Wrong sizes");
+
+  std::array<UInt, 2> correct_strides = {2, 1};
+  cr_assert(grid.getStrides() == correct_strides, "Wrong strides");
+}
+
+// Testing 2D creation
+Test(grid_creation, creation_2d) {
+  Grid<Real, 2> grid({5, 2}, 3);
+  std::array<UInt, 2> correct_size = {5, 2};
+  cr_assert(grid.sizes() == correct_size, "Wrong sizes");
+
+  std::array<UInt, 3> correct_strides = {6, 3, 1};
+  cr_assert(grid.getStrides() == correct_strides, "Wrong strides");
+}
+
+// Testing 3D creation
+Test(grid_creation, creation_3d) {
+  Grid<Real, 3> grid({8, 5, 2}, 3);
+  std::array<UInt, 3> correct_size = {8, 5, 2};
+  cr_assert(grid.sizes() == correct_size, "Wrong sizes");
+
+  std::array<UInt, 4> correct_strides = {30, 15, 3, 1};
+  cr_assert(grid.getStrides() == correct_strides, "Wrong strides");
+}
+
+/* -------------------------------------------------------------------------- */
+
+TestSuite(grid_iterators, .init = tamaas_init, .fini = tamaas_teardown);
+
+// Testing iterators in STL function iota
+Test(grid_iterators, iota) {
+  constexpr UInt N = 20;
+  Grid<UInt, 1> grid({N}, 1);
+  std::iota(grid.begin(), grid.end(), 0);
+
+  const UInt * p = grid.getInternalData();
+  for (UInt i = 0 ; i < N ; ++i)
+    cr_assert(p[i] == i, "Iota fill failed");
+}
+
+// Testing filling grid with OpenMP loop
+Test(grid_iterators, openmp_loops) {
+  Grid<UInt, 1> grid({20}, 1);
+
+#pragma omp parallel for
+  for (auto it = grid.begin() ; it < grid.end() ; ++it) {
+    UInt i = it - grid.begin();
+    *it = i;
+  }
+
+  std::vector<UInt> correct(20);
+  std::iota(correct.begin(), correct.end(), 0);
+
+  cr_assert(std::mismatch(correct.begin(), correct.end(), grid.begin(), grid.end())
+	    == std::make_pair(correct.end(), grid.end()),
+	    "Fill using OpenMP loop failed");
+}
+
+/* -------------------------------------------------------------------------- */
+
+TestSuite(grid_operators, .init = tamaas_init, .fini = tamaas_teardown);
+
+// Testing scalar simple loop-based operators
+Test(grid_operators, loop_operators) {
+  Grid<UInt, 1> grid({20}, 1);
+  grid = 1;
+  cr_expect(std::all_of(grid.begin(), grid.end(), [](UInt x){return x == 1;}),
+	    "Assignement operator failed");
+  grid += 1;
+  cr_expect(std::all_of(grid.begin(), grid.end(), [](UInt x){return x == 2;}),
+	    "Plus-equal operator failed");
+}
+
+// Testing loop-based functions with reductions
+Test(grid_operators, stats) {
+  constexpr UInt N = 20;
+  Grid<Real, 1> grid({N}, 1);
+  std::iota(grid.begin(), grid.end(), 0);
+
+  auto b = grid.begin(), e = grid.end();
+  Real min = *std::min_element(b, e);
+  Real max = *std::max_element(b, e);
+  Real acc = std::accumulate(b, e, 0);
+  Real mea = acc / N;
+  Real var = 35;
+
+  cr_expect(grid.min() == min,
+	    "Minimum function failed");
+  cr_expect(grid.max() == max,
+	    "Maximum function failed");
+  cr_expect(grid.sum() == acc,
+	    "Sum function failed");
+  cr_expect(grid.mean() == mea,
+	    "Mean function failed");
+  cr_expect(grid.var() == var,
+	    "Var function failed");
+}