Skip to content
Snippets Groups Projects
gfedifferencenormsquared.hh 12.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • #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