Newer
Older

Oliver Sander
committed
#include <config.h>

Oliver Sander
committed
#include <dune/gfe/realtuple.hh>

Oliver Sander
committed
/** \file
\brief Unit tests for the UnitVector class
*/

Oliver Sander
committed
using namespace Dune;

Oliver Sander
committed
const double eps = 1e-5;

Oliver Sander
committed
template <class TargetSpace>
double energy(const TargetSpace& a, const TargetSpace& b)

Oliver Sander
committed
return TargetSpace::distance(a,b) * TargetSpace::distance(a,b);

Oliver Sander
committed
template <class TargetSpace, int dim>
double energy(const TargetSpace& a, const FieldVector<double,dim>& b)

Oliver Sander
committed
return TargetSpace::distance(a,b) * TargetSpace::distance(a,b);

Oliver Sander
committed
template <class TargetSpace, int dim>
double energy(const FieldVector<double,dim>& a, const FieldVector<double,dim>& b)
{

Oliver Sander
committed
return TargetSpace::distance(a,b) * TargetSpace::distance(a,b);

Oliver Sander
committed
template <class TargetSpace, int dim>
FieldMatrix<double,dim,dim> getSecondDerivativeOfSecondArgumentFD(const TargetSpace& a, const TargetSpace& b)
{
// finite-difference approximation
FieldMatrix<double,dim,dim> d2d2_fd;
for (size_t i=0; i<dim; i++) {
for (size_t j=0; j<dim; j++) {
if (i==j) {
FieldVector<double,dim> bPlus = b.globalCoordinates();
FieldVector<double,dim> bMinus = b.globalCoordinates();
bPlus[i] += eps;
bMinus[i] -= eps;
d2d2_fd[i][i] = (energy(a,bPlus) - 2*energy(a,b) + energy(a,bMinus)) / (eps*eps);
} else {
FieldVector<double,dim> bPlusPlus = b.globalCoordinates();
FieldVector<double,dim> bPlusMinus = b.globalCoordinates();
FieldVector<double,dim> bMinusPlus = b.globalCoordinates();
FieldVector<double,dim> bMinusMinus = b.globalCoordinates();
bPlusPlus[i] += eps; bPlusPlus[j] += eps;
bPlusMinus[i] += eps; bPlusMinus[j] -= eps;
bMinusPlus[i] -= eps; bMinusPlus[j] += eps;
bMinusMinus[i] -= eps; bMinusMinus[j] -= eps;
d2d2_fd[i][j] = (energy(a,bPlusPlus) + energy(a,bMinusMinus)
- energy(a,bPlusMinus) - energy(a,bMinusPlus)) / (4*eps*eps);
}
}
}

Oliver Sander
committed
template <class TargetSpace, int dim>
void testDerivativesOfSquaredDistance(const TargetSpace& a, const TargetSpace& b)
{
///////////////////////////////////////////////////////////////////
// Test derivative with respect to second argument
///////////////////////////////////////////////////////////////////

Oliver Sander
committed
typename TargetSpace::EmbeddedTangentVector d2 = TargetSpace::derivativeOfDistanceSquaredWRTSecondArgument(a, b);
// finite-difference approximation

Oliver Sander
committed
typename TargetSpace::EmbeddedTangentVector d2_fd;
for (size_t i=0; i<dim; i++) {
FieldVector<double,dim> bPlus = b.globalCoordinates();
FieldVector<double,dim> bMinus = b.globalCoordinates();
bPlus[i] += eps;
bMinus[i] -= eps;
d2_fd[i] = (energy(a,bPlus) - energy(a,bMinus)) / (2*eps);
}
if ( (d2 - d2_fd).infinity_norm() > 100*eps ) {
std::cout << "Analytical gradient does not match fd approximation." << std::endl;
std::cout << "d2 Analytical: " << d2 << std::endl;
std::cout << "d2 FD : " << d2_fd << std::endl;
}
///////////////////////////////////////////////////////////////////
// Test second derivative with respect to second argument
///////////////////////////////////////////////////////////////////

Oliver Sander
committed
FieldMatrix<double,dim,dim> d2d2 = TargetSpace::secondDerivativeOfDistanceSquaredWRTSecondArgument(a, b);
// finite-difference approximation

Oliver Sander
committed
FieldMatrix<double,dim,dim> d2d2_fd = getSecondDerivativeOfSecondArgumentFD<TargetSpace,dim>(a,b);
FieldMatrix<double,dim,dim> d2d2_diff = d2d2;
d2d2_diff -= d2d2_fd;
if ( (d2d2_diff).infinity_norm() > 100*eps ) {
std::cout << "Analytical second derivative does not match fd approximation." << std::endl;
std::cout << "d2d2 Analytical:" << std::endl << d2d2 << std::endl;
std::cout << "d2d2 FD :" << std::endl << d2d2_fd << std::endl;
}
//////////////////////////////////////////////////////////////////////////////
// Test mixed second derivative with respect to first and second argument
//////////////////////////////////////////////////////////////////////////////

Oliver Sander
committed
#if 0
FieldMatrix<double,dim,dim> d1d2 = TargetSpace::secondDerivativeOfDistanceSquaredWRTFirstAndSecondArgument(a, b);
// finite-difference approximation
FieldMatrix<double,dim,dim> d1d2_fd;
for (size_t i=0; i<dim; i++) {
for (size_t j=0; j<dim; j++) {
FieldVector<double,dim> aPlus = a.globalCoordinates();
FieldVector<double,dim> aMinus = a.globalCoordinates();
aPlus[i] += eps;
aMinus[i] -= eps;
FieldVector<double,dim> bPlus = b.globalCoordinates();
FieldVector<double,dim> bMinus = b.globalCoordinates();
d1d2_fd[i][j] = (energy(aPlus,bPlus) + energy(aMinus,bMinus)
- energy(aPlus,bMinus) - energy(aMinus,bPlus)) / (4*eps*eps);
}
}
FieldMatrix<double,dim,dim> d1d2_diff = d1d2;
d1d2_diff -= d1d2_fd;
if ( (d1d2_diff).infinity_norm() > 100*eps ) {
std::cout << "Analytical mixed second derivative does not match fd approximation." << std::endl;
std::cout << "d1d2 Analytical:" << std::endl << d1d2 << std::endl;
std::cout << "d1d2 FD :" << std::endl << d1d2_fd << std::endl;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Test mixed third derivative with respect to first (once) and second (twice) argument
/////////////////////////////////////////////////////////////////////////////////////////////

Oliver Sander
committed
Tensor3<double,dim,dim,dim> d1d2d2 = TargetSpace::thirdDerivativeOfDistanceSquaredWRTFirst1AndSecond2Argument(a, b);
Tensor3<double,dim,dim,dim> d1d2d2_fd;
for (size_t i=0; i<dim; i++) {
FieldVector<double,dim> aPlus = a.globalCoordinates();
FieldVector<double,dim> aMinus = a.globalCoordinates();
aPlus[i] += eps;
aMinus[i] -= eps;

Oliver Sander
committed
FieldMatrix<double,dim,dim> hPlus = getSecondDerivativeOfSecondArgumentFD(TargetSpace(aPlus),b);
FieldMatrix<double,dim,dim> hMinus = getSecondDerivativeOfSecondArgumentFD(TargetSpace(aMinus),b);
d1d2d2_fd[i] = hPlus;
d1d2d2_fd[i] -= hMinus;
d1d2d2_fd[i] /= 2*eps;
}
if ( (d1d2d2 - d1d2d2_fd).infinity_norm() > 100*eps ) {
std::cout << "Analytical mixed third derivative does not match fd approximation." << std::endl;
std::cout << "d1d2d2 Analytical:" << std::endl << d1d2d2 << std::endl;
std::cout << "d1d2d2 FD :" << std::endl << d1d2d2_fd << std::endl;
}

Oliver Sander
committed
#endif

Oliver Sander
committed
int main()
{
// Set up elements of S^1

Oliver Sander
committed
Dune::array<double,2> w0 = {{1,0}};
UnitVector<2> uv0(w0);

Oliver Sander
committed
Dune::array<double,2> w1 = {{0,1}};
UnitVector<2> uv1(w1);

Oliver Sander
committed
testDerivativesOfSquaredDistance<UnitVector<2>, 2>(uv0, uv1);

Oliver Sander
committed
// Dune::array<double,3> w3_0 = {{0,1,0}};
// UnitVector<3> v3_0(w3_0);
// Dune::array<double,3> w3_1 = {{1,1,0}};
// UnitVector<3> v3_1(w3_1);
// testDerivativesOfSquaredDistance<3>(v3_0, v3_1);
#if 0

Oliver Sander
committed
// Set up elements of S^1
FieldVector<double,2> v;
v[0] = 1; v[1] = 1;
UnitVector<2> uv1; uv1 = v;
v[0] = 0; v[1] = 1;
UnitVector<2> uv0; uv0 = v;
// Set up elements of SO(2)
Rotation<2,double> ro1(M_PI/4);
Rotation<2,double> ro0(M_PI/2);
std::cout << UnitVector<2>::distance(uv0, uv1) << std::endl;
std::cout << Rotation<2,double>::distance(ro0, ro1) << std::endl;
std::cout << UnitVector<2>::derivativeOfDistanceSquaredWRTSecondArgument(uv0, uv1) << std::endl;
std::cout << Rotation<2,double>::derivativeOfDistanceSquaredWRTSecondArgument(ro0, ro1) << std::endl;
std::cout << UnitVector<2>::secondDerivativeOfDistanceSquaredWRTSecondArgument(uv0, uv1) << std::endl;
std::cout << Rotation<2,double>::secondDerivativeOfDistanceSquaredWRTSecondArgument(ro0, ro1) << std::endl;