diff --git a/dirneucoupling.cc b/dirneucoupling.cc
index d90c0dfb3825a15f16967e56988f3c034b6f0771..f1a3356db678bc5c189c130fc93a27b92bd94853 100644
--- a/dirneucoupling.cc
+++ b/dirneucoupling.cc
@@ -66,8 +66,13 @@ int main (int argc, char *argv[]) try
 
     // read solver settings
     const int numLevels            = parameterSet.get<int>("numLevels");
-    const double ddTolerance           = parameterSet.get<double>("ddTolerance");
-    const int maxDirichletNeumannSteps = parameterSet.get<int>("maxDirichletNeumannSteps");
+    string ddType                = parameterSet.get<string>("ddType");
+    string preconditioner        = parameterSet.get<string>("preconditioner");
+    const double ddTolerance     = parameterSet.get<double>("ddTolerance");
+    const int maxDDIterations    = parameterSet.get<int>("maxDirichletNeumannSteps");
+    const double damping         = parameterSet.get<double>("damping");
+    
+    
     const double trTolerance           = parameterSet.get<double>("trTolerance");
     const int maxTrustRegionSteps = parameterSet.get<int>("maxTrustRegionSteps");
     const int trVerbosity            = parameterSet.get<int>("trVerbosity");
@@ -79,7 +84,6 @@ int main (int argc, char *argv[]) try
     const double mgTolerance     = parameterSet.get<double>("mgTolerance");
     const double baseTolerance = parameterSet.get<double>("baseTolerance");
     const double initialTrustRegionRadius = parameterSet.get<double>("initialTrustRegionRadius");
-    const double damping         = parameterSet.get<double>("damping");
     string resultPath           = parameterSet.get("resultPath", "");
 
     // Problem settings
@@ -329,92 +333,239 @@ int main (int argc, char *argv[]) try
     //
     double normOfOldCorrection = 0;
     int dnStepsActuallyTaken = 0;
-    for (int i=0; i<maxDirichletNeumannSteps; i++) {
+    for (int i=0; i<maxDDIterations; i++) {
         
         std::cout << "----------------------------------------------------" << std::endl;
-        std::cout << "      Dirichlet-Neumann Step Number: " << i << std::endl;
+        std::cout << "      Domain-Decomposition- Step Number: " << i       << std::endl;
         std::cout << "----------------------------------------------------" << std::endl;
         
         // Backup of the current solution for the error computation later on
         VectorType      oldSolution3d  = x3d;
         RodSolutionType oldSolutionRod = rodX;
+        
+        RigidBodyMotion<3> averageInterface;
+
+        if (ddType=="FixedPointIteration") {
 
-        // //////////////////////////////////////////////////
-        //   Dirichlet step for the rod
-        // //////////////////////////////////////////////////
+            // //////////////////////////////////////////////////
+            //   Dirichlet step for the rod
+            // //////////////////////////////////////////////////
 
-        rodX[0] = lambda;
-        rodSolver.setInitialSolution(rodX);
-        rodSolver.solve();
+            rodX[0] = lambda;
+            rodSolver.setInitialSolution(rodX);
+            rodSolver.solve();
 
-        rodX = rodSolver.getSol();
+            rodX = rodSolver.getSol();
 
 //         for (int j=0; j<rodX.size(); j++)
 //             std::cout << rodX[j] << std::endl;
 
-        // ///////////////////////////////////////////////////////////
-        //   Extract Neumann values and transfer it to the 3d object
-        // ///////////////////////////////////////////////////////////
+            // ///////////////////////////////////////////////////////////
+            //   Extract Neumann values and transfer it to the 3d object
+            // ///////////////////////////////////////////////////////////
 
-        BitSetVector<1> couplingBitfield(rodX.size(),false);
-        // Using that index 0 is always the left boundary for a uniformly refined OneDGrid
-        couplingBitfield[0] = true;
-        LeafBoundaryPatch<RodGridType> couplingBoundary(rodGrid, couplingBitfield);
+            BitSetVector<1> couplingBitfield(rodX.size(),false);
+            // Using that index 0 is always the left boundary for a uniformly refined OneDGrid
+            couplingBitfield[0] = true;
+            LeafBoundaryPatch<RodGridType> couplingBoundary(rodGrid, couplingBitfield);
 
-        FieldVector<double,dim> resultantForce, resultantTorque;
-        resultantForce  = rodAssembler.getResultantForce(couplingBoundary, rodX, resultantTorque);
+            FieldVector<double,dim> resultantForce, resultantTorque;
+            resultantForce  = rodAssembler.getResultantForce(couplingBoundary, rodX, resultantTorque);
 
-        // Flip orientation
-        resultantForce  *= -1;
-        resultantTorque *= -1;
+            // Flip orientation
+            resultantForce  *= -1;
+            resultantTorque *= -1;
         
-        std::cout << "resultant force: " << resultantForce << std::endl;
-        std::cout << "resultant torque: " << resultantTorque << std::endl;
+            std::cout << "resultant force: " << resultantForce << std::endl;
+            std::cout << "resultant torque: " << resultantTorque << std::endl;
 
-        VectorType neumannValues(rhs3d.size());
+            VectorType neumannValues(rhs3d.size());
 
-        // Using that index 0 is always the left boundary for a uniformly refined OneDGrid
-        computeAveragePressure<GridType>(resultantForce, resultantTorque, 
+            // Using that index 0 is always the left boundary for a uniformly refined OneDGrid
+            computeAveragePressure<GridType>(resultantForce, resultantTorque, 
                                               interfaceBoundary[grid.maxLevel()], 
                                               rodX[0],
                                               neumannValues);
 
-        rhs3d = 0;
-        assembleAndAddNeumannTerm<GridType::LevelGridView, VectorType>(interfaceBoundary[grid.maxLevel()],
+            rhs3d = 0;
+            assembleAndAddNeumannTerm<GridType::LevelGridView, VectorType>(interfaceBoundary[grid.maxLevel()],
                                                         neumannValues,
                                                         rhs3d);
 
-        // ///////////////////////////////////////////////////////////
-        //   Solve the Neumann problem for the 3d body
-        // ///////////////////////////////////////////////////////////
-        multigridStep.setProblem(stiffnessMatrix3d, x3d, rhs3d, grid.maxLevel()+1);
+            // ///////////////////////////////////////////////////////////
+            //   Solve the Neumann problem for the continuum
+            // ///////////////////////////////////////////////////////////
+            multigridStep.setProblem(stiffnessMatrix3d, x3d, rhs3d, grid.maxLevel()+1);
         
-        solver.preprocess();
-        multigridStep.preprocess();
+            solver.preprocess();
+            multigridStep.preprocess();
         
-        solver.solve();
+            solver.solve();
         
-        x3d = multigridStep.getSol();
+            x3d = multigridStep.getSol();
 
-        // ///////////////////////////////////////////////////////////
-        //   Extract new interface position and orientation
-        // ///////////////////////////////////////////////////////////
+            // ///////////////////////////////////////////////////////////
+            //   Extract new interface position and orientation
+            // ///////////////////////////////////////////////////////////
 
-        RigidBodyMotion<3> averageInterface;
-        computeAverageInterface(interfaceBoundary[toplevel], x3d, averageInterface);
+            computeAverageInterface(interfaceBoundary[toplevel], x3d, averageInterface);
 
         //averageInterface.r[0] = averageInterface.r[1] = 0;
         //averageInterface.q = Quaternion<double>::identity();
-        std::cout << "average interface: " << averageInterface << std::endl;
+            std::cout << "average interface: " << averageInterface << std::endl;
+
+            std::cout << "director 0:  " << averageInterface.q.director(0) << std::endl;
+            std::cout << "director 1:  " << averageInterface.q.director(1) << std::endl;
+            std::cout << "director 2:  " << averageInterface.q.director(2) << std::endl;
+            std::cout << std::endl;
+
+           
+        } else if (ddType=="RichardsonIteration") {
+            
+            ///////////////////////////////////////////////////////////////////
+            //  One preconditioned Richardson step
+            ///////////////////////////////////////////////////////////////////
+            
+            ///////////////////////////////////////////////////////////////////
+            //  Evaluate the Dirichlet-to-Neumann map for the rod
+            ///////////////////////////////////////////////////////////////////
+
+            // solve a Dirichlet problem for the rod
+            rodX[0] = lambda;
+            rodSolver.setInitialSolution(rodX);
+            rodSolver.solve();
 
-        std::cout << "director 0:  " << averageInterface.q.director(0) << std::endl;
-        std::cout << "director 1:  " << averageInterface.q.director(1) << std::endl;
-        std::cout << "director 2:  " << averageInterface.q.director(2) << std::endl;
-        std::cout << std::endl;
+            rodX = rodSolver.getSol();
+
+            //   Extract Neumann values
+
+            BitSetVector<1> couplingBitfield(rodX.size(),false);
+            // Using that index 0 is always the left boundary for a uniformly refined OneDGrid
+            couplingBitfield[0] = true;
+            LeafBoundaryPatch<RodGridType> couplingBoundary(rodGrid, couplingBitfield);
+
+            FieldVector<double,dim> resultantForce, resultantTorque;
+            resultantForce  = rodAssembler.getResultantForce(couplingBoundary, rodX, resultantTorque);
+
+            // Flip orientation
+            resultantForce  *= -1;
+            resultantTorque *= -1;
+        
+            std::cout << "resultant force: " << resultantForce << std::endl;
+            std::cout << "resultant torque: " << resultantTorque << std::endl;
+            
+            ///////////////////////////////////////////////////////////////////
+            //  Evaluate the Dirichlet-to-Neumann map for the continuum
+            ///////////////////////////////////////////////////////////////////
+
+            // Turn \lambda \in TSE(3) into a Dirichlet value for the continuum
+            RigidBodyMotion<3> relativeMovement;
+            relativeMovement.r = lambda.r - referenceInterface.r;
+            relativeMovement.q = referenceInterface.q;
+            relativeMovement.q.invert();
+            relativeMovement.q = lambda.q.mult(relativeMovement.q);
+            
+            setRotation(interfaceBoundary.back(), x3d, relativeMovement);
+            
+            // Solve the Dirichlet problem
+            multigridStep.setProblem(stiffnessMatrix3d, x3d, rhs3d, grid.maxLevel()+1);
+        
+            solver.preprocess();
+            multigridStep.preprocess();
+        
+            solver.solve();
+        
+            x3d = multigridStep.getSol();
+            
+            // Integrate over the residual on the coupling boundary to obtain
+            // an element of T^*SE.
+            FieldVector<double,3> continuumForce, continuumTorque;
+            
+            VectorType residual = rhs3d;
+            stiffnessMatrix3d.mmv(x3d,residual);
+            
+            /** \todo Is referenceInterface.r the correct center of rotation? */
+            getTotalForceAndTorque(interfaceBoundary.back(), residual, referenceInterface.r,
+                                   continuumForce, continuumTorque);
+            
+            ///////////////////////////////////////////////////////////////
+            //  Compute the overall Steklov-Poincare residual
+            ///////////////////////////////////////////////////////////////
+
+            FieldVector<double,3> residualForce  = resultantForce + continuumForce;
+            FieldVector<double,3> residualTorque = resultantTorque + continuumTorque;
+            
+            
+            
+            ///////////////////////////////////////////////////////////////
+            //  Apply the preconditioner
+            ///////////////////////////////////////////////////////////////
+            if (preconditioner=="DirichletNeumann") {
+                
+                ////////////////////////////////////////////////////////////////////
+                //  Preconditioner is the linearized Neumann-to-Dirichlet map
+                //  of the continuum.
+                ////////////////////////////////////////////////////////////////////
+                
+                VectorType neumannValues(rhs3d.size());
+
+                // Using that index 0 is always the left boundary for a uniformly refined OneDGrid
+                computeAveragePressure<GridType>(resultantForce, resultantTorque, 
+                                              interfaceBoundary[grid.maxLevel()], 
+                                              rodX[0],
+                                              neumannValues);
+
+                rhs3d = 0;
+                assembleAndAddNeumannTerm<GridType::LevelGridView, VectorType>(interfaceBoundary[grid.maxLevel()],
+                                                        neumannValues,
+                                                        rhs3d);
+
+                //   Solve the Neumann problem for the continuum
+                multigridStep.setProblem(stiffnessMatrix3d, x3d, rhs3d, grid.maxLevel()+1);
+        
+                solver.preprocess();
+                multigridStep.preprocess();
+        
+                solver.solve();
+        
+                x3d = multigridStep.getSol();
+
+                //  Average the continuum displacement on the coupling boundary
+                computeAverageInterface(interfaceBoundary[toplevel], x3d, averageInterface);
+                
+                
+            } else if (preconditioner=="NeumannDirichlet") {
+            
+                ////////////////////////////////////////////////////////////////////
+                //  Preconditioner is the linearized Neumann-to-Dirichlet map
+                //  of the rod.
+                ////////////////////////////////////////////////////////////////////
+
+                DUNE_THROW(NotImplemented, "Neumann-Dirichlet preconditioner not implemented yet");
+
+            } else if (preconditioner=="NeumannNeumann") {
+            
+                ////////////////////////////////////////////////////////////////////
+                //  Preconditioner is a convex combination of the linearized
+                //  Neumann-to-Dirichlet map of the continuum and the linearized
+                //  Neumann-to-Dirichlet map of the rod.
+                ////////////////////////////////////////////////////////////////////
+
+                DUNE_THROW(NotImplemented, "Neumann-Neumann preconditioner not implemented yet");
+                
+            } else if (preconditioner=="RobinRobin") {
+            
+                DUNE_THROW(NotImplemented, "Robin-Robin preconditioner not implemented yet");
+                
+            } else
+                DUNE_THROW(NotImplemented, preconditioner << " is not a known preconditioner");
+            
+        } else
+            DUNE_THROW(NotImplemented, ddType << " is not a known domain decomposition algorithm");
 
-        // ///////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////
         //   Compute new damped interface value
-        // ///////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////
         for (int j=0; j<dim; j++)
             lambda.r[j] = (1-damping) * lambda.r[j] 
                 + damping * (referenceInterface.r[j] + averageInterface.r[j]);
@@ -553,7 +704,7 @@ int main (int argc, char *argv[]) try
 
     // Store the history of total conv rates so we can filter out numerical
     // dirt in the end.
-    std::vector<double> totalConvRate(maxDirichletNeumannSteps+1);
+    std::vector<double> totalConvRate(maxDDIterations+1);
     totalConvRate[0] = 1;