diff --git a/dune/solvers/transferoperators/genericmultigridtransfer.hh b/dune/solvers/transferoperators/genericmultigridtransfer.hh index 64352907d7f8edab35a3507727e3b5ee78be1a8e..4be44e1836409e45e795befbd3169c3da6aafcc2 100644 --- a/dune/solvers/transferoperators/genericmultigridtransfer.hh +++ b/dune/solvers/transferoperators/genericmultigridtransfer.hh @@ -8,6 +8,9 @@ #include <dune/common/fmatrix.hh> #include <dune/common/bitsetvector.hh> +#include <dune/fufem/assemblers/basisinterpolationmatrixassembler.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> + #include <dune/geometry/referenceelements.hh> #include <dune/localfunctions/lagrange/pqkfactory.hh> @@ -64,146 +67,12 @@ public: template<class TransferOperatorType, class GridType, class field_type> - static void setup(TransferOperatorType& matrix, const GridType& grid, int cL, int fL) + static void setup(TransferOperatorType& matrix, const GridType& grid, int cL, int fL, int order = 1) { - typedef typename TransferOperatorType::block_type TransferMatrixBlock; - typedef typename GridType::ctype ctype; - - if (fL != cL+1) - DUNE_THROW(Dune::Exception, "The two function spaces don't belong to consecutive levels!"); - - const int dim = GridType::dimension; - - const typename GridType::Traits::LevelIndexSet& coarseIndexSet = grid.levelIndexSet(cL); - const typename GridType::Traits::LevelIndexSet& fineIndexSet = grid.levelIndexSet(fL); - - int rows = grid.size(fL, dim); - int cols = grid.size(cL, dim); - - // A factory for the shape functions - typedef typename Dune::PQkLocalFiniteElementCache<ctype, field_type, dim, 1> P1FECache; - typedef typename P1FECache::FiniteElementType FEType; - P1FECache p1FECache; - - matrix.setSize(rows,cols); - matrix.setBuildMode(TransferOperatorType::random); - - // /////////////////////////////////////////// - // Determine the indices present in the matrix - // ///////////////////////////////////////////////// - Dune::MatrixIndexSet indices(rows, cols); - - for (const auto& cIt : elements(grid.levelGridView(cL))) { - - typedef typename GridType::template Codim<0>::Entity EntityType; - - // Get local finite element - const FEType& coarseBaseSet = p1FECache.get(cIt.type()); - - const size_t numCoarseBaseFct = coarseBaseSet.localBasis().size(); - - // preallocate vector for function evaluations - std::vector<Dune::FieldVector<field_type,1> > values(numCoarseBaseFct); - - for (const auto& fIt : descendantElements(cIt,fL)) { - - if (fIt.level()==cIt.level()) - continue; - - const auto& fineRefElement = Dune::ReferenceElements<ctype, dim>::general(fIt.type()); - - const typename EntityType::LocalGeometry& fGeometryInFather = fIt.geometryInFather(); - - // Get local finite element - const FEType& fineBaseSet = p1FECache.get(fIt.type()); - - const size_t numFineBaseFct = fineBaseSet.localBasis().size(); - - - for (size_t j=0; j<numFineBaseFct; j++) - { - const Dune::LocalKey& jLocalKey = fineBaseSet.localCoefficients().localKey(j); - - int globalFine = fineIndexSet.subIndex(fIt, jLocalKey.subEntity(), jLocalKey.codim()); - - Dune::FieldVector<ctype, dim> fineBasePosition = fineRefElement.position(jLocalKey.subEntity(), jLocalKey.codim()); - Dune::FieldVector<ctype, dim> local = fGeometryInFather.global(fineBasePosition); - - // Evaluate coarse grid base functions - coarseBaseSet.localBasis().evaluateFunction(local, values); - - for (size_t i=0; i<numCoarseBaseFct; i++) - { - if (values[i] > 0.001) - { - const Dune::LocalKey& iLocalKey = coarseBaseSet.localCoefficients().localKey(i); - int globalCoarse = coarseIndexSet.subIndex(cIt, iLocalKey.subEntity(), iLocalKey.codim()); - indices.add(globalFine, globalCoarse); - } - } - } - - } - - } - - indices.exportIdx(matrix); - - // ///////////////////////////////////////////// - // Compute the matrix - // ///////////////////////////////////////////// - - for (const auto& cIt : elements(grid.levelGridView(cL))) { - - // Get local finite element - const FEType& coarseBaseSet = p1FECache.get(cIt.type()); - - const size_t numCoarseBaseFct = coarseBaseSet.localBasis().size(); - - typedef typename GridType::template Codim<0>::Entity EntityType; - - // preallocate vector for function evaluations - std::vector<Dune::FieldVector<field_type,1> > values(numCoarseBaseFct); - - for (const auto& fIt : descendantElements(cIt,fL)) { - - if (fIt.level()==cIt.level()) - continue; - - const auto& fineRefElement = Dune::ReferenceElements<ctype, dim>::general(fIt.type()); - - const typename EntityType::LocalGeometry& fGeometryInFather = fIt.geometryInFather(); - - // Get local finite element - const FEType& fineBaseSet = p1FECache.get(fIt.type()); - - const size_t numFineBaseFct = fineBaseSet.localBasis().size(); - - for (size_t j=0; j<numFineBaseFct; j++) - { - const Dune::LocalKey& jLocalKey = fineBaseSet.localCoefficients().localKey(j); - - int globalFine = fineIndexSet.subIndex(fIt, jLocalKey.subEntity(), jLocalKey.codim()); - - Dune::FieldVector<ctype, dim> fineBasePosition = fineRefElement.position(jLocalKey.subEntity(), jLocalKey.codim()); - Dune::FieldVector<ctype, dim> local = fGeometryInFather.global(fineBasePosition); - - // Evaluate coarse grid base functions - coarseBaseSet.localBasis().evaluateFunction(local, values); - - for (size_t i=0; i<numCoarseBaseFct; i++) - { - if (values[i] > 0.001) - { - const Dune::LocalKey& iLocalKey = coarseBaseSet.localCoefficients().localKey(i); - int globalCoarse = coarseIndexSet.subIndex(cIt, iLocalKey.subEntity(), iLocalKey.codim()); - - matrix[globalFine][globalCoarse] = Dune::ScaledIdentityMatrix<ctype,TransferMatrixBlock::rows>(values[i]); - } - } - } - } - } + // call function overload with two gridViews + auto fineGridView = grid.levelGridView(fL); + auto coarseGridView = grid.levelGridView(cL); + setup(matrix, coarseGridView, fineGridView, order); } @@ -213,161 +82,15 @@ public: \param matrix The matrix object to assemble into */ - template<class TransferOperatorType, class GridViewCoarse, class GridViewFine, class field_type> - static void setup(TransferOperatorType& matrix, const GridViewCoarse& gvCoarse, const GridViewFine& gvFine) + template<class TransferOperatorType, class GridViewCoarse, class GridViewFine, class field_type = double> + static void setup(TransferOperatorType& matrix, const GridViewCoarse& gvCoarse, const GridViewFine& gvFine, int order = 1) { - typedef typename TransferOperatorType::block_type TransferMatrixBlock; - typedef typename GridViewCoarse::ctype ctype; - - const int dim = GridViewCoarse::dimension; - - const typename GridViewCoarse::IndexSet& coarseIndexSet = gvCoarse.indexSet(); - const typename GridViewFine::IndexSet& fineIndexSet = gvFine.indexSet(); - - int rows = gvFine.size(dim); - int cols = gvCoarse.size(dim); + // create Lagrange bases of given order for fine and coarse grid level + auto fineBasis = Dune::Functions::BasisFactory::makeBasis(gvFine, Dune::Functions::BasisFactory::lagrange(order)); + auto coarseBasis = Dune::Functions::BasisFactory::makeBasis(gvCoarse,Dune::Functions::BasisFactory::lagrange(order)); - // A factory for the shape functions - typedef typename Dune::PQkLocalFiniteElementCache<ctype, field_type, dim, 1> P1FECache; - typedef typename P1FECache::FiniteElementType FEType; - P1FECache p1FECache; - - matrix.setSize(rows,cols); - matrix.setBuildMode(TransferOperatorType::random); - - // /////////////////////////////////////////// - // Determine the indices present in the matrix - // ///////////////////////////////////////////////// - - Dune::MatrixIndexSet indices(rows, cols); - - for (const auto& fIt : elements(gvFine)) { - - const auto& fineRefElement = Dune::ReferenceElements<ctype, dim>::general(fIt.type()); - - // Get local finite element - const FEType& fineBaseSet = p1FECache.get(fIt.type());; - - const size_t numFineBaseFct = fineBaseSet.localBasis().size(); - - std::vector<Dune::FieldVector<ctype,dim> > local(numFineBaseFct); - - for (size_t i=0; i<numFineBaseFct; i++) - { - const Dune::LocalKey& iLocalKey = fineBaseSet.localCoefficients().localKey(i); - local[i] = fineRefElement.position(iLocalKey.subEntity(), iLocalKey.codim()); - } - - // Get ancestor element in the coarse grid view, and the local position there. - auto ancestor = fIt; - - while (not gvCoarse.contains(ancestor) && ancestor.level() != 0 ) { - - auto geometryInFather = ancestor.geometryInFather(); - - for (size_t i=0; i<numFineBaseFct; i++) - local[i] = geometryInFather.global(local[i]); - ancestor = ancestor.father(); - - } - - assert(gvCoarse.contains(ancestor)); - - for (size_t j=0; j<numFineBaseFct; j++) - { - // Get local finite element - const FEType& coarseBaseSet = p1FECache.get(ancestor.type()); - - const size_t numCoarseBaseFct = coarseBaseSet.localBasis().size(); - - // preallocate vector for function evaluations - std::vector<Dune::FieldVector<field_type,1> > values(numCoarseBaseFct); - - // Evaluate coarse grid base functions - coarseBaseSet.localBasis().evaluateFunction(local[j], values); - - const Dune::LocalKey& jLocalKey = fineBaseSet.localCoefficients().localKey(j); - int globalFine = fineIndexSet.subIndex(fIt, jLocalKey.subEntity(), jLocalKey.codim()); - - for (size_t i=0; i<numCoarseBaseFct; i++) - { - if (values[i] > 0.001) - { - const Dune::LocalKey& iLocalKey = coarseBaseSet.localCoefficients().localKey(i); - int globalCoarse = coarseIndexSet.subIndex(ancestor, iLocalKey.subEntity(), iLocalKey.codim()); - indices.add(globalFine, globalCoarse); - } - } - } - - } - - indices.exportIdx(matrix); - - // ///////////////////////////////////////////// - // Compute the matrix - // ///////////////////////////////////////////// - for (const auto& fIt : elements(gvFine)) { - - - const auto& fineRefElement = Dune::ReferenceElements<ctype, dim>::general(fIt.type()); - - // Get local finite element - const FEType& fineBaseSet = p1FECache.get(fIt.type());; - - const size_t numFineBaseFct = fineBaseSet.localBasis().size(); - - std::vector<Dune::FieldVector<ctype,dim> > local(numFineBaseFct); - - for (size_t i=0; i<numFineBaseFct; i++) - { - const Dune::LocalKey& iLocalKey = fineBaseSet.localCoefficients().localKey(i); - local[i] = fineRefElement.position(iLocalKey.subEntity(), iLocalKey.codim()); - } - - // Get ancestor element in the coarse grid view, and the local position there. - auto ancestor = fIt; - - while (not gvCoarse.contains(ancestor) && ancestor.level() != 0 ) { - - auto geometryInFather = ancestor.geometryInFather(); - - for (size_t i=0; i<numFineBaseFct; i++) - local[i] = geometryInFather.global(local[i]); - ancestor = ancestor.father(); - - } - - assert(gvCoarse.contains(ancestor)); - - for (size_t j=0; j<numFineBaseFct; j++) - { - // Get local finite element - const FEType& coarseBaseSet = p1FECache.get(ancestor.type()); - - const size_t numCoarseBaseFct = coarseBaseSet.localBasis().size(); - - // preallocate vector for function evaluations - std::vector<Dune::FieldVector<field_type,1> > values(numCoarseBaseFct); - - // Evaluate coarse grid base functions - coarseBaseSet.localBasis().evaluateFunction(local[j], values); - - const Dune::LocalKey& jLocalKey = fineBaseSet.localCoefficients().localKey(j); - int globalFine = fineIndexSet.subIndex(fIt, jLocalKey.subEntity(), jLocalKey.codim()); - - for (size_t i=0; i<numCoarseBaseFct; i++) - { - if (values[i] > 0.001) - { - const Dune::LocalKey& iLocalKey = coarseBaseSet.localCoefficients().localKey(i); - int globalCoarse = coarseIndexSet.subIndex(ancestor, iLocalKey.subEntity(), iLocalKey.codim()); - - matrix[globalFine][globalCoarse] = Dune::ScaledIdentityMatrix<ctype,TransferMatrixBlock::rows>(values[i]); - } - } - } - } + // call generic method to assemble the transfer matrix + assembleGlobalBasisTransferMatrix(matrix,coarseBasis,fineBasis); } //! Multiply the vector f from the right to the prolongation matrix