diff --git a/src/quasiconvexity-test.cc b/src/quasiconvexity-test.cc index 42df972b910993afc1e48ed5f41637c00d78244f..103950f43c8a71b9f52ef2259b85c694c49aa096 100644 --- a/src/quasiconvexity-test.cc +++ b/src/quasiconvexity-test.cc @@ -31,6 +31,7 @@ #include <dune/fufem/functiontools/boundarydofs.hh> #include <dune/fufem/dunepython.hh> +#include <dune/solvers/iterationsteps/mmgstep.hh> #include <dune/solvers/solvers/iterativesolver.hh> #include <dune/solvers/norms/energynorm.hh> @@ -47,6 +48,38 @@ const int order = 1; using namespace Dune; +template <class GridView> +Functions::BasisFactory::PeriodicIndexSet getPeriodicIndices(const GridView& gridView) +{ + // Check whether two points are equal on R/Z x R/Z + auto equivalent = [](const FieldVector<double,2>& x, const FieldVector<double,2>& y) + { + return ( (FloatCmp::eq(x[0],y[0]) or FloatCmp::eq(x[0]+1,y[0]) or FloatCmp::eq(x[0]-1,y[0])) + and (FloatCmp::eq(x[1],y[1]) or FloatCmp::eq(x[1]+1,y[1]) or FloatCmp::eq(x[1]-1,y[1])) ); + }; + + // Extract all boundary vertices + std::vector<std::pair<std::size_t, FieldVector<double,dim> > > boundaryVertices; + BoundaryPatch<GridView> domainBoundary(gridView, true); + + for (const auto& v1 : vertices(gridView)) + if (domainBoundary.containsVertex(gridView.indexSet().index(v1))) + boundaryVertices.push_back(std::make_pair(gridView.indexSet().index(v1), v1.geometry().corner(0))); + + std::cout << "Grid has " << boundaryVertices.size() << " boundary vertices" << std::endl; + + Functions::BasisFactory::PeriodicIndexSet periodicIndices; + if (order!=1) + DUNE_THROW(NotImplemented, "Periodicity detection only implemented for order==1"); + + for (const auto& v1 : boundaryVertices) + for (const auto& v2 : boundaryVertices) + if (equivalent(v1.second, v2.second)) + periodicIndices.unifyIndexPair(v1.first, v2.first); + + return periodicIndices; +} + template <class Basis, class Vector> void writeDisplacement(const Basis& basis, const Vector& periodicX, const FieldMatrix<double,2,2>& F0, std::string filename) { @@ -230,6 +263,8 @@ int main (int argc, char *argv[]) try GridView gridView = grid->leafGridView(); #endif + bool periodic = parameterSet.get<bool>("periodic", false); + // Check whether two points are equal on R/Z x R/Z auto equivalent = [](const FieldVector<double,2>& x, const FieldVector<double,2>& y) { @@ -243,31 +278,10 @@ int main (int argc, char *argv[]) try return FloatCmp::eq(x[0],y[0]) && FloatCmp::eq(x[1],y[1]); }; - // Extract all boundary vertices - std::vector<std::pair<std::size_t, FieldVector<double,dim> > > boundaryVertices; - BoundaryPatch<GridView> domainBoundary(gridView, true); - - for (const auto& v1 : vertices(gridView)) - if (domainBoundary.containsVertex(gridView.indexSet().index(v1))) - boundaryVertices.push_back(std::make_pair(gridView.indexSet().index(v1), v1.geometry().corner(0))); - - std::cout << "Grid has " << boundaryVertices.size() << " boundary vertices" << std::endl; - - bool periodic = parameterSet.get<bool>("periodic", false); - - //using namespace Dune::Fufem::BasisFactory; using namespace Dune::Functions::BasisFactory; Functions::BasisFactory::PeriodicIndexSet periodicIndices; if (periodic) - { - if (order!=1) - DUNE_THROW(NotImplemented, "Periodicity detection only implemented for order==1"); - - for (const auto& v1 : boundaryVertices) - for (const auto& v2 : boundaryVertices) - if (equivalent(v1.second, v2.second)) - periodicIndices.unifyIndexPair(v1.first, v2.first); - } + periodicIndices = getPeriodicIndices(gridView); // FE basis spanning the FE space that we are working in auto feBasis = makeBasis( @@ -339,7 +353,6 @@ int main (int argc, char *argv[]) try SolutionType x(feBasis.size()); - using namespace Dune::Functions::BasisFactory; auto powerBasis = makeBasis( gridView, power<dim>( @@ -508,27 +521,114 @@ int main (int argc, char *argv[]) try auto localADOLCStiffness = std::make_shared<Elasticity::LocalADOLCStiffness<FEBasis::LocalView> >(elasticEnergy); - Elasticity::FEAssembler<FEBasis,SolutionType> assembler(feBasis, localADOLCStiffness); + auto assembler = std::make_shared<Elasticity::FEAssembler<FEBasis,SolutionType> >(feBasis, localADOLCStiffness); + + /////////////////////////////////////////////////// + // Create a trust-region solver + /////////////////////////////////////////////////// + + using Matrix = BCRSMatrix<FieldMatrix<double, dim, dim> >; + +#ifdef HAVE_IPOPT + // First create an IPOpt base solver + auto baseSolver = std::make_shared<QuadraticIPOptSolver<Matrix,SolutionType> >( + baseTolerance, + baseIterations, + NumProc::REDUCED, + "mumps"); +#else + // First create a Gauss-seidel base solver + TrustRegionGSStep<Matrix, CorrectionType>* baseSolverStep = new TrustRegionGSStep<Matrix, SolutionType>; + + // Hack: the two-norm may not scale all that well, but it is fast! + TwoNorm<CorrectionType>* baseNorm = new TwoNorm<CorrectionType>; + + auto baseSolver = std::make_shared<::LoopSolver<CorrectionType>>(baseSolverStep, + baseIterations, + baseTolerance, + baseNorm, + Solver::QUIET); +#endif + // Make pre and postsmoothers + auto presmoother = std::make_shared< TrustRegionGSStep<Matrix, SolutionType> >(); + auto postsmoother = std::make_shared< TrustRegionGSStep<Matrix, SolutionType> >(); + + auto mmgStep = std::make_shared<MonotoneMGStep<Matrix, SolutionType> >(); + + mmgStep->setVerbosity(NumProc::FULL); + mmgStep->setMGType(mu, nu1, nu2); + mmgStep->ignoreNodes_ = &dirichletDofs; + mmgStep->setBaseSolver(baseSolver); + mmgStep->setSmoother(presmoother, postsmoother); + mmgStep->setObstacleRestrictor(std::make_shared<MandelObstacleRestrictor<SolutionType> >()); + + ////////////////////////////////////// + // Create the transfer operators + ////////////////////////////////////// + + using TransferOperatorType = typename TruncatedCompressedMGTransfer<SolutionType>::TransferOperatorType; + std::vector<std::shared_ptr<TruncatedCompressedMGTransfer<SolutionType>>> transferOperators(numLevels-1); + + // For the restriction operators: FE bases on all levels + + // This particular object is only needed to get the type of the level basis + PeriodicIndexSet dummyPeriodicIndices; + auto dummyLevelBasis = makeBasis( + grid->levelGridView(0), + power<dim>( + Functions::BasisFactory::periodic(lagrange<order>(), dummyPeriodicIndices), + blockedInterleaved() + )); + + using LevelBasis = decltype(dummyLevelBasis); + + // Construct the actual level bases + std::vector<std::shared_ptr<LevelBasis> > levelBases(numLevels); + for (int j=0; j<numLevels; j++) + { + PeriodicIndexSet periodicIndices; + if (periodic) + periodicIndices = getPeriodicIndices(grid->levelGridView(j)); + levelBases[j] = std::make_shared<LevelBasis>(makeBasis( + grid->levelGridView(j), + power<dim>( + Functions::BasisFactory::periodic(lagrange<order>(), periodicIndices), + blockedInterleaved() + ))); + } + + for (int j=0; j<numLevels-1; j++) + { + auto transferMatrix = std::make_shared<TransferOperatorType>(); + assembleGlobalBasisTransferMatrix(*transferMatrix, *levelBases[j], *levelBases[j+1]); + + // Construct the local multigrid transfer matrix + transferOperators[j] = std::make_shared<TruncatedCompressedMGTransfer<SolutionType> >(); + transferOperators[j]->setMatrix(transferMatrix); + } + + { + auto transferMatrix = std::make_shared<TransferOperatorType>(); + assembleGlobalBasisTransferMatrix(*transferMatrix, *levelBases.back(), *levelBases.back()); + + // Construct the local multigrid transfer matrix + transferOperators.push_back(std::make_shared<TruncatedCompressedMGTransfer<SolutionType> >()); + transferOperators.back()->setMatrix(transferMatrix); + } - // ///////////////////////////////////////////////// - // Create a Riemannian trust-region solver - // ///////////////////////////////////////////////// + mmgStep->setTransferOperators(transferOperators); TrustRegionSolver<FEBasis,SolutionType> solver; solver.setup(*grid, - &assembler, + assembler, x, dirichletDofs, tolerance, maxTrustRegionSteps, initialTrustRegionRadius, - multigridIterations, + mmgStep, mgTolerance, - mu, nu1, nu2, - baseIterations, - baseTolerance, - 1.0 - ); + multigridIterations); //////////////////////////////////////////////////////// // Set Dirichlet values