Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
D
dune-gfe
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Sander, Oliver
dune-gfe
Commits
3ff0de8c
Commit
3ff0de8c
authored
1 year ago
by
Sander, Oliver
Browse files
Options
Downloads
Patches
Plain Diff
A unit test for InterpolationDerivatives
parent
ab09c587
No related branches found
No related tags found
1 merge request
!138
Let ADOL-C differentiate the energy density and the GFE interpolation separately
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
test/CMakeLists.txt
+1
-0
1 addition, 0 deletions
test/CMakeLists.txt
test/interpolationderivativestest.cc
+572
-0
572 additions, 0 deletions
test/interpolationderivativestest.cc
with
573 additions
and
0 deletions
test/CMakeLists.txt
+
1
−
0
View file @
3ff0de8c
...
@@ -4,6 +4,7 @@ set(TESTS
...
@@ -4,6 +4,7 @@ set(TESTS
cosseratrodenergytest
cosseratrodenergytest
cosseratrodtest
cosseratrodtest
embeddedglobalgfefunctiontest
embeddedglobalgfefunctiontest
interpolationderivativestest
localadolcstiffnesstest
localadolcstiffnesstest
localgeodesicfefunctiontest
localgeodesicfefunctiontest
localgfetestfunctiontest
localgfetestfunctiontest
...
...
This diff is collapsed.
Click to expand it.
test/interpolationderivativestest.cc
0 → 100644
+
572
−
0
View file @
3ff0de8c
/** \file
\brief Unit tests for classes that implement derivatives of interpolation functions
*/
#include
<config.h>
#define DUNE_ISTL_WITH_CHECKING
#include
<adolc/adolc.h>
#include
<dune/fufem/utilities/adolcnamespaceinjections.hh>
#include
<dune/common/test/testsuite.hh>
#include
<dune/grid/uggrid.hh>
#include
<dune/istl/io.hh>
#include
<dune/functions/functionspacebases/lagrangebasis.hh>
#include
<dune/gfe/spaces/unitvector.hh>
#include
<dune/gfe/spaces/realtuple.hh>
#include
<dune/gfe/interpolationderivatives.hh>
#include
"valuefactory.hh"
using
namespace
Dune
;
/** \brief Compute derivatives of GFE interpolation with respect to the coefficients using finite differencts
*
* This class implements the InterpolationDerivatives interface but uses a finite difference
* approximation to approximate those derivatives. This is used for testing purposes only.
*
* \tparam LocalInterpolationRule The class that implements the interpolation from a set of coefficients
*
*/
template
<
typename
LocalInterpolationRule
>
class
FiniteDifferenceInterpolationDerivatives
{
using
TargetSpace
=
typename
LocalInterpolationRule
::
TargetSpace
;
using
Derivative
=
typename
LocalInterpolationRule
::
DerivativeType
;
constexpr
static
auto
blocksize
=
TargetSpace
::
TangentVector
::
dimension
;
constexpr
static
auto
embeddedBlocksize
=
TargetSpace
::
EmbeddedTangentVector
::
dimension
;
//////////////////////////////////////////////////////////////////////
// Data members
//////////////////////////////////////////////////////////////////////
// TODO: Do not hard-wirde this!
static
constexpr
int
domainDim
=
2
;
FieldVector
<
double
,
domainDim
>
localPos_
;
FieldMatrix
<
double
,
domainDim
,
domainDim
>
geometryJacobianInverse_
;
const
LocalInterpolationRule
&
localInterpolationRule_
;
std
::
vector
<
TargetSpace
>
coefficients_
;
// TODO: Don't hardcode FieldMatrix
std
::
vector
<
FieldMatrix
<
double
,
blocksize
,
embeddedBlocksize
>
>
orthonormalFrames_
;
public:
FiniteDifferenceInterpolationDerivatives
(
const
LocalInterpolationRule
&
localInterpolationRule
)
:
localInterpolationRule_
(
localInterpolationRule
)
{
// Copy the coefficients into a dedicated array, for easier access
coefficients_
.
resize
(
localInterpolationRule
.
size
());
for
(
std
::
size_t
i
=
0
;
i
<
localInterpolationRule
.
size
();
i
++
)
coefficients_
[
i
]
=
localInterpolationRule
.
coefficient
(
i
);
// Precompute the orthonormal frames
orthonormalFrames_
.
resize
(
localInterpolationRule_
.
size
());
for
(
size_t
i
=
0
;
i
<
localInterpolationRule_
.
size
();
++
i
)
orthonormalFrames_
[
i
]
=
localInterpolationRule_
.
coefficient
(
i
).
orthonormalFrame
();
}
/** \brief Bind the objects to a particular evaluation point
*
* In particular, this computes the value of the interpolation function at that point,
* and the derivative at that point with respect to space.
*
* \param[in] tapeNumber Number of the ADOL-C tape if ADOL-C is used. Dummy otherwise
* \param[in] localPos Local position where the FE function is evaluated
* \param[out] value The function value at the local configuration
* \param[out] derivative The derivative of the interpolation function
* with respect to the evaluation point
*/
template
<
typename
Element
>
void
bind
(
short
tapeNumber
,
const
Element
&
element
,
const
typename
Element
::
Geometry
::
LocalCoordinate
&
localPos
,
typename
TargetSpace
::
CoordinateType
&
value
,
typename
LocalInterpolationRule
::
DerivativeType
&
derivative
)
{
localPos_
=
localPos
;
value
=
localInterpolationRule_
.
evaluate
(
localPos
).
globalCoordinates
();
geometryJacobianInverse_
=
element
.
geometry
().
jacobianInverse
(
localPos
);
auto
referenceDerivative
=
localInterpolationRule_
.
evaluateDerivative
(
localPos
,
value
);
derivative
=
referenceDerivative
*
geometryJacobianInverse_
;
}
/** \brief Compute first and second derivatives of the FE interpolation
*
* This code assumes that `bind` has been called before.
*
* \param[in] tapeNumber The tape number to be used by ADOL-C. Must be the same
* that was given to the `bind` method.
* \param[in] weights Vector of weights that the second derivative is contracted with
* \param[out] embeddedFirstDerivative Derivative of the FE interpolation wrt the coefficients
* \param[out] firstDerivative Derivative of the FE interpolation wrt the coefficients
* \param[out] secondDerivative Second derivative of the FE interpolation,
* contracted with the weight vector
*/
void
evaluateDerivatives
(
short
tapeNumber
,
const
std
::
vector
<
double
>&
adjoint
,
Matrix
<
double
>&
euclideanFirstDerivative
,
Matrix
<
double
>&
riemannianFirstDerivative
,
Matrix
<
FieldMatrix
<
double
,
blocksize
,
blocksize
>
>&
secondDerivative
)
const
{
////////////////////////////////////////////////////////////////////////
// Compute Euclidean first derivative of the interpolation value
////////////////////////////////////////////////////////////////////////
for
(
std
::
size_t
coefficient
=
0
;
coefficient
<
localInterpolationRule_
.
size
();
coefficient
++
)
{
std
::
vector
<
TargetSpace
>
cornersPlus
=
coefficients_
;
std
::
vector
<
TargetSpace
>
cornersMinus
=
coefficients_
;
for
(
std
::
size_t
j
=
0
;
j
<
TargetSpace
::
CoordinateType
::
size
();
j
++
)
{
// Optimal variation size for first derivatives
const
double
eps
=
std
::
sqrt
(
std
::
numeric_limits
<
double
>::
epsilon
());
// Variation in coordinates of the surrounding spaces
typename
TargetSpace
::
CoordinateType
variation
(
0.0
);
variation
[
j
]
=
eps
;
cornersPlus
[
coefficient
]
=
TargetSpace
(
coefficients_
[
coefficient
].
globalCoordinates
()
+
variation
);
cornersMinus
[
coefficient
]
=
TargetSpace
(
coefficients_
[
coefficient
].
globalCoordinates
()
-
variation
);
LocalInterpolationRule
fPlus
(
localInterpolationRule_
.
localFiniteElement
(),
cornersPlus
);
LocalInterpolationRule
fMinus
(
localInterpolationRule_
.
localFiniteElement
(),
cornersMinus
);
/////////////////////////////////////////////////////////////
// Compute first derivative of the interpolation value
/////////////////////////////////////////////////////////////
TargetSpace
hPlus
=
fPlus
.
evaluate
(
localPos_
);
TargetSpace
hMinus
=
fMinus
.
evaluate
(
localPos_
);
for
(
std
::
size_t
k
=
0
;
k
<
TargetSpace
::
CoordinateType
::
size
();
k
++
)
euclideanFirstDerivative
[
k
][
coefficient
*
TargetSpace
::
CoordinateType
::
size
()
+
j
]
=
(
hPlus
.
globalCoordinates
()[
k
]
-
hMinus
.
globalCoordinates
()[
k
])
/
(
2
*
eps
);
/////////////////////////////////////////////////////////////
// Compute first derivative of the interpolation gradient
/////////////////////////////////////////////////////////////
auto
hPlusDer
=
fPlus
.
evaluateDerivative
(
localPos_
)
*
geometryJacobianInverse_
;
auto
hMinusDer
=
fMinus
.
evaluateDerivative
(
localPos_
)
*
geometryJacobianInverse_
;
for
(
std
::
size_t
k
=
0
;
k
<
hPlusDer
.
N
();
k
++
)
for
(
std
::
size_t
l
=
0
;
l
<
hPlusDer
.
M
();
l
++
)
euclideanFirstDerivative
[
k
*
hPlusDer
.
M
()
+
l
+
TargetSpace
::
CoordinateType
::
size
()][
coefficient
*
TargetSpace
::
CoordinateType
::
size
()
+
j
]
=
(
hPlusDer
[
k
][
l
]
-
hMinusDer
[
k
][
l
])
/
(
2
*
eps
);
}
}
////////////////////////////////////////////////////////////////////////
// Compute Riemannian first derivative of the interpolation value
////////////////////////////////////////////////////////////////////////
for
(
std
::
size_t
coefficient
=
0
;
coefficient
<
localInterpolationRule_
.
size
();
coefficient
++
)
{
// the function value at the point where we are evaluating the derivative
const
auto
B
=
orthonormalFrames_
[
coefficient
];
std
::
vector
<
TargetSpace
>
cornersPlus
=
coefficients_
;
std
::
vector
<
TargetSpace
>
cornersMinus
=
coefficients_
;
for
(
std
::
size_t
j
=
0
;
j
<
B
.
size
();
j
++
)
{
// Optimal variation size for first derivatives
const
double
eps
=
std
::
sqrt
(
std
::
numeric_limits
<
double
>::
epsilon
());
auto
forwardVariation
=
B
[
j
];
forwardVariation
*=
eps
;
auto
backwardVariation
=
B
[
j
];
backwardVariation
*=
-
eps
;
cornersPlus
[
coefficient
]
=
TargetSpace
::
exp
(
coefficients_
[
coefficient
],
forwardVariation
);
cornersMinus
[
coefficient
]
=
TargetSpace
::
exp
(
coefficients_
[
coefficient
],
backwardVariation
);
LocalInterpolationRule
fPlus
(
localInterpolationRule_
.
localFiniteElement
(),
cornersPlus
);
LocalInterpolationRule
fMinus
(
localInterpolationRule_
.
localFiniteElement
(),
cornersMinus
);
/////////////////////////////////////////////////////////////
// Compute first derivative of the interpolation value
/////////////////////////////////////////////////////////////
TargetSpace
hPlus
=
fPlus
.
evaluate
(
localPos_
);
TargetSpace
hMinus
=
fMinus
.
evaluate
(
localPos_
);
for
(
std
::
size_t
k
=
0
;
k
<
TargetSpace
::
CoordinateType
::
size
();
k
++
)
riemannianFirstDerivative
[
k
][
coefficient
*
B
.
size
()
+
j
]
=
(
hPlus
.
globalCoordinates
()[
k
]
-
hMinus
.
globalCoordinates
()[
k
])
/
(
2
*
eps
);
/////////////////////////////////////////////////////////////
// Compute first derivative of the interpolation gradient
/////////////////////////////////////////////////////////////
auto
hPlusDer
=
fPlus
.
evaluateDerivative
(
localPos_
)
*
geometryJacobianInverse_
;
auto
hMinusDer
=
fMinus
.
evaluateDerivative
(
localPos_
)
*
geometryJacobianInverse_
;
for
(
std
::
size_t
k
=
0
;
k
<
hPlusDer
.
N
();
k
++
)
for
(
std
::
size_t
l
=
0
;
l
<
hPlusDer
.
M
();
l
++
)
riemannianFirstDerivative
[
k
*
hPlusDer
.
M
()
+
l
+
TargetSpace
::
CoordinateType
::
size
()][
coefficient
*
B
.
size
()
+
j
]
=
(
hPlusDer
[
k
][
l
]
-
hMinusDer
[
k
][
l
])
/
(
2
*
eps
);
}
}
///////////////////////////////////////////////////////////////////////////
// Compute Riemannian Hesse matrix by finite-difference approximation.
///////////////////////////////////////////////////////////////////////////
// Precompute value at the current configuration
auto
centerValue
=
localInterpolationRule_
.
evaluate
(
localPos_
).
globalCoordinates
();
auto
centerDerivative
=
localInterpolationRule_
.
evaluateDerivative
(
localPos_
)
*
geometryJacobianInverse_
;
// Precompute energy infinitesimal corrections in the directions of the local basis vectors
std
::
vector
<
std
::
array
<
TargetSpace
,
blocksize
>
>
forwardValue
(
coefficients_
.
size
());
std
::
vector
<
std
::
array
<
TargetSpace
,
blocksize
>
>
backwardValue
(
coefficients_
.
size
());
std
::
vector
<
std
::
array
<
Derivative
,
blocksize
>
>
forwardDer
(
coefficients_
.
size
());
std
::
vector
<
std
::
array
<
Derivative
,
blocksize
>
>
backwardDer
(
coefficients_
.
size
());
BlockVector
<
FieldVector
<
double
,
blocksize
>
>
canonicalValues
(
coefficients_
.
size
());
for
(
size_t
i
=
0
;
i
<
coefficients_
.
size
();
i
++
)
{
for
(
size_t
i2
=
0
;
i2
<
blocksize
;
i2
++
)
{
// Optimal variation size for second derivatives
const
double
eps
=
std
::
pow
(
std
::
numeric_limits
<
double
>::
epsilon
(),
0.25
);
typename
TargetSpace
::
EmbeddedTangentVector
xi
=
orthonormalFrames_
[
i
][
i2
];
auto
forwardSolution
=
coefficients_
;
auto
backwardSolution
=
coefficients_
;
forwardSolution
[
i
]
=
TargetSpace
::
exp
(
coefficients_
[
i
],
eps
*
xi
);
backwardSolution
[
i
]
=
TargetSpace
::
exp
(
coefficients_
[
i
],
-
1
*
eps
*
xi
);
LocalInterpolationRule
fPlus
(
localInterpolationRule_
.
localFiniteElement
(),
forwardSolution
);
LocalInterpolationRule
fMinus
(
localInterpolationRule_
.
localFiniteElement
(),
backwardSolution
);
forwardValue
[
i
][
i2
]
=
fPlus
.
evaluate
(
localPos_
);
backwardValue
[
i
][
i2
]
=
fMinus
.
evaluate
(
localPos_
);
forwardDer
[
i
][
i2
]
=
fPlus
.
evaluateDerivative
(
localPos_
)
*
geometryJacobianInverse_
;
backwardDer
[
i
][
i2
]
=
fMinus
.
evaluateDerivative
(
localPos_
)
*
geometryJacobianInverse_
;
// Finite difference quotient for the second derivative
auto
valueDerivative
=
(
forwardValue
[
i
][
i2
].
globalCoordinates
()
-
2
*
centerValue
+
backwardValue
[
i
][
i2
].
globalCoordinates
())
/
(
eps
*
eps
);
auto
jacobianDerivative
=
(
forwardDer
[
i
][
i2
]
-
2
*
centerDerivative
+
backwardDer
[
i
][
i2
])
/
(
eps
*
eps
);
// Multiply with the adjoint
canonicalValues
[
i
][
i2
]
=
0
;
for
(
std
::
size_t
j
=
0
;
j
<
valueDerivative
.
size
();
j
++
)
canonicalValues
[
i
][
i2
]
+=
adjoint
[
j
]
*
valueDerivative
[
j
];
for
(
std
::
size_t
j
=
0
;
j
<
jacobianDerivative
.
N
();
j
++
)
for
(
std
::
size_t
j2
=
0
;
j2
<
jacobianDerivative
.
M
();
j2
++
)
canonicalValues
[
i
][
i2
]
+=
adjoint
[
valueDerivative
.
size
()
+
j
*
jacobianDerivative
.
M
()
+
j2
]
*
jacobianDerivative
[
j
][
j2
];
}
}
for
(
size_t
i
=
0
;
i
<
localInterpolationRule_
.
size
();
i
++
)
{
for
(
size_t
i2
=
0
;
i2
<
blocksize
;
i2
++
)
{
for
(
size_t
j
=
0
;
j
<
localInterpolationRule_
.
size
();
j
++
)
{
for
(
size_t
j2
=
0
;
j2
<
blocksize
;
j2
++
)
{
// Optimal variation size for second derivatives
const
double
eps
=
std
::
pow
(
std
::
numeric_limits
<
double
>::
epsilon
(),
0.25
);
std
::
vector
<
TargetSpace
>
forwardSolutionXiEta
=
coefficients_
;
std
::
vector
<
TargetSpace
>
backwardSolutionXiEta
=
coefficients_
;
typename
TargetSpace
::
EmbeddedTangentVector
epsXi
=
orthonormalFrames_
[
i
][
i2
];
epsXi
*=
eps
;
typename
TargetSpace
::
EmbeddedTangentVector
epsEta
=
orthonormalFrames_
[
j
][
j2
];
epsEta
*=
eps
;
if
(
i
==
j
)
forwardSolutionXiEta
[
i
]
=
TargetSpace
::
exp
(
coefficients_
[
i
],
epsXi
+
epsEta
);
else
{
forwardSolutionXiEta
[
i
]
=
TargetSpace
::
exp
(
coefficients_
[
i
],
epsXi
);
forwardSolutionXiEta
[
j
]
=
TargetSpace
::
exp
(
coefficients_
[
j
],
epsEta
);
}
if
(
i
==
j
)
backwardSolutionXiEta
[
i
]
=
TargetSpace
::
exp
(
coefficients_
[
i
],
(
-
1
)
*
epsXi
+
(
-
1
)
*
epsEta
);
else
{
backwardSolutionXiEta
[
i
]
=
TargetSpace
::
exp
(
coefficients_
[
i
],
(
-
1
)
*
epsXi
);
backwardSolutionXiEta
[
j
]
=
TargetSpace
::
exp
(
coefficients_
[
j
],
(
-
1
)
*
epsEta
);
}
LocalInterpolationRule
fPlus
(
localInterpolationRule_
.
localFiniteElement
(),
forwardSolutionXiEta
);
LocalInterpolationRule
fMinus
(
localInterpolationRule_
.
localFiniteElement
(),
backwardSolutionXiEta
);
/////////////////////////////////////////////////////////////////////////////////////
// Compute second derivative of the adjoint vector times the interpolation value
/////////////////////////////////////////////////////////////////////////////////////
auto
forwardTmp
=
fPlus
.
evaluate
(
localPos_
).
globalCoordinates
();
auto
backwardTmp
=
fMinus
.
evaluate
(
localPos_
).
globalCoordinates
();
auto
foo
=
(
forwardTmp
-
2
*
centerValue
+
backwardTmp
)
/
(
eps
*
eps
);
// Scalar product: ... = adjoint * foo;
secondDerivative
[
i
][
j
][
i2
][
j2
]
=
0
;
for
(
std
::
size_t
k
=
0
;
k
<
foo
.
size
();
k
++
)
secondDerivative
[
i
][
j
][
i2
][
j2
]
+=
adjoint
[
k
]
*
foo
[
k
];
/////////////////////////////////////////////////////////////////////////////////////
// Compute second derivative of the adjoint vector times the interpolation gradient
/////////////////////////////////////////////////////////////////////////////////////
auto
forwardDerTmp
=
fPlus
.
evaluateDerivative
(
localPos_
)
*
geometryJacobianInverse_
;
auto
backwardDerTmp
=
fMinus
.
evaluateDerivative
(
localPos_
)
*
geometryJacobianInverse_
;
auto
foo2
=
(
forwardDerTmp
-
2
*
centerDerivative
+
backwardDerTmp
)
/
(
eps
*
eps
);
// Scalar product: ... += adjoint * foo2;
for
(
std
::
size_t
k
=
0
;
k
<
foo2
.
N
();
k
++
)
for
(
std
::
size_t
l
=
0
;
l
<
foo2
.
M
();
l
++
)
secondDerivative
[
i
][
j
][
i2
][
j2
]
+=
adjoint
[
k
*
foo2
.
M
()
+
l
+
TargetSpace
::
CoordinateType
::
size
()]
*
foo2
[
k
][
l
];
////////////////////////////////////////////////////////////////////////////////////
// Use a polarization identity to get the actual Hesse matrix entry
////////////////////////////////////////////////////////////////////////////////////
secondDerivative
[
i
][
j
][
i2
][
j2
]
=
0.5
*
(
secondDerivative
[
i
][
j
][
i2
][
j2
]
-
canonicalValues
[
i
][
i2
]
-
canonicalValues
[
j
][
j2
]);
}
}
}
}
}
};
enum
class
InterpolationType
{
Geodesic
,
ProjectionBased
};
template
<
class
TargetSpace
,
InterpolationType
interpolationType
>
TestSuite
checkDerivatives
()
{
TestSuite
test
;
std
::
cout
<<
"Testing class "
<<
className
<
TargetSpace
>
()
<<
std
::
endl
;
////////////////////////////////////////////////////
// Make grid consisting of a single triangle
////////////////////////////////////////////////////
static
const
int
domainDim
=
2
;
using
Grid
=
UGGrid
<
domainDim
>
;
GridFactory
<
Grid
>
factory
;
factory
.
insertVertex
({
1.0
,
1.0
});
factory
.
insertVertex
({
2.0
,
1.5
});
factory
.
insertVertex
({
2.5
,
3.0
});
factory
.
insertElement
(
GeometryTypes
::
simplex
(
domainDim
),
{
0
,
1
,
2
});
auto
grid
=
factory
.
createGrid
();
auto
gridView
=
grid
->
leafGridView
();
using
GridView
=
decltype
(
gridView
);
/////////////////////////////////////////////////////////////////////////
// Construct a LocalInterpolationRule whose derivative we will compute
/////////////////////////////////////////////////////////////////////////
constexpr
int
order
=
1
;
Functions
::
LagrangeBasis
<
GridView
,
order
>
scalarBasis
(
gridView
);
std
::
vector
<
TargetSpace
>
testPoints
;
ValueFactory
<
TargetSpace
>::
get
(
testPoints
);
// TODO: Make sure the list of test points is longer than this.
const
std
::
size_t
nDofs
=
scalarBasis
.
dimension
();
std
::
vector
<
TargetSpace
>
localCoefficients
(
nDofs
);
for
(
std
::
size_t
i
=
0
;
i
<
nDofs
;
i
++
)
localCoefficients
[
i
]
=
testPoints
[
i
];
/////////////////////////////////////////////////////////////////////////
// Construct the InterpolationDerivatives object that we will test
/////////////////////////////////////////////////////////////////////////
// Define the two possible interpolation rules
using
GeodesicInterpolationRule
=
LocalGeodesicFEFunction
<
domainDim
,
typename
Grid
::
ctype
,
decltype
(
scalarBasis
.
localView
().
tree
().
finiteElement
()),
TargetSpace
>
;
using
ProjectionBasedInterpolationRule
=
GFE
::
LocalProjectedFEFunction
<
domainDim
,
typename
Grid
::
ctype
,
decltype
(
scalarBasis
.
localView
().
tree
().
finiteElement
()),
TargetSpace
>
;
// Select the one to test
using
LocalInterpolationRule
=
std
::
conditional_t
<
interpolationType
==
InterpolationType
::
Geodesic
,
GeodesicInterpolationRule
,
ProjectionBasedInterpolationRule
>
;
auto
localView
=
scalarBasis
.
localView
();
localView
.
bind
(
*
gridView
.
begin
<
0
>
());
LocalInterpolationRule
localGFEFunction
(
localView
.
tree
().
finiteElement
(),
localCoefficients
);
GFE
::
InterpolationDerivatives
<
LocalInterpolationRule
>
interpolationDerivatives
(
localGFEFunction
,
true
,
// doValue
true
);
// doDerivative
/////////////////////////////////////////////////////////////////////////
// Construct the finite difference InterpolationDerivatives object
// that we will use to compare with
/////////////////////////////////////////////////////////////////////////
FiniteDifferenceInterpolationDerivatives
<
LocalInterpolationRule
>
interpolationDerivativesFD
(
localGFEFunction
);
/////////////////////////////////////////////////////////////////////////
// Bind the two objects to a test point, and verify that this
// produces identical results.
/////////////////////////////////////////////////////////////////////////
// InterpolationDerivatives uses ADOL-C by default. Therefore, give a tape number
const
int
tapeNumber
=
0
;
const
typename
Grid
::
template
Codim
<
0
>
::
Entity
::
Geometry
::
LocalCoordinate
position
=
{
0.3
,
0.3
};
typename
TargetSpace
::
CoordinateType
valueGlobalCoordinates
;
typename
TargetSpace
::
CoordinateType
valueFDGlobalCoordinates
;
typename
LocalInterpolationRule
::
DerivativeType
derivative
;
typename
LocalInterpolationRule
::
DerivativeType
derivativeFD
;
interpolationDerivatives
.
bind
(
tapeNumber
,
localView
.
element
(),
position
,
valueGlobalCoordinates
,
derivative
);
TargetSpace
value
(
valueGlobalCoordinates
);
interpolationDerivativesFD
.
bind
(
tapeNumber
,
localView
.
element
(),
position
,
valueFDGlobalCoordinates
,
derivativeFD
);
TargetSpace
valueFD
(
valueFDGlobalCoordinates
);
///////////////////////////////////////////////////////
// Compute the derivatives, and compare them
///////////////////////////////////////////////////////
constexpr
auto
blocksize
=
TargetSpace
::
TangentVector
::
dimension
;
constexpr
auto
embeddedBlocksize
=
TargetSpace
::
EmbeddedTangentVector
::
dimension
;
// Number of dependent variables for the interpolation function
// The sum of the variables for the interpolation value and the variables
// for the derivative
constexpr
auto
m
=
TargetSpace
::
CoordinateType
::
size
()
+
embeddedBlocksize
*
domainDim
;
std
::
vector
<
double
>
weights
(
m
);
for
(
std
::
size_t
i
=
0
;
i
<
m
;
i
++
)
{
std
::
fill
(
weights
.
begin
(),
weights
.
end
(),
0.0
);
weights
[
i
]
=
1.0
;
Matrix
<
double
>
euclideanInterpolationGradient
(
m
,
nDofs
*
embeddedBlocksize
);
Matrix
<
double
>
riemannianInterpolationGradient
(
m
,
nDofs
*
blocksize
);
Matrix
<
FieldMatrix
<
double
,
blocksize
,
blocksize
>
>
interpolationHessian
(
nDofs
,
nDofs
);
interpolationDerivatives
.
evaluateDerivatives
(
tapeNumber
,
weights
.
data
(),
euclideanInterpolationGradient
,
riemannianInterpolationGradient
,
interpolationHessian
);
Matrix
<
double
>
euclideanInterpolationGradientFD
(
m
,
nDofs
*
embeddedBlocksize
);
Matrix
<
double
>
riemannianInterpolationGradientFD
(
m
,
nDofs
*
blocksize
);
Matrix
<
FieldMatrix
<
double
,
blocksize
,
blocksize
>
>
interpolationHessianFD
(
nDofs
,
nDofs
);
interpolationDerivativesFD
.
evaluateDerivatives
(
tapeNumber
,
weights
,
euclideanInterpolationGradientFD
,
riemannianInterpolationGradientFD
,
interpolationHessianFD
);
/////////////////////////////////////////////////////////////////
// Compare the derivatives
/////////////////////////////////////////////////////////////////
auto
riemannianDifference
=
riemannianInterpolationGradient
;
riemannianDifference
-=
riemannianInterpolationGradientFD
;
if
(
std
::
isnan
(
riemannianDifference
.
infinity_norm
())
||
riemannianDifference
.
infinity_norm
()
>
1e-6
)
{
printmatrix
(
std
::
cout
,
riemannianInterpolationGradient
,
"riemannianInterpolationGradient"
,
"--"
);
printmatrix
(
std
::
cout
,
riemannianInterpolationGradientFD
,
"riemannianInterpolationGradientFD"
,
"--"
);
}
auto
euclideanDifference
=
euclideanInterpolationGradient
;
euclideanDifference
-=
euclideanInterpolationGradientFD
;
if
(
std
::
isnan
(
euclideanDifference
.
infinity_norm
())
||
euclideanDifference
.
infinity_norm
()
>
1e-6
)
{
printmatrix
(
std
::
cout
,
euclideanInterpolationGradient
,
"euclideanInterpolationGradient"
,
"--"
);
printmatrix
(
std
::
cout
,
euclideanInterpolationGradientFD
,
"euclideanInterpolationGradientFD"
,
"--"
);
}
auto
hessianDifference
=
interpolationHessian
;
hessianDifference
-=
interpolationHessianFD
;
if
(
std
::
isnan
(
hessianDifference
.
infinity_norm
())
||
hessianDifference
.
infinity_norm
()
>
1e-5
)
{
printmatrix
(
std
::
cout
,
interpolationHessian
,
"interpolationHessian"
,
"--"
);
printmatrix
(
std
::
cout
,
interpolationHessianFD
,
"interpolationHessianFD"
,
"--"
);
}
}
return
test
;
}
int
main
(
int
argc
,
char
*
argv
[])
{
// Set up MPI, if available
MPIHelper
::
instance
(
argc
,
argv
);
TestSuite
test
;
// Test the UnitSphere class and geodesic interpolation.
// This uses the default derivatives implementation (using ADOL-C)
test
.
subTest
(
checkDerivatives
<
UnitVector
<
double
,
3
>
,
InterpolationType
::
Geodesic
>
());
// Test the RealTuple class, both with geodesic and projection-based interpolation
// Both are specialized
test
.
subTest
(
checkDerivatives
<
RealTuple
<
double
,
3
>
,
InterpolationType
::
Geodesic
>
());
test
.
subTest
(
checkDerivatives
<
RealTuple
<
double
,
3
>
,
InterpolationType
::
ProjectionBased
>
());
// Test the UnitVector class with projection-based interpolation
// This is also specialized.
test
.
subTest
(
checkDerivatives
<
UnitVector
<
double
,
3
>
,
InterpolationType
::
ProjectionBased
>
());
return
test
.
exit
();
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment