diff --git a/src/quasiconvexity-test-micromorphic.cc b/src/quasiconvexity-test-micromorphic.cc index f4df37024a429100b164102f514fb868a8c90b39..c2abca48cfe40a1e34aa242b9c8a37e58434c4b1 100644 --- a/src/quasiconvexity-test-micromorphic.cc +++ b/src/quasiconvexity-test-micromorphic.cc @@ -37,6 +37,7 @@ #include <dune/elasticity/common/trustregionsolver.hh> #include <dune/elasticity/assemblers/localadolcstiffness.hh> #include <dune/elasticity/assemblers/feassembler.hh> +#include <dune/elasticity/materials/localintegralenergy.hh> #include <dune/elasticity/materials/micromorphicallyrelaxedenergy.hh> #include <dune/elasticity/materials/pdistanceenergy.hh> #include <dune/elasticity/materials/quasiconvexitytestdensities.hh> @@ -190,7 +191,7 @@ void writeDisplacement(const Basis& basis, const Vector& x, const FieldMatrix<do template <typename Grid, typename IncompatibleDeformationGradientFunction> -void constructDeformation(const std::shared_ptr<Grid>& grid, +auto constructDeformation(const std::shared_ptr<Grid>& grid, const ParameterTree& parameterSet, const IncompatibleDeformationGradientFunction& incompatibleDeformationGradient) { @@ -403,6 +404,207 @@ void constructDeformation(const std::shared_ptr<Grid>& grid, std::cout << "2-Distance to incompatible strain: " << std::sqrt(assembler->computeEnergy(x)) << std::endl; writeDisplacement(feBasis, x, F0, resultPath + "quasiconvexity-test-micromorphic-deformation"); + + return x; +} + +template <typename Grid, typename Vector> +void minimizeEnergyInSpaceOfDeformations(const std::shared_ptr<Grid>& grid, + const ParameterTree& parameterSet, + const Vector& initialIterate) +{ + // read solver settings + const int numLevels = parameterSet.get<int>("numLevels"); + const double tolerance = parameterSet.get<double>("tolerance"); + const int maxTrustRegionSteps = parameterSet.get<int>("maxTrustRegionSteps"); + const double initialTrustRegionRadius = parameterSet.get<double>("initialTrustRegionRadius"); + const int multigridIterations = parameterSet.get<int>("numIt"); + const int nu1 = parameterSet.get<int>("nu1"); + const int nu2 = parameterSet.get<int>("nu2"); + const int mu = parameterSet.get<int>("mu"); + const int baseIterations = parameterSet.get<int>("baseIt"); + const double mgTolerance = parameterSet.get<double>("mgTolerance"); + const double baseTolerance = parameterSet.get<double>("baseTolerance"); + std::string resultPath = parameterSet.get("resultPath", ""); + +#if HAVE_DUNE_PARMG + using GridView = typename Grid::LevelGridView; + GridView gridView = grid->levelGridView(0); +#else + using GridView = typename Grid::LeafGridView; + GridView gridView = grid->leafGridView(); +#endif + + // FE basis spanning the FE space that we are working in + using namespace Dune::Functions::BasisFactory; + auto feBasis = makeBasis( + gridView, + power<dim>( + lagrange<order>(), + blockedInterleaved() + )); + using FEBasis = decltype(feBasis); + + std::cout << "Basis has " << feBasis.size() << " degrees of freedom" << std::endl; + + /////////////////////////////////////////// + // Set Dirichlet values + /////////////////////////////////////////// + + BoundaryPatch<GridView> dirichletBoundary(gridView, true); + + BitSetVector<dim> dirichletDofs(feBasis.size(), false); + constructBoundaryDofs(dirichletBoundary,feBasis,dirichletDofs); + + //////////////////////////// + // Initial iterate + //////////////////////////// + + Vector x = initialIterate; + + // Set the underlying affine deformation + auto x0 = parameterSet.get<double>("x0"); + + FieldMatrix<double,2,2> F0 = { {sqrt(x0), 0}, + { 0, 1.0 / sqrt(x0)} }; + + // Output initial iterate + writeDisplacement(feBasis, x, F0, resultPath + "quasiconvexity-test-micromorphic-deformation-magic-initial"); + + ////////////////////////////////////////////////////////////// + // Create an assembler for the energy functional + ////////////////////////////////////////////////////////////// + + const ParameterTree& materialParameters = parameterSet.sub("materialParameters"); + + // Assembler using ADOL-C + std::cout << "Selected energy is: " << parameterSet.get<std::string>("energy") << std::endl; + std::shared_ptr<Elasticity::LocalDensity<dim,adouble> > density; + + if (parameterSet.get<std::string>("energy") == "magic") + density = std::make_shared<Elasticity::MagicDensity<dim,adouble> >(F0,materialParameters); + + if(!density) + DUNE_THROW(Exception, "Error: Selected energy not available!"); + + auto elasticEnergy = std::make_shared<Elasticity::LocalIntegralEnergy<typename FEBasis::LocalView, + adouble> >(density); + + auto localADOLCStiffness = std::make_shared<Elasticity::LocalADOLCStiffness<typename FEBasis::LocalView> >(elasticEnergy); + + auto assembler = std::make_shared<Elasticity::FEAssembler<FEBasis,Vector> >(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,Vector> >( + baseTolerance, + baseIterations, + NumProc::QUIET, + "mumps"); +#else + // First create a Gauss-seidel base solver + TrustRegionGSStep<Matrix, Vector>* baseSolverStep = new TrustRegionGSStep<Matrix, Vector>; + + // Hack: the two-norm may not scale all that well, but it is fast! + TwoNorm<CorrectionType>* baseNorm = new TwoNorm<Vector>; + + auto baseSolver = std::make_shared<::LoopSolver<Vector>>(baseSolverStep, + baseIterations, + baseTolerance, + baseNorm, + Solver::QUIET); +#endif + // Make pre and postsmoothers + auto presmoother = std::make_shared< TrustRegionGSStep<Matrix, Vector> >(); + auto postsmoother = std::make_shared< TrustRegionGSStep<Matrix, Vector> >(); + + auto mmgStep = std::make_shared<MonotoneMGStep<Matrix, Vector> >(); + + 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<Vector> >()); + + ////////////////////////////////////// + // Create the transfer operators + ////////////////////////////////////// + + using TransferOperatorType = typename TruncatedCompressedMGTransfer<Vector>::TransferOperatorType; + std::vector<std::shared_ptr<TruncatedCompressedMGTransfer<Vector>>> transferOperators(numLevels-1); + + // For the restriction operators: FE bases on all levels + auto dummyLevelBasis = makeBasis( + grid->levelGridView(0), + power<dim>( + lagrange<order>(), + 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++) + { + levelBases[j] = std::make_shared<LevelBasis>(makeBasis( + grid->levelGridView(j), + power<dim>( + lagrange<order>(), + 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<Vector> >(); + transferOperators[j]->setMatrix(transferMatrix); + } + + mmgStep->setTransferOperators(transferOperators); + + TrustRegionSolver<FEBasis,Vector> solver; + solver.setup(*grid, + assembler, + x, + dirichletDofs, + tolerance, + maxTrustRegionSteps, + initialTrustRegionRadius, + mmgStep, + mgTolerance, + multigridIterations); + + + /////////////////////////////////////////////////////// + // Solve! + // ///////////////////////////////////////////////////// + + std::cout << "Energy before minimization: " << assembler->computeEnergy(x) << std::endl; + + solver.setInitialIterate(x); + solver.solve(); + + x = solver.getSol(); + + ///////////////////////////////// + // Output result + ///////////////////////////////// + + std::cout << "Energy after minimization: " << assembler->computeEnergy(x) << std::endl; + + writeDisplacement(feBasis, x, F0, resultPath + "quasiconvexity-test-micromorphic-deformation-magic"); } int main (int argc, char *argv[]) try @@ -706,7 +908,15 @@ int main (int argc, char *argv[]) try // close to the one we just constructed. ////////////////////////////////////////////////////////////////// auto incompatibleDeformationGradient = Functions::makeDiscreteGlobalBasisFunction<FieldMatrix<double,2,2>>(feBasis, x); - constructDeformation(grid, parameterSet, incompatibleDeformationGradient); + auto compatibleDeformation = constructDeformation(grid, parameterSet, incompatibleDeformationGradient); + + ////////////////////////////////////////////////////////////////// + // Minimize the W_magic energy starting from the compatible deformation + ////////////////////////////////////////////////////////////////// + minimizeEnergyInSpaceOfDeformations(grid, + parameterSet, + compatibleDeformation); + } catch (Exception& e) { std::cout << e.what() << std::endl; }