diff --git a/CHANGELOG.md b/CHANGELOG.md
index 93f9ddf1880a4ba9a5dd845abcabd872ce3b29f6..1c3b976cf2ba435ff3e88c4c95d595597b7f12a5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,9 @@
 
 - Introduce class `LocalDensity` for material-specific implementations
 - Introduce class `LocalIntegralEnergy` to work with the densities
+- Local energies and FE assemblers use now `dune-functions` power bases instead of scalar `dune-fufem` bases; the key element is the `LocalView` which contains the information for each element
 
 ## Deprecations and removals
 
 - Redundant implementations of `LocalEnergy` classes are now replaced by combining `LocalDensity` and `LocalIntegralEnergy`
+- Local energies and FE assemblers with `dune-fufem` scalar bases are now deprecated
diff --git a/dune/elasticity/assemblers/feassembler.hh b/dune/elasticity/assemblers/feassembler.hh
index 9e0c82f59a912538dbc951844985d5d0b1c96ed6..62d1751d44ac6d68c35b59cec1e6567bb2f02bb3 100644
--- a/dune/elasticity/assemblers/feassembler.hh
+++ b/dune/elasticity/assemblers/feassembler.hh
@@ -1,19 +1,188 @@
 #ifndef DUNE_ELASTICITY_ASSEMBLERS_FEASSEMBLER_HH
 #define DUNE_ELASTICITY_ASSEMBLERS_FEASSEMBLER_HH
 
-#include <dune/istl/bcrsmatrix.hh>
 #include <dune/common/fmatrix.hh>
+#include <dune/common/hybridutilities.hh>
+
+#include <dune/fufem/assemblers/istlbackend.hh>
+
+#include <dune/istl/bvector.hh>
+#include <dune/istl/bcrsmatrix.hh>
 #include <dune/istl/matrixindexset.hh>
 #include <dune/istl/matrix.hh>
 
+#include <dune/functions/functionspacebases/concepts.hh>
+#include <dune/functions/backends/istlvectorbackend.hh>
+
 #include "localfestiffness.hh"
 
 
-/** \brief A global FE assembler for variational problems
+namespace Dune::Elasticity {
+
+/** \brief A global FE assembler for variational problems for dune-functions global bases
  */
 template <class Basis, class VectorType>
 class FEAssembler {
 
+    using LocalView = typename Basis::LocalView;
+    using field_type = typename VectorType::field_type;
+
+    //! Dimension of the grid.
+    enum { gridDim = LocalView::GridView::dimension };
+
+public:
+
+    const Basis basis_;
+
+    /** \brief Partition type on which to assemble
+     *
+     * We want a fully nonoverlapping partition, and therefore need to skip ghost elements.
+     */
+    static constexpr auto partitionType = Dune::Partitions::interiorBorder;
+
+protected:
+
+    std::shared_ptr<LocalFEStiffness<LocalView,field_type>> localStiffness_;
+
+public:
+
+    /** \brief Constructor for a given basis and local assembler */
+    FEAssembler(const Basis& basis,
+                std::shared_ptr<LocalFEStiffness<LocalView, field_type>> localStiffness)
+        : basis_(basis),
+          localStiffness_(localStiffness)
+    {}
+
+    /** \brief Assemble the tangent stiffness matrix and the functional gradient together
+     *
+     * This may be more efficient than computing them separately
+     */
+    template<class MatrixType>
+    void assembleGradientAndHessian(const VectorType& configuration,
+                                    VectorType& gradient,
+                                    MatrixType& hessian,
+                                    bool computeOccupationPattern=true) const;
+
+    /** \brief Compute the energy of a deformation state */
+    auto computeEnergy(const VectorType& configuration) const;
+
+
+}; // end class
+
+
+template <class Basis, class VectorType>
+template <class MatrixType>
+void FEAssembler<Basis,VectorType>::
+assembleGradientAndHessian(const VectorType& configuration,
+                           VectorType& gradient,
+                           MatrixType& hessian,
+                           bool computeOccupationPattern) const
+{
+  // create backends for multi index access
+  auto hessianBackend  = Dune::Fufem::ISTLMatrixBackend(hessian);
+  auto configurationBackend      = Dune::Functions::istlVectorBackend(configuration);
+  auto gradientBackend = Dune::Functions::istlVectorBackend(gradient);
+
+  if (computeOccupationPattern)
+  {
+      auto patternBuilder = hessianBackend.patternBuilder();
+      patternBuilder.resize(basis_,basis_);
+
+      auto localView = basis_.localView();
+
+      for (const auto& element : elements(basis_.gridView(), partitionType))
+      {
+        localView.bind(element);
+        for (size_t i=0; i<localView.size(); i++)
+          for (size_t j=0; j<localView.size(); j++)
+            patternBuilder.insertEntry( localView.index(i), localView.index(j) );
+      }
+      patternBuilder.setupMatrix();
+  }
+
+  gradientBackend.resize(basis_);
+
+  hessian = 0;
+  gradient = 0;
+
+  auto localView = basis_.localView();
+
+  for (const auto& element : elements(basis_.gridView(), partitionType))
+  {
+    localView.bind(element);
+    const auto size = localView.size();
+
+    // Extract local configuration
+    std::vector<field_type> localConfiguration(size);
+    std::vector<field_type> localGradient(size);
+    Matrix<field_type> localHessian;
+    localHessian.setSize(size, size);
+
+    for (int i=0; i<size; i++)
+      localConfiguration[i] = configurationBackend[ localView.index(i) ];
+
+    // setup local matrix and gradient
+    localStiffness_->assembleGradientAndHessian(localView, localConfiguration, localGradient, localHessian);
+
+    for(int i=0; i<size; i++)
+    {
+      auto row = localView.index(i);
+      gradientBackend[row] += localGradient[i];
+
+      for (int j=0; j<size; j++ )
+      {
+        auto col = localView.index(j);
+        // fufem ISTLBackend uses operator() for entry access
+        hessianBackend(row,col) += localHessian[i][j];
+      }
+    }
+  }
+}
+
+template <class Basis, class VectorType>
+auto FEAssembler<Basis,VectorType>::
+computeEnergy(const VectorType& configuration) const
+{
+  double energy = 0;
+
+  if (configuration.dim()!=basis_.dimension())
+      DUNE_THROW(Dune::Exception, "Solution vector doesn't match the basis!");
+
+  auto localView = basis_.localView();
+  // fufem multi index access
+  auto configurationBackend = Functions::istlVectorBackend(configuration);
+
+  // Loop over all elements
+  for (const auto& element : elements(basis_.gridView(), partitionType))
+  {
+      localView.bind(element);
+      const auto size = localView.size();
+
+      std::vector<field_type> localConfiguration(size);
+
+      for (size_t i=0; i<size; i++)
+        localConfiguration[i] = configurationBackend[ localView.index(i) ];
+
+      energy += localStiffness_->energy(localView, localConfiguration);
+  }
+
+  return energy;
+}
+
+} // namespace Dune::Elasticity
+
+
+
+namespace Dune
+{
+
+/** \brief A global FE assembler for variational problems (old fufem bases version)
+ */
+template <class Basis, class VectorType >
+class DUNE_DEPRECATED_MSG("dune-elasticity with dune-fufem bases is now deprecated. Use Elasticity::FEAssembler with dune-functions bases.")
+FEAssembler
+{
+
     typedef typename Basis::GridView GridView;
 
     //! Dimension of the grid.
@@ -182,4 +351,7 @@ computeEnergy(const VectorType& sol) const
     return energy;
 
 }
+
+} // namespace Dune
+
 #endif
diff --git a/dune/elasticity/assemblers/localadolcstiffness.hh b/dune/elasticity/assemblers/localadolcstiffness.hh
index a22bb83dcd930a288b5ef390f2879cbe4751c985..59fe3ea8769a277d73b731c2d4a99baa51e13f20 100644
--- a/dune/elasticity/assemblers/localadolcstiffness.hh
+++ b/dune/elasticity/assemblers/localadolcstiffness.hh
@@ -14,12 +14,130 @@
 
 #include <dune/elasticity/assemblers/localfestiffness.hh>
 
-//#define ADOLC_VECTOR_MODE
+namespace Dune::Elasticity {
 
 /** \brief Assembles energy gradient and Hessian with ADOL-C (automatic differentiation)
  */
-template<class GridView, class LocalFiniteElement, class VectorType>
+template<class LocalView>
 class LocalADOLCStiffness
+    : public LocalFEStiffness<LocalView,double>
+{
+    enum {gridDim=LocalView::GridView::dimension};
+
+public:
+
+    // accepts ADOL_C's "adouble" only
+    LocalADOLCStiffness(std::shared_ptr<Dune::Elasticity::LocalEnergy<LocalView, adouble>> energy)
+    : localEnergy_(energy)
+    {}
+
+    /** \brief Compute the energy at the current configuration */
+    virtual double energy (const LocalView& localView,
+                           const std::vector<double>& localConfiguration) const;
+
+    /** \brief Assemble the local stiffness matrix at the current position
+     *
+     *     This uses the automatic differentiation toolbox ADOL_C.
+     */
+    virtual void assembleGradientAndHessian(const LocalView& localView,
+                                            const std::vector<double>& localConfiguration,
+                                            std::vector<double>& localGradient,
+                                            Dune::Matrix<double>& localHessian);
+
+    std::shared_ptr<Dune::Elasticity::LocalEnergy<LocalView, adouble>> localEnergy_;
+
+};
+
+
+template<class LocalView>
+double LocalADOLCStiffness<LocalView>::
+energy(const LocalView& localView,
+       const std::vector<double>& localConfiguration) const
+{
+    int rank = Dune::MPIHelper::getCollectiveCommunication().rank();
+    double pureEnergy;
+
+    std::vector<adouble> localAConfiguration(localConfiguration.size());
+
+    trace_on(rank);
+
+    adouble energy = 0;
+
+    for (size_t i=0; i<localConfiguration.size(); i++)
+        localAConfiguration[i] <<= localConfiguration[i];
+
+    energy = localEnergy_->energy(localView,localAConfiguration);
+
+    energy >>= pureEnergy;
+
+    trace_off(rank);
+
+    return pureEnergy;
+}
+
+
+template<class LocalView>
+void LocalADOLCStiffness<LocalView>::
+assembleGradientAndHessian(const LocalView& localView,
+                           const std::vector<double>& localConfiguration,
+                           std::vector<double>& localGradient,
+                           Dune::Matrix<double>& localHessian
+                          )
+{
+    int rank = Dune::MPIHelper::getCollectiveCommunication().rank();
+    // Tape energy computation.  We may not have to do this every time, but it's comparatively cheap.
+    energy(localView, localConfiguration);
+
+    /////////////////////////////////////////////////////////////////
+    // Compute the energy gradient
+    /////////////////////////////////////////////////////////////////
+
+    // Compute the actual gradient
+    size_t nDoubles = localConfiguration.size();
+
+    // Compute gradient
+    localGradient.resize(nDoubles);
+    gradient(rank,nDoubles,localConfiguration.data(),localGradient.data());
+
+    /////////////////////////////////////////////////////////////////
+    // Compute Hessian
+    /////////////////////////////////////////////////////////////////
+
+    localHessian.setSize(nDoubles,nDoubles);
+
+    std::vector<double> v(nDoubles);
+    std::vector<double> w(nDoubles);
+
+    std::fill(v.begin(), v.end(), 0.0);
+
+    for (size_t i=0; i<nDoubles; i++)
+    {
+      // Evaluate Hessian multiplied with the i-th canonical basis vector (i.e.: the i-th column of the Hessian)
+      v[i] = 1.;
+
+      int rc= 3;
+      MINDEC(rc, hess_vec(rank, nDoubles, const_cast<double*>(localConfiguration.data()), v.data(), w.data())); // ADOL-C won't accept pointers with const values
+      if (rc < 0)
+        DUNE_THROW(Dune::Exception, "ADOL-C has returned with error code " << rc << "!");
+
+      for (size_t j=0; j<nDoubles; j++)
+        localHessian[i][j] = w[j];
+
+      // Make v the null vector again
+      v[i] = 0.;
+    }
+
+    // TODO: implement ADOLC_VECTOR_MODE variant
+}
+
+} // namespace Dune::Elasticity
+
+
+/** \brief Assembles energy gradient and Hessian with ADOL-C (automatic differentiation)
+ */
+template<class GridView, class LocalFiniteElement, class VectorType>
+class DUNE_DEPRECATED_MSG("dune-elasticity with dune-fufem bases is now deprecated. Use Elasticity::LocalADOLCStiffness with LocalView concept!")
+LocalADOLCStiffness
     : public LocalFEStiffness<GridView,LocalFiniteElement,VectorType>
 {
     // grid types
@@ -38,7 +156,7 @@ public:
     //! Dimension of a tangent space
     enum { blocksize = VectorType::value_type::dimension };
 
-    LocalADOLCStiffness(const Dune::Elasticity::LocalEnergy<GridView, LocalFiniteElement, AVectorType>* energy)
+    LocalADOLCStiffness(const Dune::LocalEnergy<GridView, LocalFiniteElement, AVectorType>* energy)
     : localEnergy_(energy)
     {}
 
@@ -56,7 +174,7 @@ public:
                          const VectorType& localConfiguration,
                          VectorType& localGradient);
 
-    const Dune::Elasticity::LocalEnergy<GridView, LocalFiniteElement, AVectorType>* localEnergy_;
+    const Dune::LocalEnergy<GridView, LocalFiniteElement, AVectorType>* localEnergy_;
 
 };
 
diff --git a/dune/elasticity/assemblers/localenergy.hh b/dune/elasticity/assemblers/localenergy.hh
index 475ed7f340e276b67e4b0d2c50f3709a7badd54e..f4c56f3ecfa97bf26bce6522883796067c54948c 100644
--- a/dune/elasticity/assemblers/localenergy.hh
+++ b/dune/elasticity/assemblers/localenergy.hh
@@ -3,13 +3,33 @@
 
 #include <vector>
 
-namespace Dune {
+namespace Dune::Elasticity {
 
-namespace Elasticity {
+/** \brief Base class for energies defined by integrating over one grid element */
+template<class LocalView, class field_type = double>
+class LocalEnergy
+{
+
+public:
+
+  /** \brief Compute the energy at the current configuration
+   *
+   * \param localView Container with current element and local function basis
+   * \param localConfiguration The coefficients of a FE function on the current element
+   */
+  virtual field_type energy (const LocalView& localView,
+                             const std::vector<field_type>& localConfiguration) const = 0;
+
+};
+
+} // namespace Dune::Elasticity
+
+namespace Dune {
 
 /** \brief Base class for energies defined by integrating over one grid element */
 template<class GridView, class LocalFiniteElement, class VectorType>
-class LocalEnergy
+class DUNE_DEPRECATED_MSG("dune-elasticity with dune-fufem bases is now deprecated. Use Elasticity::LocalEnergy with LocalView concept!")
+LocalEnergy
 {
     typedef typename VectorType::value_type::field_type RT;
     typedef typename GridView::template Codim<0>::Entity Element;
@@ -29,8 +49,6 @@ public:
 
 };
 
-}  // namespace Elasticity
-
 }  // namespace Dune
 
 #endif  // DUNE_ELASTICITY_ASSEMBLERS_LOCALENERGY_HH
diff --git a/dune/elasticity/assemblers/localfestiffness.hh b/dune/elasticity/assemblers/localfestiffness.hh
index f2d13cb54d0c3f5da2fdcfe30c70efa5bfa2ca17..5aa1f982e88d3193cd9d9be0241f1d2fcff1dddd 100644
--- a/dune/elasticity/assemblers/localfestiffness.hh
+++ b/dune/elasticity/assemblers/localfestiffness.hh
@@ -6,9 +6,33 @@
 
 #include <dune/elasticity/assemblers/localenergy.hh>
 
-template<class GridView, class LocalFiniteElement, class VectorType>
+namespace Dune::Elasticity {
+
+template<class LocalView, class RT = double>
 class LocalFEStiffness
-: public Dune::Elasticity::LocalEnergy<GridView, LocalFiniteElement, VectorType>
+: public Dune::Elasticity::LocalEnergy<LocalView, RT>
+{
+    enum {gridDim=LocalView::GridView::dimension};
+
+public:
+
+    /** \brief Assemble the local gradient and tangent matrix at the current position
+    */
+    virtual void assembleGradientAndHessian(const LocalView& localView,
+                                            const std::vector<RT>& localConfiguration,
+                                            std::vector<RT>& localGradient,
+                                            Dune::Matrix<RT>& localHessian
+                                           ) = 0;
+
+};
+
+} // namespace Dune::Elasticity
+
+
+template<class GridView, class LocalFiniteElement, class VectorType>
+class DUNE_DEPRECATED_MSG("dune-elasticity with dune-fufem bases is now deprecated. Use Elasticity::LocalFEStiffness with LocalView concept!")
+LocalFEStiffness
+: public Dune::LocalEnergy<GridView, LocalFiniteElement, VectorType>
 {
     // grid types
     typedef typename GridView::Grid::ctype DT;
diff --git a/dune/elasticity/common/trustregionsolver.cc b/dune/elasticity/common/trustregionsolver.cc
index 432b73a029fe6abefed83cc548915a07a03d413f..5c7f54064a2d7bae8901a73f4f01262fccacb0fd 100644
--- a/dune/elasticity/common/trustregionsolver.cc
+++ b/dune/elasticity/common/trustregionsolver.cc
@@ -8,9 +8,11 @@
 #include <dune/fufem/functionspacebases/dunefunctionsbasis.hh>
 #include <dune/fufem/functionspacebases/p1nodalbasis.hh>
 #include <dune/fufem/assemblers/operatorassembler.hh>
+#include <dune/fufem/assemblers/dunefunctionsoperatorassembler.hh>
 #include <dune/fufem/assemblers/localassemblers/laplaceassembler.hh>
 #include <dune/fufem/assemblers/localassemblers/massassembler.hh>
 #include <dune/fufem/assemblers/basisinterpolationmatrixassembler.hh>
+#include <dune/fufem/assemblers/istlbackend.hh>
 
 // Using a monotone multigrid as the inner solver
 #include <dune/solvers/iterationsteps/trustregiongsstep.hh>
@@ -27,7 +29,10 @@
 template <class BasisType, class VectorType>
 void TrustRegionSolver<BasisType,VectorType>::
 setup(const typename BasisType::GridView::Grid& grid,
-      const FEAssembler<DuneFunctionsBasis<BasisType>, VectorType>* assembler,
+         std::conditional_t< // do we have a dune-functions basis? -> choose right assembler type
+           Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
+             const Dune::Elasticity::FEAssembler<BasisType,VectorType>*,
+             const Dune::FEAssembler<DuneFunctionsBasis<BasisType>,VectorType>* > assembler,
          const SolutionType& x,
          const Dune::BitSetVector<blocksize>& dirichletNodes,
          double tolerance,
@@ -65,7 +70,11 @@ setup(const typename BasisType::GridView::Grid& grid,
     mgSetup_->ignore(std::const_pointer_cast<Dune::BitSetVector<blocksize> >(ignoreNodes_));
 
     BasisType feBasis(grid.levelGridView(grid.maxLevel()));
-    DuneFunctionsBasis<BasisType> basis(feBasis);
+
+    std::conditional_t< // do we have a dune-functions basis? -> choose right assembler type
+      Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
+        BasisType,
+        DuneFunctionsBasis<BasisType> > basis(feBasis);
 
     innerMultigridStep_ = std::make_unique<Dune::ParMG::Multigrid<VectorType> >();
     innerMultigridStep_->mu_ = mu;
@@ -75,8 +84,11 @@ setup(const typename BasisType::GridView::Grid& grid,
     if (grid.comm().rank()==0)
         std::cout << "Parallel multigrid setup took " << setupTimer.stop() << " seconds." << std::endl;
 #else
-    DuneFunctionsBasis<BasisType> basis(grid.leafGridView());
 
+    std::conditional_t< // do we have a dune-functions basis?
+      Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
+        BasisType,
+        DuneFunctionsBasis<BasisType> > basis(grid.leafGridView());
     // ////////////////////////////////
     //   Create a multigrid solver
     // ////////////////////////////////
@@ -117,15 +129,46 @@ setup(const typename BasisType::GridView::Grid& grid,
     // //////////////////////////////////////////////////////////////////////////////////////
     //   Assemble a Laplace matrix to create a norm that's equivalent to the H1-norm
     // //////////////////////////////////////////////////////////////////////////////////////
-    OperatorAssembler<DuneFunctionsBasis<BasisType>,DuneFunctionsBasis<BasisType>,Dune::Partitions::Interior> operatorAssembler(basis, basis);
 
-    LaplaceAssembler<GridType,
-                     typename DuneFunctionsBasis<BasisType>::LocalFiniteElement,
-                     typename DuneFunctionsBasis<BasisType>::LocalFiniteElement> laplaceStiffness;
-    typedef Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> > ScalarMatrixType;
+
+    using ScalarMatrixType = Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >;
     ScalarMatrixType localA;
 
-    operatorAssembler.assemble(laplaceStiffness, localA);
+    std::conditional_t< // do we have a dune-functions basis?
+      Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
+        Dune::Fufem::DuneFunctionsOperatorAssembler<BasisType,BasisType>,
+        OperatorAssembler<DuneFunctionsBasis<BasisType>,DuneFunctionsBasis<BasisType>,Dune::Partitions::Interior> > operatorAssembler(basis,basis);
+
+    if constexpr ( Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>() )
+    {
+      using FiniteElement = std::decay_t<decltype(basis.localView().tree().child(0).finiteElement())>;
+      // construct a Fufem Basis Assembler
+      auto laplaceStiffness = LaplaceAssembler<GridType, FiniteElement, FiniteElement>();
+      // transform it to a dune-functions assembler
+      auto localAssembler = [&](const auto& element, auto& localMatrix, auto&& trialLocalView, auto&& ansatzLocalView){
+          laplaceStiffness.assemble(element,
+                                    localMatrix,
+                                    trialLocalView.tree().child(0).finiteElement(),
+                                    ansatzLocalView.tree().child(0).finiteElement());
+      };
+
+
+      auto matrixBackend = Dune::Fufem::istlMatrixBackend(localA);
+      auto patternBuilder = matrixBackend.patternBuilder();
+
+      operatorAssembler.assembleBulkPattern(patternBuilder);
+      patternBuilder.setupMatrix();
+
+      operatorAssembler.assembleBulkEntries(matrixBackend, localAssembler);
+    }
+    else
+    {
+      LaplaceAssembler<GridType,
+                      typename DuneFunctionsBasis<BasisType>::LocalFiniteElement,
+                      typename DuneFunctionsBasis<BasisType>::LocalFiniteElement> laplaceStiffness;
+
+      operatorAssembler.assemble(laplaceStiffness, localA);
+    }
 
     ScalarMatrixType* A = new ScalarMatrixType(localA);
 
@@ -136,12 +179,37 @@ setup(const typename BasisType::GridView::Grid& grid,
     //   This will be used to monitor the gradient
     // //////////////////////////////////////////////////////////////////////////////////////
 
-    MassAssembler<GridType,
-                  typename DuneFunctionsBasis<BasisType>::LocalFiniteElement,
-                  typename DuneFunctionsBasis<BasisType>::LocalFiniteElement> massStiffness;
     ScalarMatrixType localMassMatrix;
 
-    operatorAssembler.assemble(massStiffness, localMassMatrix);
+    if constexpr ( Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>() )
+    {
+      // construct a Fufem Basis Assembler
+      using FiniteElement = std::decay_t<decltype(basis.localView().tree().child(0).finiteElement())>;
+      auto massStiffness = MassAssembler<GridType, FiniteElement, FiniteElement>();
+      // transform it to a dune-functions assembler
+      auto localMassAssembler = [&](const auto& element, auto& localMatrix, auto&& trialLocalView, auto&& ansatzLocalView){
+        massStiffness.assemble(element,
+                               localMatrix,
+                               trialLocalView.tree().child(0).finiteElement(),
+                               ansatzLocalView.tree().child(0).finiteElement());
+      };
+
+      auto massMatrixBackend = Dune::Fufem::istlMatrixBackend(localMassMatrix);
+      auto massPatternBuilder = massMatrixBackend.patternBuilder();
+
+      operatorAssembler.assembleBulkPattern(massPatternBuilder);
+      massPatternBuilder.setupMatrix();
+
+      operatorAssembler.assembleBulkEntries(massMatrixBackend, localMassAssembler);
+    }
+    else
+    {
+      MassAssembler<GridType,
+                    typename DuneFunctionsBasis<BasisType>::LocalFiniteElement,
+                    typename DuneFunctionsBasis<BasisType>::LocalFiniteElement> massStiffness;
+
+      operatorAssembler.assemble(massStiffness, localMassMatrix);
+    }
 
     ScalarMatrixType* massMatrix = new ScalarMatrixType(localMassMatrix);
     l2Norm_ = std::make_shared<H1SemiNorm<CorrectionType> >(*massMatrix);
@@ -151,10 +219,19 @@ setup(const typename BasisType::GridView::Grid& grid,
     // ////////////////////////////////////////////////////////////
 
     hessianMatrix_ = std::make_shared<MatrixType>();
-    Dune::MatrixIndexSet indices(grid_->size(1), grid_->size(1));
-    assembler_->getNeighborsPerVertex(indices);
-    indices.exportIdx(*hessianMatrix_);
-
+    if constexpr ( Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>() )
+    {
+      auto hessianBackend = Dune::Fufem::istlMatrixBackend(*hessianMatrix_);
+      auto hessianPatternBuilder = hessianBackend.patternBuilder();
+      operatorAssembler.assembleBulkPattern(hessianPatternBuilder);
+      hessianPatternBuilder.setupMatrix();
+    }
+    else
+    {
+      Dune::MatrixIndexSet indices(grid_->size(1), grid_->size(1));
+      assembler_->getNeighborsPerVertex(indices);
+      indices.exportIdx(*hessianMatrix_);
+    }
 #if !HAVE_DUNE_PARMG
     innerSolver_ = std::make_shared<LoopSolver<CorrectionType> >(mmgStep,
                                                                    innerIterations_,
@@ -174,9 +251,26 @@ setup(const typename BasisType::GridView::Grid& grid,
     //  On the lower grid levels a hierarchy of P1/Q1 spaces is used again.
     ////////////////////////////////////////////////////////////////////////
 
-    typedef BasisType Basis;
-    bool isP1Basis = std::is_same<Basis,Dune::Functions::LagrangeBasis<typename Basis::GridView, 1> >::value;
+    using Basis = BasisType;
+    bool isP1Basis;
 
+    if constexpr ( Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>() )
+    {
+      const auto dim = VectorType::value_type::dimension;
+      using namespace Dune::Functions::BasisFactory;
+      auto p1PowerBasis = makeBasis(
+          basis.gridView(),
+          power<dim>(
+          lagrange<1>()
+      ));
+
+      using P1PowerBasis = decltype(p1PowerBasis);
+      isP1Basis = std::is_same<Basis,P1PowerBasis>::value;
+    }
+    else
+    {
+      isP1Basis = std::is_same<Basis,Dune::Functions::LagrangeBasis<typename Basis::GridView, 1> >::value;
+    }
 
     using TransferOperatorType = typename TruncatedCompressedMGTransfer<CorrectionType>::TransferOperatorType;
     std::vector<std::shared_ptr<TruncatedCompressedMGTransfer<CorrectionType>>> transferOperators(isP1Basis ? numLevels-1 : numLevels);
@@ -184,16 +278,31 @@ setup(const typename BasisType::GridView::Grid& grid,
     // Here we set up the restriction of the leaf grid space into the leaf grid P1/Q1 space
     if (not isP1Basis)
     {
+      TransferOperatorType pkToP1TransferMatrix;
+
+      if constexpr ( Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>() )
+      {
+        const auto dim = VectorType::value_type::dimension;
+        using namespace Dune::Functions::BasisFactory;
+        auto p1PowerBasis = makeBasis(
+            basis.gridView(),
+            power<dim>(
+            lagrange<1>()
+        ));
+        assembleGlobalBasisTransferMatrix(pkToP1TransferMatrix,p1PowerBasis,basis);
+      }
+      else
+      {
         P1NodalBasis<typename GridType::LeafGridView,double> p1Basis(grid_->leafGridView());
-
-        TransferOperatorType pkToP1TransferMatrix;
         assembleBasisInterpolationMatrix<TransferOperatorType,
-                                         P1NodalBasis<typename GridType::LeafGridView,double>,
-                                         DuneFunctionsBasis<BasisType> >(pkToP1TransferMatrix,p1Basis,basis);
-        auto pkToP1 = std::make_shared< TruncatedCompressedMGTransfer<CorrectionType> >();
-        transferOperators.back() = pkToP1;
-        std::shared_ptr<TransferOperatorType> topTransferOperator = std::make_shared<TransferOperatorType>(pkToP1TransferMatrix);
-        pkToP1->setMatrix(topTransferOperator);
+                                        P1NodalBasis<typename GridType::LeafGridView,double>,
+                                        DuneFunctionsBasis<BasisType> >(pkToP1TransferMatrix,p1Basis,basis);
+      }
+
+      auto pkToP1 = std::make_shared< TruncatedCompressedMGTransfer<CorrectionType> >();
+      transferOperators.back() = pkToP1;
+      std::shared_ptr<TransferOperatorType> topTransferOperator = std::make_shared<TransferOperatorType>(pkToP1TransferMatrix);
+      pkToP1->setMatrix(topTransferOperator);
     }
 
     // Now the P1/Q1 restriction operators for the remaining levels
diff --git a/dune/elasticity/common/trustregionsolver.hh b/dune/elasticity/common/trustregionsolver.hh
index 2043fb3a0166481d32f6a615a55e12d223900b06..9856856bde42fc227c53abe687f8fd2b2a197add 100644
--- a/dune/elasticity/common/trustregionsolver.hh
+++ b/dune/elasticity/common/trustregionsolver.hh
@@ -3,8 +3,10 @@
 
 #include <memory>
 #include <vector>
+#include <type_traits>
 
 #include <dune/common/bitsetvector.hh>
+#include <dune/common/concept.hh>
 
 #include <dune/istl/bcrsmatrix.hh>
 #include <dune/istl/bvector.hh>
@@ -19,6 +21,8 @@
 #include <dune/fufem/functionspacebases/p3nodalbasis.hh>
 #include <dune/fufem/assemblers/transferoperatorassembler.hh>
 
+#include <dune/functions/functionspacebases/concepts.hh>
+
 #include <dune/elasticity/assemblers/feassembler.hh>
 
 #if HAVE_DUNE_PARMG
@@ -35,13 +39,14 @@
 #endif
 
 
-/** \brief Trust-region solver  */
+/** \brief Trust-region solver */
 template <class BasisType, class VectorType>
 class TrustRegionSolver
     : public IterativeSolver<VectorType,
                              Dune::BitSetVector<VectorType::value_type::dimension> >
 {
     typedef typename BasisType::GridView::Grid GridType;
+    using GridView = typename BasisType::GridView;
 
     const static int blocksize = VectorType::value_type::dimension;
 
@@ -63,11 +68,21 @@ public:
     TrustRegionSolver()
         : IterativeSolver<VectorType, Dune::BitSetVector<blocksize> >(0,100,NumProc::FULL),
           hessianMatrix_(std::shared_ptr<MatrixType>(NULL)), h1SemiNorm_(NULL)
-    {}
+    {
+#if HAVE_DUNE_PARMG
+      // TODO currently, we cannot use PARMG together with dune-functions bases
+      static_assert( not Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>() ,
+        "Currently, dune-parmg and dune-functions bases cannot be used together."
+      );
+#endif
+    }
 
     /** \brief Set up the solver using a monotone multigrid method as the inner solver */
     void setup(const GridType& grid,
-               const FEAssembler<DuneFunctionsBasis<BasisType>,VectorType>* assembler,
+               std::conditional_t< // do we have a dune-functions basis? -> choose right assembler type
+                  Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
+                  const Dune::Elasticity::FEAssembler<BasisType,VectorType>*,
+                  const Dune::FEAssembler<DuneFunctionsBasis<BasisType>,VectorType>*> assembler,
                const SolutionType& x,
                const Dune::BitSetVector<blocksize>& dirichletNodes,
                double tolerance,
@@ -133,7 +148,10 @@ protected:
     std::shared_ptr<MatrixType> hessianMatrix_;
 
     /** \brief The assembler for the material law */
-    const FEAssembler<DuneFunctionsBasis<BasisType>, VectorType>* assembler_;
+    std::conditional_t< // do we have a dune-functions basis? -> choose right assembler type
+      Dune::models< Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(),
+        const Dune::Elasticity::FEAssembler<BasisType,VectorType>*,
+        const Dune::FEAssembler<DuneFunctionsBasis<BasisType>,VectorType>* > assembler_;
 
 #if HAVE_DUNE_PARMG
     /** \brief The solver for the inner problem */
diff --git a/dune/elasticity/materials/localintegralenergy.hh b/dune/elasticity/materials/localintegralenergy.hh
index 1ba6759d57845360700910e271e38a984bbbc32a..5b5df9b3a98a8feb18a898dafe54928ffdcd91b1 100644
--- a/dune/elasticity/materials/localintegralenergy.hh
+++ b/dune/elasticity/materials/localintegralenergy.hh
@@ -11,23 +11,107 @@
 
 namespace Dune::Elasticity {
 
-template<class GridView, class LocalFiniteElement, class field_type=double>
+template<class LocalView, class field_type=double>
 class LocalIntegralEnergy
-  : public Elasticity::LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,GridView::dimension>>>
+  : public Elasticity::LocalEnergy<LocalView,field_type>
 {
-  // grid types
+  using GridView = typename LocalView::GridView;
   using DT = typename GridView::Grid::ctype;
+
+  enum {gridDim=GridView::dimension};
+
+public:
+
+  /** \brief Constructor with a local energy density
+    */
+  LocalIntegralEnergy(const std::shared_ptr<LocalDensity<gridDim,field_type,DT>>& ld)
+  : localDensity_(ld)
+  {}
+
+  /** \brief Virtual destructor */
+  virtual ~LocalIntegralEnergy()
+  {}
+
+  /** \brief Assemble the energy for a single element */
+  field_type energy (const LocalView& localView,
+                     const std::vector<field_type>& localConfiguration) const;
+
+protected:
+  const std::shared_ptr<LocalDensity<gridDim,field_type,DT>> localDensity_ = nullptr;
+
+};
+
+template <class LocalView, class field_type>
+field_type
+LocalIntegralEnergy<LocalView, field_type>::
+energy(const LocalView& localView,
+       const std::vector<field_type>& localConfiguration) const
+{
+  // powerBasis: grab the finite element of the first child
+  const auto& localFiniteElement = localView.tree().child(0).finiteElement();
+  const auto& element = localView.element();
+
+  field_type energy = 0;
+
+  // store gradients of shape functions and base functions
+  std::vector<FieldMatrix<DT,1,gridDim> > referenceGradients(localFiniteElement.size());
+  std::vector<FieldVector<DT,gridDim> > gradients(localFiniteElement.size());
+
+  int quadOrder = (element.type().isSimplex()) ? localFiniteElement.localBasis().order()
+                                               : localFiniteElement.localBasis().order() * gridDim;
+
+  const auto& quad = Dune::QuadratureRules<DT, gridDim>::rule(element.type(), quadOrder);
+
+  for (const auto& qp : quad)
+  {
+    const DT integrationElement = element.geometry().integrationElement(qp.position());
+
+    const auto jacobianInverseTransposed = element.geometry().jacobianInverseTransposed(qp.position());
+
+    // Global position
+    auto x = element.geometry().global(qp.position());
+
+    // Get gradients of shape functions
+    localFiniteElement.localBasis().evaluateJacobian(qp.position(), referenceGradients);
+
+    // compute gradients of base functions
+    for (size_t i=0; i<gradients.size(); ++i)
+      jacobianInverseTransposed.mv(referenceGradients[i][0], gradients[i]);
+
+    // Deformation gradient
+    FieldMatrix<field_type,gridDim,gridDim> deformationGradient(0);
+    for (size_t i=0; i<gradients.size(); i++)
+      for (int j=0; j<gridDim; j++)
+        deformationGradient[j].axpy(localConfiguration[ localView.tree().child(j).localIndex(i) ], gradients[i]);
+    // Integrate the energy density
+    energy += qp.weight() * integrationElement * (*localDensity_)(x, deformationGradient);
+  }
+
+  return energy;
+}
+
+}  // namespace Dune::Elasticity
+
+
+// deprecated implementation in namespace Dune
+namespace Dune {
+
+template<class GridView, class LocalFiniteElement, class field_type=double>
+class DUNE_DEPRECATED_MSG("Use dune-functions powerBases with LocalView concept. See Elasticity::LocalIntegralEnergy")
+LocalIntegralEnergy
+  : public LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,GridView::dimension>>>
+{
   using Entity = typename GridView::template Codim<0>::Entity;
+  using DT = typename GridView::Grid::ctype;
 
   // some other sizes
   enum {gridDim=GridView::dimension};
-  enum {dim=GridView::dimension};
 
 public:
 
   /** \brief Constructor with a local energy density
     */
-  LocalIntegralEnergy(const std::shared_ptr<LocalDensity<dim,field_type,DT>>& ld)
+  LocalIntegralEnergy(const std::shared_ptr<Elasticity::LocalDensity<gridDim,field_type,DT>>& ld)
   : localDensity_(ld)
   {}
 
@@ -41,7 +125,7 @@ public:
                      const std::vector<Dune::FieldVector<field_type,gridDim> >& localConfiguration) const;
 
 protected:
-  const std::shared_ptr<LocalDensity<dim,field_type,DT>> localDensity_ = nullptr;
+  const std::shared_ptr<Elasticity::LocalDensity<gridDim,field_type,DT>> localDensity_ = nullptr;
 
 };
 
@@ -49,10 +133,10 @@ protected:
 
 template <class GridView, class LocalFiniteElement, class field_type>
 field_type
-LocalIntegralEnergy<GridView,LocalFiniteElement,field_type>::
+LocalIntegralEnergy<GridView, LocalFiniteElement, field_type>::
 energy(const Entity& element,
        const LocalFiniteElement& localFiniteElement,
-       const std::vector<Dune::FieldVector<field_type,gridDim> >& localConfiguration) const
+       const std::vector<Dune::FieldVector<field_type, gridDim> >& localConfiguration) const
 {
   assert(element.type() == localFiniteElement.type());
 
@@ -96,7 +180,7 @@ energy(const Entity& element,
   return energy;
 }
 
-}  // namespace Dune::Elasticity
+}  // namespace Dune
 
 
 #endif   //#ifndef DUNE_ELASTICITY_MATERIALS_LOCALINTEGRALENERGY_HH
diff --git a/dune/elasticity/materials/neumannenergy.hh b/dune/elasticity/materials/neumannenergy.hh
index c1e11721a30b341677dc23f19396a41adec158c0..2bb416eec2262c1c203f5cbd69c88a8978019c5d 100644
--- a/dune/elasticity/materials/neumannenergy.hh
+++ b/dune/elasticity/materials/neumannenergy.hh
@@ -8,11 +8,99 @@
 
 #include <dune/elasticity/assemblers/localenergy.hh>
 
+namespace Dune::Elasticity {
+
+template<class LocalView, class field_type=double>
+class NeumannEnergy
+  : public Elasticity::LocalEnergy<LocalView, field_type>
+{
+  using GridView = typename LocalView::GridView;
+  using DT = typename GridView::Grid::ctype;
+  using ctype = typename GridView::ctype;
+
+  enum {dim=GridView::dimension};
+
+public:
+
+  /** \brief Constructor with a set of material parameters
+   * \param parameters The material parameters
+   */
+  NeumannEnergy(const std::shared_ptr<BoundaryPatch<GridView>>& neumannBoundary,
+                const Dune::VirtualFunction<Dune::FieldVector<ctype,dim>, Dune::FieldVector<double,dim> >* neumannFunction)
+  : neumannBoundary_(neumannBoundary),
+    neumannFunction_(neumannFunction)
+  {}
+
+  /** \brief Assemble the energy for a single element */
+  field_type energy (const LocalView& localView,
+                     const std::vector<field_type>& localConfiguration) const
+  {
+    const auto& localFiniteElement = localView.tree().child(0).finiteElement();
+    const auto& element = localView.element();
+
+    field_type energy = 0;
+
+    for (auto&& it : intersections(neumannBoundary_->gridView(), element)) {
+
+      if (not neumannBoundary_ or not neumannBoundary_->contains(it))
+        continue;
+
+      int quadOrder = localFiniteElement.localBasis().order();
+
+      const auto& quad = Dune::QuadratureRules<ctype, dim-1>::rule(it.type(), quadOrder);
+
+      for (size_t pt=0; pt<quad.size(); pt++) {
+
+        // Local position of the quadrature point
+        const Dune::FieldVector<ctype,dim>& quadPos = it.geometryInInside().global(quad[pt].position());
+
+        const auto integrationElement = it.geometry().integrationElement(quad[pt].position());
+
+        // The value of the local function
+        std::vector<Dune::FieldVector<ctype,1> > shapeFunctionValues;
+        localFiniteElement.localBasis().evaluateFunction(quadPos, shapeFunctionValues);
+
+        Dune::FieldVector<field_type,dim> value(0);
+        for (size_t i=0; i<localFiniteElement.size(); i++)
+          for (int j=0; j<dim; j++)
+            value[j] += shapeFunctionValues[i] * localConfiguration[ localView.tree().child(j).localIndex(i) ];
+
+        // Value of the Neumann data at the current position
+        Dune::FieldVector<double,dim> neumannValue;
+
+        if (dynamic_cast<const VirtualGridViewFunction<GridView,Dune::FieldVector<double,dim> >*>(neumannFunction_))
+            dynamic_cast<const VirtualGridViewFunction<GridView,Dune::FieldVector<double,dim> >*>(neumannFunction_)->evaluateLocal(element, quadPos, neumannValue);
+        else
+            neumannFunction_->evaluate(it.geometry().global(quad[pt].position()), neumannValue);
+
+        // Only translational dofs are affected by the Neumann force
+        for (size_t i=0; i<neumannValue.size(); i++)
+          energy += (neumannValue[i] * value[i]) * quad[pt].weight() * integrationElement;
+
+      }
+
+    }
+
+    return energy;
+  }
+
+private:
+  /** \brief The Neumann boundary */
+  const std::shared_ptr<BoundaryPatch<GridView>> neumannBoundary_;
+
+  /** \brief The function implementing the Neumann data */
+  const Dune::VirtualFunction<Dune::FieldVector<double,dim>, Dune::FieldVector<double,dim> >* neumannFunction_;
+};
+
+}  // namespace Dune::Elasticity
+
+
 namespace Dune {
 
 template<class GridView, class LocalFiniteElement, class field_type=double>
-class NeumannEnergy
-: public Elasticity::LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,GridView::dimension> > >
+class DUNE_DEPRECATED_MSG("Use dune-functions powerBases with LocalView concept. See Elasticity::NeumannEnergy")
+NeumannEnergy
+: public LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,GridView::dimension> > >
 {
  // grid types
   typedef typename GridView::ctype ctype;
@@ -92,6 +180,7 @@ private:
   const Dune::VirtualFunction<Dune::FieldVector<double,dim>, Dune::FieldVector<double,dim> >* neumannFunction_;
 };
 
-}
+}  // namespace Dune
+
 
 #endif   //#ifndef DUNE_ELASTICITY_MATERIALS_NEUMANNENERGY_HH
diff --git a/dune/elasticity/materials/sumenergy.hh b/dune/elasticity/materials/sumenergy.hh
index 685d51e6de6b1cb8afb9efc15910d8a953cdd835..209924678da7438f649f412c95ab7befa7fc2469 100644
--- a/dune/elasticity/materials/sumenergy.hh
+++ b/dune/elasticity/materials/sumenergy.hh
@@ -11,16 +11,56 @@
 
 #include <dune/elasticity/assemblers/localenergy.hh>
 
+namespace Dune::Elasticity {
+
+template<class LocalView, class field_type=double>
+class SumEnergy
+  : public Elasticity::LocalEnergy<LocalView, field_type>
+{
+  using GridView = typename LocalView::GridView;
+  using DT = typename GridView::Grid::ctype;
+
+  enum {dim=GridView::dimension};
+
+public:
+
+  /** \brief Constructor with a set of material parameters
+   * \param parameters The material parameters
+   */
+  SumEnergy(std::shared_ptr<Elasticity::LocalEnergy<LocalView, field_type>> a,
+            std::shared_ptr<Elasticity::LocalEnergy<LocalView, field_type>> b)
+  : a_(a),
+    b_(b)
+  {}
+
+  /** \brief Assemble the energy for a single element */
+  field_type energy (const LocalView& localView,
+                     const std::vector<field_type>& localConfiguration) const
+  {
+    return a_->energy(localView, localConfiguration)
+         + b_->energy(localView, localConfiguration);
+  }
+
+private:
+  std::shared_ptr<Elasticity::LocalEnergy<LocalView, field_type>> a_;
+  std::shared_ptr<Elasticity::LocalEnergy<LocalView, field_type>> b_;
+};
+
+}  // namespace Dune::Elasticity
+
+
 namespace Dune {
 
 template<class GridView, class LocalFiniteElement, class field_type=double>
-class SumEnergy
-: public Elasticity::LocalEnergy<GridView,LocalFiniteElement,std::vector<Dune::FieldVector<field_type,GridView::dimension> > >
+class DUNE_DEPRECATED_MSG("Use dune-functions powerBases with LocalView concept. See Elasticity::SumEnergy")
+SumEnergy
+: public LocalEnergy<GridView,LocalFiniteElement,std::vector<Dune::FieldVector<field_type,GridView::dimension> > >
 {
  // grid types
   typedef typename GridView::ctype ctype;
   typedef typename GridView::template Codim<0>::Entity Entity;
 
+  // some other sizes
   enum {dim=GridView::dimension};
 
 public:
@@ -28,8 +68,8 @@ public:
   /** \brief Constructor with a set of material parameters
    * \param parameters The material parameters
    */
-  SumEnergy(std::shared_ptr<Elasticity::LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,dim> > > > a,
-            std::shared_ptr<Elasticity::LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,dim> > > > b)
+  SumEnergy(std::shared_ptr<LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,dim> > > > a,
+            std::shared_ptr<LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,dim> > > > b)
   : a_(a),
     b_(b)
   {}
@@ -45,11 +85,13 @@ public:
 
 private:
 
-  std::shared_ptr<Elasticity::LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,dim> > > > a_;
+  std::shared_ptr<LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,dim> > > > a_;
+
+  std::shared_ptr<LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,dim> > > > b_;
 
-  std::shared_ptr<Elasticity::LocalEnergy<GridView,LocalFiniteElement,std::vector<FieldVector<field_type,dim> > > > b_;
 };
 
-}
+}  // namespace Dune
+
 
 #endif   //#ifndef DUNE_ELASTICITY_MATERIALS_SUMENERGY_HH
diff --git a/src/finite-strain-elasticity.cc b/src/finite-strain-elasticity.cc
index 848c1e5624fdbc5f5a0fa6a4e820bb92efb7541a..adf18afa768097fd76f4fb08e8b0ba015943e430 100644
--- a/src/finite-strain-elasticity.cc
+++ b/src/finite-strain-elasticity.cc
@@ -25,7 +25,6 @@
 
 #include <dune/fufem/boundarypatch.hh>
 #include <dune/fufem/functiontools/boundarydofs.hh>
-#include <dune/fufem/functionspacebases/dunefunctionsbasis.hh>
 #include <dune/fufem/dunepython.hh>
 
 #include <dune/solvers/solvers/iterativesolver.hh>
@@ -151,16 +150,28 @@ int main (int argc, char *argv[]) try
   GridView gridView = grid->leafGridView();
 #endif
 
-  // FE basis spanning the FE space that we are working in
-  typedef Dune::Functions::LagrangeBasis<GridView, order> FEBasis;
-  FEBasis feBasis(gridView);
+
+  ////////////////////////////////////////////
+  // Basis
+  ////////////////////////////////////////////
+
+  using namespace Dune::Functions::BasisFactory;
+  auto basis = makeBasis(
+    gridView,
+    power<dim>(
+      lagrange<order>(),
+      blockedInterleaved()
+  ));
+
+  using PowerBasis = decltype(basis);
+  using LocalView = typename PowerBasis::LocalView;
 
   // /////////////////////////////////////////
   //   Read Dirichlet values
   // /////////////////////////////////////////
 
-  BitSetVector<1> dirichletVertices(gridView.size(dim), false);
-  BitSetVector<1> neumannVertices(gridView.size(dim), false);
+  BitSetVector<dim> dirichletVertices(gridView.size(dim), false);
+  BitSetVector<dim> neumannVertices(gridView.size(dim), false);
 
   const GridView::IndexSet& indexSet = gridView.indexSet();
 
@@ -185,19 +196,19 @@ int main (int argc, char *argv[]) try
   }
 
   BoundaryPatch<GridView> dirichletBoundary(gridView, dirichletVertices);
-  BoundaryPatch<GridView> neumannBoundary(gridView, neumannVertices);
+  auto neumannBoundary = std::make_shared<BoundaryPatch<GridView>>(gridView, neumannVertices);
 
-  std::cout << "On process " << mpiHelper.rank() << ": Neumann boundary has " << neumannBoundary.numFaces() << " faces\n";
+  std::cout << "On process " << mpiHelper.rank() << ": Neumann boundary has " << neumannBoundary->numFaces() << " faces\n";
 
 
-  BitSetVector<1> dirichletNodes(feBasis.size(), false);
-  constructBoundaryDofs(dirichletBoundary,feBasis,dirichletNodes);
+  BitSetVector<dim> dirichletNodes(basis.size(), false);
+  constructBoundaryDofs(dirichletBoundary,basis,dirichletNodes);
 
-  BitSetVector<1> neumannNodes(feBasis.size(), false);
-  constructBoundaryDofs(neumannBoundary,feBasis,neumannNodes);
+  BitSetVector<dim> neumannNodes(basis.size(), false);
+  constructBoundaryDofs(*neumannBoundary,basis,neumannNodes);
 
-  BitSetVector<dim> dirichletDofs(feBasis.size(), false);
-  for (size_t i=0; i<feBasis.size(); i++)
+  BitSetVector<dim> dirichletDofs(basis.size(), false);
+  for (size_t i=0; i<basis.size(); i++)
     if (dirichletNodes[i][0])
       for (int j=0; j<dim; j++)
         dirichletDofs[i][j] = true;
@@ -206,20 +217,12 @@ int main (int argc, char *argv[]) try
   //   Initial iterate
   // //////////////////////////
 
-  using namespace Dune::Functions::BasisFactory;
-  auto powerBasis = makeBasis(
-    gridView,
-    power<dim>(
-      lagrange<order>(),
-      blockedInterleaved()
-  ));
-
-  SolutionType x(feBasis.size());
+  SolutionType x(basis.size());
 
   lambda = std::string("lambda x: (") + parameterSet.get<std::string>("initialDeformation") + std::string(")");
   PythonFunction<FieldVector<double,dim>, FieldVector<double,dim> > pythonInitialDeformation(Python::evaluate(lambda));
 
-  Dune::Functions::interpolate(powerBasis, x, pythonInitialDeformation);
+  Dune::Functions::interpolate(basis, x, pythonInitialDeformation);
 
   ////////////////////////////////////////////////////////
   //   Main homotopy loop
@@ -227,12 +230,12 @@ int main (int argc, char *argv[]) try
 
   // Output initial iterate (of homotopy loop)
   SolutionType identity;
-  Dune::Functions::interpolate(powerBasis, identity, [](FieldVector<double,dim> x){ return x; });
+  Dune::Functions::interpolate(basis, identity, [](FieldVector<double,dim> x){ return x; });
 
   SolutionType displacement = x;
   displacement -= identity;
 
-  auto displacementFunction = Dune::Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,dim>>(feBasis, displacement);
+  auto displacementFunction = Dune::Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,dim>>(basis, displacement);
   auto localDisplacementFunction = localFunction(displacementFunction);
 
   //  We need to subsample, because VTK cannot natively display real second-order functions
@@ -288,33 +291,21 @@ int main (int argc, char *argv[]) try
     if(!elasticDensity)
       DUNE_THROW(Exception, "Error: Selected energy not available!");
 
-    auto elasticEnergy = std::make_shared<Elasticity::LocalIntegralEnergy<GridView,
-                                          FEBasis::LocalView::Tree::FiniteElement,
-                                          adouble>>(elasticDensity);
-
-    auto neumannEnergy = std::make_shared<NeumannEnergy<GridView,
-                                                        FEBasis::LocalView::Tree::FiniteElement,
-                                                        adouble> >(&neumannBoundary,neumannFunction.get());
+    auto elasticEnergy = std::make_shared<Elasticity::LocalIntegralEnergy<LocalView, adouble>>(elasticDensity);
 
-    SumEnergy<GridView,
-              FEBasis::LocalView::Tree::FiniteElement,
-              adouble> totalEnergy(elasticEnergy, neumannEnergy);
+    auto neumannEnergy = std::make_shared<Elasticity::NeumannEnergy<LocalView,adouble>>(neumannBoundary,neumannFunction.get());
 
-    LocalADOLCStiffness<GridView,
-                        FEBasis::LocalView::Tree::FiniteElement,
-                        SolutionType> localADOLCStiffness(&totalEnergy);
+    auto totalEnergy = std::make_shared<Elasticity::SumEnergy<LocalView,adouble>>(elasticEnergy, neumannEnergy);
 
-    // dune-fufem-style FE basis for the transition from dune-fufem to dune-functions
-    typedef DuneFunctionsBasis<FEBasis> FufemFEBasis;
-    FufemFEBasis fufemFEBasis(feBasis);
+    auto localADOLCStiffness = std::make_shared<Elasticity::LocalADOLCStiffness<LocalView>>(totalEnergy);
 
-    FEAssembler<FufemFEBasis,SolutionType> assembler(fufemFEBasis, &localADOLCStiffness);
+    Elasticity::FEAssembler<PowerBasis,SolutionType> assembler(basis, localADOLCStiffness);
 
     // /////////////////////////////////////////////////
     //   Create a Riemannian trust-region solver
     // /////////////////////////////////////////////////
 
-    TrustRegionSolver<FEBasis,SolutionType> solver;
+    TrustRegionSolver<PowerBasis,SolutionType> solver;
     solver.setup(*grid,
                  &assembler,
                  x,
@@ -346,7 +337,7 @@ int main (int argc, char *argv[]) try
     // Extract object member functions as Dune functions
     PythonFunction<FieldVector<double,dim>, FieldVector<double,dim> >   dirichletValues(dirichletValuesPythonObject.get("dirichletValues"));
 
-    Dune::Functions::interpolate(powerBasis, x, dirichletValues, dirichletDofs);
+    Dune::Functions::interpolate(basis, x, dirichletValues, dirichletDofs);
 
     // /////////////////////////////////////////////////////
     //   Solve!
@@ -365,7 +356,7 @@ int main (int argc, char *argv[]) try
     auto displacement = x;
     displacement -= identity;
 
-    auto displacementFunction = Dune::Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,dim>>(feBasis, displacement);
+    auto displacementFunction = Dune::Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,dim>>(basis, displacement);
 
     //  We need to subsample, because VTK cannot natively display real second-order functions
     SubsamplingVTKWriter<GridView> vtkWriter(gridView, Dune::refinementLevels(2));