diff --git a/dune/tectonic/myblockproblem.hh b/dune/tectonic/myblockproblem.hh index 078ec7b3b55951970ecf625678973d6cde3044fc..ecd7b7b9b18906627d3e72f956a4bcd19809448f 100644 --- a/dune/tectonic/myblockproblem.hh +++ b/dune/tectonic/myblockproblem.hh @@ -23,10 +23,28 @@ template <class MyConvexProblemTypeTEMPLATE> class MyBlockProblem { typedef typename MyConvexProblemType::LocalMatrixType LocalMatrixType; int static const block_size = MyConvexProblemType::block_size; + int static const coarse_block_size = block_size; /** \brief Solves one local system using a modified gradient method */ class IterateObject; + struct Linearization { + static const int block_size = coarse_block_size; + + typedef typename MyBlockProblem< + MyConvexProblemTypeTEMPLATE>::LocalMatrixType LocalMatrixType; + typedef Dune::BCRSMatrix<typename Linearization::LocalMatrixType> + MatrixType; + typedef Dune::BlockVector< + Dune::FieldVector<double, Linearization::block_size>> VectorType; + typedef Dune::BitSetVector<Linearization::block_size> BitVectorType; + typename Linearization::MatrixType A; + typename Linearization::VectorType b; + typename Linearization::BitVectorType ignore; + + Dune::BitSetVector<Linearization::block_size> truncation; + }; + MyBlockProblem(Dune::ParameterTree const &parset, MyConvexProblemType &problem) : parset(parset), problem(problem) { @@ -38,6 +56,110 @@ template <class MyConvexProblemTypeTEMPLATE> class MyBlockProblem { 0); // safety: acceptance factor for inexact minimization } + std::string virtual getOutput(bool header = false) const { + // TODO: implement (not urgent) + return std::string(); + } + + void projectCoarseCorrection(VectorType const &u, + typename Linearization::VectorType const &v, + VectorType &projected_v, + Linearization const &linearization) const { + // TODO: implement (not urgent) + projected_v = v; + }; + + double computeDampingParameter(VectorType const &u, + VectorType const &projected_v) const { + // TODO: implement + return 1.0; + }; + + void assembleTruncate(VectorType const &u, Linearization &linearization, + Dune::BitSetVector<block_size> const &ignore) const { + // we can just copy the ignore information + linearization.ignore = ignore; + + // determine truncation pattern + linearization.truncation.resize(u.size()); + linearization.truncation.unsetAll(); + Interval<double> ab; + for (int i = 0; i < u.size(); ++i) { + for (int j = 0; j < block_size; ++j) { + // problem.phi.smoothDomain(i, u[i][j], regularity_tol, ab, j); + + // // if (phi is not regular at u) or (u is not in smooth domain) or + // (component should be ignored) + // // truncate this component + // if ((problem.phi.regularity(i, u[i][j], j) > regularity_tol) + // or (u[i][j] < ab[0]) + // or (u[i][j] > ab[1]) + // or ignore[i][j]) + // linearization.truncation[i][j] = true; + } + } + + // construct sparsity pattern for linearization + Dune::MatrixIndexSet indices(problem.A.N(), problem.A.M()); + indices.import(problem.A); + // problem.phi.addHessianIndices(indices); + + // construct matrix from pattern and initialize it + indices.exportIdx(linearization.A); + linearization.A = 0.0; + + // compute quadratic part of hessian (linearization.A += problem.A) + for (int i = 0; i < problem.A.N(); ++i) { + typename MatrixType::row_type::ConstIterator it = problem.A[i].begin(); + typename MatrixType::row_type::ConstIterator end = problem.A[i].end(); + for (; it != end; ++it) + StaticMatrix::axpy(linearization.A[i][it.index()], 1.0, *it); + } + + // compute nonlinearity part of hessian + problem.phi.addHessian(u, linearization.A); + + // compute quadratic part of gradient + linearization.b.resize(u.size()); + linearization.b = 0.0; + problem.A.template umv<VectorType, VectorType>(u, linearization.b); + linearization.b -= problem.f; + + // compute nonlinearity part of gradient + problem.phi.addGradient(u, linearization.b); + + // -grad is needed for Newton step + linearization.b *= -1.0; + + // apply truncation to system + typename Linearization::MatrixType::row_type::Iterator it; + typename Linearization::MatrixType::row_type::Iterator end; + for (int row = 0; row < linearization.A.N(); ++row) { + it = linearization.A[row].begin(); + end = linearization.A[row].end(); + for (; it != end; ++it) { + int col = it.index(); + for (int i = 0; i < (*it).N(); ++i) { + typename Linearization::MatrixType::block_type::row_type::Iterator + blockIt = (*it)[i].begin(); + typename Linearization::MatrixType::block_type::row_type::Iterator + blockEnd = (*it)[i].end(); + for (; blockIt != blockEnd; ++blockIt) + if (linearization.truncation[row][i] or linearization + .truncation[col][blockIt.index()]) + (*blockIt) = 0.0; + } + } + + for (int j = 0; j < block_size; ++j) + if (linearization.truncation[row][j]) + linearization.b[row][j] = 0.0; + } + + // for(int j=0; j<block_size; ++j) + // outStream << std::setw(9) << linearization.truncation.countmasked(j); + } + /** \brief Constructs and returns an iterate object */ IterateObject getIterateObject() { return IterateObject(parset, bisection, problem); diff --git a/src/one-body-sample.cc b/src/one-body-sample.cc index efd7d49f29e3863357c5a26bb68e064d3924aa23..478d22586f566a952168e645626706e505ced5f9 100644 --- a/src/one-body-sample.cc +++ b/src/one-body-sample.cc @@ -49,6 +49,11 @@ #include <dune/tectonic/myconvexproblem.hh> #include <dune/tectonic/myblockproblem.hh> +#include <dune/solvers/iterationsteps/multigridstep.hh> +#include <dune/solvers/transferoperators/compressedmultigridtransfer.hh> +#include <dune/tnnmg/problem-classes/blocknonlineartnnmgproblem.hh> +#include <dune/tnnmg/iterationsteps/tnnmgstep.hh> + int const dim = 2; template <class GridView> @@ -242,17 +247,20 @@ int main(int argc, char *argv[]) { u1 = 0; VectorType u2 = u1; VectorType u3 = u1; + VectorType u4 = u1; VectorType u1_diff_new(grid.size(grid.maxLevel(), dim)); u1_diff_new = 0; VectorType u2_diff_new = u1_diff_new; VectorType u3_diff_new = u1_diff_new; + VectorType u4_diff_new = u1_diff_new; CellVectorType vonMisesStress; VectorType b1; VectorType b2; VectorType b3; + VectorType b4; auto nodalIntegrals = Dune::make_shared<Dune::BlockVector<Dune::FieldVector<double, 1>>>(); @@ -272,17 +280,19 @@ int main(int argc, char *argv[]) { leafView, p1Basis, neumannNodes, b1, run); b2 = b1; b3 = b1; + b4 = b1; // b -= linear update stiffnessMatrix.mmv(u1, b1); stiffnessMatrix.mmv(u2, b2); stiffnessMatrix.mmv(u3, b3); + stiffnessMatrix.mmv(u4, b4); if (parset.get<bool>("useNonlinearGS")) { MyConvexProblemType myConvexProblem( stiffnessMatrix, *myGlobalNonlinearity, b1, u1_diff_new); - MyBlockProblemType myBlockProblem(parset, myConvexProblem); - nonlinearGSStep.setProblem(u1_diff_new, myBlockProblem); + auto myBlockProblem = new MyBlockProblemType(parset, myConvexProblem); + nonlinearGSStep.setProblem(u1_diff_new, *myBlockProblem); LoopSolver<VectorType> solver(&nonlinearGSStep, solver_maxIterations, solver_tolerance, &energyNorm, verbosity); @@ -291,6 +301,72 @@ int main(int argc, char *argv[]) { u1 += u1_diff_new; + if (parset.get<bool>("useTNNMG")) { + MyConvexProblemType myConvexProblem( + stiffnessMatrix, *myGlobalNonlinearity, b4, u4_diff_new); + auto myBlockProblem = new MyBlockProblemType(parset, myConvexProblem); + + // {{{ Linear Solver; + TruncatedBlockGSStep<OperatorType, VectorType> *linearBaseSolverStep = + new TruncatedBlockGSStep<OperatorType, VectorType>; + + EnergyNorm<OperatorType, VectorType> *baseEnergyNorm = + new EnergyNorm<OperatorType, VectorType>(*linearBaseSolverStep); + LoopSolver<VectorType> *linearBaseSolver = new LoopSolver<VectorType>( + linearBaseSolverStep, solver_maxIterations, solver_tolerance, + baseEnergyNorm, Solver::QUIET); + // }}} + + // {{{ Smoothers + TruncatedBlockGSStep<OperatorType, VectorType> *linearPresmoother = + new TruncatedBlockGSStep<OperatorType, VectorType>; + TruncatedBlockGSStep<OperatorType, VectorType> *linearPostsmoother = + new TruncatedBlockGSStep<OperatorType, VectorType>; + // }}} + + MultigridStep<OperatorType, VectorType> *linearIterationStep = + new MultigridStep<OperatorType, VectorType>; + linearIterationStep->setNumberOfLevels(levels); + linearIterationStep->setMGType(1, 3, 3); // 1/3/3 (mu/nu1/nu2) + linearIterationStep->basesolver_ = linearBaseSolver; + linearIterationStep->setSmoother(linearPresmoother, linearPostsmoother); + + // {{{ Transfer operators + linearIterationStep->mgTransfer_.resize(levels - 1); + for (size_t i = 0; i < linearIterationStep->mgTransfer_.size(); i++) { + CompressedMultigridTransfer<VectorType> *newTransferOp = + new CompressedMultigridTransfer<VectorType>; + newTransferOp->setup(grid, i, i + 1); + linearIterationStep->mgTransfer_[i] = newTransferOp; + } + // }}} + + // // Now the actual nonlinear solver + typedef MyBlockProblemType TNNMGProblemType; + typedef GenericNonlinearGS<MyBlockProblemType> NonlinearSmootherType; + typedef TruncatedNonsmoothNewtonMultigrid< + TNNMGProblemType, NonlinearSmootherType> TNNMGStepType; + + TNNMGProblemType *tnnmgProblem = myBlockProblem; + NonlinearSmootherType *nonlinearSmoother = new NonlinearSmootherType; + + auto multigridStep = + new TNNMGStepType(*linearIterationStep, *nonlinearSmoother); + multigridStep->setProblem(u4_diff_new, *tnnmgProblem); + multigridStep->setSmoothingSteps(3, 1, 3); // 3/1/3 (pre/linear/post) + multigridStep->ignoreNodes_ = &ignoreNodes; + + auto energyNorm = + new EnergyNorm<OperatorType, VectorType>(stiffnessMatrix); + + LoopSolver<VectorType> overallSolver( + multigridStep, solver_maxIterations, solver_tolerance, energyNorm, + verbosity); + overallSolver.solve(); + } + + u4 += u4_diff_new; + { // Compute von Mises stress and write everything to a file auto *displacement = new BasisGridFunction<P1Basis, VectorType>(p1Basis, u1); @@ -351,12 +427,19 @@ int main(int argc, char *argv[]) { std::cout << "sup |u1 - u3| = " << diff3.infinity_norm() << ", " << "|u1 - u3| = " << diff3.two_norm() << std::endl; + VectorType diff4 = u4; + diff4 -= u1; + std::cout << "sup |u1 - u4| = " << diff4.infinity_norm() << ", " + << "|u1 - u4| = " << diff4.two_norm() << std::endl; + // Print displacement on frictional boundary for (size_t i = 0; i < frictionalNodes.size(); ++i) if (frictionalNodes[i][0]) std::cout << boost::format("u1[%02d] = %+3e, %|40t|u2[%02d] = %+3e " - "%|80t|u3[%02d] = %+3e") % - i % u1[i] % i % u2[i] % i % u3[i] << std::endl; + "%|80t|u3[%02d] = %+3e %|120t|u4[%02d] = " + "%+3e") % + i % u1[i] % i % u2[i] % i % u3[i] % i % + u4[i] << std::endl; } catch (Dune::Exception &e) { Dune::derr << "Dune reported error: " << e << std::endl; diff --git a/src/one-body-sample.parset b/src/one-body-sample.parset index caef4f15a928c88678af871d6e3dc1989a520ee8..d49f051d8a2c6f3e46e59aef31a109ea2285973d 100644 --- a/src/one-body-sample.parset +++ b/src/one-body-sample.parset @@ -6,6 +6,7 @@ verbose = false useNonlinearGS = true useGS = false useTruncatedGS = false +useTNNMG = true [grid] refinements = 5