Newer
Older
#include <iostream>
#include <dune/common/fvector.hh>
#include <dune/geometry/quadraturerules.hh>
#include <dune/geometry/type.hh>
#include <dune/geometry/referenceelements.hh>
#include <dune/localfunctions/lagrange/lagrangelfecache.hh>
#include <dune/gfe/spaces/productmanifold.hh>
#include <dune/gfe/spaces/realtuple.hh>
#include <dune/gfe/spaces/rotation.hh>
#include <dune/gfe/spaces/unitvector.hh>
#include <dune/gfe/localgeodesicfefunction.hh>
/** \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;

Sander, Oliver
committed
template <int dim, class ctype, class LocalFunction>
auto
evaluateDerivativeFD(const LocalFunction& f, const Dune::FieldVector<ctype, dim>& local)
-> decltype(f.evaluateDerivative(local))
{
double eps = 1e-8;
//static const int embeddedDim = LocalFunction::TargetSpace::embeddedDim;
decltype(f.evaluateDerivative(local)) result;

Sander, Oliver
committed
for (int i=0; i<dim; i++) {

Sander, Oliver
committed
Dune::FieldVector<ctype, dim> forward = local;
Dune::FieldVector<ctype, dim> backward = local;

Sander, Oliver
committed
forward[i] += eps;
backward[i] -= eps;

Sander, Oliver
committed
auto fdDer = f.evaluate(forward).globalCoordinates() - f.evaluate(backward).globalCoordinates();
fdDer /= 2*eps;

Sander, Oliver
committed
for (size_t j=0; j<result.N(); j++)
result[j][i] = fdDer[j];

Sander, Oliver
committed

Sander, Oliver
committed

Sander, Oliver
committed
}

Oliver Sander
committed
/** \brief Test whether interpolation is invariant under permutation of the simplex vertices
* \todo Implement this for all dimensions

Oliver Sander
committed
*/
template <int domainDim, class TargetSpace>

Oliver Sander
committed
void testPermutationInvariance(const std::vector<TargetSpace>& corners)
// works only for 2d domains
if (domainDim!=2)
return;
LagrangeLocalFiniteElementCache<double,double,domainDim,1> feCache;
typedef typename LagrangeLocalFiniteElementCache<double,double,domainDim,1>::FiniteElementType LocalFiniteElement;
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
GeometryType simplex = GeometryTypes::simplex(domainDim);
//
std::vector<TargetSpace> cornersRotated1(domainDim+1);
std::vector<TargetSpace> cornersRotated2(domainDim+1);
cornersRotated1[0] = cornersRotated2[2] = corners[1];
cornersRotated1[1] = cornersRotated2[0] = corners[2];
cornersRotated1[2] = cornersRotated2[1] = corners[0];
LocalGeodesicFEFunction<2,double,LocalFiniteElement,TargetSpace> f0(feCache.get(simplex), corners);
LocalGeodesicFEFunction<2,double,LocalFiniteElement,TargetSpace> f1(feCache.get(simplex), cornersRotated1);
LocalGeodesicFEFunction<2,double,LocalFiniteElement,TargetSpace> f2(feCache.get(simplex), cornersRotated2);
// A quadrature rule as a set of test points
int quadOrder = 3;
const Dune::QuadratureRule<double, domainDim>& quad
= Dune::QuadratureRules<double, domainDim>::rule(simplex, quadOrder);
for (size_t pt=0; pt<quad.size(); pt++) {
const Dune::FieldVector<double,domainDim>& quadPos = quad[pt].position();
Dune::FieldVector<double,domainDim> l0 = quadPos;
Dune::FieldVector<double,domainDim> l1, l2;
l1[0] = quadPos[1];
l1[1] = 1-quadPos[0]-quadPos[1];
l2[0] = 1-quadPos[0]-quadPos[1];
l2[1] = quadPos[0];
// evaluate the three functions
TargetSpace v0 = f0.evaluate(l0);
TargetSpace v1 = f1.evaluate(l1);
TargetSpace v2 = f2.evaluate(l2);
// Check that they are all equal
assert(TargetSpace::distance(v0,v1) < eps);
assert(TargetSpace::distance(v0,v2) < eps);
}

Oliver Sander
committed
}
template <int domainDim, class TargetSpace>
void testDerivative(const LocalGeodesicFEFunction<domainDim,double,typename LagrangeLocalFiniteElementCache<double,double,domainDim,1>::FiniteElementType, TargetSpace>& f)
static const int embeddedDim = TargetSpace::EmbeddedTangentVector::dimension;
// A quadrature rule as a set of test points
int quadOrder = 3;
const Dune::QuadratureRule<double, domainDim>& quad
= Dune::QuadratureRules<double, domainDim>::rule(f.type(), quadOrder);
for (size_t pt=0; pt<quad.size(); pt++) {
const Dune::FieldVector<double,domainDim>& quadPos = quad[pt].position();
// evaluate actual derivative
Dune::FieldMatrix<double, embeddedDim, domainDim> derivative = f.evaluateDerivative(quadPos);
// evaluate fd approximation of derivative
Dune::FieldMatrix<double, embeddedDim, domainDim> fdDerivative = evaluateDerivativeFD(f,quadPos);
Dune::FieldMatrix<double, embeddedDim, domainDim> diff = derivative;
diff -= fdDerivative;
if ( diff.infinity_norm() > 100*eps ) {
std::cout << className<TargetSpace>() << ": Analytical gradient does not match fd approximation." << std::endl;
std::cout << "Analytical: " << derivative << std::endl;
std::cout << "FD : " << fdDerivative << std::endl;
template <int domainDim, class TargetSpace>
void testDerivativeOfValueWRTCoefficients(const LocalGeodesicFEFunction<domainDim,double,typename LagrangeLocalFiniteElementCache<double,double,domainDim,1>::FiniteElementType, TargetSpace>& f)
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
static const int embeddedDim = TargetSpace::EmbeddedTangentVector::dimension;
// A quadrature rule as a set of test points
int quadOrder = 3;
const Dune::QuadratureRule<double, domainDim>& quad
= Dune::QuadratureRules<double, domainDim>::rule(f.type(), quadOrder);
for (size_t pt=0; pt<quad.size(); pt++) {
Dune::FieldVector<double,domainDim> quadPos = quad[pt].position();
// loop over the coefficients
for (size_t i=0; i<f.size(); i++) {
// evaluate actual derivative
FieldMatrix<double, embeddedDim, embeddedDim> derivative;
f.evaluateDerivativeOfValueWRTCoefficient(quadPos, i, derivative);
// evaluate fd approximation of derivative
FieldMatrix<double, embeddedDim, embeddedDim> fdDerivative;
f.evaluateFDDerivativeOfValueWRTCoefficient(quadPos, i, fdDerivative);
if ( (derivative - fdDerivative).infinity_norm() > eps ) {
std::cout << className<TargetSpace>() << ": Analytical derivative of value does not match fd approximation." << std::endl;
std::cout << "coefficient: " << i << std::endl;
std::cout << "quad pos: " << quadPos << std::endl;
std::cout << "gfe: ";
for (size_t j=0; j<f.size(); j++)
std::cout << ", " << f.coefficient(j);
std::cout << std::endl;
std::cout << "Analytical:\n " << derivative << std::endl;
std::cout << "FD :\n " << fdDerivative << std::endl;
assert(false);
}
template <int domainDim, class TargetSpace>
void testDerivativeOfGradientWRTCoefficients(const LocalGeodesicFEFunction<domainDim,double,typename LagrangeLocalFiniteElementCache<double,double,domainDim,1>::FiniteElementType, TargetSpace>& f)
{
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
static const int embeddedDim = TargetSpace::EmbeddedTangentVector::dimension;
// A quadrature rule as a set of test points
int quadOrder = 3;
const Dune::QuadratureRule<double, domainDim>& quad
= Dune::QuadratureRules<double, domainDim>::rule(f.type(), quadOrder);
for (size_t pt=0; pt<quad.size(); pt++) {
const Dune::FieldVector<double,domainDim>& quadPos = quad[pt].position();
// loop over the coefficients
for (size_t i=0; i<f.size(); i++) {
// evaluate actual derivative
Tensor3<double, embeddedDim, embeddedDim, domainDim> derivative;
f.evaluateDerivativeOfGradientWRTCoefficient(quadPos, i, derivative);
// evaluate fd approximation of derivative
Tensor3<double, embeddedDim, embeddedDim, domainDim> fdDerivative;
f.evaluateFDDerivativeOfGradientWRTCoefficient(quadPos, i, fdDerivative);
if ( (derivative - fdDerivative).infinity_norm() > eps ) {
std::cout << className<TargetSpace>() << ": Analytical derivative of gradient does not match fd approximation." << std::endl;
std::cout << "coefficient: " << i << std::endl;
std::cout << "quad pos: " << quadPos << std::endl;
std::cout << "gfe: ";
for (size_t j=0; j<f.size(); j++)
std::cout << ", " << f.coefficient(j);
std::cout << std::endl;
std::cout << "Analytical:\n " << derivative << std::endl;
std::cout << "FD :\n " << fdDerivative << std::endl;
assert(false);
}
}
}
void test(const GeometryType& element)

Oliver Sander
committed
{
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
std::cout << " --- Testing " << className<TargetSpace>() << ", domain dimension: " << element.dim() << " ---" << std::endl;
std::vector<TargetSpace> testPoints;
ValueFactory<TargetSpace>::get(testPoints);
int nTestPoints = testPoints.size();
size_t nVertices = Dune::ReferenceElements<double,domainDim>::general(element).size(domainDim);
// 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
LagrangeLocalFiniteElementCache<double,double,domainDim,1> feCache;
typedef typename LagrangeLocalFiniteElementCache<double,double,domainDim,1>::FiniteElementType LocalFiniteElement;
LocalGeodesicFEFunction<domainDim,double,LocalFiniteElement,TargetSpace> f(feCache.get(element),corners);
//testPermutationInvariance(corners);
testDerivative<domainDim>(f);
testDerivativeOfValueWRTCoefficients<domainDim>(f);
testDerivativeOfGradientWRTCoefficients<domainDim>(f);
}
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
// 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);
////////////////////////////////////////////////////////////////
// Test functions on 1d elements
////////////////////////////////////////////////////////////////
test<RealTuple<double,1>,1>(GeometryTypes::simplex(1));
test<UnitVector<double,2>,1>(GeometryTypes::simplex(1));
test<UnitVector<double,3>,1>(GeometryTypes::simplex(1));
test<Rotation<double,3>,1>(GeometryTypes::simplex(1));
typedef Dune::GFE::ProductManifold<RealTuple<double,1>,Rotation<double,3>,UnitVector<double,2> > CrazyManifold;
test<CrazyManifold,1>(GeometryTypes::simplex(1));
////////////////////////////////////////////////////////////////
// Test functions on 2d simplex elements
////////////////////////////////////////////////////////////////
test<RealTuple<double,1>,2>(GeometryTypes::simplex(2));
test<UnitVector<double,2>,2>(GeometryTypes::simplex(2));
test<UnitVector<double,3>,2>(GeometryTypes::simplex(2));
test<Rotation<double,3>,2>(GeometryTypes::simplex(2));
typedef Dune::GFE::ProductManifold<RealTuple<double,1>,Rotation<double,3>,UnitVector<double,2> > CrazyManifold;
test<CrazyManifold,2>(GeometryTypes::simplex(2));
////////////////////////////////////////////////////////////////
// Test functions on 2d quadrilateral elements
////////////////////////////////////////////////////////////////
test<RealTuple<double,1>,2>(GeometryTypes::cube(2));
test<UnitVector<double,2>,2>(GeometryTypes::cube(2));
test<UnitVector<double,3>,2>(GeometryTypes::cube(2));
test<Rotation<double,3>,2>(GeometryTypes::cube(2));
typedef Dune::GFE::ProductManifold<RealTuple<double,1>,Rotation<double,3>,UnitVector<double,2> > CrazyManifold;
test<CrazyManifold,2>(GeometryTypes::cube(2));