From 5e023a7a74166bd33a6623e474ce77d0cff79081 Mon Sep 17 00:00:00 2001 From: Oliver Sander <sander@igpm.rwth-aachen.de> Date: Thu, 22 Sep 2011 14:51:46 +0000 Subject: [PATCH] merge support for higher order geodesic finite element functions [[Imported from SVN: r7837]] --- dune/gfe/geodesicfeassembler.hh | 114 ++++++++++--------- dune/gfe/geodesicfefunctionadaptor.hh | 130 ++++++++++++++++++++- dune/gfe/harmonicenergystiffness.hh | 23 ++-- dune/gfe/localgeodesicfefunction.hh | 155 +++++++++++++++----------- dune/gfe/localgeodesicfestiffness.hh | 56 +++++----- dune/gfe/riemanniantrsolver.cc | 47 +++++++- dune/gfe/riemanniantrsolver.hh | 12 +- 7 files changed, 370 insertions(+), 167 deletions(-) diff --git a/dune/gfe/geodesicfeassembler.hh b/dune/gfe/geodesicfeassembler.hh index cf217226..327176c5 100644 --- a/dune/gfe/geodesicfeassembler.hh +++ b/dune/gfe/geodesicfeassembler.hh @@ -11,13 +11,12 @@ /** \brief A global FE assembler for problems involving functions that map into non-Euclidean spaces */ -template <class GridView, class TargetSpace> +template <class Basis, class TargetSpace> class GeodesicFEAssembler { - - typedef typename GridView::template Codim<0>::Entity EntityType; - typedef typename GridView::template Codim<0>::EntityPointer EntityPointer; + + typedef typename Basis::GridView GridView; typedef typename GridView::template Codim<0>::Iterator ElementIterator; - + //! Dimension of the grid. enum { gridDim = GridView::dimension }; @@ -26,19 +25,21 @@ class GeodesicFEAssembler { //! typedef Dune::FieldMatrix<double, blocksize, blocksize> MatrixBlock; - + protected: - const GridView gridView_; + const Basis basis_; - LocalGeodesicFEStiffness<GridView,TargetSpace>* localStiffness_; + LocalGeodesicFEStiffness<GridView, + typename Basis::LocalFiniteElement, + TargetSpace>* localStiffness_; public: /** \brief Constructor for a given grid */ - GeodesicFEAssembler(const GridView& gridView, - LocalGeodesicFEStiffness<GridView,TargetSpace>* localStiffness) - : gridView_(gridView), + GeodesicFEAssembler(const Basis& basis, + LocalGeodesicFEStiffness<GridView,typename Basis::LocalFiniteElement, TargetSpace>* localStiffness) + : basis_(basis), localStiffness_(localStiffness) {} @@ -62,27 +63,27 @@ public: -template <class GridView, class TargetSpace> -void GeodesicFEAssembler<GridView,TargetSpace>:: +template <class Basis, class TargetSpace> +void GeodesicFEAssembler<Basis,TargetSpace>:: getNeighborsPerVertex(Dune::MatrixIndexSet& nb) const { - const typename GridView::IndexSet& indexSet = gridView_.indexSet(); - - int n = gridView_.size(gridDim); + int n = basis_.size(); nb.resize(n, n); - ElementIterator it = gridView_.template begin<0>(); - ElementIterator endit = gridView_.template end<0> (); + ElementIterator it = basis_.getGridView().template begin<0>(); + ElementIterator endit = basis_.getGridView().template end<0> (); for (; it!=endit; ++it) { + + const typename Basis::LocalFiniteElement& lfe = basis_.getLocalFiniteElement(*it); - for (int i=0; i<it->template count<gridDim>(); i++) { + for (int i=0; i<lfe.localBasis().size(); i++) { - for (int j=0; j<it->template count<gridDim>(); j++) { + for (int j=0; j<lfe.localBasis().size(); j++) { - int iIdx = indexSet.subIndex(*it,i,gridDim); - int jIdx = indexSet.subIndex(*it,j,gridDim); + int iIdx = basis_.index(*it,i); + int jIdx = basis_.index(*it,j); nb.add(iIdx, jIdx); @@ -94,14 +95,12 @@ getNeighborsPerVertex(Dune::MatrixIndexSet& nb) const } -template <class GridView, class TargetSpace> -void GeodesicFEAssembler<GridView,TargetSpace>:: +template <class Basis, class TargetSpace> +void GeodesicFEAssembler<Basis,TargetSpace>:: assembleMatrix(const std::vector<TargetSpace>& sol, Dune::BCRSMatrix<MatrixBlock>& matrix, bool computeOccupationPattern) const { - const typename GridView::IndexSet& indexSet = gridView_.indexSet(); - if (computeOccupationPattern) { Dune::MatrixIndexSet neighborsPerVertex; @@ -112,30 +111,30 @@ assembleMatrix(const std::vector<TargetSpace>& sol, matrix = 0; - ElementIterator it = gridView_.template begin<0>(); - ElementIterator endit = gridView_.template end<0> (); + ElementIterator it = basis_.getGridView().template begin<0>(); + ElementIterator endit = basis_.getGridView().template end<0> (); for( ; it != endit; ++it ) { - const int numOfBaseFct = it->template count<gridDim>(); + const int numOfBaseFct = basis_.getLocalFiniteElement(*it).localBasis().size(); // Extract local solution - Dune::array<TargetSpace,gridDim+1> localSolution; + std::vector<TargetSpace> localSolution(numOfBaseFct); for (int i=0; i<numOfBaseFct; i++) - localSolution[i] = sol[indexSet.subIndex(*it,i,gridDim)]; + localSolution[i] = sol[basis_.index(*it,i)]; // setup matrix - localStiffness_->assembleHessian(*it, localSolution); + localStiffness_->assembleHessian(*it, basis_.getLocalFiniteElement(*it), localSolution); // Add element matrix to global stiffness matrix for(int i=0; i<numOfBaseFct; i++) { - int row = indexSet.subIndex(*it,i,gridDim); + int row = basis_.index(*it,i); for (int j=0; j<numOfBaseFct; j++ ) { - int col = indexSet.subIndex(*it,j,gridDim); + int col = basis_.index(*it,j); matrix[row][col] += localStiffness_->A_[i][j]; } @@ -145,71 +144,70 @@ assembleMatrix(const std::vector<TargetSpace>& sol, } -template <class GridView, class TargetSpace> -void GeodesicFEAssembler<GridView,TargetSpace>:: +template <class Basis, class TargetSpace> +void GeodesicFEAssembler<Basis,TargetSpace>:: assembleGradient(const std::vector<TargetSpace>& sol, Dune::BlockVector<Dune::FieldVector<double, blocksize> >& grad) const { - const typename GridView::IndexSet& indexSet = gridView_.indexSet(); - - if (sol.size()!=gridView_.size(gridDim)) + if (sol.size()!=basis_.size()) DUNE_THROW(Dune::Exception, "Solution vector doesn't match the grid!"); grad.resize(sol.size()); grad = 0; - ElementIterator it = gridView_.template begin<0>(); - ElementIterator endIt = gridView_.template end<0>(); + ElementIterator it = basis_.getGridView().template begin<0>(); + ElementIterator endIt = basis_.getGridView().template end<0>(); // Loop over all elements for (; it!=endIt; ++it) { // A 1d grid has two vertices - const int nDofs = it->template count<gridDim>(); + const int nDofs = basis_.getLocalFiniteElement(*it).localBasis().size(); // Extract local solution - Dune::array<TargetSpace,gridDim+1> localSolution; + std::vector<TargetSpace> localSolution(nDofs); for (int i=0; i<nDofs; i++) - localSolution[i] = sol[indexSet.subIndex(*it,i,gridDim)]; + localSolution[i] = sol[basis_.index(*it,i)]; // Assemble local gradient std::vector<Dune::FieldVector<double,blocksize> > localGradient(nDofs); - localStiffness_->assembleGradient(*it, localSolution, localGradient); + localStiffness_->assembleGradient(*it, basis_.getLocalFiniteElement(*it), localSolution, localGradient); // Add to global gradient for (int i=0; i<nDofs; i++) - grad[indexSet.subIndex(*it,i,gridDim)] += localGradient[i]; + grad[basis_.index(*it,i)] += localGradient[i]; } } -template <class GridView, class TargetSpace> -double GeodesicFEAssembler<GridView, TargetSpace>:: +template <class Basis, class TargetSpace> +double GeodesicFEAssembler<Basis, TargetSpace>:: computeEnergy(const std::vector<TargetSpace>& sol) const { double energy = 0; - const typename GridView::IndexSet& indexSet = gridView_.indexSet(); - - if (sol.size()!=indexSet.size(gridDim)) + if (sol.size()!=basis_.size()) DUNE_THROW(Dune::Exception, "Solution vector doesn't match the grid!"); - Dune::array<TargetSpace,gridDim+1> localSolution; - - ElementIterator it = gridView_.template begin<0>(); - ElementIterator endIt = gridView_.template end<0>(); + ElementIterator it = basis_.getGridView().template begin<0>(); + ElementIterator endIt = basis_.getGridView().template end<0>(); // Loop over all elements for (; it!=endIt; ++it) { + + // Number of degrees of freedom on this element + size_t nDofs = basis_.getLocalFiniteElement(*it).localBasis().size(); + + std::vector<TargetSpace> localSolution(nDofs); - for (int i=0; i<it->template count<gridDim>(); i++) - localSolution[i] = sol[indexSet.subIndex(*it,i,gridDim)]; + for (int i=0; i<nDofs; i++) + localSolution[i] = sol[basis_.index(*it,i)]; - energy += localStiffness_->energy(*it, localSolution); + energy += localStiffness_->energy(*it, basis_.getLocalFiniteElement(*it), localSolution); } diff --git a/dune/gfe/geodesicfefunctionadaptor.hh b/dune/gfe/geodesicfefunctionadaptor.hh index 6d152d16..48a26f3f 100644 --- a/dune/gfe/geodesicfefunctionadaptor.hh +++ b/dune/gfe/geodesicfefunctionadaptor.hh @@ -13,6 +13,8 @@ void geodesicFEFunctionAdaptor(GridType& grid, std::vector<TargetSpace>& x) { const int dim = GridType::dimension; + assert(x.size() == grid.size(dim)); + typedef typename GridType::template Codim<0>::LeafIterator ElementIterator; typedef typename GridType::template Codim<dim>::LeafIterator VertexIterator; @@ -44,6 +46,7 @@ void geodesicFEFunctionAdaptor(GridType& grid, std::vector<TargetSpace>& x) // Restore and interpolate the data // ///////////////////////////////////////////////////// + P1NodalBasis<typename GridType::LeafGridView> p1Basis(grid.leafView()); x.resize(grid.size(dim)); ElementIterator eIt = grid.template leafbegin<0>(); @@ -57,7 +60,9 @@ void geodesicFEFunctionAdaptor(GridType& grid, std::vector<TargetSpace>& x) for (int i=0; i<eIt->father()->template count<dim>(); i++) coefficients[i] = dofMap.find(idSet.subId(*eIt->father(),i,dim))->second; - LocalGeodesicFEFunction<dim,double,TargetSpace> fatherFunction(coefficients); + typedef typename P1NodalBasis<typename GridType::LeafGridView>::LocalFiniteElement LocalFiniteElement; + LocalGeodesicFEFunction<dim,double,LocalFiniteElement,TargetSpace> fatherFunction(p1Basis.getLocalFiniteElement(*eIt), + coefficients); // The embedding of this element into the father geometry const typename GridType::template Codim<0>::LocalGeometry& geometryInFather = eIt->geometryInFather(); @@ -84,4 +89,127 @@ void geodesicFEFunctionAdaptor(GridType& grid, std::vector<TargetSpace>& x) } + + +/** \brief Refine a grid globally and prolong a given geodesic finite element function + */ +template <class GridType, class TargetSpace> +void higherOrderGFEFunctionAdaptor(GridType& grid, std::vector<TargetSpace>& x) +{ + const int dim = GridType::dimension; + + typedef typename GridType::template Codim<0>::LeafIterator ElementIterator; + + // ///////////////////////////////////////////////////// + // Save leaf p1 data in a map + // ///////////////////////////////////////////////////// + + const typename GridType::Traits::LocalIdSet& idSet = grid.localIdSet(); + + // DUNE ids are not unique across all codimensions, hence the following hack. Sigh... + typedef std::pair<typename GridType::Traits::LocalIdSet::IdType, unsigned int> IdType; + std::map<IdType, TargetSpace> dofMap; + + typedef P2NodalBasis<typename GridType::LeafGridView,double> P2Basis; + P2Basis p2Basis(grid.leafView()); + + assert(x.size() == p2Basis.size()); + + ElementIterator eIt = grid.template leafbegin<0>(); + ElementIterator eEndIt = grid.template leafend<0>(); + + for (; eIt!=eEndIt; ++eIt) { + + const typename P2Basis::LocalFiniteElement& lfe = p2Basis.getLocalFiniteElement(*eIt); + //localCoefficients = p2Basis.getLocalFiniteElement(*eIt).localCoefficients(); + + for (size_t i=0; i<lfe.localCoefficients().size(); i++) { + + IdType id = std::make_pair(idSet.subId(*eIt, + lfe.localCoefficients().localKey(i).subEntity(), + lfe.localCoefficients().localKey(i).codim()), + lfe.localCoefficients().localKey(i).codim()); + + unsigned int idx = p2Basis.index(*eIt, i); + + //std::cout << "id: (" << id.first << ", " << id.second << ")" << std::endl; + dofMap.insert(std::make_pair(id, x[idx])); + + } + + } + + + // ///////////////////////////////////////////////////// + // Globally refine the grid + // ///////////////////////////////////////////////////// + + grid.globalRefine(1); + + + // ///////////////////////////////////////////////////// + // Restore and interpolate the data + // ///////////////////////////////////////////////////// + + p2Basis.update(grid.leafView()); + + x.resize(p2Basis.size()); + + for (eIt=grid.template leafbegin<0>(); eIt!=eEndIt; ++eIt) { + + const typename P2Basis::LocalFiniteElement& lfe = p2Basis.getLocalFiniteElement(*eIt); + + std::auto_ptr<typename Dune::PQkLocalFiniteElementFactory<double,double,dim,2>::FiniteElementType> fatherLFE + = std::auto_ptr<typename Dune::PQkLocalFiniteElementFactory<double,double,dim,2>::FiniteElementType>(Dune::PQkLocalFiniteElementFactory<double,double,dim,2>::create(eIt->type())); + + // Set up a local gfe function on the father element + std::vector<TargetSpace> coefficients(fatherLFE->localCoefficients().size()); + + for (int i=0; i<fatherLFE->localCoefficients().size(); i++) { + + IdType id = std::make_pair(idSet.subId(*eIt->father(), + fatherLFE->localCoefficients().localKey(i).subEntity(), + fatherLFE->localCoefficients().localKey(i).codim()), + fatherLFE->localCoefficients().localKey(i).codim()); + + coefficients[i] = dofMap.find(id)->second; + + } + + LocalGeodesicFEFunction<dim,double,typename P2Basis::LocalFiniteElement,TargetSpace> fatherFunction(*fatherLFE, coefficients); + + // The embedding of this element into the father geometry + const typename GridType::template Codim<0>::LocalGeometry& geometryInFather = eIt->geometryInFather(); + + for (int i=0; i<lfe.localCoefficients().size(); i++) { + + IdType id = std::make_pair(idSet.subId(*eIt, + lfe.localCoefficients().localKey(i).subEntity(), + lfe.localCoefficients().localKey(i).codim()), + lfe.localCoefficients().localKey(i).codim()); + + unsigned int idx = p2Basis.index(*eIt, i); + + if (dofMap.find(id) != dofMap.end()) { + + // If the vertex exists on the coarser level we take the value from there. + // That should be faster and more accurate than interpolating + x[idx] = dofMap[id]; + + } else { + + // Interpolate + const Dune::GenericReferenceElement<double,dim>& refElement = Dune::GenericReferenceElements<double,dim>::general(eIt->type()); + const Dune::FieldVector<double,dim>& pos = refElement.position(lfe.localCoefficients().localKey(i).subEntity(), + lfe.localCoefficients().localKey(i).codim()); + x[idx] = fatherFunction.evaluate(geometryInFather.global(pos)); + + } + + } + + } + +} + #endif diff --git a/dune/gfe/harmonicenergystiffness.hh b/dune/gfe/harmonicenergystiffness.hh index 2ca8e2e5..266ec1e2 100644 --- a/dune/gfe/harmonicenergystiffness.hh +++ b/dune/gfe/harmonicenergystiffness.hh @@ -11,9 +11,9 @@ #warning Finite-difference approximation of the energy gradient #endif -template<class GridView, class TargetSpace> +template<class GridView, class LocalFiniteElement, class TargetSpace> class HarmonicEnergyLocalStiffness - : public LocalGeodesicFEStiffness<GridView,TargetSpace> + : public LocalGeodesicFEStiffness<GridView,LocalFiniteElement,TargetSpace> { // grid types typedef typename GridView::Grid::ctype DT; @@ -30,7 +30,8 @@ public: /** \brief Assemble the energy for a single element */ RT energy (const Entity& e, - const Dune::array<TargetSpace,gridDim+1>& localSolution) const; + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution) const; #ifndef HARMONIC_ENERGY_FD_GRADIENT // The finite difference gradient method is in the base class. @@ -46,16 +47,18 @@ public: #endif }; -template <class GridView, class TargetSpace> -typename HarmonicEnergyLocalStiffness<GridView, TargetSpace>::RT HarmonicEnergyLocalStiffness<GridView, TargetSpace>:: +template <class GridView, class LocalFiniteElement, class TargetSpace> +typename HarmonicEnergyLocalStiffness<GridView, LocalFiniteElement, TargetSpace>::RT +HarmonicEnergyLocalStiffness<GridView, LocalFiniteElement, TargetSpace>:: energy(const Entity& element, - const Dune::array<TargetSpace,gridDim+1>& localSolution) const + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution) const { - RT energy = 0; - - assert(element.type().isSimplex()); + assert(element.type() == localFiniteElement.type()); - LocalGeodesicFEFunction<gridDim, double, TargetSpace> localGeodesicFEFunction(localSolution); + RT energy = 0; + LocalGeodesicFEFunction<gridDim, double, LocalFiniteElement, TargetSpace> localGeodesicFEFunction(localFiniteElement, + localSolution); int quadOrder = 1;//gridDim; diff --git a/dune/gfe/localgeodesicfefunction.hh b/dune/gfe/localgeodesicfefunction.hh index 663cbc03..43ee577b 100644 --- a/dune/gfe/localgeodesicfefunction.hh +++ b/dune/gfe/localgeodesicfefunction.hh @@ -20,7 +20,7 @@ \tparam ctype Type used for coordinates on the reference element \tparam TargetSpace The manifold that the function takes its values in */ -template <int dim, class ctype, class TargetSpace> +template <int dim, class ctype, class LocalFiniteElement, class TargetSpace> class LocalGeodesicFEFunction { @@ -32,8 +32,22 @@ class LocalGeodesicFEFunction public: /** \brief Constructor */ - LocalGeodesicFEFunction(const Dune::array<TargetSpace,dim+1>& coefficients) - : coefficients_(coefficients) + LocalGeodesicFEFunction(const LocalFiniteElement& localFiniteElement, + const Dune::array<TargetSpace,dim+1>& coefficients) DUNE_DEPRECATED + : localFiniteElement_(localFiniteElement), + coefficients_(coefficients.size()) + { + for (size_t i=0; i<coefficients.size(); i++) + coefficients_[i] = coefficients[i]; + } + + /** \brief Constructor + \param type Type of the reference element + */ + LocalGeodesicFEFunction(const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& coefficients) + : localFiniteElement_(localFiniteElement), + coefficients_(coefficients) {} /** \brief Evaluate the function */ @@ -67,28 +81,6 @@ public: private: - /** \brief The linear part of the map that turns coordinates on the reference simplex into coordinates on the standard simplex - \todo A special-purpose implementation of this matrix may lead to some speed-up */ - static Dune::FieldMatrix<ctype,dim+1,dim> referenceToBarycentricLinearPart() - { - Dune::FieldMatrix<ctype,dim+1,dim> B; - B[0] = -1; - for (int i=0; i<dim; i++) - for (int j=0; j<dim; j++) - B[i+1][j] = (i==j); - return B; - } - - static Dune::array<ctype,dim+1> barycentricCoordinates(const Dune::FieldVector<ctype,dim>& local) { - Dune::array<ctype,dim+1> result; - result[0] = 1; - for (int i=0; i<dim; i++) { - result[0] -= local[i]; - result[i+1] = local[i]; - } - return result; - } - static Dune::FieldMatrix<double,embeddedDim,embeddedDim> pseudoInverse(const Dune::FieldMatrix<double,embeddedDim,embeddedDim>& dFdq, const TargetSpace& q) { @@ -122,10 +114,10 @@ private: } /** \brief Compute derivate of F(w,q) (the derivative of the weighted distance fctl) wrt to w */ - Dune::FieldMatrix<ctype,embeddedDim,dim+1> computeDFdw(const TargetSpace& q) const + Dune::Matrix<Dune::FieldMatrix<ctype,1,1> > computeDFdw(const TargetSpace& q) const { - Dune::FieldMatrix<ctype,embeddedDim,dim+1> dFdw; - for (int i=0; i<dim+1; i++) { + Dune::Matrix<Dune::FieldMatrix<ctype,1,1> > dFdw(embeddedDim,localFiniteElement_.localBasis().size()); + for (int i=0; i<localFiniteElement_.localBasis().size(); i++) { Dune::FieldVector<ctype,embeddedDim> tmp = TargetSpace::derivativeOfDistanceSquaredWRTSecondArgument(coefficients_[i], q); for (int j=0; j<embeddedDim; j++) dFdw[j][i] = tmp[j]; @@ -133,27 +125,38 @@ private: return dFdw; } - Tensor3<ctype,embeddedDim,embeddedDim,embeddedDim> computeDqDqF(const Dune::array<ctype,dim+1>& w, const TargetSpace& q) const + Tensor3<ctype,embeddedDim,embeddedDim,embeddedDim> computeDqDqF(const std::vector<ctype>& w, const TargetSpace& q) const { Tensor3<ctype,embeddedDim,embeddedDim,embeddedDim> result; result = 0; - for (int i=0; i<dim+1; i++) + for (int i=0; i<w.size(); i++) result.axpy(w[i], TargetSpace::thirdDerivativeOfDistanceSquaredWRTSecondArgument(coefficients_[i],q)); return result; } + /** \brief The scalar local finite element, which provides the weighting factors + \todo We really only need the local basis + */ + const LocalFiniteElement& localFiniteElement_; + /** \brief The coefficient vector */ - Dune::array<TargetSpace,dim+1> coefficients_; + std::vector<TargetSpace> coefficients_; }; -template <int dim, class ctype, class TargetSpace> -TargetSpace LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: +template <int dim, class ctype, class LocalFiniteElement, class TargetSpace> +TargetSpace LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>:: evaluate(const Dune::FieldVector<ctype, dim>& local) const { - // First compute the coordinates on the standard simplex (in R^{n+1}) - Dune::array<ctype,dim+1> w = barycentricCoordinates(local); + // Evaluate the weighting factors---these are the Lagrangian shape function values at 'local' + std::vector<Dune::FieldVector<ctype,1> > wNested; + localFiniteElement_.localBasis().evaluateFunction(local,wNested); + std::vector<ctype> w(wNested.size()); + for (size_t i=0; i<w.size(); i++) + w[i] = wNested[i][0]; + + /** \todo The 'dim+1' parameter is a dummy here */ AverageDistanceAssembler<TargetSpace,dim+1> assembler(coefficients_, w); TargetSpaceRiemannianTRSolver<TargetSpace,dim+1> solver; @@ -172,8 +175,8 @@ evaluate(const Dune::FieldVector<ctype, dim>& local) const return solver.getSol(); } -template <int dim, class ctype, class TargetSpace> -Dune::FieldMatrix<ctype, TargetSpace::EmbeddedTangentVector::dimension, dim> LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: +template <int dim, class ctype, class LocalFiniteElement, class TargetSpace> +Dune::FieldMatrix<ctype, TargetSpace::EmbeddedTangentVector::dimension, dim> LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>:: evaluateDerivative(const Dune::FieldVector<ctype, dim>& local) const { Dune::FieldMatrix<ctype, embeddedDim, dim> result; @@ -198,18 +201,29 @@ evaluateDerivative(const Dune::FieldVector<ctype, dim>& local) const TargetSpace q = evaluate(local); // the matrix that turns coordinates on the reference simplex into coordinates on the standard simplex - Dune::FieldMatrix<ctype,dim+1,dim> B = referenceToBarycentricLinearPart(); - + std::vector<Dune::FieldMatrix<ctype,1,dim> > BNested(coefficients_.size()); + localFiniteElement_.localBasis().evaluateJacobian(local, BNested); + Dune::Matrix<Dune::FieldMatrix<double,1,1> > B(coefficients_.size(), dim); + for (size_t i=0; i<coefficients_.size(); i++) + for (size_t j=0; j<dim; j++) + B[i][j] = BNested[i][0][j]; + // compute negative derivative of F(w,q) (the derivative of the weighted distance fctl) wrt to w - Dune::FieldMatrix<ctype,embeddedDim,dim+1> dFdw = computeDFdw(q); + Dune::Matrix<Dune::FieldMatrix<ctype,1,1> > dFdw = computeDFdw(q); dFdw *= -1; // multiply the two previous matrices: the result is the right hand side - Dune::FieldMatrix<ctype,embeddedDim,dim> RHS = dFdw * B; + Dune::Matrix<Dune::FieldMatrix<ctype,1,1> > RHS = dFdw * B; // the actual system matrix - Dune::array<ctype,dim+1> w = barycentricCoordinates(local); - AverageDistanceAssembler<TargetSpace,dim+1> assembler(coefficients_, w); + std::vector<Dune::FieldVector<ctype,1> > wNested; + localFiniteElement_.localBasis().evaluateFunction(local, wNested); + + std::vector<ctype> w(wNested.size()); + for (size_t i=0; i<w.size(); i++) + w[i] = wNested[i][0]; + + AverageDistanceAssembler<TargetSpace,1> assembler(coefficients_, w); Dune::FieldMatrix<ctype,embeddedDim,embeddedDim> dFdq(0); assembler.assembleEmbeddedHessian(q,dFdq); @@ -263,8 +277,8 @@ evaluateDerivative(const Dune::FieldVector<ctype, dim>& local) const return result; } -template <int dim, class ctype, class TargetSpace> -Dune::FieldMatrix<ctype, TargetSpace::EmbeddedTangentVector::dimension, dim> LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: +template <int dim, class ctype, class LocalFiniteElement, class TargetSpace> +Dune::FieldMatrix<ctype, TargetSpace::EmbeddedTangentVector::dimension, dim> LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>:: evaluateDerivativeFD(const Dune::FieldVector<ctype, dim>& local) const { double eps = 1e-6; @@ -290,8 +304,8 @@ evaluateDerivativeFD(const Dune::FieldVector<ctype, dim>& local) const return result; } -template <int dim, class ctype, class TargetSpace> -void LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: +template <int dim, class ctype, class LocalFiniteElement, class TargetSpace> +void LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>:: evaluateDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& local, int coefficient, Dune::FieldMatrix<double,embeddedDim,embeddedDim>& result) const @@ -339,8 +353,8 @@ evaluateDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& loc } -template <int dim, class ctype, class TargetSpace> -void LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: +template <int dim, class ctype, class LocalFiniteElement, class TargetSpace> +void LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>:: evaluateFDDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& local, int coefficient, Dune::FieldMatrix<double,embeddedDim,embeddedDim>& result) const @@ -365,8 +379,8 @@ evaluateFDDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& l cornersPlus [coefficient] = TargetSpace::exp(coefficients_[coefficient], forwardVariation); cornersMinus[coefficient] = TargetSpace::exp(coefficients_[coefficient], backwardVariation); - LocalGeodesicFEFunction<dim,double,TargetSpace> fPlus(cornersPlus); - LocalGeodesicFEFunction<dim,double,TargetSpace> fMinus(cornersMinus); + LocalGeodesicFEFunction<dim,double,LocalFiniteElement,TargetSpace> fPlus(cornersPlus); + LocalGeodesicFEFunction<dim,double,LocalFiniteElement,TargetSpace> fMinus(cornersMinus); TargetSpace hPlus = fPlus.evaluate(local); TargetSpace hMinus = fMinus.evaluate(local); @@ -387,8 +401,8 @@ evaluateFDDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& l } -template <int dim, class ctype, class TargetSpace> -void LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: +template <int dim, class ctype, class LocalFiniteElement, class TargetSpace> +void LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>:: evaluateDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>& local, int coefficient, Tensor3<double,embeddedDim,embeddedDim,dim>& result) const @@ -397,13 +411,24 @@ evaluateDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>& TargetSpace q = evaluate(local); // the matrix that turns coordinates on the reference simplex into coordinates on the standard simplex - Dune::FieldMatrix<ctype,dim+1,dim> B = referenceToBarycentricLinearPart(); + std::vector<Dune::FieldMatrix<ctype,1,dim> > BNested(coefficients_.size()); + localFiniteElement_.localBasis().evaluateJacobian(local, BNested); + Dune::Matrix<Dune::FieldMatrix<double,1,1> > B(coefficients_.size(), dim); + for (size_t i=0; i<coefficients_.size(); i++) + for (size_t j=0; j<dim; j++) + B[i][j] = BNested[i][0][j]; - // compute derivate of F(w,q) (the derivative of the weighted distance fctl) wrt to w - Dune::FieldMatrix<ctype,embeddedDim,dim+1> dFdw = computeDFdw(q); + // compute derivative of F(w,q) (the derivative of the weighted distance fctl) wrt to w + Dune::Matrix<Dune::FieldMatrix<ctype,1,1> > dFdw = computeDFdw(q); // the actual system matrix - Dune::array<ctype,dim+1> w = barycentricCoordinates(local); + std::vector<Dune::FieldVector<ctype,1> > wNested; + localFiniteElement_.localBasis().evaluateFunction(local,wNested); + + std::vector<ctype> w(wNested.size()); + for (size_t i=0; i<w.size(); i++) + w[i] = wNested[i][0]; + AverageDistanceAssembler<TargetSpace,dim+1> assembler(coefficients_, w); Dune::FieldMatrix<ctype,embeddedDim,embeddedDim> dFdq(0); @@ -468,8 +493,8 @@ evaluateDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>& } -template <int dim, class ctype, class TargetSpace> -void LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: +template <int dim, class ctype, class LocalFiniteElement, class TargetSpace> +void LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,TargetSpace>:: evaluateFDDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>& local, int coefficient, Tensor3<double,embeddedDim,embeddedDim,dim>& result) const @@ -485,8 +510,8 @@ evaluateFDDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim> aMinus[j] -= eps; cornersPlus[coefficient] = TargetSpace(aPlus); cornersMinus[coefficient] = TargetSpace(aMinus); - LocalGeodesicFEFunction<dim,double,TargetSpace> fPlus(cornersPlus); - LocalGeodesicFEFunction<dim,double,TargetSpace> fMinus(cornersMinus); + LocalGeodesicFEFunction<dim,double,LocalFiniteElement,TargetSpace> fPlus(cornersPlus); + LocalGeodesicFEFunction<dim,double,LocalFiniteElement,TargetSpace> fMinus(cornersMinus); Dune::FieldMatrix<double,TargetSpace::EmbeddedTangentVector::size,dim> hPlus = fPlus.evaluateDerivative(local); Dune::FieldMatrix<double,TargetSpace::EmbeddedTangentVector::size,dim> hMinus = fMinus.evaluateDerivative(local); @@ -523,8 +548,8 @@ evaluateFDDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim> \tparam dim Dimension of the reference element \tparam ctype Type used for coordinates on the reference element */ -template <int dim, class ctype> -class LocalGeodesicFEFunction<dim,ctype,RigidBodyMotion<3> > +template <int dim, class ctype, class LocalFiniteElement> +class LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,RigidBodyMotion<3> > { typedef RigidBodyMotion<3> TargetSpace; @@ -545,7 +570,7 @@ public: for (int i=0; i<dim+1; i++) orientationCoefficients[i] = coefficients[i].q; - orientationFEFunction_ = std::auto_ptr<LocalGeodesicFEFunction<dim,ctype,Rotation<3,double> > > (new LocalGeodesicFEFunction<dim,ctype,Rotation<3,double> >(orientationCoefficients)); + orientationFEFunction_ = std::auto_ptr<LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,Rotation<3,double> > > (new LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,Rotation<3,double> >(orientationCoefficients)); } @@ -665,7 +690,7 @@ private: Dune::array<Dune::FieldVector<double,3>, dim+1> translationCoefficients_; - std::auto_ptr<LocalGeodesicFEFunction<dim,ctype,Rotation<3,double> > > orientationFEFunction_; + std::auto_ptr<LocalGeodesicFEFunction<dim,ctype,LocalFiniteElement,Rotation<3,double> > > orientationFEFunction_; }; diff --git a/dune/gfe/localgeodesicfestiffness.hh b/dune/gfe/localgeodesicfestiffness.hh index 36e1a52d..a307574d 100644 --- a/dune/gfe/localgeodesicfestiffness.hh +++ b/dune/gfe/localgeodesicfestiffness.hh @@ -7,7 +7,7 @@ #include <dune/istl/matrix.hh> -template<class GridView, class TargetSpace> +template<class GridView, class LocalFiniteElement, class TargetSpace> class LocalGeodesicFEStiffness { // grid types @@ -40,17 +40,20 @@ public: */ virtual void assembleHessian(const Entity& e, - const Dune::array<TargetSpace,gridDim+1>& localSolution); + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution); /** \brief Compute the energy at the current configuration */ virtual RT energy (const Entity& e, - const Dune::array<TargetSpace,gridDim+1>& localSolution) const = 0; + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution) const = 0; /** \brief Assemble the element gradient of the energy functional The default implementation in this class uses a finite difference approximation */ virtual void assembleGradient(const Entity& element, - const Dune::array<TargetSpace,gridDim+1>& solution, + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& solution, std::vector<typename TargetSpace::TangentVector>& gradient) const; // assembled data @@ -59,10 +62,11 @@ public: }; -template <class GridView, class TargetSpace> -void LocalGeodesicFEStiffness<GridView, TargetSpace>:: +template <class GridView, class LocalFiniteElement, class TargetSpace> +void LocalGeodesicFEStiffness<GridView, LocalFiniteElement, TargetSpace>:: assembleGradient(const Entity& element, - const Dune::array<TargetSpace,gridDim+1>& localSolution, + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution, std::vector<typename TargetSpace::TangentVector>& localGradient) const { @@ -74,8 +78,8 @@ assembleGradient(const Entity& element, localGradient.resize(localSolution.size()); - Dune::array<TargetSpace,gridDim+1> forwardSolution = localSolution; - Dune::array<TargetSpace,gridDim+1> backwardSolution = localSolution; + std::vector<TargetSpace> forwardSolution = localSolution; + std::vector<TargetSpace> backwardSolution = localSolution; for (size_t i=0; i<localSolution.size(); i++) { @@ -93,7 +97,7 @@ assembleGradient(const Entity& element, forwardSolution[i] = TargetSpace::exp(localSolution[i], forwardCorrection); backwardSolution[i] = TargetSpace::exp(localSolution[i], backwardCorrection); - localGradient[i][j] = (energy(element,forwardSolution) - energy(element,backwardSolution)) / (2*eps); + localGradient[i][j] = (energy(element,localFiniteElement,forwardSolution) - energy(element,localFiniteElement, backwardSolution)) / (2*eps); } @@ -108,22 +112,20 @@ assembleGradient(const Entity& element, // /////////////////////////////////////////////////////////// // Compute gradient by finite-difference approximation // /////////////////////////////////////////////////////////// -template <class GridType, class TargetSpace> -void LocalGeodesicFEStiffness<GridType, TargetSpace>:: +template <class GridType, class LocalFiniteElement, class TargetSpace> +void LocalGeodesicFEStiffness<GridType, LocalFiniteElement, TargetSpace>:: assembleHessian(const Entity& element, - const Dune::array<TargetSpace,gridDim+1>& localSolution) + const LocalFiniteElement& localFiniteElement, + const std::vector<TargetSpace>& localSolution) { - // 1 degree of freedom per element vertex - size_t nDofs = element.template count<gridDim>(); + // Number of degrees of freedom for this element + size_t nDofs = localSolution.size(); // Clear assemble data A_.setSize(nDofs, nDofs); A_ = 0; - - - const double eps = 1e-4; std::vector<Dune::FieldMatrix<double,blocksize,embeddedBlocksize> > B(localSolution.size()); @@ -132,7 +134,7 @@ assembleHessian(const Entity& element, // Precompute negative energy at the current configuration // (negative because that is how we need it as part of the 2nd-order fd formula) - double centerValue = -energy(element, localSolution); + double centerValue = -energy(element, localFiniteElement, localSolution); // Precompute energy infinitesimal corrections in the directions of the local basis vectors std::vector<Dune::array<double,blocksize> > forwardEnergy(nDofs); @@ -144,14 +146,14 @@ assembleHessian(const Entity& element, Dune::FieldVector<double,embeddedBlocksize> minusEpsXi = epsXi; minusEpsXi *= -1; - Dune::array<TargetSpace,gridDim+1> forwardSolution = localSolution; - Dune::array<TargetSpace,gridDim+1> backwardSolution = localSolution; + std::vector<TargetSpace> forwardSolution = localSolution; + std::vector<TargetSpace> backwardSolution = localSolution; forwardSolution[i] = TargetSpace::exp(localSolution[i],epsXi); backwardSolution[i] = TargetSpace::exp(localSolution[i],minusEpsXi); - forwardEnergy[i][i2] = energy(element, forwardSolution); - backwardEnergy[i][i2] = energy(element, backwardSolution); + forwardEnergy[i][i2] = energy(element, localFiniteElement, forwardSolution); + backwardEnergy[i][i2] = energy(element, localFiniteElement, backwardSolution); } @@ -169,8 +171,8 @@ assembleHessian(const Entity& element, Dune::FieldVector<double,embeddedBlocksize> minusEpsXi = epsXi; minusEpsXi *= -1; Dune::FieldVector<double,embeddedBlocksize> minusEpsEta = epsEta; minusEpsEta *= -1; - Dune::array<TargetSpace,gridDim+1> forwardSolutionXiEta = localSolution; - Dune::array<TargetSpace,gridDim+1> backwardSolutionXiEta = localSolution; + std::vector<TargetSpace> forwardSolutionXiEta = localSolution; + std::vector<TargetSpace> backwardSolutionXiEta = localSolution; if (i==j) forwardSolutionXiEta[i] = TargetSpace::exp(localSolution[i],epsXi+epsEta); @@ -186,8 +188,8 @@ assembleHessian(const Entity& element, backwardSolutionXiEta[j] = TargetSpace::exp(localSolution[j],minusEpsEta); } - double forwardValue = energy(element, forwardSolutionXiEta) - forwardEnergy[i][i2] - forwardEnergy[j][j2]; - double backwardValue = energy(element, backwardSolutionXiEta) - backwardEnergy[i][i2] - backwardEnergy[j][j2]; + double forwardValue = energy(element, localFiniteElement, forwardSolutionXiEta) - forwardEnergy[i][i2] - forwardEnergy[j][j2]; + double backwardValue = energy(element, localFiniteElement, backwardSolutionXiEta) - backwardEnergy[i][i2] - backwardEnergy[j][j2]; A_[i][j][i2][j2] = 0.5 * (forwardValue - 2*centerValue + backwardValue) / (eps*eps); diff --git a/dune/gfe/riemanniantrsolver.cc b/dune/gfe/riemanniantrsolver.cc index d9f20e12..19b327f8 100644 --- a/dune/gfe/riemanniantrsolver.cc +++ b/dune/gfe/riemanniantrsolver.cc @@ -12,6 +12,7 @@ #include <dune/solvers/iterationsteps/trustregiongsstep.hh> #include <dune/solvers/iterationsteps/mmgstep.hh> #include <dune/solvers/transferoperators/truncatedcompressedmgtransfer.hh> +#include <dune/solvers/transferoperators/p2top1mgtransfer.hh> #include <dune/solvers/transferoperators/mandelobsrestrictor.hh> #include <dune/solvers/solvers/iterativesolver.hh> #include "maxnormtrustregion.hh" @@ -23,7 +24,11 @@ template <class GridType, class TargetSpace> void RiemannianTrustRegionSolver<GridType,TargetSpace>:: setup(const GridType& grid, - const GeodesicFEAssembler<typename GridType::LeafGridView,TargetSpace>* assembler, +#ifdef HIGHER_ORDER + const GeodesicFEAssembler<P2NodalBasis<typename GridType::LeafGridView,double>, TargetSpace>* assembler, +#else + const GeodesicFEAssembler<P1NodalBasis<typename GridType::LeafGridView,double>, TargetSpace>* assembler, +#endif const SolutionType& x, const Dune::BitSetVector<blocksize>& dirichletNodes, double tolerance, @@ -123,9 +128,19 @@ setup(const GridType& grid, // ////////////////////////////////////////////////////////// hasObstacle_.resize(numLevels); +#ifdef HIGHER_ORDER + P2NodalBasis<typename GridType::LeafGridView,double> p2Basis(grid_->leafView()); + P1NodalBasis<typename GridType::LeafGridView,double> p1Basis(grid_->leafView()); + + hasObstacle_.back().resize(p2Basis.size(), true); + + for (int i=0; i<hasObstacle_.size()-1; i++) + hasObstacle_[i].resize(grid_->size(i+1, gridDim),true); +#else for (int i=0; i<hasObstacle_.size(); i++) hasObstacle_[i].resize(grid_->size(i, gridDim),true); - +#endif + // //////////////////////////////////// // Create the transfer operators // //////////////////////////////////// @@ -134,12 +149,27 @@ setup(const GridType& grid, mmgStep->mgTransfer_.resize(numLevels-1); +#ifdef HIGHER_ORDER + if (numLevels>1) { + P2toP1MGTransfer<CorrectionType>* topTransferOp = new P2toP1MGTransfer<CorrectionType>; + topTransferOp->setup(p2Basis,p1Basis); + mmgStep->mgTransfer_.back() = topTransferOp; + + for (int i=0; i<mmgStep->mgTransfer_.size()-1; i++){ + TruncatedCompressedMGTransfer<CorrectionType>* newTransferOp = new TruncatedCompressedMGTransfer<CorrectionType>; + newTransferOp->setup(*grid_,i+1,i+2); + mmgStep->mgTransfer_[i] = newTransferOp; + } + + } + +#else for (int i=0; i<mmgStep->mgTransfer_.size(); i++){ TruncatedCompressedMGTransfer<CorrectionType>* newTransferOp = new TruncatedCompressedMGTransfer<CorrectionType>; newTransferOp->setup(*grid_,i,i+1); mmgStep->mgTransfer_[i] = newTransferOp; } - +#endif } @@ -180,6 +210,10 @@ void RiemannianTrustRegionSolver<GridType,TargetSpace>::solve() for (int i=0; i<maxTrustRegionSteps_; i++) { +/* std::cout << "current iterate:\n"; + for (int j=0; j<x_.size(); j++) + std::cout << x_[j] << std::endl;*/ + Dune::Timer totalTimer; if (this->verbosity_ == Solver::FULL) { std::cout << "----------------------------------------------------" << std::endl; @@ -206,7 +240,9 @@ void RiemannianTrustRegionSolver<GridType,TargetSpace>::solve() // The right hand side is the _negative_ gradient rhs *= -1; - +/* std::cout << "rhs:\n" << rhs << std::endl; + std::cout << "matrix[0][0]:\n" << (*hessianMatrix_)[0][0] << std::endl;*/ + // ////////////////////////////////////////////////////////////////////// // Modify matrix and right-hand side to account for Dirichlet values // ////////////////////////////////////////////////////////////////////// @@ -346,11 +382,14 @@ void RiemannianTrustRegionSolver<GridType,TargetSpace>::solve() for (int j=0; j<newIterate.size(); j++) newIterate[j] = TargetSpace::exp(newIterate[j], corr[j]); #else + //std::cout << "embedded correction:\n"; for (int j=0; j<newIterate.size(); j++) { Dune::FieldMatrix<double,TargetSpace::TangentVector::dimension,TargetSpace::EmbeddedTangentVector::dimension> B = x_[j].orthonormalFrame(); Dune::FieldVector<double,TargetSpace::EmbeddedTangentVector::dimension> embeddedCorr(0); + //std::cout << "B[" << j << "]:\n" << B << std::endl; B.mtv(corr[j], embeddedCorr); newIterate[j] = TargetSpace::exp(newIterate[j], embeddedCorr); + //std::cout << embeddedCorr << " " << newIterate[j] << std::endl; } #endif diff --git a/dune/gfe/riemanniantrsolver.hh b/dune/gfe/riemanniantrsolver.hh index 6647e9f9..9912e07d 100644 --- a/dune/gfe/riemanniantrsolver.hh +++ b/dune/gfe/riemanniantrsolver.hh @@ -42,7 +42,11 @@ public: /** \brief Set up the solver using a monotone multigrid method as the inner solver */ void setup(const GridType& grid, - const GeodesicFEAssembler<typename GridType::LeafGridView, TargetSpace>* assembler, +#ifdef HIGHER_ORDER + const GeodesicFEAssembler<P2NodalBasis<typename GridType::LeafGridView,double>, TargetSpace>* assembler, +#else + const GeodesicFEAssembler<P1NodalBasis<typename GridType::LeafGridView,double>, TargetSpace>* assembler, +#endif const SolutionType& x, const Dune::BitSetVector<blocksize>& dirichletNodes, double tolerance, @@ -97,7 +101,11 @@ protected: std::auto_ptr<MatrixType> hessianMatrix_; /** \brief The assembler for the material law */ - const GeodesicFEAssembler<typename GridType::LeafGridView, TargetSpace>* assembler_; +#ifdef HIGHER_ORDER + const GeodesicFEAssembler<P2NodalBasis<typename GridType::LeafGridView,double>, TargetSpace>* assembler_; +#else + const GeodesicFEAssembler<P1NodalBasis<typename GridType::LeafGridView,double>, TargetSpace>* assembler_; +#endif /** \brief The solver for the quadratic inner problems */ std::shared_ptr<Solver> innerSolver_; -- GitLab