-
Oliver Sander authored
[[Imported from SVN: r8871]]
Oliver Sander authored[[Imported from SVN: r8871]]
nestednesstest.cc 6.91 KiB
#include <config.h>
#include <fenv.h>
#include <iostream>
#include <dune/common/fvector.hh>
#include <dune/geometry/quadraturerules.hh>
#include <dune/localfunctions/lagrange/pqkfactory.hh>
#include <dune/gfe/rotation.hh>
#include <dune/gfe/realtuple.hh>
#include <dune/gfe/unitvector.hh>
#include <dune/gfe/localgeodesicfefunction.hh>
#include "multiindex.hh"
#include "valuefactory.hh"
const double eps = 1e-6;
using namespace Dune;
/** \brief Computes the diameter of a set */
template <class TargetSpace>
double diameter(const std::vector<TargetSpace>& v)
{
double d = 0;
for (size_t i=0; i<v.size(); i++)
for (size_t j=0; j<v.size(); j++)
d = std::max(d, TargetSpace::distance(v[i],v[j]));
return d;
}
// The function f(x_1,x_2,x_3) := x_i, needed to get the Lagrange nodes
// from a Dune LocalFunction
template <int dim>
struct CoordinateFunction
: public Dune::VirtualFunction<FieldVector<double,dim>, FieldVector<double,1> >
{
CoordinateFunction(int dir)
: dir_(dir)
{}
void evaluate(const FieldVector<double, dim>& x, FieldVector<double,1>& out) const {
out = x[dir_];
}
int dir_;
};
template <int domainDim, int elementOrder>
std::vector<FieldVector<double,domainDim> > lagrangeNodes(const GeometryType& type)
{
PQkLocalFiniteElementCache<double,double,domainDim,elementOrder> feCache;
std::vector<FieldVector<double,domainDim> > result(feCache.get(type).localBasis().size());
std::vector<FieldVector<double,1> > resultCoeff(feCache.get(type).localBasis().size());
for (size_t i=0; i<domainDim; i++) {
CoordinateFunction<domainDim> cF(i);
feCache.get(type).localInterpolation().interpolate(cF, resultCoeff);
for (size_t j=0; j<result.size(); j++)
result[j][i] = resultCoeff[j];
}
return result;
}
template <int domainDim, class TargetSpace, int highElementOrder>
void testNestedness(const LocalGeodesicFEFunction<domainDim,double,typename PQkLocalFiniteElementCache<double,double,domainDim,1>::FiniteElementType, TargetSpace>& loF)
{
// Make higher order local gfe function
PQkLocalFiniteElementCache<double,double,domainDim,highElementOrder> feCache;
typedef typename PQkLocalFiniteElementCache<double,double,domainDim,highElementOrder>::FiniteElementType LocalFiniteElement;
// Get the Lagrange nodes of the high-order function
std::vector<FieldVector<double,domainDim> > lNodes = lagrangeNodes<domainDim,highElementOrder>(loF.type());
// Evaluate low-order function at the high-order nodal values
std::vector<TargetSpace> nodalValues(lNodes.size());
for (size_t i=0; i<lNodes.size(); i++)
nodalValues[i] = loF.evaluate(lNodes[i]);
LocalGeodesicFEFunction<domainDim,double,LocalFiniteElement,TargetSpace> hoF(feCache.get(loF.type()),nodalValues);
// A quadrature rule as a set of test points
int quadOrder = 10; // high, I want many many points
const Dune::QuadratureRule<double, domainDim>& quad
= Dune::QuadratureRules<double, domainDim>::rule(loF.type(), quadOrder);
for (size_t pt=0; pt<quad.size(); pt++) {
const Dune::FieldVector<double,domainDim>& quadPos = quad[pt].position();
// evaluate value of low-order function
TargetSpace loValue = loF.evaluate(quadPos);
// evaluate value of high-order function
TargetSpace hoValue = hoF.evaluate(quadPos);
typename TargetSpace::CoordinateType diff = loValue.globalCoordinates();
diff -= hoValue.globalCoordinates();
static double maxDiff = 0;
maxDiff = std::max(maxDiff, diff.infinity_norm());
if (maxDiff > 0.2)
assert(false);
if ( diff.infinity_norm() > eps ) {
std::cout << className<TargetSpace>() << ": Values does not match." << std::endl;
std::cout << "Low order : " << loValue << std::endl;
std::cout << "High order: " << hoValue << std::endl;
assert(false);
}
}
}
template <class TargetSpace, int domainDim, int lowOrder, int highOrder>
void test(const GeometryType& element)
{
std::cout << " --- Testing " << element << " --> " << className<TargetSpace>()
<< ", low: " << lowOrder
<< ", high: " << highOrder << std::endl;
std::vector<TargetSpace> testPoints;
ValueFactory<TargetSpace>::get(testPoints);
int nTestPoints = testPoints.size();
typedef typename PQkLocalFiniteElementCache<double,double,domainDim,lowOrder>::FiniteElementType LocalFiniteElement;
PQkLocalFiniteElementCache<double,double,domainDim,lowOrder> feCache;
size_t nVertices = feCache.get(element).localBasis().size();
// Set up elements of the target space
std::vector<TargetSpace> corners(nVertices);
MultiIndex index(nVertices, nTestPoints);
int numIndices = index.cycle();
for (int i=0; i<numIndices; i++, ++index) {
for (size_t j=0; j<nVertices; j++)
corners[j] = testPoints[index[j]];
if (diameter(corners) > 0.5*M_PI)
continue;
// Make local gfe function to be tested
LocalGeodesicFEFunction<domainDim,double,LocalFiniteElement,TargetSpace> f(feCache.get(element),corners);
testNestedness<domainDim,TargetSpace,highOrder>(f);
}
}
template <int domainDim>
void testElement(const GeometryType& element)
{
test<RealTuple<double,1>,domainDim,1,2>(element);
test<UnitVector<double,2>,domainDim,1,2>(element);
test<UnitVector<double,3>,domainDim,1,2>(element);
test<Rotation<double,3>,domainDim,1,2>(element);
test<RigidBodyMotion<double,3>,domainDim,1,2>(element);
test<RealTuple<double,1>,domainDim,2,3>(element);
test<UnitVector<double,2>,domainDim,2,3>(element);
test<UnitVector<double,3>,domainDim,2,3>(element);
test<Rotation<double,3>,domainDim,2,3>(element);
test<RigidBodyMotion<double,3>,domainDim,2,3>(element);
}
int main()
{
// choke on NaN -- don't enable this by default, as there are
// a few harmless NaN in the loopsolver
//feenableexcept(FE_INVALID);
std::cout << std::setw(15) << std::setprecision(12);
GeometryType element;
////////////////////////////////////////////////////////////////
// Test functions on 1d elements
////////////////////////////////////////////////////////////////
element.makeSimplex(1);
testElement<1>(element);
////////////////////////////////////////////////////////////////
// Test functions on 2d simplex elements
////////////////////////////////////////////////////////////////
element.makeSimplex(2);
testElement<2>(element);
////////////////////////////////////////////////////////////////
// Test functions on 2d quadrilateral elements
////////////////////////////////////////////////////////////////
element.makeCube(2);
testElement<2>(element);
}