diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b673e1c0e796ae612baeb3832611d17fb3755f62..37a4f997b9446fc0a2f6f4263f23d429f49ef969 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -125,7 +125,6 @@ stages:
   only:
     - master
 
-
 # debian gcc
 setup:debian_gcc:
   <<: *debian_gcc
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7113ee31e3ab8dcdd05f2a839341c9c524bf033a..4ecfbae737589684010b03ae64bfa9dcd470db18 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,9 @@ Types of changes
  -->
 
 ## [Unreleased]
+### Added
+- Code documentation
+- Brief installation instructions
 
 ## [0.1.0] - 2019-10-11
 ### Added
diff --git a/README.md b/README.md
index e76e7106d744b80aeb1dc8bc14ce77180a41da62..db6258af267b33c3cf0a3c03b87f0e519cc5be1d 100644
--- a/README.md
+++ b/README.md
@@ -2,88 +2,230 @@
 [![Build Status](https://travis-ci.org/SoilRos/dune-copasi.svg?branch=master)](https://travis-ci.org/SoilRos/dune-copasi)
 [![Build status](https://ci.appveyor.com/api/projects/status/6605joy2w17qvca8/branch/master?svg=true)](https://ci.appveyor.com/project/SoilRos/dune-copasi/history)
 
-#### Dependencies
+# dune-copasi
+
+Solver for reaction-diffusion systems in multiple compartments
+
+ * Solve a reaction-diffusion system for each comartment
+ * Each compartment may have different system with different number of variables
+ * Neumann flux at the interface of compartments for variables with
+   the same name on the two compartments
+ * Easy to modify configuration file
+ * Initial conditions might be either TIFF file or a math expression.
+ * Solved using the finite element method
+ * Output in the VTK format
+ * Currently it only supports 2D simulations
+
+This project is made under the umbrella of the 
+[*Distributed and Unified Numerics Environment* `DUNE`](https://www.dune-project.org/) and the
+[*Biochemical System Simulator* `COPASI`](http://copasi.org/). 
+Altought the rationale of the design is always driven by biochemical process (e.g. cell biology), 
+this software is not limited to this scope and can be used for other processes involving reaction-diffusion systems.
+
+## Graphical User Interface for SMBL files
+
+For those working in bio-informatics there exist a grafical user interface for SMBL files!
+The GUI is able to convert non-spatial SBML models of bio-chemical reactions into 
+2d spatial models, and to simulate them with `dune-copasi`.
+
+https://github.com/lkeegan/spatial-model-editor
+
+## Installation
+
+This requires that you have installed the following packages before the actual installation of `dune-copasi`.
 
 | Software | Version/Branch | Comments |
 | ---------| -------------- | -------- |
-| muParser | - |
-| CMake | 3.10.2 |
+| [CMake](https://cmake.org/) | 3.1 |
 | C++ compiler | [C++17](https://en.wikipedia.org/wiki/List_of_compilers#C++_compilers) | 
-| [dune-common](https://gitlab.dune-project.org/santiago.ospina/dune-common) | support/dune-copasi
-| [dune-logging](https://gitlab.dune-project.org/staging/dune-logging) | master
-| [dune-geometry](https://gitlab.dune-project.org/core/dune-geometry) | master
-| [dune-grid](https://gitlab.dune-project.org/core/dune-grid) | master
-| [dune-uggrid](https://gitlab.dune-project.org/staging/dune-uggrid) | master
-| [dune-istl](https://gitlab.dune-project.org/core/dune-istl) | master
-| [dune-localfunctions](https://gitlab.dune-project.org/core/dune-localfunctions) | master
-| [dune-functions](https://gitlab.dune-project.org/staging/dune-functions) | master
-| [dune-typetree](https://gitlab.dune-project.org/santiago.ospina/dune-typetree) | support/dune-copasi
-| [dune-pdelab](https://gitlab.dune-project.org/santiago.ospina/dune-pdelab) | support/dune-copasi
-| [dune-multidomaingrid](https://gitlab.dune-project.org/santiago.ospina/dune-multidomaingrid) | support/dune-copasi
-
-<!-- 
-Preparing the Sources
-=========================
-
-Additional to the software mentioned in README you'll need the
-following programs installed on your system:
+| [libTIFF](http://www.libtiff.org/) | 3.6.1 |
+| [muParser](https://beltoforion.de/article.php?a=muparser) | 2.2.5 |
+| [dune-common](https://gitlab.dune-project.org/santiago.ospina/dune-common) | support/dune-copasi | https://gitlab.dune-project.org/santiago.ospina/dune-common
+| [dune-logging](https://gitlab.dune-project.org/staging/dune-logging) | master (recursive) | https://gitlab.dune-project.org/staging/dune-logging
+| [dune-geometry](https://gitlab.dune-project.org/core/dune-geometry) | master | https://gitlab.dune-project.org/core/dune-geometry
+| [dune-grid](https://gitlab.dune-project.org/core/dune-grid) | master | https://gitlab.dune-project.org/core/dune-grid
+| [dune-uggrid](https://gitlab.dune-project.org/staging/dune-uggrid) | master | https://gitlab.dune-project.org/staging/dune-uggrid
+| [dune-istl](https://gitlab.dune-project.org/core/dune-istl) | master | https://gitlab.dune-project.org/core/dune-istl
+| [dune-localfunctions](https://gitlab.dune-project.org/core/dune-localfunctions) | master | https://gitlab.dune-project.org/core/dune-localfunctions
+| [dune-functions](https://gitlab.dune-project.org/staging/dune-functions) | master | https://gitlab.dune-project.org/staging/dune-functions
+| [dune-typetree](https://gitlab.dune-project.org/santiago.ospina/dune-typetree) | support/dune-copasi | https://gitlab.dune-project.org/santiago.ospina/dune-typetree
+| [dune-pdelab](https://gitlab.dune-project.org/santiago.ospina/dune-pdelab) | support/dune-copasi | https://gitlab.dune-project.org/santiago.ospina/dune-pdelab
+| [dune-multidomaingrid](https://gitlab.dune-project.org/santiago.ospina/dune-multidomaingrid) | support/dune-copasi | https://gitlab.dune-project.org/santiago.ospina/dune-multidomaingrid
+
+The first four can be obtained by your prefered package manager in unix-like operating systems. e.g.
 
-```
-  cmake >= 2.8.12
+```bash
+# if you are in a debian/ubuntu OS
+apt update
+apt install cmake gcc g++ libtiff-dev libmuparser-dev git
+
+# if you are in a macOS
+xcode-select --install # Apple Command Line Tools
+brew update
+brew install cmake gcc libtiff muparser git
 ```
 
-Getting started
----------------
+Now, the dune modules (including `dune-copasi`) can be all checkout in a same folder and be installed in one go. 
 
-If these preliminaries are met, you should run
-
-```
-  dunecontrol all
+```bash
+# prepare a folder to download and build dune modules
+mkdir ~/dune-modules && cd ~/dune-modules
+
+# fetch dependencies & dune-copasi in ~/dune-modules folder
+git clone -b support/dune-copasi https://gitlab.dune-project.org/santiago.ospina/dune-common
+git clone -b master --recursive https://gitlab.dune-project.org/staging/dune-logging
+git clone -b master https://gitlab.dune-project.org/core/dune-geometry
+git clone -b master https://gitlab.dune-project.org/core/dune-grid
+git clone -b master https://gitlab.dune-project.org/staging/dune-uggrid
+git clone -b master https://gitlab.dune-project.org/core/dune-istl
+git clone -b master https://gitlab.dune-project.org/core/dune-localfunctions
+git clone -b master https://gitlab.dune-project.org/staging/dune-functions
+git clone -b support/dune-copasi https://gitlab.dune-project.org/santiago.ospina/dune-typetree
+git clone -b support/dune-copasi https://gitlab.dune-project.org/santiago.ospina/dune-pdelab
+git clone -b support/dune-copasi https://gitlab.dune-project.org/santiago.ospina/dune-multidomaingrid
+git clone -b master https://gitlab.dune-project.org/copasi/dune-copasi
+
+# configure and build dune modules
+./dune-common/bin/dunecontrol make all
+
+# install dune-copasi (this operation may requiere sudo)
+./dune-common/bin/dunecontrol --only=dune-copasi bexec make install
+
+# if you do not want to install dune-copasi system-wide, you can set
+# the CMAKE_INSTALL_PREFIX to a non restricted folder
+# see https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html
+
+# remove source and build files
+cd .. && rm -r ~/dune-modules
 ```
 
-which will find all installed dune modules as well as all dune modules
-(not installed) which sources reside in a subdirectory of the current
-directory. Note that if dune is not installed properly you will either
-have to add the directory where the `dunecontrol` script resides (probably
-`./dune-common/bin`) to your path or specify the relative path of the script.
+For further info on dune module installation process, please check out 
+the [dune-project web page](https://www.dune-project.org/doc/installation/)
 
-Most probably you'll have to provide additional information to `dunecontrol`
-(e. g. compilers, configure options) and/or make options.
+## Usage 
 
-The most convenient way is to use options files in this case. The files
-define four variables:
+If you installed `dune-copasi` system-wide, you should be able to call the program
+`dune_copasi` from your command line accompained with a configuration file.
 
-```
-CMAKE_FLAGS      flags passed to cmake (during configure)
+```bash
+dune_copasi config.ini
 ```
 
-An example options file might look like this:
+### Configuration File
 
-```bash
-#use this options to configure and make if no other options are given
-CMAKE_FLAGS=" \
--DCMAKE_CXX_COMPILER=g++-5 \
--DCMAKE_CXX_FLAGS='-Wall -pedantic' \
--DCMAKE_INSTALL_PREFIX=/install/path" #Force g++-5 and set compiler flags
-```
+The configuration file follows [INI file format](https://en.wikipedia.org/wiki/INI_file).
+It should contain at least two sections: `grid`, and `model`, whereas a third section 
+`logging` is optional.
 
-If you save this information into example.opts you can pass the opts file to
-dunecontrol via the `--opts option`, e. g.
+#### Grid
 
-```bash
-  dunecontrol --opts=example.opts all
+The grid section is fairly simple as it only contains the path to a [gmsh file](http://gmsh.info/)
+and its initial refinement level:
+
+```ini
+[grid]
+file = my_gmsh_file.msh
+initial_level = 1
 ```
 
-More info
----------
+#### Model
 
-See
+The model section starts with the definitions of the simulation time interval 
+and the polynomal order of the finite element method (currently only supports `1` and `2`).
 
-```bash
-     dunecontrol --help
+```ini
+[model]
+begin_time = 0.
+end_time = 10
+time_step = 0.1
+order = 1
+```
+
+The following is the definition of the compartments of the model. 
+Each compartment corresponds to a *physical group* in the gmsh jargon.
+Although the gmsh format allows you to name such physical groups, 
+we still need to assign them to a `dune-copasi` compartmet and for that
+we use the *physical group* index. Notice that uses 0-based indices while 
+`gmsh` uses 1-based indices. In other words, 
+`<gmsh_physical_group> = <dune_copasi_compartment> - 1`. 
+Let's say for example that there is two *physical groups* in our gmsh file
+and we are going to use them as `nucleous` and `cytoplasm` compartments:
+
+```ini
+[model.compartments]
+ # nucleous corresponds to the physical group 1 in the gmsh file
+nucleous  = 0
+ # cytoplasm corresponds to the physical group 2 in the gmsh file
+cytoplasm = 0
 ```
 
-for further options.
+Now, each of these compartments will define its own initial conditions,
+its diffusion-reaction system, and its vtk writter. For that, you have to expand
+the `model` section with the defined compartments, e.g. `model.nucleous` or `model.cytoplasm`.
+The subsection `initial`, `reaction`, `diffusion` and `operator` define the system variables 
+and its properties. You can put as many variables as desired as long as they are the same 
+in this three subsections. Notice that each variable defines a new diffusion-reaction partial 
+differential equation associated with it. 
+
+  * The `initial` subsection allow the initialization of each of the variables. 
+  * The `diffusion` subsection defines the diffusion coefficient math 
+  expression associated with each variable. It may only depend on the grid coordinates `x` and `y`.
+  * The `reaction` subsection defines the reaction part of each equation in the PDE. 
+  Since this is the souce of non-linearities, it allows to be dependent on other defined variables
+  within the compartment. This section has to include yet another subsection called `jacobian`.
+  * The `reaction.jacobian` subsection must describe the 
+  [jacobian matrix](https://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant)
+  of the `reaction` part. It must follow the syntax of `d<var_i>_d<var_j>`, which 
+  reads as the *partial derivate of `<var_i>` with respect to `<var_j>`*. 
+  * The `operator` subsection is an experimental feature and we recommend to set all variables to the 
+  same index, e.g. 0. 
+  * Finally, the subsection `writer` will define the file name for the vtk output. 
+  
+For example, the following `mode.nucleous` section defines a [Gray-Scott
+model with `F=0.0420` and `k=0.0610`](http://mrob.com/pub/comp/xmorphia/F420/F420-k610.html):
+
+```ini
+[model.nucleous.initial]
+u = 0.5
+v = (x>0) && (x<0.5) && (y>0.) && (y<0.5) ? 1 : 0
+
+[model.nucleous.diffusion]
+u = 2e-5
+v = 2e-5/2
+
+[model.nucleous.reaction]
+u = -u*v^2+0.0420*(1-u)
+v = u*v^2-(0.0420+0.0610)*v
+
+[model.nucleous.reaction.jacobian]
+du_du = -v^2-0.0420
+du_dv = -2*u*v
+dv_du = v^2
+dv_dv = 2*u*v-(0.0420+0.0610)
+
+[model.nucleous.operator]
+u = 0
+v = 0
+
+[model.nucleous.writer]
+file_name = nucleous_output
+```
+The `model.cytoplasm` would have to be defined in similar way. An important aspect when working 
+with different compartments is the interface fluxes. In `dune-copasi` thex fluxes are set 
+automatically to [dirichlet-dirichlet](https://en.wikipedia.org/wiki/Dirichlet_boundary_condition)
+boundary conditions iff the variable is shared between the two intersecting domains. Further 
+improvements will come for interface treatment.
+
+#### Logging
+
+The logging settings are directly forwarded to the `dune-logging` module. Please check 
+its doxygen documentation for detailed information. A simple configuration is the following:
 
+```ini
+[logging]
+# possible levels: off, critical, error, waring, notice, info, debug, trace, all
+default.level = trace
 
-The full build system is described in the `dune-common/doc/buildsystem` (Git version) or under `share/doc/dune-common/buildsystem` if you installed DUNE! -->
\ No newline at end of file
+[logging.sinks.stdout]
+pattern = [{reldays:0>2}-{reltime:8%T}] [{backend}] {msg}
+```
\ No newline at end of file
diff --git a/dune/copasi/CMakeLists.txt b/dune/copasi/CMakeLists.txt
index 37f27f3e2103ab36e8b3c7856f637fb82e6728b2..3dbb4df0941a249320ed12876df55db539ac4611 100644
--- a/dune/copasi/CMakeLists.txt
+++ b/dune/copasi/CMakeLists.txt
@@ -1,25 +1,5 @@
+add_subdirectory(common)
 add_subdirectory(concepts)
-
-install(FILES   coefficient_mapper.hh
-                dynamic_local_basis.hh
-                dynamic_local_coefficients.hh
-                dynamic_local_finite_element.hh
-                dynamic_local_interpolation.hh
-                enum.hh
-                gmsh_reader.hh
-                grid_function_writer.hh
-                local_operator_multidomain.hh
-                local_operator.hh
-                model_base.hh
-                model_diffusion_reaction.cc
-                model_diffusion_reaction.hh
-                model_multidomain_diffusion_reaction.cc
-                model_multidomain_diffusion_reaction.hh
-                model_state.hh
-                multidomain_entity_transformation.hh
-                multidomain_local_finite_element_map.hh
-                muparser_data_handler.hh
-                pdelab_callable_adapter.hh
-                pdelab_expression_adapter.hh
-                tiff_grayscale.hh
-        DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dune/copasi")
+add_subdirectory(finite_element)
+add_subdirectory(grid)
+add_subdirectory(model)
diff --git a/dune/copasi/common/CMakeLists.txt b/dune/copasi/common/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0f8d8e5f28ada1bfa23fea434caa7f46eb9b26ef
--- /dev/null
+++ b/dune/copasi/common/CMakeLists.txt
@@ -0,0 +1,6 @@
+install(FILES   coefficient_mapper.hh
+                enum.hh
+                muparser_data_handler.hh
+                pdelab_expression_adapter.hh
+                tiff_grayscale.hh
+        DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dune/copasi/common")
\ No newline at end of file
diff --git a/dune/copasi/coefficient_mapper.hh b/dune/copasi/common/coefficient_mapper.hh
similarity index 52%
rename from dune/copasi/coefficient_mapper.hh
rename to dune/copasi/common/coefficient_mapper.hh
index 260dd832d3156b03c9eca33cc5f8d85f98cfffa6..4f95bddf78080a33f8773b4e6a298e03d0997c75 100644
--- a/dune/copasi/coefficient_mapper.hh
+++ b/dune/copasi/common/coefficient_mapper.hh
@@ -14,12 +14,38 @@
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      Default coefficinet mapper
+ * @details    Does nothing but evaluate the second an the third arguments of
+ *             the parenthesis call into the first one. Useful to keep code
+ *             compatible with other coefficient mappers
+ */
 struct DefaultCoefficientMapper
 {
+  /**
+   * @brief      Constructor. Arguments in this class do nothimg.
+   *
+   * @param[in]  operator_config  The operator configuration file
+   * @param[in]  this_op          The operator for local coefficients
+   */
   DefaultCoefficientMapper(const ParameterTree& operator_config,
                            std::size_t this_op)
   {}
 
+  /**
+   * @brief      Evaluates the coefficents for a give component and a degree of
+   *             freedom. Either from a local vector x_view_local, or by other
+   *             stored coefficients vector.
+   *
+   * @param[in]  x_view_local  The view on the local coefficients vector
+   * @param[in]  comp          The component
+   * @param[in]  dof           The degree of freedom
+   *
+   * @tparam     XViewLocal    The type fo the local coefficient view
+   *
+   * @return     The coefficient value for the requested component and the
+   *             degree of freedom
+   */
   template<class XViewLocal>
   auto operator()(const XViewLocal& x_view_local,
                   const std::size_t& comp,
@@ -28,17 +54,41 @@ struct DefaultCoefficientMapper
     return x_view_local(comp, dof);
   }
 
+  /**
+   * @brief      Bind internal coefficients to an entity
+   *
+   * @param[in]  <unnamed>  The entity
+   *
+   * @tparam     E          The entity
+   */
   template<class E>
   void bind(const E&)
   {}
 
+  /**
+   * @brief      Unbind this coefficients to an entity
+   */
   void unbind() {}
 
+  /**
+   * @brief      Updates the internal coefficients with a exteral source.
+   *
+   * @param[in]  <unnamed>  Map to the model states
+   *
+   * @tparam     T          Map to the model states
+   */
   template<class T>
   void update(const T&)
   {}
 };
 
+/**
+ * @brief      Model coefficinet mapper base
+ * @details    Keeps a reference to external coefficients so that they are
+ *             accessible within other local operators.
+ *
+ * @tparam     ModelState  The model state type
+ */
 template<class ModelState>
 struct ModelCoefficientMapperBase
 {
@@ -58,13 +108,27 @@ struct ModelCoefficientMapperBase
   std::map<std::size_t, std::shared_ptr<XView>> _x_view;
   std::map<std::size_t, std::shared_ptr<SolutionVector>> _x;
 
+  /**
+   * @brief      Constructs the model coefficient mapper base
+   * @details    The operator in the argument refers to the index to which the
+   *             coefficient mapper has to use local coefficients (passed as
+   *             argument during evaluation) instead of the external
+   *             coefficients. The index refers to the index to which the model
+   *             states are mapped from.
+   *
+   * @param[in]  this_op  The operator for local coefficients
+   */
   ModelCoefficientMapperBase(std::size_t this_op)
     : _this_op(this_op)
   {}
 
+  /**
+   * @brief      Updates the given model states.
+   *
+   * @param[in]  states  The model states
+   */
   void update(const std::map<std::size_t, ModelState>& states)
   {
-
     _x.clear();
     _x_view.clear();
     _lfs_cache.clear();
@@ -81,6 +145,15 @@ struct ModelCoefficientMapperBase
     }
   }
 
+  /**
+   * @brief      Bind internal coefficients to an entity
+   * @details    This binds the entity to a internal local function space and
+   *             local coefficients to the internal coefficients
+   *
+   * @param[in]  entity  The entity
+   *
+   * @tparam     E       The entity
+   */
   template<class E>
   void bind(const E& entity)
   {
@@ -95,6 +168,9 @@ struct ModelCoefficientMapperBase
     }
   }
 
+  /**
+   * @brief      Unbind this coefficients to an entity
+   */
   void unbind()
   {
     for (auto& [op, x_view] : _x_view)
@@ -102,6 +178,14 @@ struct ModelCoefficientMapperBase
   }
 };
 
+/**
+ * @brief      Constructs the model coefficient mapper
+ * @details    This coefficient mapper is designed to one domain local
+ *             operators. That is, when the PDELab local function tree only
+ *             has depth equal to 1
+ *
+ * @tparam     ModelState  The model state type
+ */
 template<class ModelState>
 struct ModelCoefficientMapper : public ModelCoefficientMapperBase<ModelState>
 {
@@ -113,10 +197,21 @@ struct ModelCoefficientMapper : public ModelCoefficientMapperBase<ModelState>
   // component -> (operator,child)
   std::unordered_map<std::size_t, std::array<std::size_t, 2>> _comp_mapper;
 
+  /**
+   * @brief      Constructor of the coefficient mapper
+   *
+   * @param[in]  this_op  The operator for local coefficients
+   */
   ModelCoefficientMapper(std::size_t this_op = 0)
     : Base(this_op)
   {}
 
+  /**
+   * @brief      Constructor of the coefficient mapper
+   *
+   * @param[in]  map_operator  A vector mapping components to operators
+   * @param[in]  this_op       The operator for local coefficients
+   */
   ModelCoefficientMapper(const std::vector<std::size_t>& map_operator,
                          std::size_t this_op)
     : Base(this_op)
@@ -124,6 +219,12 @@ struct ModelCoefficientMapper : public ModelCoefficientMapperBase<ModelState>
     set_mapper(map_operator);
   }
 
+  /**
+   * @brief      Constructor of the coefficient mapper
+   *
+   * @param[in]  operator_config  The operator configuration
+   * @param[in]  this_op          The operator for local coefficients
+   */
   ModelCoefficientMapper(const ParameterTree& operator_config,
                          std::size_t this_op)
     : Base(this_op)
@@ -141,6 +242,12 @@ struct ModelCoefficientMapper : public ModelCoefficientMapperBase<ModelState>
     set_mapper(map_op);
   }
 
+  /**
+   * @brief      Sets a map from component to operator and child in the PDELab
+   *             tree
+   *
+   * @param[in]  map_op  A vector mapping components to operators
+   */
   void set_mapper(const std::vector<std::size_t>& map_op)
   {
     std::size_t max_op = *std::max_element(map_op.begin(), map_op.end());
@@ -151,6 +258,20 @@ struct ModelCoefficientMapper : public ModelCoefficientMapperBase<ModelState>
         std::array<std::size_t, 2>{ map_op[i], comp_child[map_op[i]]++ };
   }
 
+  /**
+   * @brief      Evaluates the coefficents for a give component and a degree of
+   *             freedom. Either from a local vector x_view_local, or by other
+   *             stored coefficients vector.
+   *
+   * @param[in]  x_view_local  The view on the local coefficients vector
+   * @param[in]  comp          The component
+   * @param[in]  dof           The degree of freedom
+   *
+   * @tparam     XViewLocal    The type fo the local coefficient view
+   *
+   * @return     The coefficient value for the requested component and the
+   *             degree of freedom
+   */
   template<class XViewLocal>
   auto operator()(const XViewLocal& x_view_local,
                   const std::size_t& comp,
@@ -167,6 +288,14 @@ struct ModelCoefficientMapper : public ModelCoefficientMapperBase<ModelState>
   }
 };
 
+/**
+ * @brief      Constructs the coefficient mapper for multidomain models
+ * @details    This coefficient mapper is designed to multidomain domain local
+ *             operators. That is, when the PDELab local function tree has
+ *             depth equal to 2
+ *
+ * @tparam     ModelState  The model state type
+ */
 template<class ModelState>
 struct MultiDomainModelCoefficientMapper
   : public ModelCoefficientMapper<ModelState>
@@ -179,6 +308,20 @@ struct MultiDomainModelCoefficientMapper
   using Base::Base;
   std::size_t _domain;
 
+  /**
+   * @brief      Evaluates the coefficents for a give component and a degree of
+   *             freedom. Either from a local vector x_view_local, or by other
+   *             stored coefficients vector.
+   *
+   * @param[in]  x_view_local  The view on the local coefficients vector
+   * @param[in]  comp          The component
+   * @param[in]  dof           The degree of freedom
+   *
+   * @tparam     XViewLocal    The type fo the local coefficient view
+   *
+   * @return     The coefficient value for the requested component and the
+   *             degree of freedom
+   */
   template<class XViewLocal>
   auto operator()(const XViewLocal& x_view_local,
                   const std::size_t& comp,
@@ -195,6 +338,16 @@ struct MultiDomainModelCoefficientMapper
     }
   }
 
+  /**
+   * @brief      Bind internal coefficients to an entity
+   * @details    This procedure sets the first child in the PDELab tree by
+   *             finding the domain the entity belongs to, plus further bindings
+   *             for the other coefficients
+   *
+   * @param[in]  entity  The entity
+   *
+   * @tparam     E       The entity
+   */
   template<class E>
   void bind(const E& entity)
   {
diff --git a/dune/copasi/enum.hh b/dune/copasi/common/enum.hh
similarity index 67%
rename from dune/copasi/enum.hh
rename to dune/copasi/common/enum.hh
index a3035334865d0acf78507875c9cbc9b95ca99fe0..c0e90b30ec8fa8e920ebe62f05e0bef68b85b6f8 100644
--- a/dune/copasi/enum.hh
+++ b/dune/copasi/common/enum.hh
@@ -3,6 +3,9 @@
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      This class describes a model setup policy.
+ */
 enum class ModelSetupPolicy
 {
   None,
@@ -16,11 +19,17 @@ enum class ModelSetupPolicy
   All
 };
 
+/**
+ * @brief      This class describes an adaptivity policy.
+ */
 enum class AdaptivityPolicy
 {
   None
 };
 
+/**
+ * @brief      This class describes a jacobian method.
+ */
 enum class JacobianMethod
 {
   Analytical,
diff --git a/dune/copasi/common/muparser_data_handler.hh b/dune/copasi/common/muparser_data_handler.hh
new file mode 100644
index 0000000000000000000000000000000000000000..48955f7f31a324bd13b20f5d3f64c45c6200f895
--- /dev/null
+++ b/dune/copasi/common/muparser_data_handler.hh
@@ -0,0 +1,111 @@
+#ifndef DUNE_MUPARSER_DATA_HANDLER_HH
+#define DUNE_MUPARSER_DATA_HANDLER_HH
+
+#include <dune/common/hybridutilities.hh>
+#include <dune/common/parametertree.hh>
+
+#include <muParser.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace Dune::Copasi {
+
+/**
+ * @brief      MuParser data handler.
+ * @details    MuParser only allows to define functions if they are defined
+ *             statically. Hence, this is a trick to make happy muparser about
+ *             them. We basically store all possible functions in a static
+ *             vector, allow mu parser to call them in a static function. The
+ *             trick is that we assig the content of each function at run time.
+ *             This is mainly for tiff files, but it can be extended for other
+ *             cases.
+ * @todo       Add static check to check that T is a callable of two arguments
+ *
+ * @tparam     T     The type to manage statically. It has to have the
+ *                   parenthesis operator for two arguments.
+ */
+template<class T>
+struct MuParserDataHandler
+{
+
+  /**
+   * @brief      Destroys the object.
+   */
+  ~MuParserDataHandler()
+  {
+    MuParserDataHandler<T>::_names.clear();
+    MuParserDataHandler<T>::_functions.clear();
+  }
+
+  /**
+   * @brief      The static functions for MuParser
+   *
+   * @param[in]  x     The x position in global coordinates
+   * @param[in]  y     The x position in global coordinates
+   *
+   * @tparam     i     Index to make each function to be unique
+   *
+   * @return     The return value of the wrapped function
+   */
+  template<int i>
+  static double function_wrapper(double x, double y)
+  {
+    assert(MuParserDataHandler<T>::_functions[i]);
+    return (*MuParserDataHandler<T>::_functions[i])(x, y);
+  }
+
+  /**
+   * @brief      Adds tiff functions.
+   * @todo       Disable this function if T is not a tiff grayscale
+   *
+   * @param[in]  data_config  The data configuration
+   */
+  void add_tiff_functions(const ParameterTree& data_config)
+  {
+    const auto& keys = data_config.getValueKeys();
+    for (std::size_t i = 0; i < keys.size(); i++) {
+      _names.push_back(keys[i]);
+      std::string filename = data_config[keys[i]];
+      _functions.push_back(std::make_shared<T>(filename));
+    }
+  }
+
+  /**
+   * @brief      Sets the functions to muParser.
+   *
+   * @param      parser         The muParser parser
+   *
+   * @tparam     max_functions  Maximum set of static functions to set to
+   *                            muParser
+   */
+  template<std::size_t max_functions = 20>
+  void set_functions(mu::Parser& parser)
+  {
+    auto indices =
+      Dune::range(std::integral_constant<std::size_t, max_functions>{});
+    Dune::Hybrid::forEach(indices, [&](auto i) {
+      if (i < _functions.size())
+        parser.DefineFun(_names[i], function_wrapper<i>);
+    });
+  }
+
+  /// vector of strigs descriving the name for each function
+  static std::vector<std::string> _names;
+
+  /// vector of callables to be used for each static function
+  static std::vector<std::shared_ptr<T>> _functions;
+};
+
+/// initialization fo the static vectore of names
+template<class T>
+std::vector<std::string> MuParserDataHandler<T>::_names = {};
+
+/// initialization of vector of callables
+template<class T>
+std::vector<std::shared_ptr<T>> MuParserDataHandler<T>::_functions = {};
+
+} // namespace Dune::Copasi
+
+#endif // DUNE_MUPARSER_DATA_HANDLER_HH
\ No newline at end of file
diff --git a/dune/copasi/common/parameter_tree_check.hh b/dune/copasi/common/parameter_tree_check.hh
new file mode 100644
index 0000000000000000000000000000000000000000..600023e72d71501d9462e6349ce0e94adaba2f4f
--- /dev/null
+++ b/dune/copasi/common/parameter_tree_check.hh
@@ -0,0 +1,282 @@
+#ifndef DUNE_COPASI_PARAMETER_PARSER_HH
+#define DUNE_COPASI_PARAMETER_PARSER_HH
+
+#include <functional>
+
+#include <dune/common/parametertree.hh>
+
+namespace Dune::Copasi {
+
+bool
+eq(const ParameterTree& config_l, const ParameterTree& config_r)
+{
+  // absolutely not obtimal for big trees!
+  for (auto&& key : config_r.getValueKeys())
+    if (not config_l.hasKey(key))
+      return false;
+
+  for (auto&& key : config_l.getValueKeys())
+    if (not config_r.hasKey(key))
+      return false;
+
+  for (auto&& section : config_r.getSubKeys())
+    if (not eq(config_l.sub(section), config_r.sub(section)))
+      return false;
+
+  for (auto&& section : config_l.getSubKeys())
+    if (not eq(config_l.sub(section), config_r.sub(section)))
+      return false;
+
+  return true;
+}
+
+// merge parameter trees
+// config_l += config_r
+void
+add(ParameterTree& config_l,
+    const ParameterTree& config_r,
+    bool trow_on_override = true)
+{
+  for (auto&& key : config_r.getValueKeys()) {
+    if (config_l.hasKey(key))
+      DUNE_THROW(RangeError,
+                 "config file addition failed due to duplucated key: " << key);
+    config_l[key] = config_r[key];
+  }
+  for (auto&& section : config_r.getSubKeys())
+    add(config_l.sub(section), config_r.sub(section));
+}
+
+// diff parameter trees
+// config_l -= config_r
+void
+diff(ParameterTree& config_l, const ParameterTree& config_r)
+{
+  ParameterTree config_l_copy(config_l);
+  config_l = {};
+
+  for (auto&& key : config_l_copy.getValueKeys())
+    if (not config_r.hasKey(key))
+      config_l[key] = config_l_copy[key];
+
+  for (auto&& section : config_l_copy.getSubKeys()) {
+    diff(config_l_copy.sub(section), config_r.sub(section));
+    if (config_l_copy.sub(section).getValueKeys().size() > 0 or
+        config_l_copy.sub(section).getSubKeys().size() >
+          0) // remove empty sections
+      config_l.sub(section) = config_l_copy.sub(section);
+  }
+}
+
+// get keys in vector
+ParameterTree
+get_keys(const ParameterTree& config, const std::vector<std::string>& keys)
+{
+  ParameterTree new_config;
+  for (auto&& key : keys)
+    new_config[key] = config[key];
+  return new_config;
+}
+
+// get all keys (no section)
+ParameterTree
+get_keys(const ParameterTree& config)
+{
+  return get_keys(config, config.getValueKeys());
+}
+
+// get sections in vector
+ParameterTree
+get_sections(
+  const ParameterTree& config,
+  const std::vector<std::function<ParameterTree(const ParameterTree&)>>&
+    sections)
+{
+  ParameterTree new_config;
+  for (auto&& section : sections)
+    add(new_config, section(config));
+  return new_config;
+}
+
+ParameterTree
+get_grid(const ParameterTree& config)
+{
+  std::vector<std::string> grid_keys{ "file", "initial_level" };
+  auto grid_config = get_keys(config.sub("grid"), grid_keys);
+  // todo : check file is valid
+  // todo : check initial_level is > 0
+
+  ParameterTree new_config;
+  new_config.sub("grid") = grid_config;
+  return new_config;
+}
+
+ParameterTree
+get_initial(const ParameterTree& config)
+{
+  auto initial_config = get_keys(config.sub("initial"));
+  // todo : check that they are math expressions
+  // todo : keys are ordered
+
+  ParameterTree new_config;
+  new_config.sub("initial") = initial_config;
+  return new_config;
+}
+
+// check_var_consistency with respect to initial sections
+ParameterTree
+get_diffusion(const ParameterTree& config, bool check_var_consistency = true)
+{
+  ParameterTree diffusion_config;
+  if (check_var_consistency) {
+    auto initial_config = get_keys(config.sub("initial"));
+    diffusion_config =
+      get_keys(config.sub("diffusion"), initial_config.getValueKeys());
+  } else {
+    diffusion_config = get_keys(config.sub("diffusion"));
+  }
+  // todo : check that they are math expressions
+  // todo : keys are ordered
+
+  ParameterTree new_config;
+  new_config.sub("diffusion") = diffusion_config;
+  return new_config;
+}
+
+// check_var_consistency with respect to initial sections
+ParameterTree
+get_operator(const ParameterTree& config, bool check_var_consistency = true)
+{
+  ParameterTree operator_config;
+  if (check_var_consistency) {
+    auto initial_config = get_keys(config.sub("initial"));
+    operator_config =
+      get_keys(config.sub("operator"), initial_config.getValueKeys());
+  } else {
+    operator_config = get_keys(config.sub("operator"));
+  }
+  // todo : check that they are signed integers
+  // todo : keys are ordered
+
+  ParameterTree new_config;
+  new_config.sub("operator") = operator_config;
+  return new_config;
+}
+
+ParameterTree
+get_jacobian(const ParameterTree& config,
+             std::vector<std::string> base_variables)
+{
+  auto jacobian_config = get_keys(config.sub("jacobian"));
+  std::size_t jac_size = jacobian_config.getValueKeys().size();
+  std::size_t base_size = base_variables.size();
+
+  // it's important that jacobian has the right size and is ordered
+  if (jac_size != base_size * base_size)
+    DUNE_THROW(RangeError, "jacobian section has wrong size");
+
+  std::size_t count(0);
+  for (auto&& var_i : base_variables) {
+    for (auto&& var_j : base_variables) {
+      std::string jac_key = jacobian_config.getValueKeys()[count];
+      auto found_i = jac_key.find(var_i);
+      if (found_i == std::string::npos)
+        DUNE_THROW(RangeError,
+                   "Jacobian key '" << jac_key
+                                    << "' does not contain its base key i '"
+                                    << var_i << "'");
+      auto found_j = jac_key.find(var_j);
+      if (found_j == std::string::npos)
+        DUNE_THROW(RangeError,
+                   "Jacobian key '" << jac_key
+                                    << "' does not contain its base key j '"
+                                    << var_j << "'");
+      count++;
+    }
+  }
+
+  // todo : check that they are math expressions
+  // todo : keys are ordered
+
+  ParameterTree new_config;
+  new_config.sub("jacobian") = jacobian_config;
+  return new_config;
+}
+
+ParameterTree
+get_reaction(const ParameterTree& config, bool check_var_consistency = true)
+{
+  ParameterTree reaction_config;
+  if (check_var_consistency) {
+    auto initial_config = get_keys(config.sub("initial"));
+    reaction_config =
+      get_keys(config.sub("reaction"), initial_config.getValueKeys());
+  } else {
+    reaction_config = get_keys(config.sub("reaction"));
+  }
+
+  auto jacobian_config =
+    get_jacobian(config.sub("reaction"), reaction_config.getValueKeys());
+  add(reaction_config, jacobian_config);
+  // todo : check that they are math expressions
+  // todo : keys are ordered
+
+  ParameterTree new_config;
+  new_config.sub("reaction") = reaction_config;
+  return new_config;
+}
+
+ParameterTree
+get_compartment_i(const ParameterTree& config, const std::string& name)
+{
+  std::vector<std::function<ParameterTree(const ParameterTree&)>> sections;
+  sections.push_back(get_initial);
+  sections.push_back([](auto i) { return get_diffusion(i); });
+  sections.push_back([](auto i) { return get_reaction(i); });
+  sections.push_back([](auto i) { return get_operator(i); });
+  auto compart_config = get_sections(config.sub(name), sections);
+
+  ParameterTree new_config;
+  new_config.sub(name) = compart_config;
+  return new_config;
+}
+
+ParameterTree
+get_compartments(const ParameterTree& config)
+{
+  auto compart_config = get_keys(config.sub("compartments"));
+  // todo : check that they are valid keys
+
+  ParameterTree new_config;
+  new_config.sub("compartments") = compart_config;
+  return new_config;
+}
+
+ParameterTree
+get_model(const ParameterTree& config)
+{
+  auto compartments = get_compartments(config.sub("model"));
+
+  std::vector<std::function<ParameterTree(const ParameterTree&)>> sections;
+  for (auto&& compartment : compartments.sub("compartments").getValueKeys())
+    sections.push_back(
+      [&](auto ini) { return get_compartment_i(ini, compartment); });
+
+  auto compartment_i = get_sections(config.sub("model"), sections);
+
+  add(compartments, compartment_i);
+
+  ParameterTree new_config;
+  new_config.sub("model") = compartments;
+
+  // bug in parameter tree. If keys go first, sub section is not well set!
+  std::vector<std::string> model_keys{ "begin_time", "end_time", "time_step" };
+  add(new_config.sub("model"), get_keys(config.sub("model"), model_keys));
+
+  // todo : check that they are valid keys
+  return new_config;
+}
+
+} // namespace Dune::Copasi
+
+#endif // DUNE_COPASI_PARAMETER_PARSER_HH
\ No newline at end of file
diff --git a/dune/copasi/pdelab_expression_adapter.hh b/dune/copasi/common/pdelab_expression_adapter.hh
similarity index 70%
rename from dune/copasi/pdelab_expression_adapter.hh
rename to dune/copasi/common/pdelab_expression_adapter.hh
index 60670113d94b35e456bcaf16b81648ef7ab02c16..1a1b48d3f446ec1df2f42302d7906efb7a440872 100644
--- a/dune/copasi/pdelab_expression_adapter.hh
+++ b/dune/copasi/common/pdelab_expression_adapter.hh
@@ -1,7 +1,7 @@
 #ifndef DUNE_COPASI_GRID_FUNCTION_EXPRESSION_ADAPTER_HH
 #define DUNE_COPASI_GRID_FUNCTION_EXPRESSION_ADAPTER_HH
 
-#include <dune/copasi/tiff_grayscale.hh>
+#include <dune/copasi/common/tiff_grayscale.hh>
 
 #include <dune/pdelab/common/function.hh>
 
@@ -18,6 +18,14 @@
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      Converts an interface to match an expression to a PDELab grid
+ *             function.
+ * @details    The resulting grid view is only for scalar expressions
+ *
+ * @tparam     GV    Grid View
+ * @tparam     RF    Range Field
+ */
 template<typename GV, typename RF>
 class ExpressionToGridFunctionAdapter
   : public PDELab::GridFunctionBase<
@@ -27,8 +35,16 @@ class ExpressionToGridFunctionAdapter
 public:
   using Traits = PDELab::GridFunctionTraits<GV, RF, 1, FieldVector<RF, 1>>;
 
-  //! construct from grid view
-
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  grid_view          The grid view
+   * @param[in]  equation           The math expression
+   * @param[in]  do_compile_parser  Bool to compile parser at object
+   * construction
+   * @param[in]  other_variables    Extra varialbes names to be available in the
+   * expression
+   */
   ExpressionToGridFunctionAdapter(const GV& grid_view,
                                   const std::string& equation,
                                   bool do_compile_parser = true,
@@ -67,15 +83,32 @@ public:
     _logger.debug("ExpressionToGridFunctionAdapter constructed"_fmt);
   }
 
+  /**
+   * @brief      Destroys the object.
+   */
   ~ExpressionToGridFunctionAdapter()
   {
     _logger.debug("ExpressionToGridFunctionAdapter deconstructed"_fmt);
   }
 
-  //! get a reference to the grid view
+  /**
+   * @brief      Gets a reference to the grid view
+   *
+   * @return     The grid view.
+   */
   inline const GV& getGridView() const { return _gv; }
 
-  //! evaluate extended function on element
+  /**
+   * @brief      Evaluates extended function on a element
+   *
+   * @param[in]  e     Entity to operate with
+   * @param[in]  x     Local coordinates in the entity
+   * @param      y     Resulting value
+   *
+   * @tparam     E     Entity
+   * @tparam     D     Domain
+   * @tparam     R     Range
+   */
   template<class E, class D, class R>
   void evaluate(const E& e, const D& x, R& y) const
   {
@@ -91,12 +124,22 @@ public:
     }
   }
 
+  /**
+   * @brief      Updates the given other values set at construction.
+   * @details    The extra values have to have the same order as entred in the
+   *             object construction
+   *
+   * @param[in]  other_value  The other values
+   */
   inline void update(const DynamicVector<RF>& other_value)
   {
     assert(_other_value.size() == other_value.size());
     _other_value = other_value;
   }
 
+  /**
+   * @brief      Compiles the parser and checks that it is able to be evaluated
+   */
   void compile_parser()
   {
     try {
@@ -116,13 +159,18 @@ public:
     return _parser;
   }
 
+  /**
+   * @brief      Sets the time.
+   *
+   * @param[in]  t     The new time
+   */
   void set_time(double t) { _time = t; }
 
 private:
-  /// Output information on the parser error and throw DUNE exception
   /**
-   *  \param e Exception thrown by the parser
-   *  \throw IOError (always throws)
+   * @brief      Output information on the parser error and throw DUNE exception
+   *
+   * @param[in]  e     Exception thrown by the parser
    */
   void handle_parser_error(const mu::Parser::exception_type& e) const
   {
diff --git a/dune/copasi/common/tiff_grayscale.hh b/dune/copasi/common/tiff_grayscale.hh
new file mode 100644
index 0000000000000000000000000000000000000000..8be21255636468880adf596d99d29cbeb7b3ccc0
--- /dev/null
+++ b/dune/copasi/common/tiff_grayscale.hh
@@ -0,0 +1,249 @@
+#ifndef DUNE_COPASI_TIFF_GRAYSCALE_HH
+#define DUNE_COPASI_TIFF_GRAYSCALE_HH
+
+#include <dune/common/exceptions.hh>
+#include <dune/common/float_cmp.hh>
+
+#include <tiffio.h>
+
+#include <memory>
+#include <queue>
+#include <string>
+
+namespace Dune::Copasi {
+
+/**
+ * @brief      This class describes a tiff grayscale.
+ * @details    This class opens, closes, and quere information from a single
+ *             tiff image. Data can be querid using matrix like indices with the
+ *             bracket operator or using space coordinates using the parethesis
+ *             operator.
+ *
+ * @tparam     T     Unsigned integer type to represent each pixel information.
+ */
+template<class T>
+class TIFFGrayscale
+{
+  static_assert(std::is_integral_v<T>, "T must be an integral type");
+  static_assert(std::is_unsigned_v<T>, "T must be an unsigned type");
+
+  /**
+   * @brief      This class represents a single row of a tiff grayscale
+   */
+  struct TIFFGrayscaleRow
+  {
+    /**
+     * @brief      Constructs a tiff grayscale row
+     *
+     * @param      tiff_file  The tiff file
+     * @param[in]  row        The row
+     * @param[in]  col_size   The column size
+     * @param[in]  zero       Zero based grayscale?
+     */
+    TIFFGrayscaleRow(TIFF* const tiff_file,
+                     const T& row,
+                     const short& col_size,
+                     const bool& zero)
+      : _row(row)
+      , _col_size(col_size)
+      , _zero(zero)
+    {
+      T* raw_buffer = (T*)_TIFFmalloc(TIFFScanlineSize(tiff_file));
+      auto deleter = [](auto& ptr) { _TIFFfree(ptr); };
+      _tiff_buffer = std::shared_ptr<T>(raw_buffer, deleter);
+      TIFFReadScanline(tiff_file, _tiff_buffer.get(), _row);
+    }
+
+    /**
+     * @brief      Array indexer column operator.
+     * @details    This operator always scales the gayscale value with its
+     *             maximum value. This way, the results is independent of the
+     *             template argument T being used
+     *
+     * @param[in]  col   The column for the current row
+     *
+     * @return     The result of the array indexer scaled between 0 and 1.
+     */
+    double operator[](const T& col) const
+    {
+      assert((short)col < _col_size);
+      const T max = std::numeric_limits<T>::max();
+      T val = *(_tiff_buffer.get() + col);
+      val = _zero ? val : max - val;
+      return (double)val / max;
+    }
+
+    /**
+     * @brief      The size of this row
+     *
+     * @return     Number of columns in this row
+     */
+    std::size_t size() const { return static_cast<std::size_t>(_col_size); }
+
+    /**
+     * @brief      The current row
+     *
+     * @return     Current row
+     */
+    std::size_t row() const { return static_cast<std::size_t>(_row); }
+
+  private:
+    std::shared_ptr<T> _tiff_buffer;
+    const T _row;
+    const short _col_size;
+    const bool _zero;
+  };
+
+public:
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  filename   The filename
+   * @param[in]  max_cache  The maximum row cache.
+   */
+  TIFFGrayscale(const std::string& filename, std::size_t max_cache = 8)
+    : _tiff_file(TIFFOpen(filename.c_str(), "r"))
+    , _max_cache(max_cache)
+  {
+    if (not _tiff_file)
+      DUNE_THROW(IOError, "Error opening TIFF file '" << filename << "'.");
+
+    short photometric;
+    TIFFGetField(_tiff_file, TIFFTAG_PHOTOMETRIC, &photometric);
+    if ((photometric != PHOTOMETRIC_MINISWHITE) and
+        (photometric != PHOTOMETRIC_MINISBLACK))
+      DUNE_THROW(IOError,
+                 "TIFF file '" << filename << "' must be in grayscale.");
+    _zero = (bool)photometric;
+
+    short bits_per_sample;
+    TIFFGetField(_tiff_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
+
+    if (bits_per_sample != 8 * sizeof(T)) {
+      TIFFClose(_tiff_file);
+      DUNE_THROW(IOError,
+                 "TIFF file '" << filename
+                               << "' contains a non-readable grayscale field.");
+    }
+
+    TIFFGetField(_tiff_file, TIFFTAG_IMAGELENGTH, &_row_size);
+    TIFFGetField(_tiff_file, TIFFTAG_IMAGEWIDTH, &_col_size);
+    TIFFGetField(_tiff_file, TIFFTAG_XRESOLUTION, &_x_res);
+    TIFFGetField(_tiff_file, TIFFTAG_YRESOLUTION, &_y_res);
+    assert(FloatCmp::gt(_x_res, 0.f));
+    assert(FloatCmp::gt(_y_res, 0.f));
+    _x_off = _y_off = 0.;
+    TIFFGetField(_tiff_file, TIFFTAG_XPOSITION, &_x_off);
+    TIFFGetField(_tiff_file, TIFFTAG_YPOSITION, &_y_off);
+  }
+
+  /**
+   * @brief      Destroys the object.
+   */
+  ~TIFFGrayscale() { TIFFClose(_tiff_file); }
+
+  /**
+   * @brief      Array indexer row operator.
+   * @warning    If rows are read concurrently, this object has to be copied
+   *
+   * @param[in]  row   The row index
+   *
+   * @return     The row
+   */
+  const TIFFGrayscaleRow& operator[](T row) const
+  {
+    assert((short)row < _row_size);
+    return cache(row);
+  }
+
+  /**
+   * @brief      TIFF value by position call operator.
+   * @details    Here we assume that TIFFTAG_RESOLUTIONUNIT has same units as
+   *             the grid. Since we never check grid units, we also do not check
+   *             tiff units
+   *
+   * @param[in]  x     The x position in same units as the tiff file
+   * @param[in]  y     The x position in same units as the tiff file
+   *
+   * @tparam     DF    Domain Field type
+   *
+   * @return     Scaled TIFF value if x and y are in the TIFF domain, 0
+   *             otherwise
+   */
+  template<class DF>
+  double operator()(const DF& x, const DF& y)
+  {
+    // return 0 if not in the domain
+    if (FloatCmp::lt((float)x, _x_off) or FloatCmp::lt((float)y, _y_off))
+      return 0;
+
+    const T i = _x_res * (_x_off + x);
+    const T j = _row_size - _y_res * (_y_off + y) - 1;
+
+    // return 0 if not in the domain
+    if (i >= cols() or j >= rows())
+      return 0;
+    else
+      return (*this)[j][i];
+  }
+
+  /**
+   * @brief      The size of rows for this file
+   *
+   * @return     Number of rows in this file
+   */
+  std::size_t size() const { return rows(); }
+
+  /**
+   * @brief      The size of rows for this file
+   *
+   * @return     Number of rows in this file
+   */
+  std::size_t rows() const { return static_cast<std::size_t>(_row_size); }
+
+  /**
+   * @brief      The size of cols for this file
+   *
+   * @return     Number of cols in this file
+   */
+  std::size_t cols() const { return static_cast<std::size_t>(_col_size); }
+
+private:
+  /**
+   * @brief      Cache rows
+   *
+   * @param[in]  row   The row to be cached
+   *
+   * @return     The cached row
+   */
+  const TIFFGrayscaleRow& cache(T row) const
+  {
+    auto it = _row_cache.rbegin();
+    while ((it != _row_cache.rend()) and (it->row() != row))
+      it++;
+
+    if (it != _row_cache.rend())
+      return *it;
+    else
+      _row_cache.emplace_back(_tiff_file, row, _col_size, _zero);
+
+    if (_row_cache.size() >= 8)
+      _row_cache.pop_front();
+
+    return *(_row_cache.rbegin());
+  }
+
+private:
+  TIFF* _tiff_file;
+  mutable std::deque<TIFFGrayscaleRow> _row_cache;
+  short _row_size;
+  short _col_size;
+  float _x_res, _x_off;
+  float _y_res, _y_off;
+  bool _zero;
+  const std::size_t _max_cache;
+};
+
+} // namespace Dune::Copasi
+
+#endif // DUNE_COPASI_TIFF_GRAYSCALE_HH
\ No newline at end of file
diff --git a/dune/copasi/finite_element/CMakeLists.txt b/dune/copasi/finite_element/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..eac0d20d8ff38c50ca14077b97e6ea1d600c7070
--- /dev/null
+++ b/dune/copasi/finite_element/CMakeLists.txt
@@ -0,0 +1,6 @@
+install(FILES   dynamic_local_basis.hh
+                dynamic_local_coefficients.hh
+                dynamic_local_interpolation.hh
+                dynamic_local_finite_element.hh
+                multidomain_local_finite_element_map.hh
+        DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dune/copasi/finite_element")
\ No newline at end of file
diff --git a/dune/copasi/dynamic_local_basis.hh b/dune/copasi/finite_element/dynamic_local_basis.hh
similarity index 50%
rename from dune/copasi/dynamic_local_basis.hh
rename to dune/copasi/finite_element/dynamic_local_basis.hh
index 169e672481f8565198ead7c81ab6307cce07dfef..abcc7b7afeecaf3bd3fa2a9e5b1c5db8f80ea484 100644
--- a/dune/copasi/dynamic_local_basis.hh
+++ b/dune/copasi/finite_element/dynamic_local_basis.hh
@@ -9,12 +9,23 @@
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      This class describes dynamic power local basis.
+ *
+ * @tparam     Basis  The base local basis
+ */
 template<class Basis>
 class DynamicPowerLocalBasis
 {
 public:
   using Traits = typename Basis::Traits;
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  basis       The base local basis
+   * @param[in]  power_size  The power size
+   */
   DynamicPowerLocalBasis(const Basis& basis, std::size_t power_size)
     : _power_size(power_size)
     , _basis(basis)
@@ -23,22 +34,53 @@ public:
     assert(_power_size >= 0);
   }
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  basis  The base local basis
+   */
   DynamicPowerLocalBasis(const Basis& basis)
     : DynamicPowerLocalBasis(basis, 1)
   {}
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  power_size  The power size
+   *
+   * @tparam     <unnamed>   Internal use to allow default constructible base
+   *                         local basis
+   */
   template<class = std::enable_if_t<std::is_default_constructible_v<Basis>>>
   DynamicPowerLocalBasis(std::size_t power_size)
     : DynamicPowerLocalBasis(Basis{}, power_size)
   {}
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @tparam     <unnamed>   Internal use to allow default constructible base
+   *                         local basis
+   */
   template<class = std::enable_if_t<std::is_default_constructible_v<Basis>>>
   DynamicPowerLocalBasis()
     : DynamicPowerLocalBasis(1)
   {}
 
+  /**
+   * @brief      Returns the number of shape functions for this local finite
+   *             element
+   *
+   * @return     The number of shape functions
+   */
   unsigned int size() const { return _power_size * _basis.size(); }
 
+  /**
+   * @brief      Evaluation function for a given local coordinate
+   *
+   * @param[in]  in    The local coordinates
+   * @param      out   The value of each shape function
+   */
   inline void evaluateFunction(
     const typename Traits::DomainType& in,
     std::vector<typename Traits::RangeType>& out) const
@@ -47,6 +89,12 @@ public:
     populate_output(f, in, out);
   }
 
+  /**
+   * @brief      Jacobian evaluation function for a given local coordinate
+   *
+   * @param[in]  in    The local coordinates
+   * @param      out   The value of the jacobian for each shape function
+   */
   inline void evaluateJacobian(
     const typename Traits::DomainType& in,
     std::vector<typename Traits::JacobianType>& out) const
@@ -55,6 +103,18 @@ public:
     populate_output(f, in, out);
   }
 
+  /**
+   * @brief      The partial derivate of the shape functions
+   * @warning    This function is here only fulfill the interface requirements.
+   *             This was never used nor tested.
+   *
+   * @param[in]  order  The order
+   * @param[in]  in     The local coordinates
+   * @param      out    The value of the partial derivate for each shape
+   * function
+   *
+   * @tparam     dim    The grid entity dimension
+   */
   template<int dim>
   void partial(const std::array<unsigned int, dim>& order,
                const typename Traits::DomainType& in,
@@ -64,9 +124,27 @@ public:
     populate_output(f, in, out);
   }
 
+  /**
+   * @brief      Polynomal order of the shape functions
+   *
+   * @return     The polynomal order of the shape functions
+   */
   unsigned int order() const { return _basis.order(); }
 
 private:
+  /**
+   * @brief      Helper class to polulate results for interface functions
+   *
+   * @param[in]  f     A function that evaluates a interface function for an
+   *                   individual local basis function
+   * @param[in]  in    The local coordinates
+   * @param      out   The result of the evaluation of f over the power local
+   *                   basis function
+   *
+   * @tparam     F     The function type
+   * @tparam     In    The local coordinates type
+   * @tparam     Out   The result populated type
+   */
   template<class F, class In, class Out>
   void populate_output(const F& f, const In& in, Out& out) const
   {
diff --git a/dune/copasi/dynamic_local_coefficients.hh b/dune/copasi/finite_element/dynamic_local_coefficients.hh
similarity index 68%
rename from dune/copasi/dynamic_local_coefficients.hh
rename to dune/copasi/finite_element/dynamic_local_coefficients.hh
index 47ac7d2a5ccbcbb5377fe3b106243aedd695ec02..b1fb8a701bd47cbb347e48efd331eb7ad674fa09 100644
--- a/dune/copasi/dynamic_local_coefficients.hh
+++ b/dune/copasi/finite_element/dynamic_local_coefficients.hh
@@ -11,10 +11,21 @@
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      This class describes dynamic power local coefficients.
+ *
+ * @tparam     Coefficients  The base local coefficients
+ */
 template<class Coefficients>
 class DynamicPowerLocalCoefficients
 {
 public:
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  coefficients  The base coefficients
+   * @param[in]  power_size    The power size
+   */
   DynamicPowerLocalCoefficients(const Coefficients& coefficients,
                                 std::size_t power_size)
     : _size(power_size * coefficients.size())
@@ -53,24 +64,55 @@ public:
     assert(_local_keys.size() == size());
   }
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  coefficients  The base coefficients
+   */
   DynamicPowerLocalCoefficients(const Coefficients& coefficients)
     : DynamicPowerLocalCoefficients(coefficients, 1)
   {}
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  power_size  The power size
+   *
+   * @tparam     <unnamed>   Internal use to allow default constructible base
+   *                         local coefficients
+   */
   template<
     class = std::enable_if_t<std::is_default_constructible_v<Coefficients>>>
   DynamicPowerLocalCoefficients(std::size_t power_size)
     : DynamicPowerLocalCoefficients(Coefficients{}, power_size)
   {}
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @tparam     <unnamed>   Internal use to allow default constructible base
+   *                         local coefficients
+   */
   template<
     class = std::enable_if_t<std::is_default_constructible_v<Coefficients>>>
   DynamicPowerLocalCoefficients()
     : DynamicPowerLocalCoefficients(1)
   {}
 
+  /**
+   * @brief      Returns the number of coefficients
+   *
+   * @return     The size
+   */
   std::size_t size() const { return _size; }
 
+  /**
+   * @brief      Returns a local key for each degree of freedom
+   *
+   * @param[in]  i     The degree of freedom
+   *
+   * @return     The local key for the given degree of freedom
+   */
   const LocalKey& localKey(std::size_t i) const { return _local_keys[i]; }
 
 private:
diff --git a/dune/copasi/dynamic_local_finite_element.hh b/dune/copasi/finite_element/dynamic_local_finite_element.hh
similarity index 59%
rename from dune/copasi/dynamic_local_finite_element.hh
rename to dune/copasi/finite_element/dynamic_local_finite_element.hh
index ccc8a78075bd67464347efab0bf5829dce532b35..fc92602eb276f183e1e5ec39a810cdb47f897d91 100644
--- a/dune/copasi/dynamic_local_finite_element.hh
+++ b/dune/copasi/finite_element/dynamic_local_finite_element.hh
@@ -1,9 +1,9 @@
 #ifndef DUNE_COPASI_DYNAMIC_LOCAL_FINITE_ELEMENT_HH
 #define DUNE_COPASI_DYNAMIC_LOCAL_FINITE_ELEMENT_HH
 
-#include <dune/copasi/dynamic_local_basis.hh>
-#include <dune/copasi/dynamic_local_coefficients.hh>
-#include <dune/copasi/dynamic_local_interpolation.hh>
+#include <dune/copasi/finite_element/dynamic_local_basis.hh>
+#include <dune/copasi/finite_element/dynamic_local_coefficients.hh>
+#include <dune/copasi/finite_element/dynamic_local_interpolation.hh>
 
 #include <dune/localfunctions/common/localfiniteelementtraits.hh>
 
@@ -11,6 +11,11 @@
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      This class describes a dynamic power local finite element.
+ *
+ * @tparam     LocalFiniteElement  The base local finite element
+ */
 template<class LocalFiniteElement>
 class DynamicPowerLocalFiniteElement
 {
@@ -30,6 +35,14 @@ public:
   using Traits =
     LocalFiniteElementTraits<LocalBasis, LocalCoefficients, LocalInterpolation>;
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  finite_element       The base local finite element
+   * @param[in]  local_basis          The base local basis
+   * @param[in]  local_coeficcients   The base local coeficcients
+   * @param[in]  local_interpolation  The base local interpolation
+   */
   DynamicPowerLocalFiniteElement(const LocalFiniteElement& finite_element,
                                  const LocalBasis& local_basis,
                                  const LocalCoefficients& local_coeficcients,
@@ -40,6 +53,15 @@ public:
     , _interpolation(local_interpolation)
   {}
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  finite_element  The base local finite element
+   * @param[in]  power_size      The power size
+   * @param[in]  local_basis          The base local basis
+   * @param[in]  local_coeficcients   The base local coeficcients
+   * @param[in]  local_interpolation  The base local interpolation
+   */
   DynamicPowerLocalFiniteElement(const LocalFiniteElement& finite_element,
                                  std::size_t power_size)
     : _finite_element(finite_element)
@@ -48,24 +70,54 @@ public:
     , _interpolation(_finite_element.localInterpolation(), power_size)
   {}
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  power_size  The power size
+   */
   DynamicPowerLocalFiniteElement(std::size_t power_size)
     : DynamicPowerLocalFiniteElement(LocalFiniteElement{}, power_size)
   {}
 
+  /**
+   * @brief      Returns the power local basis
+   *
+   * @return     The power local basis
+   */
   const typename Traits::LocalBasisType& localBasis() const { return _basis; }
 
+  /**
+   * @brief      Returns the power local coefficents
+   *
+   * @return     The power local coefficients
+   */
   const typename Traits::LocalCoefficientsType& localCoefficients() const
   {
     return _coefficients;
   }
 
+  /**
+   * @brief      Returns the power local interpolation
+   *
+   * @return     The power local interpolation
+   */
   const typename Traits::LocalInterpolationType& localInterpolation() const
   {
     return _interpolation;
   }
 
+  /**
+   * @brief      Returns the number of degrees of freedom for this element
+   *
+   * @return     The size
+   */
   unsigned int size() const { return _coefficients.size(); }
 
+  /**
+   * @brief      Returns the geometry type for this finite element
+   *
+   * @return     The geometry type
+   */
   GeometryType type() const { return _finite_element.type(); }
 
 private:
diff --git a/dune/copasi/dynamic_local_interpolation.hh b/dune/copasi/finite_element/dynamic_local_interpolation.hh
similarity index 69%
rename from dune/copasi/dynamic_local_interpolation.hh
rename to dune/copasi/finite_element/dynamic_local_interpolation.hh
index f6a0c5f47f043d6bd06bfae580c9daa99cd8f7e2..cfe518745494aeaae9101c22d47a0611b13c33d1 100644
--- a/dune/copasi/dynamic_local_interpolation.hh
+++ b/dune/copasi/finite_element/dynamic_local_interpolation.hh
@@ -6,10 +6,16 @@
 #include <dune/common/classname.hh>
 #include <dune/common/dynvector.hh>
 #include <dune/common/fvector.hh>
+
 #include <iostream>
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      This class describes a dynamic power local interpolation.
+ *
+ * @tparam     Interpolation  The base interpolation
+ */
 template<class Interpolation>
 class DynamicPowerLocalInterpolation
 {
@@ -22,22 +28,52 @@ public:
     assert(_power_size >= 0);
   }
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  interpolation  The base interpolation
+   */
   DynamicPowerLocalInterpolation(const Interpolation& interpolation)
     : DynamicPowerLocalInterpolation(interpolation, 1)
   {}
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  power_size  The power size
+   *
+   * @tparam     <unnamed>   Internal template argument to allow default
+   *                         constructible base interpolations
+   */
   template<
     class = std::enable_if_t<std::is_default_constructible_v<Interpolation>>>
   DynamicPowerLocalInterpolation(std::size_t power_size)
     : DynamicPowerLocalInterpolation(Interpolation{}, power_size)
   {}
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @tparam     <unnamed>   Internal template argument to allow default
+   *                         constructible base interpolations
+   */
   template<
     class = std::enable_if_t<std::is_default_constructible_v<Interpolation>>>
   DynamicPowerLocalInterpolation()
     : DynamicPowerLocalInterpolation(1)
   {}
 
+  /**
+   * @brief      Interpolation method
+   *
+   * @param[in]  f     Function to be interpolated. If its return type is a
+   *                   dynamic vector, it has to have a size equal or greater
+   *                   than the power size set to this ibject
+   * @param      out   The vector of coefficients for the local finite element
+   *
+   * @tparam     F     The function type
+   * @tparam     C     The coefficents type
+   */
   template<typename F, typename C>
   void interpolate(const F& f, std::vector<C>& out) const
   {
diff --git a/dune/copasi/multidomain_local_finite_element_map.hh b/dune/copasi/finite_element/multidomain_local_finite_element_map.hh
similarity index 52%
rename from dune/copasi/multidomain_local_finite_element_map.hh
rename to dune/copasi/finite_element/multidomain_local_finite_element_map.hh
index 1d62a11c86cd3eb5508db45bab9ce381a5e08838..ece64b44b2c03fd5e3d9b6d0f3ee7a534fd97827 100644
--- a/dune/copasi/multidomain_local_finite_element_map.hh
+++ b/dune/copasi/finite_element/multidomain_local_finite_element_map.hh
@@ -1,12 +1,26 @@
 #ifndef DUNE_COPASI_MULTIDOMAIN_LOCAL_FINITE_ELEMENT_MAP_HH
 #define DUNE_COPASI_MULTIDOMAIN_LOCAL_FINITE_ELEMENT_MAP_HH
 
-#include <dune/pdelab/finiteelementmap/finiteelementmap.hh>
+#include <dune/copasi/finite_element/dynamic_local_finite_element.hh>
 
-#include <dune/copasi/dynamic_local_finite_element.hh>
+#include <dune/pdelab/finiteelementmap/finiteelementmap.hh>
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      This class describes a multi domain local finite element map.
+ * @details    This class wrapps a usual PDELab finite element map into a
+ *             dynamic power finite element map. If the entity to be map does
+ *             not belong to the grid view, it will return a 0 power element map
+ *             that turns to return a finite element with no degrees of freedom.
+ *             This behaviour is useful when the pdelab machinary is operating
+ *             in the whole grid (e.g. multidomain grid) but you want to have
+ *             different finite elements per sub domain.
+ *
+ * @tparam     FiniteElementMap  The original finite element map to wrap
+ * @tparam     GridView          The grid view where the finite element will be
+ *                               not zero
+ */
 template<class FiniteElementMap, class GridView>
 class MultiDomainLocalFiniteElementMap
   : public PDELab::LocalFiniteElementMapInterface<
@@ -20,6 +34,17 @@ class MultiDomainLocalFiniteElementMap
 public:
   static const int dimension = FiniteElementMap::dimension;
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  grid_view            The grid view (may be a sub domain)
+   * @param[in]  fem                  The finite element map to wrap
+   * @param[in]  base_finite_element  The base finite element of the finite
+   *                                  element map
+   * @param[in]  power_size           The power size for the sub domain part
+   *                                  (this is always 0 outside of the
+   *                                  subdomain)
+   */
   MultiDomainLocalFiniteElementMap(GridView grid_view,
                                    FiniteElementMap fem,
                                    BaseFiniteElement base_finite_element,
@@ -31,6 +56,19 @@ public:
     , _fe_null(base_finite_element, 0)
   {}
 
+  /**
+   * @brief      Constructs a new instance.
+   * @details    This constructor is only available if the base finite element
+   *             is default constructiible
+   *
+   * @param[in]  grid_view   The grid view
+   * @param[in]  fem         The finite element map to wrap
+   * @param[in]  power_size  The power size for the sub domain part (this is
+   *                         always 0 outside of the subdomain)
+   *
+   * @tparam     <unnamed>   Template helper to allow default construction of
+   *                         base finite element constructor. Internal use only
+   */
   template<
     typename =
       std::enable_if_t<std::is_default_constructible_v<BaseFiniteElement>, int>>
@@ -43,8 +81,22 @@ public:
                                        power_size)
   {}
 
+  /**
+   * @brief      Destroys the object.
+   */
   ~MultiDomainLocalFiniteElementMap() { delete _fe_cache; }
 
+  /**
+   * @brief      Searches for the finite element for entity e.
+   * @todo       Cache more than one finite element
+   *
+   * @param[in]  e           The entity
+   *
+   * @tparam     EntityType  The entity
+   *
+   * @return     A dynamic power local finite element
+   *             @DynamicPowerLocalFiniteElement
+   */
   template<class EntityType>
   const FiniteElement& find(const EntityType& e) const
   {
@@ -66,12 +118,15 @@ public:
                               .contains(sub_domain);
         if (not in_grid_view)
           return _fe_null;
+      } else {
+        DUNE_THROW(NotImplemented,
+                   "Method not implemented for subdomain entites");
       }
     }
     auto base_fe = _fem.find(e);
+
     // cache the last used base finite element
-    if (_base_fe_cache != &base_fe) // TODO: Cache more than one fe
-    {
+    if (_base_fe_cache != &base_fe) {
       _base_fe_cache = &base_fe;
       if (_fe_cache != NULL)
         delete _fe_cache;
@@ -80,18 +135,42 @@ public:
     return *_fe_cache;
   }
 
+  /**
+   * @brief      Returns true if this finite element map has a fixed size
+   *
+   * @return     Always false for this type
+   */
   bool fixedSize() const { return false; }
 
+  /**
+   * @brief      Size for a given geometry type
+   *
+   * @param[in]  gt    The geometry type
+   *
+   * @return     The size for the given geometry type
+   */
   std::size_t size(GeometryType gt) const
   {
     return _power_size * _fem.size(gt);
   }
 
+  /**
+   * @brief      Describes wheter a codim has associated degrees of freedom
+   *
+   * @param[in]  codim  The codim
+   *
+   * @return     True if codim has dregees of freedom
+   */
   bool hasDOFs(int codim) const
   {
     return (_power_size != 0) && _fem.hasDOFs(codim);
   }
 
+  /**
+   * @brief      Maximum local size for all finite elements
+   *
+   * @return     The maximim size
+   */
   std::size_t maxLocalSize() const { return _power_size * _fem.maxLocalSize(); }
 
 private:
diff --git a/dune/copasi/grid/CMakeLists.txt b/dune/copasi/grid/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4c65b42015765434df6bfa6a4294f1033f45d438
--- /dev/null
+++ b/dune/copasi/grid/CMakeLists.txt
@@ -0,0 +1,3 @@
+install(FILES   multidomain_gmsh_reader.hh
+                multidomain_entity_transformation.hh
+        DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dune/copasi/grid")
\ No newline at end of file
diff --git a/dune/copasi/multidomain_entity_transformation.hh b/dune/copasi/grid/multidomain_entity_transformation.hh
similarity index 57%
rename from dune/copasi/multidomain_entity_transformation.hh
rename to dune/copasi/grid/multidomain_entity_transformation.hh
index ef0bee2b3780d605a537040c967ec4432681f2b0..6e1077462597f34fc12999be1998e2d8613b574b 100644
--- a/dune/copasi/multidomain_entity_transformation.hh
+++ b/dune/copasi/grid/multidomain_entity_transformation.hh
@@ -5,6 +5,17 @@
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      Multidomain entity transformation
+ * @details    This class transform an entity of a multidomain grid to a
+ *             subdomain grid entity. Equivalent to the lambda function:
+ * @code{.cpp}
+ * auto entity_transform = [&](auto e){return
+ * _grid->multiDomainEntity(entity);};
+ * @endcode
+ *
+ * @tparam     Grid  The grid
+ */
 template<class Grid>
 struct MultiDomainEntityTransformation
 {
@@ -14,15 +25,28 @@ struct MultiDomainEntityTransformation
   using SubDomainEntity =
     typename Grid::SubDomainGrid::Traits::template Codim<0>::Entity;
 
+  /**
+   * @brief      Constructor.
+   *
+   * @param[in]  grid  A pointer to the grid
+   */
   MultiDomainEntityTransformation(std::shared_ptr<const Grid> grid)
     : _grid(grid)
   {}
 
+  /**
+   * @brief      Function call operator.
+   *
+   * @param[in]  entity  The subdomain entity
+   *
+   * @return     The multidomain entity
+   */
   const MultiDomainEntity& operator()(const SubDomainEntity& entity)
   {
     return _grid->multiDomainEntity(entity);
   }
 
+private:
   const std::shared_ptr<const Grid> _grid;
 };
 
diff --git a/dune/copasi/gmsh_reader.hh b/dune/copasi/grid/multidomain_gmsh_reader.hh
similarity index 62%
rename from dune/copasi/gmsh_reader.hh
rename to dune/copasi/grid/multidomain_gmsh_reader.hh
index c5996759bbf8cbf2822a7d46fe5034b5e84770fb..2a17b1701d549aa0e4ef8ddb692e26e292b71072 100644
--- a/dune/copasi/gmsh_reader.hh
+++ b/dune/copasi/grid/multidomain_gmsh_reader.hh
@@ -1,26 +1,63 @@
 #ifndef DUNE_COPASI_GMSH_READER_HH
 #define DUNE_COPASI_GMSH_READER_HH
 
+#include <dune/copasi/concepts/grid.hh>
+
 #include <dune/grid/common/gridinfo.hh>
 #include <dune/grid/io/file/gmshreader.hh>
 #include <dune/grid/multidomaingrid.hh>
 
 #include <dune/logging/logging.hh>
 
+#include <dune/common/typetraits.hh>
+
 #include <algorithm>
 #include <type_traits>
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      This class describes a multi domain gmsh reader.
+ *
+ * @tparam     Grid  The grid
+ */
 template<class Grid>
-class GmshReader;
+class MultiDomainGmshReader
+{
+  static_assert(Dune::Copasi::Concept::isMultiDomainGrid<Grid>(),
+                "Grid is not multidomain grid");
+
+  // this is due the fact that multidomain grids do not export its traits type.
+  // And, since it is needed for the some grids construction, the only way is by
+  // template specialization.
+  static_assert(AlwaysFalse<Grid>::value,
+                "Not implemented: This class only accepts multidomain grids "
+                "from the dune-multidomain grid module");
+};
 
+/**
+ * @brief      This class describes a multi domain gmsh reader.
+ *
+ * @tparam     HostGrid   The host grid of the multidomain grid
+ * @tparam     MDGTraits  Traits of the multidomain grid (this is different to
+ *                        the grid interface traits!)
+ */
 template<class HostGrid, class MDGTraits>
-class GmshReader<Dune::mdgrid::MultiDomainGrid<HostGrid, MDGTraits>>
+class MultiDomainGmshReader<Dune::mdgrid::MultiDomainGrid<HostGrid, MDGTraits>>
 {
 public:
   using Grid = Dune::mdgrid::MultiDomainGrid<HostGrid, MDGTraits>;
 
+  /**
+   * @brief      Reads a grid out of a file name and a configuration file
+   *
+   * @param[in]  fileName                The gmsh file name
+   * @param[in]  config                  The configuration file
+   * @param[in]  insertBoundarySegments  Bool to include boundary segments while
+   *                                     reading file
+   *
+   * @return     A pair containing pointers to the host and the multidomain grid
+   */
   static auto read(const std::string& fileName,
                    ParameterTree config,
                    bool insertBoundarySegments = true)
diff --git a/dune/copasi/grid_function_writer.hh b/dune/copasi/grid_function_writer.hh
deleted file mode 100644
index d155566e9d7ec922555a5eeb87b5bac1a4a1ae74..0000000000000000000000000000000000000000
--- a/dune/copasi/grid_function_writer.hh
+++ /dev/null
@@ -1,240 +0,0 @@
-#ifndef DUNE_COPASI_GRID_FUNCTION_WRITER_HH
-#define DUNE_COPASI_GRID_FUNCTION_WRITER_HH
-
-#include <dune/copasi/concepts/grid.hh>
-#include <dune/copasi/concepts/typetree.hh>
-
-#include <dune/pdelab/gridfunctionspace/gridfunctionspaceutilities.hh>
-
-#include <dune/grid/io/file/vtk/subsamplingvtkwriter.hh>
-#include <dune/grid/io/file/vtk/vtksequencewriter.hh>
-
-#include <dune/common/exceptions.hh>
-#include <dune/common/parametertree.hh>
-
-#include <memory>
-#include <string>
-#include <type_traits>
-
-namespace Dune::Copasi {
-
-template<typename Data,
-         typename GV = typename Data::LFS::Traits::GridView,
-         typename RF =
-           typename BasisInterfaceSwitch<typename FiniteElementInterfaceSwitch<
-             typename Data::LFS::Traits::FiniteElement>::Basis>::RangeField,
-         int dimRange =
-           BasisInterfaceSwitch<typename FiniteElementInterfaceSwitch<
-             typename Data::LFS::Traits::FiniteElement>::Basis>::dimRange,
-         typename Range =
-           typename BasisInterfaceSwitch<typename FiniteElementInterfaceSwitch<
-             typename Data::LFS::Traits::FiniteElement>::Basis>::Range>
-class DiscreteGridFunction
-  : public PDELab::GridFunctionBase<
-      PDELab::GridFunctionTraits<GV, RF, dimRange, Range>,
-      DiscreteGridFunction<Data, GV, RF, dimRange, Range>>
-{
-  typedef PDELab::GridFunctionBase<
-    PDELab::GridFunctionTraits<GV, RF, dimRange, Range>,
-    DiscreteGridFunction<Data, GV, RF, dimRange, Range>>
-    BaseT;
-
-public:
-  typedef typename BaseT::Traits Traits;
-
-  DiscreteGridFunction(const shared_ptr<Data>& data,
-                       GV grid_view,
-                       std::size_t id_begin,
-                       std::size_t id_end)
-    : _grid_view(grid_view)
-    , _data(data)
-    , _basis(data->_lfs.maxSize())
-    , _id_begin(id_begin)
-    , _id_end(id_end)
-  {}
-
-  // Evaluate
-  void evaluate(const typename Traits::ElementType& e,
-                const typename Traits::DomainType& x,
-                typename Traits::RangeType& y) const
-  {
-    y = 0;
-
-    using LFS = decltype(_data->_lfs);
-
-    if constexpr (Concept::isSubDomainGrid<typename GV::Grid>()) {
-      _data->bind(_grid_view.grid().multiDomainGrid().multiDomainEntity(e));
-
-      if constexpr (Concept::isTypeTreeNode<LFS>()) {
-        int subdomain = _grid_view.grid().domain();
-        auto lfs_child = _data->_lfs.child(subdomain);
-        typedef FiniteElementInterfaceSwitch<typename decltype(
-          lfs_child)::Traits::FiniteElement>
-          FESwitch;
-
-        FESwitch::basis(lfs_child.finiteElement()).evaluateFunction(x, _basis);
-        for (unsigned int i = _id_begin; i < _id_end; i++)
-          y.axpy(_data->_x_local(lfs_child, i), _basis[i]);
-      } else {
-        static_assert(AlwaysTrue<GV>::value);
-      }
-    } else {
-      _data->bind(e);
-
-      typedef FiniteElementInterfaceSwitch<typename LFS::Traits::FiniteElement>
-        FESwitch;
-
-      FESwitch::basis(_data->_lfs.finiteElement()).evaluateFunction(x, _basis);
-
-      for (unsigned int i = _id_begin; i < _id_end; i++)
-        y.axpy(_data->_x_local(_data->_lfs, i), _basis[i]);
-    }
-  }
-
-  //! get a reference to the GridView
-  const typename Traits::GridViewType& gridView() const { return _grid_view; }
-
-private:
-  GV _grid_view;
-  const shared_ptr<Data> _data;
-  mutable std::vector<typename Traits::RangeType> _basis;
-  const std::size_t _id_begin, _id_end;
-};
-
-/**
- * @brief      Converts PDELab grid function to match a dune-function.
- * @note       This adapter differs from the one provided in PDELab in that this
- *             one has the current interface of dune-grid to write vtk files.
- *             The main difference using this adapter is that it allows to write
- *             more than 3 components.
- *
- * @tparam     GF    PDELab grid function type.
- */
-template<class GF>
-class VTKGridFunctionAdapter
-{
-  using GridFunction = typename std::decay<GF>::type;
-  using GridView = typename GF::Traits::GridViewType;
-  using Entity = typename GridView::template Codim<0>::Entity;
-  using Range = typename GF::Traits::RangeType;
-  using Domain = typename GF::Traits::DomainType;
-
-public:
-  /**
-   * @brief      Constructs the object
-   *
-   * @param[in]  gf    pointer to a constant grid function
-   */
-  VTKGridFunctionAdapter(std::shared_ptr<const GF> gf)
-    : _entity(nullptr)
-    , _gf(gf)
-  {}
-
-  /**
-   * @brief      Binds an entity to the grid function
-   *
-   * @param[in]  e     Entity
-   */
-  void bind(const Entity& e) { _entity = &e; }
-
-  /**
-   * @brief      Unbinds the previously binded entity
-   */
-  void unbind() { _entity = nullptr; }
-
-  /**
-   * @brief      Evaluates the grid function at a given coordinate
-   *
-   * @param[in]  x     Local coordinate with respect to the last binded entity
-   */
-  Range operator()(const Domain& x) const
-  {
-    Range y;
-    assert(_entity);
-    _gf->evaluate(*_entity, x, y);
-    return y;
-  }
-
-private:
-  const Entity* _entity;
-  std::shared_ptr<const GF> _gf;
-};
-
-/**
- * @brief      Class for grid fucntion vtk sequence writer. This class works
- *             exacly the same way as a VTKSequence writer but it receives
- *             directly smart pointers to grid functions
- *
- * @tparam     GV    GridView of the dune grid
- */
-template<class GV>
-class GridFunctionVTKSequenceWriter : public Dune::VTKSequenceWriter<GV>
-{
-public:
-  // export constructors of vtk sequence writer
-  using Dune::VTKSequenceWriter<GV>::VTKSequenceWriter;
-
-  ~GridFunctionVTKSequenceWriter() { this->clear(); }
-  /**
-   * @brief      Adds a vertex data.
-   *
-   * @param[in]  gf_ptr  A pointer to a grid function of the type GF
-   * @param[in]  name    Name of the variable
-   *
-   * @tparam     GF      Type of the grid function
-   */
-  template<class GF>
-  void addVertexData(std::shared_ptr<const GF> gf_ptr, std::string name)
-  {
-    static_assert(std::is_same<typename GF::Traits::GridViewType, GV>::value,
-                  "GridFunctionVTKSequenceWriter only works with only one "
-                  "GridView type.");
-
-    VTKGridFunctionAdapter<GF> vtk_gf(gf_ptr);
-
-    const int vtk_ncomps = GF::Traits::dimRange;
-    const int dim = GF::Traits::dimDomain;
-    auto vtk_type = (vtk_ncomps == dim) ? VTK::FieldInfo::Type::vector
-                                        : VTK::FieldInfo::Type::scalar;
-    auto vtk_info = VTK::FieldInfo(name, vtk_type, vtk_ncomps);
-
-    this->vtkWriter()->addVertexData(vtk_gf, vtk_info);
-  }
-
-  /**
-   * @brief      Adds a cell data.
-   *
-   * @param[in]  gf_ptr  A pointer to a grid function of the type GF
-   * @param[in]  name    Name of the variable
-   *
-   * @tparam     GF      Type of the grid function
-   */
-  template<class GF>
-  void addCellData(std::shared_ptr<const GF> gf_ptr, std::string name)
-  {
-    static_assert(std::is_same<typename GF::Traits::GridViewType, GV>::value,
-                  "GridFunctionVTKSequenceWriter only works with only one "
-                  "GridView type.");
-
-    VTKGridFunctionAdapter<GF> vtk_gf(gf_ptr);
-
-    const int vtk_ncomps = GF::Traits::dimRange;
-    const int dim = GF::Traits::dimDomain;
-    auto vtk_type = (vtk_ncomps == dim) ? VTK::FieldInfo::Type::vector
-                                        : VTK::FieldInfo::Type::scalar;
-    auto vtk_info = VTK::FieldInfo(name, vtk_type, vtk_ncomps);
-
-    this->vtkWriter()->addCellData(vtk_gf, vtk_info);
-  }
-
-  /**
-   * @brief      Clear all the attached VTKFunctions.
-   * @details    This is necessary for each iteration if VTKFunctions are
-   * managed internaly with pointers instead of references
-   */
-  void clear() { this->vtkWriter()->clear(); }
-};
-
-} // namespace Dune::Copasi
-
-#endif // DUNE_COPASI_GRID_FUNCTION_WRITER_HH
\ No newline at end of file
diff --git a/dune/copasi/model/CMakeLists.txt b/dune/copasi/model/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7d137ca6a2df6a58cf4325ae725868d0d6a5c89f
--- /dev/null
+++ b/dune/copasi/model/CMakeLists.txt
@@ -0,0 +1,9 @@
+install(FILES   base.hh
+                multidomain_local_operator.hh
+                local_operator.hh
+                diffusion_reaction.cc
+                diffusion_reaction.hh
+                multidomain_diffusion_reaction.cc
+                multidomain_diffusion_reaction.hh
+                state.hh
+        DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dune/copasi/model")
\ No newline at end of file
diff --git a/dune/copasi/model_base.cc b/dune/copasi/model/base.cc
similarity index 98%
rename from dune/copasi/model_base.cc
rename to dune/copasi/model/base.cc
index 8f2410a4bdb69dae0d70c41ed1e0486f720ddea6..bec0aafe09877343d3d01ba19419f752bd35f1f4 100644
--- a/dune/copasi/model_base.cc
+++ b/dune/copasi/model/base.cc
@@ -2,7 +2,7 @@
 #include "config.h"
 #endif
 
-#include <dune/copasi/model_base.hh>
+#include <dune/copasi/model/base.hh>
 
 #include <dune/common/exceptions.hh>
 #include <dune/common/float_cmp.hh>
diff --git a/dune/copasi/model_base.hh b/dune/copasi/model/base.hh
similarity index 98%
rename from dune/copasi/model_base.hh
rename to dune/copasi/model/base.hh
index fa45f54732526124ef762c9aaa83d36b99a8b83c..a0ff199970e5e9dee7ab6f622ef59a844cbaaa98 100644
--- a/dune/copasi/model_base.hh
+++ b/dune/copasi/model/base.hh
@@ -1,7 +1,7 @@
 #ifndef DUNE_COPASI_MODEL_BASE_HH
 #define DUNE_COPASI_MODEL_BASE_HH
 
-#include <dune/copasi/enum.hh>
+#include <dune/copasi/common/enum.hh>
 
 #include <dune/logging/logging.hh>
 
diff --git a/dune/copasi/model_diffusion_reaction.cc b/dune/copasi/model/diffusion_reaction.cc
similarity index 89%
rename from dune/copasi/model_diffusion_reaction.cc
rename to dune/copasi/model/diffusion_reaction.cc
index a8f0ef4a1c3d69c22798a8d5860bc9689de6825c..770e4464b232567441e46314db9f8a1aca221a50 100644
--- a/dune/copasi/model_diffusion_reaction.cc
+++ b/dune/copasi/model/diffusion_reaction.cc
@@ -7,9 +7,8 @@
  * file but a header which has to be included when compiling.
  */
 
-#include <dune/copasi/model_diffusion_reaction.hh>
-#include <dune/copasi/pdelab_callable_adapter.hh>
-#include <dune/copasi/pdelab_expression_adapter.hh>
+#include <dune/copasi/common/pdelab_expression_adapter.hh>
+#include <dune/copasi/model/diffusion_reaction.hh>
 
 #include <dune/pdelab/function/callableadapter.hh>
 #include <dune/pdelab/gridfunctionspace/vtk.hh>
@@ -21,11 +20,11 @@
 namespace Dune::Copasi {
 
 template<class Traits>
-ModelDiffusionReaction<Traits>::
-  ModelDiffusionReaction(std::shared_ptr<Grid> grid,
-                         const Dune::ParameterTree& config,
-                         GV grid_view,
-                         ModelSetupPolicy setup_policy)
+ModelDiffusionReaction<Traits>::ModelDiffusionReaction(
+  std::shared_ptr<Grid> grid,
+  const Dune::ParameterTree& config,
+  GV grid_view,
+  ModelSetupPolicy setup_policy)
   : ModelBase(config)
   , _solver_logger(Logging::Logging::componentLogger(config, "solver"))
   , _components(config.sub("reaction").getValueKeys().size())
@@ -48,8 +47,7 @@ ModelDiffusionReaction<Traits>::
 }
 
 template<class Traits>
-ModelDiffusionReaction<Traits>::
-  ~ModelDiffusionReaction()
+ModelDiffusionReaction<Traits>::~ModelDiffusionReaction()
 {
   _logger.debug("ModelDiffusionReaction deconstructed"_fmt);
 }
@@ -87,8 +85,7 @@ ModelDiffusionReaction<Traits>::step()
 
 template<class Traits>
 void
-ModelDiffusionReaction<Traits>::suggest_timestep(
-  double dt)
+ModelDiffusionReaction<Traits>::suggest_timestep(double dt)
 {
   DUNE_THROW(NotImplemented, "");
 }
@@ -131,8 +128,8 @@ ModelDiffusionReaction<Traits>::suggest_timestep(
 
 template<class Traits>
 auto
-ModelDiffusionReaction<Traits>::
-  setup_component_grid_function_space(std::string name) const
+ModelDiffusionReaction<Traits>::setup_component_grid_function_space(
+  std::string name) const
 {
   _logger.trace("create a finite element map"_fmt);
   BaseFEM base_fem(_grid->leafGridView());
@@ -140,8 +137,7 @@ ModelDiffusionReaction<Traits>::
 
   _logger.trace("setup grid function space for component {}"_fmt, name);
   const ES entity_set(_grid->leafGridView());
-  auto comp_gfs =
-    std::make_shared<LGFS>(entity_set, finite_element_map);
+  auto comp_gfs = std::make_shared<LGFS>(entity_set, finite_element_map);
   comp_gfs->name(name);
 
   return comp_gfs;
@@ -149,8 +145,8 @@ ModelDiffusionReaction<Traits>::
 
 template<class Traits>
 auto
-ModelDiffusionReaction<Traits>::
-  setup_domain_grid_function_space(std::vector<std::string> comp_names) const
+ModelDiffusionReaction<Traits>::setup_domain_grid_function_space(
+  std::vector<std::string> comp_names) const
 {
   _logger.debug("setup domain grid function space"_fmt);
 
@@ -166,8 +162,7 @@ ModelDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelDiffusionReaction<Traits>::
-  setup_grid_function_space()
+ModelDiffusionReaction<Traits>::setup_grid_function_space()
 {
   // get component names
   auto& operator_splitting_config = _config.sub("operator");
@@ -201,8 +196,7 @@ ModelDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelDiffusionReaction<Traits>::
-  setup_coefficient_vectors()
+ModelDiffusionReaction<Traits>::setup_coefficient_vectors()
 {
   _logger.debug("setup coefficient vector"_fmt);
   for (auto& [op, state] : _states) {
@@ -217,8 +211,7 @@ ModelDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelDiffusionReaction<Traits>::
-  setup_constraints()
+ModelDiffusionReaction<Traits>::setup_constraints()
 {
   _logger.debug("setup constraints"_fmt);
 
@@ -240,8 +233,7 @@ ModelDiffusionReaction<Traits>::
 
 template<class Traits>
 auto
-ModelDiffusionReaction<Traits>::
-  setup_local_operator(std::size_t i) const
+ModelDiffusionReaction<Traits>::setup_local_operator(std::size_t i) const
 {
   _logger.trace("setup local operators {}"_fmt, i);
 
@@ -260,8 +252,7 @@ ModelDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelDiffusionReaction<Traits>::
-  setup_local_operators()
+ModelDiffusionReaction<Traits>::setup_local_operators()
 {
   _logger.trace("setup local operators"_fmt);
 
@@ -277,8 +268,7 @@ ModelDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelDiffusionReaction<Traits>::
-  setup_grid_operators()
+ModelDiffusionReaction<Traits>::setup_grid_operators()
 {
   _logger.debug("setup grid operators"_fmt);
   _spatial_grid_operators.clear();
@@ -343,8 +333,7 @@ ModelDiffusionReaction<Traits>::setup_solvers()
 
 template<class Traits>
 void
-ModelDiffusionReaction<Traits>::
-  setup_vtk_writer()
+ModelDiffusionReaction<Traits>::setup_vtk_writer()
 {
   _logger.debug("setup vtk writer"_fmt);
 
@@ -370,8 +359,7 @@ ModelDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelDiffusionReaction<Traits>::setup(
-  ModelSetupPolicy setup_policy)
+ModelDiffusionReaction<Traits>::setup(ModelSetupPolicy setup_policy)
 {
   if (setup_policy >= ModelSetupPolicy::GridFunctionSpace)
     setup_grid_function_space();
@@ -391,8 +379,7 @@ ModelDiffusionReaction<Traits>::setup(
 
 template<class Traits>
 void
-ModelDiffusionReaction<Traits>::write_states()
-  const
+ModelDiffusionReaction<Traits>::write_states() const
 {
   for (auto& [op, state] : _states) {
     auto& x = state.coefficients;
@@ -408,8 +395,7 @@ ModelDiffusionReaction<Traits>::write_states()
     using ET = decltype(etity_transformation);
 
     using Predicate = PDELab::vtk::DefaultPredicate;
-    using Data =
-      PDELab::vtk::DGFTreeCommonData<GFS, X, Predicate, GV, ET>;
+    using Data = PDELab::vtk::DGFTreeCommonData<GFS, X, Predicate, GV, ET>;
     std::shared_ptr<Data> data =
       std::make_shared<Data>(*gfs, *x, _grid_view, etity_transformation);
     PDELab::vtk::OutputCollector<SW, Data> collector(*_sequential_writer, data);
diff --git a/dune/copasi/model_diffusion_reaction.hh b/dune/copasi/model/diffusion_reaction.hh
similarity index 90%
rename from dune/copasi/model_diffusion_reaction.hh
rename to dune/copasi/model/diffusion_reaction.hh
index de8781d31ea2f4052a1533f1451e21436cab77fa..fd9ab700ec06f9d6e9d3ac8324db74b82a59d619 100644
--- a/dune/copasi/model_diffusion_reaction.hh
+++ b/dune/copasi/model/diffusion_reaction.hh
@@ -1,14 +1,13 @@
 #ifndef DUNE_COPASI_MODEL_DIFFUSION_REACTION_HH
 #define DUNE_COPASI_MODEL_DIFFUSION_REACTION_HH
 
-#include <dune/copasi/coefficient_mapper.hh>
+#include <dune/copasi/common/coefficient_mapper.hh>
+#include <dune/copasi/common/enum.hh>
 #include <dune/copasi/concepts/grid.hh>
-#include <dune/copasi/enum.hh>
-#include <dune/copasi/grid_function_writer.hh>
-#include <dune/copasi/local_operator.hh>
-#include <dune/copasi/model_base.hh>
-#include <dune/copasi/model_state.hh>
-#include <dune/copasi/multidomain_local_finite_element_map.hh>
+#include <dune/copasi/finite_element/multidomain_local_finite_element_map.hh>
+#include <dune/copasi/model/base.hh>
+#include <dune/copasi/model/local_operator.hh>
+#include <dune/copasi/model/state.hh>
 
 #include <dune/pdelab/backend/istl.hh>
 #include <dune/pdelab/constraints/conforming.hh>
@@ -28,6 +27,15 @@
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      Traits for diffusion reaction models
+ *
+ * @tparam     G         Grid
+ * @tparam     GV        Grid View
+ * @tparam     FEMorder  Order of the finite element method
+ * @tparam     OT        PDELab ordering tag
+ * @tparam     JM        Jacobian method
+ */
 template<class G,
          class GV = typename G::Traits::LeafGridView,
          int FEMorder = 1,
@@ -44,9 +52,9 @@ struct ModelDiffusionReactionTraits
 
 /**
  * @brief      Class for diffusion-reaction models.
+ * @todo       Make this class work as stand-alone again
  *
- * @tparam     components  Number of components
- * @tparam     Param       Parameterization class
+ * @tparam     Traits  Class that define static policies on the model
  */
 template<class Traits>
 class ModelDiffusionReaction : public ModelBase
@@ -209,16 +217,16 @@ public:
   void step();
 
   /**
-   * @brief      Get the model state
+   * @brief      Get mutable model states
    *
-   * @return     Model state
+   * @return     Model states
    */
   std::map<std::size_t, State> states() { return _states; }
 
   /**
-   * @brief      Get the model state
+   * @brief      Get constat model states
    *
-   * @return     Model state
+   * @return     Constant model states
    */
   std::map<std::size_t, ConstState> const_states() const
   {
@@ -228,9 +236,9 @@ public:
   }
 
   /**
-   * @brief      Get the model state
+   * @brief      Get constat model states
    *
-   * @return     Model state
+   * @return     Constant model states
    */
   std::map<std::size_t, ConstState> states() const { return const_states(); }
 
diff --git a/dune/copasi/local_operator.hh b/dune/copasi/model/local_operator.hh
similarity index 73%
rename from dune/copasi/local_operator.hh
rename to dune/copasi/model/local_operator.hh
index 3f43b1f118af1257a4211d00ea97510efbc62524..def904307167c96b4e002ece2d80935787b77aef 100644
--- a/dune/copasi/local_operator.hh
+++ b/dune/copasi/model/local_operator.hh
@@ -1,8 +1,9 @@
 #ifndef DUNE_COPASI_LOCAL_OPERATOR_DIFFUSION_REACTION_HH
 #define DUNE_COPASI_LOCAL_OPERATOR_DIFFUSION_REACTION_HH
 
-#include <dune/copasi/coefficient_mapper.hh>
-#include <dune/copasi/enum.hh>
+#include <dune/copasi/common/coefficient_mapper.hh>
+#include <dune/copasi/common/enum.hh>
+#include <dune/copasi/common/pdelab_expression_adapter.hh>
 
 #include <dune/pdelab/common/quadraturerules.hh>
 #include <dune/pdelab/localoperator/flags.hh>
@@ -16,12 +17,26 @@
 
 #include <dune/common/fvector.hh>
 
-#include <dune/copasi/pdelab_expression_adapter.hh>
-
 #include <set>
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      This class describes a PDELab local operator for diffusion
+ *             reaction systems.
+ * @details    This class describre the operatrions for local integrals required
+ *             for diffusion reaction system. The operator is only valid for
+ *             entities contained in the grid view. The local finite element is
+ *             used for caching shape function evaluations. The coefficient
+ *             mapper is the interface to fetch date from either local or
+ *             external coefficient vectors. And the jacobian method switches
+ *             between numerical and analytical jacobians.
+ *
+ * @tparam     GV    Grid View
+ * @tparam     LFE   Local Finite Element
+ * @tparam     CM    Coefficient Mapper
+ * @tparam     JM    Jacobian Method
+ */
 template<class GV,
          class LFE,
          class CM = DefaultCoefficientMapper,
@@ -106,14 +121,25 @@ public:
   //! residual assembly flags
   static constexpr bool doAlphaVolume = true;
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @todo       Make integration order variable depending on user requirements
+   *             and polynomail order of the local finite element
+   *
+   * @param[in]  grid_view       The grid view where this local operator is
+   *                             valid
+   * @param[in]  config          The configuration tree
+   * @param[in]  finite_element  The local finite element
+   * @param[in]  id_operator     The index of this operator
+   */
   LocalOperatorDiffusionReaction(GridView grid_view,
                                  const ParameterTree& config,
                                  const LocalFiniteElement& finite_element,
                                  std::size_t id_operator)
     : _basis_size(finite_element.localBasis().size())
     , _components(config.sub("reaction").getValueKeys().size())
-    , _rule(QuadratureRules<RF, dim>::rule(finite_element.type(),
-                                           3)) // TODO: make order variable
+    , _rule(QuadratureRules<RF, dim>::rule(finite_element.type(), 3))
     , _diffusion_gf(_components)
     , _reaction_gf(_components)
     , _jacobian_gf(_components * _components)
@@ -215,12 +241,32 @@ public:
     _logger.debug("LocalOperatorDiffusionReaction constructed"_fmt);
   }
 
+  /**
+   * @brief      Updates the coefficient mapper with given states.
+   *
+   * @param[in]  states  A map from operator index to states
+   *
+   * @tparam     States  Map from index to states
+   */
   template<class States>
   void update(const States& states)
   {
     _coefficient_mapper.update(states);
   }
 
+  /**
+   * @brief      Pattern volume
+   * @details    This method links degrees of freedom between trial and test
+   *             spaces taking into account the structure of the reaction term
+   *
+   * @param[in]  lfsu          The trial local function space
+   * @param[in]  lfsv          The test local function space
+   * @param      pattern       The local pattern
+   *
+   * @tparam     LFSU          The trial local function space
+   * @tparam     LFSV          The test local function space
+   * @tparam     LocalPattern  The local pattern
+   */
   template<typename LFSU, typename LFSV, typename LocalPattern>
   void pattern_volume(const LFSU& lfsu,
                       const LFSV& lfsv,
@@ -238,6 +284,11 @@ public:
               pattern.addLink(lfsv.child(i), k, lfsu.child(j), l);
   }
 
+  /**
+   * @brief      Sets the time.
+   *
+   * @param[in]  t     The new time
+   */
   void setTime(double t)
   {
     Dune::PDELab::InstationaryLocalOperatorDefaultMethods<double>::setTime(t);
@@ -252,6 +303,25 @@ public:
         gf->set_time(t);
   }
 
+  /**
+   * @brief      The jacobian volume integral for matrix free operations
+   * @details    This only switches between the actual implementation (in
+   *             _jacobian_apply_volume) and the numerical jacobian
+   *
+   * @param[in]  eg    The entity
+   * @param[in]  lfsu  The trial local function space
+   * @param[in]  x     The local coefficient vector
+   * @param[in]  z     The local position in the trial space to which to apply
+   *                   the Jacobian.
+   * @param[in]  lfsv  The test local function space
+   * @param      r     The resulting vector
+   *
+   * @tparam     EG    The entity
+   * @tparam     LFSU  The trial local function space
+   * @tparam     X     The local coefficient vector type
+   * @tparam     LFSV  The test local function space
+   * @tparam     R     The resulting vector
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void jacobian_apply_volume(const EG& eg,
                              const LFSU& lfsu,
@@ -268,6 +338,57 @@ public:
     }
   }
 
+  /**
+   * @brief      The jacobian volume integral for matrix free operations (linear
+   *             variant)
+   * @details    This only switches between the actual implementation (in
+   *             _jacobian_apply_volume) and the numerical jacobian
+   *
+   * @param[in]  eg    The entity
+   * @param[in]  lfsu  The trial local function space
+   * @param[in]  x     The local coefficient vector
+   * @param[in]  lfsv  The test local function space
+   * @param      r     The resulting vector
+   *
+   * @tparam     EG    The entity
+   * @tparam     LFSU  The trial local function space
+   * @tparam     X     The local coefficient vector type
+   * @tparam     LFSV  The test local function space
+   * @tparam     R     The resulting vector
+   */
+  template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
+  void jacobian_apply_volume(const EG& eg,
+                             const LFSU& lfsu,
+                             const X& x,
+                             const LFSV& lfsv,
+                             R& r) const
+  {
+    if constexpr (JM == JacobianMethod::Numerical) {
+      PDELab::NumericalJacobianApplyVolume<LocalOperatorDiffusionReaction>::
+        jacobian_apply_volume(eg, lfsu, x, lfsv, r);
+      return;
+    } else {
+      _jacobian_apply_volume(eg, lfsu, x, x, lfsv, r);
+    }
+  }
+
+  /**
+   * @brief      The jacobian volume integral for matrix free operations
+   *
+   * @param[in]  eg    The entity
+   * @param[in]  lfsu  The trial local function space
+   * @param[in]  x     The local coefficient vector
+   * @param[in]  z     The local position in the trial space to which to apply
+   *                   the Jacobian.
+   * @param[in]  lfsv  The test local function space
+   * @param      r     The resulting vector
+   *
+   * @tparam     EG    The entity
+   * @tparam     LFSU  The trial local function space
+   * @tparam     X     The local coefficient vector type
+   * @tparam     LFSV  The test local function space
+   * @tparam     R     The resulting vector
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void _jacobian_apply_volume(const EG& eg,
                               const LFSU& lfsu,
@@ -361,7 +482,21 @@ public:
     }
   }
 
-  //! jacobian contribution of volume term
+  /**
+   * @brief      The jacobian volume integral
+   *
+   * @param[in]  eg    The entity
+   * @param[in]  lfsu  The trial local function space
+   * @param[in]  x     The local coefficient vector
+   * @param[in]  lfsv  The test local function space
+   * @param      mat   The local matrix
+   *
+   * @tparam     EG    The entity
+   * @tparam     LFSU  The trial local function space
+   * @tparam     X     The local coefficient vector type
+   * @tparam     LFSV  The test local function space
+   * @tparam     M     The local matrix
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename M>
   void jacobian_volume(const EG& eg,
                        const LFSU& lfsu,
@@ -467,6 +602,21 @@ public:
     }
   }
 
+  /**
+   * @brief      The volume integral
+   *
+   * @param[in]  eg    The entity
+   * @param[in]  lfsu  The trial local function space
+   * @param[in]  x     The local coefficient vector
+   * @param[in]  lfsv  The test local function space
+   * @param      r     The local residual vector
+   *
+   * @tparam     EG    The entity
+   * @tparam     LFSU  The trial local function space
+   * @tparam     X     The local coefficient vector type
+   * @tparam     LFSV  The test local function space
+   * @tparam     R     The local residual vector
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void alpha_volume(const EG& eg,
                     const LFSU& lfsu,
@@ -476,24 +626,21 @@ public:
   {
     _jacobian_apply_volume(eg, lfsu, x, x, lfsv, r);
   }
-
-  //! apply local jacobian of the volume term -> linear variant
-  template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
-  void jacobian_apply_volume(const EG& eg,
-                             const LFSU& lfsu,
-                             const X& x,
-                             const LFSV& lfsv,
-                             R& r) const
-  {
-    if constexpr (JM == JacobianMethod::Numerical) {
-      PDELab::NumericalJacobianApplyVolume<LocalOperatorDiffusionReaction>::
-        jacobian_apply_volume(eg, lfsu, x, lfsv, r);
-      return;
-    }
-    _jacobian_apply_volume(eg, lfsu, x, x, lfsv, r);
-  }
 };
 
+/**
+ * @brief      This class describes a PDELab local operator for temporal part
+ *             for diffusion reaction systems.
+ * @details    This class describre the operatrions for local integrals required
+ *             for diffusion reaction system. The operator is only valid for
+ *             entities contained in the grid view. The local finite element is
+ *             used for caching shape function evaluations. And the jacobian
+ *             method switches between numerical and analytical jacobians.
+ *
+ * @tparam     GV    Grid View
+ * @tparam     LFE   Local Finite Element
+ * @tparam     JM    Jacobian Method
+ */
 template<class GV, class LFE, JacobianMethod JM = JacobianMethod::Analytical>
 class TemporalLocalOperatorDiffusionReaction
   : public Dune::PDELab::LocalOperatorDefaultFlags
@@ -560,6 +707,18 @@ public:
   //! residual assembly flags
   static constexpr bool doAlphaVolume = true;
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @todo       Make integration order variable depending on user requirements
+   *             and polynomail order of the local finite element
+   *
+   * @param[in]  grid_view       The grid view where this local operator is
+   *                             valid
+   * @param[in]  config          The configuration tree
+   * @param[in]  finite_element  The local finite element
+   * @param[in]  id_operator     The index of this operator
+   */
   TemporalLocalOperatorDiffusionReaction(
     GridView grid_view,
     const ParameterTree& config,
@@ -567,8 +726,7 @@ public:
     std::size_t id_operator)
     : _basis_size(finite_element.size())
     , _components(config.sub("reaction").getValueKeys().size())
-    , _rule(QuadratureRules<RF, dim>::rule(finite_element.type(),
-                                           3)) // TODO: make order variable
+    , _rule(QuadratureRules<RF, dim>::rule(finite_element.type(), 3))
     , _logger(Logging::Logging::componentLogger(config, "model"))
   {
     auto& config_operator = config.sub("operator");
@@ -602,6 +760,21 @@ public:
     _logger.debug("TemporalLocalOperatorDiffusionReaction constructed"_fmt);
   }
 
+  /**
+   * @brief      The volume integral
+   *
+   * @param[in]  eg    The entity
+   * @param[in]  lfsu  The trial local function space
+   * @param[in]  x     The local coefficient vector
+   * @param[in]  lfsv  The test local function space
+   * @param      r     The local residual vector
+   *
+   * @tparam     EG    The entity
+   * @tparam     LFSU  The trial local function space
+   * @tparam     X     The local coefficient vector type
+   * @tparam     LFSV  The test local function space
+   * @tparam     R     The local residual vector
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void alpha_volume(const EG& eg,
                     const LFSU& lfsu,
@@ -643,12 +816,27 @@ public:
     }
   }
 
-  template<typename EG, typename LFSU, typename X, typename LFSV, typename Mat>
+  /**
+   * @brief      The jacobian volume integral
+   *
+   * @param[in]  eg    The entity
+   * @param[in]  lfsu  The trial local function space
+   * @param[in]  x     The local coefficient vector
+   * @param[in]  lfsv  The test local function space
+   * @param      mat   The local matrix
+   *
+   * @tparam     EG    The entity
+   * @tparam     LFSU  The trial local function space
+   * @tparam     X     The local coefficient vector type
+   * @tparam     LFSV  The test local function space
+   * @tparam     M     The local matrix
+   */
+  template<typename EG, typename LFSU, typename X, typename LFSV, typename M>
   void jacobian_volume(const EG& eg,
                        const LFSU& lfsu,
                        const X& x,
                        const LFSV& lfsv,
-                       Mat& mat) const
+                       M& mat) const
   {
     if constexpr (JM == JacobianMethod::Numerical) {
       PDELab::NumericalJacobianVolume<TemporalLocalOperatorDiffusionReaction>::
@@ -683,6 +871,25 @@ public:
     }
   }
 
+  /**
+   * @brief      The jacobian volume integral for matrix free operations
+   * @details    This only switches between the actual implementation (in
+   *             alpha_volume) and the numerical jacobian
+   *
+   * @param[in]  eg    The entity
+   * @param[in]  lfsu  The trial local function space
+   * @param[in]  x     The local coefficient vector
+   * @param[in]  z     The local position in the trial space to which to apply
+   *                   the Jacobian.
+   * @param[in]  lfsv  The test local function space
+   * @param      r     The resulting vector
+   *
+   * @tparam     EG    The entity
+   * @tparam     LFSU  The trial local function space
+   * @tparam     X     The local coefficient vector type
+   * @tparam     LFSV  The test local function space
+   * @tparam     R     The resulting vector
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void jacobian_apply_volume(const EG& eg,
                              const LFSU& lfsu,
@@ -704,6 +911,24 @@ public:
     alpha_volume(eg, lfsu, z, lfsv, r);
   }
 
+  /**
+   * @brief      The jacobian volume integral for matrix free operations (linear
+   *             variant)
+   * @details    This only switches between the actual implementation (in
+   *             alpha_volume) and the numerical jacobian
+   *
+   * @param[in]  eg    The entity
+   * @param[in]  lfsu  The trial local function space
+   * @param[in]  x     The local coefficient vector
+   * @param[in]  lfsv  The test local function space
+   * @param      r     The resulting vector
+   *
+   * @tparam     EG    The entity
+   * @tparam     LFSU  The trial local function space
+   * @tparam     X     The local coefficient vector type
+   * @tparam     LFSV  The test local function space
+   * @tparam     R     The resulting vector
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void jacobian_apply_volume(const EG& eg,
                              const LFSU& lfsu,
diff --git a/dune/copasi/model_multidomain_diffusion_reaction.cc b/dune/copasi/model/multidomain_diffusion_reaction.cc
similarity index 91%
rename from dune/copasi/model_multidomain_diffusion_reaction.cc
rename to dune/copasi/model/multidomain_diffusion_reaction.cc
index 7b87ef283e81bab5c59835be0a29e38406c925a9..3ac990e4ecc53c338eff63e0e3303c68eeaa6073 100644
--- a/dune/copasi/model_multidomain_diffusion_reaction.cc
+++ b/dune/copasi/model/multidomain_diffusion_reaction.cc
@@ -7,18 +7,18 @@
  * file but a header which has to be included when compiling.
  */
 
+#include <dune/copasi/common/muparser_data_handler.hh>
+#include <dune/copasi/model/multidomain_diffusion_reaction.hh>
+
 #include <dune/pdelab/common/functionutilities.hh>
 #include <dune/pdelab/gridfunctionspace/gridfunctionadapter.hh>
 
-#include <dune/copasi/model_multidomain_diffusion_reaction.hh>
-#include <dune/copasi/muparser_data_handler.hh>
-
 namespace Dune::Copasi {
 
 template<class Traits>
-ModelMultiDomainDiffusionReaction<Traits>::
-  ModelMultiDomainDiffusionReaction(std::shared_ptr<Grid> grid,
-                                    const Dune::ParameterTree& config)
+ModelMultiDomainDiffusionReaction<Traits>::ModelMultiDomainDiffusionReaction(
+  std::shared_ptr<Grid> grid,
+  const Dune::ParameterTree& config)
   : ModelBase(config)
   , _solver_logger(Logging::Logging::componentLogger(config, "solver"))
   , _config(config)
@@ -92,16 +92,14 @@ ModelMultiDomainDiffusionReaction<Traits>::
 }
 
 template<class Traits>
-ModelMultiDomainDiffusionReaction<Traits>::
-  ~ModelMultiDomainDiffusionReaction()
+ModelMultiDomainDiffusionReaction<Traits>::~ModelMultiDomainDiffusionReaction()
 {
   _logger.debug("ModelMultiDomainDiffusionReaction deconstructed"_fmt);
 }
 
 template<class Traits>
 void
-ModelMultiDomainDiffusionReaction<Traits>::
-  setup_grid_function_spaces()
+ModelMultiDomainDiffusionReaction<Traits>::setup_grid_function_spaces()
 {
   _logger.debug("setup grid function space"_fmt);
 
@@ -155,8 +153,7 @@ ModelMultiDomainDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelMultiDomainDiffusionReaction<Traits>::
-  setup_coefficient_vectors()
+ModelMultiDomainDiffusionReaction<Traits>::setup_coefficient_vectors()
 {
   for (auto& [op, state] : _states) {
     _logger.debug("setup coefficient vector for operator {}"_fmt, op);
@@ -171,8 +168,7 @@ ModelMultiDomainDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelMultiDomainDiffusionReaction<Traits>::
-  setup_constraints()
+ModelMultiDomainDiffusionReaction<Traits>::setup_constraints()
 {
   _logger.debug("setup constraints"_fmt);
 
@@ -198,8 +194,8 @@ ModelMultiDomainDiffusionReaction<Traits>::
 
 template<class Traits>
 auto
-ModelMultiDomainDiffusionReaction<Traits>::
-  setup_local_operator(std::size_t i) const
+ModelMultiDomainDiffusionReaction<Traits>::setup_local_operator(
+  std::size_t i) const
 {
   _logger.trace("setup local operators {}"_fmt, i);
 
@@ -218,8 +214,7 @@ ModelMultiDomainDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelMultiDomainDiffusionReaction<Traits>::
-  setup_local_operators()
+ModelMultiDomainDiffusionReaction<Traits>::setup_local_operators()
 {
   _logger.trace("setup local operators"_fmt);
 
@@ -235,8 +230,7 @@ ModelMultiDomainDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelMultiDomainDiffusionReaction<Traits>::
-  setup_grid_operators()
+ModelMultiDomainDiffusionReaction<Traits>::setup_grid_operators()
 {
   _logger.debug("setup grid operators"_fmt);
   _spatial_grid_operators.clear();
@@ -250,9 +244,9 @@ ModelMultiDomainDiffusionReaction<Traits>::
 
     std::size_t max_comps(0);
     for (std::size_t i = 0; i < gfs->degree(); i++)
-      max_comps = std::max(max_comps,gfs->child(i).degree());
+      max_comps = std::max(max_comps, gfs->child(i).degree());
 
-    MBE mbe((int)pow(3, dim)*max_comps);
+    MBE mbe((int)pow(3, dim) * max_comps);
 
     _logger.trace("create spatial grid operator {}"_fmt, op);
     _spatial_grid_operators[op] = std::make_shared<GOS>(
@@ -299,8 +293,7 @@ ModelMultiDomainDiffusionReaction<Traits>::setup_solvers()
 
 template<class Traits>
 void
-ModelMultiDomainDiffusionReaction<Traits>::
-  setup_vtk_writer()
+ModelMultiDomainDiffusionReaction<Traits>::setup_vtk_writer()
 {
   _logger.debug("setup vtk writer"_fmt);
   const auto& compartments = _config.sub("compartments").getValueKeys();
@@ -343,16 +336,14 @@ ModelMultiDomainDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelMultiDomainDiffusionReaction<Traits>::
-  suggest_timestep(double dt)
+ModelMultiDomainDiffusionReaction<Traits>::suggest_timestep(double dt)
 {
   DUNE_THROW(NotImplemented, "not implemented");
 }
 
 template<class Traits>
 void
-ModelMultiDomainDiffusionReaction<Traits>::setup(
-  ModelSetupPolicy setup_policy)
+ModelMultiDomainDiffusionReaction<Traits>::setup(ModelSetupPolicy setup_policy)
 {
   _logger.trace("setup operator started"_fmt);
 
@@ -445,8 +436,8 @@ ModelMultiDomainDiffusionReaction<Traits>::step()
 
 template<class Traits>
 auto
-ModelMultiDomainDiffusionReaction<Traits>::
-  get_data_handler(std::map<std::size_t, State> states) const
+ModelMultiDomainDiffusionReaction<Traits>::get_data_handler(
+  std::map<std::size_t, State> states) const
 {
   std::vector<std::map<std::size_t, std::shared_ptr<DataHandler>>> data(
     _domains);
@@ -469,18 +460,17 @@ ModelMultiDomainDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelMultiDomainDiffusionReaction<Traits>::
-  update_data_handler()
+ModelMultiDomainDiffusionReaction<Traits>::update_data_handler()
 {
   _data = get_data_handler(_states);
 }
 
 template<class Traits>
 auto
-ModelMultiDomainDiffusionReaction<Traits>::
-  get_grid_function(const std::map<std::size_t, State>& states,
-                    std::size_t domain,
-                    std::size_t comp) const
+ModelMultiDomainDiffusionReaction<Traits>::get_grid_function(
+  const std::map<std::size_t, State>& states,
+  std::size_t domain,
+  std::size_t comp) const
 {
   auto data = get_data_handler(states);
   const auto& compartments = _config.sub("compartments").getValueKeys();
@@ -503,8 +493,7 @@ ModelMultiDomainDiffusionReaction<Traits>::
 
 template<class Traits>
 void
-ModelMultiDomainDiffusionReaction<Traits>::write_states()
-  const
+ModelMultiDomainDiffusionReaction<Traits>::write_states() const
 {
 
   const auto& compartments = _config.sub("compartments").getValueKeys();
diff --git a/dune/copasi/model_multidomain_diffusion_reaction.hh b/dune/copasi/model/multidomain_diffusion_reaction.hh
similarity index 77%
rename from dune/copasi/model_multidomain_diffusion_reaction.hh
rename to dune/copasi/model/multidomain_diffusion_reaction.hh
index 7f2f47465242e711a7598f3ade64e9fc4acf7e81..e95fc71b8a4526d4f8413a879b48b588319354be 100644
--- a/dune/copasi/model_multidomain_diffusion_reaction.hh
+++ b/dune/copasi/model/multidomain_diffusion_reaction.hh
@@ -1,13 +1,13 @@
 #ifndef DUNE_COPASI_MODEL_MULTIDOMAIN_DIFFUSION_REACTION_HH
 #define DUNE_COPASI_MODEL_MULTIDOMAIN_DIFFUSION_REACTION_HH
 
+#include <dune/copasi/common/enum.hh>
 #include <dune/copasi/concepts/grid.hh>
-#include <dune/copasi/enum.hh>
-#include <dune/copasi/local_operator_multidomain.hh>
-#include <dune/copasi/model_base.hh>
-#include <dune/copasi/model_diffusion_reaction.cc>
-#include <dune/copasi/model_diffusion_reaction.hh>
-#include <dune/copasi/multidomain_entity_transformation.hh>
+#include <dune/copasi/grid/multidomain_entity_transformation.hh>
+#include <dune/copasi/model/base.hh>
+#include <dune/copasi/model/diffusion_reaction.cc>
+#include <dune/copasi/model/diffusion_reaction.hh>
+#include <dune/copasi/model/multidomain_local_operator.hh>
 
 #include <dune/pdelab/backend/istl.hh>
 #include <dune/pdelab/backend/istl/novlpistlsolverbackend.hh>
@@ -20,6 +20,14 @@
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      Traits for diffusion reaction models in multigrid domains
+ *
+ * @tparam     G         Grid
+ * @tparam     FEMorder  Order of the finite element method
+ * @tparam     OT        PDELab ordering tag
+ * @tparam     JM        Jacobian method
+ */
 template<class G,
          int FEMorder = 1,
          class OT = PDELab::EntityBlockedOrderingTag,
@@ -32,6 +40,11 @@ struct ModelMultiDomainDiffusionReactionTraits
   static constexpr JacobianMethod jacobian_method = JM;
 };
 
+/**
+ * @brief      Class for diffusion-reaction models in multigrid domains.
+ *
+ * @tparam     Traits  Class that define static policies on the model
+ */
 template<class Traits>
 class ModelMultiDomainDiffusionReaction : public ModelBase
 {
@@ -163,28 +176,44 @@ class ModelMultiDomainDiffusionReaction : public ModelBase
     DGFTreeLeafFunction<ComponentLFS, DataHandler, SubDomainGridView>;
 
 public:
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  grid    The grid
+   * @param[in]  config  The configuration
+   */
   ModelMultiDomainDiffusionReaction(std::shared_ptr<Grid> grid,
                                     const Dune::ParameterTree& config);
 
+  /**
+   * @brief      Destroys the object.
+   */
   ~ModelMultiDomainDiffusionReaction();
 
   /**
-   * @brief      Get the model state
+   * @brief      Get mutable model states
    *
-   * @return     Model state
+   * @return     Model states
    */
   std::map<std::size_t, State> states() { return _states; }
 
   /**
-   * @brief      Get the model state
+   * @brief      Get constat model states
    *
-   * @return     Model state
+   * @return     Constant model states
    */
   std::map<std::size_t, ConstState> const_states() const
   {
     return const_states(_states);
   }
 
+  /**
+   * @brief      Get constat model states
+   *
+   * @param[in]  states  A map to mutable states
+   *
+   * @return     Constant model states
+   */
   std::map<std::size_t, ConstState> const_states(
     const std::map<std::size_t, State>& states) const
   {
@@ -194,21 +223,44 @@ public:
   }
 
   /**
-   * @brief      Get the model state
+   * @brief      Get the model states
    *
-   * @return     Model state
+   * @return     Model states
    */
   std::map<std::size_t, ConstState> states() const { return const_states(); }
 
+  /**
+   * @brief      Setup function
+   * @details    This class sets up the model to have completely defined the
+   *             requested feature in the policy
+   *
+   * @param[in]  setup_policy  The setup policy
+   */
   void setup(ModelSetupPolicy setup_policy = ModelSetupPolicy::All);
 
+  /**
+   * @copydoc ModelBase::suggest_timestep
+   */
   void suggest_timestep(double dt) override;
 
+  /**
+   * @copydoc ModelBase::step
+   */
   void step() override;
 
-  auto get_grid_function(const std::map<std::size_t, State>&,
-                         std::size_t,
-                         std::size_t) const;
+  /**
+   * @brief      Gets a grid function for a given component and a sub domain.
+   * @todo       Make this function operate on constant states
+   *
+   * @param[in]  states  The model states
+   * @param[in]  domain  The domain
+   * @param[in]  comp    The component
+   *
+   * @return     The grid function.
+   */
+  auto get_grid_function(const std::map<std::size_t, State>& states,
+                         std::size_t domain,
+                         std::size_t comp) const;
 
 protected:
   void setup_grid_function_spaces();
diff --git a/dune/copasi/local_operator_multidomain.hh b/dune/copasi/model/multidomain_local_operator.hh
similarity index 80%
rename from dune/copasi/local_operator_multidomain.hh
rename to dune/copasi/model/multidomain_local_operator.hh
index 4f800788ee95d8da3d8dde9768bd4c1b02908f22..17208f68e3e61dc519deebe8bdad840fa9f373d4 100644
--- a/dune/copasi/local_operator_multidomain.hh
+++ b/dune/copasi/model/multidomain_local_operator.hh
@@ -1,9 +1,9 @@
 #ifndef DUNE_COPASI_LOCAL_OPERATOR_MULTIDOMAIN_DIFFUSION_REACTION_HH
 #define DUNE_COPASI_LOCAL_OPERATOR_MULTIDOMAIN_DIFFUSION_REACTION_HH
 
+#include <dune/copasi/common/enum.hh>
 #include <dune/copasi/concepts/grid.hh>
-#include <dune/copasi/enum.hh>
-#include <dune/copasi/local_operator.hh>
+#include <dune/copasi/model/local_operator.hh>
 
 #include <dune/pdelab/localoperator/numericaljacobian.hh>
 #include <dune/pdelab/localoperator/numericaljacobianapply.hh>
@@ -15,6 +15,24 @@
 
 namespace Dune::Copasi {
 
+/**
+ * @brief      This class describes a PDELab local operator for multi domain
+ *             diffusion reaction systems.
+ * @details    This class describre the operatrions for local integrals required
+ *             for diffusion reaction system. The operator is only valid for
+ *             entities contained in the grid. The local finite element is used
+ *             for caching shape function evaluations. The coefficient mapper is
+ *             the interface to fetch date from either local or external
+ *             coefficient vectors. And the jacobian method switches between
+ *             numerical and analytical jacobians. This local operator creates
+ *             internally an individual local operator for every subdomain in
+ *             the grid
+ *
+ * @tparam     Grid                The grid
+ * @tparam     LocalFiniteElement  Local Finite Element
+ * @tparam     CM                  Coefficient Mapper
+ * @tparam     JM                  Jacobian Method
+ */
 template<class Grid,
          class LocalFiniteElement,
          class CM = DefaultCoefficientMapper,
@@ -94,6 +112,14 @@ public:
   //! residual assembly flags
   static constexpr bool doAlphaSkeleton = true;
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  grid            The grid
+   * @param[in]  config          The configuration
+   * @param[in]  finite_element  The local finite element
+   * @param[in]  id_operator     The index of this operator
+   */
   LocalOperatorMultiDomainDiffusionReaction(
     std::shared_ptr<const Grid> grid,
     const ParameterTree& config,
@@ -146,6 +172,13 @@ public:
     }
   }
 
+  /**
+   * @brief      Updates the coefficient mapper with given states.
+   *
+   * @param[in]  states  A map from operator index to states
+   *
+   * @tparam     States  Map from index to states
+   */
   template<class States>
   void update(const States& states)
   {
@@ -153,7 +186,9 @@ public:
       _local_operator[i]->update(states);
   }
 
-  // define sparsity pattern of operator representation
+  /**
+   * @copydoc LocalOperatorDiffusionReaction::pattern_volume
+   */
   template<typename LFSU, typename LFSV, typename LocalPattern>
   void pattern_volume(const LFSU& lfsu,
                       const LFSV& lfsv,
@@ -164,6 +199,23 @@ public:
     }
   }
 
+  /**
+   * @brief      Pattern sckeleton
+   * @details    This method links degrees of freedom between trial and test
+   *             spaces at entities intersection taking into account the
+   *             structure of the reaction term
+   *
+   * @param[in]  lfsu_i        The inside trial local function space
+   * @param[in]  lfsv_i        The inside test local function space
+   * @param[in]  lfsu_o        The outside trial local function space
+   * @param[in]  lfsv_o        The outside test local function space
+   * @param      pattern_io    The inside-outside local pattern
+   * @param      pattern_oi    The outside-inside local pattern
+   *
+   * @tparam     LFSU          The trial local function space
+   * @tparam     LFSV          The test local function space
+   * @tparam     LocalPattern  The local pattern
+   */
   template<typename LFSU, typename LFSV, typename LocalPattern>
   void pattern_skeleton(const LFSU& lfsu_i,
                         const LFSV& lfsv_i,
@@ -235,6 +287,11 @@ public:
     }
   }
 
+  /**
+   * @brief      Sets the time.
+   *
+   * @param[in]  t     The new time
+   */
   void setTime(double t)
   {
     Dune::PDELab::InstationaryLocalOperatorDefaultMethods<double>::setTime(t);
@@ -242,6 +299,11 @@ public:
       lp->setTime(t);
   }
 
+  /**
+   * @copydoc LocalOperatorDiffusionReaction::jacobian_apply_volume
+   * @details    This particular operator does a jacobian apply volume for the
+   *             LocalOperatorDiffusionReaction corresponding to incoming entity
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void jacobian_apply_volume(const EG& eg,
                              const LFSU& lfsu,
@@ -262,7 +324,34 @@ public:
     }
   }
 
-  //! jacobian contribution of volume term
+  /**
+   * @copydoc LocalOperatorDiffusionReaction::jacobian_apply_volume
+   * @details    This particular operator does a jacobian apply volume for the
+   *             LocalOperatorDiffusionReaction corresponding to incoming entity
+   */
+  template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
+  void jacobian_apply_volume(const EG& eg,
+                             const LFSU& lfsu,
+                             const X& x,
+                             const LFSV& lfsv,
+                             R& r) const
+  {
+    for (std::size_t i = 0; i < _size; ++i) {
+      if (lfsu.child(i).size() > 0) {
+        const auto& sub_lfsu = lfsu.child(i);
+        const auto& sub_lfsv = lfsv.child(i);
+        if (sub_lfsu.size() == 0)
+          continue;
+        _local_operator[i]->jacobian_apply_volume(eg, sub_lfsu, x, sub_lfsv, r);
+      }
+    }
+  }
+
+  /**
+   * @copydoc LocalOperatorDiffusionReaction::jacobian_volume
+   * @details    This particular operator does a jacobian volume for the
+   *             LocalOperatorDiffusionReaction corresponding to incoming entity
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename M>
   void jacobian_volume(const EG& eg,
                        const LFSU& lfsu,
@@ -281,6 +370,11 @@ public:
     }
   }
 
+  /**
+   * @copydoc LocalOperatorDiffusionReaction::alpha_volume
+   * @details    This particular operator does a alpha volume for the
+   *             LocalOperatorDiffusionReaction corresponding to incoming entity
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void alpha_volume(const EG& eg,
                     const LFSU& lfsu,
@@ -300,26 +394,28 @@ public:
     }
   }
 
-  //! apply local jacobian of the volume term -> linear variant
-  template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
-  void jacobian_apply_volume(const EG& eg,
-                             const LFSU& lfsu,
-                             const X& x,
-                             const LFSV& lfsv,
-                             R& r) const
-  {
-    for (std::size_t i = 0; i < _size; ++i) {
-      if (lfsu.child(i).size() > 0) {
-        const auto& sub_lfsu = lfsu.child(i);
-        const auto& sub_lfsv = lfsv.child(i);
-        if (sub_lfsu.size() == 0)
-          continue;
-        _local_operator[i]->jacobian_apply_volume(eg, sub_lfsu, x, sub_lfsv, r);
-      }
-    }
-  }
-
-  // skeleton integral depending on test and ansatz functions
+  /**
+   * @brief      The skeleton integral
+   * @details    This integral is only performed at the interface between
+   *             different domains. Currently it has the form of
+   *             dichlet-dirichlet boundary condition between domains
+   *
+   * @param[in]  ig      The intersection
+   * @param[in]  lfsu_i  The inside trial local function space
+   * @param[in]  x_i     The inside local coefficient vector
+   * @param[in]  lfsv_i  The inside test local function space
+   * @param[in]  lfsu_o  The outside trial local function space
+   * @param[in]  x_o     The outside local coefficient vector
+   * @param[in]  lfsv_o  The outside test local function space
+   * @param      r_i     The inside residual vector
+   * @param      r_o     The outside residual vector
+   *
+   * @tparam     IG      The indersection
+   * @tparam     LFSU    The trial local function space
+   * @tparam     X       The local coefficient vector
+   * @tparam     LFSV    The test local function space
+   * @tparam     R       The residual vector
+   */
   template<typename IG, typename LFSU, typename X, typename LFSV, typename R>
   void alpha_skeleton(const IG& ig,
                       const LFSU& lfsu_i,
@@ -451,6 +547,28 @@ public:
     }
   }
 
+  /**
+   * @brief      The jacobian skeleton integral
+   * @copydetails alpha_skeleton
+   *
+   * @param[in]  ig      The intersection
+   * @param[in]  lfsu_i  The inside trial local function space
+   * @param[in]  x_i     The inside local coefficient vector
+   * @param[in]  lfsv_i  The inside test local function space
+   * @param[in]  lfsu_o  The outside trial local function space
+   * @param[in]  x_o     The outside local coefficient vector
+   * @param[in]  lfsv_o  The outside test local function space
+   * @param      mat_ii  The local inside-inside matrix
+   * @param      mat_io  The local inside-outside matrix
+   * @param      mat_oi  The local outside-inside matrix
+   * @param      mat_oo  The local outside-outside matrix
+   *
+   * @tparam     IG      The indersection
+   * @tparam     LFSU    The trial local function space
+   * @tparam     X       The local coefficient vector
+   * @tparam     LFSV    The test local function space
+   * @tparam     J       The local jacobian matrix
+   */
   template<typename IG, typename LFSU, typename X, typename LFSV, typename J>
   void jacobian_skeleton(const IG& ig,
                          const LFSU& lfsu_i,
@@ -640,52 +758,23 @@ public:
       }
     }
   }
-
-  template<typename IG, typename LFSU, typename X, typename LFSV, typename Y>
-  void jacobian_apply_skeleton(const IG& ig,
-                               const LFSU& lfsu_i,
-                               const X& x_i,
-                               const LFSV& lfsv_i,
-                               const LFSU& lfsu_o,
-                               const X& x_o,
-                               const LFSV& lfsv_o,
-                               Y& y_i,
-                               Y& y_o) const
-  {
-    if constexpr (JM == JacobianMethod::Numerical) {
-      PDELab::NumericalJacobianApplySkeleton<
-        LocalOperatorMultiDomainDiffusionReaction>::
-        jacobian_apply_skeleton(
-          ig, lfsu_i, x_i, lfsv_i, lfsu_o, x_o, lfsv_o, y_i, y_o);
-      return;
-    }
-    DUNE_THROW(NotImplemented, "Analytic jacobian is not implemented");
-  }
-
-  template<typename IG, typename LFSU, typename X, typename LFSV, typename Y>
-  void jacobian_apply_skeleton(const IG& ig,
-                               const LFSU& lfsu_i,
-                               const X& x_i,
-                               const X& z_i,
-                               const LFSV& lfsv_i,
-                               const LFSU& lfsu_o,
-                               const X& x_o,
-                               const X& z_o,
-                               const LFSV& lfsv_o,
-                               Y& y_i,
-                               Y& y_o) const
-  {
-    if constexpr (JM == JacobianMethod::Numerical) {
-      PDELab::NumericalJacobianApplySkeleton<
-        LocalOperatorMultiDomainDiffusionReaction>::
-        jacobian_apply_skeleton(
-          ig, lfsu_i, x_i, z_i, lfsv_i, lfsu_o, x_o, z_o, lfsv_o, y_i, y_o);
-      return;
-    }
-    DUNE_THROW(NotImplemented, "Analytic jacobian is not implemented");
-  }
 };
 
+/**
+ * @brief      This class describes a PDELab temporal local operator for multi
+ *             domain diffusion reaction systems.
+ * @details    This class describre the operatrions for local integrals required
+ *             for diffusion reaction system. The operator is only valid for
+ *             entities contained in the grid. The local finite element is used
+ *             for caching shape function evaluations.And the jacobian method
+ *             switches between numerical and analytical jacobians. This local
+ *             operator creates internally an individual local operator for
+ *             every subdomain in the grid
+ *
+ * @tparam     Grid                The grid
+ * @tparam     LocalFiniteElement  The local finite element
+ * @tparam     JM                  The jacobian method
+ */
 template<class Grid,
          class LocalFiniteElement,
          JacobianMethod JM = JacobianMethod::Analytical>
@@ -710,6 +799,14 @@ public:
   //! residual assembly flags
   static constexpr bool doAlphaVolume = true;
 
+  /**
+   * @brief      Constructs a new instance.
+   *
+   * @param[in]  grid            The grid
+   * @param[in]  config          The configuration
+   * @param[in]  finite_element  The local finite element
+   * @param[in]  id_operator     The index of this operator
+   */
   TemporalLocalOperatorMultiDomainDiffusionReaction(
     std::shared_ptr<const Grid> grid,
     const ParameterTree& config,
@@ -733,7 +830,9 @@ public:
     }
   }
 
-  // define sparsity pattern of operator representation
+  /**
+   * @copydoc TemporalLocalOperatorDiffusionReaction::pattern_volume
+   */
   template<typename LFSU, typename LFSV, typename LocalPattern>
   void pattern_volume(const LFSU& lfsu,
                       const LFSV& lfsv,
@@ -743,6 +842,9 @@ public:
       _local_operator[i]->pattern_volume(lfsu.child(i), lfsv.child(i), pattern);
   }
 
+  /**
+   * @copydoc LocalOperatorMultiDomainDiffusionReaction::alpha_volume
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void alpha_volume(const EG& eg,
                     const LFSU& lfsu,
@@ -761,6 +863,9 @@ public:
     }
   }
 
+  /**
+   * @copydoc LocalOperatorMultiDomainDiffusionReaction::jacobian_volume
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename Mat>
   void jacobian_volume(const EG& eg,
                        const LFSU& lfsu,
@@ -779,6 +884,9 @@ public:
     }
   }
 
+  /**
+   * @copydoc LocalOperatorMultiDomainDiffusionReaction::jacobian_apply_volume
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void jacobian_apply_volume(const EG& eg,
                              const LFSU& lfsu,
@@ -799,6 +907,9 @@ public:
     }
   }
 
+  /**
+   * @copydoc LocalOperatorMultiDomainDiffusionReaction::jacobian_apply_volume
+   */
   template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
   void jacobian_apply_volume(const EG& eg,
                              const LFSU& lfsu,
diff --git a/dune/copasi/model_state.hh b/dune/copasi/model/state.hh
similarity index 91%
rename from dune/copasi/model_state.hh
rename to dune/copasi/model/state.hh
index 94c3da8b71bcb9c46089b3c5dac6aa4968dfc1ee..131fca52099f4bb594c85e7ea471a3845d506fa7 100644
--- a/dune/copasi/model_state.hh
+++ b/dune/copasi/model/state.hh
@@ -7,9 +7,17 @@
 
 namespace Dune::Copasi {
 
+/// forward declaration of model state
 template<class G, class GFS, class X>
 struct ModelState;
 
+/**
+ * @brief      Constant model state container
+ *
+ * @tparam     G     Grid type
+ * @tparam     GFS   Grid function space type
+ * @tparam     X     Coefficients vector
+ */
 template<class G, class GFS, class X>
 struct ConstModelState
 {
diff --git a/dune/copasi/muparser_data_handler.hh b/dune/copasi/muparser_data_handler.hh
deleted file mode 100644
index 7f60f1d877ad79efd50022ab4554dc3c5e0cd141..0000000000000000000000000000000000000000
--- a/dune/copasi/muparser_data_handler.hh
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef DUNE_MUPARSER_DATA_HANDLER_HH
-#define DUNE_MUPARSER_DATA_HANDLER_HH
-
-#include <dune/common/hybridutilities.hh>
-#include <dune/common/parametertree.hh>
-
-#include <muParser.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace Dune::Copasi {
-
-// This is a trick to make happy muparser about static functions
-
-template<class T>
-struct MuParserDataHandler
-{
-  MuParserDataHandler() {}
-
-  ~MuParserDataHandler()
-  {
-    MuParserDataHandler<T>::_names.clear();
-    MuParserDataHandler<T>::_functions.clear();
-  }
-
-  template<int i>
-  static double function_wrapper(double x, double y)
-  {
-    assert(MuParserDataHandler<T>::_functions[i]);
-    return (*MuParserDataHandler<T>::_functions[i])(x, y);
-  }
-
-  void add_tiff_functions(const ParameterTree& data_config)
-  {
-    const auto& keys = data_config.getValueKeys();
-    for (std::size_t i = 0; i < keys.size(); i++) {
-      _names.push_back(keys[i]);
-      std::string filename = data_config[keys[i]];
-      _functions.push_back(std::make_shared<T>(filename));
-    }
-  }
-
-  template<std::size_t max_data = 100>
-  void set_functions(mu::Parser& parser)
-  {
-    auto indices = Dune::range(std::integral_constant<std::size_t, max_data>{});
-    Dune::Hybrid::forEach(indices, [&](auto i) {
-      if (i < _functions.size())
-        parser.DefineFun(_names[i], function_wrapper<i>);
-    });
-  }
-
-  static std::vector<std::string> _names;
-  static std::vector<std::shared_ptr<T>> _functions;
-};
-
-template<class T>
-std::vector<std::string> MuParserDataHandler<T>::_names = {};
-
-template<class T>
-std::vector<std::shared_ptr<T>> MuParserDataHandler<T>::_functions = {};
-
-} // namespace Dune::Copasi
-
-#endif // DUNE_MUPARSER_DATA_HANDLER_HH
\ No newline at end of file
diff --git a/dune/copasi/pdelab_callable_adapter.hh b/dune/copasi/pdelab_callable_adapter.hh
deleted file mode 100644
index e095af244207679336a86aa27f0fc028926a4e98..0000000000000000000000000000000000000000
--- a/dune/copasi/pdelab_callable_adapter.hh
+++ /dev/null
@@ -1,142 +0,0 @@
-#ifndef DUNE_COPASI_GRID_FUNCTION_CALLABLE_ADAPTER_HH
-#define DUNE_COPASI_GRID_FUNCTION_CALLABLE_ADAPTER_HH
-
-#include <dune/copasi/concepts/pdelab.hh>
-
-#include <dune/pdelab/common/function.hh>
-
-#include <dune/common/fvector.hh>
-#include <dune/common/typetraits.hh>
-
-#include <type_traits>
-#include <utility>
-
-namespace Dune::Copasi {
-
-namespace {
-// namespaces unique to this translation unit/file
-
-template<class GV, class R>
-class GridFunctionTraitsFromRange;
-
-template<class GV, class RF, int dim>
-class GridFunctionTraitsFromRange<GV, Dune::FieldVector<RF, dim>>
-  : public PDELab::GridFunctionTraits<GV, RF, dim, Dune::FieldVector<RF, dim>>
-{};
-
-template<class GV, class RF>
-class GridFunctionTraitsFromRange<GV, Dune::DynamicVector<RF>>
-  : public PDELab::GridFunctionTraits<GV, RF, -1, Dune::DynamicVector<RF>>
-{};
-
-} // namespace
-
-template<typename GV, typename R, typename F>
-class GlobalCallableToGridFunctionAdapter
-  : public Dune::PDELab::GridFunctionBase<
-      GridFunctionTraitsFromRange<GV, R>,
-      GlobalCallableToGridFunctionAdapter<GV, R, F>>
-{
-public:
-  typedef GridFunctionTraitsFromRange<GV, R> Traits;
-
-  //! construct from grid view
-  GlobalCallableToGridFunctionAdapter(const GV& grid_view, const F& callable)
-    : _gv(grid_view)
-    , _f(callable)
-  {}
-
-  //! get a reference to the grid view
-  inline const GV& getGridView() const { return _gv; }
-
-  //! evaluate extended function on element
-  inline void evaluate(const typename Traits::ElementType& e,
-                       const typename Traits::DomainType& xl,
-                       typename Traits::RangeType& y) const
-  {
-    typename Traits::DomainType xg = e.geometry().global(xl);
-    y = _f(xg);
-  }
-
-private:
-  GV _gv;
-  F _f;
-};
-
-template<typename GV, typename R, typename F>
-class LocalCallableToGridFunctionAdapter
-  : public Dune::PDELab::GridFunctionBase<
-      GridFunctionTraitsFromRange<GV, R>,
-      LocalCallableToGridFunctionAdapter<GV, R, F>>
-{
-public:
-  typedef GridFunctionTraitsFromRange<GV, R> Traits;
-
-  //! construct from grid view
-  LocalCallableToGridFunctionAdapter(const GV& grid_view, const F& callable)
-    : _gv(grid_view)
-    , _f(callable)
-  {}
-
-  //! get a reference to the grid view
-  inline const GV& getGridView() const { return _gv; }
-
-  //! evaluate extended function on element
-  inline void evaluate(const typename Traits::ElementType& e,
-                       const typename Traits::DomainType& xl,
-                       typename Traits::RangeType& y) const
-  {
-    y = _f(e, xl);
-  }
-
-private:
-  GV _gv;
-  F _f;
-};
-
-/** \brief Create PDELab GridFunction from a callable f(x) that expects a global
- * coordinate x */
-template<typename GV, typename F>
-auto
-makeGridFunctionFromCallable(const GV& gv, const F& f) ->
-  typename std::enable_if<
-    Concept::isPDELabGlobalCallable<GV, F>(),
-    GlobalCallableToGridFunctionAdapter<
-      GV,
-      decltype(f(std::declval<typename GV::template Codim<
-                   0>::Entity::Geometry::GlobalCoordinate>())),
-      F>>::type
-{
-  typedef typename GV::template Codim<0>::Entity::Geometry::GlobalCoordinate X;
-  X x;
-  typedef decltype(f(x)) Range;
-  typedef GlobalCallableToGridFunctionAdapter<GV, Range, F> TheType;
-  return TheType(gv, f);
-}
-
-/** \brief Create PDELab GridFunction from a callable f(e,x) that expects
-    an entity e and a local coordinate x */
-template<typename GV, typename F>
-auto
-makeGridFunctionFromCallable(const GV& gv, const F& f) ->
-  typename std::enable_if<
-    Concept::isPDELabLocalCallable<GV, F>(),
-    LocalCallableToGridFunctionAdapter<
-      GV,
-      decltype(f(std::declval<typename GV::template Codim<0>::Entity>(),
-                 std::declval<typename GV::template Codim<
-                   0>::Entity::Geometry::LocalCoordinate>())),
-      F>>::type
-{
-  typedef typename GV::template Codim<0>::Entity E;
-  E e;
-  typedef typename E::Geometry::LocalCoordinate X;
-  X x;
-  typedef decltype(f(e, x)) Range;
-  typedef LocalCallableToGridFunctionAdapter<GV, Range, F> TheType;
-  return TheType(gv, f);
-}
-
-} // namespace Dune::Copasi
-
-#endif // DUNE_COPASI_GRID_FUNCTION_CALLABLE_ADAPTER_HH
\ No newline at end of file
diff --git a/dune/copasi/tiff_grayscale.hh b/dune/copasi/tiff_grayscale.hh
deleted file mode 100644
index 63c2639dea5ecc2a052818848a5d74fdfb499917..0000000000000000000000000000000000000000
--- a/dune/copasi/tiff_grayscale.hh
+++ /dev/null
@@ -1,158 +0,0 @@
-#ifndef DUNE_COPASI_TIFF_GRAYSCALE_HH
-#define DUNE_COPASI_TIFF_GRAYSCALE_HH
-
-#include <dune/common/exceptions.hh>
-#include <dune/common/float_cmp.hh>
-
-#include <tiffio.h>
-
-#include <string>
-#include <queue>
-#include <memory>
-
-namespace Dune::Copasi {
-
-template<class T>
-class TIFFGrayscale
-{
-  static_assert(std::is_integral_v<T>, "T must be an integral type");
-  static_assert(std::is_unsigned_v<T>, "T must be an unsigned type");
-
-  struct TIFFGrayscaleRow
-  {
-    TIFFGrayscaleRow(TIFF* const tiff_file, const T& row, const short& col_size, const bool& zero)
-      : _row(row)
-      , _col_size(col_size)
-      , _zero(zero)
-    {
-      T* raw_buffer = (T*)_TIFFmalloc(TIFFScanlineSize(tiff_file));
-      auto deleter = [](auto& ptr){_TIFFfree(ptr);};
-      _tiff_buffer = std::shared_ptr<T>(raw_buffer, deleter);
-      TIFFReadScanline(tiff_file, _tiff_buffer.get(), _row);
-    }
-
-    double operator[](const T& col) const
-    {
-      assert((short)col < _col_size);
-      const T max = std::numeric_limits<T>::max();
-      T val = *(_tiff_buffer.get() + col);
-      val = _zero ? val : max-val; 
-      return (double)val/max;
-    }
-
-    std::size_t size() const { return static_cast<std::size_t>(_col_size); }
-    std::size_t row() const { return static_cast<std::size_t>(_row); }
-
-  private:
-    std::shared_ptr<T> _tiff_buffer;
-    const T _row;
-    const short _col_size;
-    const bool _zero;
-  };
-
-public:
-  TIFFGrayscale(const std::string& filename)
-    : _tiff_file(TIFFOpen(filename.c_str(), "r"))
-  {
-    if (not _tiff_file)
-      DUNE_THROW(IOError, "Error opening TIFF file '" << filename << "'.");
-
-    short photometric;
-    TIFFGetField(_tiff_file, TIFFTAG_PHOTOMETRIC, &photometric);
-    if ((photometric != PHOTOMETRIC_MINISWHITE) and
-        (photometric != PHOTOMETRIC_MINISBLACK))
-      DUNE_THROW(IOError,
-                 "TIFF file '" << filename << "' must be in grayscale.");
-    _zero = (bool)photometric;
-
-    short bits_per_sample;
-    TIFFGetField(_tiff_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
-
-    if (bits_per_sample != 8 * sizeof(T)) {
-      TIFFClose(_tiff_file);
-      DUNE_THROW(IOError,
-                 "TIFF file '" << filename
-                               << "' contains a non-readable grayscale field.");
-    }
-
-    TIFFGetField(_tiff_file, TIFFTAG_IMAGELENGTH, &_row_size);
-    TIFFGetField(_tiff_file, TIFFTAG_IMAGEWIDTH, &_col_size);
-    TIFFGetField(_tiff_file, TIFFTAG_XRESOLUTION, &_x_res);
-    TIFFGetField(_tiff_file, TIFFTAG_YRESOLUTION, &_y_res);
-    assert(FloatCmp::gt(_x_res, 0.f));
-    assert(FloatCmp::gt(_y_res, 0.f));
-    _x_off = _y_off = 0.;
-    TIFFGetField(_tiff_file, TIFFTAG_XPOSITION, &_x_off);
-    TIFFGetField(_tiff_file, TIFFTAG_YPOSITION, &_y_off);
-  }
-
-  ~TIFFGrayscale()
-  {
-    TIFFClose(_tiff_file);
-  }
-
-  // if rows are read concurrently, this object has to be copied
-  const TIFFGrayscaleRow& operator[](T row) const
-  {
-    assert((short)row < _row_size);
-    return cache(row);
-  }
-
-  template<class DF>
-  double operator()(const DF& x, const DF& y)
-  {
-    // here we assume TIFFTAG_RESOLUTIONUNIT has same units as the grid.
-    // since we never check grid units, we also do not check tiff units
-
-    // return 0 if not in the domain
-    if (FloatCmp::lt((float)x, _x_off) or FloatCmp::lt((float)y, _y_off)) 
-      return 0;
-
-    const T i = _x_res * (_x_off + x);
-    const T j = _row_size - _y_res * (_y_off + y) - 1;
-
-    // return 0 if not in the domain
-    if (i>=cols() or j>=rows()) 
-      return 0;
-    else
-      return (*this)[j][i];
-  }
-
-  std::size_t size() const { return cols(); }
-
-  std::size_t rows() const { return static_cast<std::size_t>(_row_size); }
-
-  std::size_t cols() const { return static_cast<std::size_t>(_col_size); }
-
-private:
-
-const TIFFGrayscaleRow& cache(T row) const
-{
-  auto it = _row_cache.rbegin();
-  while ((it != _row_cache.rend()) and (it->row() != row))
-    it++;
-  
-  if (it != _row_cache.rend())
-    return *it;
-  else
-    _row_cache.emplace_back(_tiff_file, row, _col_size, _zero);
-  
-  if (_row_cache.size() >= 8)
-    _row_cache.pop_front();
-
-  return *(_row_cache.rbegin());
-}
-
-private:
-  TIFF* _tiff_file;
-  mutable std::deque<TIFFGrayscaleRow> _row_cache;
-  short _row_size;
-  short _col_size;
-  float _x_res, _x_off;
-  float _y_res, _y_off;
-  bool _zero;
-};
-
-} // namespace Dune::Copasi
-
-#endif // DUNE_COPASI_TIFF_GRAYSCALE_HH
\ No newline at end of file
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 9825ccfd9e6ce151b73f72069f174a411d4d60ff..e5d249db320f93243105d2fd4a3b94abc20b8754 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -1,5 +1,5 @@
-add_library(dune_copasi_lib STATIC ../dune/copasi/model_base.cc
-                                   model_multidomain_diffusion_reaction.cc)
+add_library(dune_copasi_lib STATIC ../dune/copasi/model/base.cc
+                                   multidomain_diffusion_reaction.cc)
 
 target_link_libraries(dune_copasi_lib PUBLIC ${DUNE_LIBS} TIFF::TIFF muparser::muparser)
 
diff --git a/lib/model_multidomain_diffusion_reaction.cc b/lib/model_multidomain_diffusion_reaction.cc
deleted file mode 100644
index b3fb2ebe95460a926c50fae17b3d6c1f33e818d2..0000000000000000000000000000000000000000
--- a/lib/model_multidomain_diffusion_reaction.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <dune/copasi/model_multidomain_diffusion_reaction.hh>
-#include <dune/copasi/model_multidomain_diffusion_reaction.cc>
-
-#include <dune/grid/multidomaingrid.hh>
-
-#include <dune/grid/uggrid.hh>
-
-namespace Dune{
-namespace Copasi{
-
-constexpr int dim = 2;
-using HostGrid = Dune::UGGrid<dim>;
-using MDGTraits = Dune::mdgrid::DynamicSubDomainCountTraits<dim,1>;
-using Grid = Dune::mdgrid::MultiDomainGrid<HostGrid,MDGTraits>;
-
-using ModelTraits1 = Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid,1>;
-template class ModelMultiDomainDiffusionReaction<ModelTraits1>;
-
-using ModelTraits2 = Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid,2>;
-template class ModelMultiDomainDiffusionReaction<ModelTraits2>;
-
-using Ordering = Dune::PDELab::EntityBlockedOrderingTag;
-constexpr Dune::Copasi::JacobianMethod Jac = Dune::Copasi::JacobianMethod::Numerical;
-using ModelTraits1Num = Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid,1,Ordering,Jac>;
-template class ModelMultiDomainDiffusionReaction<ModelTraits1Num>;
-
-} // namespace Dorie
-} // namespace Dune
diff --git a/lib/multidomain_diffusion_reaction.cc b/lib/multidomain_diffusion_reaction.cc
new file mode 100644
index 0000000000000000000000000000000000000000..050efaf122f5eab0736059647af84a8a594a22c6
--- /dev/null
+++ b/lib/multidomain_diffusion_reaction.cc
@@ -0,0 +1,36 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <dune/copasi/model/multidomain_diffusion_reaction.cc>
+#include <dune/copasi/model/multidomain_diffusion_reaction.hh>
+
+#include <dune/grid/multidomaingrid.hh>
+
+#include <dune/grid/uggrid.hh>
+
+namespace Dune {
+namespace Copasi {
+
+constexpr int dim = 2;
+using HostGrid = Dune::UGGrid<dim>;
+using MDGTraits = Dune::mdgrid::DynamicSubDomainCountTraits<dim, 1>;
+using Grid = Dune::mdgrid::MultiDomainGrid<HostGrid, MDGTraits>;
+
+using ModelTraits1 =
+  Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid, 1>;
+template class ModelMultiDomainDiffusionReaction<ModelTraits1>;
+
+using ModelTraits2 =
+  Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid, 2>;
+template class ModelMultiDomainDiffusionReaction<ModelTraits2>;
+
+using Ordering = Dune::PDELab::EntityBlockedOrderingTag;
+constexpr Dune::Copasi::JacobianMethod Jac =
+  Dune::Copasi::JacobianMethod::Numerical;
+using ModelTraits1Num =
+  Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid, 1, Ordering, Jac>;
+template class ModelMultiDomainDiffusionReaction<ModelTraits1Num>;
+
+} // namespace Dorie
+} // namespace Dune
diff --git a/src/dune_copasi.cc b/src/dune_copasi.cc
index e8068f4d83188ec2750116d3d25573ad0ca4e2d4..e52e7327648e3e441bf5d7658db34591735f12b9 100644
--- a/src/dune_copasi.cc
+++ b/src/dune_copasi.cc
@@ -1,35 +1,36 @@
 #ifdef HAVE_CONFIG_H
-# include "config.h"
+#include "config.h"
 #endif
 
-#include <dune/copasi/gmsh_reader.hh>
-#include <dune/copasi/model_diffusion_reaction.hh>
-#include <dune/copasi/model_diffusion_reaction.cc>
-#include <dune/copasi/model_multidomain_diffusion_reaction.hh>
-#include <dune/copasi/enum.hh>
+#include <dune/copasi/common/enum.hh>
+#include <dune/copasi/grid/multidomain_gmsh_reader.hh>
+#include <dune/copasi/model/diffusion_reaction.cc>
+#include <dune/copasi/model/diffusion_reaction.hh>
+#include <dune/copasi/model/multidomain_diffusion_reaction.hh>
 
-#include <dune/grid/multidomaingrid.hh>
 #include <dune/grid/io/file/gmshreader.hh>
+#include <dune/grid/multidomaingrid.hh>
 
 #include <dune/logging/logging.hh>
 
 #include <dune/common/exceptions.hh>
+#include <dune/common/parallel/mpihelper.hh>
 #include <dune/common/parametertree.hh>
 #include <dune/common/parametertreeparser.hh>
-#include <dune/common/parallel/mpihelper.hh>
 
 #include <iostream>
 
-int main(int argc, char** argv)
+int
+main(int argc, char** argv)
 {
 
-  try{
+  try {
     // initialize mpi
     auto& mpi_helper = Dune::MPIHelper::instance(argc, argv);
     auto comm = mpi_helper.getCollectiveCommunication();
 
     // Read and parse ini file
-    if (argc!=2)
+    if (argc != 2)
       DUNE_THROW(Dune::IOError, "Wrong number of arguments");
     const std::string config_filename = argv[1];
 
@@ -38,7 +39,7 @@ int main(int argc, char** argv)
     ptreeparser.readINITree(config_filename, config);
 
     // initialize loggers
-    Dune::Logging::Logging::init(comm,config.sub("logging"));
+    Dune::Logging::Logging::init(comm, config.sub("logging"));
 
     using namespace Dune::Literals;
     auto log = Dune::Logging::Logging::logger(config);
@@ -47,49 +48,49 @@ int main(int argc, char** argv)
     // create a grid
     constexpr int dim = 2;
     using HostGrid = Dune::UGGrid<dim>;
-    using MDGTraits = Dune::mdgrid::DynamicSubDomainCountTraits<dim,1>;
-    using Grid = Dune::mdgrid::MultiDomainGrid<HostGrid,MDGTraits>;
+    using MDGTraits = Dune::mdgrid::DynamicSubDomainCountTraits<dim, 1>;
+    using Grid = Dune::mdgrid::MultiDomainGrid<HostGrid, MDGTraits>;
 
     auto& grid_config = config.sub("grid");
-    auto level = grid_config.get<int>("initial_level",0);
+    auto level = grid_config.get<int>("initial_level", 0);
 
     log.info("Creating a rectangular grid in {}D"_fmt, dim);
 
     auto grid_file = grid_config.get<std::string>("file");
 
-    auto [grid_ptr,host_grid_ptr] = Dune::Copasi::GmshReader<Grid>::read(grid_file,config);
+    auto [grid_ptr, host_grid_ptr] =
+      Dune::Copasi::MultiDomainGmshReader<Grid>::read(grid_file, config);
 
     log.debug("Applying global refinement of level: {}"_fmt, level);
     grid_ptr->globalRefine(level);
 
     auto& model_config = config.sub("model");
     int order = model_config.get<int>("order");
-    
-    if (order == 1)
-    {
+
+    if (order == 1) {
       constexpr int Order = 1;
-      using ModelTraits = Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid,Order>;
-      Dune::Copasi::ModelMultiDomainDiffusionReaction<ModelTraits> model(grid_ptr,model_config);
+      using ModelTraits =
+        Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid, Order>;
+      Dune::Copasi::ModelMultiDomainDiffusionReaction<ModelTraits> model(
+        grid_ptr, model_config);
       model.run();
-    } 
-    else if (order == 2)
-    {
+    } else if (order == 2) {
       constexpr int Order = 2;
-      using ModelTraits = Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid,Order>;
-      Dune::Copasi::ModelMultiDomainDiffusionReaction<ModelTraits> model(grid_ptr,model_config);
+      using ModelTraits =
+        Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid, Order>;
+      Dune::Copasi::ModelMultiDomainDiffusionReaction<ModelTraits> model(
+        grid_ptr, model_config);
       model.run();
-    } 
-    else
-    {
-      DUNE_THROW(Dune::IOError,"Finite element order " << order << " is not supported by dune-copasi");
+    } else {
+      DUNE_THROW(Dune::IOError,
+                 "Finite element order " << order
+                                         << " is not supported by dune-copasi");
     }
 
     return 0;
-  }
-  catch (Dune::Exception &e){
+  } catch (Dune::Exception& e) {
     std::cerr << "Dune reported error: " << e << std::endl;
-  }
-  catch (...){
+  } catch (...) {
     std::cerr << "Unknown exception thrown!" << std::endl;
   }
 }
diff --git a/test/test_concepts_grid.cc b/test/test_concepts_grid.cc
index f2e193ba8a3881c7b4009cc1a89348a02961f320..ad9f46d66b78282202d697aa1d076a1b3882f7e8 100644
--- a/test/test_concepts_grid.cc
+++ b/test/test_concepts_grid.cc
@@ -28,11 +28,14 @@ test_multidomaingrid()
 
   // check that it is a multidomain grid with its respective subdomain grids
   passed &= isGrid<Grid>();
-  if (not passed) DUNE_THROW(Dune::Exception, "");
+  if (not passed)
+    DUNE_THROW(Dune::Exception, "");
   passed &= isMultiDomainGrid<Grid>();
-  if (not passed) DUNE_THROW(Dune::Exception, "");
+  if (not passed)
+    DUNE_THROW(Dune::Exception, "");
   passed &= isSubDomainGrid<typename Grid::SubDomainGrid>();
-  if (not passed) DUNE_THROW(Dune::Exception, "");
+  if (not passed)
+    DUNE_THROW(Dune::Exception, "");
 
   if constexpr (i > 0)
     // test for nested multidomains
@@ -44,7 +47,7 @@ test_multidomaingrid()
 int
 main(int argc, char** argv)
 {
-  [[maybe_unused]]  auto& mpi_helper = Dune::MPIHelper::instance(argc, argv);
+  [[maybe_unused]] auto& mpi_helper = Dune::MPIHelper::instance(argc, argv);
 
   try {
     bool passed = true;
@@ -53,53 +56,73 @@ main(int argc, char** argv)
 
     // check grids yaspgrid dim 1
     passed &= isGrid<Dune::YaspGrid<1>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isMultiDomainGrid<Dune::YaspGrid<1>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isSubDomainGrid<Dune::YaspGrid<1>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= test_multidomaingrid<Dune::YaspGrid<1>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     // check grids yaspgrid dim 2
     passed &= isGrid<Dune::YaspGrid<2>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isMultiDomainGrid<Dune::YaspGrid<2>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isSubDomainGrid<Dune::YaspGrid<2>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= test_multidomaingrid<Dune::YaspGrid<2>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     // check grids yaspgrid dim 5
     passed &= isGrid<Dune::YaspGrid<5>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isMultiDomainGrid<Dune::YaspGrid<5>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isSubDomainGrid<Dune::YaspGrid<5>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= test_multidomaingrid<Dune::YaspGrid<5>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     // check grids uggrid dim 2
     passed &= isGrid<Dune::UGGrid<2>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isMultiDomainGrid<Dune::UGGrid<2>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isSubDomainGrid<Dune::UGGrid<2>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= test_multidomaingrid<Dune::UGGrid<2>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     // check grids uggrid dim 3
     passed &= isGrid<Dune::UGGrid<3>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isMultiDomainGrid<Dune::UGGrid<3>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isSubDomainGrid<Dune::UGGrid<3>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= test_multidomaingrid<Dune::UGGrid<3>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     return not passed;
   } catch (Dune::Exception& e) {
diff --git a/test/test_concepts_pdelab.cc b/test/test_concepts_pdelab.cc
index 394c7dbdcc7b93a62ca4042f9a99360ca9871e66..92ca4de05c32caec5619fb9e31442959fcbf5f27 100644
--- a/test/test_concepts_pdelab.cc
+++ b/test/test_concepts_pdelab.cc
@@ -9,8 +9,8 @@
 
 #include <dune/grid/yaspgrid.hh>
 
-#include <dune/common/math.hh>
 #include <dune/common/exceptions.hh>
+#include <dune/common/math.hh>
 
 #include <cassert>
 #include <complex>
@@ -47,18 +47,24 @@ main(int argc, char** argv)
 
     // check functions
     passed &= isPDELabFunction<F<double>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= isPDELabFunction<F<int>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= isPDELabFunction<F<std::complex<double>>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     passed &= not isPDELabFunction<double>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isPDELabFunction<int>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isPDELabFunction<std::complex<double>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     // we need a grid for the following checks
     int constexpr dimDomain = 3;
@@ -78,46 +84,58 @@ main(int argc, char** argv)
 
     using PDELabLocalCallable = decltype(pdelab_local_callable);
     passed &= isPDELabLocalCallable<GridView, PDELabLocalCallable>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= isPDELabCallable<GridView, PDELabLocalCallable>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     passed &= not isPDELabLocalCallable<GridView, F<double>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isPDELabLocalCallable<GridView, double>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     // check global callable
     auto pdelab_global_callable = [](const auto& x) { return x; };
 
     using PDELabGlobalCallable = decltype(pdelab_global_callable);
     passed &= isPDELabGlobalCallable<GridView, PDELabGlobalCallable>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= isPDELabCallable<GridView, PDELabGlobalCallable>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     passed &= not isPDELabGlobalCallable<GridView, F<double>>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isPDELabGlobalCallable<GridView, double>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     passed &= not isPDELabGlobalCallable<GridView, PDELabLocalCallable>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
     passed &= not isPDELabLocalCallable<GridView, PDELabGlobalCallable>();
-    if (not passed) DUNE_THROW(Dune::Exception, "");
+    if (not passed)
+      DUNE_THROW(Dune::Exception, "");
 
     // check grid function from the pdelab creator from callables
-    [[maybe_unused]] auto gf_from_local = Dune::PDELab::makeGridFunctionFromCallable(
-      grid_view, pdelab_local_callable);
-    [[maybe_unused]] auto gf_from_global = Dune::PDELab::makeGridFunctionFromCallable(
-      grid_view, pdelab_global_callable);
+    [[maybe_unused]] auto gf_from_local =
+      Dune::PDELab::makeGridFunctionFromCallable(grid_view,
+                                                 pdelab_local_callable);
+    [[maybe_unused]] auto gf_from_global =
+      Dune::PDELab::makeGridFunctionFromCallable(grid_view,
+                                                 pdelab_global_callable);
 
     // TODO: For some reason, they are not recoginized as grid functions
     // passed &= isPDELabGridFunction<decltype(gf_from_local)>();
     // if (not passed) DUNE_THROW(Dune::Exception, "");
     // passed &= isPDELabGridFunction<decltype(gf_from_global)>();
     // if (not passed) DUNE_THROW(Dune::Exception, "");
-    
+
     return not passed;
   } catch (Dune::Exception& e) {
     std::cerr << "Dune reported error: " << e << std::endl;
diff --git a/test/test_dynamic_local_finite_element.cc b/test/test_dynamic_local_finite_element.cc
index a78e47dcf1811eed4b18862d87d74edd8fa0a375..8553a7a8b48512d8dfcb645632b8581a372f72de 100644
--- a/test/test_dynamic_local_finite_element.cc
+++ b/test/test_dynamic_local_finite_element.cc
@@ -2,9 +2,9 @@
 #include "config.h"
 #endif
 
-#include <dune/copasi/dynamic_local_basis.hh>
-#include <dune/copasi/dynamic_local_coefficients.hh>
-#include <dune/copasi/dynamic_local_finite_element.hh>
+#include <dune/copasi/finite_element/dynamic_local_basis.hh>
+#include <dune/copasi/finite_element/dynamic_local_coefficients.hh>
+#include <dune/copasi/finite_element/dynamic_local_finite_element.hh>
 
 #include <dune/localfunctions/common/localkey.hh>
 #include <dune/localfunctions/lagrange.hh>
diff --git a/test/test_jacobian.cc b/test/test_jacobian.cc
index be667b3c6ebf518cf61e2944b86d6c7c4d1a282a..f40c1ba99db754e03466b1aebb9abc97222c2447 100644
--- a/test/test_jacobian.cc
+++ b/test/test_jacobian.cc
@@ -1,35 +1,36 @@
 #ifdef HAVE_CONFIG_H
-# include "config.h"
+#include "config.h"
 #endif
 
-#include <dune/copasi/gmsh_reader.hh>
-#include <dune/copasi/model_diffusion_reaction.hh>
-#include <dune/copasi/model_diffusion_reaction.cc>
-#include <dune/copasi/model_multidomain_diffusion_reaction.hh>
-#include <dune/copasi/enum.hh>
+#include <dune/copasi/common/enum.hh>
+#include <dune/copasi/grid/multidomain_gmsh_reader.hh>
+#include <dune/copasi/model/diffusion_reaction.cc>
+#include <dune/copasi/model/diffusion_reaction.hh>
+#include <dune/copasi/model/multidomain_diffusion_reaction.hh>
 
-#include <dune/grid/multidomaingrid.hh>
 #include <dune/grid/io/file/gmshreader.hh>
+#include <dune/grid/multidomaingrid.hh>
 
 #include <dune/logging/logging.hh>
 
 #include <dune/common/exceptions.hh>
+#include <dune/common/parallel/mpihelper.hh>
 #include <dune/common/parametertree.hh>
 #include <dune/common/parametertreeparser.hh>
-#include <dune/common/parallel/mpihelper.hh>
 
 #include <iostream>
 
-int main(int argc, char** argv)
+int
+main(int argc, char** argv)
 {
 
-  try{
+  try {
     // initialize mpi
     auto& mpi_helper = Dune::MPIHelper::instance(argc, argv);
     auto comm = mpi_helper.getCollectiveCommunication();
 
     // Read and parse ini file
-    if (argc!=2)
+    if (argc != 2)
       DUNE_THROW(Dune::IOError, "Wrong number of arguments");
     const std::string config_filename = argv[1];
 
@@ -38,7 +39,7 @@ int main(int argc, char** argv)
     ptreeparser.readINITree(config_filename, config);
 
     // initialize loggers
-    Dune::Logging::Logging::init(comm,config.sub("logging"));
+    Dune::Logging::Logging::init(comm, config.sub("logging"));
 
     using namespace Dune::Literals;
     auto log = Dune::Logging::Logging::logger(config);
@@ -47,17 +48,18 @@ int main(int argc, char** argv)
     // create a grid
     constexpr int dim = 2;
     using HostGrid = Dune::UGGrid<dim>;
-    using MDGTraits = Dune::mdgrid::DynamicSubDomainCountTraits<dim,1>;
-    using Grid = Dune::mdgrid::MultiDomainGrid<HostGrid,MDGTraits>;
+    using MDGTraits = Dune::mdgrid::DynamicSubDomainCountTraits<dim, 1>;
+    using Grid = Dune::mdgrid::MultiDomainGrid<HostGrid, MDGTraits>;
 
     auto& grid_config = config.sub("grid");
-    auto level = grid_config.get<int>("initial_level",0);
+    auto level = grid_config.get<int>("initial_level", 0);
 
     log.info("Creating a rectangular grid in {}D"_fmt, dim);
 
     auto grid_file = grid_config.get<std::string>("file");
 
-    auto [grid_ptr,host_grid_ptr] = Dune::Copasi::GmshReader<Grid>::read(grid_file,config);
+    auto [grid_ptr, host_grid_ptr] =
+      Dune::Copasi::MultiDomainGmshReader<Grid>::read(grid_file, config);
 
     log.debug("Applying global refinement of level: {}"_fmt, level);
     grid_ptr->globalRefine(level);
@@ -65,41 +67,41 @@ int main(int argc, char** argv)
     auto& model_config = config.sub("model");
     int order = model_config.get<int>("order");
     std::string jacobian = model_config.get<std::string>("jacobian_type");
-    
-    if (order == 1)
-    {
+
+    if (order == 1) {
       using Ordering = Dune::PDELab::EntityBlockedOrderingTag;
       constexpr int Order = 1;
-      if (jacobian == "analytical")
-      {
-        constexpr Dune::Copasi::JacobianMethod Jac = Dune::Copasi::JacobianMethod::Analytical;
-        using ModelTraits = Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid,Order,Ordering,Jac>;
-        Dune::Copasi::ModelMultiDomainDiffusionReaction<ModelTraits> model(grid_ptr,model_config);
+      if (jacobian == "analytical") {
+        constexpr Dune::Copasi::JacobianMethod Jac =
+          Dune::Copasi::JacobianMethod::Analytical;
+        using ModelTraits = Dune::Copasi::
+          ModelMultiDomainDiffusionReactionTraits<Grid, Order, Ordering, Jac>;
+        Dune::Copasi::ModelMultiDomainDiffusionReaction<ModelTraits> model(
+          grid_ptr, model_config);
         model.run();
-      }
-      else if (jacobian == "numerical")
-      {
-        constexpr Dune::Copasi::JacobianMethod Jac = Dune::Copasi::JacobianMethod::Numerical;
-        using ModelTraits = Dune::Copasi::ModelMultiDomainDiffusionReactionTraits<Grid,Order,Ordering,Jac>;
-        Dune::Copasi::ModelMultiDomainDiffusionReaction<ModelTraits> model(grid_ptr,model_config);
+      } else if (jacobian == "numerical") {
+        constexpr Dune::Copasi::JacobianMethod Jac =
+          Dune::Copasi::JacobianMethod::Numerical;
+        using ModelTraits = Dune::Copasi::
+          ModelMultiDomainDiffusionReactionTraits<Grid, Order, Ordering, Jac>;
+        Dune::Copasi::ModelMultiDomainDiffusionReaction<ModelTraits> model(
+          grid_ptr, model_config);
         model.run();
+      } else {
+        DUNE_THROW(Dune::IOError,
+                   "Jacobian type " << jacobian
+                                    << " is not supported by dune-copasi");
       }
-      else 
-      {
-        DUNE_THROW(Dune::IOError,"Jacobian type " << jacobian << " is not supported by dune-copasi");        
-      }
-    } 
-    else
-    {
-      DUNE_THROW(Dune::IOError,"Finite element order " << order << " is not supported by dune-copasi");
+    } else {
+      DUNE_THROW(Dune::IOError,
+                 "Finite element order " << order
+                                         << " is not supported by dune-copasi");
     }
 
     return 0;
-  }
-  catch (Dune::Exception &e){
+  } catch (Dune::Exception& e) {
     std::cerr << "Dune reported error: " << e << std::endl;
-  }
-  catch (...){
+  } catch (...) {
     std::cerr << "Unknown exception thrown!" << std::endl;
   }
 }
diff --git a/test/test_parameter_tree_check.cc b/test/test_parameter_tree_check.cc
new file mode 100644
index 0000000000000000000000000000000000000000..bd4c7f8d79b3df2bf2513e672d848e6616c594fd
--- /dev/null
+++ b/test/test_parameter_tree_check.cc
@@ -0,0 +1,72 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include <dune/copasi/parameter_tree_check.hh>
+
+#include <dune/common/exceptions.hh>
+#include <dune/common/parametertreeparser.hh>
+
+int
+main(int argc, char** argv)
+{
+  bool failed = false;
+
+  try {
+
+    Dune::ParameterTree param_a, param_b, param_c;
+
+    param_a["a"] = "1";
+    param_a["A.a"] = "11";
+    param_b["b"] = "2";
+    param_c["C.c.a"] = "333";
+
+    if (not Dune::Copasi::eq(param_a,param_a))
+      DUNE_THROW(Dune::RangeError,"eq operator is wrong");
+
+    if (Dune::Copasi::eq(param_a,param_b))
+      DUNE_THROW(Dune::RangeError,"eq operator is wrong");
+
+    Dune::Copasi::add(param_a,param_b);
+
+    param_b["a"] = "1";
+    if (Dune::Copasi::eq(param_a,param_b))
+      DUNE_THROW(Dune::RangeError,"eq operator is wrong");
+
+    param_b["A.a"] = "11";
+    if (not Dune::Copasi::eq(param_a,param_b))
+      DUNE_THROW(Dune::RangeError,"eq operator is wrong");
+
+    Dune::Copasi::diff(param_a,param_b);
+    if (not Dune::Copasi::eq(param_a,{}))
+      DUNE_THROW(Dune::RangeError,"diff operator is wrong");
+
+    Dune::ParameterTree param_c_copy(param_c);
+    Dune::Copasi::add(param_c,param_b);
+    Dune::Copasi::add(param_a,param_b);
+    Dune::Copasi::diff(param_c,param_a);
+
+    if (not Dune::Copasi::eq(param_c,param_c_copy))
+      DUNE_THROW(Dune::RangeError,"diff operator is wrong");
+
+    const std::string config_filename = argv[1];
+    Dune::ParameterTree config;
+    Dune::ParameterTreeParser ptreeparser;
+    ptreeparser.readINITree(config_filename, config);
+
+    auto config_model = Dune::Copasi::get_model(config);
+    std::cout << "*******************Valid configuration model*******************" << std::endl;
+    config_model.report();
+
+    std::cout << "***************************Diff***************************" << std::endl;
+    Dune::Copasi::diff(config,config_model);
+    config.report();
+
+    return failed;
+  } catch (Dune::Exception& e) {
+    std::cerr << "Dune reported error: " << e << std::endl;
+  } catch (...) {
+    std::cerr << "Unknown exception thrown!" << std::endl;
+  }
+}
diff --git a/test/test_tiff_grayscale.cc b/test/test_tiff_grayscale.cc
index 2dbd9fe5a30703be4bdca93a1a37a2035a8bab8e..c3e85243173f70f645f488ac34304807ba2e766c 100644
--- a/test/test_tiff_grayscale.cc
+++ b/test/test_tiff_grayscale.cc
@@ -2,7 +2,7 @@
 #include "config.h"
 #endif
 
-#include <dune/copasi/tiff_grayscale.hh>
+#include <dune/copasi/common/tiff_grayscale.hh>
 
 #include <dune/grid/yaspgrid.hh>