From 707a73ffbdc42fc2ac0f3607dadb2318f0eb91e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20M=C3=BCller?= <felix.mueller2@mailbox.tu-dresden.de>
Date: Mon, 7 Oct 2019 17:51:51 +0200
Subject: [PATCH] Redesign of automatic basis, communicator and DOFVector
 updates

Major changes:
  Add wrapper class AdaptiveGrid<Grid> to be used instead of a
    dune-grid within AMDiS. This provides most of the grid interface
    and supports automatic updates of bases.
  Change: MeshCreator now returns an AdaptiveGrid
  Change: ProblemStat uses AdaptiveGrid internally and returns an
    object of that type
  Add class ParallelGlobalBasis<Basis> as a replacement for a
    dune-functions basis. This implements the complete interface and
    can be used as a replacement for a regular basis in all contexts.
    It supports automatic updates.
  Add free function makeGlobalBasis to make a ParallelGlobalBasis
  Change: AMDiS basis creators now return a ParallelGlobalBasis
  Change: ProblemStat uses ParallelGlobalBasis internally and returns
    an object of that type
  Add classes Observer/Signals. Classes can derive from those to take
    part in the automatic update feature.
  Add update(Event const& e) methods to classes using the feature
    above. They implement the action to be done when the registered
    Event is triggered.
  Remove GridTransfer[-Manager] and replace with the new
    Observer/Signals implementation
  Change: linear algebra communicator is now a part of
    ParallelGlobalBasis
  Add wrapper for DataTransfer objects that can be used instead of a
    base class pointer and performs deep-copy operations on copy
    construction and assignment
  Change: DOFVector DataTransfer member is now stored using the new
    wrapper class DataTransferWrapper
  Change: preAdapt, adapt, postAdapt callbacks are now called after
    calling the respective grid function. Classes that previously used
    any of them had their methods changed accordingly.

Minor changes:
  Remove Comm argument for ctor of [Bi-]LinearForm, DOFVector
  Change ctor argument from Comm to Basis in
    linearalgebra/<impl>/[Matrix-, Vector-]Backend.hpp
  Simplify DOFVector copy/move by defaulting
  Remove DOFVector::resize override
  Remove DOFVectorInterface.hpp
  Change: linearalgebra/Traits.hpp includes the backend-specific
    Traits file. This is required to break an include loop.
  Add global 'solver category' initfile parameter used by the ISTL
    backend communicator when no parameter  at prefix + '->category'
    is found
  Fix commented out parts in DOFVectorTest, DiscreteFunctionTest
  Add unit test for Observer functionality
  Add helper function wrap_or_share (see amdis/common/SharedPtr.hpp)
  Fix backend = ISTL check for ISTLCommTest in CMakeLists
---
 examples/periodic.cc                          |   2 +-
 src/amdis/AdaptiveGrid.hpp                    | 307 ++++++++++++++++++
 src/amdis/BiLinearForm.hpp                    |  19 +-
 src/amdis/CMakeLists.txt                      |   5 +-
 src/amdis/DOFVector.hpp                       | 183 ++++-------
 src/amdis/DOFVectorInterface.hpp              |  28 --
 src/amdis/DataTransfer.hpp                    |  83 ++++-
 src/amdis/DataTransfer.inc.hpp                |  28 +-
 src/amdis/GridTransfer.hpp                    | 203 ------------
 src/amdis/GridTransferManager.hpp             | 106 ------
 src/amdis/LinearForm.hpp                      |  25 +-
 src/amdis/MeshCreator.hpp                     |  14 +-
 src/amdis/Observer.hpp                        | 232 +++++++++++++
 src/amdis/ProblemStat.hpp                     |  58 ++--
 src/amdis/ProblemStat.inc.hpp                 |  84 +++--
 src/amdis/ProblemStatTraits.hpp               |  12 +-
 src/amdis/common/CMakeLists.txt               |   3 +-
 src/amdis/common/SharedPtr.hpp                |  62 ++++
 src/amdis/functions/CMakeLists.txt            |   1 +
 src/amdis/functions/ParallelGlobalBasis.hpp   | 293 +++++++++++++++++
 src/amdis/io/FileWriterCreator.hpp            |   3 +-
 src/amdis/linearalgebra/Communication.hpp     |   4 +-
 src/amdis/linearalgebra/MatrixBase.hpp        |  24 +-
 src/amdis/linearalgebra/Traits.hpp            |  14 +-
 src/amdis/linearalgebra/VectorBase.hpp        |  33 +-
 .../linearalgebra/eigen/MatrixBackend.hpp     |   3 +-
 .../linearalgebra/eigen/VectorBackend.hpp     |   3 +-
 .../linearalgebra/istl/Communication.hpp      |   1 +
 .../linearalgebra/istl/Communication.inc.hpp  |  12 +-
 .../linearalgebra/istl/MatrixBackend.hpp      |   3 +-
 .../linearalgebra/istl/VectorBackend.hpp      |   3 +-
 src/amdis/linearalgebra/mtl/MatrixBackend.hpp |   3 +-
 src/amdis/linearalgebra/mtl/VectorBackend.hpp |   3 +-
 .../linearalgebra/petsc/MatrixBackend.hpp     |  11 +-
 .../petsc/MatrixNnzStructure.hpp              |   4 +-
 .../petsc/MatrixNnzStructure.inc.hpp          |  15 +-
 .../linearalgebra/petsc/VectorBackend.hpp     |   8 +-
 test/BackupRestoreTest.cpp                    |   2 +-
 test/CMakeLists.txt                           |  15 +-
 test/DOFVectorTest.cpp                        | 109 ++++---
 test/DiscreteFunctionTest.cpp                 |  76 +++--
 test/GlobalIdSetTest.cpp                      |   2 +-
 test/GradientTest.cpp                         |  19 +-
 test/ISTLCommTest.cpp                         |  22 +-
 test/MarkerTest.cpp                           |   4 +-
 test/ObserverTest.cpp                         | 180 ++++++++++
 test/ProblemStatTest.cpp                      |  11 +-
 47 files changed, 1585 insertions(+), 750 deletions(-)
 create mode 100644 src/amdis/AdaptiveGrid.hpp
 delete mode 100644 src/amdis/DOFVectorInterface.hpp
 delete mode 100644 src/amdis/GridTransfer.hpp
 delete mode 100644 src/amdis/GridTransferManager.hpp
 create mode 100644 src/amdis/Observer.hpp
 create mode 100644 src/amdis/common/SharedPtr.hpp
 create mode 100644 src/amdis/functions/ParallelGlobalBasis.hpp
 create mode 100644 test/ObserverTest.cpp

diff --git a/examples/periodic.cc b/examples/periodic.cc
index 02218df1..8236d99c 100644
--- a/examples/periodic.cc
+++ b/examples/periodic.cc
@@ -65,7 +65,7 @@ void run(Grid& grid)
   using BC = PeriodicBC<FieldVector<double,2>, typename Traits::GlobalBasis::MultiIndex>;
   BC periodicBC(prob.boundaryManagerPtr(),-1,{{{1.0,0.0}, {0.0,1.0}}, {1.0, 0.0}});
 
-  periodicBC.init(prob.globalBasis(), prob.globalBasis());
+  periodicBC.init(*prob.globalBasis(), *prob.globalBasis());
   std::cout << "periodicNodes:\n";
   for (std::size_t i = 0; i < periodicBC.periodicNodes().size(); ++i)
     std::cout << i << ": " << periodicBC.periodicNodes()[i] << "\n";
diff --git a/src/amdis/AdaptiveGrid.hpp b/src/amdis/AdaptiveGrid.hpp
new file mode 100644
index 00000000..e9303e8c
--- /dev/null
+++ b/src/amdis/AdaptiveGrid.hpp
@@ -0,0 +1,307 @@
+#pragma once
+
+#include <algorithm>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <shared_mutex>
+#include <type_traits>
+#include <utility>
+
+#include <dune/common/parallel/mpihelper.hh>
+#include <dune/common/timer.hh>
+
+#include <dune/geometry/type.hh>
+
+#include <amdis/common/ConceptsBase.hpp>
+#include <amdis/common/SharedPtr.hpp>
+#include <amdis/Observer.hpp>
+#include <amdis/Output.hpp>
+
+namespace AMDiS
+{
+  namespace Impl
+  {
+    template <class Grid, class... Args,
+    REQUIRES(std::is_convertible<decltype(std::declval<Grid>().loadBalance()), bool>::value)>
+    bool loadBalanceImpl(Grid& grid, Args&&... args)
+    {
+      return grid.loadBalance(FWD(args)...);
+    }
+
+    // Workaround for grids not adhering to the correct interface
+    template <class Grid, class... Args,
+    REQUIRES(not std::is_convertible<decltype(std::declval<Grid>().loadBalance()), bool>::value)>
+    bool loadBalanceImpl(Grid& grid, Args&&... args)
+    {
+      grid.loadBalance(FWD(args)...);
+      return true;
+    }
+  }
+
+  namespace event
+  {
+    /** Event generated from an AdaptiveGrid when calling preAdapt(). It contains the return value
+     *  of preAdapt() as its 'mightCoarsen' member and is passed to registered observers after
+     *  calling preAdapt on the underlying grid.
+     */
+    struct preAdapt { bool mightCoarsen; };
+
+    /** Event generated from an AdaptiveGrid when calling adapt(). Its 'adapted' member contains the
+     *  value true if either preAdapt() or adapt() returned true. This event is passed to registered
+     *  observers after calling adapt on the underlying grid.
+     */
+    struct adapt { bool adapted; };
+
+    /** Event generated from an AdaptiveGrid when calling postAdapt().This event is passed to
+     *  registered observers after calling postAdapt on the underlying grid.
+     */
+    struct postAdapt {};
+  }
+
+  /** Wrapper class for Dune-grids that allows automatic signalling of events during grid adaptation
+   *  This class needs to be created after construction of the associated grid by calling the
+   *  instance method.
+   *  Calls to grid.preAdapt(), grid.adapt() and grid.postAdapt() need to be replaced by calls to
+   *  the corresponding methods of this class to use the automatic update functionality.
+   */
+  template <class Grid>
+  class AdaptiveGrid
+      : public Signals<event::preAdapt, event::adapt, event::postAdapt>
+  {
+    using Self = AdaptiveGrid<Grid>;
+    using Element = typename Grid::template Codim<0>::Entity;
+    struct HiddenStruct {};
+
+  public:
+    using HostGrid = Grid;
+    enum { dimension = HostGrid::dimension };
+    enum { dimensionworld = HostGrid::dimensionworld };
+    using LeafGridView = typename HostGrid::LeafGridView;
+    using LevelGridView = typename HostGrid::LevelGridView;
+
+    template <int cd>
+    struct Codim
+    {
+      using Geometry = typename HostGrid::template Codim<cd>::Geometry;
+      using Entity = typename HostGrid::template Codim<cd>::Entity;
+    };
+
+    using GlobalIdSet = typename HostGrid::GlobalIdSet;
+    using LocalIdSet = typename HostGrid::LocalIdSet;
+    using LevelIndexSet = typename HostGrid::LevelIndexSet;
+    using LeafIndexSet = typename HostGrid::LeafIndexSet;
+
+    /// Constructor that may only be called indirectly via the instance method
+    explicit AdaptiveGrid(std::shared_ptr<HostGrid> grid, HiddenStruct)
+      : hostGrid_(std::move(grid))
+    {}
+
+    /// Unreachable constructor required to compile the unreachable branch in instance method
+    explicit AdaptiveGrid(std::shared_ptr<HostGrid const> grid, HiddenStruct)
+    {
+      error_exit("Cannot create AdaptiveGrid from const Grid.");
+    }
+
+    int maxLevel() const { return hostGrid_->maxLevel(); }
+
+    int size(int level, int codim) const { return hostGrid_->size(level, codim); }
+
+    /// Return number of leaf entities of a given codim in this process
+    int size(int codim) const { return hostGrid_->size(codim); }
+
+    /// Return number of entities per level and geometry type in this process
+    int size(int level, Dune::GeometryType type) const { return hostGrid_->size(level, type); }
+
+    /// Return number of leaf entities per geometry type in this process
+    int size(Dune::GeometryType type) const { return hostGrid_->size(type); }
+
+    auto numBoundarySegments () const { return hostGrid_->numBoundarySegments(); }
+
+    /// View for a grid level for All_Partition
+    LevelGridView levelGridView(int l) const { return hostGrid_->levelGridView(l); }
+
+    /// View for the leaf grid for All_Partition
+    LeafGridView leafGridView() const { return hostGrid_->leafGridView(); }
+
+    GlobalIdSet const& globalIdSet() const { return hostGrid_->globalIdSet(); }
+
+    /// return const reference to the host grids local id set
+    LocalIdSet const& localIdSet() const { return hostGrid_->localIdSet(); }
+
+    /// return const reference to the host grids level index set for level level
+    LevelIndexSet const& levelIndexSet(int level) const { return hostGrid_->levelIndexSet(level); }
+
+    /// return const reference to the host grids leaf index set
+    LeafIndexSet const& leafIndexSet() const { return hostGrid_->leafIndexSet(); }
+
+    /// Refines all grid elements refCount times.
+    void globalRefine(int refCount)
+    {
+      for (int i = 0; i < refCount; ++i) {
+        // mark all entities for grid refinement
+        for (const auto& element : elements(hostGrid_->leafGridView()))
+          hostGrid_->mark(1, element);
+        preAdapt();
+        adapt();
+        postAdapt();
+      }
+    }
+
+    /// Mark entity for refinement
+    bool mark(int refCount, Element const& e) { return hostGrid_->mark(refCount, e); }
+
+    /// Return refinement mark for entity
+    int getMark(Element const& e) const { return hostGrid_->getMark(e); }
+
+    /// Prepare the grid for adaptation and notify observers of the preAdapt event
+    bool preAdapt()
+    {
+      Dune::Timer t;
+      mightCoarsen_ = hostGrid_->preAdapt();
+      Dune::MPIHelper::getCollectiveCommunication().max(&mightCoarsen_, 1);
+      this->notify(event::preAdapt{mightCoarsen_});
+      info(2,"preAdapt needed {} seconds", t.elapsed());
+      return mightCoarsen_;
+    }
+
+    /// Adapt the grid and notify observers of the adapt event
+    bool adapt()
+    {
+      Dune::Timer t;
+      refined_ = hostGrid_->adapt();
+      Dune::MPIHelper::getCollectiveCommunication().max(&refined_, 1);
+      this->notify(event::adapt{mightCoarsen_ || refined_});
+      return refined_;
+    }
+
+    /// Perform cleanup after grid adaptation and notify observers of the postAdapt event
+    void postAdapt()
+    {
+      Dune::Timer t;
+      hostGrid_->postAdapt();
+      this->notify(event::postAdapt{});
+      changeIndex_++;
+      info(2,"postAdapt needed {} seconds", t.elapsed());
+    }
+
+    /** Calls loadBalance on the underlying grid.
+     *  Re-balances the load each process has to handle for a parallel grid.
+     *  \return True if the grid has changed.
+     */
+    bool loadBalance()
+    {
+      return Impl::loadBalanceImpl(*hostGrid_);
+    }
+
+    /*  Calls loadBalance(handle) on the underlying grid.
+     *  Re-balances the load each process has to handle for a parallel grid and moves the data.
+     *  \param data A data handle telling the method which data should be communicated
+     *  and how. Has to adhere to the interface described by Dune::CommDataHandleIf.
+     *  \return True if the grid has changed.
+     */
+    template <class DataHandle>
+    bool loadBalance (DataHandle& handle)
+    {
+      return Impl::loadBalanceImpl(*hostGrid_, handle);
+    }
+
+    /// Returns the grid change index, see \ref changeIndex.
+    unsigned long changeIndex() const
+    {
+      return changeIndex_;
+    }
+
+  private:
+    template <class Grid_>
+    static std::shared_ptr<Self>
+    instanceImpl(std::shared_ptr<Grid_> grid)
+    {
+      using mutex_type = std::shared_timed_mutex;
+      static mutex_type access_mutex;
+
+      // 1. Cleanup. Since the iterators may be invalidated only one accessor is allowed. Erases all
+      //    expired weak pointers (all pointers that no longer have valid instances attached).
+      std::unique_lock<mutex_type> write_lock(access_mutex);
+      for (auto it = adaptiveGrids_.begin(); it != adaptiveGrids_.end(); ++it)
+        if (it->expired())
+          it = adaptiveGrids_.erase(it);
+      write_lock.unlock();
+
+      std::shared_lock<mutex_type> read_lock(access_mutex);
+      // 2. Find matching observed grid object. We obtain a lock here to avoid complications with
+      //    insertions made by other threads in step 3.
+      auto it = find_if(adaptiveGrids_.begin(), adaptiveGrids_.end(),
+        [&](std::weak_ptr<Self>& wPtr) {
+          auto ag = wPtr.lock();
+          return ag->hostGrid_ == grid;
+        });
+
+      // 3. Register new object or return existing. In case of inserting a new instance we obtain a
+      //    write lock.
+      if (it == adaptiveGrids_.end())
+      {
+        test_exit(!std::is_const<Grid_>::value,
+          "No existing AdaptiveGrid found and no mutable grid passed to create a new instance");
+        auto ptr = std::make_shared<Self>(std::move(grid), HiddenStruct{});
+        read_lock.unlock();
+        write_lock.lock();
+        adaptiveGrids_.emplace_back(ptr);
+        return std::move(ptr);
+      }
+      else
+      {
+        return it->lock();
+      }
+    }
+
+    // Do-nothing specialization if argument is already an AdaptiveGrid
+    static std::shared_ptr<Self> instanceImpl(std::shared_ptr<Self> grid) { return grid; }
+
+  public:
+    /** Returns the AdaptiveGrid associated to the grid passed.
+     *  If no AdaptiveGrid exists, this method creates a new one if the passed grid is mutable,
+     *  otherwise the call fails with an error.
+     */
+    template <class Grid_>
+    static std::shared_ptr<Self> instance(Grid_&& grid)
+    {
+      return instanceImpl(wrap_or_share(FWD(grid)));
+    }
+
+    // Test for equality of the grid pointers
+    bool operator==(AdaptiveGrid<HostGrid> const& that) const
+    {
+      return (hostGrid_ == that.hostGrid_);
+    }
+
+    /// Return the underlying grid
+    std::shared_ptr<HostGrid> hostGrid() const { return hostGrid_; }
+
+  private:
+    /// List of previously created instances, indexed by address of the HostGrid.
+    /**
+     *  For each grid type Grid we maintain a list of instances handed out by the instance method.
+     *  We use weak pointers here that are valid as long as there is at least one other place where
+     *  the shared pointer to the instance is used. When the instance is no longer used the weak
+     *  pointers here do not hinder the object's destruction.
+     */
+    static std::list<std::weak_ptr<Self>> adaptiveGrids_;
+
+    /// The underlying grid implementation
+    std::shared_ptr<HostGrid> hostGrid_;
+
+    /// Flag set during \ref preAdapt(), indicating whether any element might be coarsened in \ref adapt()
+    bool mightCoarsen_ = false;
+
+    /// Flag set during \ref adapt() indicating that at least one entity was refined
+    bool refined_ = false;
+
+    /// This index is incremented every time the grid is changed, e.g. by refinement or coarsening.
+    unsigned long changeIndex_ = 0;
+  };
+
+  template <class Grid>
+  std::list<std::weak_ptr<AdaptiveGrid<Grid>>> AdaptiveGrid<Grid>::adaptiveGrids_;
+
+} // end namespace AMDiS
diff --git a/src/amdis/BiLinearForm.hpp b/src/amdis/BiLinearForm.hpp
index ff1fda26..d3864d6d 100644
--- a/src/amdis/BiLinearForm.hpp
+++ b/src/amdis/BiLinearForm.hpp
@@ -45,12 +45,11 @@ namespace AMDiS
     using ElementMatrix = FlatMatrix<CoefficientType>;
 
   public:
-    /// Constructor. Wraps the reference into a non-destroying shared_ptr or moves
-    /// the basis into a new shared_ptr. The additional arguments can be the communication
-    /// object. If not provided, a new communication is created.
-    template <class RB_, class CB_, class... Args>
-    BiLinearForm(RB_&& rowBasis, CB_&& colBasis, Args&&... args)
-      : Super(FWD(rowBasis), FWD(colBasis), FWD(args)...)
+    /// Constructor. Wraps the reference into a non-destroying shared_ptr or moves the basis into
+    /// a new shared_ptr.
+    template <class RB_, class CB_>
+    BiLinearForm(RB_&& rowBasis, CB_&& colBasis)
+      : Super(FWD(rowBasis), FWD(colBasis))
     {
       operators_.init(*Super::rowBasis(), *Super::colBasis());
     }
@@ -123,16 +122,16 @@ namespace AMDiS
 
 
 #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
-  template <class RB, class CB, class... Args>
-  BiLinearForm(RB&&, CB&&, Args&&...)
+  template <class RB, class CB>
+  BiLinearForm(RB&&, CB&&)
     -> BiLinearForm<Underlying_t<RB>, Underlying_t<CB>>;
 #endif
 
   template <class RB, class CB, class... Args>
-  auto makeBiLinearForm(RB&& rowBasis, CB&& colBasis, Args&&... args)
+  auto makeBiLinearForm(RB&& rowBasis, CB&& colBasis)
   {
     using BLF = BiLinearForm<Underlying_t<RB>, Underlying_t<CB>>;
-    return BLF{FWD(rowBasis), FWD(colBasis), FWD(args)...};
+    return BLF{FWD(rowBasis), FWD(colBasis)};
   }
 
 } // end namespace AMDiS
diff --git a/src/amdis/CMakeLists.txt b/src/amdis/CMakeLists.txt
index 25ca9c6c..3527447c 100644
--- a/src/amdis/CMakeLists.txt
+++ b/src/amdis/CMakeLists.txt
@@ -18,6 +18,7 @@ install(FILES
     AdaptInfo.hpp
     AdaptInstationary.hpp
     AdaptionInterface.hpp
+    AdaptiveGrid.hpp
     AdaptStationary.hpp
     AMDiS.hpp
     Assembler.hpp
@@ -37,13 +38,10 @@ install(FILES
     DirichletBC.inc.hpp
     DOFVector.hpp
     DOFVector.inc.hpp
-    DOFVectorInterface.hpp
     Environment.hpp
     Flag.hpp
     GridFunctionOperator.hpp
     GridFunctions.hpp
-    GridTransfer.hpp
-    GridTransferManager.hpp
     Initfile.hpp
     InitfileParser.hpp
     Integrate.hpp
@@ -55,6 +53,7 @@ install(FILES
     Marker.hpp
     Marker.inc.hpp
     MeshCreator.hpp
+    Observer.hpp
     Operations.hpp
     OperatorList.hpp
     Output.hpp
diff --git a/src/amdis/DOFVector.hpp b/src/amdis/DOFVector.hpp
index 9a606d9b..7b1e3235 100644
--- a/src/amdis/DOFVector.hpp
+++ b/src/amdis/DOFVector.hpp
@@ -6,16 +6,35 @@
 #include <dune/common/shared_ptr.hh>
 
 #include <amdis/DataTransfer.hpp>
-#include <amdis/DOFVectorInterface.hpp>
-#include <amdis/GridTransferManager.hpp>
 #include <amdis/LinearAlgebra.hpp>
+#include <amdis/Observer.hpp>
 #include <amdis/common/Concepts.hpp>
 #include <amdis/common/TypeTraits.hpp>
 #include <amdis/gridfunctions/GridFunction.hpp>
 #include <amdis/typetree/TreePath.hpp>
 
+namespace Dune
+{
+  namespace Functions
+  {
+    template <class PB>
+    class DefaultGlobalBasis;
+  }
+}
+
 namespace AMDiS
 {
+  // Forward declarations
+  template <class PB>
+  class ParallelGlobalBasis;
+
+  namespace event
+  {
+    struct preAdapt;
+    struct postAdapt;
+    template <class B> struct basisUpdate;
+  }
+
   /// \brief The basic container that stores a base vector and a corresponding basis
   /**
    * \tparam GB  Basis of the vector
@@ -24,14 +43,14 @@ namespace AMDiS
   template <class GB, class T = double>
   class DOFVector
       : public VectorBase<GB, VectorBackend<BackendTraits<GB,T>>>
-      , public DOFVectorInterface
+      , public Observer<GB, event::preAdapt, event::basisUpdate<GB>, event::postAdapt>
   {
     using Self = DOFVector;
     using Super = VectorBase<GB, VectorBackend<BackendTraits<GB,T>>>;
+    using Obs = Observer<GB, event::preAdapt, event::basisUpdate<GB>, event::postAdapt>;
 
   public:
     using Backend = VectorBackend<BackendTraits<GB,T>>;
-    using Comm = typename Backend::Traits::Comm;
 
     using GlobalBasis = GB;
 
@@ -41,89 +60,32 @@ namespace AMDiS
     /// The type of the elements of the DOFVector
     using value_type = typename Backend::value_type;
 
-    /// Defines an interface to transfer the data during grid adaption
-    using DataTransfer = DataTransferInterface<Self>;
-
-    /// A creator for a concrete data transfer object, depending on \ref DataTransferOperation
-    using DataTransferFactory = AMDiS::DataTransferFactory<Self>;
+    /// Wrapper for the implementation of the transfer of data during grid adaption
+    using DataTransfer = DataTransferWrapper<Self>;
 
   public:
     /// Constructor. Stores the shared_ptr of the basis and creates a new DataTransfer.
-    DOFVector(std::shared_ptr<GlobalBasis> basis, std::shared_ptr<Comm> comm, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
-      : Super(basis, std::move(comm))
-      , dataTransfer_(DataTransferFactory::create(op, basis))
-    {
-      attachToGridTransfer();
-    }
-
-    /// Forwarding constructor that wraps the arguments into shared_ptr
-    template <class GB_, class Comm_,
-      REQUIRES(Concepts::Similar<GB_,GB>),
-      REQUIRES(Concepts::Similar<Comm_,Comm>)>
-    DOFVector(GB_&& basis, Comm_&& comm, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
-      : DOFVector(Dune::wrap_or_move(FWD(basis)), Dune::wrap_or_move(FWD(comm)), op)
+    DOFVector(std::shared_ptr<GB> basis,
+              DataTransferOperation op = DataTransferOperation::INTERPOLATE)
+      : Super(basis)
+      , Obs(basis)
+      , dataTransfer_(op, basis)
+      , basis_(basis)
     {}
 
+    /// Constructor creating a new basis from a Dune::Functions::DefaultGlobalBasis.
+    // TODO(FM): Replace explicit type with concept check
+    DOFVector(Dune::Functions::DefaultGlobalBasis<typename GB::PreBasis>&& basis,
+              DataTransferOperation op = DataTransferOperation::INTERPOLATE)
+      : DOFVector(std::make_shared<GB>(std::move(basis)), op)
+    {}
 
-    /// Construct the DOFVector from a basis by first creating a comm object. This constructor
-    /// Registers the basis and comm object into the \ref GridTransferManager so that it gets updated
-    /// on grid changes.
-    DOFVector(std::shared_ptr<GlobalBasis> basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
-      : DOFVector(basis, CommunicationCreator<Comm>::create(*basis), op)
-    {
-      GridTransferManager::attach(this->basis()->gridView().grid(), *this->comm(), [c=this->comm(), b=this->basis()]() -> void {
-        b->update(b->gridView());
-        c->update(*b);
-      });
-    }
-
-    /// Forwarding constructor that wraps the arguments into shared_ptr
     template <class GB_,
       REQUIRES(Concepts::Similar<GB_,GB>)>
     DOFVector(GB_&& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
       : DOFVector(Dune::wrap_or_move(FWD(basis)), op)
     {}
 
-    /// Copy constructor
-    DOFVector(Self const& that)
-      : Super(static_cast<Super const&>(that))
-      , dataTransfer_(that.dataTransfer_)
-    {
-      attachToGridTransfer();
-    }
-
-    /// Move constructor
-    DOFVector(Self&& that)
-      : Super(static_cast<Super&&>(that))
-      , dataTransfer_(std::move(that.dataTransfer_))
-    {
-      attachToGridTransfer();
-    }
-
-    /// Destructor
-    ~DOFVector() override
-    {
-      detachFromGridTransfer();
-    }
-
-    /// Copy assignment operator
-    Self& operator=(Self const& that)
-    {
-      detachFromGridTransfer();
-      Super::operator=(that);
-      dataTransfer_ = that.dataTransfer_;
-      attachToGridTransfer();
-      return *this;
-    }
-
-    /// Move assignment
-    Self& operator=(Self&& that) = default;
-
-    void resize() override
-    {
-      Super::resize();
-    }
-
 
     template <class TreePath = RootTreePath>
     auto child(TreePath const& path = {})
@@ -175,71 +137,68 @@ namespace AMDiS
 
 
     /// Return the associated DataTransfer object
-    std::shared_ptr<DataTransfer const> dataTransfer() const
+    DataTransfer const& dataTransfer() const
     {
       return dataTransfer_;
     }
 
     /// Return the associated DataTransfer object
-    std::shared_ptr<DataTransfer> dataTransfer()
+    DataTransfer& dataTransfer()
     {
       return dataTransfer_;
     }
 
-    /// Create a new DataTransfer object based on the operation type
-    void setDataTransfer(DataTransferOperation op)
-    {
-      dataTransfer_ = DataTransferFactory::create(op, this->basis());
-    }
-
     /// Assign the DataTransfer object
-    void setDataTransfer(std::shared_ptr<DataTransfer> const& dataTransfer)
+    void setDataTransfer(DataTransfer const& dataTransfer)
     {
       dataTransfer_ = dataTransfer;
     }
 
+    void setDataTransfer(DataTransfer&& dataTransfer)
+    {
+      dataTransfer_ = std::move(dataTransfer);
+    }
 
-    /// Implementation of \ref DOFVectorInterface::preAdapt
-    /// Redirects to a \ref DataTransfer object.
-    void preAdapt(bool mightCoarsen) override
+    /// Create a new DataTransfer object based on the operation type
+    void setDataTransfer(DataTransferOperation op)
     {
-      dataTransfer_->preAdapt(*this, mightCoarsen);
+      setDataTransfer(newDataTransfer(op, basis_));
     }
 
-    /// Implementation of \ref DOFVectorInterface::postAdapt
-    /// Redirects to a \ref DataTransfer object.
-    void postAdapt(bool refined) override
+    /// Override of Observer update(event::preAdapt) method. Redirects to preAdapt method of the
+    /// \ref DataTransfer object.
+    void update(event::preAdapt const& e) override
     {
-      dataTransfer_->postAdapt(*this, refined);
+      dataTransfer_.preAdapt(*this, e.mightCoarsen);
     }
 
-  private:
-    // register this DOFVector and its basis to the DataTransfer
-    void attachToGridTransfer()
+    /// Override of Observer update(event::adapt) method. Redirects to adapt method of the
+    /// \ref DataTransfer object.
+    void update(event::basisUpdate<GB> const&) override
     {
-      GridTransferManager::attach(this->basis()->gridView().grid(), *this);
+      this->resize();
+      dataTransfer_.adapt(*this);
     }
 
-    // deregister this DOFVector and its basis from the DataTransfer
-    void detachFromGridTransfer()
+    /// Override of Observer update(event::postAdapt) method. Redirects to postAdapt method of the
+    /// \ref DataTransfer object.
+    void update(event::postAdapt const&) override
     {
-      GridTransferManager::detach(this->basis()->gridView().grid(), *this);
+      dataTransfer_.postAdapt(*this);
     }
 
   private:
     /// Data interpolation when the grid changes, set by default
     /// to \ref DataTransferOperation::INTERPOLATE.
-    std::shared_ptr<DataTransfer> dataTransfer_;
+    DataTransfer dataTransfer_;
+
+    std::shared_ptr<GB> basis_;
   };
 
 #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
-  template <class GB, class C>
-  DOFVector(GB&& basis, C&& comm, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
-    -> DOFVector<Underlying_t<GB>>;
-
   template <class GB>
   DOFVector(GB&& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
-    -> DOFVector<Underlying_t<GB>>;
+    -> DOFVector<ParallelGlobalBasis<typename Underlying_t<GB>::PreBasis>>;
 #endif
 
   /// \brief Create a DOFVector from a basis.
@@ -252,21 +211,13 @@ namespace AMDiS
    * DOFVector. The default is interpolation of the data to the new grid. See
    * \ref DataTransferOperation for more options.
    **/
-  template <class ValueType = double, class GlobalBasis, class Communication>
-  DOFVector<Underlying_t<GlobalBasis>, ValueType>
-  makeDOFVector(GlobalBasis&& basis, Communication&& comm, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
-  {
-    return {FWD(basis), FWD(comm), op};
-  }
-
-  template <class ValueType = double, class GlobalBasis>
-  DOFVector<Underlying_t<GlobalBasis>, ValueType>
-  makeDOFVector(GlobalBasis&& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
+  template <class ValueType = double, class GB>
+  DOFVector<ParallelGlobalBasis<typename Underlying_t<GB>::PreBasis>, ValueType>
+  makeDOFVector(GB&& basis, DataTransferOperation op = DataTransferOperation::INTERPOLATE)
   {
     return {FWD(basis), op};
   }
 
-
 } // end namespace AMDiS
 
 #include <amdis/DOFVector.inc.hpp>
diff --git a/src/amdis/DOFVectorInterface.hpp b/src/amdis/DOFVectorInterface.hpp
deleted file mode 100644
index 316186b3..00000000
--- a/src/amdis/DOFVectorInterface.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-namespace AMDiS
-{
-  class DOFVectorInterface
-  {
-  public:
-    /// Virtual destructor
-    virtual ~DOFVectorInterface() = default;
-
-    /// Change dimension of DOFVector to dimension of basis
-    virtual void resize() = 0;
-
-    /// \brief Prepare the data interpolation between grids
-    /**
-     * \param mightCoarsen  Indicator that any element in the grid might be
-     *                      coarsened in adapt()
-     **/
-    virtual void preAdapt(bool mightCoarsen) = 0;
-
-    /// \brief Apply the actual interpolation
-    /**
-     * \param refined  Indicator that at least one entity was refined
-     **/
-    virtual void postAdapt(bool refined) = 0;
-  };
-
-} // end namespace AMDiS
diff --git a/src/amdis/DataTransfer.hpp b/src/amdis/DataTransfer.hpp
index 01c74055..3ca2a27c 100644
--- a/src/amdis/DataTransfer.hpp
+++ b/src/amdis/DataTransfer.hpp
@@ -29,11 +29,17 @@ namespace AMDiS
     /// Virtual destructor
     virtual ~DataTransferInterface() = default;
 
+    /// Clone method
+    virtual std::unique_ptr<DataTransferInterface> clone() const = 0;
+
     /// Collect data that is needed before grid adaption
     virtual void preAdapt(Container const& container, bool mightCoarsen) = 0;
 
     /// Interpolate data to new grid after grid adaption
-    virtual void postAdapt(Container& container, bool refined) = 0;
+    virtual void adapt(Container& container) = 0;
+
+    /// Perform cleanup after grid adaption
+    virtual void postAdapt(Container& container) = 0;
   };
 
 
@@ -45,13 +51,22 @@ namespace AMDiS
   class NoDataTransfer
       : public DataTransferInterface<Container>
   {
+    using Interface = DataTransferInterface<Container>;
+
   public:
-    void preAdapt(Container const& container, bool) override {}
+    std::unique_ptr<Interface> clone() const override
+    {
+      return std::make_unique<NoDataTransfer>();
+    }
+
+    void preAdapt(Container const&, bool) override {}
 
-    void postAdapt(Container& container, bool) override
+    void adapt(Container& container) override
     {
       container.resize();
     }
+
+    void postAdapt(Container&) override {}
   };
 
 
@@ -81,8 +96,15 @@ namespace AMDiS
     using NodeElementData = typename NodeDataTransfer<Node, Container, Basis>::NodeElementData;
     using ElementData = TYPEOF(makeTreeContainer<NodeElementData>(std::declval<const Tree&>()));
 
+    using Interface = DataTransferInterface<Container>;
+
   public:
-    DataTransfer(std::shared_ptr<Basis> basis);
+    DataTransfer(std::shared_ptr<Basis const> basis);
+
+    std::unique_ptr<Interface> clone() const override
+    {
+      return std::make_unique<DataTransfer<Container, Basis>>(basis_);
+    }
 
     /** Saves data contained in coeff in the PersistentContainer
      *  To be called after grid.preAdapt() and before grid.adapt()
@@ -92,9 +114,14 @@ namespace AMDiS
     /** Unpacks data from the PersistentContainer
      *  To be called after grid.adapt() and before grid.postAdapt()
      */
-    // [[expects: basis is update in gridView]]
+    // [[expects: basis is updated in gridView]]
     // [[expects: comm is updated in basis]]
-    void postAdapt(Container& coeff, bool refined) override;
+    void adapt(Container& coeff) override;
+
+    /** Performs cleanup
+     *  To be called after grid.postAdapt()
+     */
+    void postAdapt(Container& coeff) override;
 
   private:
     /// The global basis
@@ -139,6 +166,50 @@ namespace AMDiS
     }
   };
 
+
+  /** Wrapper class for (No)DataTransfer objects.
+   *  This wrapper class may be used instead of a pointer type to DataTransferInterface. It wraps
+   *  and redirects to the implementation, while providing deep copy and move functionality.
+   *  A virtual clone() method in the interface and implementation classes is required to perform
+   *  the deep copy of the implementation.
+   */
+  template <class Container>
+  class DataTransferWrapper
+  {
+    using Interface = DataTransferInterface<Container>;
+    using Factory = DataTransferFactory<Container>;
+    using Self = DataTransferWrapper<Container>;
+
+  public:
+    template <class Basis>
+    DataTransferWrapper(DataTransferOperation op, std::shared_ptr<Basis> basis)
+      : impl_(std::move(Factory::create(op, basis)))
+    {}
+
+    DataTransferWrapper(Self const& that)
+      : impl_(std::move(that.impl_->clone()))
+    {}
+
+    DataTransferWrapper(Self&& that) = default;
+
+    Self& operator=(Self const& that)
+    {
+      impl_ = std::move(that.impl_->clone());
+      return *this;
+    }
+
+    Self& operator=(Self&& that) = default;
+
+    void preAdapt(Container const& c, bool b) { impl_->preAdapt(c, b); }
+
+    void adapt(Container& c) { impl_->adapt(c); }
+
+    void postAdapt(Container& c) { impl_->postAdapt(c); }
+
+  private:
+    std::unique_ptr<Interface> impl_;
+  };
+
   /// @}
 
 } // end namespace AMDiS
diff --git a/src/amdis/DataTransfer.inc.hpp b/src/amdis/DataTransfer.inc.hpp
index 64319984..bf84ccfc 100644
--- a/src/amdis/DataTransfer.inc.hpp
+++ b/src/amdis/DataTransfer.inc.hpp
@@ -43,8 +43,7 @@ struct CoordHasher
 
 
 template <class C, class B>
-DataTransfer<C,B>::
-DataTransfer(std::shared_ptr<B> basis)
+DataTransfer<C,B>::DataTransfer(std::shared_ptr<B const> basis)
   : basis_(std::move(basis))
   , mapper_(basis_->gridView().grid(), Dune::mcmgElementLayout())
   , nodeDataTransfer_(makeTreeContainer<NDT>(basis_->localView().tree()))
@@ -64,7 +63,7 @@ preAdapt(C const& coeff, bool mightCoarsen)
   });
 
   // Make persistent DoF container
-  persistentContainer_.clear();
+  persistentContainer_.clear(); // Redundant if postAdapt was correctly called last cycle
   for (const auto& e : elements(gv))
   {
     auto it = persistentContainer_.emplace(idSet.id(e), makeTreeContainer<NodeElementData>(lv.tree()));
@@ -147,16 +146,18 @@ preAdapt(C const& coeff, bool mightCoarsen)
 
 
 template <class C, class B>
-void DataTransfer<C,B>::
-postAdapt(C& coeff, bool refined)
+void DataTransfer<C,B>::adapt(C& coeff)
 {
   coeff.init(false);
 
+  test_exit(!persistentContainer_.empty(), "No data was saved before adapting the grid, make "
+    "sure to call DataTransfer::preAdapt before calling adapt() on the grid");
+
   GridView gv = basis_->gridView();
   LocalView lv = basis_->localView();
   auto const& idSet = gv.grid().localIdSet();
   for_each_leaf_node(lv.tree(), [&](auto const& node, auto const& tp) {
-    nodeDataTransfer_[tp].postAdaptInit(lv, coeff, node);
+    nodeDataTransfer_[tp].adaptInit(lv, coeff, node);
   });
 
   mapper_.update();
@@ -221,6 +222,13 @@ postAdapt(C& coeff, bool refined)
 }
 
 
+template <class C, class B>
+void DataTransfer<C,B>::postAdapt(C&)
+{
+  persistentContainer_.clear();
+}
+
+
 /** Element-local data transfer on a single leaf node of the basis tree
  *  Handles computations related to the finite element basis node
  */
@@ -283,8 +291,8 @@ public:
                       NodeElementData const& childDOFs, bool init);
 
 
-  /// To be called once before copyLocal/prolongLocal are called within the postAdapt step
-  void postAdaptInit(LocalView const& lv, Container& coeff, Node const& node)
+  /// To be called once before copyLocal/prolongLocal are called within the adapt step
+  void adaptInit(LocalView const& lv, Container& coeff, Node const& node)
   {
     lv_ = &lv;
     node_ = &node;
@@ -293,7 +301,7 @@ public:
   }
 
   /// \brief Copy already existing data to element bound to node_
-  // [[expects: postAdaptInit to be called before]]
+  // [[expects: adaptInit to be called before]]
   void copyLocal(NodeElementData const& dofs) const
   {
     coeff_->scatter(*lv_, *node_, dofs, Assigner::assign{});
@@ -310,7 +318,7 @@ public:
    *                    coordinates in father element
    * \param init        Father element is visited for the first time
    **/
-  // [[expects: postAdaptInit to be called before]]
+  // [[expects: adaptInit to be called before]]
   template <class Trafo>
   void prolongLocal(Element const& father, NodeElementData const& fatherDOFs,
                     Trafo const& trafo, bool init);
diff --git a/src/amdis/GridTransfer.hpp b/src/amdis/GridTransfer.hpp
deleted file mode 100644
index 406245fb..00000000
--- a/src/amdis/GridTransfer.hpp
+++ /dev/null
@@ -1,203 +0,0 @@
-#pragma once
-
-#include <functional>
-#include <list>
-
-#include <amdis/AdaptionInterface.hpp>
-#include <amdis/Output.hpp>
-
-namespace AMDiS
-{
-  /**
-   * \addtogroup Adaption
-   * @{
-   **/
-
-  /// \brief Implementation of \ref AdaptionInterface for concrete Grid type.
-  template <class Grid>
-  class GridTransfer
-      : public AdaptionInterface
-  {
-    using Self = GridTransfer;
-    using Key = std::uintptr_t;
-
-    struct InterpolateCallback
-    {
-      std::function<void(bool)> preAdapt;
-      std::function<void(bool)> postAdapt;
-      int count = 0;
-    };
-
-    struct UpdateCallback
-    {
-      std::function<void(void)> update;
-      int count = 0;
-    };
-
-  public:
-    /// Bind a (mutable) grid to this GridTransfer. Must be called before any xxxAdapt() method.
-    // [[ensures: bound()]]
-    void bind(Grid& grid)
-    {
-      grid_ = &grid;
-    }
-
-    /// Release the grid from this GridTransfer
-    // [[ensures: not bound()]]
-    void unbind()
-    {
-      grid_ = nullptr;
-    }
-
-    /// Returns whether this GridTransfer is bound to a grid.
-    bool bound() const
-    {
-      return grid_ != nullptr;
-    }
-
-    /// Register data to GridTransfer.
-    /**
-     * This inserts a callback that is called in \ref preAdapt() and another that is
-     * called in \ref postAdapt() step.
-     *
-     * *Requirement:*
-     * - Data must be a model of \ref Concepts::InterpolateData
-     **/
-    template <class Data,
-      REQUIRES(Concepts::InterpolateData<Data>)>
-    void attach(Data& data)
-    {
-      auto it = interpolateCallbacks_.emplace(Key(&data), InterpolateCallback{
-        [&data](bool mightCoarsen) -> void { data.preAdapt(mightCoarsen); },
-        [&data](bool refined) -> void { data.postAdapt(refined); }});
-
-      it.first->second.count++;
-    }
-
-    /// Register data to GridTransfer.
-    /**
-     * This inserts a callback that is called after the \ref adapt() step.
-     * The callback calls `data.update(data.gridView())`.
-     *
-     * *Requirement:*
-     * - Data must be a model of \ref Concepts::UpdateData
-     **/
-    template <class Data,
-      REQUIRES(Concepts::UpdateData<Data>)>
-    void attach(Data& data)
-    {
-      attach(data, [&data]() -> void { data.update(data.gridView()); });
-    }
-
-    /// Register callback to GridTransfer
-    template <class Data, class Callback>
-    void attach(Data const& data, Callback&& callback)
-    {
-      auto it = updateCallbacks_.emplace(Key(&data), UpdateCallback{FWD(callback)});
-      it.first->second.count++;
-    }
-
-    /// Unregister data from GridTransfer. Data is identified by its address.
-    template <class Data,
-      REQUIRES(Concepts::InterpolateData<Data>)>
-    void detach(Data const& data)
-    {
-      eraseCallback(interpolateCallbacks_, Key(&data));
-    }
-
-    /// Unregister data from GridTransfer. Data is identified by its address.
-    template <class Data,
-      REQUIRES(Concepts::UpdateData<Data>)>
-    void detach(Data const& data)
-    {
-      eraseCallback(updateCallbacks_, Key(&data));
-    }
-
-    /// Implements \ref GridTransferInterface::preAdapt
-    // [[expects: bound()]]
-    bool preAdapt() override
-    {
-      assert(bound());
-      Dune::Timer t;
-      mightCoarsen_ = grid_->preAdapt();
-      Dune::MPIHelper::getCollectiveCommunication().max(&mightCoarsen_, 1);
-
-      for (auto&& data : interpolateCallbacks_)
-        data.second.preAdapt(mightCoarsen_);
-
-      info(2,"preAdapt needed {} seconds", t.elapsed());
-      return mightCoarsen_;
-    }
-
-    /// Implements \ref GridTransferInterface::adapt
-    // [[expects: bound()]]
-    bool adapt() override
-    {
-      assert(bound());
-      Dune::Timer t;
-      refined_ = grid_->adapt();
-      Dune::MPIHelper::getCollectiveCommunication().max(&refined_, 1);
-
-      info(2,"adapt needed {} seconds", t.elapsed());
-      return refined_;
-    }
-
-    /// Implements \ref GridTransferInterface::postAdapt
-    // [[expects: bound()]]
-    void postAdapt() override
-    {
-      assert(bound());
-      Dune::Timer t;
-      if (mightCoarsen_ || refined_) {
-        for (auto&& data : updateCallbacks_)
-          data.second.update();
-        for (auto&& data : interpolateCallbacks_)
-          data.second.postAdapt(refined_);
-      }
-
-      grid_->postAdapt();
-      changeIndex_++;
-      info(2,"postAdapt needed {} seconds", t.elapsed());
-    }
-
-    /// Returns the grid change index, see \ref changeIndex.
-    unsigned long changeIndex() const
-    {
-      return changeIndex_;
-    }
-
-  private:
-    // remove entry from map if count <= 1, otherwise reduce count by 1
-    template <class Map>
-    void eraseCallback(Map& map, Key key)
-    {
-      auto it = map.find(key);
-      if (it == map.end())
-        warning("Data to detach not found");
-      else if (it->second.count > 1)
-        it->second.count--;
-      else
-        map.erase(it);
-    }
-
-  private:
-    /// A grid this GridTransfer is bound to in \ref bind()
-    Grid* grid_ = nullptr;
-
-    /// A list of data containers handled during grid adaption
-    std::map<Key,InterpolateCallback> interpolateCallbacks_;
-    std::map<Key,UpdateCallback> updateCallbacks_;
-
-    /// Flag set during \ref preAdapt(), indicating whether any element might be coarsened in \ref adapt()
-    bool mightCoarsen_ = false;
-
-    /// Flag set during \ref adapt() indicating that at least one entity was refined
-    bool refined_ = false;
-
-    /// This index is incremented every time the grid is changed, e.g. by refinement or coarsening.
-    unsigned long changeIndex_ = 0;
-  };
-
-  /// @}
-
-} // end namespace AMDiS
diff --git a/src/amdis/GridTransferManager.hpp b/src/amdis/GridTransferManager.hpp
deleted file mode 100644
index 45375be2..00000000
--- a/src/amdis/GridTransferManager.hpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#pragma once
-
-#include <cstdint>
-#include <map>
-#include <memory>
-
-#include <amdis/AdaptionInterface.hpp>
-#include <amdis/GridTransfer.hpp>
-#include <amdis/common/ConcurrentCache.hpp>
-
-namespace AMDiS
-{
-  /**
-   * \addtogroup Adaption
-   * @{
-   **/
-
-  /// Static administration class for automatic handling of DOFVectors during grid adaption
-  class GridTransferManager
-  {
-    using Self = GridTransferManager;
-    using Key = std::uintptr_t;
-    using Data = std::shared_ptr<AdaptionInterface>;
-
-  private:
-    // Constructors. Since this is a static class you cannot call any constructor.
-    GridTransferManager() = delete;
-
-  public:
-    /**
-     * \brief Adapts the grid according to previously set marks and performs data transfer on
-     *        all DOFVectors associated to the given grid.
-     *
-     * This function retrieves the grid's stored GridTransfer and calls its adaptation methods.
-     * During this process the grid will change according to previously set grid element markings.
-     * All DOFVectors associated to the given grid will be interpolated to the new grid according to
-     * their DataTransfer member object.
-     *
-     * Takes a grid as argument. Marking of the grid needs to be performed prior to calling this.
-     * Returns true if the grid changed during adaptation.
-     **/
-    template <class Grid>
-    static bool adapt(Grid& grid)
-    {
-      auto transfer = gridTransfer(grid);
-      bool adapted = transfer->preAdapt();
-      adapted |= transfer->adapt();
-      transfer->postAdapt();
-      return adapted;
-    }
-
-    /// Returns the GridTransfer bound to a Grid, to be used during the adaptation cycle
-    template <class Grid>
-    static std::shared_ptr<GridTransfer<Grid>> gridTransfer(Grid& grid)
-    {
-      auto transfer = get(grid);
-      transfer->bind(grid);
-      return transfer;
-    }
-
-  public:
-    template <class Grid, class Data>
-    static void attach(Grid const& grid, Data& data)
-    {
-      get(grid)->attach(data);
-    }
-
-    template <class Grid, class Data, class Callback>
-    static void attach(Grid const& grid, Data const& data, Callback&& callback)
-    {
-      get(grid)->attach(data, FWD(callback));
-    }
-
-    template <class Grid, class Data>
-    static void detach(Grid const& grid, Data const& data)
-    {
-      get(grid)->detach(data);
-    }
-
-
-    /// \brief Returns the GridTransfer class, used for attaching and detaching Data
-    /**
-     * NOTE: The returned GridTransfer is not yet bound to a grid, since a
-     * mutable reference `Grid&` is needed for the binding.
-     **/
-    template <class Grid>
-    static std::shared_ptr<GridTransfer<Grid>> get(Grid const& grid)
-    {
-      Key key = Key(&grid);
-      GridTransferCache cache;
-      auto& gridTransferInterface = cache.get(key, [&](Key const&)
-      {
-        return std::make_unique<GridTransfer<Grid>>();
-      });
-
-      return std::dynamic_pointer_cast<GridTransfer<Grid>>(gridTransferInterface);
-    }
-
-  private:
-    // Associate to each Grid (represented as address) a GridTransfer
-    using GridTransferCache = ConcurrentCache< Key, Data, StaticLockedPolicy, std::map<Key, Data> >;
-  };
-
-  /// @}
-
-} // end namespace AMDiS
diff --git a/src/amdis/LinearForm.hpp b/src/amdis/LinearForm.hpp
index a57ec0f1..8601d904 100644
--- a/src/amdis/LinearForm.hpp
+++ b/src/amdis/LinearForm.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <dune/common/typeutilities.hh>
+
 #include <amdis/LinearAlgebra.hpp>
 #include <amdis/OperatorList.hpp>
 #include <amdis/common/FlatVector.hpp>
@@ -25,7 +27,6 @@ namespace AMDiS
 
   public:
     using Backend = VectorBackend<BackendTraits<GB,T>>;
-    using Comm = typename Backend::Traits::Comm;
 
     /// The type of the functionspace basis associated to this linearform
     using GlobalBasis = GB;
@@ -42,12 +43,10 @@ namespace AMDiS
 
   public:
     /// Constructor. Stores the shared_ptr of the basis and creates a new DataTransfer.
-    /// The additional arguments can be the communication object. If not provided,
-    /// a new communication is created.
-    template <class GB_, class... Args,
-      Dune::disableCopyMove<Self, GB_, Args...> = 0>
-    explicit LinearForm(GB_&& basis, Args&&... args)
-      : Super(FWD(basis), FWD(args)...)
+    template <class GB_,
+      Dune::disableCopyMove<Self, GB_> = 0>
+    explicit LinearForm(GB_&& basis)
+      : Super(FWD(basis))
     {
       operators_.init(*Super::basis());
     }
@@ -117,16 +116,16 @@ namespace AMDiS
 
 
 #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
-  template <class GB, class... Args>
-  LinearForm(GB&& basis, Args&&... args)
-    -> LinearForm<Underlying_t<GB>, double>;
+  template <class GB>
+  LinearForm(GB&& basis)
+    -> LinearForm<Underlying_t<GB>>;
 #endif
 
-  template <class T = double, class GB, class... Args>
-  auto makeLinearForm(GB&& basis, Args&&... args)
+  template <class T = double, class GB>
+  auto makeLinearForm(GB&& basis)
   {
     using LF = LinearForm<Underlying_t<GB>, T>;
-    return LF{FWD(basis), FWD(args)...};
+    return LF{FWD(basis)};
   }
 
 } // end namespace AMDiS
diff --git a/src/amdis/MeshCreator.hpp b/src/amdis/MeshCreator.hpp
index 41d1d0b9..743ec9e0 100644
--- a/src/amdis/MeshCreator.hpp
+++ b/src/amdis/MeshCreator.hpp
@@ -15,6 +15,7 @@
 #include <dune/grid/io/file/gmshreader.hh>
 #include <dune/grid/utility/structuredgridfactory.hh>
 
+#include <amdis/AdaptiveGrid.hpp>
 #include <amdis/Initfile.hpp>
 #include <amdis/Output.hpp>
 #include <amdis/common/Concepts.hpp>
@@ -63,27 +64,28 @@ namespace AMDiS
      *
      * Otherwise tries to create a grid depending on the grid type.
      **/
-    std::unique_ptr<Grid> create() const
+    std::shared_ptr<AdaptiveGrid<Grid>> create() const
     {
       auto filename = Parameters::get<std::string>(name_ + "->macro file name");
       auto structured = Parameters::get<std::string>(name_ + "->structured");
+      std::shared_ptr<Grid> gridPtr;
       if (filename) {
         // read a macro file
-        return create_unstructured_grid(filename.value());
+        gridPtr = create_unstructured_grid(filename.value());
       } else if (structured) {
         // create structured grids
         if (structured.value() == "cube") {
-          return create_cube_grid();
+          gridPtr = create_cube_grid();
         } else if (structured && structured.value() == "simplex") {
-          return create_simplex_grid();
+          gridPtr = create_simplex_grid();
         } else {
           error_exit("Unknown structured grid type. Must be either `cube` or `simplex` in parameter [meshName]->structured.");
-          return {};
         }
       } else {
         // decide by inspecting the grid type how to create the grid
-        return create_by_gridtype<Grid>(Dune::PriorityTag<42>{});
+        gridPtr = create_by_gridtype<Grid>(Dune::PriorityTag<42>{});
       }
+      return AdaptiveGrid<Grid>::instance(gridPtr);
     }
 
     /// Create a structured cube grid
diff --git a/src/amdis/Observer.hpp b/src/amdis/Observer.hpp
new file mode 100644
index 00000000..62383a9f
--- /dev/null
+++ b/src/amdis/Observer.hpp
@@ -0,0 +1,232 @@
+#pragma once
+
+#include <algorithm>
+#include <list>
+#include <memory>
+#include <type_traits>
+
+#include <amdis/common/ConceptsBase.hpp>
+#include <amdis/Output.hpp>
+
+namespace AMDiS
+{
+  namespace Impl
+  {
+    // Forward declaration
+    template <class Event>
+    class SignalInterface;
+
+    template <class Event>
+    class ObserverInterface
+    {
+    public:
+      virtual ~ObserverInterface() = default;
+
+      /// Attach the observer to a subject. It will then receive notifications from the subject when
+      /// an event of type Event it triggered.
+      void attach(std::shared_ptr<SignalInterface<Event>> const& subject)
+      {
+        subject->attachObserver(this);
+      }
+
+      /// Detach the observer from the subject. It will then no longer receive notifications. This
+      /// must be called before the observer is deleted.
+      void detach(std::shared_ptr<SignalInterface<Event>> const& subject)
+      {
+        subject->detachObserver(this);
+      }
+
+      /// This method will be called by the subject when triggering the event.
+      virtual void update(Event const&)
+      {
+        error_exit("Method must be overridden by derived class");
+      }
+    };
+
+    template <class Event>
+    class SignalInterface
+    {
+    public:
+      virtual ~SignalInterface() = default;
+
+      /// Attaches an observer to this class. This method will be called by all observers with
+      /// with themselves as argument.
+      virtual void attachObserver(ObserverInterface<Event>*) = 0;
+
+      /// Detaches an observer to this class. This method will be called by all observers with
+      /// with themselves as argument.
+      virtual void detachObserver(ObserverInterface<Event>*) = 0;
+
+      /// Notify all observers that have called attachObserver but have not called detachObserver
+      virtual void notify(Event const&) const = 0;
+    };
+
+    template <class Event>
+    class SignalsImpl
+        : virtual public SignalInterface<Event>
+    {
+    public:
+      virtual ~SignalsImpl() = default;
+
+      void attachObserver(ObserverInterface<Event>* o) override
+      {
+        observers_.push_back(o);
+      }
+
+      void detachObserver(ObserverInterface<Event>* o) override
+      {
+        auto it = std::find(observers_.begin(), observers_.end(), o);
+        if (it != observers_.end())
+          observers_.erase(it);
+      }
+
+      void notify(Event const& e) const override
+      {
+        for (ObserverInterface<Event>* o : observers_)
+          o->update(e);
+      }
+
+    private:
+      std::list<ObserverInterface<Event>*> observers_;
+    };
+
+    template <class Event>
+    class SignalsDummy
+        : virtual public SignalInterface<Event>
+    {
+    public:
+      virtual ~SignalsDummy() = default;
+      void attachObserver(ObserverInterface<Event>* o) override {}
+      void detachObserver(ObserverInterface<Event>* o) override {}
+      void notify(Event const& e) const override {}
+    };
+
+    template <class Event>
+    class ObserverImpl
+        : virtual public ObserverInterface<Event>
+    {
+      using Self = ObserverImpl;
+
+      ObserverImpl()
+        : subject_(std::make_shared<SignalsDummy<Event>>())
+      {}
+
+    public:
+      ObserverImpl(std::shared_ptr<SignalInterface<Event>> subject)
+        : subject_(std::move(subject))
+      {
+        this->attach(subject_);
+      }
+
+      // Get next subject in hierarchy if Event is not handled
+      template <class Subject,
+        REQUIRES(!std::is_convertible<std::shared_ptr<Subject>, std::shared_ptr<SignalInterface<Event>>>::value)>
+      ObserverImpl(std::shared_ptr<Subject> subject)
+        : Self(subject->getSubject())
+      {}
+
+      /// Copy constructor
+      ObserverImpl(Self const& that)
+        : subject_(that.subject_)
+      {
+        this->attach(subject_);
+      }
+
+      /// Move constructor
+      ObserverImpl(Self&& that)
+        : ObserverImpl()
+      {
+        swap(*this, that);
+      }
+
+      /// Destructor. Detaches observer from the subject
+      virtual ~ObserverImpl()
+      {
+        this->detach(subject_);
+      }
+
+      /// Copy/Move assignment
+      Self& operator=(Self that)
+      {
+        swap(*this, that);
+        return *this;
+      }
+
+      /// Swaps the contents of lhs and rhs
+      friend void swap(Self& lhs, Self& rhs)
+      {
+        using std::swap;
+        lhs.detach(lhs.subject_);
+        rhs.detach(rhs.subject_);
+        swap(lhs.subject_, rhs.subject_);
+        lhs.attach(lhs.subject_);
+        rhs.attach(rhs.subject_);
+      }
+
+    private:
+      /// The observed subject
+      std::shared_ptr<SignalInterface<Event>> subject_;
+    };
+  }
+
+  /** Mixin for signaling of certain events.
+   *  Derived classes T can emit a signal e by calling notify(e). This will send the signal to all
+   *  classes U... deriving from Observer<S, Events...> if
+   *  - the type of the event is included in Events,
+   *  - T = S or S is an Observer of T (directly or indirectly via other Observers),
+   *  - U called the Observer constructor with an instance of S that has direct or indirect access
+   *      to the instance of T (see Observer)
+   */
+  template <class Event, class... Events>
+  class Signals
+      : public Impl::SignalsImpl<Event>
+      , public Signals<Events...>
+  {
+  public:
+    using Impl::SignalsImpl<Event>::notify;
+    using Signals<Events...>::notify;
+  };
+
+  template <class Event>
+  class Signals<Event>
+      : public Impl::SignalsImpl<Event>
+  {
+  public:
+    using Impl::SignalsImpl<Event>::notify;
+  };
+
+
+  /** Mixin for reacting to certain events
+   *  Derived classes T can react to events by implementing the functions update(Event& e) for
+   *  all Events specified in the template parameter list, whose origin is an instance of class
+   *  Subject specified in the constructor to Observer and any indirectly observed class instances.
+   *  Observed instances may include:
+   *  - the instance of class Subject passed to the constructor
+   *  - the instance passed to the constructor of Subject::Observer<S> if Subject inherits from
+   *      Observer<S>
+   *  - all other instances indirectly accesible in the above way
+   *  For each event E the first object in the above hierarchy that implements Signals<Es> with E
+   *  included in Es will be observed by this class.
+   */
+  template <class Subject, class... Events>
+  class Observer
+      : public Impl::ObserverImpl<Events>...
+  {
+    template <class E>
+    friend class Impl::ObserverImpl;
+
+  public:
+    Observer(std::shared_ptr<Subject> s)
+      : Impl::ObserverImpl<Events>(s)...
+      , subject_(std::move(s))
+    {}
+
+  private:
+    /// Get the direct subject of this instance. Used by the implementation to move upwards in the
+    /// observer hierarchy.
+    std::shared_ptr<Subject> const& getSubject() { return subject_; }
+
+    std::shared_ptr<Subject> subject_;
+  };
+
+} // end namespace AMDiS
diff --git a/src/amdis/ProblemStat.hpp b/src/amdis/ProblemStat.hpp
index 02796a2d..e44a627a 100644
--- a/src/amdis/ProblemStat.hpp
+++ b/src/amdis/ProblemStat.hpp
@@ -10,8 +10,12 @@
 
 #include <dune/common/fvector.hh>
 #include <dune/common/fmatrix.hh>
+#include <dune/common/shared_ptr.hh>
+
 #include <dune/grid/common/grid.hh>
+
 #include <amdis/AdaptInfo.hpp>
+#include <amdis/AdaptiveGrid.hpp>
 #include <amdis/BiLinearForm.hpp>
 #include <amdis/CreatorInterface.hpp>
 #include <amdis/CreatorMap.hpp>
@@ -22,14 +26,15 @@
 #include <amdis/Initfile.hpp>
 #include <amdis/LinearAlgebra.hpp>
 #include <amdis/LinearForm.hpp>
-#include <amdis/OperatorList.hpp>
 #include <amdis/Marker.hpp>
 #include <amdis/MeshCreator.hpp>
+#include <amdis/OperatorList.hpp>
 #include <amdis/PeriodicBC.hpp>
 #include <amdis/ProblemStatBase.hpp>
 #include <amdis/ProblemStatTraits.hpp>
 #include <amdis/StandardProblemIteration.hpp>
 
+#include <amdis/common/SharedPtr.hpp>
 #include <amdis/common/TupleUtility.hpp>
 #include <amdis/common/TypeTraits.hpp>
 
@@ -61,7 +66,9 @@ namespace AMDiS
 
     using GlobalBasis = typename Traits::GlobalBasis;
     using GridView    = typename GlobalBasis::GridView;
-    using Grid        = typename GridView::Grid;
+    // TODO(FM): Make this GridView::Grid::HostGrid as soon as AdaptiveGrid is a complete metagrid
+    using HostGrid    = typename GridView::Grid;
+    using Grid        = AdaptiveGrid<HostGrid>;
     using Element     = typename GridView::template Codim<0>::Entity;
     using WorldVector = typename Element::Geometry::GlobalCoordinate;
     using WorldMatrix = FieldMatrix<typename WorldVector::field_type, WorldVector::dimension, WorldVector::dimension>;
@@ -89,20 +96,22 @@ namespace AMDiS
       : name_(name)
     {}
 
-    /// Constructor taking additionally a reference to a grid that is used
+    /// Constructor taking additionally a grid that is used
     /// instead of the default created grid, \ref ProblemStat
-    ProblemStat(std::string const& name, Grid& grid)
+    template <class Grid_>
+    ProblemStat(std::string const& name, Grid_&& grid)
       : ProblemStat(name)
     {
-      adoptGrid(Dune::stackobject_to_shared_ptr(grid));
+      adoptGrid(Grid::instance(FWD(grid)));
     }
 
-    /// \brief Constructor taking a grid reference and a basis reference.
-    /// Stores pointers to both.
-    ProblemStat(std::string const& name, Grid& grid, GlobalBasis& globalBasis)
-      : ProblemStat(name, grid)
+    /// \brief Constructor taking a grid and basis
+    /// Wraps both in shared pointers.
+    template <class Grid_, class GB>
+    ProblemStat(std::string const& name, Grid_&& grid, GB&& globalBasis)
+      : ProblemStat(name, FWD(grid))
     {
-      adoptGlobalBasis(Dune::stackobject_to_shared_ptr(globalBasis));
+      adoptGlobalBasis(wrap_or_share(FWD(globalBasis)));
     }
 
 
@@ -312,12 +321,11 @@ namespace AMDiS
     /// Implementation of \ref ProblemStatBase::name
     std::string const& name() const override { return name_; }
 
-
-    /// Return a reference to the grid, \ref grid
+    /// Return the \ref grid_
     std::shared_ptr<Grid>       grid()       { return grid_; }
     std::shared_ptr<Grid const> grid() const { return grid_; }
 
-    /// Return the gridView of the leaf-level
+    /// Return the gridView of the basis
     GridView gridView() const { return globalBasis_->gridView(); }
 
     /// Return the boundary manager to identify boundary segments
@@ -328,9 +336,6 @@ namespace AMDiS
     std::shared_ptr<GlobalBasis>       globalBasis()       { return globalBasis_; }
     std::shared_ptr<GlobalBasis const> globalBasis() const { return globalBasis_; }
 
-    std::shared_ptr<CommunicationType>       communication()       { return communication_; }
-    std::shared_ptr<CommunicationType const> communication() const { return communication_; }
-
     /// Return a reference to the linear solver, \ref linearSolver
     std::shared_ptr<LinearSolverType>       solver()       { return linearSolver_; }
     std::shared_ptr<LinearSolverType const> solver() const { return linearSolver_; }
@@ -385,9 +390,9 @@ namespace AMDiS
 
     /// Set the grid. Stores pointer and initializes feSpaces
     /// matrices and vectors, as well as markers and file-writers.
-    void setGrid(std::shared_ptr<Grid> const& grid)
+    void setGrid(std::shared_ptr<Grid> grid)
     {
-      adoptGrid(grid);
+      adoptGrid(std::move(grid));
       createGlobalBasis();
       createMatricesAndVectors();
       createMarker();
@@ -395,9 +400,10 @@ namespace AMDiS
     }
 
     /// Wrap the grid into a non-destroying shared_ptr
-    void setGrid(Grid& grid)
+    template <class Grid_>
+    void setGrid(Grid_&& grid)
     {
-      setGrid(Dune::stackobject_to_shared_ptr(grid));
+      setGrid(Grid::instance(FWD(grid)));
     }
 
 
@@ -444,13 +450,13 @@ namespace AMDiS
     void createMarker();
     void createFileWriter();
 
-    void adoptGlobalBasis(std::shared_ptr<GlobalBasis> const& globalBasis)
+    void adoptGlobalBasis(std::shared_ptr<GlobalBasis> globalBasis)
     {
-      globalBasis_ = globalBasis;
+      globalBasis_ = std::move(globalBasis);
       initGlobalBasis();
     }
 
-    void adoptGrid(std::shared_ptr<Grid> const& grid,
+    void adoptGrid(std::shared_ptr<Grid> grid,
                    std::shared_ptr<BoundaryManager<Grid>> const& boundaryManager)
     {
       grid_ = grid;
@@ -458,7 +464,7 @@ namespace AMDiS
       Parameters::get(name_ + "->mesh", gridName_);
     }
 
-    void adoptGrid(std::shared_ptr<Grid> const& grid)
+    void adoptGrid(std::shared_ptr<Grid> grid)
     {
       adoptGrid(grid, std::make_shared<BoundaryManager<Grid>>(grid));
     }
@@ -483,7 +489,7 @@ namespace AMDiS
     /// Management of boundary conditions
     std::shared_ptr<BoundaryManager<Grid>> boundaryManager_;
 
-    /// FE spaces of this problem.
+    /// FE space of this problem.
     std::shared_ptr<GlobalBasis> globalBasis_;
 
     /// A FileWriter object
@@ -508,8 +514,6 @@ namespace AMDiS
     /// of the equation, filled during assembling
     std::shared_ptr<SystemVector> rhs_;
 
-    std::shared_ptr<CommunicationType> communication_;
-
     /// A vector with the local element error estimates
     /// for each node in the basis tree, indexed by [to_string(treePath)][element index]
     std::map<std::string, std::vector<double>> estimates_;
diff --git a/src/amdis/ProblemStat.inc.hpp b/src/amdis/ProblemStat.inc.hpp
index c6e7fe9f..b12361d2 100644
--- a/src/amdis/ProblemStat.inc.hpp
+++ b/src/amdis/ProblemStat.inc.hpp
@@ -14,7 +14,6 @@
 #include <amdis/BackupRestore.hpp>
 #include <amdis/Assembler.hpp>
 #include <amdis/GridFunctionOperator.hpp>
-#include <amdis/GridTransferManager.hpp>
 #include <amdis/io/FileWriterCreator.hpp>
 #include <amdis/linearalgebra/SymmetryStructure.hpp>
 
@@ -57,12 +56,10 @@ void ProblemStat<Traits>::initialize(
     bool loadBalance = false;
     Parameters::get(gridName_ + "->load balance", loadBalance);
     if (loadBalance)
-      grid_->loadBalance();
+      loadBalance = grid_->loadBalance();
 
-    if (globalBasis_ && (globalRefinements > 0 || loadBalance)) {
+    if (globalBasis_ && (globalRefinements > 0 || loadBalance))
       globalBasis_->update(globalBasis_->gridView());
-      communication_->update(*globalBasis_);
-    }
   }
 
   // create fespace
@@ -84,7 +81,6 @@ void ProblemStat<Traits>::initialize(
   if (!globalBasis_)
     warning("no globalBasis created\n");
 
-
   // create system
   if (initFlag.isSet(INIT_SYSTEM))
     createMatricesAndVectors();
@@ -141,10 +137,10 @@ restore(Flag initFlag)
   test_exit(filesystem::exists(solution_filename), "Restore file '{}' not found.", solution_filename);
 
   // restore grid from file
-  if (Dune::Capabilities::hasBackupRestoreFacilities<Grid>::v)
-    adoptGrid(std::unique_ptr<Grid>(Dune::BackupRestoreFacility<Grid>::restore(grid_filename)));
+  if (Dune::Capabilities::hasBackupRestoreFacilities<HostGrid>::v)
+    adoptGrid(Grid::instance(Dune::BackupRestoreFacility<HostGrid>::restore(grid_filename)));
   else
-    adoptGrid(std::unique_ptr<Grid>(BackupRestoreByGridFactory<Grid>::restore(grid_filename)));
+    adoptGrid(Grid::instance(BackupRestoreByGridFactory<HostGrid>::restore(grid_filename)));
 
   // create fespace
   if (initFlag.isSet(INIT_FE_SPACE) || initFlag.isSet(INIT_SYSTEM))
@@ -177,12 +173,13 @@ template <class Traits>
 void ProblemStat<Traits>::createGrid()
 {
   Parameters::get(name_ + "->mesh", gridName_);
-  MeshCreator<Grid> creator(gridName_);
+  MeshCreator<HostGrid> creator(gridName_);
   grid_ = creator.create();
 
   Dune::Timer t;
-  grid_->loadBalance();
-  info(2,"load balance needed {} seconds", t.elapsed());
+  bool loadBalance = grid_->loadBalance();
+  if (loadBalance)
+    info(2,"load balance needed {} seconds", t.elapsed());
 
   boundaryManager_ = std::make_shared<BoundaryManager<Grid>>(grid_);
   if (!creator.boundaryIds().empty())
@@ -214,8 +211,10 @@ template <class Traits>
 void ProblemStat<Traits>::createGlobalBasisImpl(std::true_type)
 {
   assert( bool(grid_) );
-  static_assert(std::is_same<GridView, typename Grid::LeafGridView>::value, "");
-  globalBasis_ = std::make_shared<GlobalBasis>(Traits::create(grid_->leafGridView()));
+  // TODO(FM): Replace HostGrid -> Grid once AdaptiveGrid is full metagrid
+  static_assert(std::is_same<GridView, typename HostGrid::LeafGridView>::value, "");
+  auto basis = Traits::create(name_, grid_->leafGridView());
+  globalBasis_ = std::make_shared<GlobalBasis>(std::move(basis));
 }
 
 
@@ -231,24 +230,15 @@ void ProblemStat<Traits>::initGlobalBasis()
 {
   dirichletBCs_.init(*globalBasis_, *globalBasis_);
   periodicBCs_.init(*globalBasis_, *globalBasis_);
-
-  using CommCreator = CommunicationCreator<CommunicationType>;
-  communication_ = CommCreator::create(*globalBasis_, name_ + "->solver");
-
-  GridTransferManager::attach(*grid_, *communication_, [c=communication_, b=globalBasis_]() -> void
-  {
-    b->update(b->gridView());
-    c->update(*b);
-  });
 }
 
 
 template <class Traits>
 void ProblemStat<Traits>::createMatricesAndVectors()
 {
-  systemMatrix_ = std::make_shared<SystemMatrix>(globalBasis_, globalBasis_, communication_);
-  solution_ = std::make_shared<CoefficientVector>(globalBasis_, communication_);
-  rhs_ = std::make_shared<SystemVector>(globalBasis_, communication_);
+  systemMatrix_ = std::make_shared<SystemMatrix>(globalBasis_, globalBasis_);
+  solution_ = std::make_shared<CoefficientVector>(globalBasis_);
+  rhs_ = std::make_shared<SystemVector>(globalBasis_);
 
   auto localView = globalBasis_->localView();
   for_each_node(localView.tree(), [&,this](auto const& node, auto treePath) -> void
@@ -338,7 +328,7 @@ addDirichletBC(Predicate const& predicate, RowTreePath row, ColTreePath col, Val
   auto i = child(localView.tree(), makeTreePath(row));
   auto j = child(localView.tree(), makeTreePath(col));
 
-  auto valueGridFct = makeGridFunction(values, globalBasis_->gridView());
+  auto valueGridFct = makeGridFunction(values, this->gridView());
 
   using Range = RangeType_t<decltype(i)>;
   using BcType = DirichletBC<WorldVector,Range>;
@@ -357,7 +347,7 @@ addDirichletBC(BoundaryType id, RowTreePath row, ColTreePath col, Values const&
   auto i = child(localView.tree(), makeTreePath(row));
   auto j = child(localView.tree(), makeTreePath(col));
 
-  auto valueGridFct = makeGridFunction(values, globalBasis_->gridView());
+  auto valueGridFct = makeGridFunction(values, this->gridView());
 
   using Range = RangeType_t<decltype(i)>;
   using BcType = DirichletBC<WorldVector,Range>;
@@ -389,8 +379,8 @@ solve(AdaptInfo& adaptInfo, bool createMatrixData, bool storeMatrixData)
   solverInfo.setStoreMatrixData(storeMatrixData);
 
   solution_->resize();
-  linearSolver_->solve(systemMatrix_->backend().matrix(), solution_->backend().vector(), rhs_->backend().vector(),
-                       *communication_, solverInfo);
+  linearSolver_->solve(systemMatrix_->backend().matrix(), solution_->backend().vector(),
+                       rhs_->backend().vector(), globalBasis_->communicator(), solverInfo);
 
   if (solverInfo.info() > 0) {
     msg("solution of discrete system needed {} seconds", t.elapsed());
@@ -439,12 +429,19 @@ globalCoarsen(int n)
 {
   Dune::Timer t;
   bool adapted = false;
+  // TODO(FM): Find a less expensive alternative to the loop adaption
   for (int i = 0; i < n; ++i) {
-    // mark all entities for grid refinement
+    // mark all entities for coarsening
     for (const auto& element : elements(grid_->leafGridView()))
       grid_->mark(-1, element);
 
-    adapted |= GridTransferManager::adapt(*grid_);
+    bool adaptedInLoop = grid_->preAdapt();
+    adaptedInLoop |= grid_->adapt();
+    grid_->postAdapt();
+    if (!adaptedInLoop)
+      break;
+    else
+      adapted = true;
   }
 
   msg("globalCoarsen needed {} seconds", t.elapsed());
@@ -454,31 +451,24 @@ globalCoarsen(int n)
 
 // grid has globalRefine(int, AdaptDataHandleInterface&)
 template <class G>
-using HasGlobalRefineADHI = decltype(std::declval<G>().globalRefine(1,std::declval<GridTransfer<G>&>()));
+using HasGlobalRefineADHI = decltype(
+  std::declval<G>().globalRefine(1,std::declval<typename G::ADHI&>()));
 
 template <class Traits>
 Flag ProblemStat<Traits>::
-globalRefine(int refCount)
+globalRefine(int n)
 {
   Dune::Timer t;
-  bool adapted = false;
   Dune::Hybrid::ifElse(Dune::Std::is_detected<HasGlobalRefineADHI, Grid>{},
   /*then*/ [&](auto id) -> void {
-    // TODO(FM): Add a way to pass a GridTransfer as ADH with *globalBasis_ argument
-    id(grid_)->globalRefine(refCount, GridTransferManager::gridTransfer(*grid_));
+    id(grid_)->globalRefine(n, globalBasis_->globalRefineCallback());
   },
   /*else*/ [&](auto id) -> void {
-    for (int i = 0; i < refCount; ++i) {
-      // mark all entities for grid refinement
-      for (const auto& element : elements(grid_->leafGridView()))
-        grid_->mark(1, element);
-
-      adapted |= GridTransferManager::adapt(*id(grid_));
-    }
+    id(grid_)->globalRefine(n);
   });
 
   msg("globalRefine needed {} seconds", t.elapsed());
-  return adapted ? MESH_ADAPTED : Flag(0);
+  return n > 0 ? MESH_ADAPTED : Flag(0);
 }
 
 
@@ -488,7 +478,9 @@ adaptGrid(AdaptInfo& adaptInfo)
 {
   Dune::Timer t;
 
-  bool adapted = GridTransferManager::adapt(*grid_);
+  bool adapted = grid_->preAdapt();
+  adapted |= grid_->adapt();
+  grid_->postAdapt();
 
   msg("adaptGrid needed {} seconds", t.elapsed());
   return adapted ? MESH_ADAPTED : Flag(0);
diff --git a/src/amdis/ProblemStatTraits.hpp b/src/amdis/ProblemStatTraits.hpp
index befa48b5..87393b72 100644
--- a/src/amdis/ProblemStatTraits.hpp
+++ b/src/amdis/ProblemStatTraits.hpp
@@ -7,6 +7,8 @@
 #include <dune/grid/yaspgrid.hh>
 
 #include <amdis/common/Logical.hpp>
+#include <amdis/common/TypeTraits.hpp>
+#include <amdis/functions/ParallelGlobalBasis.hpp>
 
 namespace AMDiS
 {
@@ -69,13 +71,17 @@ namespace AMDiS
   struct DefaultBasisCreator
   {
     using GridView = typename Grid::LeafGridView;
+    static auto create(std::string const& name, GridView const& gridView)
+    {
+      return makeGlobalBasis(name, gridView, PreBasisCreator::create());
+    }
+
     static auto create(GridView const& gridView)
     {
-      using namespace Dune::Functions::BasisFactory;
-      return makeBasis(gridView, PreBasisCreator::create());
+      return makeGlobalBasis(gridView, PreBasisCreator::create());
     }
 
-    using GlobalBasis = decltype(create(std::declval<GridView>()));
+    using GlobalBasis = Underlying_t<decltype(create(std::declval<GridView>()))>;
     using CoefficientType = T;
   };
 
diff --git a/src/amdis/common/CMakeLists.txt b/src/amdis/common/CMakeLists.txt
index f14c1c24..32b15cb3 100644
--- a/src/amdis/common/CMakeLists.txt
+++ b/src/amdis/common/CMakeLists.txt
@@ -28,6 +28,7 @@ install(FILES
     Range.hpp
     Resize.hpp
     QuadMath.hpp
+    SharedPtr.hpp
     StaticSize.hpp
     String.hpp
     SwitchCases.hpp
@@ -38,4 +39,4 @@ install(FILES
     ValueCategory.hpp
 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/common)
 
-add_subdirectory(parallel)
\ No newline at end of file
+add_subdirectory(parallel)
diff --git a/src/amdis/common/SharedPtr.hpp b/src/amdis/common/SharedPtr.hpp
new file mode 100644
index 00000000..3cb9bffd
--- /dev/null
+++ b/src/amdis/common/SharedPtr.hpp
@@ -0,0 +1,62 @@
+#pragma once
+
+#include <memory>
+#include <utility>
+
+#include <dune/common/shared_ptr.hh>
+
+#include <amdis/common/TypeTraits.hpp>
+
+namespace AMDiS
+{
+  /**
+   *  Helper function converting the argument into a shared_ptr. The following cases are handled:
+   *  - objects passed as rvalue references are used to construct a new shared_ptr
+   *  - objects passed as references are used to construct a shared_ptr with a null deleter that
+   *    does nothing when the pointer is destroyed, using the stored base pointer in case of a
+   *    unique_ptr argument
+   *  - shared_ptr are simply forwarded
+   */
+  template <class T>
+  std::shared_ptr<T> wrap_or_share(T& t)
+  {
+    return Dune::stackobject_to_shared_ptr(t);
+  }
+
+  template<class T>
+  std::shared_ptr<T> wrap_or_share(T&& t)
+  {
+    return std::make_shared<T>(FWD(t));
+  }
+
+  template <class T>
+  std::shared_ptr<T> wrap_or_share(T*& t)
+  {
+    return std::shared_ptr<T>(t, Dune::null_deleter<T>());
+  }
+
+  template <class T>
+  std::shared_ptr<T> wrap_or_share(T*&& t)
+  {
+    return std::shared_ptr<T>(t);
+  }
+
+  template <class T>
+  std::shared_ptr<T> wrap_or_share(std::shared_ptr<T> t)
+  {
+    return std::move(t);
+  }
+
+  template <class T>
+  std::shared_ptr<T> wrap_or_share(std::unique_ptr<T>& t)
+  {
+    return std::shared_ptr<T>(t.get(), Dune::null_deleter<T>());
+  }
+
+  template <class T>
+  std::shared_ptr<T> wrap_or_share(std::unique_ptr<T>&& t)
+  {
+    return std::shared_ptr<T>(std::move(t));
+  }
+
+} // end namespace AMDiS
diff --git a/src/amdis/functions/CMakeLists.txt b/src/amdis/functions/CMakeLists.txt
index 4dd010be..73697b63 100644
--- a/src/amdis/functions/CMakeLists.txt
+++ b/src/amdis/functions/CMakeLists.txt
@@ -5,4 +5,5 @@ install(FILES
     Interpolate.hpp
     NodeIndices.hpp
     Nodes.hpp
+    ParallelGlobalBasis.hpp
 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/functions)
diff --git a/src/amdis/functions/ParallelGlobalBasis.hpp b/src/amdis/functions/ParallelGlobalBasis.hpp
new file mode 100644
index 00000000..81ca2ab8
--- /dev/null
+++ b/src/amdis/functions/ParallelGlobalBasis.hpp
@@ -0,0 +1,293 @@
+#pragma once
+
+
+#include <algorithm>
+#include <list>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include <dune/common/concept.hh>
+#include <dune/common/reservedvector.hh>
+#include <dune/common/shared_ptr.hh>
+#include <dune/common/typeutilities.hh>
+#include <dune/common/version.hh>
+
+#include <dune/functions/common/type_traits.hh>
+#include <dune/functions/functionspacebases/concepts.hh>
+#include <dune/functions/functionspacebases/defaultlocalview.hh>
+#include <dune/functions/functionspacebases/flatmultiindex.hh>
+
+#include <dune/grid/common/adaptcallback.hh>
+
+#include <dune/typetree/treepath.hh>
+
+#include <amdis/common/Concepts.hpp>
+#include <amdis/common/TypeTraits.hpp>
+#include <amdis/linearalgebra/Traits.hpp>
+#include <amdis/AdaptiveGrid.hpp>
+#include <amdis/Observer.hpp>
+#include <amdis/Output.hpp>
+
+#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)
+#include <dune/functions/functionspacebases/defaultlocalindexset.hh>
+#endif
+
+namespace Dune
+{
+  namespace Functions
+  {
+    // Forward declaration
+    template <class PB>
+    class DefaultGlobalBasis;
+  }
+}
+
+namespace AMDiS
+{
+  namespace event
+  {
+    template <class B>
+    struct basisUpdate
+    {
+      basisUpdate(B const& b_)
+        : basis(b_)
+      {}
+
+      B const& basis;
+    };
+  }
+
+  /**
+   * \brief Parallel global basis defined on a (sequential) pre-basis
+   *
+   * This class is an expansion to Dune::Functions::DefaultGlobalBasis<PB>. It adds a communicator
+   * to use the basis in parallel as well as automatic update functionality.
+   *
+   * \tparam PB  Pre-basis providing the implementation details
+   */
+  template <class PB>
+  class ParallelGlobalBasis
+        : public Observer<AdaptiveGrid<typename PB::GridView::Grid>, event::adapt>
+        , public Signals<event::basisUpdate<ParallelGlobalBasis<PB>>>
+  {
+    using Subject = AdaptiveGrid<typename PB::GridView::Grid>;
+    using Obs = Observer<Subject, event::adapt>;
+    using Self = ParallelGlobalBasis<PB>;
+
+    struct DummyImpl {};
+
+  public:
+
+    /// Pre-basis providing the implementation details
+    using PreBasis = PB;
+
+    /// The empty prefix path that identifies the root in the local ansatz tree
+    using PrefixPath = Dune::TypeTree::HybridTreePath<>;
+
+    /// The grid view that the FE space is defined on
+    using GridView = typename PreBasis::GridView;
+    // using Grid = typename GridView::Grid; // TODO(FM): Use once AdaptiveGrid is complete Metagrid
+    using Grid = Subject;
+
+    /// Type used for global numbering of the basis vectors
+    using MultiIndex = typename PreBasis::MultiIndex;
+
+    /// Type used for indices and size information
+    using size_type = std::size_t;
+
+    /// Type of the local view on the restriction of the basis to a single element
+    using LocalView = Dune::Functions::DefaultLocalView<Self>;
+
+    /// Type used for prefixes handed to the size() method
+    using SizePrefix = typename PreBasis::SizePrefix;
+
+#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)
+    /// Node index set provided by PreBasis
+    using NodeIndexSet = typename PreBasis::template IndexSet<PrefixPath>;
+
+    /// Type of local indixes set exported by localIndexSet()
+    using LocalIndexSet = Dune::Functions::DefaultLocalIndexSet<LocalView, NodeIndexSet>;
+#endif
+
+    /// Type of the communicator
+    using Comm = typename BackendTraits<Self>::Comm;
+
+    using ADH = Dune::AdaptDataHandle<Grid, DummyImpl>;
+
+    /**
+     * \brief Constructor
+     *
+     * \tparam T Argument list for PreBasis
+     * \param s The AdaptiveGrid providing the GridView for this basis
+     * \param t Argument list for PreBasis
+     *
+     * This will forward all arguments to the constructor of PreBasis
+     */
+    template<class... T,
+      Dune::Functions::enableIfConstructible<PreBasis, T...> = 0>
+    ParallelGlobalBasis(std::string const& name, std::shared_ptr<Subject> s, T&&... t)
+      : Obs(std::move(s))
+      , preBasis_(FWD(t)...)
+      , prefixPath_()
+    {
+      static_assert(Dune::models<Dune::Functions::Concept::PreBasis<GridView>, PreBasis>(),
+        "Type passed to ParallelGlobalBasis does not model the PreBasis concept.");
+      preBasis_.initializeIndices();
+      comm_ = CommunicationCreator<Comm>::create(*this, name + "->solver");
+    }
+
+    template <class... T>
+    ParallelGlobalBasis(std::string const& name, Subject& s, T&&... t)
+      : ParallelGlobalBasis(name, Dune::stackobject_to_shared_ptr(s), FWD(t)...)
+    {}
+
+    template <class S, class... T,
+    REQUIRES(Concepts::Same<Underlying_t<S>, Subject>)>
+    ParallelGlobalBasis(S&& s, T&&... t)
+      : ParallelGlobalBasis("", FWD(s), FWD(t)...)
+    {}
+
+    /** Converting constructor from Dune::DefaultGlobalBasis<PB>.
+     *  This will create a new ParallellGlobalBasis. The pre-basis is copied from the constructor
+     *  argument and a new communication object is built.
+     */
+    // TODO(FM): Replace explicit type with concept
+    ParallelGlobalBasis(Dune::Functions::DefaultGlobalBasis<PB>&& from)
+      : Obs(Subject::instance(from.gridView().grid()))
+      , preBasis_(from.preBasis())
+      , prefixPath_(from.prefixPath())
+    {
+      comm_ = CommunicationCreator<Comm>::create(*this);
+    }
+
+    /// Obtain the grid view that the basis is defined on
+    GridView const& gridView() const
+    {
+      return preBasis_.gridView();
+    }
+
+    /// Obtain the pre-basis providing the implementation details
+    PreBasis const& preBasis() const
+    {
+      return preBasis_;
+    }
+
+    /// Obtain the pre-basis providing the implementation details
+    PreBasis& preBasis()
+    {
+      return preBasis_;
+    }
+
+    /// Updates the underlying basis when event::adapt is triggered by the observed grid
+    void update(event::adapt const& e) override
+    {
+      if (e.adapted)
+      {
+        update(gridView());
+        event::basisUpdate<Self> eNew{*this};
+        this->notify(eNew);
+      }
+    }
+
+    /**
+     * \brief Update the stored grid view
+     *
+     * This will update the indexing information of the global basis as well as the communicator.
+     * It is called automatically if the grid has changed.
+     */
+    void update(GridView const& gv)
+    {
+      preBasis_.update(gv);
+      preBasis_.initializeIndices();
+      comm_->update(*this);
+    }
+
+    /// Get the total dimension of the space spanned by this basis
+    size_type dimension() const
+    {
+      return preBasis_.dimension();
+    }
+
+    /// Return number of possible values for next position in empty multi index
+    size_type size() const
+    {
+      return preBasis_.size();
+    }
+
+    /// Return number of possible values for next position in multi index
+    size_type size(const SizePrefix& prefix) const
+    {
+      return preBasis_.size(prefix);
+    }
+
+    /// Return local view for basis
+    LocalView localView() const
+    {
+      return LocalView(*this);
+    }
+
+    /// Return *this because we are not embedded in a larger basis
+    ParallelGlobalBasis const& rootBasis() const
+    {
+      return *this;
+    }
+
+    /// Return empty path, because this is the root in the local ansatz tree
+    PrefixPath const& prefixPath() const
+    {
+      return prefixPath_;
+    }
+
+    /// Return the communicator.
+    /// This provides the means to communicate data associated to the basis with other processes.
+    Comm const& communicator() const  { return *comm_; }
+    Comm&       communicator()        { return *comm_; }
+
+    ADH& globalRefineCallback() const
+    {
+      // TODO(FM): Implement
+      error_exit("Not implemented: ParallelGlobalBasis::globalRefineCallback()");
+      return ADH{};
+    }
+
+  protected:
+    PreBasis preBasis_;
+    PrefixPath prefixPath_;
+    std::unique_ptr<Comm> comm_;
+  };
+
+  template<class MultiIndex, class GridView, class PreBasisFactory>
+  auto makeGlobalBasis(std::string const& name, GridView const& gridView,
+                       PreBasisFactory&& preBasisFactory)
+  {
+    auto preBasis = preBasisFactory.template makePreBasis<MultiIndex>(gridView);
+    using PreBasis = std::decay_t<decltype(preBasis)>;
+
+    using Grid = typename GridView::Grid;
+    auto ag = AdaptiveGrid<Grid>::instance(gridView.grid());
+
+    return ParallelGlobalBasis<PreBasis>(name, std::move(ag), std::move(preBasis));
+  }
+
+  template<class GridView, class PreBasisFactory>
+  auto makeGlobalBasis(std::string const& name, GridView const& gridView,
+                       PreBasisFactory&& preBasisFactory)
+  {
+    using RawPreBasisFactory = std::decay_t<PreBasisFactory>;
+    using MultiIndex = std::conditional_t<
+      (RawPreBasisFactory::requiredMultiIndexSize == 1),
+      Dune::Functions::FlatMultiIndex<std::size_t>,
+      Dune::ReservedVector<std::size_t, RawPreBasisFactory::requiredMultiIndexSize>>;
+
+    return makeGlobalBasis<MultiIndex, GridView, PreBasisFactory>(name, gridView,
+      FWD(preBasisFactory));
+  }
+
+  template<class GridView, class PreBasisFactory>
+  auto makeGlobalBasis(GridView const& gridView, PreBasisFactory&& preBasisFactory)
+  {
+    return makeGlobalBasis("", gridView, FWD(preBasisFactory));
+  }
+
+} // end namespace AMDiS
diff --git a/src/amdis/io/FileWriterCreator.hpp b/src/amdis/io/FileWriterCreator.hpp
index 1193f19b..52f62913 100644
--- a/src/amdis/io/FileWriterCreator.hpp
+++ b/src/amdis/io/FileWriterCreator.hpp
@@ -24,7 +24,8 @@ namespace AMDiS
   {
     using GlobalBasis  = typename SystemVector::GlobalBasis;
     using GridView     = typename GlobalBasis::GridView;
-    using Grid         = typename GridView::Grid;
+    using Grid         = typename GlobalBasis::Grid;
+    //using Grid = typename GridView::Grid; // TODO(FM): Use once AdaptiveGrid is complete Metagrid
 
   public:
     /// Constructor. Stores the pointer to the systemVector and to the (optional) boundaryManager.
diff --git a/src/amdis/linearalgebra/Communication.hpp b/src/amdis/linearalgebra/Communication.hpp
index ba5612e2..e0809238 100644
--- a/src/amdis/linearalgebra/Communication.hpp
+++ b/src/amdis/linearalgebra/Communication.hpp
@@ -16,8 +16,8 @@ namespace AMDiS
   public:
     using Impl = SequentialCommunication;
 
-    template <class Comm>
-    SequentialCommunication(Comm&&) {}
+    template <class T>
+    SequentialCommunication(T&&) {}
 
     Impl const& get() const
     {
diff --git a/src/amdis/linearalgebra/MatrixBase.hpp b/src/amdis/linearalgebra/MatrixBase.hpp
index 60133032..38481bda 100644
--- a/src/amdis/linearalgebra/MatrixBase.hpp
+++ b/src/amdis/linearalgebra/MatrixBase.hpp
@@ -38,34 +38,16 @@ namespace AMDiS
 
     /// The Linear-Algebra backend used to store the assembled coefficients
     using Backend = B;
-    using Comm = typename B::Traits::Comm;
 
   public:
     /// (1) Constructor. Stores the shared_ptr to the bases and the communication object.
-    MatrixBase(std::shared_ptr<RB> rowBasis, std::shared_ptr<CB> colBasis,
-               std::shared_ptr<Comm> comm)
+    MatrixBase(std::shared_ptr<RB> rowBasis, std::shared_ptr<CB> colBasis)
       : rowBasis_(std::move(rowBasis))
       , colBasis_(std::move(colBasis))
-      , backend_(std::move(comm))
+      , backend_(*rowBasis_, *colBasis_)
     {}
 
-    /// (2) Constructor. Forwards to (1) by wraping reference into non-destroying
-    /// shared_ptr, see \ref Dune::wrap_or_move.
-    template <class RB_, class CB_, class Comm_,
-      REQUIRES(Concepts::Similar<Types<RB_,CB_,Comm_>, Types<RB,CB,Comm>>)>
-    MatrixBase(RB_&& rowBasis, CB_&& colBasis, Comm_&& comm)
-      : MatrixBase(Dune::wrap_or_move(FWD(rowBasis)),
-                   Dune::wrap_or_move(FWD(colBasis)),
-                   Dune::wrap_or_move(FWD(comm)))
-    {}
-
-    /// (3) Constructor. Forwards to (1) by creating a new communicator
-    MatrixBase(std::shared_ptr<RB> const& rowBasis, std::shared_ptr<CB> const& colBasis)
-      : MatrixBase(rowBasis, colBasis,
-                   std::shared_ptr<Comm>(CommunicationCreator<Comm>::create(*rowBasis)))
-    {}
-
-    /// (4) Constructor. Forwards to (3) by wrapping references into non-destroying
+    /// (2) Constructor. Forwards to (1) by wrapping reference into non-destroying
     /// shared_ptr, see \ref Dune::wrap_or_move.
     template <class RB_, class CB_,
       REQUIRES(Concepts::Similar<Types<RB_,CB_>, Types<RB,CB>>)>
diff --git a/src/amdis/linearalgebra/Traits.hpp b/src/amdis/linearalgebra/Traits.hpp
index 9f858ff2..30f08052 100644
--- a/src/amdis/linearalgebra/Traits.hpp
+++ b/src/amdis/linearalgebra/Traits.hpp
@@ -1,5 +1,18 @@
 #pragma once
 
+#if HAVE_MTL
+#include <amdis/linearalgebra/mtl/Traits.hpp>
+
+#elif HAVE_EIGEN
+#include <amdis/linearalgebra/eigen/Traits.hpp>
+
+#elif HAVE_PETSC
+#include <amdis/linearalgebra/petsc/Traits.hpp>
+
+#else // ISTL
+#include <amdis/linearalgebra/istl/Traits.hpp>
+#endif
+
 namespace AMDiS
 {
 #ifdef DOXYGEN
@@ -23,5 +36,4 @@ namespace AMDiS
     using PartitionSet = Dune::Partitions::All;  //< The dune partition set where to assemble operators
   };
 #endif
-
 } // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/VectorBase.hpp b/src/amdis/linearalgebra/VectorBase.hpp
index 36a55ad1..25fc10ed 100644
--- a/src/amdis/linearalgebra/VectorBase.hpp
+++ b/src/amdis/linearalgebra/VectorBase.hpp
@@ -44,7 +44,6 @@ namespace AMDiS
 
     /// The Linear-Algebra backend used to store the assembled coefficients
     using Backend = B;
-    using Comm = typename B::Traits::Comm;
 
   private:
     // proxy class redirecting the mutable element access to the insertValue method
@@ -65,33 +64,18 @@ namespace AMDiS
       std::integral_constant<VectorState, VectorState::insert_values>>;
 
   public:
-    /// (1) Constructor. Stores the shared_ptr of the basis and communication object.
-    VectorBase(std::shared_ptr<GB> basis, std::shared_ptr<Comm> comm)
+    /// (1) Constructor. Stores the shared_ptr of the basis.
+    VectorBase(std::shared_ptr<GB> basis)
       : basis_(std::move(basis))
-      , comm_(std::move(comm))
-      , backend_(comm_)
+      , backend_(*basis_)
     {
       resizeZero();
     }
 
-    /// (2) Constructor. Forwards to (1) by wraping reference into non-destroying
-    /// shared_ptr.
-    template <class GB_, class Comm_,
-      REQUIRES(Concepts::Similar<Types<GB_,Comm_>, Types<GB,Comm>>)>
-    VectorBase(GB_&& basis, Comm_&& comm)
-      : VectorBase(Dune::wrap_or_move(FWD(basis)), Dune::wrap_or_move(FWD(comm)))
-    {}
-
-    /// (3) Constructor. Forwards to (1) by creating a new communicator
-    explicit VectorBase(std::shared_ptr<GB> const& basis)
-      : VectorBase(basis, std::shared_ptr<Comm>(CommunicationCreator<Comm>::create(*basis)))
-    {}
-
-    /// (4) Constructor. Forwards to (3) by wrapping references into non-destroying
-    /// shared_ptr, see \ref Dune::wrap_or_move.
+    /// (2) Constructor. Forwards to (1) by wrapping reference into non-destroying shared_ptr.
     template <class GB_,
       REQUIRES(Concepts::Similar<GB_,GB>)>
-    explicit VectorBase(GB_&& basis)
+    VectorBase(GB_&& basis)
       : VectorBase(Dune::wrap_or_move(FWD(basis)))
     {}
 
@@ -99,10 +83,6 @@ namespace AMDiS
     std::shared_ptr<GlobalBasis> const& basis() const { return basis_; }
     std::shared_ptr<GlobalBasis> const& basis()       { return basis_; }
 
-    /// Return the communication object \ref comm_
-    std::shared_ptr<Comm> const& comm() const { return comm_; }
-    std::shared_ptr<Comm> const& comm()       { return comm_; }
-
     /// Return the underlying linear algebra backend
     Backend const& backend() const { return backend_; }
     Backend&       backend()       { return backend_; }
@@ -423,9 +403,6 @@ namespace AMDiS
     /// The finite element space / basis associated with the data vector
     std::shared_ptr<GlobalBasis> basis_;
 
-    /// A Communication object providing an indexSet, remoteIndices, and a dofMap.
-    std::shared_ptr<Comm> comm_;
-
     /// Data backend
     Backend backend_;
 
diff --git a/src/amdis/linearalgebra/eigen/MatrixBackend.hpp b/src/amdis/linearalgebra/eigen/MatrixBackend.hpp
index 459d5203..ed184958 100644
--- a/src/amdis/linearalgebra/eigen/MatrixBackend.hpp
+++ b/src/amdis/linearalgebra/eigen/MatrixBackend.hpp
@@ -31,7 +31,8 @@ namespace AMDiS
 
   public:
     /// Constructor. Constructs new BaseMatrix.
-    MatrixBackend(std::shared_ptr<typename Traits::Comm> const&) {}
+    template <class Basis>
+    explicit MatrixBackend(Basis const&, Basis const&) {}
 
     /// Return a reference to the data-matrix \ref matrix
     BaseMatrix& matrix()
diff --git a/src/amdis/linearalgebra/eigen/VectorBackend.hpp b/src/amdis/linearalgebra/eigen/VectorBackend.hpp
index af9e0f68..5efb9506 100644
--- a/src/amdis/linearalgebra/eigen/VectorBackend.hpp
+++ b/src/amdis/linearalgebra/eigen/VectorBackend.hpp
@@ -33,7 +33,8 @@ namespace AMDiS
 
   public:
     /// Constructor. Constructs new BaseVector.
-    VectorBackend(std::shared_ptr<typename Traits::Comm> const&) {}
+    template <class Basis>
+    explicit VectorBackend(Basis const&) {}
 
     /// Return the data-vector \ref vector_
     BaseVector const& vector() const
diff --git a/src/amdis/linearalgebra/istl/Communication.hpp b/src/amdis/linearalgebra/istl/Communication.hpp
index a4139075..08a1f2a7 100644
--- a/src/amdis/linearalgebra/istl/Communication.hpp
+++ b/src/amdis/linearalgebra/istl/Communication.hpp
@@ -4,6 +4,7 @@
 #include <string>
 
 #include <dune/common/std/optional.hh>
+
 #include <dune/istl/owneroverlapcopy.hh>
 #include <dune/istl/solvercategory.hh>
 #include <dune/istl/paamg/pinfo.hh>
diff --git a/src/amdis/linearalgebra/istl/Communication.inc.hpp b/src/amdis/linearalgebra/istl/Communication.inc.hpp
index b58be7fd..3886a9d3 100644
--- a/src/amdis/linearalgebra/istl/Communication.inc.hpp
+++ b/src/amdis/linearalgebra/istl/Communication.inc.hpp
@@ -9,12 +9,18 @@ namespace AMDiS {
 
 template <class Basis>
 std::unique_ptr<ISTLCommunication<Basis>>
-CommunicationCreator<ISTLCommunication<Basis>>::
-create(Basis const& basis, std::string const& prefix)
+CommunicationCreator<ISTLCommunication<Basis>>
+  ::create(Basis const& basis, std::string const& prefix)
 {
   using SolverType = Dune::SolverCategory::Category;
-  std::string category = "default";
+  std::string category = "";
   Parameters::get(prefix + "->category", category);
+  if (category == "")
+  {
+    // check global parameter if no local one was found
+    category = "default";
+    Parameters::get("solver category", category);
+  }
   SolverType cat;
   auto const& gv = basis.gridView();
   int mpiSize = gv.comm().size();
diff --git a/src/amdis/linearalgebra/istl/MatrixBackend.hpp b/src/amdis/linearalgebra/istl/MatrixBackend.hpp
index 4d0b4a65..a62e1135 100644
--- a/src/amdis/linearalgebra/istl/MatrixBackend.hpp
+++ b/src/amdis/linearalgebra/istl/MatrixBackend.hpp
@@ -28,7 +28,8 @@ namespace AMDiS
 
   public:
     /// Constructor. Constructs new BaseVector.
-    MatrixBackend(std::shared_ptr<typename Traits::Comm> const&) {}
+    template <class Basis>
+    explicit MatrixBackend(Basis const&, Basis const&) {}
 
     /// Return the data-vector \ref vector
     BaseMatrix const& matrix() const
diff --git a/src/amdis/linearalgebra/istl/VectorBackend.hpp b/src/amdis/linearalgebra/istl/VectorBackend.hpp
index 03bc1028..378248a6 100644
--- a/src/amdis/linearalgebra/istl/VectorBackend.hpp
+++ b/src/amdis/linearalgebra/istl/VectorBackend.hpp
@@ -28,7 +28,8 @@ namespace AMDiS
 
   public:
     /// Constructor. Constructs new BaseVector.
-    VectorBackend(std::shared_ptr<typename Traits::Comm> const&) {}
+    template <class Basis>
+    explicit VectorBackend(Basis const&) {}
 
     /// Return the data-vector \ref vector
     BaseVector const& vector() const
diff --git a/src/amdis/linearalgebra/mtl/MatrixBackend.hpp b/src/amdis/linearalgebra/mtl/MatrixBackend.hpp
index c002b8e8..364bf7c9 100644
--- a/src/amdis/linearalgebra/mtl/MatrixBackend.hpp
+++ b/src/amdis/linearalgebra/mtl/MatrixBackend.hpp
@@ -35,7 +35,8 @@ namespace AMDiS
 
   public:
     /// Constructor. Constructs new BaseMatrix.
-    MatrixBackend(std::shared_ptr<typename Traits::Comm> const&) {}
+    template <class Basis>
+    explicit MatrixBackend(Basis const&, Basis const&) {}
 
     /// Return a reference to the data-matrix \ref matrix
     BaseMatrix& matrix()
diff --git a/src/amdis/linearalgebra/mtl/VectorBackend.hpp b/src/amdis/linearalgebra/mtl/VectorBackend.hpp
index f9b3602a..c0108522 100644
--- a/src/amdis/linearalgebra/mtl/VectorBackend.hpp
+++ b/src/amdis/linearalgebra/mtl/VectorBackend.hpp
@@ -31,7 +31,8 @@ namespace AMDiS
 
   public:
     /// Constructor. Constructs new BaseVector.
-    VectorBackend(std::shared_ptr<typename Traits::Comm> const&) {}
+    template <class Basis>
+    explicit VectorBackend(Basis const&) {}
 
     /// Return the data-vector \ref vector_
     BaseVector const& vector() const
diff --git a/src/amdis/linearalgebra/petsc/MatrixBackend.hpp b/src/amdis/linearalgebra/petsc/MatrixBackend.hpp
index 656fdbdc..2c70d304 100644
--- a/src/amdis/linearalgebra/petsc/MatrixBackend.hpp
+++ b/src/amdis/linearalgebra/petsc/MatrixBackend.hpp
@@ -34,8 +34,9 @@ namespace AMDiS
 
   public:
     /// Constructor. Constructs new BaseMatrix.
-    MatrixBackend(std::shared_ptr<Communication> comm)
-      : comm_(std::move(comm))
+    template <class Basis>
+    explicit MatrixBackend(Basis const& rowBasis, Basis const& /*colBasis*/)
+      : comm_(rowBasis.communicator())
     {}
 
     // disable copy and move operations
@@ -109,7 +110,7 @@ namespace AMDiS
       Dune::Timer t;
 
       // update the non-zeros structure of the matrix.
-      pattern_.update(rowBasis, *comm_);
+      pattern_.update(rowBasis);
       info(3, "  update pattern needed {} seconds", t.elapsed());
       t.reset();
 
@@ -173,7 +174,7 @@ namespace AMDiS
     // The local-to-global map
     auto const& dofMap() const
     {
-      return comm_->dofMap();
+      return comm_.dofMap();
     }
 
     // An MPI Communicator or PETSC_COMM_SELF
@@ -194,7 +195,7 @@ namespace AMDiS
     }
 
   private:
-    std::shared_ptr<Communication> comm_;
+    Communication const& comm_;
 
     /// The data-matrix
     Mat matrix_;
diff --git a/src/amdis/linearalgebra/petsc/MatrixNnzStructure.hpp b/src/amdis/linearalgebra/petsc/MatrixNnzStructure.hpp
index ea504b28..29423da2 100644
--- a/src/amdis/linearalgebra/petsc/MatrixNnzStructure.hpp
+++ b/src/amdis/linearalgebra/petsc/MatrixNnzStructure.hpp
@@ -25,8 +25,8 @@ namespace AMDiS
 
     /// Calculate the matrix pattern from the local pattern of a basis.
     // NOTE: this assumes a square matrix with row-basis = col-basis.
-    template <class Basis, class Communication>
-    void update(Basis const& basis, Communication const& comm);
+    template <class Basis>
+    void update(Basis const& basis);
 
   private:
     std::vector<PetscInt> dnnz_; //< number of nonzeros in the diagonal part (owner part)
diff --git a/src/amdis/linearalgebra/petsc/MatrixNnzStructure.inc.hpp b/src/amdis/linearalgebra/petsc/MatrixNnzStructure.inc.hpp
index 63793587..29e493b6 100644
--- a/src/amdis/linearalgebra/petsc/MatrixNnzStructure.inc.hpp
+++ b/src/amdis/linearalgebra/petsc/MatrixNnzStructure.inc.hpp
@@ -6,7 +6,7 @@
 #include <dune/common/timer.hh>
 #include <dune/grid/common/partitionset.hh>
 
-#include <amdis/GridTransferManager.hpp>
+#include <amdis/AdaptiveGrid.hpp>
 #include <amdis/Output.hpp>
 #include <amdis/common/parallel/Communicator.hpp>
 #include <amdis/common/parallel/RequestOperations.hpp>
@@ -14,10 +14,11 @@
 
 namespace AMDiS {
 
-template <class Basis, class Communication>
-void MatrixNnzStructure::update(Basis const& basis, Communication const& c)
+template <class Basis>
+void MatrixNnzStructure::update(Basis const& basis)
 {
-  unsigned long newChangeIndex = GridTransferManager::get(basis.gridView().grid())->changeIndex();
+  using Grid = AdaptiveGrid<typename Basis::GridView::Grid>;
+  unsigned long newChangeIndex = Grid::instance(basis.gridView().grid())->changeIndex();
   bool gridChanged = newChangeIndex > changeIndex_;
   changeIndex_ = newChangeIndex;
 
@@ -27,7 +28,7 @@ void MatrixNnzStructure::update(Basis const& basis, Communication const& c)
 
   Dune::Timer t;
 
-  auto const& dofMap = c.dofMap();
+  auto const& dofMap = basis.communicator().dofMap();
   std::size_t localSize = dofMap.localSize();
   test_exit(localSize > 0, "Local domain has no owned DOFs!");
 
@@ -84,7 +85,7 @@ void MatrixNnzStructure::update(Basis const& basis, Communication const& c)
   std::vector<RemoteNz> sendList(world.size());
   std::vector<std::size_t> receiveList(world.size(), 0);
 
-  for (auto const& rim : c.remoteIndices()) {
+  for (auto const& rim : basis.communicator().remoteIndices()) {
     int p = rim.first;
 
     auto* sourceRemoteIndexList = rim.second.first;
@@ -187,4 +188,4 @@ void MatrixNnzStructure::update(Basis const& basis, Communication const& c)
   msg("update MatrixNnzStructure need {} sec", t.elapsed());
 }
 
-} // end namespace AMDiS
\ No newline at end of file
+} // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/petsc/VectorBackend.hpp b/src/amdis/linearalgebra/petsc/VectorBackend.hpp
index 21486241..3634c607 100644
--- a/src/amdis/linearalgebra/petsc/VectorBackend.hpp
+++ b/src/amdis/linearalgebra/petsc/VectorBackend.hpp
@@ -3,6 +3,7 @@
 #include <petscvec.h>
 
 #include <dune/common/ftraits.hh>
+#include <dune/common/shared_ptr.hh>
 
 #include <amdis/Output.hpp>
 #include <amdis/common/FakeContainer.hpp>
@@ -36,8 +37,9 @@ namespace AMDiS
 
   public:
     /// Constructor. Constructs new BaseVector.
-    VectorBackend(std::shared_ptr<Communication> comm)
-      : comm_(std::move(comm))
+    template <class Basis>
+    explicit VectorBackend(Basis const& basis)
+      : comm_(Dune::stackobject_to_shared_ptr(basis.communicator()))
     {}
 
     /// Move constructor
@@ -305,7 +307,7 @@ namespace AMDiS
     }
 
   private:
-    std::shared_ptr<Communication> comm_;
+    std::shared_ptr<Communication const> comm_;
 
     /// The data-vector
     mutable Vec vector_ = nullptr;
diff --git a/test/BackupRestoreTest.cpp b/test/BackupRestoreTest.cpp
index 4f6cc20f..4749405f 100644
--- a/test/BackupRestoreTest.cpp
+++ b/test/BackupRestoreTest.cpp
@@ -58,7 +58,7 @@ void test(Factory factory)
     AMDIS_TEST_EQ(num_elements, prob.grid()->size(0));
     AMDIS_TEST_EQ(num_vertices, prob.grid()->size(Grid::dimension));
 
-    DOFVector<typename Param::GlobalBasis> vec(prob.globalBasis(), prob.communication());
+    DOFVector<typename Param::GlobalBasis> vec(prob.globalBasis());
     vec.child(Dune::Indices::_0) << [](auto const& x) { return x; };
     vec.child(Dune::Indices::_1) << [](auto const& x) { return two_norm(x); };
 
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index a1095005..046593ec 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -67,11 +67,13 @@ dune_add_test(SOURCES GradientTest.cpp
 dune_add_test(SOURCES HybridSizeTest.cpp
   LINK_LIBRARIES amdis)
 
-dune_add_test(SOURCES ISTLCommTest.cpp
-  LINK_LIBRARIES amdis
-  MPI_RANKS 2 4
-  TIMEOUT 300
-  CMAKE_GUARD "MPI_FOUND AND dune-istl_FOUND")
+if(BACKEND STREQUAL "ISTL")
+  dune_add_test(SOURCES ISTLCommTest.cpp
+    LINK_LIBRARIES amdis
+    MPI_RANKS 2 4
+    TIMEOUT 300
+    CMAKE_GUARD MPI_FOUND)
+endif()
 
 dune_add_test(SOURCES IntegrateTest.cpp
   LINK_LIBRARIES amdis)
@@ -94,6 +96,9 @@ dune_add_test(SOURCES MultiTypeMatrixTest.cpp
 dune_add_test(SOURCES NodeIndicesTest.cpp
   LINK_LIBRARIES amdis)
 
+dune_add_test(SOURCES ObserverTest.cpp
+  LINK_LIBRARIES amdis)
+
 dune_add_test(SOURCES OperationsTest.cpp
   LINK_LIBRARIES amdis)
 
diff --git a/test/DOFVectorTest.cpp b/test/DOFVectorTest.cpp
index b4258119..7a448f56 100644
--- a/test/DOFVectorTest.cpp
+++ b/test/DOFVectorTest.cpp
@@ -1,15 +1,18 @@
 #include "config.h"
 
+#include <memory>
+
 #include <dune/common/filledarray.hh>
+#include <dune/common/shared_ptr.hh>
 #include <dune/grid/yaspgrid.hh>
-#include <dune/functions/backends/concepts.hh>
 #include <dune/functions/functionspacebases/compositebasis.hh>
 #include <dune/functions/functionspacebases/powerbasis.hh>
 #include <dune/functions/functionspacebases/lagrangebasis.hh>
 
+#include <amdis/AdaptiveGrid.hpp>
 #include <amdis/AMDiS.hpp>
-#include <amdis/GridTransferManager.hpp>
 #include <amdis/LinearAlgebra.hpp>
+#include <amdis/functions/ParallelGlobalBasis.hpp>
 
 #include "Tests.hpp"
 
@@ -17,23 +20,35 @@ using namespace AMDiS;
 using namespace Dune::Functions::BasisFactory;
 
 template <class B, class T>
-void test_dofvector(B const& basis, DOFVector<B,T>& vec)
+void test_dofvector(DOFVector<B,T>& vec)
 {
-  // TODO:
-  // AMDIS_TEST( vec.size() == basis.dimension() );
+  using size_type = typename DOFVector<B,T>::GlobalBasis::LocalView::size_type;
+  using value_type = typename DOFVector<B,T>::value_type;
+
+  auto const& basis = *vec.basis();
+  AMDIS_TEST( vec.localSize() == basis.dimension() );
   vec.resizeZero();
 
-//   vec = T(0);
-//   vec[0] = T(1);
-// #if HAVE_MTL || HAVE_ISTL
-//   auto m0 = std::min_element(std::begin(vec.vector()), std::end(vec.vector()));
-//   auto m1 = std::max_element(std::begin(vec.vector()), std::end(vec.vector()));
-//   AMDIS_TEST( *m0 == T(0) );
-//   AMDIS_TEST( *m1 == T(1) );
-// #endif
-
-//   // DOFVector models the concept of a VectorBackend in Dune::Functions
-//   static_assert(Dune::models<Dune::Functions::Concept::VectorBackend<B>, decltype(vec)>(), "");
+  vec.init(false);
+  vec.insert(0, value_type(1));
+  vec.finish();
+
+  value_type min(10);
+  value_type max(-10);
+  auto lv = basis.localView();
+  auto const& gv = basis.gridView();
+  for (auto const& e : elements(gv))
+  {
+    lv.bind(e);
+    for (size_type i = 0; i < lv.size(); ++i)
+    {
+      auto value = vec.at(lv.index(i));
+      min = std::min(min, value);
+      max = std::max(max, value);
+    }
+  }
+  AMDIS_TEST( min == T(0) || vec.localSize() == 1 );
+  AMDIS_TEST( max == T(1) );
 }
 
 int main(int argc, char** argv)
@@ -41,52 +56,56 @@ int main(int argc, char** argv)
   Environment env(argc, argv);
 
   // create grid
+  using HostGrid = Dune::YaspGrid<2>;
   Dune::FieldVector<double, 2> L; L = 1.0;
   auto s = Dune::filledArray<2>(1);
-  Dune::YaspGrid<2> grid(L, s);
-  auto const& gridView = grid.leafGridView();
+  HostGrid hostGrid(L, s);
+  auto grid = AdaptiveGrid<HostGrid>::instance(hostGrid);
+  auto const& gridView = grid->leafGridView();
 
   // create basis
-  auto basis = makeBasis(gridView,
-    composite(power<2>(lagrange<2>(), flatInterleaved()), lagrange<1>(), flatLexicographic()));
-  using Basis = decltype(basis);
+  auto preBasis = composite(power<2>(lagrange<2>(), flatInterleaved()),
+                            lagrange<1>(),
+                            flatLexicographic());
+  auto basis = makeGlobalBasis(gridView, preBasis);
 
-  using Traits = BackendTraits<Basis>;
-  auto comm = CommunicationCreator<typename Traits::Comm>::create(basis);
-
-  GridTransferManager::attach(grid, *comm, [&]()
-  {
-    basis.update(gridView);
-    comm->update(basis);
-  });
+  using Basis = decltype(basis);
 
   {
-    DOFVector<Basis> vec1(basis, *comm);
-    test_dofvector(basis, vec1);
+    DOFVector<Basis> vec1(basis);
+    test_dofvector(vec1);
 
-    DOFVector<Basis, double> vec2(basis, *comm);
-    test_dofvector(basis, vec2);
+    DOFVector<Basis, double> vec2(basis);
+    test_dofvector(vec2);
 
-    auto vec3 = makeDOFVector(basis, *comm);
-    test_dofvector(basis, vec3);
+    auto vec3 = makeDOFVector(basis);
+    test_dofvector(vec3);
 
-    auto vec4 = makeDOFVector<double>(basis, *comm);
-    test_dofvector(basis, vec4);
+    auto vec4 = makeDOFVector<double>(basis);
+    test_dofvector(vec4);
 
 #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
-    DOFVector vec5(basis, *comm);
-    test_dofvector(basis, vec5);
+    DOFVector vec5(basis);
+    test_dofvector(vec5);
 #endif
   }
 
-  // test GridTransferManager registration
+  // test automatic updates
   {
-    DOFVector<Basis> vec1(basis, *comm);
-    test_dofvector(basis, vec1);
+    DOFVector<Basis> vec1(basis);
+
+    // Conversion from Dune::Functions::DefaultGlobalBasis
+    auto vec2 = makeDOFVector(makeBasis(gridView, preBasis));
+
+    test_dofvector(vec1);
     for (auto const& e : elements(gridView))
-      grid.mark(1, e);
-    GridTransferManager::adapt(grid);
-    // AMDIS_TEST_EQ(vec1.size(), basis.dimension());
+      grid->mark(1, e);
+    grid->preAdapt();
+    grid->adapt();
+    grid->postAdapt();
+    std::size_t newSize = basis.dimension();
+    AMDIS_TEST_EQ(vec1.localSize(), newSize);
+    AMDIS_TEST_EQ(vec2.localSize(), newSize);
   }
 
   report_errors();
diff --git a/test/DiscreteFunctionTest.cpp b/test/DiscreteFunctionTest.cpp
index bf164eaf..f3ad5286 100644
--- a/test/DiscreteFunctionTest.cpp
+++ b/test/DiscreteFunctionTest.cpp
@@ -14,21 +14,30 @@
 
 using namespace AMDiS;
 
-using ElliptParam   = YaspGridBasis<2, 2>;
+using ElliptParam   = YaspGridBasis<2, 2, 2>;
 using ElliptProblem = ProblemStat<ElliptParam>;
 
 template <class GB, class T>
 bool comp(DOFVector<GB,T> const& U, DOFVector<GB,T> const& V)
 {
-  // TODO:
-  // if (U.size() != V.size())
-  //   return false;
-
-  // using Int = typename DOFVector<GB,T>::size_type;
-  // for (Int i = 0; i < U.size(); ++i) {
-  //   if (U[i] != V[i])
-  //     return false;
-  // }
+  if (U.localSize() != V.localSize() || U.globalSize() != V.globalSize())
+    return false;
+  using size_type = typename DOFVector<GB,T>::GlobalBasis::LocalView::size_type;
+  auto const& basis = U.basis();
+  if (basis.get() != V.basis().get())
+    return false;
+  auto lv = basis->localView();
+  auto const& gv = basis->gridView();
+  for (auto const& e : elements(gv))
+  {
+    lv.bind(e);
+    for (size_type i = 0; i < lv.size(); ++i)
+    {
+      auto multiIndex = lv.index(i);
+      if (std::abs(U.at(multiIndex) - V.at(multiIndex)) > AMDIS_TEST_TOL)
+        return false;
+    }
+  }
   return true;
 }
 
@@ -50,15 +59,24 @@ int main(int argc, char** argv)
   auto u1 = makeDOFVectorView(U1);
   auto u2 = makeDOFVectorView(U2);
 
-  auto expr = [](auto const& x) { return 1 + x[0] + x[1]; };
-  u0.interpolate_noalias(expr);
-  u1.interpolate(expr);
-  u2 << expr;
+  using Range = typename decltype(u0)::Range;
+
+  auto expr1 = [](auto const& x) {
+    return Range{ 1 + x[0] + x[1],
+                  2 + x[0] + x[1]};
+  };
+
+  u0.interpolate_noalias(expr1);
+  u1.interpolate(expr1);
+  u2 << expr1;
 
   AMDIS_TEST( comp(U0, U1) );
   AMDIS_TEST( comp(U0, U2) );
 
-  auto expr2 = [](auto const& x) { return 1 + 2*x[0] - 3*x[1]; };
+  auto expr2 = [](auto const& x) {
+    return Range{ 1 + 2*x[0] - 3*x[1],
+                  2 + 2*x[0] - 3*x[1]};
+  };
 
   u0.interpolate_noalias(u2 + expr2);
   u1.interpolate(u1 + expr2);
@@ -67,7 +85,10 @@ int main(int argc, char** argv)
   AMDIS_TEST( comp(U0, U1) );
   AMDIS_TEST( comp(U0, U2) );
 
-  auto expr3 = [](auto const& x) { return 1 - 0.5*x[0] - 2*x[1]; };
+  auto expr3 = [](auto const& x) {
+    return Range{ 1 - 0.5*x[0] - 2*x[1],
+                  2 - 0.5*x[0] - 2*x[1]};
+  };
 
   u0.interpolate_noalias(u2 - expr3);
   u1.interpolate(u1 - expr3);
@@ -87,20 +108,23 @@ int main(int argc, char** argv)
     auto y0 = localFct(local);
     auto y1 = u0(geo.global(local));
 
-    AMDIS_TEST(std::abs(y0 - y1) < 1.e-10);
+    for (auto it1 = y0.begin(), it2 = y1.begin(); it1 != y0.end(); ++it1, ++it2)
+      AMDIS_TEST(std::abs(*it1 - *it2) < 1.e-10);
+
     localFct.unbind();
 
     dlocalFct.bind(e);
     auto g0 = dlocalFct(local);
     auto g1 = du0(geo.global(local));
 
-    AMDIS_TEST(two_norm(g0 - g1) < 1.e-10);
+    for (auto it1 = g0.begin(), it2 = g1.begin(); it1 != g0.end(); ++it1, ++it2)
+      AMDIS_TEST(two_norm(*it1 - *it2) < 1.e-10);
     dlocalFct.unbind();
   }
 
-  auto V0 = makeDOFVector<double>(*prob.globalBasis());
+  auto V0 = makeDOFVector<double>(prob.globalBasis());
   auto v0 = makeDOFVectorView(V0);
-  v0 << expr;
+  v0 << expr1;
 
   // test makeDiscreteFunction
   int preTP1 = 0;
@@ -114,9 +138,12 @@ int main(int argc, char** argv)
   auto w2 = makeDiscreteFunction(W2, tp);
 
   // test makeDOFVectorView with (pre)treepath argument
+  auto expr = [](auto const& x) { return 1 + x[0] + x[1]; };
   auto W3 = *prob.solutionVector();
   auto W4 = *prob.solutionVector();
   auto W5 = *prob.solutionVector();
+  auto W7 = *prob.solutionVector();
+  auto W8 = *prob.solutionVector();
   auto w3 = makeDOFVectorView(W3, preTP1);
   auto w4 = makeDOFVectorView(W4, preTP2);
   auto w5 = makeDOFVectorView(W5, tp);
@@ -130,5 +157,14 @@ int main(int argc, char** argv)
   AMDIS_TEST( comp(W3, W5) );
   AMDIS_TEST( comp(W3, W6) );
 
+  // test interpolation on subbasis
+  auto w7 = makeDOFVectorView(W7);
+  auto w8_0 = makeDOFVectorView(W8, 0);
+  auto w8_1 = makeDOFVectorView(W8, 1);
+  w7 << expr;
+  w8_0 << expr;
+  w8_1 << expr;
+  AMDIS_TEST( comp(W7, W8) );
+
   return 0;
 }
diff --git a/test/GlobalIdSetTest.cpp b/test/GlobalIdSetTest.cpp
index 6cd937d1..b92485e7 100644
--- a/test/GlobalIdSetTest.cpp
+++ b/test/GlobalIdSetTest.cpp
@@ -42,7 +42,7 @@ template <class Grid>
 void checkGrid(const Grid& grid)
 {
   // create basis
-  using namespace Dune::Functions::BasisBuilder;
+  using namespace Dune::Functions::BasisFactory;
   auto basis1 = makeBasis(grid.leafGridView(),
     composite(
       power<2>(lagrange<2>()),
diff --git a/test/GradientTest.cpp b/test/GradientTest.cpp
index 17b62282..7d6d1ef3 100644
--- a/test/GradientTest.cpp
+++ b/test/GradientTest.cpp
@@ -4,6 +4,8 @@
 #include <iostream>
 
 #include <amdis/AMDiS.hpp>
+
+#include <amdis/AdaptiveGrid.hpp>
 #include <amdis/LinearAlgebra.hpp>
 #include <amdis/GridFunctions.hpp>
 #include <amdis/Integrate.hpp>
@@ -15,11 +17,13 @@ using namespace AMDiS;
 template <std::size_t p>
 void test()
 {
-  using Grid = Dune::YaspGrid<2>;
-  using Basis1 = LagrangeBasis<Grid,p,p>;
+  using HostGrid = Dune::YaspGrid<2>;
+  using Basis1 = LagrangeBasis<HostGrid,p,p>;
+
+  HostGrid hostGrid({1.0, 1.0}, {16,16});
+  auto grid = AdaptiveGrid<HostGrid>::instance(hostGrid);
+  auto const& gridView = grid->leafGridView();
 
-  Grid grid({1.0, 1.0}, {16,16});
-  auto gridView = grid.leafGridView();
   auto basis = Basis1::create(gridView);
 
   auto uVector = makeDOFVector(basis);
@@ -57,7 +61,8 @@ void test()
   u_0 << evalAtQP([](auto const& x) { return std::sin(x[0]) + std::cos(x[1]); });
   u_1 << evalAtQP([](auto const& x) { return -std::sin(x[0]) * std::cos(x[1]); });
 
-  AMDIS_TEST_APPROX((integrate(divergenceAtQP(u), gridView)), (integrate(partialAtQP(u_0,0) + partialAtQP(u_1,1), gridView)));
+  AMDIS_TEST_APPROX((integrate(divergenceAtQP(u), gridView)),
+                    (integrate(partialAtQP(u_0,0) + partialAtQP(u_1,1), gridView)));
 
   auto vVector(uVector);
   auto v = makeDOFVectorView(vVector);
@@ -65,7 +70,9 @@ void test()
   auto v_1 = makeDOFVectorView(vVector, 1);
 
   // test gradient
-  v << evalAtQP([](auto const& x) { return Dune::FieldVector<double,2>{std::cos(x[0]), -std::sin(x[1])}; });
+  v << evalAtQP([](auto const& x) {
+    return Dune::FieldVector<double,2>{std::cos(x[0]), -std::sin(x[1])};
+  });
   AMDIS_TEST((std::sqrt(integrate(unary_dot(v - gradientAtQP(u_0)), gridView))) < 0.05);
 
   // test divergence
diff --git a/test/ISTLCommTest.cpp b/test/ISTLCommTest.cpp
index 60a25034..1ef3d0e1 100644
--- a/test/ISTLCommTest.cpp
+++ b/test/ISTLCommTest.cpp
@@ -13,6 +13,7 @@
 #include <dune/grid/yaspgrid.hh>
 
 #include <amdis/linearalgebra/istl/Communication.hpp>
+#include <amdis/AdaptiveGrid.hpp>
 #include <amdis/Environment.hpp>
 #include <amdis/ProblemStatTraits.hpp>
 
@@ -23,7 +24,6 @@ using namespace AMDiS;
 template <class Basis>
 bool test(Basis& basis, std::string const& prefix)
 {
-  using Comm = ISTLCommunication<Basis>;
   using GV = typename Basis::GridView;
   using Grid = typename GV::Grid;
   using Coord = typename Grid::template Codim<0>::Geometry::GlobalCoordinate;
@@ -32,17 +32,15 @@ bool test(Basis& basis, std::string const& prefix)
 
   bool passed = true;
 
+#if HAVE_MPI
   // Interpolate test function f onto dofs and reference
   auto f = [&](const Coord& x) -> T { return std::pow(x[0],3) + x[1] + (d == 3 ? x[2] : 0.0); };
   std::vector<T> ref(basis.size());
   Dune::Functions::interpolate(basis, ref, f);
   std::vector<T> dofs = ref;
 
-  // Make communicator and exchange dofs
-#if HAVE_MPI
-  using CommCreator = CommunicationCreator<Comm>;
-  auto comm = CommCreator::create(basis, prefix);
-  comm->get().copyOwnerToAll(dofs, dofs);
+  // Exchange dofs
+  basis.communicator().get().copyOwnerToAll(dofs, dofs);
 
   // Compare post-exchange data with reference
   for (std::size_t i = 0; i < dofs.size(); ++i)
@@ -77,16 +75,24 @@ int main(int argc, char** argv)
   int ovlp = 1;
 
   {
-    auto grid = std::make_unique<YaspGrid2d>(lower2d, upper2d, nElements2d, std::bitset<2>(), ovlp);
+    auto hostGrid = std::make_unique<YaspGrid2d>(lower2d, upper2d, nElements2d, std::bitset<2>(),
+                                                 ovlp);
+    auto grid = AdaptiveGrid<YaspGrid2d>::instance(hostGrid);
+
     auto l1 = LagrangeBasis<YaspGrid2d, 1>::create(grid->leafGridView());
     AMDIS_TEST(test(l1, "Yasp2d_L1_Ovlp"));
+
     auto th = TaylorHoodBasis<YaspGrid2d, 1>::create(grid->leafGridView());
     AMDIS_TEST(test(th, "Yasp2d_TH_Ovlp"));
   }
   {
-    auto grid = std::make_unique<YaspGrid3d>(lower3d, upper3d, nElements3d, std::bitset<3>(), ovlp);
+    auto hostGrid = std::make_unique<YaspGrid3d>(lower3d, upper3d, nElements3d, std::bitset<3>(),
+                                                 ovlp);
+    auto grid = AdaptiveGrid<YaspGrid3d>::instance(hostGrid);
+
     auto l1 = LagrangeBasis<YaspGrid3d, 1>::create(grid->leafGridView());
     AMDIS_TEST(test(l1, "Yasp3d_L1_Ovlp"));
+
     auto th = TaylorHoodBasis<YaspGrid3d, 1>::create(grid->leafGridView());
     AMDIS_TEST(test(th, "Yasp3d_TH_Ovlp"));
   }
diff --git a/test/MarkerTest.cpp b/test/MarkerTest.cpp
index 6ae27b0d..bc931654 100644
--- a/test/MarkerTest.cpp
+++ b/test/MarkerTest.cpp
@@ -39,9 +39,9 @@ int main(int argc, char** argv)
   };
 
 #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
-  GridFunctionMarker marker("mymarker", grid, markerFunc);
+  GridFunctionMarker marker("mymarker", prob.grid(), markerFunc);
 #else
-  auto marker = makeGridFunctionMarker("mymarker", grid, markerFunc);
+  auto marker = makeGridFunctionMarker("mymarker", prob.grid(), markerFunc);
 #endif
 
   prob.addMarker(marker);
diff --git a/test/ObserverTest.cpp b/test/ObserverTest.cpp
new file mode 100644
index 00000000..77039fee
--- /dev/null
+++ b/test/ObserverTest.cpp
@@ -0,0 +1,180 @@
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include <amdis/Observer.hpp>
+
+#include "Tests.hpp"
+
+using namespace AMDiS;
+
+namespace event {
+  struct fooEvent {};
+  struct barEvent {};
+  struct bazEvent {};
+}
+
+std::string testValue = "";
+
+bool checkAndResetTestValue(std::string testName, std::string ref, std::string refOpt = "X")
+{
+  bool result = testValue == ref || testValue == refOpt;
+  testValue.clear();
+  return result;
+}
+
+class A
+    : public Signals<event::fooEvent, event::barEvent, event::bazEvent>
+{
+public:
+  void foo()
+  {
+    std::cout << "A::foo()\n";
+    testValue += "A.foo ";
+    event::fooEvent e;
+    this->notify(e);
+  }
+
+  void bar()
+  {
+    std::cout << "A::bar()\n";
+    testValue += "A.bar ";
+    event::barEvent e;
+    this->notify(e);
+  }
+
+  void baz()
+  {
+    std::cout << "A::baz()\n";
+    testValue += "A.baz ";
+    event::bazEvent e;
+    this->notify(e);
+  }
+};
+
+class B
+    : public Observer<A, event::fooEvent, event::bazEvent>
+    , public Signals<event::bazEvent>
+{
+public:
+  B(std::shared_ptr<A> a)
+    : Observer<A, event::fooEvent, event::bazEvent>(a)
+  {}
+
+  void update(event::fooEvent const& e) override
+  {
+    std::cout << "B::update(foo)\n";
+    testValue += "B.foo ";
+  }
+
+  void update(event::bazEvent const& e) override
+  {
+    std::cout << "B::update(baz)\n";
+    testValue += "B.baz ";
+    this->notify(e);
+  }
+};
+
+class C
+    : public Observer<B, event::barEvent, event::bazEvent>
+{
+public:
+  C(std::shared_ptr<B> b)
+    : Observer<B, event::barEvent, event::bazEvent>(b)
+  {}
+
+  void update(event::barEvent const& e) override
+  {
+    std::cout << "C::update(bar)\n";
+    testValue += "C.bar ";
+  }
+
+  void update(event::bazEvent const& e) override
+  {
+    std::cout << "C::update(baz)\n";
+    testValue += "C.baz ";
+  }
+};
+
+class D
+    : public Signals<event::barEvent>
+{
+public:
+  void bar()
+  {
+    std::cout << "D::bar()\n";
+    testValue += "D.bar ";
+    event::barEvent e;
+    this->notify(e);
+  }
+};
+
+class E
+    : public Observer<A, event::fooEvent>
+    , public Observer<D, event::barEvent>
+{
+public:
+  E(std::shared_ptr<A> a, std::shared_ptr<D> d)
+      : Observer<A, event::fooEvent>(a)
+      , Observer<D, event::barEvent>(d)
+  {}
+
+  void update(event::fooEvent const& e) override
+  {
+    std::cout << "E::update(foo)\n";
+    testValue += "E.foo ";
+  }
+
+  void update(event::barEvent const& e) override
+  {
+    std::cout << "E::update(bar)\n";
+    testValue += "E.bar ";
+  }
+};
+
+/// Observing a class that inherits from Observer<T, Events...> more than once is not supported
+// class F
+//     : public Observer<E, event::fooEvent>
+// {
+// public:
+//   F(std::shared_ptr<E> e)
+//     : Observer<E, event::fooEvent>(e)  // Error
+//   {}
+// };
+
+/// Test the observer hierarchy.
+/**
+ *  There are 4 hierarchies tested.
+ *  A::foo(): A -> B, E     (multiple observers [B,E] of one event)
+ *  A::bar(): A -> (B) -> C (indirect observer [C of A])
+ *  A::baz(): A -> B -> C   (simultanious observer and signaller of an event [B])
+ *  D::bar(): D -> E        (observer of multiple classes [E])
+ */
+int main()
+{
+  auto a = std::make_shared<A>();
+  auto b = std::make_shared<B>(a);
+  auto c = std::make_shared<C>(b);
+  auto d = std::make_shared<D>();
+  auto e = std::make_shared<E>(a, d);
+  std::string ref, refOpt;
+
+  a->foo();
+  ref = "A.foo B.foo E.foo ";
+  refOpt = "A.foo E.foo B.foo ";  // Order of b->foo() and e->foo() unspecified
+  AMDIS_TEST(checkAndResetTestValue("A:foo()", ref, refOpt));
+
+  a->bar();
+  ref = "A.bar C.bar ";
+  AMDIS_TEST(checkAndResetTestValue("A:bar()", ref));
+
+  a->baz();
+  ref = "A.baz B.baz C.baz ";
+  AMDIS_TEST(checkAndResetTestValue("A:baz()", ref));
+
+  d->bar();
+  ref = "D.bar E.bar ";
+  AMDIS_TEST(checkAndResetTestValue("D:bar()", ref));
+
+  return report_errors();
+}
diff --git a/test/ProblemStatTest.cpp b/test/ProblemStatTest.cpp
index c74a9cd6..9d44993f 100644
--- a/test/ProblemStatTest.cpp
+++ b/test/ProblemStatTest.cpp
@@ -1,8 +1,10 @@
 #include <amdis/AMDiS.hpp>
+#include <amdis/AdaptiveGrid.hpp>
 #include <amdis/AdaptStationary.hpp>
 #include <amdis/LocalOperators.hpp>
 #include <amdis/ProblemStat.hpp>
 #include <amdis/common/QuadMath.hpp>
+#include <amdis/functions/ParallelGlobalBasis.hpp>
 
 #include <dune/common/version.hh>
 #include <dune/grid/yaspgrid.hh>
@@ -13,15 +15,16 @@ template <class T>
 void test()
 {
   // use T as coordinate type
-  using Grid = Dune::YaspGrid<2, Dune::EquidistantCoordinates<T,2>>;
-  Grid grid({T(1), T(1)}, {8,8});
+  using HostGrid = Dune::YaspGrid<2, Dune::EquidistantCoordinates<T,2>>;
+  HostGrid hostGrid({T(1), T(1)}, {8,8});
+  auto grid = AdaptiveGrid<HostGrid>::instance(hostGrid);
 
   // use T as range type for basis
   using namespace Dune::Functions::BasisFactory;
 #if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)
-  auto basis = makeBasis(grid.leafGridView(), power<1>(lagrange<1>(), flatLexicographic()));
+  auto basis = makeGlobalBasis(grid->leafGridView(), power<1>(lagrange<1>(), flatLexicographic()));
 #else
-  auto basis = makeBasis(grid.leafGridView(), power<1>(lagrange<1,T>(), flatLexicographic()));
+  auto basis = makeGlobalBasis(grid->leafGridView(), power<1>(lagrange<1,T>(), flatLexicographic()));
 #endif
   using Basis = decltype(basis);
 
-- 
GitLab