From 918b29a21437fc697600d1f2b9126bda22dd77cd Mon Sep 17 00:00:00 2001
From: Oliver Sander <sander@igpm.rwth-aachen.de>
Date: Tue, 4 Mar 2008 17:26:22 +0000
Subject: [PATCH] - new path to ag-common - do not hardwire the 3d material
 parameters - add method to create a straight initial rod - remove Neumann
 damping - remove anisotropic damping - do not hardwire the rod material and
 shape parameters - use the C++ IPOpt, if requested - use absolute corrections
 size for termination - better determination of the overall convergence rate

[[Imported from SVN: r2018]]
---
 dirneucoupling.cc | 267 ++++++++++++++++++++++++++++++----------------
 1 file changed, 173 insertions(+), 94 deletions(-)

diff --git a/dirneucoupling.cc b/dirneucoupling.cc
index 5e0d8708..b348438e 100644
--- a/dirneucoupling.cc
+++ b/dirneucoupling.cc
@@ -13,17 +13,22 @@
 #include <dune/common/bitfield.hh>
 #include <dune/common/configparser.hh>
 
-#include "../common/multigridstep.hh"
-#include "../common/iterativesolver.hh"
-#include "../common/projectedblockgsstep.hh"
-#include "../common/linearipopt.hh"
-#include "../common/readbitfield.hh"
-#include "../common/energynorm.hh"
-#include "../common/boundarypatch.hh"
-#include "../common/prolongboundarypatch.hh"
-#include "../common/sampleonbitfield.hh"
-#include "../common/neumannassembler.hh"
-#include "../common/computestress.hh"
+#include <dune/ag-common/multigridstep.hh>
+#include <dune/ag-common/iterativesolver.hh>
+#include <dune/ag-common/projectedblockgsstep.hh>
+#ifdef HAVE_IPOPT
+#include <dune/ag-common/linearipopt.hh>
+#endif
+#ifdef HAVE_IPOPT_CPP
+#include <dune/ag-common/quadraticipopt.hh>
+#endif
+#include <dune/ag-common/readbitfield.hh>
+#include <dune/ag-common/energynorm.hh>
+#include <dune/ag-common/boundarypatch.hh>
+#include <dune/ag-common/prolongboundarypatch.hh>
+#include <dune/ag-common/sampleonbitfield.hh>
+#include <dune/ag-common/neumannassembler.hh>
+#include <dune/ag-common/computestress.hh>
 
 #include "src/quaternion.hh"
 #include "src/rodassembler.hh"
@@ -36,11 +41,51 @@
 // Space dimension
 const int dim = 3;
 
-const double E = 2.5e5;
-const double nu = 0.3;
-
 using namespace Dune;
 using std::string;
+using std::vector;
+
+// Some types that I need
+//typedef BCRSMatrix<FieldMatrix<double, dim, dim> > OperatorType;
+//typedef BlockVector<FieldVector<double, dim> >     VectorType;
+typedef vector<Configuration>                      RodSolutionType;
+typedef BlockVector<FieldVector<double, 6> >       RodDifferenceType;
+
+
+// Make a straight rod from two given endpoints
+void makeStraightRod(RodSolutionType& rod, int n,
+                     const FieldVector<double,3>& beginning, const FieldVector<double,3>& end)
+{
+    // Compute the correct orientation
+    Quaternion<double> orientation = Quaternion<double>::identity();
+
+    FieldVector<double,3> zAxis(0);
+    zAxis[2] = 1;
+    FieldVector<double,3> axis = crossProduct(end-beginning, zAxis);
+
+    if (axis.two_norm() != 0)
+        axis /= -axis.two_norm();
+
+    FieldVector<double,3> d3 = end-beginning;
+    d3 /= d3.two_norm();
+
+    double angle = std::acos(zAxis * d3);
+
+    if (angle != 0)
+        orientation = Quaternion<double>(axis, angle);
+
+    // Set the values
+    rod.resize(n);
+    for (int i=0; i<n; i++) {
+
+        rod[i].r = beginning;
+        rod[i].r.axpy(double(i) / (n-1), end-beginning);
+        rod[i].q = orientation;
+
+    }
+
+
+}
 
 int main (int argc, char *argv[]) try
 {
@@ -72,27 +117,40 @@ 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 dirichletDamping         = parameterSet.get<double>("dirichletDamping");
-    FieldVector<double,3> neumannDamping;
-    neumannDamping           = parameterSet.get("neumannDamping", double(1));
-    neumannDamping[0]           = parameterSet.get("neumannDampingT", neumannDamping[0]);
-    neumannDamping[1]           = parameterSet.get("neumannDampingT", neumannDamping[1]);
-    neumannDamping[2]           = parameterSet.get("neumannDampingL", neumannDamping[2]);
-    std::string resultPath           = parameterSet.get("resultPath", "");
+    const double damping         = parameterSet.get<double>("damping");
+    string resultPath           = parameterSet.get("resultPath", "");
 
     // Problem settings
-    std::string path = parameterSet.get<string>("path");
-    std::string objectName = parameterSet.get<string>("gridFile");
-    std::string dirichletNodesFile  = parameterSet.get<string>("dirichletNodes");
-    std::string dirichletValuesFile = parameterSet.get<string>("dirichletValues");
-    std::string interfaceNodesFile  = parameterSet.get<string>("interfaceNodes");
-    const int numRodBaseElements = parameterSet.get<int>("numRodBaseElements");
-    
+    string path = parameterSet.get<string>("path");
+    string objectName = parameterSet.get<string>("gridFile");
+    string dirichletNodesFile  = parameterSet.get<string>("dirichletNodes");
+    string dirichletValuesFile = parameterSet.get<string>("dirichletValues");
+    string interfaceNodesFile  = parameterSet.get<string>("interfaceNodes");
+    const int numRodBaseElements    = parameterSet.get<int>("numRodBaseElements");
+
+    double E      = parameterSet.get<double>("E");
+    double nu     = parameterSet.get<double>("nu");
+
+    // rod material parameters
+    double rodA   = parameterSet.get<double>("rodA");
+    double rodJ1  = parameterSet.get<double>("rodJ1");
+    double rodJ2  = parameterSet.get<double>("rodJ2");
+    double rodE   = parameterSet.get<double>("rodE");
+    double rodNu  = parameterSet.get<double>("rodNu");
+
+    std::tr1::array<FieldVector<double,3>,2> rodRestEndPoint;
+    rodRestEndPoint[0][0] = parameterSet.get<double>("rodRestEndPoint0X");
+    rodRestEndPoint[0][1] = parameterSet.get<double>("rodRestEndPoint0Y");
+    rodRestEndPoint[0][2] = parameterSet.get<double>("rodRestEndPoint0Z");
+    rodRestEndPoint[1][0] = parameterSet.get<double>("rodRestEndPoint1X");
+    rodRestEndPoint[1][1] = parameterSet.get<double>("rodRestEndPoint1Y");
+    rodRestEndPoint[1][2] = parameterSet.get<double>("rodRestEndPoint1Z");
+
     // ///////////////////////////////////////
     //    Create the rod grid
     // ///////////////////////////////////////
     typedef OneDGrid RodGridType;
-    RodGridType rodGrid(numRodBaseElements, 0, 5);
+    RodGridType rodGrid(numRodBaseElements, 0, (rodRestEndPoint[1]-rodRestEndPoint[0]).two_norm());
 
     // ///////////////////////////////////////
     //    Create the grid for the 3d object
@@ -117,20 +175,22 @@ int main (int argc, char *argv[]) try
     // //////////////////////////
     //   Initial solution
     // //////////////////////////
-
+#if 0
     for (int i=0; i<rodX.size(); i++) {
         rodX[i].r[0] = 0.5;
         rodX[i].r[1] = 0.5;
         rodX[i].r[2] = 5 + (i* 5.0 /(rodX.size()-1));
         rodX[i].q = Quaternion<double>::identity();
     }
+#endif
+    makeStraightRod(rodX, rodGrid.size(1), rodRestEndPoint[0], rodRestEndPoint[1]);
 
     // /////////////////////////////////////////
     //   Read Dirichlet values
     // /////////////////////////////////////////
-    rodX.back().r[0] = parameterSet.get("dirichletValueX", double(0));
-    rodX.back().r[1] = parameterSet.get("dirichletValueY", double(0));
-    rodX.back().r[2] = parameterSet.get("dirichletValueZ", double(0));
+    rodX.back().r[0] = parameterSet.get("dirichletValueX", rodRestEndPoint[1][0]);
+    rodX.back().r[1] = parameterSet.get("dirichletValueY", rodRestEndPoint[1][1]);
+    rodX.back().r[2] = parameterSet.get("dirichletValueZ", rodRestEndPoint[1][2]);
 
     FieldVector<double,3> axis;
     axis[0] = parameterSet.get("dirichletAxisX", double(0));
@@ -210,7 +270,8 @@ int main (int argc, char *argv[]) try
     //   Create a solver for the rod problem
     // ///////////////////////////////////////////
     RodAssembler<RodGridType> rodAssembler(rodGrid);
-    rodAssembler.setShapeAndMaterial(1, 1.0/12, 1.0/12, 2.5e5, 0.3);
+    rodAssembler.setShapeAndMaterial(rodA, rodJ1, rodJ2, rodE, rodNu);
+
 
     RodSolver<RodGridType> rodSolver;
     rodSolver.setup(rodGrid, 
@@ -241,7 +302,12 @@ int main (int argc, char *argv[]) try
     // ////////////////////////////////
 
     // First create a gauss-seidel base solver
+#ifdef HAVE_IPOPT
     LinearIPOptSolver<VectorType> baseSolver;
+#endif
+#ifdef HAVE_IPOPT_CPP
+    QuadraticIPOptSolver<MatrixType,VectorType> baseSolver;
+#endif
     baseSolver.verbosity_ = NumProc::QUIET;
     baseSolver.tolerance_ = baseTolerance;
 
@@ -255,14 +321,15 @@ int main (int argc, char *argv[]) try
     multigridStep.basesolver_        = &baseSolver;
     multigridStep.presmoother_       = &presmoother;
     multigridStep.postsmoother_      = &postsmoother;    
-    multigridStep.verbosity_         = Solver::REDUCED;
+    multigridStep.verbosity_         = Solver::QUIET;
 
 
 
     EnergyNorm<MatrixType, VectorType> energyNorm(multigridStep);
 
     IterativeSolver<MatrixType, VectorType> solver(&multigridStep,
-                                                   multigridIterations,
+                                                   // IPOpt doesn't like to be started in the solution
+                                                   (numLevels!=1) ? multigridIterations : 1,
                                                    mgTolerance,
                                                    &energyNorm,
                                                    Solver::QUIET);
@@ -301,7 +368,8 @@ int main (int argc, char *argv[]) try
         std::cout << "----------------------------------------------------" << std::endl;
         
         // Backup of the current solution for the error computation later on
-        VectorType oldSolution3d = x3d;
+        VectorType      oldSolution3d  = x3d;
+        RodSolutionType oldSolutionRod = rodX;
 
         // //////////////////////////////////////////////////
         //   Dirichlet step for the rod
@@ -313,8 +381,8 @@ int main (int argc, char *argv[]) try
 
         rodX = rodSolver.getSol();
 
-        for (int j=0; j<rodX.size(); j++)
-            std::cout << rodX[j] << std::endl;
+//         for (int j=0; j<rodX.size(); j++)
+//             std::cout << rodX[j] << std::endl;
 
         // ///////////////////////////////////////////////////////////
         //   Extract Neumann values and transfer it to the 3d object
@@ -331,41 +399,6 @@ int main (int argc, char *argv[]) try
         std::cout << "resultant force: " << resultantForce << std::endl;
         std::cout << "resultant torque: " << resultantTorque << std::endl;
 
-#if 0
-        for (int j=0; j<dim; j++) {
-            lambdaForce[j] = (1-neumannDamping[j]) * lambdaForce[j] + neumannDamping[j] * resultantForce[j];
-            lambdaTorque[j] = (1-neumannDamping[j]) * lambdaTorque[j] + neumannDamping[j] * resultantTorque[j];
-        }
-#else
-        // damp in local coordinate system
-        FieldVector<double,dim> lambdaForceLocal, lambdaTorqueLocal;
-        FieldVector<double,dim> resultantForceLocal, resultantTorqueLocal;
-        for (int j=0; j<dim; j++) {
-
-            lambdaForceLocal[j]  = lambdaForce  * rodX[0].q.director(j);
-            lambdaTorqueLocal[j] = lambdaTorque * rodX[0].q.director(j);
-
-            resultantForceLocal[j]  = resultantForce  * rodX[0].q.director(j);
-            resultantTorqueLocal[j] = resultantTorque * rodX[0].q.director(j);
-
-            // Anisotropic damping
-            lambdaForceLocal[j] = (1-neumannDamping[j]) * lambdaForceLocal[j] + neumannDamping[j] * resultantForceLocal[j];
-            lambdaTorqueLocal[j] = (1-neumannDamping[j]) * lambdaTorqueLocal[j] + neumannDamping[j] * resultantTorqueLocal[j];
-
-        }
-
-        // Back to canonical coordinates
-        FieldMatrix<double,3,3> orientationMatrix;
-        rodX[0].q.matrix(orientationMatrix);
-            
-        lambdaForce  = 0;
-        lambdaTorque = 0;
-
-        orientationMatrix.umv(lambdaForceLocal, lambdaForce);
-        orientationMatrix.umv(lambdaTorqueLocal, lambdaTorque);
-
-#endif
-
         // For the time being the Neumann data coming from the rod is a dg function (== not continuous)
         // Maybe that is not necessary
         DGIndexSet<GridType> dgIndexSet(grid,grid.maxLevel());
@@ -374,7 +407,7 @@ int main (int argc, char *argv[]) try
         VectorType neumannValues(dgIndexSet.size());
 
         // Using that index 0 is always the left boundary for a uniformly refined OneDGrid
-        computeAveragePressure<GridType>(lambdaForce, lambdaTorque, 
+        computeAveragePressure<GridType>(resultantForce, resultantTorque, 
                                          interfaceBoundary[grid.maxLevel()], 
                                          rodX[0],
                                          neumannValues);
@@ -417,12 +450,12 @@ int main (int argc, char *argv[]) try
         //   Compute new damped interface value
         // ///////////////////////////////////////////////////////////
         for (int j=0; j<dim; j++)
-            lambda.r[j] = (1-dirichletDamping) * lambda.r[j] 
-                + dirichletDamping * (referenceInterface.r[j] + averageInterface.r[j]);
+            lambda.r[j] = (1-damping) * lambda.r[j] 
+                + damping * (referenceInterface.r[j] + averageInterface.r[j]);
 
         lambda.q = Quaternion<double>::interpolate(lambda.q, 
                                                    referenceInterface.q.mult(averageInterface.q), 
-                                                   dirichletDamping);
+                                                   damping);
 
         std::cout << "Lambda: " << lambda << std::endl;
 
@@ -473,8 +506,27 @@ int main (int argc, char *argv[]) try
         oldSolution3d -= x3d;
         double normOfCorrection = EnergyNorm<MatrixType,VectorType>::normSquared(oldSolution3d, *hessian3d);
 
-        // the rod \todo missing
-#warning Energy error of the rod still missing
+        double max3dRelCorrection = 0;
+        for (size_t j=0; j<x3d.size(); j++)
+            for (int k=0; k<dim; k++)
+                max3dRelCorrection = std::max(max3dRelCorrection, 
+                                              std::fabs(oldSolution3d[j][k])/ std::fabs(x3d[j][k]));
+
+
+        RodDifferenceType rodDiff = computeRodDifference(oldSolutionRod, rodX);
+        double maxRodRelCorrection = 0;
+        for (size_t j=0; j<rodX.size(); j++)
+            for (int k=0; k<dim; k++)
+                maxRodRelCorrection = std::max(maxRodRelCorrection, 
+                                              std::fabs(rodDiff[j][k])/ std::fabs(rodX[j].r[k]));
+
+        double maxRodCorrection = computeRodDifference(oldSolutionRod, rodX).infinity_norm();
+        double max3dCorrection  = oldSolution3d.infinity_norm();
+        std::cout << "rod correction: " << maxRodCorrection
+                  << "    rod rel correction: " <<  maxRodRelCorrection
+                  << "    3d correction: " <<  max3dCorrection
+                  << "    3d rel correction: " <<  max3dRelCorrection << std::endl;
+        
 
         oldNorm = std::sqrt(oldNorm);
 
@@ -490,7 +542,8 @@ int main (int argc, char *argv[]) try
         std::cout << "DD iteration: " << i << "  --  ||u^{n+1} - u^n|| / ||u^n||: " << relativeError << ",      "
                   << "convrate " << convRate << "\n";
 
-        if (relativeError < ddTolerance)
+        //if (relativeError < ddTolerance)
+        if (std::max(max3dRelCorrection,maxRodRelCorrection) < ddTolerance)
             break;
 
     }
@@ -512,7 +565,7 @@ int main (int argc, char *argv[]) try
     MatrixIndexSet indices(exactSolRod.size(), exactSolRod.size());
     rodAssembler.getNeighborsPerVertex(indices);
     indices.exportIdx(hessianRod);
-    rodAssembler.assembleMatrix(exactSolRod, hessianRod);
+    rodAssembler.assembleMatrixFD(exactSolRod, hessianRod);
 
 
     double error = std::numeric_limits<double>::max();
@@ -539,6 +592,13 @@ int main (int argc, char *argv[]) try
     totalConvRate[0] = 1;
 
 
+    double oldConvRate = 100;
+    bool firstTime = true;
+    std::stringstream levelAsAscii, dampingAsAscii;
+    levelAsAscii << numLevels;
+    dampingAsAscii << damping;
+    std::string filename = resultPath + "convrate_" + levelAsAscii.str() + "_" + dampingAsAscii.str();
+
     int i;
     for (i=0; i<maxDirichletNeumannSteps; i++) {
         
@@ -595,25 +655,44 @@ int main (int argc, char *argv[]) try
                   << "convrate " << convRate 
                   << "    total conv rate " << std::pow(totalConvRate[i+1], 1/((double)i+1)) << std::endl;
 
+        // Convergence rates tend to stay fairly constant after a few initial iterates.
+        // Only when we hit numerical dirt are they starting to wiggle around wildly.
+        // We use this to detect 'the' convergence rate as the last averaged rate before
+        // we hit the dirt.
+        if (convRate > oldConvRate + 0.1 && i > 5 && firstTime) {
+
+            std::cout << "Damping: " << damping
+                      << "   convRate: " << std::pow(totalConvRate[i], 1/((double)i)) 
+                      << std::endl;
+
+            std::ofstream convRateFile(filename.c_str());
+            convRateFile << damping << "   " 
+                         << std::pow(totalConvRate[i], 1/((double)i)) 
+                         << std::endl;
+
+            firstTime = false;
+        }
+
         if (error < 1e-12)
           break;
 
         oldError = error;
+        oldConvRate = convRate;
         
     }            
 
-    int backTrace = std::min(size_t(4),totalConvRate.size());
-    std::cout << "Dirichlet damping: " << dirichletDamping
-              << "Neumann damping: " << neumannDamping
-              << "   convRate: " << std::pow(totalConvRate[i+1-backTrace], 1/((double)i+1-backTrace)) 
-              << std::endl;
-
-    std::ofstream convRateFile("convrate");
-    convRateFile << dirichletDamping << "   " 
-                 << neumannDamping << "   " 
-                 << std::pow(totalConvRate[i+1-backTrace], 1/((double)i+1-backTrace)) 
-                 << std::endl;
-
+    // Convergence without dirt: write the overall convergence rate now
+    if (firstTime) {
+        int backTrace = std::min(size_t(4),totalConvRate.size());
+        std::cout << "Damping: " << damping
+                  << "   convRate: " << std::pow(totalConvRate[i+1-backTrace], 1/((double)i+1-backTrace)) 
+                  << std::endl;
+        
+        std::ofstream convRateFile(filename.c_str());
+        convRateFile << damping << "   " 
+                     << std::pow(totalConvRate[i+1-backTrace], 1/((double)i+1-backTrace)) 
+                     << std::endl;
+    }
 
     // //////////////////////////////
     //   Output result
-- 
GitLab