13#ifndef MG_PROLONGATION_HH
14#define MG_PROLONGATION_HH
16#include <boost/fusion/include/vector.hpp>
17#include <boost/timer/timer.hpp>
42 template <
class SparseIndex=
size_t,
class CoarseSpace,
class FineSpace>
44 FineSpace
const& fineSpace)
49 timer.
start(
"space prolongation");
51 std::vector<bf::vector<std::vector<size_t>,std::vector<size_t>,
55 typename CoarseSpace::Mapper::ShapeFunctionSet::SfValueArray afValues;
59 for (
auto const& cell: elements(fineSpace.gridView()))
61 auto index = fineSpace.indexSet().index(cell);
65 auto const& fineIndices = fineSpace.mapper().globalIndices(index);
66 auto const& coarseIndices = coarseSpace.mapper().globalIndices(index);
67 std::copy(fineIndices.begin(), fineIndices.end(), std::back_inserter(bf::at_c<0>(interpolationData[index])));
68 std::copy(coarseIndices.begin(),coarseIndices.end(),std::back_inserter(bf::at_c<1>(interpolationData[index])));
70 auto const& fineSfs = fineSpace.mapper().shapefunctions(cell);
71 auto const& coarseSfs = coarseSpace.mapper().shapefunctions(cell);
74 auto const& iNodes(fineSpace.mapper().shapefunctions(cell).interpolationNodes());
82 timer.
stop(
"space prolongation");
84 timer.
start(
"matrix creation");
90 for (
auto const& block: interpolationData)
91 for (
int i=0; i<bf::at_c<0>(block).size(); ++i)
92 for (
int j=0; j<bf::at_c<1>(block).size(); ++j)
94 auto entry = bf::at_c<2>(block)[i][j];
95 if (std::abs(entry) > 1e-12)
96 creator.
addElement(bf::at_c<0>(block)[i],bf::at_c<1>(block)[j]);
104 for (
auto const& block: interpolationData)
105 for (
int i=0; i<bf::at_c<0>(block).size(); ++i)
106 for (
int j=0; j<bf::at_c<1>(block).size(); ++j)
108 auto entry = bf::at_c<2>(block)[i][j];
109 if (std::abs(entry) > 1e-12)
110 p[bf::at_c<0>(block)[i]][bf::at_c<1>(block)[j]] = entry;
113 timer.
stop(
"matrix creation");
129 template <
class SparseIndex,
class Mapper>
130 std::vector<NumaBCRSMatrix<Dune::FieldMatrix<typename Mapper::Scalar,1,1>,SparseIndex>>
133 std::vector<NumaBCRSMatrix<Dune::FieldMatrix<typename Mapper::Scalar,1,1>,SparseIndex>> stack;
134 int p = space.
mapper().maxOrder();
140 stack.push_back(prolongation<SparseIndex>(coarseSpace,space));
149 namespace ProlongationDetail
183 size_t nc,
int fineLevel);
191 std::array<size_t,2>
const&
parents(
size_t i)
const
203 template <
class Vector>
206 assert(f.size()==entries.size());
207 assert(c.size()==nc);
209 for (
size_t row=0; row<entries.size(); ++row)
211 auto e = entries[row];
212 f[row] +=
static_cast<typename Vector::field_type
>(0.5)*(c[e[0]] + c[e[1]]);
227 template <
class Vector>
230 assert(f.size()==entries.size());
231 assert(c.size()==nc);
233 for (
size_t row=0; row<entries.size(); ++row)
235 auto e = entries[row];
236 f[row] =
static_cast<typename Vector::field_type
>(0.5)*(c[e[0]] + c[e[1]]);
247 template <
class Vector>
250 assert(f.size()==entries.size());
253 for (
size_t i=0; i<c.N(); ++i)
256 for (
size_t row=0; row<entries.size(); ++row)
258 c[entries[row][0]] +=
static_cast<typename Vector::field_type
>(0.5)*f[row];
259 c[entries[row][1]] +=
static_cast<typename Vector::field_type
>(0.5)*f[row];
268 return entries.size();
282 template <
class Real>
287 for (
size_t i=0; i<
N(); ++i)
288 creator.
addElements(&i,&i+1,begin(entries[i]),end(entries[i]));
291 for (
size_t i=0; i<
N(); ++i)
292 for (
size_t j: entries[i])
308 template <
class Entry,
class Index>
311 assert(A.
N()==
N() && A.
M()==
N());
323 timer.
start(
"h conjugation pattern");
324 for (Index k=0; k<A.
N(); ++k)
326 auto const& is = entries[k];
328 for (
auto ca=row.begin(); ca!=row.end(); ++ca)
330 Index
const l = ca.index();
331 auto const& js = entries[l];
333 if (is[0]==is[1] && js[0]==js[1])
335 else if (is[0]==is[1])
336 creator.
addElements(std::begin(is),std::begin(is)+1,std::begin(js),std::end(js));
337 else if (js[0]==js[1])
338 creator.
addElements(std::begin(is),std::end(is),std::begin(js),std::begin(js)+1);
340 creator.
addElements(std::begin(is),std::end(is),std::begin(js),std::end(js));
342 if (onlyLowerTriangle && k>l)
343 creator.
addElements(std::begin(js),std::end(js),std::begin(is),std::end(is));
346 timer.
stop(
"h conjugation pattern");
361 timer.
start(
"matrix creation");
363 timer.
stop(
"matrix creation");
367 timer.
start(
"matrix conjugation");
368 for (Index k=0; k<A.
N(); ++k)
370 auto const& is = entries[k];
372 for (
auto ca=row.begin(); ca!=row.end(); ++ca)
374 Index
const l = ca.index();
375 auto const& js = entries[l];
377 if (is[0]==is[1] && js[0]==js[1])
378 pap[is[0]][js[0]] += *ca;
381 auto pap0 = pap[is[0]];
382 static typename Entry::field_type
const quarter = 0.25;
383 pap0[js[0]] += quarter * *ca;
384 pap0[js[1]] += quarter * *ca;
386 auto pap1 = pap[is[1]];
387 pap1[js[0]] += quarter * *ca;
388 pap1[js[1]] += quarter * *ca;
391 if (onlyLowerTriangle)
395 timer.
stop(
"matrix conjugation");
406 std::vector<std::array<size_t,2>> entries;
420 template <
class Entry,
class Index>
423 return p.template galerkinProjection(a,onlyLowerTriangle);
429 namespace ProlongationDetail
433 template <
class LeafView,
class Cell,
class Parents>
434 void computeParents(LeafView
const& leafView,
Cell const& cell, Parents& parents)
437 if (!cell.hasFather())
440 int const dim = LeafView::dimension;
446 assert(cell.type().isSimplex());
447 auto const& geo = cell.geometryInFather();
448 int nCorners = geo.corners();
449 for (
int i=0; i<nCorners; ++i)
466 for (
int k=0; k<b.N(); ++k)
467 if (std::abs(b[k]-0.5) < 0.01)
469 pc[pcount] = (k+1) % (dim+1);
475 auto const& is = leafView.indexSet();
476 parents.push_back(std::make_pair(is.index(cell.template subEntity<dim>(i)),
477 Node{is.index(cell.father().template subEntity<dim>(pc[0])),
478 is.index(cell.father().template subEntity<dim>(pc[1])),
486 template <
class LeafView,
class Cell,
class Parents>
487 void computeShiftedParents(LeafView
const& leafView,
Cell const& cell, Parents& parents,
488 bool interpolateAtShiftedPosition=
true)
491 if (!cell.hasFather())
494 int const dim = LeafView::dimension;
500 assert(cell.type().isSimplex());
501 auto const& geo = cell.geometryInFather();
502 int nCorners = geo.corners();
503 for (
int i=0; i<nCorners; ++i)
511 for (
int k=0; k<b.N(); ++k)
512 if (std::abs(b[k]-0.5) < 0.01)
514 pc[pcount] = (k+1) % (dim+1);
520 auto x = cell.geometry().corner(i);
521 auto y0 = cell.father().geometry().corner(pc[0]);
522 auto y1 = cell.father().geometry().corner(pc[1]);
524 auto const& is = leafView.indexSet();
525 std::vector<std::pair<size_t,double>> parentVertices;
527 if (!interpolateAtShiftedPosition ||
528 (0.5*(y0+y1)-x).two_norm() < 1e-5*(y0-y1).two_norm())
530 parentVertices.push_back(std::make_pair(is.index(cell.father().template subEntity<dim>(pc[0])),0.5));
531 parentVertices.push_back(std::make_pair(is.index(cell.father().template subEntity<dim>(pc[1])),0.5));
538 for (
int j=0; j<=dim; ++j)
540 auto vj = cell.father().geometry().corner(j);
541 for (
int k=0; k<dim; ++k)
546 for (
int k=0; k<dim; ++k)
551 for (
int j=0; j<=dim; ++j)
552 parentVertices.push_back(std::make_pair(is.index(cell.father().template subEntity<dim>(j)),w[j]));
556 parents.push_back(std::make_tuple(
static_cast<size_t>(is.index(cell.template subEntity<dim>(i))),
557 cell.level(),parentVertices));
567 std::vector<MGProlongation> makeProlongationStack(std::vector<Node> parents,
int maxLevel,
int minLevel,
size_t minNodes);
569 std::vector<NumaBCRSMatrix<Dune::FieldMatrix<double,1,1>>>
570 makeDeformedProlongationStack(std::vector<std::pair<
int,std::vector<std::pair<size_t,double>>>>,
571 int maxLevel,
int minLevel,
size_t minNodes);
587 template <
class Gr
idMan>
588 std::vector<MGProlongation>
prolongationStack(GridMan
const& gridman,
int coarseLevel=0,
size_t minNodes=0)
592 auto const& grid = gridman.grid();
593 auto const& leafView = grid.leafGridView();
594 auto const& cellRanges = gridman.cellRanges(grid.levelGridView(0));
597 timer.
start(
"parent computation");
598 std::vector<std::vector<std::pair<size_t,ProlongationDetail::Node>>> myParents(cellRanges.maxRanges());
601 for (
auto const& coarseCell: cellRanges.range(n,k))
602 for (
auto const& cell: descendantElements(coarseCell,grid.maxLevel()))
603 ProlongationDetail::computeParents(leafView,cell,myParents[k]);
608 std::vector<ProlongationDetail::Node> parents(leafView.size(leafView.dimension),ProlongationDetail::Node{0,0,-1});
609 for (
auto const& ps: myParents)
610 for (
auto const& p: ps)
611 parents[p.first] = p.second;
612 timer.
stop(
"parent computation");
616 timer.
start(
"made stack parents");
617 auto ps = ProlongationDetail::makeProlongationStack(std::move(parents),grid.maxLevel(),coarseLevel,minNodes);
618 timer.
stop(
"made stack parents");
642 template <
class Gr
idMan>
643 std::vector<NumaBCRSMatrix<Dune::FieldMatrix<double,1,1>>>
645 bool interpolateAtShiftedPosition=
true)
648 using InterpolationNode = std::pair<size_t,double>;
649 using InterpolationNodes = std::vector<InterpolationNode>;
653 auto const& grid = gridman.grid();
654 auto const& leafView = grid.leafGridView();
655 auto const& cellRanges = gridman.cellRanges(grid.levelGridView(0));
656 constexpr int dim = GridMan::Grid::dimension;
665 std::vector<std::vector<std::tuple<size_t,int,InterpolationNodes>>> interpolationData(cellRanges.maxRanges());
668 for (
auto const& coarseCell: gridman.cellRanges(grid.levelGridView(0)).range(n,k))
669 for (
auto const& cell: descendantElements(coarseCell,grid.maxLevel()))
670 ProlongationDetail::computeShiftedParents(leafView,cell,interpolationData[k],interpolateAtShiftedPosition);
671 },interpolationData.size());
674 std::vector<std::vector<std::pair<int,InterpolationNodes>>> interpolationOptions(leafView.size(dim));
675 for (
auto const& idk: interpolationData)
676 for (
auto const&
id: idk)
677 interpolationOptions[get<0>(
id)].push_back(std::make_pair(get<1>(
id),get<2>(
id)));
685 std::vector<std::pair<int,InterpolationNodes>> interpolation(interpolationOptions.size());
686 for (
size_t k=0; k<interpolationOptions.size(); ++k)
688 auto const& i = interpolationOptions[k];
694 bool isEdgeMidpoint =
false;
695 bool isShifted =
false;
696 for (
auto const& ip: i)
698 assert(ip.first == i[0].first);
699 isEdgeMidpoint = isEdgeMidpoint || ip.second.size()==2;
700 isShifted = isShifted || ip.second.size()>2;
702 assert(isEdgeMidpoint != isShifted);
706 interpolation[k] = i[0];
710 for (
auto const& ip: i)
713 for (
auto const& p: ip.second)
714 inner = inner && p.second>=0;
716 interpolation[k] = ip;
719 if (interpolation[k].second.size()>0)
723 interpolation[k].first = i[0].first;
724 for (
auto const& ip: i)
725 for (
auto const& cn: ip.second)
726 interpolation[k].second.push_back(std::make_pair(cn.first,cn.second/i.size()));
730 timer.
start(
"made stack parents");
731 auto ps = ProlongationDetail::makeDeformedProlongationStack(interpolation,grid.maxLevel(),coarseLevel,minNodes);
732 timer.
stop(
"made stack parents");
746 template <
class Pro
longation,
class Entry,
class Index>
761 : prolongations(std::move(ps)), galerkinMatrices(std::move(as))
763 assert(prolongations.size()+1==galerkinMatrices.size());
778 prolongations = std::move(ps);
779 galerkinMatrices.push_back(std::move(A));
781 assert((prolongations.size() == 0) || (prolongations.back().N() == galerkinMatrices[0].N()));
782 assert(galerkinMatrices[0].N() == galerkinMatrices[0].M());
785 timer.
start(
"matrix projection");
786 for (
auto pi=prolongations.crbegin(); pi!=prolongations.crend(); ++pi)
787 galerkinMatrices.insert(galerkinMatrices.begin(),
conjugation(*pi,galerkinMatrices.front(),onlyLowerTriangle));
788 timer.
stop(
"matrix projection");
798 return galerkinMatrices.size();
807 assert(0<=level && level<
levels()-1);
808 return prolongations[level];
821 assert(0<=level && level<
levels());
822 return galerkinMatrices[level];
837 return galerkinMatrices[0];
842 for (
auto const&
p: prolongations)
843 out <<
"Prolongation:\n" <<
p;
845 for (
auto const&
a: galerkinMatrices)
846 out <<
"GalerkinMatrix: \n" <<
a;
850 std::vector<Prolongation> prolongations;
851 std::vector<NumaBCRSMatrix<Entry,Index>> galerkinMatrices;
854 template <
typename Pro
longations,
typename Entry,
typename Index>
870 template <
class Pro
longation,
class Entry,
class Index>
872 bool onlyLowerTriangle)
881 template <
class Gr
idMan,
class Entry,
class Index>
883 size_t minNodes=10000,
bool onlyLowerTriangle=
false)
906 template <
class Entry,
class Index>
908 Index n=0,
bool onlyLowerTriangle=
false);
920 template <
typename FineSpace>
923 using Real =
typename FineSpace::Scalar;
932 if (space.mapper().maxOrder() > 1)
935 prolongations.push_back(prolongation<typename Matrix::size_type>(coarseSpace,space));
938 return prolongations;
945 template <
typename FineSpace,
typename Matrix>
948 std::vector<NumaBCRSMatrix<Dune::FieldMatrix<typename FineSpace::Scalar,1,1>,
typename Matrix::size_type>> prolongations;
950 if (space.mapper().maxOrder() > 1)
953 prolongations.push_back(prolongation<typename Matrix::size_type>(coarseSpace,space));
956 return makeMultiGridStack(std::move(prolongations),std::move(A),onlyLowerTriangle);
960 namespace ProlongationDetail
962 template <
typename FineSpace,
typename CoarseSpace,
typename Matrix>
964 CoarseSpace
const& coarseSpace, std::unique_ptr<Matrix> cA = std::unique_ptr<Matrix>())
966 using Prolongation = NumaBCRSMatrix<Dune::FieldMatrix<typename FineSpace::Scalar,1,1>,
typename Matrix::size_type>;
967 std::vector<Prolongation> prolongations;
968 prolongations.push_back(prolongation<typename Matrix::size_type>(coarseSpace,fineSpace));
970 std::vector<Matrix> matrices;
972 matrices.push_back(std::move(*cA));
974 matrices.push_back(
conjugation(prolongations[0],fA));
975 matrices.push_back(std::move(fA));
977 return MultiGridStack<
Prolongation,
typename Matrix::block_type,
978 typename Matrix::size_type>(std::move(prolongations),std::move(matrices));
988 template <
typename FineSpace,
typename CoarseSpace,
typename Matrix>
1001 template <
typename FineSpace,
typename CoarseSpace,
typename Matrix>
1002 auto makePMultiGridStack(FineSpace
const& fineSpace, Matrix&& fA, CoarseSpace
const& coarseSpace, Matrix&& cA)
A LAPACK-compatible dense matrix class with shape specified at runtime.
A representation of a finite element function space defined over a domain covered by a grid.
GridManagerBase< Grid > & gridManager() const
Access to the GridManager.
GridView const & gridView() const
Provides access to the index set defining the potential support of the space.
LocalToGlobalMapper const & mapper() const
Provides read access to the node manager.
A prolongation operator for P1 finite elements from a coarser grid level to the next finer level.
size_t N() const
The number of rows.
void mtv(Vector const &f, Vector &c) const
Transpose matrix vector multiplication.
NumaBCRSMatrix< Dune::FieldMatrix< Real, 1, 1 > > asMatrix() const
Returns the prolongation in form of a sparse matrix.
MGProlongation(std::vector< ProlongationDetail::Node > const &parents, std::vector< size_t > const &indexInCoarse, size_t nc, int fineLevel)
Constructor.
void mv(Vector const &c, Vector &f) const
Matrix vector multiplcation.
size_t M() const
The number of columns.
NumaBCRSMatrix< Entry, Index > galerkinProjection(NumaBCRSMatrix< Entry, Index > const &A, bool onlyLowerTriangle=false) const
Galerkin projection of fine grid matrices. This computes .
std::array< size_t, 2 > const & parents(size_t i) const
Returns the parent nodes indices.
void umv(Vector const &c, Vector &f) const
Matrix vector multiplcation (update mode).
Class for multigrid stacks.
int levels() const
The number of grid levels.
Prolongation const & p(int level) const
Returns the prolongation from given level to next higher one.
NumaBCRSMatrix< Entry, Index > & coarseGridMatrix()
Returns the projected Galerkin matrix on the coarsest level.
MultiGridStack(std::vector< Prolongation > &&ps, std::vector< NumaBCRSMatrix< Entry, Index > > &&as)
Constructor.
void report(std::ostream &out) const
NumaBCRSMatrix< Entry, Index > const & a(int level) const
Returns the projected Galerkin matrix on the given level.
MultiGridStack(std::vector< Prolongation > &&ps, NumaBCRSMatrix< Entry, Index > &&A, bool onlyLowerTriangle)
Constructor.
MultiGridStack(MultiGridStack &&other)=default
A NUMA-aware compressed row storage matrix adhering mostly to the Dune ISTL interface (to complete....
Index M() const
The number of columns.
Index N() const
The number of rows.
A NUMA-aware creator for matrix sparsity patterns.
void addElements(IterRow const fromRow, IterRow const toRow, IterCol const fromCol, IterCol const toCol, bool colIsSorted=false)
Enters entries into the sparsity pattern.
void addElement(Index row, Index col)
Enters a single entry into the sparsity pattern.
Supports gathering and reporting execution times information for nested program parts.
static Timings & instance()
Returns a reference to a single default instance.
void stop(std::string const &name)
Stops the timing of given section.
struct Times const * start(std::string const &name)
Starts or continues the timing of given section.
void approximateGlobalValues(Space const &space, typename Space::Grid::template Codim< 0 >::Entity const &cell, DynamicMatrix< Dune::FieldMatrix< typename Space::Scalar, Space::sfComponents, 1 > > &globalValues, DynamicMatrix< Dune::FieldMatrix< typename Space::Scalar, 1, 1 > > &coeff, ShapeFunctionSet const &sfs)
Computes global shape function coefficients such that the given set of global function values at the ...
void evaluateGlobalShapeFunctions(Space const &space, Cell< typename Space::GridView > const &cell, std::vector< LocalPosition< typename Space::GridView > > const &xi, DynamicMatrix< Dune::FieldMatrix< typename Space::Scalar, Space::sfComponents, 1 > > &sfValues, ShapeFunctionSet const &shapeFunctionSet)
Computes the values of global shape functions at the given points (which are supposed to be local coo...
typename GridView::template Codim< 0 >::Entity Cell
The type of cells (entities of codimension 0) in the grid view.
Dune::FieldVector< CoordType, dim+1 > barycentric(Dune::FieldVector< CoordType, dim > const &x)
Computes the barycentric coordinates of a point in the unit simplex.
MultiGridStack< Prolongation, Entry, Index > makeMultiGridStack(std::vector< Prolongation > &&ps, NumaBCRSMatrix< Entry, Index > &&A, bool onlyLowerTriangle)
Convenience routine for creating multigrid stacks.
NumaBCRSMatrix< Dune::FieldMatrix< typename FineSpace::Scalar, 1, 1 >, SparseIndex > prolongation(CoarseSpace const &coarseSpace, FineSpace const &fineSpace)
Computes an interpolation-based prolongation matrix from a (supposedly) coarser space to a finer spac...
auto makePMultiGridStack(FineSpace const &space, Matrix &&A, bool onlyLowerTriangle)
convenience routine for creating multigrid stacks based on coarsening by reducing the ansatz order fr...
MultiGridStack< MGProlongation, Entry, Index > makeAlgebraicMultigridStack(NumaBCRSMatrix< Entry, Index > &&A, Index n=0, bool onlyLowerTriangle=false)
Creates stack of prolongations and projected Galerkin matrices.
std::vector< NumaBCRSMatrix< Dune::FieldMatrix< double, 1, 1 > > > deformedProlongationStack(GridMan const &gridman, int coarseLevel=0, size_t minNodes=0, bool interpolateAtShiftedPosition=true)
Computes a sequence of prolongation matrices for P1 finite elements in hierarchical grids.
std::vector< NumaBCRSMatrix< Dune::FieldMatrix< typename Mapper::Scalar, 1, 1 >, SparseIndex > > prolongationStack(FEFunctionSpace< Mapper > const &space)
Computes a stack of prolongation matrices for higher order finite element spaces.
MultiGridStack< MGProlongation, Entry, Index > makeGeometricMultiGridStack(GridMan const &gridManager, NumaBCRSMatrix< Entry, Index > &&A, size_t minNodes=10000, bool onlyLowerTriangle=false)
convenience routine for creating multigrid stacks based on geometric coarsening for P1 elements
auto makeDeepProlongationStack(FineSpace const &space, int coarseLevel=0, int minNodes=0)
Convenience routine for creating a deep prolongation stack from coarse to fine grid and on from P1 to...
auto makePMultiGridStack(FineSpace const &fineSpace, Matrix &&fA, CoarseSpace const &coarseSpace, Matrix &&cA)
convenience routine for creating multigrid stacks between two spaces.
void parallelFor(Func const &f, int maxTasks=std::numeric_limits< int >::max())
A parallel for loop that executes the given functor in parallel on different CPUs.
auto moveUnique(A &&a)
Creates a dynamically allocated object from an r-value reference.
Dune::FieldVector< Scalar, dim > Vector
void conjugation(Dune::BCRSMatrix< Entry > &C, Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > const &P, Dune::BCRSMatrix< Entry > const &A, bool onlyLowerTriangle=false)
Computes the triple sparse matrix product .
std::ostream & operator<<(std::ostream &s, std::vector< Scalar > const &vec)
NumaBCRSMatrix< Dune::FieldMatrix< double, 1, 1 > > Prolongation
Convenience typedefs and creation functions for common function spaces.