Skip to content
Snippets Groups Projects
Commit ce928b33 authored by Oliver Sander's avatar Oliver Sander Committed by sander@FU-BERLIN.DE
Browse files

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]]
parent cec5d344
No related branches found
No related tags found
No related merge requests found
#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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment