Newer
Older
#ifndef GLOBAL_GEODESIC_FE_ASSEMBLER_HH
#define GLOBAL_GEODESIC_FE_ASSEMBLER_HH
#include <dune/istl/bcrsmatrix.hh>
#include <dune/common/fmatrix.hh>
#include <dune/istl/matrixindexset.hh>
#include <dune/istl/matrix.hh>
#include "localgeodesicfestiffness.hh"
/** \brief A global FE assembler for problems involving functions that map into non-Euclidean spaces
template <class Basis, class TargetSpace>
class GeodesicFEAssembler {
typedef typename Basis::GridView GridView;
typedef typename GridView::template Codim<0>::template Partition<Dune::Interior_Partition>::Iterator ElementIterator;
//! Dimension of the grid.
enum { gridDim = GridView::dimension };
//! Dimension of a tangent space
enum { blocksize = TargetSpace::TangentVector::dimension };
//!
typedef Dune::FieldMatrix<double, blocksize, blocksize> MatrixBlock;

Oliver Sander
committed
LocalGeodesicFEStiffness<Basis,TargetSpace>* localStiffness_;
/** \brief Constructor for a given grid */
GeodesicFEAssembler(const Basis& basis,

Oliver Sander
committed
LocalGeodesicFEStiffness<Basis, TargetSpace>* localStiffness)
: basis_(basis),
localStiffness_(localStiffness)
/** \brief Assemble the tangent stiffness matrix and the functional gradient together
*
* This is more efficient than computing them separately, because you need the gradient
* anyway to compute the Riemannian Hessian.
virtual void assembleGradientAndHessian(const std::vector<TargetSpace>& sol,
Dune::BlockVector<Dune::FieldVector<double, blocksize> >& gradient,
Dune::BCRSMatrix<MatrixBlock>& hessian,
bool computeOccupationPattern=true) const;
/** \brief Assemble the gradient */
virtual void assembleGradient(const std::vector<TargetSpace>& sol,
Dune::BlockVector<Dune::FieldVector<double, blocksize> >& grad) const;
/** \brief Compute the energy of a deformation state */
virtual double computeEnergy(const std::vector<TargetSpace>& sol) const;
void getNeighborsPerVertex(Dune::MatrixIndexSet& nb) const;
}; // end class
template <class Basis, class TargetSpace>
void GeodesicFEAssembler<Basis,TargetSpace>::
getNeighborsPerVertex(Dune::MatrixIndexSet& nb) const
{
nb.resize(n, n);

Oliver Sander
committed
// A view on the FE basis on a single element
auto localView = basis_.localView();
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)
auto localIndexSet = basis_.localIndexSet();

Oliver Sander
committed
ElementIterator it = basis_.gridView().template begin<0,Dune::Interior_Partition>();
ElementIterator endit = basis_.gridView().template end<0,Dune::Interior_Partition> ();
for (; it!=endit; ++it) {

Oliver Sander
committed
// Bind the local FE basis view to the current element
localView.bind(*it);
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
localIndexSet.bind(localView);

Oliver Sander
committed
const auto& lfe = localView.tree().finiteElement();

Oliver Sander
committed
for (size_t i=0; i<lfe.size(); i++) {

Oliver Sander
committed
for (size_t j=0; j<lfe.size(); j++) {
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
auto iIdx = localIndexSet.index(i)[0];
auto jIdx = localIndexSet.index(j)[0];
#else
auto iIdx = localView.index(i);
auto jIdx = localView.index(j);
#endif
nb.add(iIdx, jIdx);
template <class Basis, class TargetSpace>
void GeodesicFEAssembler<Basis,TargetSpace>::
assembleGradientAndHessian(const std::vector<TargetSpace>& sol,
Dune::BlockVector<Dune::FieldVector<double, blocksize> >& gradient,
Dune::BCRSMatrix<MatrixBlock>& hessian,
bool computeOccupationPattern) const
if (computeOccupationPattern) {
Dune::MatrixIndexSet neighborsPerVertex;
getNeighborsPerVertex(neighborsPerVertex);
neighborsPerVertex.exportIdx(hessian);
hessian = 0;
gradient.resize(sol.size());
gradient = 0;

Oliver Sander
committed
// A view on the FE basis on a single element
auto localView = basis_.localView();
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)
auto localIndexSet = basis_.localIndexSet();

Oliver Sander
committed
ElementIterator it = basis_.gridView().template begin<0,Dune::Interior_Partition>();
ElementIterator endit = basis_.gridView().template end<0,Dune::Interior_Partition> ();
for( ; it != endit; ++it ) {

Oliver Sander
committed
localView.bind(*it);
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
localIndexSet.bind(localView);

Oliver Sander
committed
const int numOfBaseFct = localView.tree().size();
// Extract local solution
std::vector<TargetSpace> localSolution(numOfBaseFct);
for (int i=0; i<numOfBaseFct; i++)
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
localSolution[i] = sol[localIndexSet.index(i)[0]];
#else
localSolution[i] = sol[localView.index(i)];
#endif
std::vector<Dune::FieldVector<double,blocksize> > localGradient(numOfBaseFct);
// setup local matrix and gradient
localStiffness_->assembleGradientAndHessian(localView, localSolution, localGradient);
// Add element matrix to global stiffness matrix
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
auto row = localIndexSet.index(i)[0];
#else
auto row = localView.index(i);
#endif
for (int j=0; j<numOfBaseFct; j++ ) {
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
auto col = localIndexSet.index(j)[0];
#else
auto col = localView.index(j);
#endif
hessian[row][col] += localStiffness_->A_[i][j];
// Add local gradient to global gradient
for (int i=0; i<numOfBaseFct; i++)
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
gradient[localIndexSet.index(i)[0]] += localGradient[i];
#else
gradient[localView.index(i)] += localGradient[i];
#endif
}
}
template <class Basis, class TargetSpace>
void GeodesicFEAssembler<Basis,TargetSpace>::
assembleGradient(const std::vector<TargetSpace>& sol,
Dune::BlockVector<Dune::FieldVector<double, blocksize> >& grad) const
{
if (sol.size()!=basis_.size())
DUNE_THROW(Dune::Exception, "Solution vector doesn't match the grid!");
grad.resize(sol.size());
grad = 0;

Oliver Sander
committed
// A view on the FE basis on a single element
auto localView = basis_.localView();
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)
auto localIndexSet = basis_.localIndexSet();

Oliver Sander
committed
ElementIterator it = basis_.gridView().template begin<0,Dune::Interior_Partition>();
ElementIterator endIt = basis_.gridView().template end<0,Dune::Interior_Partition>();
// Loop over all elements
for (; it!=endIt; ++it) {

Oliver Sander
committed
localView.bind(*it);
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
localIndexSet.bind(localView);

Oliver Sander
committed
// A 1d grid has two vertices

Oliver Sander
committed
const auto nDofs = localView.tree().size();
// Extract local solution
std::vector<TargetSpace> localSolution(nDofs);
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
localSolution[i] = sol[localIndexSet.index(i)[0]];
#else
localSolution[i] = sol[localView.index(i)];
#endif
// Assemble local gradient
std::vector<Dune::FieldVector<double,blocksize> > localGradient(nDofs);
localStiffness_->assembleGradient(localView, localSolution, localGradient);
// Add to global gradient
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
grad[localIndexSet.index(i)[0]] += localGradient[i];
#else
grad[localView.index(i)[0]] += localGradient[i];
#endif
template <class Basis, class TargetSpace>
double GeodesicFEAssembler<Basis, TargetSpace>::
computeEnergy(const std::vector<TargetSpace>& sol) const
{
double energy = 0;
if (sol.size() != basis_.size())

Oliver Sander
committed
DUNE_THROW(Dune::Exception, "Coefficient vector doesn't match the function space basis!");

Oliver Sander
committed
// A view on the FE basis on a single element
auto localView = basis_.localView();
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)
auto localIndexSet = basis_.localIndexSet();

Oliver Sander
committed
ElementIterator it = basis_.gridView().template begin<0,Dune::Interior_Partition>();
ElementIterator endIt = basis_.gridView().template end<0,Dune::Interior_Partition>();
// Loop over all elements
for (; it!=endIt; ++it) {

Oliver Sander
committed
localView.bind(*it);
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
localIndexSet.bind(localView);

Oliver Sander
committed
// Number of degrees of freedom on this element

Oliver Sander
committed
size_t nDofs = localView.tree().size();
std::vector<TargetSpace> localSolution(nDofs);
#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7)

Oliver Sander
committed
localSolution[i] = sol[localIndexSet.index(i)[0]];
#else
localSolution[i] = sol[localView.index(i)[0]];
#endif
energy += localStiffness_->energy(localView, localSolution);