From 2b0449b0312b884328b30cb0f254c856e5638ec5 Mon Sep 17 00:00:00 2001
From: Oliver Sander <sander@igpm.rwth-aachen.de>
Date: Mon, 27 May 2013 13:37:05 +0000
Subject: [PATCH] Set up a transfer operator between two arbitrary grid views
 of one grid

This is needed, e.g., to implement two-level Schwarz methods.
It includes the previous 'setup' method for two adjacent level views
as a special case.  I haven't touched the old method, but we may
consider removing it.

[[Imported from SVN: r8759]]
---
 .../genericmultigridtransfer.hh               | 173 ++++++++++++++++++
 1 file changed, 173 insertions(+)

diff --git a/dune/solvers/transferoperators/genericmultigridtransfer.hh b/dune/solvers/transferoperators/genericmultigridtransfer.hh
index fdc9522..133817d 100644
--- a/dune/solvers/transferoperators/genericmultigridtransfer.hh
+++ b/dune/solvers/transferoperators/genericmultigridtransfer.hh
@@ -223,6 +223,179 @@ public:
     }
 
 
+    /** \brief Set up transfer operator between two arbitrary grid views of the same grid 
+     
+       The 'fine' grid view gvFine is expected to be a refinement of the 'coarse' one gvCoarse.
+     
+       \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)
+    {
+        typedef typename TransferOperatorType::block_type TransferMatrixBlock;
+        typedef typename GridViewCoarse::ctype ctype;
+        typedef typename GridViewCoarse::Grid GridType;
+
+        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);
+
+        // 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);
+
+        typedef typename GridViewFine::template Codim<0>::Iterator ElementIterator;
+
+        ElementIterator fIt    = gvFine.template begin<0>();
+        ElementIterator fEndIt = gvFine.template end<0>();
+
+
+        // ///////////////////////////////////////////
+        // Determine the indices present in the matrix
+        // /////////////////////////////////////////////////
+        Dune::MatrixIndexSet indices(rows, cols);
+
+        for (; fIt != fEndIt; ++fIt) {
+
+            const Dune::ReferenceElement<ctype,dim>& 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.
+            typename GridViewFine::template Codim<0>::EntityPointer ancestor(fIt);
+            
+            while (not gvCoarse.contains(ancestor) && ancestor->level() != 0 ) {
+                
+                typename GridType::template Codim<0>::LocalGeometry 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 (fIt = gvFine.template begin<0>(); fIt != fEndIt; ++fIt) {
+
+
+            const Dune::ReferenceElement<ctype,dim>& 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.
+            typename GridViewFine::template Codim<0>::EntityPointer ancestor(fIt);
+            
+            while (not gvCoarse.contains(ancestor) && ancestor->level() != 0 ) {
+                
+                typename GridType::template Codim<0>::LocalGeometry 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]);
+                    }
+                }
+            }
+
+        }
+
+    }
+
     //! Multiply the vector f from the right to the prolongation matrix
     template<class TransferOperatorType, class DiscFuncType>
     static void prolong(const TransferOperatorType& matrix, const DiscFuncType& f, DiscFuncType &t)
-- 
GitLab