KASKADE 7 development version
scalarspace.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2002-2023 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef SCALARSPACE_HH
14#define SCALARSPACE_HH
15
16#include <algorithm>
17#include <functional>
18#include <map>
19#include <vector>
20
21#include <boost/compressed_pair.hpp>
22#include <boost/iterator/transform_iterator.hpp>
23
24#include "fem/firstless.hh"
25#include "fem/gridBasics.hh"
27#include "fem/views.hh"
28
29namespace Kaskade
30{
31 // forward declarations
32 template <class,class> class ContinuousLagrangeBoundaryMapper;
33
34 namespace ScalarSpaceDetail
35 {
36 struct Empty {};
37
41 template <class Pair>
43 {
44 typedef typename Pair::first_const_reference result_type;
45
46 typename Pair::first_const_reference operator()(Pair const& pair) const
47 {
48 return pair.first();
49 }
50 };
51
52 // Overload here as compressed pair's entries are accessed by method call.
53 struct FirstLess
54 {
55 template <class Data>
56 bool operator()(boost::compressed_pair<size_t,Data> const& a, boost::compressed_pair<size_t,Data> const& b)
57 {
58 return a.first() < b.first();
59 }
60 };
61
69 inline bool onSimplexFace(int dim, int codim, int id, int localFaceId)
70 {
71 assert(dim<=3);
72
73 if(codim==0) return false; // cell is never part of a face
74 if(codim==1) return id==localFaceId; // ... face only if it is the same face
75
76 if(dim==2)
77 {
78 if(localFaceId==0) return (id==0 || id==1);
79 if(localFaceId==1) return (id==0 || id==2);
80 if(localFaceId==2) return (id==2 || id==1);
81 }
82 else if(dim==3)
83 {
84 // edges
85 if(codim==2)
86 {
87 if(localFaceId==0) return (id>=0 && id<3);
88 if(localFaceId==1) return (id==0 || id==3 || id==4);
89 if(localFaceId==2) return (id==1 || id==3 || id==5);
90 if(localFaceId==3) return (id==2 || id==4 || id==5);
91 }
92 // vertices
93 if(codim==3)
94 {
95 if(localFaceId==0) return (id>=0 && id<3);
96 if(localFaceId==1) return (id==0 || id==1 || id==3);
97 if(localFaceId==2) return (id==0 || id==2 || id==3);
98 if(localFaceId==3) return (id==1 || id==2 || id==3);
99 }
100 return false;
101 }
102
103 return false; // never get here
104 }
105
106 static constexpr int defaultIndex = -94279;
107
108 template <class Face>
109 int getBoundaryId(Face const& face, std::vector<int> const& boundaryIds)
110 {
111 size_t boundarySegmentIndex = face.boundarySegmentIndex();
112 if(boundarySegmentIndex < boundaryIds.size()) return boundaryIds[boundarySegmentIndex];
113 return defaultIndex;
114 }
115
116 inline bool usedId(int id, std::vector<int> const& usedIds)
117 {
118 if (id==defaultIndex) return false;
119 return std::find(usedIds.begin(), usedIds.end(), id) != usedIds.end();
120 }
121
122 template <class Face>
123 inline bool considerFace(Face const& face, std::vector<int> const& boundaryIds, std::vector<int> const& usedIds)
124 {
125 if(boundaryIds.empty()) return face.boundary();
126 return (face.boundary() && usedId(getBoundaryId(face,boundaryIds),usedIds));
127 }
128
130 {
133 RestrictToBoundary(std::vector<int> const& boundaryIds_, std::vector<int> const& usedIds_) : boundaryIds(boundaryIds_), usedIds(usedIds_)
134 {}
135
136 template <class Data, class GridView, class Cell>
137 void treatBoundary(Data& data, GridView const& gridView, Cell const& cell, int codim, int subentity) const
138 {
139 // ignore shape functions that are associated with codim-0 entities
140 assert(cell.type().isSimplex());
141 if(codim > 0)
142 for(auto const& face: intersections(gridView,cell))
143 // only consider boundary faces
145 && onSimplexFace(GridView::dimension,codim,subentity,face.indexInInside()))
146 data.first() = true;
147 }
148
149 std::vector<int> const boundaryIds;
150 std::vector<int> const usedIds;
151 };
152
153 template <class Policy>
154 constexpr bool isRestriction()
155 {
156 return std::is_same<Policy,RestrictToBoundary>::value;
157 }
158
161 {
162 template <class Data, class GridView, class Cell> void treatBoundary(Data&, GridView const&, Cell const&, int, int) const {}
163 };
164 } // End of namespace ScalarSpaceDetail
165
166 // --------------------------------------------------------------------------------------------
167 // --------------------------------------------------------------------------------------------
168
174 template <class SFData>
176
203 template <class Implementation, class SFData = ScalarSpaceDetail::Empty>
205 {
206 public:
207 typedef typename Implementation::Grid Grid;
209 typedef typename Implementation::ShapeFunctionSet ShapeFunctionSet;
210 typedef typename Implementation::Converter Converter;
211 typedef typename Implementation::Combiner Combiner;
212 typedef typename Implementation::Scalar Scalar;
213 typedef typename Implementation::GridView GridView;
214 typedef typename GridView::IndexSet IndexSet;
215 typedef std::pair<size_t,int> IndexPair;
216
217 private:
218 typedef boost::compressed_pair<size_t,SFData> Data;
219
221
222 typedef boost::transform_iterator<First,typename std::vector<Data>::const_iterator> GlobalIndexIterator;
223 typedef std::vector<IndexPair>::const_iterator SortedIndexIterator;
224
225 static constexpr int dim = Grid::dimension;
226
227 public:
230
234 static bool const globalSupport = false;
235
236 UniformScalarMapper(Implementation const& impl) : implementation(impl)
237 {
238 update();
239 }
240
244 GridView const& gridView() const
245 {
246 return implementation.gridView();
247 }
248
252 int maxOrder() const
253 {
254 return order;
255 }
256
257
262 {
263 return GlobalIndexRange(GlobalIndexIterator(globIdx[0].begin(),First()),
264 GlobalIndexIterator(globIdx[0].begin(),First()));
265 }
266
267
275 {
276 return globalIndices(implementation.indexSet().index(cell));
277 }
278
286 {
287 return GlobalIndexRange(GlobalIndexIterator(globIdx[n].begin(),First()),
288 GlobalIndexIterator(globIdx[n].end(), First()));
289 }
290
295 {
296 static std::vector<IndexPair> dummy; // empty
297 return SortedIndexRange(dummy.begin(),dummy.end());
298 }
299
304 {
305 return sortedIndices(implementation.indexSet().index(cell));
306 }
307
312 {
313 return SortedIndexRange(sortedIdx[n].begin(),sortedIdx[n].end());
314 }
315
323 size_t size() const { return n; }
324
331 ShapeFunctionSet const& shapefunctions(Cell const& cell, bool contained=false) const
332 {
333 if (contained || implementation.indexSet().contains(cell))
334 return shapefunctions(implementation.indexSet().index(cell));
335 else
336 return implementation.shapeFunctions(cell);
337 }
338
340 {
341 return shapefunctions_non_const(implementation.indexSet().index(cell));
342 }
343
347 ShapeFunctionSet const& shapefunctions(size_t n) const
348 {
349 return *sfs[n];
350 }
351
353 {
354 return *sfs[n];
355 }
356
357 ShapeFunctionSet const& lowerShapeFunctions(Cell const& cell) const
358 {
359 if (globalIndices(cell).empty())
360 return implementation.emptyShapeFunctionSet();
361 else
362 return implementation.lowerShapeFunctions(cell);
363 }
364
370 Combiner combiner(Cell const& cell, size_t index) const
371 {
372 assert(implementation.indexSet().index(cell)==index);
373 return Combiner(rangeView(globIdx[index].begin(),globIdx[index].end()),
374 shapefunctions(index));
375 }
376
377
378 // just returns the index, since nothing is restricted
379 std::pair<bool,size_t> unrestrictedToRestrictedIndex(size_t unrestrictedIndex)
380 {
381 return std::make_pair(true, unrestrictedIndex);
382 }
383
389 void update()
390 {
391 GridView const& gridView = implementation.gridView();
392 IndexSet const& indexSet = implementation.indexSet();
393
394 // Notify the implementation of the update request.
395 implementation.update();
396
397 // For each codimension (i.e. type of subentity) compute the
398 // number of global ansatz functions as well as an accumulated
399 // index into an array of all ansatz functions.
400 startIndex.clear();
401
402 size_t ndofs = 0;
403 for (int codim=0; codim<=Grid::dimension; ++codim)
404 for(auto const& geoType: implementation.indexSet().types(codim))
405 {
406 startIndex[geoType] = ndofs;
407
408 size_t numOfEntity = implementation.size(geoType);
409 size_t dofOnEntity = implementation.dofOnEntity(geoType);
410 ndofs += numOfEntity * dofOnEntity;
411 }
412
413 // Store the total number of degrees of freedom.
414 n = ndofs;
415
416 sfs.resize(indexSet.size(0));
417 order = 0;
418
419 // Precompute and cache all the global indices. First allocate the
420 // memory needed to prevent frequent reallocation.
421 globIdx.resize(implementation.indexSet().size(0));
422 sortedIdx.resize(implementation.indexSet().size(0));
423
424 // Step through all cells and compute the global ansatz function
425 // indices of all shape functions on that cell.
426 for(auto const& cell : elements(gridView))
427 {
428 size_t const cellIndex = indexSet.index(cell);
429
430 // Store a shape function set even if the current cell does not belong to our
431 // support subdomain. This is necessary because we return a *reference*
432 // to a shape function set for all cells.
433 ShapeFunctionSet const& sf = implementation.shapeFunctions(cell);
434 sfs[cellIndex] = &sf;
435
436
437 // Skip this cell and let it's set of dofs empty if it is not in our support.
438 if (!implementation.inSupport(cell))
439 {
440 globIdx[cellIndex].clear(); // We must clear the indices explicitly, as on refinement
441 sortedIdx[cellIndex].clear(); // there may be leftovers from the previous grid.
442 continue;
443 }
444
445 // Track the maximum shape function order encountered on any cell.
446 order = std::max(order,sf.order());
447
448 size_t localNumberOfShapeFunctions = sf.size();
449 globIdx[cellIndex].resize(localNumberOfShapeFunctions);
450 sortedIdx[cellIndex].resize(localNumberOfShapeFunctions);
451
452 // For each (local) shape function, have it's global index computed and noted.
453 // TODO: pull common parts out of this loop
454 for(size_t i=0; i<localNumberOfShapeFunctions; ++i)
455 {
456 Dune::GeometryType gt;
457 int subentity, codim, indexInSubentity;
458 SFData sfData;
459 implementation.entityIndex(cell,sf[i],i,gt,subentity,codim,indexInSubentity,sfData);
460
461 // compute the global index of the subentity to which the shape function is associated
462 int gt_idx = implementation.subIndex(cell,subentity,codim);
463
464 auto mi = startIndex.find(gt);
465 assert(mi!=startIndex.end());
466
467 int globalIndex = mi->second+gt_idx*implementation.dofOnEntity(gt) + indexInSubentity;
468
469 globIdx[cellIndex][i] = Data(globalIndex,sfData);
470 sortedIdx[cellIndex][i] = std::make_pair(globIdx[cellIndex][i].first(),i);
471 }
472
473
474 // sort the index pairs according to the global index
475 std::sort(sortedIdx[cellIndex].begin(),sortedIdx[cellIndex].end(),FirstLess());
476
477 // make sure that any assigned shape function forms at most one ansatz function.
478 // This is a functionality restriction, but seems quite reasonable as a debugging check.
479 // Note that not all shape functions need not be assigned. If a shape function is mapped //Jakob: Are negative indices for unused shape function really allowed? Are'nt they simply not present in globIdx, such that the check idx[j]<0 below is nonsense?
480 // to negative global index, it takes not part at all (e.g. in hp-methods).
481#ifndef NDEBUG
482 std::vector<size_t> idx(globIdx[cellIndex].size());
483 for (int j=0; j<idx.size(); ++j)
484 idx[j] = globIdx[cellIndex][j].first();
485 std::sort(idx.begin(),idx.end());
486 for (int j=1; j<idx.size(); ++j)
487 assert(idx[j]>idx[j-1] || idx[j]<0);
488#endif
489 }
490 }
491
492
493 private:
494 // The number of dofs.
495 size_t n;
496
497 // In startIndex, for any geometry type that occurs in the indexSet
498 // there is an index stored, such that the dofs associated with
499 // nodes on subentities of this type start at this index. We request
500 // that there is a fixed number of dofs associated with each
501 // subentity type, such that equal length index blocks are assigned
502 // to each subentity of a given type. The layout of dofs is thus as
503 // follows (example continuous 2D simplex mesh with two triangles,
504 // order 4):
505 //
506 // [Interior Triangle Nodes, Interior Edge Nodes, Vertex Nodes] with substructuring
507 // [ [[t1a,t1b,t1c],[t2a,t2b,t2c]], [[e1a,e1b],[e2a,e2b],[e3a,e3b],[e4a,e4b],[e5a,e5b]], [v1,v2,v3,v4] ]
508 // | start index triangles | start index edges | start index vertices
509 // localDofs(triangles)=3, localDofs(edges)=2, localDofs(vertices)=1
510 std::map<Dune::GeometryType,size_t> startIndex;
511
512 // In globIdx, for each cell there are the global ansatz function indices on that cell.
513 std::vector<std::vector<Data>> globIdx;
514
515 // In sortedIdx, for each cell there is a vector of (global index, local index) pairs, sorted ascendingly
516 // by the global index. This could be computed outside on demand, but the sorting takes time and may be
517 // amortized over multiple assembly passes/matrix blocks if cached here.
518 std::vector<std::vector<IndexPair>> sortedIdx;
519
520 // In sfs, for each cell there is a pointer to the shape function set on this cell cached.
521 std::vector<ShapeFunctionSet const*> sfs;
522
523 // The maximum polynomial ansatz order of shape functions on the cells.
524 int order;
525
526
527 protected:
528 Implementation implementation;
529 };
530} // end of namespace Kaskade
531
532#endif
DEPRECATED. Use boost::iterator_range instead.
Definition: views.hh:25
Base class for uniform scalar local to global mappers.
Definition: scalarspace.hh:205
Kaskade::Cell< Grid > Cell
Definition: scalarspace.hh:208
Combiner combiner(Cell const &cell, size_t index) const
Returns a combiner for the given leaf cell.
Definition: scalarspace.hh:370
RangeView< SortedIndexIterator > SortedIndexRange
Definition: scalarspace.hh:229
GlobalIndexRange globalIndices(size_t n) const
Returns an immutable sequence containing the global indices of the shape functions associated to this...
Definition: scalarspace.hh:285
static SortedIndexRange initSortedIndexRange()
Returns an empty range just for initialization, since RangeView is not default constructible.
Definition: scalarspace.hh:294
ShapeFunctionSet const & shapefunctions(Cell const &cell, bool contained=false) const
Returns the set of shape functions defined on this cell.
Definition: scalarspace.hh:331
GridView::IndexSet IndexSet
Definition: scalarspace.hh:214
UniformScalarMapper(Implementation const &impl)
Definition: scalarspace.hh:236
std::pair< size_t, int > IndexPair
Definition: scalarspace.hh:215
RangeView< GlobalIndexIterator > GlobalIndexRange
Definition: scalarspace.hh:228
GridView const & gridView() const
Returns the grid view used.
Definition: scalarspace.hh:244
GlobalIndexRange initGlobalIndexRange() const
Returns an empty range just for initialization purposes, since RangeView is not default constructible...
Definition: scalarspace.hh:261
SortedIndexRange sortedIndices(Cell const &cell) const
Returns an immutable sequence of (global index, local index) pairs sorted in ascending global index o...
Definition: scalarspace.hh:303
Implementation::Grid Grid
Definition: scalarspace.hh:207
ShapeFunctionSet & shapefunctions_non_const(Cell const &cell)
Definition: scalarspace.hh:339
Implementation::Scalar Scalar
Definition: scalarspace.hh:212
Implementation::Combiner Combiner
Definition: scalarspace.hh:211
size_t size() const
Returns the number of global degrees of freedom managed.
Definition: scalarspace.hh:323
Implementation::GridView GridView
Definition: scalarspace.hh:213
void update()
(Re)computes the internal data.
Definition: scalarspace.hh:389
ShapeFunctionSet const & shapefunctions(size_t n) const
Returns the set of shape functions defined on this cell.
Definition: scalarspace.hh:347
Implementation::ShapeFunctionSet ShapeFunctionSet
Definition: scalarspace.hh:209
int maxOrder() const
Returns the maximal polynomial order of shape functions encountered in any cell.
Definition: scalarspace.hh:252
std::pair< bool, size_t > unrestrictedToRestrictedIndex(size_t unrestrictedIndex)
Definition: scalarspace.hh:379
SortedIndexRange sortedIndices(size_t n) const
Returns an immutable sequence of (global index, local index) pairs sorted in ascending global index o...
Definition: scalarspace.hh:311
Implementation::Converter Converter
Definition: scalarspace.hh:210
ShapeFunctionSet const & lowerShapeFunctions(Cell const &cell) const
Definition: scalarspace.hh:357
ShapeFunctionSet & shapefunctions_non_const(size_t n)
Definition: scalarspace.hh:352
GlobalIndexRange globalIndices(Cell const &cell) const
Returns an immutable sequence containing the global indices of the shape functions associated to this...
Definition: scalarspace.hh:274
static bool const globalSupport
Whether the ansatz functions have global support (i.e. lead to dense matrices).
Definition: scalarspace.hh:234
typename GridView::template Codim< 0 >::Entity Cell
The type of cells (entities of codimension 0) in the grid view.
Definition: gridBasics.hh:35
typename GridView::Intersection Face
The type of faces in the grid view.
Definition: gridBasics.hh:42
Dune::FieldVector< T, n > max(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise maximum.
Definition: fixdune.hh:110
int getBoundaryId(Face const &face, std::vector< int > const &boundaryIds)
Definition: scalarspace.hh:109
bool onSimplexFace(int dim, int codim, int id, int localFaceId)
check if a given subentity E is part of a certain simplex face F
Definition: scalarspace.hh:69
bool considerFace(Face const &face, std::vector< int > const &boundaryIds, std::vector< int > const &usedIds)
Definition: scalarspace.hh:123
bool usedId(int id, std::vector< int > const &usedIds)
Definition: scalarspace.hh:116
constexpr bool isRestriction()
Definition: scalarspace.hh:154
RangeView< It > rangeView(It first, It last)
Convenience function for constructing range views on the fly.
Definition: views.hh:59
A comparator functor that supports sorting std::pair by their first component.
Definition: firstless.hh:22
void treatBoundary(Data &, GridView const &, Cell const &, int, int) const
Definition: scalarspace.hh:162
A functor for extracting the first component of a boost compressed pair.
Definition: scalarspace.hh:43
Pair::first_const_reference result_type
Definition: scalarspace.hh:44
Pair::first_const_reference operator()(Pair const &pair) const
Definition: scalarspace.hh:46
bool operator()(boost::compressed_pair< size_t, Data > const &a, boost::compressed_pair< size_t, Data > const &b)
Definition: scalarspace.hh:56
RestrictToBoundary(std::vector< int > const &boundaryIds_, std::vector< int > const &usedIds_)
Definition: scalarspace.hh:133
void treatBoundary(Data &data, GridView const &gridView, Cell const &cell, int codim, int subentity) const
Definition: scalarspace.hh:137
RestrictToBoundary(RestrictToBoundary const &other)
Definition: scalarspace.hh:132