diff --git a/simplecoupling.cc b/simplecoupling.cc new file mode 100644 index 0000000000000000000000000000000000000000..f50ee2ef73136f136444b668d789289ec0551ca0 --- /dev/null +++ b/simplecoupling.cc @@ -0,0 +1,456 @@ +#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; + + }