From b2573d88955bd42f9300c866b9b89c44b9985f0a Mon Sep 17 00:00:00 2001 From: Oliver Sander <oliver.sander@tu-dresden.de> Date: Mon, 21 Sep 2020 11:09:48 +0200 Subject: [PATCH] Allow to set up a TrustRegionSolver with externally given MMGStep This is needed as soon as the finite element spaces are not simply Lagrange spaces anymore, because the current TrustRegionSolver implementation simply hard-codes particular Lagrange-space prolongation operators. --- dune/elasticity/common/trustregionsolver.cc | 137 ++++++++++++++++++++ dune/elasticity/common/trustregionsolver.hh | 24 +++- 2 files changed, 159 insertions(+), 2 deletions(-) diff --git a/dune/elasticity/common/trustregionsolver.cc b/dune/elasticity/common/trustregionsolver.cc index 82fb9c7..ecae2a3 100644 --- a/dune/elasticity/common/trustregionsolver.cc +++ b/dune/elasticity/common/trustregionsolver.cc @@ -344,6 +344,143 @@ setup(const typename BasisType::GridView::Grid& grid, #endif } +template <class BasisType, class VectorType> +void TrustRegionSolver<BasisType,VectorType>:: +setup(const typename BasisType::GridView::Grid& grid, + std::shared_ptr<Dune::Elasticity::FEAssembler<BasisType,VectorType> > assembler, + const VectorType& x, + const Dune::BitSetVector<blocksize>& dirichletNodes, + double tolerance, + std::size_t maxTrustRegionSteps, + double initialTrustRegionRadius, + std::shared_ptr<MonotoneMGStep<MatrixType, CorrectionType> > mmgStep, + double mgTolerance, + std::size_t multigridIterations) +{ + grid_ = &grid; + assembler_ = assembler.get(); // FIXME: The class data member should be shared_ptr + x_ = x; + this->tolerance_ = tolerance; + maxTrustRegionSteps_ = maxTrustRegionSteps; + initialTrustRegionRadius_ = initialTrustRegionRadius; + innerIterations_ = multigridIterations; + innerTolerance_ = mgTolerance; + ignoreNodes_ = std::make_shared<Dune::BitSetVector<blocksize>>(dirichletNodes); + + const auto dim = VectorType::value_type::dimension; + +#if HAVE_DUNE_PARMG + DUNE_THROW(Dune::NotImplemented, + "TrustRegionSolver with dune-parmg does not support externally given multigrid step!"); +#endif + const auto& basis = assembler_->basis_; + + // ////////////////////////////////////////////////////////////////////////////////////// + // Assemble a Laplace matrix to create a norm that's equivalent to the H1-norm + // ////////////////////////////////////////////////////////////////////////////////////// + + + using ScalarMatrixType = Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >; + ScalarMatrixType localA; + + Dune::Fufem::DuneFunctionsOperatorAssembler<BasisType,BasisType> operatorAssembler(basis,basis); + + using FiniteElement = std::decay_t<decltype(basis.localView().tree().child(0).finiteElement())>; + // construct a Fufem Basis Assembler + auto laplaceStiffness = LaplaceAssembler<GridType, FiniteElement, FiniteElement, Dune::ScaledIdentityMatrix<double,dim>>(); + // transform it to a dune-functions assembler + auto localAssembler = [&](const auto& element, auto& localMatrix, auto&& trialLocalView, auto&& ansatzLocalView){ + // the fufem basis assembler assumes a scalar basis but a blocked element matrix! + // we can use ScaledIdentityMatrix here + Dune::Matrix<Dune::ScaledIdentityMatrix<double,dim>> localBlockedMatrix( localMatrix.N()/dim, localMatrix.M()/dim ); + laplaceStiffness.assemble(element, + localBlockedMatrix, + trialLocalView.tree().child(0).finiteElement(), + ansatzLocalView.tree().child(0).finiteElement()); + // convert back to flat matrix (we need only the diagonal entries in the blocks) + localMatrix = 0; + for(size_t i=0; i<localBlockedMatrix.N(); i++) + for(size_t j=0; j<localBlockedMatrix.M(); j++) + Dune::MatrixVector::addToDiagonal(localMatrix[i*dim][j*dim], localBlockedMatrix[i][j].scalar()); + }; + + + auto matrixBackend = Dune::Fufem::istlMatrixBackend(localA); + auto patternBuilder = matrixBackend.patternBuilder(); + + operatorAssembler.assembleBulkPattern(patternBuilder); + patternBuilder.setupMatrix(); + + operatorAssembler.assembleBulkEntries(matrixBackend, localAssembler); + + ScalarMatrixType* A = new ScalarMatrixType(localA); + + h1SemiNorm_ = std::make_shared< H1SemiNorm<CorrectionType> >(*A); + + // ////////////////////////////////////////////////////////////////////////////////////// + // Assemble a mass matrix to create a norm that's equivalent to the L2-norm + // This will be used to monitor the gradient + // ////////////////////////////////////////////////////////////////////////////////////// + + ScalarMatrixType localMassMatrix; + + // construct a Fufem Basis Assembler + using FiniteElement = std::decay_t<decltype(basis.localView().tree().child(0).finiteElement())>; + auto massStiffness = MassAssembler<GridType, FiniteElement, FiniteElement, Dune::ScaledIdentityMatrix<double,dim>>(); + // transform it to a dune-functions assembler + auto localMassAssembler = [&](const auto& element, auto& localMatrix, auto&& trialLocalView, auto&& ansatzLocalView){ + // the fufem basis assembler assumes a scalar basis but a blocked element matrix! + // we can use ScaledIdentityMatrix here + Dune::Matrix<Dune::ScaledIdentityMatrix<double,dim>> localBlockedMatrix( localMatrix.N()/dim, localMatrix.M()/dim ); + massStiffness.assemble(element, + localBlockedMatrix, + trialLocalView.tree().child(0).finiteElement(), + ansatzLocalView.tree().child(0).finiteElement()); + // convert back to flat matrix (we need only the diagonal entries in the blocks) + localMatrix = 0; + for(size_t i=0; i<localBlockedMatrix.N(); i++) + for(size_t j=0; j<localBlockedMatrix.M(); j++) + Dune::MatrixVector::addToDiagonal(localMatrix[i*dim][j*dim], localBlockedMatrix[i][j].scalar()); + }; + + auto massMatrixBackend = Dune::Fufem::istlMatrixBackend(localMassMatrix); + auto massPatternBuilder = massMatrixBackend.patternBuilder(); + + operatorAssembler.assembleBulkPattern(massPatternBuilder); + massPatternBuilder.setupMatrix(); + + operatorAssembler.assembleBulkEntries(massMatrixBackend, localMassAssembler); + + ScalarMatrixType* massMatrix = new ScalarMatrixType(localMassMatrix); + l2Norm_ = std::make_shared<H1SemiNorm<CorrectionType> >(*massMatrix); + + // //////////////////////////////////////////////////////////// + // Create Hessian matrix and its occupation structure + // //////////////////////////////////////////////////////////// + + hessianMatrix_ = std::make_shared<MatrixType>(); + + auto hessianBackend = Dune::Fufem::istlMatrixBackend(*hessianMatrix_); + auto hessianPatternBuilder = hessianBackend.patternBuilder(); + operatorAssembler.assembleBulkPattern(hessianPatternBuilder); + hessianPatternBuilder.setupMatrix(); + +#if !HAVE_DUNE_PARMG + innerSolver_ = std::make_shared<LoopSolver<CorrectionType> >(mmgStep, + innerIterations_, + innerTolerance_, + h1SemiNorm_, + Solver::REDUCED); + + //////////////////////////////////////////////////////////// + // Create obstacles + //////////////////////////////////////////////////////////// + + hasObstacle_.resize(basis.size(), true); + mmgStep->setHasObstacles(hasObstacle_); +#endif +} + template <class BasisType, class VectorType> void TrustRegionSolver<BasisType,VectorType>::solve() diff --git a/dune/elasticity/common/trustregionsolver.hh b/dune/elasticity/common/trustregionsolver.hh index 838f2a1..3947b55 100644 --- a/dune/elasticity/common/trustregionsolver.hh +++ b/dune/elasticity/common/trustregionsolver.hh @@ -72,10 +72,15 @@ public: TrustRegionSolver() : IterativeSolver<VectorType, Dune::BitSetVector<blocksize> >(0,100,NumProc::FULL), - hessianMatrix_(std::shared_ptr<MatrixType>(NULL)), h1SemiNorm_(NULL) + damping_(1.0), + hessianMatrix_(std::shared_ptr<MatrixType>(NULL)), + h1SemiNorm_(NULL) {} - /** \brief Set up the solver using a monotone multigrid method as the inner solver */ + /** \brief Set up the solver using a monotone multigrid method as the inner solver + * + * The monotone multigrid solver is created constructed internally. + */ void setup(const GridType& grid, std::conditional_t< // do we have a dune-functions basis? -> choose right assembler type Dune::models<Dune::Functions::Concept::GlobalBasis<GridView>, BasisType>(), @@ -95,6 +100,21 @@ public: double baseTolerance, double damping); + /** \brief Set up the solver using a monotone multigrid method as the inner solver + * + * The monotone multigrid solver is given from the outside. + */ + void setup(const GridType& grid, + std::shared_ptr<Dune::Elasticity::FEAssembler<BasisType,VectorType> > assembler, + const SolutionType& x, + const Dune::BitSetVector<blocksize>& dirichletNodes, + double tolerance, + std::size_t maxTrustRegionSteps, + double initialTrustRegionRadius, + std::shared_ptr<MonotoneMGStep<MatrixType, CorrectionType> > mmgStep, + double mgTolerance, + std::size_t multigridIterations); + void setIgnoreNodes(const Dune::BitSetVector<blocksize>& ignoreNodes) { ignoreNodes_ = &ignoreNodes; -- GitLab