#include <config.h> //#define HAVE_IPOPT //#define DUNE_EXPRESSIONTEMPLATES #include <dune/grid/onedgrid.hh> #include <dune/grid/uggrid.hh> #include <dune/disc/elasticity/linearelasticityassembler.hh> #include <dune/disc/operators/p1operator.hh> #include <dune/istl/io.hh> #include <dune/grid/io/file/amirameshreader.hh> #include <dune/grid/io/file/amirameshwriter.hh> #include <dune/common/bitfield.hh> #include <dune/common/configparser.hh> #include "../contact/src/contactmmgstep.hh" #include "../solver/iterativesolver.hh" #include "../common/projectedblockgsstep.hh" #include "../common/geomestimator.hh" #include "../common/readbitfield.hh" #include "../common/energynorm.hh" #include "../common/boundarypatch.hh" #include "../common/prolongboundarypatch.hh" #include "src/quaternion.hh" #include "src/rodassembler.hh" #include "src/configuration.hh" #include "src/rodcoupling.hh" #include "src/rodwriter.hh" // Number of degrees of freedom of a correction for a rod configuration // 6 (x, y, z, v_1, v_2, v_3) for a spatial rod const int blocksize = 6; // Space dimension const int dim = 3; using namespace Dune; using std::string; void setTrustRegionObstacles(double trustRegionRadius, SimpleVector<BoxConstraint<dim> >& trustRegionObstacles, const BitField& dirichletNodes) { for (int i=0; i<trustRegionObstacles.size(); i++) { for (int k=0; k<dim; k++) { if (dirichletNodes[i*dim+k]) continue; trustRegionObstacles[i].val[2*k] = -trustRegionRadius; trustRegionObstacles[i].val[2*k+1] = trustRegionRadius; } } //std::cout << trustRegionObstacles << std::endl; // exit(0); } 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 BCRSMatrix<FieldMatrix<double, blocksize, blocksize> > RodMatrixType; typedef BlockVector<FieldVector<double, blocksize> > RodCorrectionType; typedef std::vector<Configuration> RodSolutionType; // parse data file ConfigParser parameterSet; parameterSet.parseFile("simplecoupling.parset"); // read solver settings const int minLevel = parameterSet.get("minLevel", int(0)); const int maxLevel = parameterSet.get("maxLevel", int(0)); const int maxTrustRegionSteps = parameterSet.get("maxTrustRegionSteps", int(0)); const int numIt = parameterSet.get("numIt", int(0)); const int nu1 = parameterSet.get("nu1", int(0)); const int nu2 = parameterSet.get("nu2", int(0)); const int mu = parameterSet.get("mu", int(0)); const int baseIt = parameterSet.get("baseIt", int(0)); const double tolerance = parameterSet.get("tolerance", double(0)); const double baseTolerance = parameterSet.get("baseTolerance", double(0)); const bool paramBoundaries = parameterSet.get("paramBoundaries", int(0)); // Problem settings std::string path = parameterSet.get("path", "xyz"); std::string objectName = parameterSet.get("gridFile", "xyz"); std::string parFile = parameterSet.get("parFile", "xyz"); std::string dirichletNodesFile = parameterSet.get("dirichletNodes", "xyz"); std::string dirichletValuesFile = parameterSet.get("dirichletValues", "xyz"); const int numRodBaseElements = parameterSet.get("numRodBaseElements", int(0)); // /////////////////////////////////////// // Create the rod grid // /////////////////////////////////////// typedef OneDGrid<1,1> RodGridType; RodGridType rodGrid(numRodBaseElements, 0, 5); // /////////////////////////////////////// // Create the grid for the 3d object // /////////////////////////////////////// typedef UGGrid<dim,dim> GridType; GridType grid; grid.setRefinementType(GridType::COPY); if (paramBoundaries) { AmiraMeshReader<GridType>::read(grid, path + objectName, path + parFile); } else { AmiraMeshReader<GridType>::read(grid, path + objectName); } Array<SimpleVector<BoxConstraint<dim> > > trustRegionObstacles(1); Array<BitField> hasObstacle(1); Array<BitField> dirichletNodes(1); double trustRegionRadius = 0.1; RodSolutionType rodX(rodGrid.size(0,1)); // ////////////////////////// // Initial solution // ////////////////////////// for (int i=0; i<rodX.size(); i++) { rodX[i].r = 0.5; rodX[i].r[2] = i+5; rodX[i].q = Quaternion<double>::identity(); } rodX[rodX.size()-1].r[0] = 0.5; rodX[rodX.size()-1].r[1] = 0.5; rodX[rodX.size()-1].r[2] = 11; // rodX[rodX.size()-1].q[0] = 0; // rodX[rodX.size()-1].q[1] = 0; // rodX[rodX.size()-1].q[2] = 1/sqrt(2); // rodX[rodX.size()-1].q[3] = 1/sqrt(2); // std::cout << "Left boundary orientation:" << std::endl; // std::cout << "director 0: " << rodX[0].q.director(0) << std::endl; // std::cout << "director 1: " << rodX[0].q.director(1) << std::endl; // std::cout << "director 2: " << rodX[0].q.director(2) << std::endl; // std::cout << std::endl; std::cout << "Right boundary orientation:" << std::endl; std::cout << "director 0: " << rodX[rodX.size()-1].q.director(0) << std::endl; std::cout << "director 1: " << rodX[rodX.size()-1].q.director(1) << std::endl; std::cout << "director 2: " << rodX[rodX.size()-1].q.director(2) << std::endl; // exit(0); int toplevel = rodGrid.maxLevel(); // ///////////////////////////////////////////////////// // Determine the Dirichlet nodes // ///////////////////////////////////////////////////// Array<VectorType> dirichletValues; dirichletValues.resize(toplevel+1); dirichletValues[0].resize(grid.size(0, dim)); AmiraMeshReader<int>::readFunction(dirichletValues[0], path + dirichletValuesFile); Array<BoundaryPatch<GridType> > dirichletBoundary; dirichletBoundary.resize(maxLevel+1); dirichletBoundary[0].setup(grid, 0); readBoundaryPatch(dirichletBoundary[0], path + dirichletNodesFile); prolongBoundaryPatch(dirichletBoundary); dirichletNodes.resize(toplevel+1); for (int i=0; i<=toplevel; i++) { dirichletNodes[i].resize( dim*grid.size(i,dim) + blocksize * rodGrid.size(i,1)); dirichletNodes[i].unsetAll(); for (int j=0; j<grid.size(i,dim); j++) for (int k=0; k<dim; k++) dirichletNodes[i][j*dim+k] = dirichletBoundary[i].containsVertex(j); for (int j=0; j<blocksize; j++) dirichletNodes[i][dirichletNodes[i].size()-1-j] = true; } // //////////////////////////////////////////////////////////// // Create solution and rhs vectors // //////////////////////////////////////////////////////////// VectorType totalRhs, totalCorr; totalRhs.resize(grid.size(toplevel,dim) + 2*rodGrid.size(toplevel,1)); totalCorr.resize(grid.size(toplevel,dim) + 2*rodGrid.size(toplevel,1)); // //////////////////////////////////////////////////////////// // Create and set up assembler for the separate problems // //////////////////////////////////////////////////////////// RodMatrixType rodHessian; RodAssembler<RodGridType> rodAssembler(rodGrid); //std::cout << "Energy: " << rodAssembler.computeEnergy(rodX) << std::endl; MatrixIndexSet indices(rodGrid.size(toplevel,1), rodGrid.size(toplevel,1)); rodAssembler.getNeighborsPerVertex(indices); indices.exportIdx(rodHessian); RodCorrectionType rodRhs, rodCorr; // ////////////////////////////////////////// // Assemble 3d linear elasticity problem // ////////////////////////////////////////// LeafP1Function<GridType,double,dim> u(grid),f(grid); LinearElasticityLocalStiffness<GridType,double> lstiff(2.5e5, 0.3); LeafP1OperatorAssembler<GridType,double,dim> hessian3d(grid); hessian3d.assemble(lstiff,u,f); VectorType x3d(grid.size(toplevel,dim)); VectorType corr3d(grid.size(toplevel,dim)); VectorType rhs3d(grid.size(toplevel,dim)); // No external forces rhs3d = 0; // Set initial solution x3d = 0; for (int i=0; i<x3d.size(); i++) for (int j=0; j<dim; j++) if (dirichletNodes[toplevel][i*dim+j]) x3d[i][j] = dirichletValues[toplevel][i][j]; // /////////////////////////////////////////// // Set up the total matrix // /////////////////////////////////////////// MatrixType totalHessian; RodCoupling<MatrixType, VectorType, RodMatrixType, RodCorrectionType> coupling; coupling.setUpMatrix(totalHessian, *hessian3d, rodHessian); coupling.insert3dPart(totalHessian, *hessian3d); // ////////////////////////////////////////////////////////// // Create obstacles // ////////////////////////////////////////////////////////// hasObstacle.resize(toplevel+1); for (int i=0; i<hasObstacle.size(); i++) { hasObstacle[i].resize(grid.size(i, dim) + 2*rodGrid.size(i,1)); hasObstacle[i].setAll(); } trustRegionObstacles.resize(toplevel+1); for (int i=0; i<toplevel+1; i++) { trustRegionObstacles[i].resize(grid.size(i,dim) + 2*rodGrid.size(i,1)); } // //////////////////////////////// // Create a multigrid solver // //////////////////////////////// // First create a gauss-seidel base solver ProjectedBlockGSStep<MatrixType, VectorType> baseSolverStep; EnergyNorm<MatrixType, VectorType> baseEnergyNorm(baseSolverStep); IterativeSolver<MatrixType, VectorType> baseSolver; baseSolver.iterationStep = &baseSolverStep; baseSolver.numIt = baseIt; baseSolver.verbosity_ = Solver::QUIET; baseSolver.errorNorm_ = &baseEnergyNorm; baseSolver.tolerance_ = baseTolerance; // Make pre and postsmoothers ProjectedBlockGSStep<MatrixType, VectorType> presmoother, postsmoother; ContactMMGStep<MatrixType, VectorType> contactMMGStep(totalHessian, totalCorr, totalRhs, 1); contactMMGStep.setMGType(mu, nu1, nu2); contactMMGStep.dirichletNodes_ = &dirichletNodes; contactMMGStep.basesolver_ = &baseSolver; contactMMGStep.presmoother_ = &presmoother; contactMMGStep.postsmoother_ = &postsmoother; contactMMGStep.hasObstacle_ = &hasObstacle; contactMMGStep.obstacles_ = &trustRegionObstacles; contactMMGStep.verbosity_ = Solver::QUIET; EnergyNorm<MatrixType, VectorType> energyNorm(contactMMGStep); IterativeSolver<MatrixType, VectorType> solver; solver.iterationStep = &contactMMGStep; solver.numIt = numIt; solver.verbosity_ = Solver::FULL; solver.errorNorm_ = &energyNorm; solver.tolerance_ = tolerance; // //////////////////////////////////// // Create the transfer operators // //////////////////////////////////// for (int k=0; k<contactMMGStep.mgTransfer_.size(); k++) delete(contactMMGStep.mgTransfer_[k]); contactMMGStep.mgTransfer_.resize(toplevel); for (int i=0; i<contactMMGStep.mgTransfer_.size(); i++){ TruncatedMGTransfer<VectorType>* newTransferOp = new TruncatedMGTransfer<VectorType>; newTransferOp->setup(grid,i,i+1); contactMMGStep.mgTransfer_[i] = newTransferOp; } // ///////////////////////////////////////////////////// // Trust-Region Solver // ///////////////////////////////////////////////////// for (int i=0; i<maxTrustRegionSteps; i++) { std::cout << "----------------------------------------------------" << std::endl; std::cout << " Trust-Region Step Number: " << i << std::endl; std::cout << "----------------------------------------------------" << std::endl; std::cout << "### Trust-Region Radius: " << trustRegionRadius << " ###" << std::endl; std::cout << " -- Rod energy: " << rodAssembler.computeEnergy(rodX) << " --" << std::endl; VectorType tmp3d(x3d.size()); tmp3d = 0; (*hessian3d).umv(x3d, tmp3d); double energy3d = 0.5 * (x3d*tmp3d); std::cout << " -- 3d energy: " << energy3d << " --" << std::endl; totalCorr = 0; totalRhs = 0; // Update the 3d part of the right hand side rhs3d = 0; // The zero here is the true right hand side (*hessian3d).mmv(x3d, rhs3d); coupling.insert3dPart(totalRhs, rhs3d); // Update the rod part of the total Hessian and right hand side rodRhs = 0; rodAssembler.assembleGradient(rodX, rodRhs); rodRhs *= -1; rodAssembler.assembleMatrix(rodX, rodHessian); coupling.insertRodPart(totalHessian, rodHessian); coupling.insertRodPart(totalRhs, rodRhs); // Create trust-region obstacles setTrustRegionObstacles(trustRegionRadius, trustRegionObstacles[toplevel], dirichletNodes[toplevel]); // ///////////////////////////// // Solve ! // ///////////////////////////// dynamic_cast<MultigridStep<MatrixType,VectorType>*>(solver.iterationStep)->setProblem(totalHessian, totalCorr, totalRhs, toplevel+1); solver.preprocess(); contactMMGStep.preprocess(); solver.solve(); totalCorr = contactMMGStep.getSol(); //std::cout << "Correction: " << std::endl << totalCorr << std::endl; printf("infinity norm of the correction: %g\n", totalCorr.infinity_norm()); if (totalCorr.infinity_norm() < 1e-5) { std::cout << "CORRECTION IS SMALL ENOUGH" << std::endl; break; } // //////////////////////////////////////////////////// // Split overall correction into its separate parts // //////////////////////////////////////////////////// coupling.get3dPart(totalCorr, corr3d); coupling.getRodPart(totalCorr, rodCorr); std::cout << "3ddCorrection: " << std::endl << corr3d << std::endl; std::cout << "RodCorrection: " << std::endl << rodCorr << std::endl; //exit(0); // //////////////////////////////////////////////////// // Check whether trust-region step can be accepted // //////////////////////////////////////////////////// RodSolutionType newRodIterate = rodX; for (int j=0; j<rodX.size(); j++) { // Add translational correction for (int k=0; k<3; k++) newRodIterate[j].r[k] += rodCorr[j][k]; // Add rotational correction newRodIterate[j].q = newRodIterate[j].q.mult(Quaternion<double>::exp(rodCorr[j][3], rodCorr[j][4], rodCorr[j][5])); } VectorType new3dIterate = x3d; new3dIterate += corr3d; // std::cout << "newIterate: \n"; // for (int j=0; j<newIterate.size(); j++) // printf("%d: (%g %g %g) (%g %g %g %g)\n", j, // newIterate[j].r[0],newIterate[j].r[1],newIterate[j].r[2], // newIterate[j].q[0],newIterate[j].q[1],newIterate[j].q[2],newIterate[j].q[3]); /** \todo Don't always recompute old energy */ double oldRodEnergy = rodAssembler.computeEnergy(rodX); double rodEnergy = rodAssembler.computeEnergy(newRodIterate); // compute the model decrease for the 3d part // It is $ m(x) - m(x+s) = -<g,s> - 0.5 <s, Hs> // Note that rhs = -g tmp3d = 0; (*hessian3d).umv(corr3d, tmp3d); double modelDecrease3d = (rhs3d*corr3d) - 0.5 * (corr3d*tmp3d); // compute the model decrease for the rod // It is $ m(x) - m(x+s) = -<g,s> - 0.5 <s, Hs> // Note that rhs = -g RodCorrectionType tmp(rodCorr.size()); tmp = 0; rodHessian.mmv(rodCorr, tmp); double rodModelDecrease = (rodRhs*rodCorr) - 0.5 * (rodCorr*tmp); std::cout << "Rod model decrease: " << rodModelDecrease << ", rod functional decrease: " << oldRodEnergy - rodEnergy << std::endl; std::cout << "3d decrease: " << modelDecrease3d << std::endl; if (rodEnergy >= oldRodEnergy) { printf("Richtung ist keine Abstiegsrichtung!\n"); // std::cout << "corr[0]\n" << corr[0] << std::endl; exit(0); } // Add correction to the current solution rodX = newRodIterate; x3d = new3dIterate; } // ////////////////////////////// // Output result // ////////////////////////////// AmiraMeshWriter<GridType>::writeGrid(grid, "grid.result"); AmiraMeshWriter<GridType>::writeBlockVector(grid, x3d, "grid.sol"); writeRod(rodX, "rod3d.result"); } catch (Exception e) { std::cout << e << std::endl; }