diff --git a/python/wrap/test_features.cpp b/python/wrap/test_features.cpp
index 6d4c0ae2..a9a075d3 100644
--- a/python/wrap/test_features.cpp
+++ b/python/wrap/test_features.cpp
@@ -1,93 +1,96 @@
 /**
  * @file
  *
  * @author Lucas Frérot <lucas.frerot@epfl.ch>
  *
  * @section LICENSE
  *
  * Copyright (©)  2017 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 "kelvin.hh"
 #include "mindlin.hh"
+#include "boussinesq.hh"
 #include "model.hh"
 #include "model_type.hh"
 #include "volume_potential.hh"
 #include "isotropic_hardening.hh"
 #include "wrap.hh"
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_TAMAAS__
 
 namespace wrap {
 
 template <template <model_type, UInt> class KOp, model_type type,
           UInt tensor_order>
 void wrapKOp(const std::string& basename, py::module& mod) {
   constexpr UInt dim = model_type_traits<type>::dimension;
   std::stringstream str;
   str << basename << tensor_order;
   py::class_<KOp<type, tensor_order>>(mod, str.str().c_str())
       .def(py::init<Model*>())
       .def("apply",
            [](const KOp<type, tensor_order>& engine, Grid<Real, dim>& in,
               Grid<Real, dim>& out) { engine.apply(in, out); });
 }
 
 template <model_type type>
 void wrapIsotropicHardening(py::module& mod) {
   constexpr UInt dim = model_type_traits<type>::dimension;
   py::class_<IsotropicHardening<type>>(mod, "IsotropicHardening")
       .def(py::init<Model*, Real, Real>())
       .def_property("h", &IsotropicHardening<type>::getHardeningModulus,
                     &IsotropicHardening<type>::setHardeningModulus)
       .def_property("sigma_0", &IsotropicHardening<type>::getYieldStress,
                     &IsotropicHardening<type>::setYieldStress)
       .def("computeStress",
            [](IsotropicHardening<type>& iso, Grid<Real, dim>& stress,
               const Grid<Real, dim>& strain,
               const Grid<Real, dim>& strain_increment) {
              iso.template computeStress<false>(stress, strain, strain_increment);
            })
       .def("computeStressUpdate",
            [](IsotropicHardening<type>& iso, Grid<Real, dim>& stress,
               const Grid<Real, dim>& strain,
               const Grid<Real, dim>& strain_increment) {
              iso.template computeStress<true>(stress, strain, strain_increment);
            });
 }
 
 /// Wrap temporary features for testing
 void wrapTestFeatures(py::module& mod) {
   auto test_module = mod.def_submodule("_test_features");
   test_module.doc() =
       "Module for testing new features.\n"
       "DISCLAIMER: this API is subject to frequent and unannounced changes "
       "and should **not** be relied upon!";
   wrapKOp<Kelvin, model_type::volume_2d, 2>("Kelvin_", test_module);
   wrapKOp<Kelvin, model_type::volume_2d, 3>("Kelvin_", test_module);
   wrapKOp<Kelvin, model_type::volume_2d, 4>("Kelvin_", test_module);
   wrapKOp<Mindlin, model_type::volume_2d, 3>("Mindlin_", test_module);
   wrapKOp<Mindlin, model_type::volume_2d, 4>("Mindlin_", test_module);
+  wrapKOp<Boussinesq, model_type::volume_2d, 0>("Boussinesq_", test_module);
+  wrapKOp<Boussinesq, model_type::volume_2d, 1>("Boussinesq_", test_module);
 
   wrapIsotropicHardening<model_type::volume_2d>(test_module);
 }
 }
 
 __END_TAMAAS__
diff --git a/src/SConscript b/src/SConscript
index 32569169..6389279d 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -1,116 +1,117 @@
 import os
 Import('main_env')
 
 
 def prepend(path, list):
     return [os.path.join(path, x) for x in list]
 
 
 env = main_env
 
 # Core
 core_list = """
 fft_plan_manager.cpp
 fftransform.cpp
 fftransform_fftw.cpp
 grid.cpp
 grid_hermitian.cpp
 statistics.cpp
 surface.cpp
 tamaas.cpp
 legacy_types.cpp
 loop.cpp
 """.split()
 core_list = prepend('core', core_list)
 core_list.append('tamaas_info.cpp')
 
 # Lib roughcontact
 generator_list = """
 surface_generator.cpp
 surface_generator_filter.cpp
 surface_generator_filter_fft.cpp
 isopowerlaw.cpp
 """.split()
 generator_list = prepend('surface', generator_list)
 
 # Lib PERCOLATION
 percolation_list = """
 flood_fill.cpp
 """.split()
 percolation_list = prepend('percolation', percolation_list)
 
 # BEM PERCOLATION
 bem_list = """
 bem_kato.cpp
 bem_polonski.cpp
 bem_gigi.cpp
 bem_gigipol.cpp
 bem_penalty.cpp
 bem_uzawa.cpp
 bem_fft_base.cpp
 bem_functional.cpp
 bem_meta_functional.cpp
 elastic_energy_functional.cpp
 exponential_adhesion_functional.cpp
 squared_exponential_adhesion_functional.cpp
 maugis_adhesion_functional.cpp
 complimentary_term_functional.cpp
 bem_grid.cpp
 bem_grid_polonski.cpp
 bem_grid_kato.cpp
 bem_grid_teboulle.cpp
 bem_grid_condat.cpp
 """.split()
 bem_list = prepend('bem', bem_list)
 
 # Model
 model_list = """
 model.cpp
 model_factory.cpp
 model_type.cpp
 model_template.cpp
 be_engine.cpp
 westergaard.cpp
 elastic_functional.cpp
 meta_functional.cpp
 adhesion_functional.cpp
 elasto_plastic_model.cpp
 volume_potential.cpp
 kelvin.cpp
 mindlin.cpp
+boussinesq.cpp
 isotropic_hardening.cpp
 """.split()
 model_list = prepend('model', model_list)
 
 # Solvers
 solvers_list = """
 contact_solver.cpp
 polonsky_keer_rey.cpp
 """.split()
 solvers_list = prepend('solvers', solvers_list)
 
 # GPU API
 gpu_list = """
 fftransform_cufft.cpp
 """.split()
 gpu_list = prepend('gpu', gpu_list)
 
 # Assembling total list
 rough_contact_list = \
   core_list + generator_list + percolation_list + model_list + solvers_list + bem_list
 
 # Adding GPU if needed
 if env['backend'] == 'cuda':
     rough_contact_list += gpu_list
 
 # Generating dependency files
 # env.AppendUnique(CXXFLAGS=['-MMD'])
 
 # for file_name in rough_contact_list:
 #     obj = file_name.replace('.cpp', '.os')
 #     dep_file_name = file_name.replace('.cpp', '.d')
 #     env.SideEffect(dep_file_name, obj)
 #     env.ParseDepends(dep_file_name)
 
 libTamaas = env.SharedLibrary('Tamaas', rough_contact_list)
 Export('libTamaas')
diff --git a/src/model/boussinesq.cpp b/src/model/boussinesq.cpp
new file mode 100644
index 00000000..5e87d389
--- /dev/null
+++ b/src/model/boussinesq.cpp
@@ -0,0 +1,133 @@
+/**
+ * @file
+ *
+ * @author Lucas Frérot <lucas.frerot@epfl.ch>
+ *
+ * @section LICENSE
+ *
+ * Copyright (©)  2017 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 "boussinesq.hh"
+#include "influence.hh"
+#include "kelvin_helper.hh"
+#include "model.hh"
+/* -------------------------------------------------------------------------- */
+__BEGIN_TAMAAS__
+/* -------------------------------------------------------------------------- */
+
+namespace detail {
+template <model_type type, typename T>
+class BoussinesqHelper {
+  using boussinesq_t = T;
+  using trait = model_type_traits<type>;
+  static constexpr UInt dim = trait::dimension;
+  static constexpr UInt bdim = trait::boundary_dimension;
+
+public:
+  BoussinesqHelper(const T& boussinesq, Real y_3, Real cutoff)
+      : boussinesq(boussinesq), y_3(y_3), cutoff(cutoff) {}
+
+  inline void applyIntegral(GridHermitian<Real, bdim>& out,
+                            GridHermitian<Real, bdim>& source,
+                            const Grid<Real, bdim>& wavevectors) const {
+    Loop::stridedLoop(
+        [&](typename KelvinTrait<T>::out_t&& out_local,
+            VectorProxy<Complex, dim>&& traction,
+            VectorProxy<const Real, bdim>&& q) {
+          // Cutoff
+          if (-q.l2norm() * std::abs(y_3) < std::log(cutoff))
+            return;
+
+          out_local +=
+              boussinesq.applyU0(traction, q) *
+              influence::KelvinIntegrator<0>::g0<true>(q.l2norm() * y_3);
+          out_local +=
+              (boussinesq.applyU1(traction, q) *
+               influence::KelvinIntegrator<0>::g1<true>(q.l2norm() * y_3));
+        },
+        out, source, wavevectors);
+  }
+
+protected:
+  const T& boussinesq;
+  const Real y_3, cutoff;
+};
+}  // namespace detail
+
+template <>
+Boussinesq<model_type::volume_2d, 0>::Boussinesq(Model* model) : parent(model) {
+  this->initialize(trait::dimension, trait::dimension);
+}
+
+template <>
+Boussinesq<model_type::volume_2d, 1>::Boussinesq(Model* model) : parent(model) {
+  this->initialize(trait::dimension, trait::dimension * trait::dimension);
+}
+
+/* -------------------------------------------------------------------------- */
+/* Operator implementation */
+/* -------------------------------------------------------------------------- */
+template <model_type type, UInt derivative>
+void Boussinesq<type, derivative>::apply(GridBase<Real>& source,
+                                         GridBase<Real>& out) const {
+  Real nu = this->model->getPoissonRatio(), mu = this->model->getShearModulus();
+  influence::Boussinesq<trait::dimension, derivative> boussinesq(mu, nu);
+
+  auto apply = [&](UInt i, decltype(this->source_buffers)& source_buffers,
+                   decltype(this->disp_buffer)& out_buffer) {
+    const Real L = this->model->getSystemSize().front();
+    const UInt N = this->model->getDiscretization().front();
+    const Real dl = L / (N - 1);
+
+    out_buffer = 0;
+    const Real xi = i * dl;
+    detail::BoussinesqHelper<type, decltype(boussinesq)> helper(boussinesq, xi,
+                                                                1e-2);
+    helper.applyIntegral(out_buffer, source_buffers.front(), this->wavevectors);
+    typename detail::KelvinTrait<decltype(boussinesq)>::out_t out_fundamental(
+        out_buffer(0));
+    out_fundamental = 0;
+  };
+
+  this->fourierApply(apply, source, out);
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <model_type type, UInt derivative>
+void Boussinesq<type, derivative>::initialize(UInt source_components,
+                                              UInt out_components) {
+  // Copy horizontal sizes
+  std::array<UInt, trait::boundary_dimension> sizes;
+  std::copy(this->model->getDiscretization().begin() + 1,
+            this->model->getDiscretization().end(), sizes.begin());
+
+  auto hermitian_sizes =
+      GridHermitian<Real, trait::boundary_dimension>::hermitianDimensions(
+          sizes);
+  this->disp_buffer.setNbComponents(out_components);
+  this->disp_buffer.resize(hermitian_sizes);
+  this->source_buffers.resize(1);
+  auto& source = this->source_buffers.front();
+  source.setNbComponents(source_components);
+  source.resize(hermitian_sizes);
+}
+
+__END_TAMAAS__
diff --git a/src/model/boussinesq.hh b/src/model/boussinesq.hh
new file mode 100644
index 00000000..1f019227
--- /dev/null
+++ b/src/model/boussinesq.hh
@@ -0,0 +1,60 @@
+/**
+ * @file
+ *
+ * @author Lucas Frérot <lucas.frerot@epfl.ch>
+ *
+ * @section LICENSE
+ *
+ * Copyright (©)  2017 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 BOUSSINESQ_HH
+#define BOUSSINESQ_HH
+/* -------------------------------------------------------------------------- */
+#include "grid_hermitian.hh"
+#include "model_type.hh"
+#include "volume_potential.hh"
+/* -------------------------------------------------------------------------- */
+__BEGIN_TAMAAS__
+
+/**
+ * @brief Boussinesq tensor
+ */
+template <model_type type, UInt derivative>
+class Boussinesq : public VolumePotential<type> {
+  static_assert(type == model_type::volume_1d || type == model_type::volume_2d,
+                "Only volume types are supported");
+  using trait = model_type_traits<type>;
+  using parent = VolumePotential<type>;
+
+public:
+  /// Constructor
+  Boussinesq(Model* model);
+
+protected:
+  void initialize(UInt source_components, UInt out_components);
+
+public:
+  /// Apply the Boussinesq operator
+  void apply(GridBase<Real>& source, GridBase<Real>& out) const override;
+};
+
+__END_TAMAAS__
+
+#endif  // BOUSSINESQ_HH
diff --git a/src/model/mindlin.cpp b/src/model/mindlin.cpp
index f159fd22..6df0eb91 100644
--- a/src/model/mindlin.cpp
+++ b/src/model/mindlin.cpp
@@ -1,161 +1,158 @@
 /**
  * @file
  *
  * @author Lucas Frérot <lucas.frerot@epfl.ch>
  *
  * @section LICENSE
  *
  * Copyright (©)  2017 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 "mindlin.hh"
 #include "elasto_plastic_model.hh"
 #include "influence.hh"
 #include "kelvin_helper.hh"
 /* -------------------------------------------------------------------------- */
 __BEGIN_TAMAAS__
 /* -------------------------------------------------------------------------- */
 
 namespace detail {
 template <model_type type, typename T>
 class MindlinBoussinesqHelper {
   using boussinesq_t = T;
   using trait = model_type_traits<type>;
   static constexpr UInt dim = trait::dimension;
   static constexpr UInt bdim = trait::boundary_dimension;
 
 public:
   MindlinBoussinesqHelper(const T& boussinesq,
                           const influence::ElasticHelper<dim>& el, Real y_3,
                           Real cutoff)
       : boussinesq(boussinesq), el(el), y_3(y_3), cutoff(cutoff) {}
 
   inline void applyIntegral(GridHermitian<Real, bdim>& out,
                             GridHermitian<Real, bdim>& source,
                             const Grid<Real, bdim>& wavevectors) const {
     Loop::stridedLoop(
         [&](typename KelvinTrait<T>::out_t&& out_local,
             MatrixProxy<Complex, dim, dim>&& source_local,
             VectorProxy<const Real, bdim>&& q) {
           // Cutoff
           if (-q.l2norm() * std::abs(y_3) < std::log(cutoff))
             return;
 
 	  Vector<Real, dim> normal{{{0, 0, 1}}};
 	  auto traction{el(source_local) * normal};
 	  out_local += boussinesq.applyU0(traction, q) *
 	    influence::KelvinIntegrator<0>::g0<true>(q.l2norm() * y_3);
 	  out_local += (boussinesq.applyU1(traction, q) *
 		  influence::KelvinIntegrator<0>::g1<true>(q.l2norm() * y_3));
         },
         out, source, wavevectors);
   }
 
 protected:
   const T& boussinesq;
   const influence::ElasticHelper<dim>& el;
   const Real y_3, cutoff;
 };
 }  // namespace detail
 
 template <model_type type, UInt order>
 void Mindlin<type, order>::apply(GridBase<Real>& source,
                                  GridBase<Real>& out) const {
   Real nu = this->model->getPoissonRatio(), mu = this->model->getShearModulus();
   constexpr UInt derivative = order - 2;
   influence::Kelvin<trait::dimension, derivative> kelvin(mu, nu);
   influence::Kelvin<trait::dimension, 2> kelvin_strain(mu, nu);
   influence::Boussinesq<trait::dimension, derivative - 1> boussinesq(mu, nu);
   influence::ElasticHelper<trait::dimension> elasticity(mu, nu);
 
   auto apply = [&](UInt i, decltype(this->source_buffers)& source_buffers,
                    decltype(this->disp_buffer)& out_buffer) {
-    constexpr UInt dim = trait::dimension;
     const Real L = this->model->getSystemSize().front();
     const UInt N = this->model->getDiscretization().front();
     const Real dl = L / (N - 1);
 
     out_buffer = 0;
 
     /// Compute surface strains only once (dirty)
     if (i == 0) {
       surface_strains = 0;
       for (UInt j : Loop::range(N)) {
         const Real dij = j * dl;
         auto& source = source_buffers[j];
-        detail::KelvinHelper<type, influence::Kelvin<dim, 2>> helper(
+        detail::KelvinHelper<type, decltype(kelvin_strain)> helper(
             kelvin_strain, dij, dl, 1e-2);
 
         if (j > i) {
           helper.template applyIntegral<1>(surface_strains, source,
                                            this->wavevectors);
         } else if (j == i) {
           helper.template applyIntegral<0>(surface_strains, source,
                                            this->wavevectors);
           helper.applyFreeTerm(surface_strains, source, this->wavevectors);
         } else {
           helper.template applyIntegral<-1>(surface_strains, source,
                                             this->wavevectors);
         }
       }
     }
 
     for (UInt j : Loop::range(N)) {
       const Real dij = j * dl - i * dl;  // don't factorize!
       auto& source = source_buffers[j];
-      detail::KelvinHelper<type, influence::Kelvin<dim, derivative>> helper(
+      detail::KelvinHelper<type, decltype(kelvin)> helper(
           kelvin, dij, dl, 1e-2);
 
       if (j > i) {
         helper.template applyIntegral<1>(out_buffer, source, this->wavevectors);
       } else if (j == i) {
         helper.template applyIntegral<0>(out_buffer, source, this->wavevectors);
         helper.applyFreeTerm(out_buffer, source, this->wavevectors);
       } else {
         helper.template applyIntegral<-1>(out_buffer, source,
                                           this->wavevectors);
       }
     }
 
     // Correcting for the tractions on the surface
-    Real xi = i * dl;
-    detail::MindlinBoussinesqHelper<type,
-                                    influence::Boussinesq<dim, derivative - 1>>
-        helper(boussinesq, elasticity, xi, 1e-2);
+    const Real xi = i * dl;
+    detail::MindlinBoussinesqHelper<type, decltype(boussinesq)> helper(
+        boussinesq, elasticity, xi, 1e-2);
     helper.applyIntegral(out_buffer, surface_strains, this->wavevectors);
     
 
     // Setting fundamental frequency to zero
-    typename detail::KelvinTrait<
-        influence::Kelvin<trait::dimension, derivative>>::out_t
-        out_fundamental(out_buffer(0));
+    typename detail::KelvinTrait<decltype(kelvin)>::out_t out_fundamental(
+        out_buffer(0));
     out_fundamental = 0;
   };
 
   this->fourierApply(apply, source, out);
 }
 
 /* -------------------------------------------------------------------------- */
 /* Template instanciation                                                     */
 /* -------------------------------------------------------------------------- */
 template class Mindlin<model_type::volume_2d, 3>;
 template class Mindlin<model_type::volume_2d, 4>;
 
 /* -------------------------------------------------------------------------- */
 __END_TAMAAS__
diff --git a/src/model/volume_potential.hh b/src/model/volume_potential.hh
index 3f85f1aa..a1f0c4ee 100644
--- a/src/model/volume_potential.hh
+++ b/src/model/volume_potential.hh
@@ -1,95 +1,97 @@
 /**
  * @file
  *
  * @author Lucas Frérot <lucas.frerot@epfl.ch>
  *
  * @section LICENSE
  *
  * Copyright (©)  2017 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 VOLUME_POTENTIAL_HH
 #define VOLUME_POTENTIAL_HH
 /* -------------------------------------------------------------------------- */
 #include "integral_operator.hh"
 #include "model_type.hh"
+#include "grid_view.hh"
 #include "grid_hermitian.hh"
 #include "fft_plan_manager.hh"
 /* -------------------------------------------------------------------------- */
 __BEGIN_TAMAAS__
 
 /**
  * @brief Volume potential operator class. Applies the operators for computation
  * of displacements and strains due to residual/eigen strains
  */
 template <model_type type>
 class VolumePotential : public IntegralOperator {
   using trait = model_type_traits<type>;
 public:
   VolumePotential(Model * model);
 
   /// Update from model (does nothing)
   void updateFromModel() override {}
 
 protected:
   /// Function to handle layer-by-layer Fourier treatment of operators
   template <typename Func>
   void fourierApply(Func func, GridBase<Real>& in, GridBase<Real>& out) const;
 
 protected:
   Grid<Real, trait::boundary_dimension> wavevectors;
   using BufferType = GridHermitian<Real, trait::boundary_dimension>;
   mutable std::vector<BufferType> source_buffers;
   mutable BufferType disp_buffer;
 };
 
 /* -------------------------------------------------------------------------- */
 /* Template implementation */
 /* -------------------------------------------------------------------------- */
 
 template <model_type type>
 template <typename Func>
 void VolumePotential<type>::fourierApply(Func func, GridBase<Real>& in,
                                          GridBase<Real>& out) const {
   constexpr UInt dim = trait::dimension;
   Grid<Real, dim>& i = dynamic_cast<decltype(i)>(in);
   Grid<Real, dim>& o = dynamic_cast<decltype(o)>(out);
 
-  TAMAAS_ASSERT(i.sizes().front() == o.sizes().front(),
-                "Number of layers does not match");
+  // TAMAAS_ASSERT(i.sizes().front() == o.sizes().front(),
+  //               "Number of layers does not match");
+  // ^^^^ not applicable for Boussinesq
 
   for (UInt layer : Loop::range(i.sizes().front())) {
     auto in_layer = make_view(i, layer);
     FFTPlanManager::get()
         .createPlan(in_layer, source_buffers[layer])
         .forwardTransform();
   }
 
-  for (UInt layer : Loop::range(i.sizes().front())) {
+  for (UInt layer : Loop::range(o.sizes().front())) {
     func(layer, source_buffers, disp_buffer);
     auto out_layer = make_view(o, layer);
     FFTPlanManager::get()
         .createPlan(out_layer, disp_buffer)
         .backwardTransform();
   }
 }
 
 __END_TAMAAS__
 
 #endif  // VOLUME_POTENTIAL_HH