From f0a8d830e47a2109277f366ad91ac3ea48861fc0 Mon Sep 17 00:00:00 2001
From: Oliver Sander <sander@igpm.rwth-aachen.de>
Date: Fri, 17 Aug 2007 09:40:58 +0000
Subject: [PATCH] error mesurement infrastructure

[[Imported from SVN: r1530]]
---
 dirneucoupling.cc | 230 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 212 insertions(+), 18 deletions(-)

diff --git a/dirneucoupling.cc b/dirneucoupling.cc
index 3ac1eb75..d9dab118 100644
--- a/dirneucoupling.cc
+++ b/dirneucoupling.cc
@@ -30,6 +30,7 @@
 #include "src/configuration.hh"
 #include "src/averageinterface.hh"
 #include "src/rodsolver.hh"
+#include "src/roddifference.hh"
 #include "src/rodwriter.hh"
 
 // Space dimension
@@ -38,12 +39,23 @@ const int dim = 3;
 using namespace Dune;
 using std::string;
 
+template <class DiscFuncType, int blocksize>
+double computeEnergyNormSquared(const DiscFuncType& u, 
+                                const BCRSMatrix<FieldMatrix<double,blocksize,blocksize> >& A)
+{
+    DiscFuncType tmp(u.size());
+    tmp = 0;
+    A.umv(u, tmp);
+    return u*tmp;
+}
+
 int main (int argc, char *argv[]) try
 {
     // Some types that I need
     typedef BCRSMatrix<FieldMatrix<double, dim, dim> >   MatrixType;
     typedef BlockVector<FieldVector<double, dim> >       VectorType;
     typedef std::vector<Configuration>                   RodSolutionType;
+    typedef BlockVector<FieldVector<double, 6> >         RodDifferenceType;
 
     // parse data file
     ConfigParser parameterSet;
@@ -52,7 +64,9 @@ int main (int argc, char *argv[]) try
     // read solver settings
     const int minLevel            = parameterSet.get("minLevel", int(0));
     const int maxLevel            = parameterSet.get("maxLevel", int(0));
+    const double ddTolerance           = parameterSet.get("ddTolerance", double(0));
     const int maxDirichletNeumannSteps = parameterSet.get("maxDirichletNeumannSteps", int(0));
+    const double trTolerance           = parameterSet.get("trTolerance", double(0));
     const int maxTrustRegionSteps = parameterSet.get("maxTrustRegionSteps", int(0));
     const int multigridIterations = parameterSet.get("numIt", int(0));
     const int nu1              = parameterSet.get("nu1", int(0));
@@ -61,7 +75,7 @@ int main (int argc, char *argv[]) try
     const int baseIterations   = parameterSet.get("baseIt", int(0));
     const double mgTolerance     = parameterSet.get("tolerance", double(0));
     const double baseTolerance = parameterSet.get("baseTolerance", double(0));
-    const int initialTrustRegionRadius = parameterSet.get("initialTrustRegionRadius", int(0));
+    const double initialTrustRegionRadius = parameterSet.get("initialTrustRegionRadius", double(0));
     const double damping       = parameterSet.get("damping", double(1));
 
     // Problem settings
@@ -72,7 +86,6 @@ int main (int argc, char *argv[]) try
     std::string interfaceNodesFile  = parameterSet.get("interfaceNodes", "xyz");
     const int numRodBaseElements = parameterSet.get("numRodBaseElements", int(0));
     
-    
     // ///////////////////////////////////////
     //    Create the rod grid
     // ///////////////////////////////////////
@@ -192,13 +205,15 @@ int main (int argc, char *argv[]) try
     rodSolver.setup(rodGrid, 
                     &rodAssembler,
                     rodX,
+                    trTolerance,
                     maxTrustRegionSteps,
                     initialTrustRegionRadius,
                     multigridIterations,
                     mgTolerance,
                     mu, nu1, nu2,
                     baseIterations,
-                    baseTolerance);
+                    baseTolerance,
+                    false);
 
     // ////////////////////////////////
     //   Create a multigrid solver
@@ -229,7 +244,7 @@ int main (int argc, char *argv[]) try
                                                    multigridIterations,
                                                    mgTolerance,
                                                    &energyNorm,
-                                                   Solver::FULL);
+                                                   Solver::QUIET);
 
     // ////////////////////////////////////
     //   Create the transfer operators
@@ -253,12 +268,18 @@ int main (int argc, char *argv[]) try
     Configuration referenceInterface = rodX[0];
     Configuration lambda = referenceInterface;
 
+    //
+    double normOfOldCorrection = 0;
+
     for (int i=0; i<maxDirichletNeumannSteps; i++) {
         
         std::cout << "----------------------------------------------------" << std::endl;
         std::cout << "      Dirichlet-Neumann Step Number: " << i << std::endl;
         std::cout << "----------------------------------------------------" << std::endl;
         
+        // Backup of the current solution for the error computation later on
+        VectorType oldSolution3d = x3d;
+
         // //////////////////////////////////////////////////
         //   Dirichlet step for the rod
         // //////////////////////////////////////////////////
@@ -272,16 +293,20 @@ int main (int argc, char *argv[]) try
         // ///////////////////////////////////////////////////////////
         //   Extract Neumann values and transfer it to the 3d object
         // ///////////////////////////////////////////////////////////
-        FieldVector<double,dim> resultantForce  = rodAssembler.getResultantForce(rodX);
+
+        BitField couplingBitfield(rodX.size(),false);
+        // Using the index 0 is always the left boundary for a uniformly refined OneDGrid
+        couplingBitfield[0] = true;
+        BoundaryPatch<RodGridType> couplingBoundary(rodGrid, rodGrid.maxLevel(), couplingBitfield);
+
+        FieldVector<double,dim> resultantTorque;
+        FieldVector<double,dim> resultantForce  = rodAssembler.getResultantForce(couplingBoundary, rodX, resultantTorque);
+
         std::cout << "resultant force: " << resultantForce << std::endl;
-#if 0
-        FieldVector<double,dim> resultantTorque = rodAssembler.getResultantTorque(grid, rodX);
-#endif
+        std::cout << "resultant torque: " << resultantTorque << std::endl;
+
         VectorType neumannValues(grid.size(dim));
-        neumannValues = 0;
-        for (int j=0; j<neumannValues.size(); j++)
-            if (interfaceBoundary[grid.maxLevel()].containsVertex(j))
-                neumannValues[j] = resultantForce;
+        computeAveragePressure<GridType>(resultantForce, resultantTorque, interfaceBoundary[grid.maxLevel()], neumannValues);
 
         rhs3d = 0;
         assembleAndAddNeumannTerm<GridType, VectorType>(interfaceBoundary[grid.maxLevel()],
@@ -305,10 +330,6 @@ int main (int argc, char *argv[]) try
         // ///////////////////////////////////////////////////////////
 
         Configuration averageInterface;
-//         x3d = 0;
-//         for (int i=0; i<x3d.size(); i++)
-//             x3d[i][2] = 1;
-
         computeAverageInterface(interfaceBoundary[toplevel], x3d, averageInterface);
 
         std::cout << "average interface: " << averageInterface << std::endl;
@@ -321,8 +342,181 @@ int main (int argc, char *argv[]) try
             lambda.r[j] = (1-damping) * lambda.r[j] + damping * (referenceInterface.r[j] + averageInterface.r[j]);
         lambda.q = averageInterface.q.mult(referenceInterface.q);
 
+        // ////////////////////////////////////////////////////////////////////////
+        //   Write the two iterates to disk for later convergence rate measurement
+        // ////////////////////////////////////////////////////////////////////////
+
+        // First the 3d body
+        char iSolFilename[100];
+        sprintf(iSolFilename, "tmp/intermediate3dSolution_%04d", i);
+            
+        FILE* fp = fopen(iSolFilename, "wb");
+        if (!fp)
+            DUNE_THROW(SolverError, "Couldn't open file " << iSolFilename << " for writing");
+            
+        for (int j=0; j<x3d.size(); j++)
+            for (int k=0; k<dim; k++)
+                fwrite(&x3d[j][k], sizeof(double), 1, fp);
+
+        fclose(fp);
+
+        // Then the rod
+        char iRodFilename[100];
+        sprintf(iRodFilename, "tmp/intermediateRodSolution_%04d", i);
+
+        FILE* fpRod = fopen(iRodFilename, "wb");
+        if (!fpRod)
+            DUNE_THROW(SolverError, "Couldn't open file " << iRodFilename << " for writing");
+            
+        for (int j=0; j<rodX.size(); j++) {
+
+            for (int k=0; k<dim; k++)
+                fwrite(&rodX[j].r[k], sizeof(double), 1, fpRod);
+
+            for (int k=0; k<4; k++)  // 3d hardwired here!
+                fwrite(&rodX[j].q[k], sizeof(double), 1, fpRod);
+
+        }
+
+        fclose(fpRod);
+
+        // ////////////////////////////////////////////
+        //   Compute error in the energy norm
+        // ////////////////////////////////////////////
+
+        // the 3d body
+        double oldNorm = computeEnergyNormSquared(oldSolution3d, *hessian3d);
+        oldSolution3d -= x3d;
+        double normOfCorrection = computeEnergyNormSquared(oldSolution3d, *hessian3d);
+
+        // the rod \todo missing
+#warning Energy error of the rod still missing
+
+        oldNorm = std::sqrt(oldNorm);
+
+        normOfCorrection = std::sqrt(normOfCorrection);
+
+        double relativeError = normOfCorrection / oldNorm;
+
+        double convRate = normOfCorrection / normOfOldCorrection;
+
+        normOfOldCorrection = normOfCorrection;
+
+        // Output
+        std::cout << "DD iteration: " << i << "  --  ||u^{n+1} - u^n||: " << relativeError << ",      "
+                  << "convrate " << convRate << "\n";
+
+        if (relativeError < ddTolerance)
+            break;
+
     }
 
+
+
+    // //////////////////////////////////////////////////////////
+    //   Recompute and compare against exact solution
+    // //////////////////////////////////////////////////////////
+    VectorType exactSol3d       = x3d;
+    RodSolutionType exactSolRod = rodX;
+
+    // //////////////////////////////////////////////////////////
+    //   Compute hessian of the rod functional at the exact solution
+    //   for use of the energy norm it creates.
+    // //////////////////////////////////////////////////////////
+
+    BCRSMatrix<FieldMatrix<double, 6, 6> > hessianRod;
+    MatrixIndexSet indices(exactSolRod.size(), exactSolRod.size());
+    rodAssembler.getNeighborsPerVertex(indices);
+    indices.exportIdx(hessianRod);
+    rodAssembler.assembleMatrix(exactSolRod, hessianRod);
+
+
+    double error = std::numeric_limits<double>::max();
+    double oldError = 0;
+    double totalConvRate = 1;
+
+    VectorType      intermediateSol3d(x3d.size());
+    RodSolutionType intermediateSolRod(rodX.size());
+
+    // Compute error of the initial 3d solution
+    
+    // This should really be exactSol-initialSol, but we're starting
+    // from zero anyways
+    oldError += computeEnergyNormSquared(exactSol3d, *hessian3d);
+    
+    /** \todo Rod error still missing */
+
+    oldError = std::sqrt(oldError);
+
+    
+
+    int i;
+    for (i=0; i<maxDirichletNeumannSteps; i++) {
+        
+        // /////////////////////////////////////////////////////
+        //   Read iteration from file
+        // /////////////////////////////////////////////////////
+
+        // Read 3d solution from file
+        char iSolFilename[100];
+        sprintf(iSolFilename, "tmp/intermediate3dSolution_%04d", i);
+            
+        FILE* fpInt = fopen(iSolFilename, "rb");
+        if (!fpInt)
+            DUNE_THROW(IOError, "Couldn't open intermediate solution '" << iSolFilename << "'");
+        for (int j=0; j<intermediateSol3d.size(); j++)
+            fread(&intermediateSol3d[j], sizeof(double), dim, fpInt);
+        
+        fclose(fpInt);
+
+        // Read rod solution from file
+        sprintf(iSolFilename, "tmp/intermediateRodSolution_%04d", i);
+            
+        fpInt = fopen(iSolFilename, "rb");
+        if (!fpInt)
+            DUNE_THROW(IOError, "Couldn't open intermediate solution '" << iSolFilename << "'");
+        for (int j=0; j<intermediateSolRod.size(); j++) {
+            fread(&intermediateSolRod[j].r, sizeof(double), dim, fpInt);
+            fread(&intermediateSolRod[j].q, sizeof(double), 4, fpInt);
+        }
+        
+        fclose(fpInt);
+
+
+
+        // /////////////////////////////////////////////////////
+        //   Compute error
+        // /////////////////////////////////////////////////////
+        
+        VectorType solBackup0 = intermediateSol3d;
+        solBackup0 -= exactSol3d;
+
+        RodDifferenceType rodDifference = computeRodDifference(exactSolRod, intermediateSolRod);
+        
+        error = std::sqrt(computeEnergyNormSquared(solBackup0, *hessian3d)
+                          +
+                          computeEnergyNormSquared(rodDifference, hessianRod));
+        
+
+        double convRate = error / oldError;
+        totalConvRate *= convRate;
+
+        // Output
+        std::cout << "DD iteration: " << i << "  error : " << error << ",      "
+                  << "convrate " << convRate 
+                  << "    total conv rate " << std::pow(totalConvRate, 1/((double)i+1)) << std::endl;
+
+        if (error < 1e-12)
+          break;
+
+        oldError = error;
+        
+    }            
+
+    std::cout << "damping: " << damping
+              << "   convRate: " << std::pow(totalConvRate, 1/((double)i+1)) << std::endl;
+
+
     // //////////////////////////////
     //   Output result
     // //////////////////////////////
@@ -330,8 +524,8 @@ int main (int argc, char *argv[]) try
     LeafAmiraMeshWriter<GridType>::writeBlockVector(grid, x3d, "grid.sol");
     writeRod(rodX, "rod3d.result");
 
-    for (int i=0; i<rodX.size(); i++)
-        std::cout << rodX[i] << std::endl;
+//     for (int i=0; i<rodX.size(); i++)
+//         std::cout << rodX[i] << std::endl;
 
  } catch (Exception e) {
 
-- 
GitLab