diff --git a/test/porousmediumflow/2pnc/implicit/fuelcellproblem.hh b/test/porousmediumflow/2pnc/implicit/fuelcellproblem.hh
index 18d6aaacee9b0b623ed71ef501fc373b46fd3a08..eb3ed5df471c3db7548685f64c5052ad4ac31711 100644
--- a/test/porousmediumflow/2pnc/implicit/fuelcellproblem.hh
+++ b/test/porousmediumflow/2pnc/implicit/fuelcellproblem.hh
@@ -24,9 +24,10 @@
 #ifndef DUMUX_FUELCELL_PROBLEM_HH
 #define DUMUX_FUELCELL_PROBLEM_HH
 
-#include <dumux/implicit/cellcentered/tpfa/properties.hh>
+#include <dumux/discretization/cellcentered/tpfa/properties.hh>
+#include <dumux/discretization/box/properties.hh>
 #include <dumux/porousmediumflow/2pnc/implicit/model.hh>
-#include <dumux/porousmediumflow/implicit/problem.hh>
+#include <dumux/porousmediumflow/problem.hh>
 #include <dumux/material/fluidsystems/h2on2o2.hh>
 #include <dumux/material/chemistry/electrochemistry/electrochemistry.hh>
 
@@ -75,14 +76,13 @@ SET_INT_PROP(FuelCellProblem, ReplaceCompEqIdx, 3);
  * <tt>./test_box2pnc</tt>
  */
 template <class TypeTag>
-class FuelCellProblem : public ImplicitPorousMediaProblem<TypeTag>
+class FuelCellProblem : public PorousMediumFlowProblem<TypeTag>
 {
-    using ParentType = ImplicitPorousMediaProblem<TypeTag>;
+    using ParentType = PorousMediumFlowProblem<TypeTag>;
 
     using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
     using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
     using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
-    using TimeManager = typename GET_PROP_TYPE(TypeTag, TimeManager);
     using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
     using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
     using Sources = typename GET_PROP_TYPE(TypeTag, NumEqVector);
@@ -90,9 +90,15 @@ class FuelCellProblem : public ImplicitPorousMediaProblem<TypeTag>
     using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
     using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
     using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
-    using VtkOutputModule = typename GET_PROP_TYPE(TypeTag, VtkOutputModule);
     using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
     using Element = typename GridView::template Codim<0>::Entity;
+    using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
+    using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
+    using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
+    using ElementSolutionVector = typename GET_PROP_TYPE(TypeTag, ElementSolutionVector);
+
+
+
 
     // Select the electrochemistry method
     using ElectroChemistry = typename Dumux::ElectroChemistry<TypeTag, ElectroChemistryModel::Ochs>;
@@ -124,7 +130,7 @@ class FuelCellProblem : public ImplicitPorousMediaProblem<TypeTag>
 
     static constexpr int dim = GridView::dimension;
     static constexpr int dimWorld = GridView::dimensionworld;
-    static constexpr bool isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox);
+    static constexpr bool isBox = GET_PROP_VALUE(TypeTag, DiscretizationMethod) == DiscretizationMethods::Box;
     using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
 
     enum { dofCodim = isBox ? dim : 0 };
@@ -135,20 +141,20 @@ public:
      * \param timeManager The time manager
      * \param gridView The grid view
      */
-    FuelCellProblem(TimeManager &timeManager, const GridView &gridView)
-    : ParentType(timeManager, gridView)
+    FuelCellProblem(std::shared_ptr<const FVGridGeometry> fvGridGeometry)
+    : ParentType(fvGridGeometry)
     {
-        nTemperature_       = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, FluidSystem, NTemperature);
-        nPressure_          = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, FluidSystem, NPressure);
-        pressureLow_        = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, FluidSystem, PressureLow);
-        pressureHigh_       = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, FluidSystem, PressureHigh);
-        temperatureLow_     = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, FluidSystem, TemperatureLow);
-        temperatureHigh_    = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, FluidSystem, TemperatureHigh);
-        temperature_        = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, FluidSystem, InitialTemperature);
+        nTemperature_       = getParam<int>("Problem.NTemperature");
+        nPressure_          = getParam<int>("Problem.NPressure");
+        pressureLow_        = getParam<Scalar>("Problem.PressureLow");
+        pressureHigh_       = getParam<Scalar>("Problem.PressureHigh");
+        temperatureLow_     = getParam<Scalar>("Problem.TemperatureLow");
+        temperatureHigh_    = getParam<Scalar>("Problem.TemperatureHigh");
+        temperature_        = getParam<Scalar>("Problem.InitialTemperature");
 
-        name_               = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name);
+        name_               = getParam<std::string>("Problem.Name");
 
-        pO2Inlet_            = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, ElectroChemistry, pO2Inlet);
+        pO2Inlet_           = getParam<Scalar>("ElectroChemistry.pO2Inlet");
 
         FluidSystem::init(/*Tmin=*/temperatureLow_,
                           /*Tmax=*/temperatureHigh_,
@@ -156,6 +162,10 @@ public:
                           /*pmin=*/pressureLow_,
                           /*pmax=*/pressureHigh_,
                           /*np=*/nPressure_);
+
+        currentDensity_.resize(fvGridGeometry->gridView().size(dofCodim));
+        reactionSourceH2O_.resize(fvGridGeometry->gridView().size(dofCodim));
+        reactionSourceO2_.resize(fvGridGeometry->gridView().size(dofCodim));
     }
 
     /*!
@@ -259,50 +269,63 @@ public:
     /*!
      * \brief Adds additional VTK output data to the VTKWriter. Function is called by the output module on every write.
      */
-    void addVtkOutputFields(VtkOutputModule& outputModule) const
+    const std::vector<Scalar>& getCurrentDensity()
     {
-        // create the required scalar fields
-        auto& currentDensity = outputModule.createScalarField("currentDensity [A/cm^2]", dofCodim);
-        auto& reactionSourceH2O = outputModule.createScalarField("reactionSourceH2O [mol/(sm^2)]", dofCodim);
-        auto& reactionSourceO2 = outputModule.createScalarField("reactionSourceO2 [mol/(sm^2)]", dofCodim);
+        return currentDensity_;
+    }
 
-        for (const auto& element : elements(this->gridView()))
+    const std::vector<Scalar>& getReactionSourceH2O()
+    {
+        return reactionSourceH2O_;
+    }
+
+    const std::vector<Scalar>& getReactionSourceO2()
+    {
+        return reactionSourceO2_;
+    }
+
+
+    void updateVtkOutput(const SolutionVector& curSol)
+    {
+        for (const auto& element : elements(this->fvGridGeometry().gridView()))
         {
-            auto fvGeometry = localView(this->model().fvGridGeometry());
-            fvGeometry.bindElement(element);
+            ElementSolutionVector elemSol(element, curSol, this->fvGridGeometry());
 
-            auto elemVolVars = localView(this->model().curGlobalVolVars());
-            elemVolVars.bindElement(element, fvGeometry, this->model().curSol());
+            auto fvGeometry = localView(this->fvGridGeometry());
+            fvGeometry.bindElement(element);
 
             for (auto&& scv : scvs(fvGeometry))
             {
+                VolumeVariables volVars;
+                volVars.update(elemSol, *this, element, scv);
                 const auto& globalPos = scv.dofPosition();
                 const auto dofIdxGlobal = scv.dofIndex();
 
-                //reaction sources from electro chemistry
                 if(inReactionLayer_(globalPos))
                 {
                     //reactionSource Output
                     PrimaryVariables source;
-                    auto i = ElectroChemistry::calculateCurrentDensity(elemVolVars[scv]);
+                    auto i = ElectroChemistry::calculateCurrentDensity(volVars);
                     ElectroChemistry::reactionSource(source, i);
 
-                    reactionSourceH2O[dofIdxGlobal] = source[wPhaseIdx];
-                    reactionSourceO2[dofIdxGlobal] = source[numComponents-1];
+                    reactionSourceH2O_[dofIdxGlobal] = source[wPhaseIdx];
+                    reactionSourceO2_[dofIdxGlobal] = source[numComponents-1];
 
                     //Current Output in A/cm^2
-                    currentDensity[dofIdxGlobal] = i/10000;
+                    currentDensity_[dofIdxGlobal] = i/10000;
                 }
                 else
                 {
-                    reactionSourceH2O[dofIdxGlobal] = 0.0;
-                    reactionSourceO2[dofIdxGlobal] = 0.0;
-                    currentDensity[dofIdxGlobal] = 0.0;
+                    reactionSourceH2O_[dofIdxGlobal] = 0.0;
+                    reactionSourceO2_[dofIdxGlobal] = 0.0;
+                    currentDensity_[dofIdxGlobal] = 0.0;
                 }
             }
         }
     }
 
+
+
 private:
 
     PrimaryVariables initial_(const GlobalPosition &globalPos) const
@@ -319,19 +342,19 @@ private:
     }
 
     bool onLeftBoundary_(const GlobalPosition &globalPos) const
-    { return globalPos[0] < this->bBoxMin()[0] + eps_; }
+    { return globalPos[0] < this->fvGridGeometry().bBoxMin()[0] + eps_; }
 
     bool onRightBoundary_(const GlobalPosition &globalPos) const
-    { return globalPos[0] > this->bBoxMax()[0] - eps_; }
+    { return globalPos[0] > this->fvGridGeometry().bBoxMax()[0] - eps_; }
 
     bool onLowerBoundary_(const GlobalPosition &globalPos) const
-    { return globalPos[1] < this->bBoxMin()[1] + eps_; }
+    { return globalPos[1] < this->fvGridGeometry().bBoxMin()[1] + eps_; }
 
     bool onUpperBoundary_(const GlobalPosition &globalPos) const
-    { return globalPos[1] > this->bBoxMax()[1] - eps_; }
+    { return globalPos[1] > this->fvGridGeometry().bBoxMax()[1] - eps_; }
 
     bool inReactionLayer_(const GlobalPosition& globalPos) const
-    { return globalPos[1] < 0.1*(this->bBoxMax()[1] - this->bBoxMin()[1]) + eps_; }
+    { return globalPos[1] < 0.1*(this->fvGridGeometry().bBoxMax()[1] - this->fvGridGeometry().bBoxMin()[1]) + eps_; }
 
     Scalar temperature_;
     static constexpr Scalar eps_ = 1e-6;
@@ -341,6 +364,9 @@ private:
     Scalar pressureLow_, pressureHigh_;
     Scalar temperatureLow_, temperatureHigh_;
     Scalar pO2Inlet_;
+    std::vector<double> currentDensity_;
+    std::vector<double> reactionSourceH2O_;
+    std::vector<double> reactionSourceO2_;
 };
 
 } //end namespace Dumux
diff --git a/test/porousmediumflow/2pnc/implicit/fuelcellspatialparams.hh b/test/porousmediumflow/2pnc/implicit/fuelcellspatialparams.hh
index 6d591fb9eeaaf1d6bf4ad08a689c83ef9f185e80..255da0f8e9f99d4b2690f5eeb418e77789cc1a3c 100644
--- a/test/porousmediumflow/2pnc/implicit/fuelcellspatialparams.hh
+++ b/test/porousmediumflow/2pnc/implicit/fuelcellspatialparams.hh
@@ -100,8 +100,8 @@ public:
      *
      * \param gridView The grid view
      */
-    FuelCellSpatialParams(const Problem& problem, const GridView &gridView)
-    : ParentType(problem, gridView), K_(0)
+    FuelCellSpatialParams(const Problem& problem)
+    : ParentType(problem), K_(0)
     {
         // intrinsic permeabilities
         K_[0][0] = 5e-11;
diff --git a/test/porousmediumflow/2pnc/implicit/test_2pnc.input b/test/porousmediumflow/2pnc/implicit/test_2pnc.input
index 387623cb1d62bba07a7e304ccc3990fea777b79d..00a7b1890c9fda8fde2c5589d4b36eacb3520c56 100644
--- a/test/porousmediumflow/2pnc/implicit/test_2pnc.input
+++ b/test/porousmediumflow/2pnc/implicit/test_2pnc.input
@@ -2,7 +2,7 @@
 # Everything behind a '#' is a comment.
 # Type "./test_2pnc --help" for more information.
 
-[TimeManager]
+[TimeLoop]
 DtInitial = 5e-1                 # [s] initial time step size
 MaxTimeStepSize = 1000           # [s] maximum time step size
 TEnd= 1e3                        # [s] duration of the simulation
@@ -14,8 +14,6 @@ Cells = 21 6                # [-] number of cells in x,y-direction
 [Problem]
 Name = fuelcell
 EnableGravity = 0
-
-[FluidSystem]
 NTemperature = 3                # [-] number of temperature table entries
 NPressure = 200                 # [-] number of pressure table entries
 PressureLow = 1e5               # [Pa] lower pressure limit for tabularization
diff --git a/test/porousmediumflow/2pnc/implicit/test_box2pnc.cc b/test/porousmediumflow/2pnc/implicit/test_box2pnc.cc
index 826b60d1217f7d77df8b232f592eea3ae4c2cc77..2a77047cfd1e4b2bf7e278425b3ae0d734176a9e 100644
--- a/test/porousmediumflow/2pnc/implicit/test_box2pnc.cc
+++ b/test/porousmediumflow/2pnc/implicit/test_box2pnc.cc
@@ -22,8 +22,34 @@
  * \brief Test for the 2pnc box model used for water management in PEM fuel cells.
  */
 #include <config.h>
+
+#include <ctime>
+#include <iostream>
+
+#include <dune/common/parallel/mpihelper.hh>
+#include <dune/common/timer.hh>
+#include <dune/grid/io/file/dgfparser/dgfexception.hh>
+#include <dune/grid/io/file/vtk.hh>
+#include <dune/istl/io.hh>
+
 #include "fuelcellproblem.hh"
-#include <dumux/common/start.hh>
+
+#include <dumux/common/propertysystem.hh>
+#include <dumux/common/parameters.hh>
+#include <dumux/common/valgrind.hh>
+#include <dumux/common/dumuxmessage.hh>
+#include <dumux/common/defaultusagemessage.hh>
+
+#include <dumux/linear/amgbackend.hh>
+#include <dumux/nonlinear/newtonmethod.hh>
+#include <dumux/porousmediumflow/compositional/privarswitchnewtoncontroller.hh>
+
+#include <dumux/assembly/fvassembler.hh>
+#include <dumux/assembly/diffmethod.hh>
+
+#include <dumux/discretization/methods.hh>
+
+#include <dumux/io/vtkoutputmodule.hh>
 
 /*!
  * \brief Provides an interface for customizing error messages associated with
@@ -48,8 +74,177 @@ void usage(const char *progName, const std::string &errorMsg)
     }
 }
 
-int main(int argc, char** argv)
+int main(int argc, char** argv) try
+{
+    using namespace Dumux;
+
+    // define the type tag for this problem
+    using TypeTag = TTAG(FuelCellBoxProblem);
+
+    // initialize MPI, finalize is done automatically on exit
+    const auto& mpiHelper = Dune::MPIHelper::instance(argc, argv);
+
+    // print dumux start message
+    if (mpiHelper.rank() == 0)
+        DumuxMessage::print(/*firstCall=*/true);
+
+    // parse command line arguments and input file
+    Parameters::init(argc, argv, usage);
+
+    // try to create a grid (from the given grid file or the input file)
+    using GridCreator = typename GET_PROP_TYPE(TypeTag, GridCreator);
+    GridCreator::makeGrid();
+    GridCreator::loadBalance();
+
+    ////////////////////////////////////////////////////////////
+    // run instationary non-linear problem on this grid
+    ////////////////////////////////////////////////////////////
+
+    // we compute on the leaf grid view
+    const auto& leafGridView = GridCreator::grid().leafGridView();
+
+    // create the finite volume grid geometry
+    using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
+    auto fvGridGeometry = std::make_shared<FVGridGeometry>(leafGridView);
+    fvGridGeometry->update();
+
+    // the problem (initial and boundary conditions)
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    auto problem = std::make_shared<Problem>(fvGridGeometry);
+
+    // the solution vector
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
+    SolutionVector x(leafGridView.size(GridView::dimension));
+    problem->applyInitialSolution(x);
+    auto xOld = x;
+
+    // the grid variables
+    using GridVariables = typename GET_PROP_TYPE(TypeTag, GridVariables);
+    auto gridVariables = std::make_shared<GridVariables>(problem, fvGridGeometry);
+    gridVariables->init(x, xOld);
+
+    // get some time loop parameters
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    const auto tEnd = getParam<Scalar>("TimeLoop.TEnd");
+    const auto maxDivisions = getParam<int>("TimeLoop.MaxTimeStepDivisions");
+    const auto maxDt = getParam<Scalar>("TimeLoop.MaxTimeStepSize");
+    auto dt = getParam<Scalar>("TimeLoop.DtInitial");
+
+    // check if we are about to restart a previously interrupted simulation
+    Scalar restartTime = 0;
+    if (Parameters::getTree().hasKey("Restart") || Parameters::getTree().hasKey("TimeLoop.Restart"))
+        restartTime = getParam<Scalar>("TimeLoop.Restart");
+
+    // intialize the vtk output module
+    using VtkOutputFields = typename GET_PROP_TYPE(TypeTag, VtkOutputFields);
+    VtkOutputModule<TypeTag> vtkWriter(*problem, *fvGridGeometry, *gridVariables, x, problem->name());
+    VtkOutputFields::init(vtkWriter); //! Add model specific output fields
+    //add specific output
+    vtkWriter.addField(problem->getCurrentDensity(), "currentDensity [A/cm^2]");
+    vtkWriter.addField(problem->getReactionSourceH2O(), "reactionSourceH2O [mol/(sm^2)]");
+    vtkWriter.addField(problem->getReactionSourceO2(), "reactionSourceO2 [mol/(sm^2)]");
+    vtkWriter.write(0.0);
+
+    // instantiate time loop
+    auto timeLoop = std::make_shared<TimeLoop<Scalar>>(restartTime, dt, tEnd);
+    timeLoop->setMaxTimeStepSize(maxDt);
+
+    // the assembler with time loop for instationary problem
+    using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>;
+    auto assembler = std::make_shared<Assembler>(problem, fvGridGeometry, gridVariables, timeLoop);
+
+    // the linear solver
+    using LinearSolver = AMGBackend<TypeTag>;
+    auto linearSolver = std::make_shared<LinearSolver>(leafGridView, fvGridGeometry->elementMapper());
+
+    // the non-linear solver
+    using NewtonController = PriVarSwitchNewtonController<TypeTag>;
+    using NewtonMethod = NewtonMethod<TypeTag, NewtonController, Assembler, LinearSolver>;
+    auto newtonController = std::make_shared<NewtonController>(leafGridView.comm(), timeLoop);
+    NewtonMethod nonLinearSolver(newtonController, assembler, linearSolver);
+
+    // time loop
+    timeLoop->start(); do
+    {
+        // set previous solution for storage evaluations
+        assembler->setPreviousSolution(xOld);
+
+        // try solving the non-linear system
+        for (int i = 0; i < maxDivisions; ++i)
+        {
+            // linearize & solve
+            auto converged = nonLinearSolver.solve(x);
+
+            if (converged)
+                break;
+
+            if (!converged && i == maxDivisions-1)
+                DUNE_THROW(Dune::MathError,
+                           "Newton solver didn't converge after "
+                           << maxDivisions
+                           << " time-step divisions. dt="
+                           << timeLoop->timeStepSize()
+                           << ".\nThe solutions of the current and the previous time steps "
+                           << "have been saved to restart files.");
+        }
+
+        // make the new solution the old solution
+        xOld = x;
+        gridVariables->advanceTimeStep();
+
+        // advance to the time loop to the next step
+        timeLoop->advanceTimeStep();
+
+        problem->updateVtkOutput(xOld);
+
+        // write vtk output
+        vtkWriter.write(timeLoop->time());
+
+        // report statistics of this time step
+        timeLoop->reportTimeStep();
+
+        // set new dt as suggested by newton controller
+        timeLoop->setTimeStepSize(newtonController->suggestTimeStepSize(timeLoop->timeStepSize()));
+
+    } while (!timeLoop->finished());
+
+    timeLoop->finalize(leafGridView.comm());
+
+    ////////////////////////////////////////////////////////////
+    // finalize, print dumux message to say goodbye
+    ////////////////////////////////////////////////////////////
+
+    // print dumux end message
+    if (mpiHelper.rank() == 0)
+    {
+        Parameters::print();
+        DumuxMessage::print(/*firstCall=*/false);
+    }
+
+    return 0;
+} // end main
+catch (Dumux::ParameterException &e)
+{
+    std::cerr << std::endl << e << " ---> Abort!" << std::endl;
+    return 1;
+}
+catch (Dune::DGFException & e)
+{
+    std::cerr << "DGF exception thrown (" << e <<
+                 "). Most likely, the DGF file name is wrong "
+                 "or the DGF file is corrupted, "
+                 "e.g. missing hash at end of file or wrong number (dimensions) of entries."
+                 << " ---> Abort!" << std::endl;
+    return 2;
+}
+catch (Dune::Exception &e)
+{
+    std::cerr << "Dune reported error: " << e << " ---> Abort!" << std::endl;
+    return 3;
+}
+catch (...)
 {
-    typedef TTAG(FuelCellBoxProblem) ProblemTypeTag;
-    return Dumux::start<ProblemTypeTag>(argc, argv, usage);
+    std::cerr << "Unknown exception thrown! ---> Abort!" << std::endl;
+    return 4;
 }
diff --git a/test/porousmediumflow/2pnc/implicit/test_cc2pnc.cc b/test/porousmediumflow/2pnc/implicit/test_cc2pnc.cc
index 7786be91f6af42353d346dab84014bf752633bfa..8b0406201e4c9a6f6c85e6d6f7de3e408c192044 100644
--- a/test/porousmediumflow/2pnc/implicit/test_cc2pnc.cc
+++ b/test/porousmediumflow/2pnc/implicit/test_cc2pnc.cc
@@ -22,8 +22,34 @@
  * \brief Test for the 2pnc cc model used for water management in PEM fuel cells.
  */
 #include <config.h>
+
+#include <ctime>
+#include <iostream>
+
+#include <dune/common/parallel/mpihelper.hh>
+#include <dune/common/timer.hh>
+#include <dune/grid/io/file/dgfparser/dgfexception.hh>
+#include <dune/grid/io/file/vtk.hh>
+#include <dune/istl/io.hh>
+
 #include "fuelcellproblem.hh"
-#include <dumux/common/start.hh>
+
+#include <dumux/common/propertysystem.hh>
+#include <dumux/common/parameters.hh>
+#include <dumux/common/valgrind.hh>
+#include <dumux/common/dumuxmessage.hh>
+#include <dumux/common/defaultusagemessage.hh>
+
+#include <dumux/linear/amgbackend.hh>
+#include <dumux/nonlinear/newtonmethod.hh>
+#include <dumux/porousmediumflow/compositional/privarswitchnewtoncontroller.hh>
+
+#include <dumux/assembly/fvassembler.hh>
+#include <dumux/assembly/diffmethod.hh>
+
+#include <dumux/discretization/methods.hh>
+
+#include <dumux/io/vtkoutputmodule.hh>
 
 /*!
  * \brief Provides an interface for customizing error messages associated with
@@ -48,8 +74,176 @@ void usage(const char *progName, const std::string &errorMsg)
     }
 }
 
-int main(int argc, char** argv)
+int main(int argc, char** argv) try
+{
+    using namespace Dumux;
+
+    // define the type tag for this problem
+    using TypeTag = TTAG(FuelCellCCProblem);
+
+    // initialize MPI, finalize is done automatically on exit
+    const auto& mpiHelper = Dune::MPIHelper::instance(argc, argv);
+
+    // print dumux start message
+    if (mpiHelper.rank() == 0)
+        DumuxMessage::print(/*firstCall=*/true);
+
+    // parse command line arguments and input file
+    Parameters::init(argc, argv, usage);
+
+    // try to create a grid (from the given grid file or the input file)
+    using GridCreator = typename GET_PROP_TYPE(TypeTag, GridCreator);
+    GridCreator::makeGrid();
+    GridCreator::loadBalance();
+
+    ////////////////////////////////////////////////////////////
+    // run instationary non-linear problem on this grid
+    ////////////////////////////////////////////////////////////
+
+    // we compute on the leaf grid view
+    const auto& leafGridView = GridCreator::grid().leafGridView();
+
+    // create the finite volume grid geometry
+    using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
+    auto fvGridGeometry = std::make_shared<FVGridGeometry>(leafGridView);
+    fvGridGeometry->update();
+
+    // the problem (initial and boundary conditions)
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    auto problem = std::make_shared<Problem>(fvGridGeometry);
+
+    // the solution vector
+    using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
+    SolutionVector x(leafGridView.size(0));
+    problem->applyInitialSolution(x);
+    auto xOld = x;
+
+    // the grid variables
+    using GridVariables = typename GET_PROP_TYPE(TypeTag, GridVariables);
+    auto gridVariables = std::make_shared<GridVariables>(problem, fvGridGeometry);
+    gridVariables->init(x, xOld);
+
+    // get some time loop parameters
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    const auto tEnd = getParam<Scalar>("TimeLoop.TEnd");
+    const auto maxDivisions = getParam<int>("TimeLoop.MaxTimeStepDivisions");
+    const auto maxDt = getParam<Scalar>("TimeLoop.MaxTimeStepSize");
+    auto dt = getParam<Scalar>("TimeLoop.DtInitial");
+
+    // check if we are about to restart a previously interrupted simulation
+    Scalar restartTime = 0;
+    if (Parameters::getTree().hasKey("Restart") || Parameters::getTree().hasKey("TimeLoop.Restart"))
+        restartTime = getParam<Scalar>("TimeLoop.Restart");
+
+    // intialize the vtk output module
+    using VtkOutputFields = typename GET_PROP_TYPE(TypeTag, VtkOutputFields);
+    VtkOutputModule<TypeTag> vtkWriter(*problem, *fvGridGeometry, *gridVariables, x, problem->name());
+    VtkOutputFields::init(vtkWriter); //! Add model specific output fields
+    //add specific output
+    vtkWriter.addField(problem->getCurrentDensity(), "currentDensity [A/cm^2]");
+    vtkWriter.addField(problem->getReactionSourceH2O(), "reactionSourceH2O [mol/(sm^2)]");
+    vtkWriter.addField(problem->getReactionSourceO2(), "reactionSourceO2 [mol/(sm^2)]");
+    vtkWriter.write(0.0);
+
+    // instantiate time loop
+    auto timeLoop = std::make_shared<TimeLoop<Scalar>>(restartTime, dt, tEnd);
+    timeLoop->setMaxTimeStepSize(maxDt);
+
+    // the assembler with time loop for instationary problem
+    using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>;
+    auto assembler = std::make_shared<Assembler>(problem, fvGridGeometry, gridVariables, timeLoop);
+
+    // the linear solver
+    using LinearSolver = AMGBackend<TypeTag>;
+    auto linearSolver = std::make_shared<LinearSolver>(leafGridView, fvGridGeometry->elementMapper());
+
+    // the non-linear solver
+    using NewtonController = PriVarSwitchNewtonController<TypeTag>;
+    using NewtonMethod = NewtonMethod<TypeTag, NewtonController, Assembler, LinearSolver>;
+    auto newtonController = std::make_shared<NewtonController>(leafGridView.comm(), timeLoop);
+    NewtonMethod nonLinearSolver(newtonController, assembler, linearSolver);
+
+    // time loop
+    timeLoop->start(); do
+    {
+        // set previous solution for storage evaluations
+        assembler->setPreviousSolution(xOld);
+
+        // try solving the non-linear system
+        for (int i = 0; i < maxDivisions; ++i)
+        {
+            // linearize & solve
+            auto converged = nonLinearSolver.solve(x);
+
+            if (converged)
+                break;
+
+            if (!converged && i == maxDivisions-1)
+                DUNE_THROW(Dune::MathError,
+                           "Newton solver didn't converge after "
+                           << maxDivisions
+                           << " time-step divisions. dt="
+                           << timeLoop->timeStepSize()
+                           << ".\nThe solutions of the current and the previous time steps "
+                           << "have been saved to restart files.");
+        }
+
+        // make the new solution the old solution
+        xOld = x;
+        gridVariables->advanceTimeStep();
+
+        // advance to the time loop to the next step
+        timeLoop->advanceTimeStep();
+
+        problem->updateVtkOutput(xOld);
+
+        // write vtk output
+        vtkWriter.write(timeLoop->time());
+
+        // report statistics of this time step
+        timeLoop->reportTimeStep();
+
+        // set new dt as suggested by newton controller
+        timeLoop->setTimeStepSize(newtonController->suggestTimeStepSize(timeLoop->timeStepSize()));
+
+    } while (!timeLoop->finished());
+
+    timeLoop->finalize(leafGridView.comm());
+
+    ////////////////////////////////////////////////////////////
+    // finalize, print dumux message to say goodbye
+    ////////////////////////////////////////////////////////////
+
+    // print dumux end message
+    if (mpiHelper.rank() == 0)
+    {
+        Parameters::print();
+        DumuxMessage::print(/*firstCall=*/false);
+    }
+
+    return 0;
+} // end main
+catch (Dumux::ParameterException &e)
+{
+    std::cerr << std::endl << e << " ---> Abort!" << std::endl;
+    return 1;
+}
+catch (Dune::DGFException & e)
+{
+    std::cerr << "DGF exception thrown (" << e <<
+                 "). Most likely, the DGF file name is wrong "
+                 "or the DGF file is corrupted, "
+                 "e.g. missing hash at end of file or wrong number (dimensions) of entries."
+                 << " ---> Abort!" << std::endl;
+    return 2;
+}
+catch (Dune::Exception &e)
+{
+    std::cerr << "Dune reported error: " << e << " ---> Abort!" << std::endl;
+    return 3;
+}
+catch (...)
 {
-    typedef TTAG(FuelCellCCProblem) ProblemTypeTag;
-    return Dumux::start<ProblemTypeTag>(argc, argv, usage);
+    std::cerr << "Unknown exception thrown! ---> Abort!" << std::endl;
+    return 4;
 }