diff --git a/Applications/ApplicationsLib/ProjectData.cpp b/Applications/ApplicationsLib/ProjectData.cpp
index 60954b084caadd2969f0f314b7e9bba1f74c22de..a038048709e3d97481938d59a05ca7d014e48216 100644
--- a/Applications/ApplicationsLib/ProjectData.cpp
+++ b/Applications/ApplicationsLib/ProjectData.cpp
@@ -34,8 +34,8 @@
 
 #include "ProcessLib/UncoupledProcessesTimeLoop.h"
 
-#include "ProcessLib/GroundwaterFlow/CreateGroundwaterFlowProcess.h"
 #include "ProcessLib/ComponentTransport/CreateComponentTransportProcess.h"
+#include "ProcessLib/GroundwaterFlow/CreateGroundwaterFlowProcess.h"
 #include "ProcessLib/HT/CreateHTProcess.h"
 #include "ProcessLib/HeatConduction/CreateHeatConductionProcess.h"
 #include "ProcessLib/HydroMechanics/CreateHydroMechanicsProcess.h"
@@ -43,6 +43,7 @@
 #include "ProcessLib/LIE/SmallDeformation/CreateSmallDeformationProcess.h"
 #include "ProcessLib/LiquidFlow/CreateLiquidFlowProcess.h"
 #include "ProcessLib/PhaseField/CreatePhaseFieldProcess.h"
+#include "ProcessLib/RichardsComponentTransport/CreateRichardsComponentTransportProcess.h"
 #include "ProcessLib/RichardsFlow/CreateRichardsFlowProcess.h"
 #include "ProcessLib/SmallDeformation/CreateSmallDeformationProcess.h"
 #include "ProcessLib/TES/CreateTESProcess.h"
@@ -420,6 +421,14 @@ void ProjectData::parseProcesses(BaseLib::ConfigTree const& processes_config,
                     break;
             }
         }
+        else if (type == "RichardsComponentTransport")
+        {
+            process = ProcessLib::RichardsComponentTransport::
+                createRichardsComponentTransportProcess(
+                    *_mesh_vec[0], std::move(jacobian_assembler),
+                    _process_variables, _parameters, integration_order,
+                    process_config);
+        }
         else if (type == "SMALL_DEFORMATION")
         {
             switch (_mesh_vec[0]->getDimension())
diff --git a/ProcessLib/CMakeLists.txt b/ProcessLib/CMakeLists.txt
index aa8acef9f7287e25d49f6a699b533136a99b9d1b..5d0e0d3d03a805efb36f2c498edd2c2512f5db32 100644
--- a/ProcessLib/CMakeLists.txt
+++ b/ProcessLib/CMakeLists.txt
@@ -4,6 +4,7 @@ APPEND_SOURCE_FILES(SOURCES)
 APPEND_SOURCE_FILES(SOURCES BoundaryCondition)
 APPEND_SOURCE_FILES(SOURCES CalculateSurfaceFlux)
 APPEND_SOURCE_FILES(SOURCES ComponentTransport)
+APPEND_SOURCE_FILES(SOURCES RichardsComponentTransport)
 APPEND_SOURCE_FILES(SOURCES Deformation)
 APPEND_SOURCE_FILES(SOURCES GroundwaterFlow)
 APPEND_SOURCE_FILES(SOURCES HeatConduction)
diff --git a/ProcessLib/RichardsComponentTransport/CreatePorousMediaProperties.cpp b/ProcessLib/RichardsComponentTransport/CreatePorousMediaProperties.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fb65c752e570e541fde15b981ea2d1fa3c74490e
--- /dev/null
+++ b/ProcessLib/RichardsComponentTransport/CreatePorousMediaProperties.cpp
@@ -0,0 +1,89 @@
+/**
+ * \file
+ *
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#include "CreatePorousMediaProperties.h"
+
+#include "BaseLib/reorderVector.h"
+
+#include "MaterialLib/PorousMedium/Permeability/createPermeabilityModel.h"
+#include "MaterialLib/PorousMedium/Porosity/createPorosityModel.h"
+#include "MaterialLib/PorousMedium/Storage/createStorageModel.h"
+
+#include "MeshLib/Mesh.h"
+
+namespace ProcessLib
+{
+namespace RichardsComponentTransport
+{
+PorousMediaProperties createPorousMediaProperties(
+    MeshLib::Mesh& mesh, BaseLib::ConfigTree const& porous_medium_configs)
+{
+    DBUG("Create PorousMediaProperties.");
+
+    std::vector<Eigen::MatrixXd> intrinsic_permeability_models;
+    std::vector<std::unique_ptr<MaterialLib::PorousMedium::Porosity>>
+        porosity_models;
+    std::vector<std::unique_ptr<MaterialLib::PorousMedium::Storage>>
+        storage_models;
+
+    std::vector<int> mat_ids;
+    for (auto const& porous_medium_config :
+         //! \ogs_file_param{prj__processes__process__RichardsComponentTransport__porous_medium__porous_medium}
+         porous_medium_configs.getConfigSubtreeList("porous_medium"))
+    {
+         //! \ogs_file_attr{prj__processes__process__RichardsComponentTransport__porous_medium__porous_medium__id}
+        auto const id = porous_medium_config.getConfigAttribute<int>("id");
+        mat_ids.push_back(id);
+
+        auto const& porosity_config =
+            //! \ogs_file_param{prj__processes__process__RichardsComponentTransport__porous_medium__porous_medium__porosity}
+            porous_medium_config.getConfigSubtree("porosity");
+        porosity_models.emplace_back(
+            MaterialLib::PorousMedium::createPorosityModel(porosity_config));
+
+        // Configuration for the intrinsic permeability
+        auto const& permeability_config =
+            //! \ogs_file_param{prj__processes__process__RichardsComponentTransport__porous_medium__porous_medium__permeability}
+            porous_medium_config.getConfigSubtree("permeability");
+        intrinsic_permeability_models.emplace_back(
+            MaterialLib::PorousMedium::createPermeabilityModel(
+                permeability_config));
+
+        // Configuration for the specific storage.
+        auto const& storage_config =
+            //! \ogs_file_param{prj__processes__process__RichardsComponentTransport__porous_medium__porous_medium__storage}
+            porous_medium_config.getConfigSubtree("storage");
+        storage_models.emplace_back(
+            MaterialLib::PorousMedium::createStorageModel(storage_config));
+    }
+
+    BaseLib::reorderVector(intrinsic_permeability_models, mat_ids);
+    BaseLib::reorderVector(porosity_models, mat_ids);
+    BaseLib::reorderVector(storage_models, mat_ids);
+
+    std::vector<int> material_ids(mesh.getNumberOfElements());
+    if (mesh.getProperties().existsPropertyVector<int>("MaterialIDs"))
+    {
+        auto const& mesh_material_ids =
+            mesh.getProperties().getPropertyVector<int>("MaterialIDs");
+        material_ids.reserve(mesh_material_ids->size());
+        std::copy(mesh_material_ids->cbegin(), mesh_material_ids->cend(),
+                  material_ids.begin());
+    }
+
+    return PorousMediaProperties{std::move(porosity_models),
+                                 std::move(intrinsic_permeability_models),
+                                 std::move(storage_models),
+                                 std::move(material_ids)};
+}
+
+}  // namespace ComponentTransport
+}  // namespace ProcessLib
diff --git a/ProcessLib/RichardsComponentTransport/CreatePorousMediaProperties.h b/ProcessLib/RichardsComponentTransport/CreatePorousMediaProperties.h
new file mode 100644
index 0000000000000000000000000000000000000000..73e0ece1062340d303ccfb5839b813c8ebfe9e07
--- /dev/null
+++ b/ProcessLib/RichardsComponentTransport/CreatePorousMediaProperties.h
@@ -0,0 +1,29 @@
+/**
+ * \file
+ *
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#pragma once
+
+#include "BaseLib/ConfigTree.h"
+#include "PorousMediaProperties.h"
+
+namespace MeshLib
+{
+class Mesh;
+}
+
+namespace ProcessLib
+{
+namespace RichardsComponentTransport
+{
+PorousMediaProperties createPorousMediaProperties(
+    MeshLib::Mesh& mesh, BaseLib::ConfigTree const& porous_media_config);
+}
+}
diff --git a/ProcessLib/RichardsComponentTransport/CreateRichardsComponentTransportProcess.cpp b/ProcessLib/RichardsComponentTransport/CreateRichardsComponentTransportProcess.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..50a3377cd626089d55f2baebe075339a42309a3f
--- /dev/null
+++ b/ProcessLib/RichardsComponentTransport/CreateRichardsComponentTransportProcess.cpp
@@ -0,0 +1,153 @@
+/**
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#include "CreateRichardsComponentTransportProcess.h"
+
+#include "MaterialLib/Fluid/FluidProperties/CreateFluidProperties.h"
+
+#include "ProcessLib/Parameter/ConstantParameter.h"
+#include "ProcessLib/Utils/ParseSecondaryVariables.h"
+#include "ProcessLib/Utils/ProcessUtils.h"
+
+#include "CreatePorousMediaProperties.h"
+#include "RichardsComponentTransportProcess.h"
+#include "RichardsComponentTransportProcessData.h"
+
+namespace ProcessLib
+{
+namespace RichardsComponentTransport
+{
+std::unique_ptr<Process> createRichardsComponentTransportProcess(
+    MeshLib::Mesh& mesh,
+    std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler,
+    std::vector<ProcessVariable> const& variables,
+    std::vector<std::unique_ptr<ParameterBase>> const& parameters,
+    unsigned const integration_order,
+    BaseLib::ConfigTree const& config)
+{
+    //! \ogs_file_param{prj__processes__process__type}
+    config.checkConfigParameter("type", "RichardsComponentTransport");
+
+    DBUG("Create RichardsComponentTransportProcess.");
+
+    // Process variable.
+
+    //! \ogs_file_param{prj__processes__process__RichardsComponentTransport__process_variables}
+    auto const pv_config = config.getConfigSubtree("process_variables");
+
+    auto process_variables = findProcessVariables(
+        variables, pv_config,
+        {
+        //! \ogs_file_param_special{prj__processes__process__RichardsComponentTransport__process_variables__concentration}
+        "concentration",
+        //! \ogs_file_param_special{prj__processes__process__RichardsComponentTransport__process_variables__pressure}
+        "pressure"});
+
+    auto const& porous_medium_configs =
+        //! \ogs_file_param{prj__processes__process__RichardsComponentTransport__porous_medium}
+        config.getConfigSubtree("porous_medium");
+    PorousMediaProperties porous_media_properties{
+        createPorousMediaProperties(mesh, porous_medium_configs)};
+
+    //! \ogs_file_param{prj__processes__process__RichardsComponentTransport__fluid}
+    auto const& fluid_config = config.getConfigSubtree("fluid");
+
+    auto fluid_properties =
+        MaterialLib::Fluid::createFluidProperties(fluid_config);
+
+    // Parameter for the density of the fluid.
+    auto& fluid_reference_density= findParameter<double>(
+        config,
+        //! \ogs_file_param_special{prj__processes__process__RichardsComponentTransport__fluid_reference_density}
+        "fluid_reference_density", parameters, 1);
+    DBUG("Use \'%s\' as fluid_reference_density parameter.",
+         fluid_reference_density.name.c_str());
+
+    // Parameter for the longitudinal solute dispersivity.
+    auto const& molecular_diffusion_coefficient = findParameter<double>(
+        config,
+        //! \ogs_file_param_special{prj__processes__process__RichardsComponentTransport__molecular_diffusion_coefficient}
+        "molecular_diffusion_coefficient", parameters, 1);
+    DBUG("Use \'%s\' as molecular diffusion coefficient parameter.",
+         molecular_diffusion_coefficient.name.c_str());
+
+    // Parameter for the longitudinal solute dispersivity.
+    auto const& solute_dispersivity_longitudinal = findParameter<double>(
+        config,
+        //! \ogs_file_param_special{prj__processes__process__RichardsComponentTransport__solute_dispersivity_longitudinal}
+        "solute_dispersivity_longitudinal", parameters, 1);
+    DBUG("Use \'%s\' as longitudinal solute dispersivity parameter.",
+         solute_dispersivity_longitudinal.name.c_str());
+
+    // Parameter for the transverse solute dispersivity.
+    auto const& solute_dispersivity_transverse = findParameter<double>(
+        config,
+        //! \ogs_file_param_special{prj__processes__process__RichardsComponentTransport__solute_dispersivity_transverse}
+        "solute_dispersivity_transverse", parameters, 1);
+    DBUG("Use \'%s\' as transverse solute dispersivity parameter.",
+         solute_dispersivity_transverse.name.c_str());
+
+    // Parameter for the retardation factor.
+    auto const& retardation_factor = findParameter<double>(
+        config,
+        //! \ogs_file_param_special{prj__processes__process__RichardsComponentTransport__retardation_factor}
+        "retardation_factor", parameters, 1);
+
+    // Parameter for the decay rate.
+    auto const& decay_rate = findParameter<double>(
+        config,
+        //! \ogs_file_param_special{prj__processes__process__RichardsComponentTransport__decay_rate}
+        "decay_rate", parameters, 1);
+
+    // Specific body force parameter.
+    Eigen::VectorXd specific_body_force;
+    std::vector<double> const b =
+        //! \ogs_file_param{prj__processes__process__RichardsComponentTransport__specific_body_force}
+        config.getConfigParameter<std::vector<double>>("specific_body_force");
+    assert(b.size() > 0 && b.size() < 4);
+    if (b.size() < mesh.getDimension())
+        OGS_FATAL(
+            "specific body force (gravity vector) has %d components, mesh "
+            "dimension is %d",
+            b.size(), mesh.getDimension());
+    bool const has_gravity = MathLib::toVector(b).norm() > 0;
+    if (has_gravity)
+    {
+        specific_body_force.resize(b.size());
+        std::copy_n(b.data(), b.size(), specific_body_force.data());
+    }
+
+    RichardsComponentTransportProcessData process_data{
+        std::move(porous_media_properties),
+        fluid_reference_density,
+        std::move(fluid_properties),
+        molecular_diffusion_coefficient,
+        solute_dispersivity_longitudinal,
+        solute_dispersivity_transverse,
+        retardation_factor,
+        decay_rate,
+        specific_body_force,
+        has_gravity};
+
+    SecondaryVariableCollection secondary_variables;
+
+    NumLib::NamedFunctionCaller named_function_caller(
+        {"RichardsComponentTransport_concentration_pressure"});
+
+    ProcessLib::parseSecondaryVariables(config, secondary_variables,
+                                        named_function_caller);
+
+    return std::make_unique<RichardsComponentTransportProcess>(
+        mesh, std::move(jacobian_assembler), parameters, integration_order,
+        std::move(process_variables), std::move(process_data),
+        std::move(secondary_variables), std::move(named_function_caller));
+}
+
+}  // namespace RichardsComponentTransport
+}  // namespace ProcessLib
diff --git a/ProcessLib/RichardsComponentTransport/CreateRichardsComponentTransportProcess.h b/ProcessLib/RichardsComponentTransport/CreateRichardsComponentTransportProcess.h
new file mode 100644
index 0000000000000000000000000000000000000000..539b88eea044cd36b74b1d419e71e0d32b320bb7
--- /dev/null
+++ b/ProcessLib/RichardsComponentTransport/CreateRichardsComponentTransportProcess.h
@@ -0,0 +1,28 @@
+/**
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#pragma once
+
+#include <memory>
+#include "ProcessLib/Process.h"
+
+namespace ProcessLib
+{
+namespace RichardsComponentTransport
+{
+std::unique_ptr<Process> createRichardsComponentTransportProcess(
+    MeshLib::Mesh& mesh,
+    std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler,
+    std::vector<ProcessVariable> const& variables,
+    std::vector<std::unique_ptr<ParameterBase>> const& parameters,
+    unsigned const integration_order,
+    BaseLib::ConfigTree const& config);
+
+}  // namespace RichardsComponentTransport
+}  // namespace ProcessLib
diff --git a/ProcessLib/RichardsComponentTransport/PorousMediaProperties.cpp b/ProcessLib/RichardsComponentTransport/PorousMediaProperties.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c89ce7c999ee640201bff1271a45bfe28a9c8679
--- /dev/null
+++ b/ProcessLib/RichardsComponentTransport/PorousMediaProperties.cpp
@@ -0,0 +1,57 @@
+/**
+ * \file
+ *
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#include "PorousMediaProperties.h"
+
+namespace ProcessLib
+{
+namespace RichardsComponentTransport
+{
+int PorousMediaProperties::getMaterialID(SpatialPosition const& pos) const
+{
+    int const element_id = pos.getElementID().get();
+    return _material_ids[element_id];
+}
+
+MaterialLib::PorousMedium::Porosity const& PorousMediaProperties::getPorosity(
+    double /*t*/, SpatialPosition const& pos) const
+{
+    return *_porosity_models[getMaterialID(pos)];
+}
+
+Eigen::MatrixXd const& PorousMediaProperties::getIntrinsicPermeability(
+    double /*t*/, SpatialPosition const& pos) const
+{
+    return _intrinsic_permeability_models[getMaterialID(pos)];
+}
+
+MaterialLib::PorousMedium::Storage const&
+PorousMediaProperties::getSpecificStorage(double /*t*/,
+                                          SpatialPosition const& pos) const
+{
+    return *_specific_storage_models[getMaterialID(pos)];
+}
+
+MaterialLib::PorousMedium::CapillaryPressureSaturation const&
+PorousMediaProperties::getCapillaryPressureSaturationModel(
+    double /*t*/, SpatialPosition const& pos) const
+{
+    return *_capillary_pressure_saturation_models[getMaterialID(pos)];
+}
+
+MaterialLib::PorousMedium::RelativePermeability const&
+PorousMediaProperties::getRelativePermeability(
+    double /*t*/, SpatialPosition const& pos) const
+{
+    return *_relative_permeability_models[getMaterialID(pos)];
+}
+}
+}
diff --git a/ProcessLib/RichardsComponentTransport/PorousMediaProperties.h b/ProcessLib/RichardsComponentTransport/PorousMediaProperties.h
new file mode 100644
index 0000000000000000000000000000000000000000..12dd178163fb0fa5dc5a11e048548c9e59778308
--- /dev/null
+++ b/ProcessLib/RichardsComponentTransport/PorousMediaProperties.h
@@ -0,0 +1,77 @@
+/**
+ * \file
+ *
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+#include <Eigen/Dense>
+#include "BaseLib/reorderVector.h"
+
+
+#include "MaterialLib/PorousMedium/Porosity/Porosity.h"
+#include "MaterialLib/PorousMedium/Storage/Storage.h"
+
+#include "ProcessLib/Parameter/SpatialPosition.h"
+
+namespace ProcessLib
+{
+namespace RichardsComponentTransport
+{
+
+class PorousMediaProperties
+{
+public:
+    PorousMediaProperties(
+        std::vector<std::unique_ptr<MaterialLib::PorousMedium::Porosity>>&&
+            porosity_models,
+        std::vector<Eigen::MatrixXd>&& intrinsic_permeability_models,
+        std::vector<std::unique_ptr<MaterialLib::PorousMedium::Storage>>&&
+            specific_storage_models,
+        std::vector<int>&& material_ids)
+        : _porosity_models(std::move(porosity_models)),
+          _intrinsic_permeability_models(
+              std::move(intrinsic_permeability_models)),
+          _specific_storage_models(std::move(specific_storage_models)),
+          _material_ids(std::move(material_ids))
+    {
+    }
+
+    PorousMediaProperties(PorousMediaProperties&& other)
+        : _porosity_models(std::move(other._porosity_models)),
+          _intrinsic_permeability_models(other._intrinsic_permeability_models),
+          _specific_storage_models(std::move(other._specific_storage_models)),
+          _material_ids(other._material_ids)
+    {
+    }
+
+    MaterialLib::PorousMedium::Porosity const& getPorosity(
+        double t, SpatialPosition const& pos) const;
+
+    Eigen::MatrixXd const& getIntrinsicPermeability(
+        double t, SpatialPosition const& pos) const;
+
+    MaterialLib::PorousMedium::Storage const& getSpecificStorage(
+        double t, SpatialPosition const& pos) const;
+
+private:
+    int getMaterialID(SpatialPosition const& pos) const;
+private:
+    std::vector<std::unique_ptr<MaterialLib::PorousMedium::Porosity>>
+        _porosity_models;
+    std::vector<Eigen::MatrixXd> _intrinsic_permeability_models;
+    std::vector<std::unique_ptr<MaterialLib::PorousMedium::Storage>>
+        _specific_storage_models;
+    std::vector<int> _material_ids;
+};
+
+}
+}
diff --git a/ProcessLib/RichardsComponentTransport/RichardsComponentTransportFEM.h b/ProcessLib/RichardsComponentTransport/RichardsComponentTransportFEM.h
new file mode 100644
index 0000000000000000000000000000000000000000..c23ac9fb2c6f3d9d82c87f7349ea27a92f6eda47
--- /dev/null
+++ b/ProcessLib/RichardsComponentTransport/RichardsComponentTransportFEM.h
@@ -0,0 +1,379 @@
+/**
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#pragma once
+
+#include <Eigen/Dense>
+#include <vector>
+
+
+#include "RichardsComponentTransportProcessData.h"
+#include "MaterialLib/Fluid/FluidProperties/FluidProperties.h"
+#include "MathLib/LinAlg/Eigen/EigenMapTools.h"
+#include "NumLib/Extrapolation/ExtrapolatableElement.h"
+#include "NumLib/Fem/FiniteElement/TemplateIsoparametric.h"
+#include "NumLib/Fem/ShapeMatrixPolicy.h"
+#include "NumLib/Function/Interpolation.h"
+#include "ProcessLib/LocalAssemblerInterface.h"
+#include "ProcessLib/Parameter/Parameter.h"
+#include "ProcessLib/Utils/InitShapeMatrices.h"
+
+namespace ProcessLib
+{
+namespace RichardsComponentTransport
+{
+template <typename NodalRowVectorType, typename GlobalDimNodalMatrixType>
+struct IntegrationPointData final
+{
+    IntegrationPointData(NodalRowVectorType const& N_,
+                         GlobalDimNodalMatrixType const& dNdx_,
+                         double const& integration_weight_)
+        : N(N_), dNdx(dNdx_), integration_weight(integration_weight_)
+    {
+    }
+
+    NodalRowVectorType const N;
+    GlobalDimNodalMatrixType const dNdx;
+    double const integration_weight;
+
+    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
+};
+
+const unsigned NUM_NODAL_DOF = 2;
+
+class RichardsComponentTransportLocalAssemblerInterface
+    : public ProcessLib::LocalAssemblerInterface,
+      public NumLib::ExtrapolatableElement
+{
+public:
+    virtual std::vector<double> const& getIntPtDarcyVelocityX(
+        const double /*t*/,
+        GlobalVector const& /*current_solution*/,
+        NumLib::LocalToGlobalIndexMap const& /*dof_table*/,
+        std::vector<double>& /*cache*/) const = 0;
+
+    virtual std::vector<double> const& getIntPtDarcyVelocityY(
+        const double /*t*/,
+        GlobalVector const& /*current_solution*/,
+        NumLib::LocalToGlobalIndexMap const& /*dof_table*/,
+        std::vector<double>& /*cache*/) const = 0;
+
+    virtual std::vector<double> const& getIntPtDarcyVelocityZ(
+        const double /*t*/,
+        GlobalVector const& /*current_solution*/,
+        NumLib::LocalToGlobalIndexMap const& /*dof_table*/,
+        std::vector<double>& /*cache*/) const = 0;
+};
+
+template <typename ShapeFunction, typename IntegrationMethod,
+          unsigned GlobalDim>
+class LocalAssemblerData
+    : public RichardsComponentTransportLocalAssemblerInterface
+{
+    using ShapeMatricesType = ShapeMatrixPolicyType<ShapeFunction, GlobalDim>;
+    using ShapeMatrices = typename ShapeMatricesType::ShapeMatrices;
+
+    using LocalMatrixType = typename ShapeMatricesType::template MatrixType<
+        NUM_NODAL_DOF * ShapeFunction::NPOINTS,
+        NUM_NODAL_DOF * ShapeFunction::NPOINTS>;
+    using LocalVectorType =
+        typename ShapeMatricesType::template VectorType<NUM_NODAL_DOF *
+                                                        ShapeFunction::NPOINTS>;
+
+    using NodalVectorType = typename ShapeMatricesType::NodalVectorType;
+    using NodalRowVectorType = typename ShapeMatricesType::NodalRowVectorType;
+
+    using GlobalDimVectorType = typename ShapeMatricesType::GlobalDimVectorType;
+    using GlobalDimNodalMatrixType =
+        typename ShapeMatricesType::GlobalDimNodalMatrixType;
+    using GlobalDimMatrixType = typename ShapeMatricesType::GlobalDimMatrixType;
+
+public:
+    LocalAssemblerData(
+        MeshLib::Element const& element,
+        std::size_t const local_matrix_size,
+        bool is_axially_symmetric,
+        unsigned const integration_order,
+        RichardsComponentTransportProcessData const& process_data)
+        : _element(element),
+          _process_data(process_data),
+          _integration_method(integration_order),
+          _darcy_velocities(
+              GlobalDim,
+              std::vector<double>(_integration_method.getNumberOfPoints()))
+    {
+        // This assertion is valid only if all nodal d.o.f. use the same shape
+        // matrices.
+        assert(local_matrix_size == ShapeFunction::NPOINTS * NUM_NODAL_DOF);
+        (void)local_matrix_size;
+
+        unsigned const n_integration_points =
+            _integration_method.getNumberOfPoints();
+        _ip_data.reserve(n_integration_points);
+
+        auto const shape_matrices =
+            initShapeMatrices<ShapeFunction, ShapeMatricesType,
+                              IntegrationMethod, GlobalDim>(
+                element, is_axially_symmetric, _integration_method);
+
+        for (unsigned ip = 0; ip < n_integration_points; ip++)
+        {
+            _ip_data.emplace_back(
+                shape_matrices[ip].N, shape_matrices[ip].dNdx,
+                _integration_method.getWeightedPoint(ip).getWeight() *
+                    shape_matrices[ip].integralMeasure *
+                    shape_matrices[ip].detJ);
+        }
+    }
+
+    void assemble(double const t, std::vector<double> const& local_x,
+                  std::vector<double>& local_M_data,
+                  std::vector<double>& local_K_data,
+                  std::vector<double>& local_b_data) override
+    {
+        auto const local_matrix_size = local_x.size();
+        // This assertion is valid only if all nodal d.o.f. use the same shape
+        // matrices.
+        assert(local_matrix_size == ShapeFunction::NPOINTS * NUM_NODAL_DOF);
+
+        auto local_M = MathLib::createZeroedMatrix<LocalMatrixType>(
+            local_M_data, local_matrix_size, local_matrix_size);
+        auto local_K = MathLib::createZeroedMatrix<LocalMatrixType>(
+            local_K_data, local_matrix_size, local_matrix_size);
+        auto local_b = MathLib::createZeroedVector<LocalVectorType>(
+            local_b_data, local_matrix_size);
+
+        unsigned const n_integration_points =
+            _integration_method.getNumberOfPoints();
+
+        SpatialPosition pos;
+        pos.setElementID(_element.getID());
+
+        auto const num_nodes = ShapeFunction::NPOINTS;
+        auto p_nodal_values =
+            Eigen::Map<const NodalVectorType>(&local_x[num_nodes], num_nodes);
+
+        auto const& b = _process_data.specific_body_force;
+
+        MaterialLib::Fluid::FluidProperty::ArrayType vars;
+
+        GlobalDimMatrixType const& I(
+            GlobalDimMatrixType::Identity(GlobalDim, GlobalDim));
+
+        auto KCC = local_K.template block<num_nodes, num_nodes>(0, 0);
+        auto MCC = local_M.template block<num_nodes, num_nodes>(0, 0);
+        auto Kpp =
+            local_K.template block<num_nodes, num_nodes>(num_nodes, num_nodes);
+        auto Mpp =
+            local_M.template block<num_nodes, num_nodes>(num_nodes, num_nodes);
+        auto Bp = local_b.template block<num_nodes, 1>(num_nodes, 0);
+
+        for (std::size_t ip(0); ip < n_integration_points; ++ip)
+        {
+            pos.setIntegrationPoint(ip);
+
+            // \todo the argument to getValue() has to be changed for non
+            // constant storage model
+            auto const specific_storage =
+                _process_data.porous_media_properties.getSpecificStorage(t, pos)
+                    .getValue(0.0);
+
+            auto const& ip_data = _ip_data[ip];
+            auto const& N = ip_data.N;
+            auto const& dNdx = ip_data.dNdx;
+            auto const& w = ip_data.integration_weight;
+
+            double C_int_pt = 0.0;
+            double p_int_pt = 0.0;
+            // Order matters: First C, then p!
+            NumLib::shapeFunctionInterpolate(local_x, N, C_int_pt, p_int_pt);
+
+            // \todo the first argument has to be changed for non constant
+            // porosity model
+            auto const porosity =
+                _process_data.porous_media_properties.getPorosity(t, pos)
+                    .getValue(0.0, C_int_pt);
+
+            auto const retardation_factor =
+                _process_data.retardation_factor(t, pos)[0];
+
+            auto const& solute_dispersivity_transverse =
+                _process_data.solute_dispersivity_transverse(t, pos)[0];
+            auto const& solute_dispersivity_longitudinal =
+                _process_data.solute_dispersivity_longitudinal(t, pos)[0];
+
+            // Use the fluid density model to compute the density
+            vars[static_cast<int>(
+                MaterialLib::Fluid::PropertyVariableType::C)] = C_int_pt;
+            vars[static_cast<int>(
+                MaterialLib::Fluid::PropertyVariableType::p)] = p_int_pt;
+            auto const density = _process_data.fluid_properties->getValue(
+                MaterialLib::Fluid::FluidPropertyType::Density, vars);
+            auto const& decay_rate = _process_data.decay_rate(t, pos)[0];
+            auto const& molecular_diffusion_coefficient =
+                _process_data.molecular_diffusion_coefficient(t, pos)[0];
+
+            auto const& K =
+                _process_data.porous_media_properties.getIntrinsicPermeability(
+                    t, pos);
+            // Use the viscosity model to compute the viscosity
+            auto const mu = _process_data.fluid_properties->getValue(
+                MaterialLib::Fluid::FluidPropertyType::Viscosity, vars);
+
+            GlobalDimMatrixType const K_over_mu = K / mu;
+
+            GlobalDimVectorType const velocity =
+                _process_data.has_gravity
+                    ? GlobalDimVectorType(-K_over_mu *
+                                          (dNdx * p_nodal_values - density * b))
+                    : GlobalDimVectorType(-K_over_mu * dNdx * p_nodal_values);
+
+            double const velocity_magnitude = velocity.norm();
+            GlobalDimMatrixType const hydrodynamic_dispersion =
+                velocity_magnitude != 0.0
+                    ? GlobalDimMatrixType(
+                          (porosity * molecular_diffusion_coefficient +
+                           solute_dispersivity_transverse *
+                               velocity_magnitude) *
+                              I +
+                          (solute_dispersivity_longitudinal -
+                           solute_dispersivity_transverse) /
+                              velocity_magnitude * velocity *
+                              velocity.transpose())
+                    : GlobalDimMatrixType(
+                          (porosity * molecular_diffusion_coefficient +
+                           solute_dispersivity_transverse *
+                               velocity_magnitude) *
+                          I);
+
+            // matrix assembly
+            KCC.noalias() +=
+                (dNdx.transpose() * hydrodynamic_dispersion * dNdx +
+                 N.transpose() * velocity.transpose() * dNdx +
+                 N.transpose() * decay_rate * porosity * retardation_factor *
+                     N) *
+                w;
+            MCC.noalias() +=
+                w * N.transpose() * porosity * retardation_factor * N;
+            Kpp.noalias() += w * dNdx.transpose() * K_over_mu * dNdx;
+            Mpp.noalias() += w * N.transpose() * specific_storage * N;
+            if (_process_data.has_gravity)
+                Bp += w * density * dNdx.transpose() * K_over_mu * b;
+            /* with Oberbeck-Boussing assumption density difference only exists
+             * in buoyancy effects */
+        }
+    }
+
+    void computeSecondaryVariableConcrete(
+        double const t, std::vector<double> const& local_x) override
+    {
+        SpatialPosition pos;
+        pos.setElementID(_element.getID());
+
+        auto const& K =
+            _process_data.porous_media_properties.getIntrinsicPermeability(t,
+                                                                           pos);
+        MaterialLib::Fluid::FluidProperty::ArrayType vars;
+
+        auto const mu = _process_data.fluid_properties->getValue(
+            MaterialLib::Fluid::FluidPropertyType::Viscosity, vars);
+        GlobalDimMatrixType const K_over_mu = K / mu;
+
+        unsigned const n_integration_points =
+            _integration_method.getNumberOfPoints();
+
+        auto const p_nodal_values = Eigen::Map<const NodalVectorType>(
+            &local_x[ShapeFunction::NPOINTS], ShapeFunction::NPOINTS);
+
+        for (unsigned ip = 0; ip < n_integration_points; ++ip)
+        {
+            auto const& ip_data = _ip_data[ip];
+            auto const& N = ip_data.N;
+            auto const& dNdx = ip_data.dNdx;
+
+            GlobalDimVectorType velocity = -K_over_mu * dNdx * p_nodal_values;
+            if (_process_data.has_gravity)
+            {
+                double C_int_pt = 0.0;
+                double p_int_pt = 0.0;
+                NumLib::shapeFunctionInterpolate(local_x, N, C_int_pt,
+                                                 p_int_pt);
+                vars[static_cast<int>(
+                    MaterialLib::Fluid::PropertyVariableType::C)] = C_int_pt;
+                vars[static_cast<int>(
+                    MaterialLib::Fluid::PropertyVariableType::p)] = p_int_pt;
+
+                auto const rho_w = _process_data.fluid_properties->getValue(
+                    MaterialLib::Fluid::FluidPropertyType::Density, vars);
+                auto const b = _process_data.specific_body_force;
+                // here it is assumed that the vector b is directed 'downwards'
+                velocity += K_over_mu * rho_w * b;
+            }
+
+            for (unsigned d = 0; d < GlobalDim; ++d)
+            {
+                _darcy_velocities[d][ip] = velocity[d];
+            }
+        }
+    }
+
+    Eigen::Map<const Eigen::RowVectorXd> getShapeMatrix(
+        const unsigned integration_point) const override
+    {
+        auto const& N = _ip_data[integration_point].N;
+
+        // assumes N is stored contiguously in memory
+        return Eigen::Map<const Eigen::RowVectorXd>(N.data(), N.size());
+    }
+
+    std::vector<double> const& getIntPtDarcyVelocityX(
+        const double /*t*/,
+        GlobalVector const& /*current_solution*/,
+        NumLib::LocalToGlobalIndexMap const& /*dof_table*/,
+        std::vector<double>& /*cache*/) const override
+    {
+        assert(_darcy_velocities.size() > 0);
+        return _darcy_velocities[0];
+    }
+
+    std::vector<double> const& getIntPtDarcyVelocityY(
+        const double /*t*/,
+        GlobalVector const& /*current_solution*/,
+        NumLib::LocalToGlobalIndexMap const& /*dof_table*/,
+        std::vector<double>& /*cache*/) const override
+    {
+        assert(_darcy_velocities.size() > 1);
+        return _darcy_velocities[1];
+    }
+
+    std::vector<double> const& getIntPtDarcyVelocityZ(
+        const double /*t*/,
+        GlobalVector const& /*current_solution*/,
+        NumLib::LocalToGlobalIndexMap const& /*dof_table*/,
+        std::vector<double>& /*cache*/) const override
+    {
+        assert(_darcy_velocities.size() > 2);
+        return _darcy_velocities[2];
+    }
+
+private:
+    MeshLib::Element const& _element;
+    RichardsComponentTransportProcessData const& _process_data;
+
+    IntegrationMethod const _integration_method;
+    std::vector<
+        IntegrationPointData<NodalRowVectorType, GlobalDimNodalMatrixType>,
+        Eigen::aligned_allocator<
+            IntegrationPointData<NodalRowVectorType, GlobalDimNodalMatrixType>>>
+        _ip_data;
+    std::vector<std::vector<double>> _darcy_velocities;
+};
+
+}  // namespace RichardsComponentTransport
+}  // namespace ProcessLib
diff --git a/ProcessLib/RichardsComponentTransport/RichardsComponentTransportProcess.cpp b/ProcessLib/RichardsComponentTransport/RichardsComponentTransportProcess.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1310718ea9145adf891b4a2838c22727b22f117d
--- /dev/null
+++ b/ProcessLib/RichardsComponentTransport/RichardsComponentTransportProcess.cpp
@@ -0,0 +1,115 @@
+/**
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#include "RichardsComponentTransportProcess.h"
+
+#include <cassert>
+
+#include "ProcessLib/Utils/CreateLocalAssemblers.h"
+
+namespace ProcessLib
+{
+namespace RichardsComponentTransport
+{
+RichardsComponentTransportProcess::RichardsComponentTransportProcess(
+    MeshLib::Mesh& mesh,
+    std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler,
+    std::vector<std::unique_ptr<ParameterBase>> const& parameters,
+    unsigned const integration_order,
+    std::vector<std::reference_wrapper<ProcessVariable>>&& process_variables,
+    RichardsComponentTransportProcessData&& process_data,
+    SecondaryVariableCollection&& secondary_variables,
+    NumLib::NamedFunctionCaller&& named_function_caller)
+    : Process(mesh, std::move(jacobian_assembler), parameters,
+              integration_order, std::move(process_variables),
+              std::move(secondary_variables), std::move(named_function_caller)),
+      _process_data(std::move(process_data))
+{
+}
+
+void RichardsComponentTransportProcess::initializeConcreteProcess(
+    NumLib::LocalToGlobalIndexMap const& dof_table,
+    MeshLib::Mesh const& mesh,
+    unsigned const integration_order)
+{
+    ProcessLib::ProcessVariable const& pv = getProcessVariables()[0];
+    ProcessLib::createLocalAssemblers<LocalAssemblerData>(
+        mesh.getDimension(), mesh.getElements(), dof_table,
+        pv.getShapeFunctionOrder(), _local_assemblers,
+        mesh.isAxiallySymmetric(), integration_order, _process_data);
+
+    _secondary_variables.addSecondaryVariable(
+        "darcy_velocity_x",
+        makeExtrapolator(1, getExtrapolator(), _local_assemblers,
+                         &RichardsComponentTransportLocalAssemblerInterface::
+                             getIntPtDarcyVelocityX));
+
+    if (mesh.getDimension() > 1)
+    {
+        _secondary_variables.addSecondaryVariable(
+            "darcy_velocity_y",
+            makeExtrapolator(
+                1, getExtrapolator(), _local_assemblers,
+                &RichardsComponentTransportLocalAssemblerInterface::
+                    getIntPtDarcyVelocityY));
+    }
+    if (mesh.getDimension() > 2)
+    {
+        _secondary_variables.addSecondaryVariable(
+            "darcy_velocity_z",
+            makeExtrapolator(
+                1, getExtrapolator(), _local_assemblers,
+                &RichardsComponentTransportLocalAssemblerInterface::
+                    getIntPtDarcyVelocityZ));
+    }
+}
+
+void RichardsComponentTransportProcess::assembleConcreteProcess(
+    const double t,
+    GlobalVector const& x,
+    GlobalMatrix& M,
+    GlobalMatrix& K,
+    GlobalVector& b)
+{
+    DBUG("Assemble RichardsComponentTransportProcess.");
+
+    // Call global assembler for each local assembly item.
+    GlobalExecutor::executeMemberDereferenced(
+        _global_assembler, &VectorMatrixAssembler::assemble, _local_assemblers,
+        *_local_to_global_index_map, t, x, M, K, b, _coupling_term);
+}
+
+void RichardsComponentTransportProcess::assembleWithJacobianConcreteProcess(
+    const double t, GlobalVector const& x, GlobalVector const& xdot,
+    const double dxdot_dx, const double dx_dx, GlobalMatrix& M, GlobalMatrix& K,
+    GlobalVector& b, GlobalMatrix& Jac)
+{
+    DBUG("AssembleWithJacobian RichardsComponentTransportProcess.");
+
+    // Call global assembler for each local assembly item.
+    GlobalExecutor::executeMemberDereferenced(
+        _global_assembler, &VectorMatrixAssembler::assembleWithJacobian,
+        _local_assemblers, *_local_to_global_index_map, t, x, xdot, dxdot_dx,
+        dx_dx, M, K, b, Jac, _coupling_term);
+}
+
+void RichardsComponentTransportProcess::computeSecondaryVariableConcrete(
+    double const t, GlobalVector const& x,
+    StaggeredCouplingTerm const& coupling_term)
+{
+    DBUG("Compute the Darcy velocity for RichardsComponentTransportProcess.");
+    GlobalExecutor::executeMemberOnDereferenced(
+        &RichardsComponentTransportLocalAssemblerInterface::
+            computeSecondaryVariable,
+        _local_assemblers, *_local_to_global_index_map, t, x, coupling_term);
+}
+
+}  // namespace RichardsComponentTransport
+}  // namespace ProcessLib
+
diff --git a/ProcessLib/RichardsComponentTransport/RichardsComponentTransportProcess.h b/ProcessLib/RichardsComponentTransport/RichardsComponentTransportProcess.h
new file mode 100644
index 0000000000000000000000000000000000000000..d1967fea7d7869596b251c893f82a178c609854b
--- /dev/null
+++ b/ProcessLib/RichardsComponentTransport/RichardsComponentTransportProcess.h
@@ -0,0 +1,88 @@
+/**
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#pragma once
+
+#include "RichardsComponentTransportFEM.h"
+#include "RichardsComponentTransportProcessData.h"
+#include "NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator.h"
+#include "ProcessLib/Process.h"
+
+namespace ProcessLib
+{
+namespace RichardsComponentTransport
+{
+/**
+ * # RichardsComponentTransport process
+ *
+ * The implementation uses a monolithic approach, i.e., both processes
+ * are assembled within one global system of equations.
+ *
+ * ## Process Coupling
+ *
+ * The advective term of the concentration equation is given by the Richards
+ * flow process, i.e., the concentration distribution depends on
+ * darcy velocity of the Richards flow process. On the other hand the
+ * concentration dependencies of the viscosity and density in the groundwater
+ * flow couples the unsaturated H process to the C process.
+ *
+ * \note At the moment there is not any coupling by source or sink terms, i.e.,
+ * the coupling is implemented only by density changes due to concentration
+ * changes in the buoyance term in the groundwater flow. This coupling schema is
+ * referred to as the Boussinesq approximation.
+ * */
+class RichardsComponentTransportProcess final : public Process
+{
+public:
+    RichardsComponentTransportProcess(
+        MeshLib::Mesh& mesh,
+        std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&&
+            jacobian_assembler,
+        std::vector<std::unique_ptr<ParameterBase>> const& parameters,
+        unsigned const integration_order,
+        std::vector<std::reference_wrapper<ProcessVariable>>&&
+            process_variables,
+        RichardsComponentTransportProcessData&& process_data,
+        SecondaryVariableCollection&& secondary_variables,
+        NumLib::NamedFunctionCaller&& named_function_caller);
+
+    //! \name ODESystem interface
+    //! @{
+
+    bool isLinear() const override { return false; }
+    //! @}
+
+    void computeSecondaryVariableConcrete(
+        double const t, GlobalVector const& x,
+        StaggeredCouplingTerm const& coupling_term) override;
+
+private:
+    void initializeConcreteProcess(
+        NumLib::LocalToGlobalIndexMap const& dof_table,
+        MeshLib::Mesh const& mesh,
+        unsigned const integration_order) override;
+
+    void assembleConcreteProcess(const double t, GlobalVector const& x,
+                                 GlobalMatrix& M, GlobalMatrix& K,
+                                 GlobalVector& b) override;
+
+    void assembleWithJacobianConcreteProcess(
+        const double t, GlobalVector const& x, GlobalVector const& xdot,
+        const double dxdot_dx, const double dx_dx, GlobalMatrix& M,
+        GlobalMatrix& K, GlobalVector& b, GlobalMatrix& Jac) override;
+
+    RichardsComponentTransportProcessData _process_data;
+
+    std::vector<
+        std::unique_ptr<RichardsComponentTransportLocalAssemblerInterface>>
+        _local_assemblers;
+};
+
+}  // namespace RichardsComponentTransport
+}  // namespace ProcessLib
diff --git a/ProcessLib/RichardsComponentTransport/RichardsComponentTransportProcessData.h b/ProcessLib/RichardsComponentTransport/RichardsComponentTransportProcessData.h
new file mode 100644
index 0000000000000000000000000000000000000000..97c4c58a803b9714ecd38469f84cdf201a4036c8
--- /dev/null
+++ b/ProcessLib/RichardsComponentTransport/RichardsComponentTransportProcessData.h
@@ -0,0 +1,94 @@
+/**
+ * \copyright
+ * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "MaterialLib/Fluid/FluidProperties/FluidProperties.h"
+#include "MaterialLib/PorousMedium/Porosity/Porosity.h"
+#include "MaterialLib/PorousMedium/Storage/Storage.h"
+
+#include "PorousMediaProperties.h"
+
+namespace ProcessLib
+{
+template <typename ReturnType>
+struct Parameter;
+
+namespace RichardsComponentTransport
+{
+struct RichardsComponentTransportProcessData
+{
+    RichardsComponentTransportProcessData(
+        PorousMediaProperties&& porous_media_properties_,
+        ProcessLib::Parameter<double> const& fluid_reference_density_,
+        std::unique_ptr<MaterialLib::Fluid::FluidProperties>&&
+            fluid_properties_,
+        ProcessLib::Parameter<double> const& molecular_diffusion_coefficient_,
+        ProcessLib::Parameter<double> const& solute_dispersivity_longitudinal_,
+        ProcessLib::Parameter<double> const& solute_dispersivity_transverse_,
+        ProcessLib::Parameter<double> const& retardation_factor_,
+        ProcessLib::Parameter<double> const& decay_rate_,
+        Eigen::VectorXd const& specific_body_force_,
+        bool const has_gravity_)
+        : porous_media_properties(std::move(porous_media_properties_)),
+          fluid_reference_density(fluid_reference_density_),
+          fluid_properties(std::move(fluid_properties_)),
+          molecular_diffusion_coefficient(molecular_diffusion_coefficient_),
+          solute_dispersivity_longitudinal(solute_dispersivity_longitudinal_),
+          solute_dispersivity_transverse(solute_dispersivity_transverse_),
+          retardation_factor(retardation_factor_),
+          decay_rate(decay_rate_),
+          specific_body_force(specific_body_force_),
+          has_gravity(has_gravity_)
+    {
+    }
+
+    RichardsComponentTransportProcessData(
+        RichardsComponentTransportProcessData&& other)
+        : porous_media_properties(std::move(other.porous_media_properties)),
+          fluid_reference_density(other.fluid_reference_density),
+          fluid_properties(other.fluid_properties.release()),
+          molecular_diffusion_coefficient(
+              other.molecular_diffusion_coefficient),
+          solute_dispersivity_longitudinal(
+              other.solute_dispersivity_longitudinal),
+          solute_dispersivity_transverse(other.solute_dispersivity_transverse),
+          retardation_factor(other.retardation_factor),
+          decay_rate(other.decay_rate),
+          specific_body_force(other.specific_body_force),
+          has_gravity(other.has_gravity)
+    {
+    }
+
+    //! Copies are forbidden.
+    RichardsComponentTransportProcessData(
+        RichardsComponentTransportProcessData const&) = delete;
+
+    //! Assignments are not needed.
+    void operator=(RichardsComponentTransportProcessData const&) = delete;
+
+    //! Assignments are not needed.
+    void operator=(RichardsComponentTransportProcessData&&) = delete;
+
+    PorousMediaProperties porous_media_properties;
+    Parameter<double> const& fluid_reference_density;
+    std::unique_ptr<MaterialLib::Fluid::FluidProperties> fluid_properties;
+    Parameter<double> const& molecular_diffusion_coefficient;
+    Parameter<double> const& solute_dispersivity_longitudinal;
+    Parameter<double> const& solute_dispersivity_transverse;
+    Parameter<double> const& retardation_factor;
+    Parameter<double> const& decay_rate;
+    Eigen::VectorXd const specific_body_force;
+    bool const has_gravity;
+};
+
+}  // namespace RichardsComponentTransport
+}  // namespace ProcessLib