Commit a1c2c4f1 authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

new global assembler class finished, needs some more corrections

parent 5de54da3
......@@ -6,9 +6,10 @@
#include <dune/common/fmatrix.hh>
#include <dune/common/fvector.hh>
#include <dune/amdis/FiniteElementSpaces.hpp>
#include <dune/amdis/LinearAlgebra.hpp>
#include <dune/amdis/LocalFiniteElemenet.hpp>
#include <dune/amdis/common/Mpl.hpp>
#include <dune/amdis/common/TypeDefs.hpp>
namespace AMDiS
{
......@@ -27,6 +28,9 @@ namespace AMDiS
template <class T>
using VectorEntries = Dune::FieldVector<T, nComponents>;
using ElementVector = Impl::ElementVector;
using ElementMatrix = Impl::ElementMatrix;
public:
/// Constructor, stores a shared-pointer to the feSpaces
Assembler(std::shared_ptr<FeSpaces> const& feSpaces_)
......@@ -42,92 +46,103 @@ namespace AMDiS
/// Assemble the linear system
template <class Operators>
void assemble(SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_);
void assemble(
SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_);
private:
// Return whether the matrix-block needs to be assembled
template <int R, int C, class Operators>
bool assembleMatrix(const index_t<R>, const index_t<C>,
MatrixEntries<Operators> const& matrix_operators, bool asmMatrix_) const
{
return asmMatrix_ && (!matrix_operators[R][C].assembled || matrix_operators[R][C].changing);
}
// Return whether the vector-block needs to be assembled
template <int R, class Operators>
bool assembleVector(const index_t<R>, VectorEntries<Operators> const& rhs_operators, bool asmVector_) const
{
return asmVector_ && (!rhs_operators[R].assembled || rhs_operators[R].changing);
}
// Sets the system to zero and initializes all operators and boundary conditions
/// Sets the system to zero and initializes all operators and boundary conditions
template <class Operators>
void initMatrixVector(SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_);
void initMatrixVector(
SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_);
/// Assemble a block-matrix of element-matrices and return a matrix of flags, whether
/// a given block has received some entries.
template <class Operators>
MatrixEntries<bool> assembleElementMatrices(MatrixEntries<Operators>& operators,
MatrixEntries<ElementMatrix>& elementMatrix,
LocalFiniteElement<FeSpaces> const& localFiniteElem,
bool asmMatrix_);
MatrixEntries<bool> assembleElementMatrices(
MatrixEntries<Operators>& operators,
MatrixEntries<ElementMatrix>& elementMatrix,
FiniteElementSpaces<FeSpaces> const& elementBases,
bool asmMatrix_);
/// Assemble a block-vector of element-vectors and return a vector of flags, whether
/// a given block has received some entries.
template <class Operators>
VectorEntries<bool> assembleElementVectors(VectorEntries<Operators>& operators,
VectorEntries<ElementVector>& elementVector,
LocalFiniteElement<FeSpaces> const& localFiniteElem,
bool asmVector_);
VectorEntries<bool> assembleElementVectors(
VectorEntries<Operators>& operators,
VectorEntries<ElementVector>& elementVector,
FiniteElementSpaces<FeSpaces> const& elementBases,
bool asmVector_);
/// Assemble one block of the block-element-matrix
// The MatrixData argument stores all matrix-operators
template <class Operators, class RowView, class ColView>
bool assembleElementMatrix(Operators& operators,
ElementMatrix& elementMatrix,
RowView const& rowLocalView, ColView const& colLocalView);
bool assembleElementMatrix(
Operators& operators,
ElementMatrix& elementMatrix,
RowView const& rowLocalView,
ColView const& colLocalView);
/// Assemble one block of the block-element-vector
// The VectorData argument stores all vector-operators
template <class Operators, class RowView>
bool assembleElementVector(Operators& operators,
ElementVector& elementVector,
RowView const& rowLocalView);
bool assembleElementVector(
Operators& operators,
ElementVector& elementVector,
RowView const& rowLocalView);
/// Add the block-element-matrix to the system-matrix
void addElementMatrices(SystemMatrixType& dofmatrix,
LocalFiniteElement<FeSpaces> const& localFiniteElem,
MatrixEntries<bool> const& addMat,
MatrixEntries<ElementMatrix> const& elementMatrix);
void addElementMatrices(
SystemMatrixType& dofmatrix,
FiniteElementSpaces<FeSpaces> const& elementBases,
MatrixEntries<bool> const& addMat,
MatrixEntries<ElementMatrix> const& elementMatrix);
/// Add the block-element-vector to the system-vector
void addElementVectors(SystemVectorType& dofvector,
LocalFiniteElement<FeSpaces> const& localFiniteElem,
VectorEntries<bool> const& addVec,
VectorEntries<ElementVector> const& elementVector);
void addElementVectors(
SystemVectorType& dofvector,
FiniteElementSpaces<FeSpaces> const& elementBases,
VectorEntries<bool> const& addVec,
VectorEntries<ElementVector> const& elementVector);
/// Finish insertion into the matrix and assembles boundary conditions
/// Return the number of nonzeros assembled into the matrix
template <class Operators>
std::size_t finishMatrixVector(SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_);
std::size_t finishMatrixVector(
SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_);
/// Return whether the matrix-block needs to be assembled
template <std::size_t R, std::size_t C, class Operators>
bool assembleMatrix(const index_t<R>, const index_t<C>,
MatrixEntries<Operators> const& matrix_operators, bool asmMatrix_) const
{
return asmMatrix_ && (!matrix_operators[R][C].assembled || matrix_operators[R][C].changing);
}
/// Return whether the vector-block needs to be assembled
template <std::size_t R, class Operators>
bool assembleVector(const index_t<R>, VectorEntries<Operators> const& rhs_operators, bool asmVector_) const
{
return asmVector_ && (!rhs_operators[R].assembled || rhs_operators[R].changing);
}
private:
std::shared_ptr<FeSpaces> feSpaces;
......
......@@ -4,37 +4,39 @@ namespace AMDiS {
template <class FeSpaces>
template <class Operators>
void Assembler<FeSpaces>::
assemble(SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_)
void Assembler<FeSpaces>::assemble(
SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_)
{
// 1. init matrix and rhs vector and initialize dirichlet boundary conditions
initMatrixVector(matrix, solution, rhs, matrix_operators, rhs_operators, asmMatrix_, asmVector_);
// 2. create a localView and localIndexSet object for each global basis
LocalFiniteElement<FeSpaces> localFiniteElem(*feSpaces);
FiniteElementSpaces<FeSpaces> elementBases(*feSpaces);
// 3. traverse grid and assemble operators on the elements
for (auto const& element : elements(gridView))
for (auto const& element : elements(elementBases.gridView()))
{
localFiniteElem.bind(element);
elementBases.bind(element);
#if 0
MatrixEntries<ElementMatrix> elementMatrix;
VectorEntries<ElementVector> elementVector;
MatrixEntries<bool> addMat = assembleElementMatrices(matrix_operators, elementMatrix, localFiniteElem, asmMatrix_);
VectorEntries<bool> addVec = assembleElementVectors(rhs_operators, elementVector, localFiniteElem, asmVector_);
MatrixEntries<bool> addMat = assembleElementMatrices(matrix_operators, elementMatrix, elementBases, asmMatrix_);
VectorEntries<bool> addVec = assembleElementVectors(rhs_operators, elementVector, elementBases, asmVector_);
addElementMatrices(matrix, localFiniteElem, addMat, elementMatrix);
addElementVectors(rhs, localFiniteElem, addVec, elementVector);
addElementMatrices(matrix, elementBases, addMat, elementMatrix);
addElementVectors(rhs, elementBases, addVec, elementVector);
#endif
elementBases.unbind();
}
// 4. finish matrix insertion and apply dirichlet boundary conditions
std::size_t nnz = finishMatrixVector(asmMatrix_, asmVector_);
std::size_t nnz = finishMatrixVector(matrix, solution, rhs, matrix_operators, rhs_operators, asmMatrix_, asmVector_);
msg("fillin of assembled matrix: ", nnz);
}
......@@ -42,51 +44,54 @@ assemble(SystemMatrixType& matrix,
template <class FeSpaces>
template <class Operators>
void Assembler<FeSpaces>::
initMatrixVector(SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_)
void Assembler<FeSpaces>::initMatrixVector(
SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_)
{
forEach(range_<0, nComponents>, [&,this](auto const _r)
{
static const int R = decltype(_r)::value;
msg(this->getFeSpace(_r).size(), " DOFs for FeSpace[", R, "]");
auto const& rowFeSpace = std::get<R>(*feSpaces);
msg(rowFeSpace.size(), " DOFs for FeSpace[", R, "]");
if (assembleVector(_r, rhs_operators, asmVector_)) {
if (this->assembleVector(_r, rhs_operators, asmVector_)) {
rhs.compress(_r);
rhs.getVector(_r) = 0.0;
// init vector operators
for (auto& op : rhs_operators[R].element)
op.init(this->getFeSpace(_r));
for (auto& op : rhs_operators[R].boundary)
op.init(this->getFeSpace(_r));
for (auto& op : rhs_operators[R].intersection)
op.init(this->getFeSpace(_r));
for (auto& scaled : rhs_operators[R].element)
scaled.op->init(rowFeSpace);
for (auto& scaled : rhs_operators[R].boundary)
scaled.op->init(rowFeSpace);
for (auto& scaled : rhs_operators[R].intersection)
scaled.op->init(rowFeSpace);
}
forEach(range_<0, nComponents>, [&,this](auto const _c)
{
static const int C = decltype(_c)::value;
auto const& colFeSpace = std::get<C>(*feSpaces);
bool asmMatrix = assembleMatrix(_r, _c, matrix_operators, asmMatrix_);
bool asmMatrix = this->assembleMatrix(_r, _c, matrix_operators, asmMatrix_);
matrix(_r, _c).init(asmMatrix);
if (asmMatrix) {
// init matrix operators
for (auto& op : matrix_operators[R][C].element)
op.init(this->getFeSpace(_r), this->getFeSpace(_c));
for (auto& op : matrix_operators[R][C].boundary)
op.init(this->getFeSpace(_r), this->getFeSpace(_c));
for (auto& op : matrix_operators[R][C].intersection)
op.init(this->getFeSpace(_r), this->getFeSpace(_c));
for (auto& scaled : matrix_operators[R][C].element)
scaled.op->init(rowFeSpace, colFeSpace);
for (auto& scaled : matrix_operators[R][C].boundary)
scaled.op->init(rowFeSpace, colFeSpace);
for (auto& scaled : matrix_operators[R][C].intersection)
scaled.op->init(rowFeSpace, colFeSpace);
// init boundary condition
for (int c = 0; c < nComponents; ++c)
for (auto bc : dirichletBc[R][c])
for (auto bc : matrix_operators[R][c].dirichlet)
bc->init(c == C, matrix(_r, _c), solution[_c], rhs[_r]);
}
});
......@@ -96,10 +101,12 @@ initMatrixVector(SystemMatrixType& matrix,
template <class FeSpaces>
template <class Operators>
MatrixEntries<bool> Assembler<FeSpaces>::
assembleElementMatrices(MatrixEntries<Operators>& operators,
MatrixEntries<ElementMatrix>& elementMatrix,
LocalFiniteElement<FeSpaces> const& localFiniteElem, bool asmMatrix_)
typename Assembler<FeSpaces>::template MatrixEntries<bool>
Assembler<FeSpaces>::assembleElementMatrices(
MatrixEntries<Operators>& operators,
MatrixEntries<ElementMatrix>& elementMatrix,
FiniteElementSpaces<FeSpaces> const& elementBases,
bool asmMatrix_)
{
MatrixEntries<bool> addMat;
forEach(range_<0, nComponents>, [&,this](auto const _r)
......@@ -110,9 +117,9 @@ assembleElementMatrices(MatrixEntries<Operators>& operators,
static const std::size_t C = decltype(_c)::value;
// assemble block of element matrix
addMat[R][C] = assembleMatrix(_r, _c, operators, asmMatrix_)
? assembleElementMatrix(operators[R][C], elementMatrix[R][C],
localFiniteElem.localView(_r), localFiniteElem.localView(_c))
addMat[R][C] = this->assembleMatrix(_r, _c, operators, asmMatrix_)
? this->assembleElementMatrix(operators[R][C], elementMatrix[R][C],
elementBases.localView(_r), elementBases.localView(_c))
: false;
});
});
......@@ -123,10 +130,12 @@ assembleElementMatrices(MatrixEntries<Operators>& operators,
template <class FeSpaces>
template <class Operators>
VectorEntries<bool> Assembler<FeSpaces>::
assembleElementVectors(VectorEntries<Operators>& operators,
VectorEntries<ElementVector>& elementVector,
LocalFiniteElement<FeSpaces> const& localFiniteElem, bool asmVector_)
typename Assembler<FeSpaces>::template VectorEntries<bool>
Assembler<FeSpaces>::assembleElementVectors(
VectorEntries<Operators>& operators,
VectorEntries<ElementVector>& elementVector,
FiniteElementSpaces<FeSpaces> const& elementBases,
bool asmVector_)
{
VectorEntries<bool> addVec;
forEach(range_<0, nComponents>, [&,this](auto const _r)
......@@ -134,8 +143,8 @@ assembleElementVectors(VectorEntries<Operators>& operators,
static const std::size_t R = decltype(_r)::value;
// assemble block of element vector
addVec[R] = assembleVector(_r, operators, asmVector_)
? assembleElementVector(operators[R], elementVector[R], localFiniteElem.localView(_r))
addVec[R] = this->assembleVector(_r, operators, asmVector_)
? this->assembleElementVector(operators[R], elementVector[R], elementBases.localView(_r))
: false;
});
......@@ -145,11 +154,11 @@ assembleElementVectors(VectorEntries<Operators>& operators,
template <class FeSpaces>
template <class Operators, class RowView, class ColView>
bool Assembler<FeSpaces>::
assembleElementMatrix(Operators& operators,
ElementMatrix& elementMatrix,
RowView const& rowLocalView,
ColView const& colLocalView)
bool Assembler<FeSpaces>::assembleElementMatrix(
Operators& operators,
ElementMatrix& elementMatrix,
RowView const& rowLocalView,
ColView const& colLocalView)
{
if (operators.element.empty() && operators.boundary.empty() && operators.intersection.empty())
return false; // nothing to do
......@@ -194,10 +203,11 @@ assembleElementMatrix(Operators& operators,
template <class FeSpaces>
template <class Operators, class RowView>
bool Assembler<FeSpaces>::
assembleElementVector(Operators& operators, ElementVector& elementVector, RowView const& rowLocalView)
bool Assembler<FeSpaces>::assembleElementVector(
Operators& operators,
ElementVector& elementVector,
RowView const& rowLocalView)
{
if (operators.element.empty() && operators.boundary.empty() && operators.intersection.empty())
return false;
......@@ -239,11 +249,11 @@ assembleElementVector(Operators& operators, ElementVector& elementVector, RowVie
template <class FeSpaces>
void Assembler<FeSpaces>::
addElementMatrices(SystemMatrixType& dofmatrix,
LocalFiniteElement<FeSpaces> const& localFiniteElem,
MatrixEntries<bool> const& addMat,
MatrixEntries<ElementMatrix> const& elementMatrix)
void Assembler<FeSpaces>::addElementMatrices(
SystemMatrixType& dofmatrix,
FiniteElementSpaces<FeSpaces> const& elementBases,
MatrixEntries<bool> const& addMat,
MatrixEntries<ElementMatrix> const& elementMatrix)
{
forEach(range_<0, nComponents>, [&,this](auto const _r)
{
......@@ -254,6 +264,9 @@ addElementMatrices(SystemMatrixType& dofmatrix,
if (!addMat[R][C])
return;
auto const& rowIndexSet = elementBases.localIndexSet(_r);
auto const& colIndexSet = elementBases.localIndexSet(_c);
// NOTE: current implementation does not utilize the multi-indices that we get from localIndexSet.
for (std::size_t i = 0; i < num_rows(elementMatrix[R][C]); ++i) {
......@@ -262,7 +275,7 @@ addElementMatrices(SystemMatrixType& dofmatrix,
for (std::size_t j = 0; j < num_cols(elementMatrix[R][C]); ++j) {
// The global index of the j−th vertex of the element
auto const col = colIndexSet.index(j);
dofmatrix[R][C](row,col) += elementMatrix[R][C](i,j);
dofmatrix(_r,_c)(row,col) += elementMatrix[R][C](i,j);
}
}
});
......@@ -271,11 +284,11 @@ addElementMatrices(SystemMatrixType& dofmatrix,
template <class FeSpaces>
void Assembler<FeSpaces>::
addElementVectors(SystemVectorType& dofvector,
LocalFiniteElement<FeSpaces> const& localFiniteElem,
VectorEntries<bool> const& addVec,
VectorEntries<ElementVector> const& elementVector)
void Assembler<FeSpaces>::addElementVectors(
SystemVectorType& dofvector,
FiniteElementSpaces<FeSpaces> const& elementBases,
VectorEntries<bool> const& addVec,
VectorEntries<ElementVector> const& elementVector)
{
forEach(range_<0, nComponents>, [&,this](auto const _r)
{
......@@ -283,10 +296,12 @@ addElementVectors(SystemVectorType& dofvector,
if (!addVec[R])
return;
auto const& localIndexSet = elementBases.localIndexSet(_r);
for (std::size_t i = 0; i < size(elementVector[R]); ++i) {
// The global index of the i-th vertex
auto const row = indexSet.index(i);
dofvector[R][row] += elementVector[R][i];
auto const row = localIndexSet.index(i);
dofvector[_r][row] += elementVector[R][i];
}
});
}
......@@ -294,29 +309,31 @@ addElementVectors(SystemVectorType& dofvector,
template <class FeSpaces>
template <class Operators>
std::size_t Assembler<FeSpaces>::
finishMatrixVector(SystemMatrixType& matrix, SystemVectorType& solution, SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators, VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_)
std::size_t Assembler<FeSpaces>::finishMatrixVector(
SystemMatrixType& matrix,
SystemVectorType& solution,
SystemVectorType& rhs,
MatrixEntries<Operators>& matrix_operators,
VectorEntries<Operators>& rhs_operators,
bool asmMatrix_, bool asmVector_)
{
std::size_t nnz = 0;
forEach(range_<0, nComponents>, [&,this](auto const _r)
{
static const int R = decltype(_r)::value;
if (assembleVector(asmVector_, _r))
if (this->assembleVector(_r, rhs_operators, asmVector_))
rhs_operators[R].assembled = true;
forEach(range_<0, nComponents>, [&,this](auto const _c)
{
static const int C = decltype(_c)::value;
bool asmMatrix = assembleMatrix(asmMatrix_, _r, _c);
bool asmMatrix = this->assembleMatrix(_r, _c, matrix_operators, asmMatrix_);
matrix(_r, _c).finish();
if (asmMatrix)
if (asmMatrix) {
matrix_operators[R][C].assembled = true;
if (asmMatrix) {
// finish boundary condition
for (int c = 0; c < nComponents; ++c) {
for (int r = 0; r < nComponents; ++r) {
......@@ -328,6 +345,7 @@ finishMatrixVector(SystemMatrixType& matrix, SystemVectorType& solution, SystemV
}
nnz += matrix(_r, _c).getNnz();
}
});
});
......
......@@ -21,25 +21,6 @@ add_dune_alberta_flags("duneamdis" OBJECT USE_GENERIC)
target_compile_definitions("duneamdis" PUBLIC AMDIS_BACKEND_MTL=1)
target_compile_options("duneamdis" PUBLIC -ftemplate-backtrace-limit=0)
# set(BOOST_VERSION "1.54")
# set(BOOST_LIBS_REQUIRED system program_options)
# if (NOT BUILD_SHARED_LIBS)
# set(Boost_USE_STATIC_LIBS ON)
# endif (NOT BUILD_SHARED_LIBS)
# find_package(Boost ${BOOST_VERSION} REQUIRED ${BOOST_LIBS_REQUIRED})
# if (Boost_FOUND)
# add_library(boost INTERFACE)
# target_include_directories(boost INTERFACE ${Boost_INCLUDE_DIR})
# target_link_libraries(boost INTERFACE ${Boost_LIBRARIES})
# target_link_libraries(duneamdis INTERFACE boost)
# if (MSVC_SHARED_LIBS)
# link_directories(${Boost_LIBRARY_DIRS})
# target_compile_definitions("duneamdis" INTERFACE ${Boost_LIB_DIAGNOSTIC_DEFINITIONS})
# endif (MSVC_SHARED_LIBS)
# endif (Boost_FOUND)
find_package(MTL REQUIRED
PATHS /usr/local/lib/mtl4)
if (MTL_FOUND)
......
#pragma once
#include <tuple>
#include <dune/amdis/common/TupleUtility.hpp>
#include <dune/amdis/common/IndexSeq.hpp>
namespace AMDiS
{
namespace Impl
{
template <template<class> class Base, class Tuple, class Indices> struct MakeTupleType;
template <template<class> class Base, class Tuple, std::size_t... I>
struct MakeTupleType<Base, Tuple, Indices<I...>>
{
using type = std::tuple<typename Base<std::tuple_element_t<I, Tuple>>::type...>;
};
/// Constructs tuple type, by wrapping Base around the tuple elements.
/// Returns tuple type tuple<Base<tuple_element_t<0>>::type, Base<tuple_element_t<1>>::type, ...>
template <template<class> class Base, class Tuple>
using MakeTupleType_t =
typename MakeTupleType<Base, Tuple, MakeSeq_t<std::tuple_size<Tuple>::value>>::type;
template <class Functor, class Tuple, std::size_t... I>
auto makeTupleType(Functor f, Tuple&& tuple, Indices<I...>)
{
return std::make_tuple(f(std::get<I>(std::forward<Tuple>(tuple>)))...);
}
// construction method to construct a tuple of DOFVectors
template <class Functor, class Tuple>
auto makeTupleType(Functor f, Tuple&& tuple)
{
return makeTupleType(f, std::forward<Tuple>(tuple), MakeSeq_t<std::tuple_size<Tuple>::value>{});
}
} // end namespace Impl
template <class FeSpace>
struct LocalView
{
......@@ -52,15 +19,17 @@ namespace AMDiS
template <class FeSpaces>
class LocalFiniteElement
class FiniteElementSpaces
{
template <std::size_t I>
using FeSpace = std::tuple_element_t<I, FeSpaces>;
static constexpr int nComponents = std::tuple_size<FeSpaces>::value;
using LocalViews = Impl::MakeTupleType_t<LocalView, FeSpaces>;
using LocalIndexSets = Impl::MakeTupleType_t<LocalIndexSet, FeSpaces>;
static_assert( nComponents > 0, "" );