From ce928b3310dcb1ec2c0d7f142789809ef9c8ca9d Mon Sep 17 00:00:00 2001
From: Oliver Sander <sander@igpm.rwth-aachen.de>
Date: Sun, 1 Jan 2012 16:37:29 +0000
Subject: [PATCH] Helper method which computes the energy norm (squared) of the
 difference of the fe functions on two different refinements of the same base
 grid.

[[Imported from SVN: r8331]]
---
 dune/gfe/gfedifferencenormsquared.hh | 288 +++++++++++++++++++++++++++
 1 file changed, 288 insertions(+)
 create mode 100644 dune/gfe/gfedifferencenormsquared.hh

diff --git a/dune/gfe/gfedifferencenormsquared.hh b/dune/gfe/gfedifferencenormsquared.hh
new file mode 100644
index 00000000..9b452e07
--- /dev/null
+++ b/dune/gfe/gfedifferencenormsquared.hh
@@ -0,0 +1,288 @@
+#ifndef GFE_DIFFERENCE_NORM_SQUARED_HH
+#define GFE_DIFFERENCE_NORM_SQUARED_HH
+
+/** \file
+    \brief Helper method which computes the energy norm (squared) of the difference of
+    the fe functions on two different refinements of the same base grid.
+*/
+
+#include <dune/geometry/type.hh>
+#include <dune/common/fvector.hh>
+
+#include <dune/grid/common/mcmgmapper.hh>
+
+#include <dune/fufem/assemblers/localoperatorassembler.hh>
+
+#include <dune/gfe/globalgeodesicfefunction.hh>
+
+template <class Basis, class TargetSpace>
+class GFEDifferenceNormSquared {
+
+    typedef typename Basis::GridView GridView;
+    typedef typename Basis::GridView::Grid GridType;
+    
+    // Grid dimension
+    const static int dim = GridType::dimension;
+
+    /** \brief Check whether given local coordinates are contained in the reference element
+        \todo This method exists in the Dune grid interface!  But we need the eps.
+    */
+    static bool checkInside(const Dune::GeometryType& type,
+                            const Dune::FieldVector<double, dim> &loc,
+                            double eps)
+    {
+        switch (type.dim()) {
+            
+        case 0: // vertex
+            return false;
+        case 1: // line
+            return -eps <= loc[0] && loc[0] <= 1+eps;
+        case 2: 
+            
+            if (type.isSimplex()) {
+                return -eps <= loc[0] && -eps <= loc[1] && (loc[0]+loc[1])<=1+eps;
+            } else if (type.isCube()) {
+                return -eps <= loc[0] && loc[0] <= 1+eps
+                    && -eps <= loc[1] && loc[1] <= 1+eps;
+            } else {
+                DUNE_THROW(Dune::GridError, "checkInside():  ERROR:  Unknown type " << type << " found!");
+            }
+            
+        case 3: 
+            if (type.isSimplex()) {
+                return -eps <= loc[0] && -eps <= loc[1] && -eps <= loc[2]
+                    && (loc[0]+loc[1]+loc[2]) <= 1+eps;
+            } else if (type.isPyramid()) {
+                return -eps <= loc[0] && -eps <= loc[1] && -eps <= loc[2]
+                    && (loc[0]+loc[2]) <= 1+eps
+                    && (loc[1]+loc[2]) <= 1+eps;
+            } else if (type.isPrism()) {
+                return -eps <= loc[0] && -eps <= loc[1] 
+                    && (loc[0]+loc[1])<= 1+eps
+                    && -eps <= loc[2] && loc[2] <= 1+eps;
+            } else if (type.isCube()) {
+                return -eps <= loc[0] && loc[0] <= 1+eps
+                    && -eps <= loc[1] && loc[1] <= 1+eps
+                    && -eps <= loc[2] && loc[2] <= 1+eps;
+            }else {
+                DUNE_THROW(Dune::GridError, "checkInside():  ERROR:  Unknown type " << type << " found!");
+            }
+        default:
+            DUNE_THROW(Dune::GridError, "checkInside():  ERROR:  Unknown type " << type << " found!");
+        }
+        
+    }
+    
+    
+    /** \brief Coordinate function in one variable, constant in the others 
+ 
+    This is used to extract the positions of the Lagrange nodes.
+    */
+    struct CoordinateFunction
+        : public Dune::VirtualFunction<Dune::FieldVector<double,dim>, Dune::FieldVector<double,1> >
+    {
+        CoordinateFunction(int d)
+        : d_(d)
+        {}
+    
+        void evaluate(const Dune::FieldVector<double, dim>& x, Dune::FieldVector<double,1>& out) const {
+            out[0] = x[d_];
+        }
+
+        //
+        int d_;
+    };
+
+public:
+
+    static void interpolate(const GridType& sourceGrid, 
+                            const std::vector<TargetSpace>& source,
+                            const GridType& targetGrid, 
+                            std::vector<TargetSpace>& target)
+    {
+        // Create a leaf function, which we need to be able to call 'evalall()'
+        Basis sourceBasis(sourceGrid.leafView());
+        GlobalGeodesicFEFunction<Basis,TargetSpace> sourceFunction(sourceBasis, source);
+
+        Basis targetBasis(targetGrid.leafView());
+
+        // ///////////////////////////////////////////////////////////////////////////////////////////
+        //   Prolong the adaptive solution onto the uniform grid in order to make it comparable
+        // ///////////////////////////////////////////////////////////////////////////////////////////
+        
+        target.resize(targetBasis.size());
+        
+        // handle each dof only once
+        Dune::BitSetVector<1> handled(targetBasis.size(), false);
+
+        typename GridView::template Codim<0>::Iterator eIt    = targetGrid.template leafbegin<0>();
+        typename GridView::template Codim<0>::Iterator eEndIt = targetGrid.template leafend<0>();
+        
+        // Loop over all dofs by looping over all elements
+        for (; eIt!=eEndIt; ++eIt) {
+
+            const typename Basis::LocalFiniteElement& targetLFE = targetBasis.getLocalFiniteElement(*eIt);
+
+            // Generate position of the Lagrange nodes
+            std::vector<Dune::FieldVector<double,dim> > lagrangeNodes(targetLFE.localBasis().size());
+        
+            for (int i=0; i<dim; i++) {
+                CoordinateFunction lFunction(i);
+                std::vector<Dune::FieldVector<double,1> > coordinates;
+                targetLFE.localInterpolation().interpolate(lFunction, coordinates);
+            
+                for (size_t j=0; j<coordinates.size(); j++)
+                    lagrangeNodes[j][i] = coordinates[j];
+            
+            }
+
+            for (size_t i=0; i<targetLFE.localCoefficients().size(); i++) {
+
+                typename GridType::template Codim<0>::EntityPointer element(eIt);
+
+                Dune::FieldVector<double,dim> pos = lagrangeNodes[i];
+                
+                if (handled[targetBasis.index(*eIt,i)][0])
+                    continue;
+
+                handled[targetBasis.index(*eIt,i)] = true;
+
+                assert(checkInside(element->type(), pos, 1e-7));
+                
+                // ////////////////////////////////////////////////////////////////////
+                // Get an element on the coarsest grid which contains the vertex and
+                // its local coordinates there
+                // ////////////////////////////////////////////////////////////////////
+                while (element->level() != 0){
+                    
+                    pos = element->geometryInFather().global(pos);
+                    element = element->father();
+                    
+                    assert(checkInside(element->type(), pos, 1e-7));
+                }
+                
+                // ////////////////////////////////////////////////////////////////////
+                //   Find the corresponding coarse grid element on the adaptive grid.
+                //   This is a linear algorithm, but we expect the coarse grid to be small.
+                // ////////////////////////////////////////////////////////////////////
+                Dune::LevelMultipleCodimMultipleGeomTypeMapper<GridType,Dune::MCMGElementLayout> uniformP0Mapper (targetGrid,  0);
+                Dune::LevelMultipleCodimMultipleGeomTypeMapper<GridType,Dune::MCMGElementLayout> adaptiveP0Mapper(sourceGrid, 0);
+                int coarseIndex = uniformP0Mapper.map(*element);
+                
+                typename GridType::template Codim<0>::LevelIterator adaptEIt    = sourceGrid.template lbegin<0>(0);
+                typename GridType::template Codim<0>::LevelIterator adaptEEndIt = sourceGrid.template lend<0>(0);
+                
+                for (; adaptEIt!=adaptEEndIt; ++adaptEIt)
+                    if (adaptiveP0Mapper.map(*adaptEIt) == coarseIndex)
+                        break;
+                
+                element = adaptEIt;
+                
+                // ////////////////////////////////////////////////////////////////////////
+                //   Find a corresponding point (not necessarily vertex) on the leaf level
+                //   of the adaptive grid.
+                // ////////////////////////////////////////////////////////////////////////
+                
+                while (!element->isLeaf()) {
+                    
+
+                    typename GridType::template Codim<0>::Entity::HierarchicIterator hIt    = element->hbegin(element->level()+1);
+                    typename GridType::template Codim<0>::Entity::HierarchicIterator hEndIt = element->hend(element->level()+1);
+                    
+                    Dune::FieldVector<double,dim> childPos;
+                    assert(checkInside(element->type(), pos, 1e-7));
+                    
+                    for (; hIt!=hEndIt; ++hIt) {
+                        
+                        childPos = hIt->geometryInFather().local(pos);
+                        if (checkInside(hIt->type(), childPos, 1e-7))
+                            break;
+                        
+                    }
+                    
+                    assert(hIt!=hEndIt);
+                    element = hIt;
+                    pos     = childPos;
+                    
+                }
+                
+                // ////////////////////////////////////////////////////////////////////////
+                //   Sample adaptive function
+                // ////////////////////////////////////////////////////////////////////////
+                sourceFunction.evaluateLocal(*element, pos, 
+                                            target[targetBasis.index(*eIt,i)]);
+                
+            }
+            
+        }
+        
+    }
+
+
+    template <int blocksize>
+    static double computeNormSquared(const GridType& grid, 
+                              const Dune::BlockVector<Dune::FieldVector<double,blocksize> >& x,
+                              const LocalOperatorAssembler<GridType,
+                              typename Basis::LocalFiniteElement,
+                              typename Basis::LocalFiniteElement,
+                              Dune::FieldMatrix<double,1,1> >* localStiffness)
+    {
+        // ///////////////////////////////////////////////////////////////////////////////////////////
+        //   Compute the energy norm 
+        // ///////////////////////////////////////////////////////////////////////////////////////////
+        
+        double energyNormSquared = 0;
+        Basis basis(grid.leafView());
+        Dune::Matrix<Dune::FieldMatrix<double,1,1> > localMatrix;
+        
+        typename GridType::template Codim<0>::LeafIterator eIt    = grid.template leafbegin<0>();
+        typename GridType::template Codim<0>::LeafIterator eEndIt = grid.template leafend<0>();
+        
+        for (; eIt!=eEndIt; ++eIt) {
+
+            size_t nLocalDofs = basis.getLocalFiniteElement(*eIt).localCoefficients().size();
+        
+            localMatrix.setSize(nLocalDofs,nLocalDofs);
+            
+            localStiffness->assemble(*eIt, localMatrix,
+                                     basis.getLocalFiniteElement(*eIt),
+                                     basis.getLocalFiniteElement(*eIt));
+            
+            for (size_t i=0; i<nLocalDofs; i++)
+                for (size_t j=0; j<nLocalDofs; j++)
+                    energyNormSquared += localMatrix[i][j][0][0] * (x[basis.index(*eIt,i)] * x[basis.index(*eIt,j)]);
+            
+        }
+        
+        return energyNormSquared;
+    }
+
+    static double compute(const GridType& uniformGrid, 
+                          const std::vector<TargetSpace>& uniformSolution,
+                          const GridType& adaptiveGrid, 
+                          const std::vector<TargetSpace>& adaptiveSolution,
+                          const LocalOperatorAssembler<GridType,
+                          typename Basis::LocalFiniteElement,
+                          typename Basis::LocalFiniteElement,
+                          Dune::FieldMatrix<double,1,1> >* localStiffness)
+    {
+        std::vector<TargetSpace> uniformAdaptiveSolution;
+
+        interpolate(adaptiveGrid, adaptiveSolution, uniformGrid, uniformAdaptiveSolution);
+
+        // Compute difference in the embedding space
+        Dune::BlockVector<typename TargetSpace::CoordinateType> difference(uniformSolution.size());
+        
+        for (size_t i=0; i<difference.size(); i++)
+            difference[i] = uniformAdaptiveSolution[i].globalCoordinates() - uniformSolution[i].globalCoordinates();
+
+        //std::cout << "new difference:\n" << difference << std::endl;
+//         std::cout << "new projected:\n" << std::endl;
+//         for (size_t i=0; i<difference.size(); i++)
+//             std::cout << uniformAdaptiveSolution[i].globalCoordinates() << std::endl;
+            
+        return computeNormSquared(uniformGrid, difference, localStiffness);
+    }
+};
+
+#endif
-- 
GitLab