1 #ifndef DUNE_MULTIDOMAINGRID_INDEXSETS_HH
2 #define DUNE_MULTIDOMAINGRID_INDEXSETS_HH
3 
4 #include <map>
5 #include <unordered_map>
6 #include <vector>
7 #include <array>
8 #include <algorithm>
9 #include <memory>
10 #include <type_traits>
11 #include <tuple>
12 #include <utility>
13 
14 
15 #include <dune/geometry/typeindex.hh>
16 #include <dune/grid/common/exceptions.hh>
17 #include <dune/grid/common/indexidset.hh>
18 
19 #include <dune/grid/multidomaingrid/utility.hh>
20 #include <dune/grid/multidomaingrid/subdomaingrid/indexsets.hh>
21 
22 #include <dune/typetree/utility.hh>
23 
24 namespace Dune {
25 
26 namespace mdgrid {
27 
28 template<typename HostGrid, typename MDGridTraits>
29 class MultiDomainGrid;
30 
31 //! @cond DEV_DOC
32 
33 //! \internal
34 namespace detail {
35 
36 template<template<int> class StructForCodim, typename Codims>
37 struct _buildMap;
38 
39 //! \internal template meta program for assembling the per-codim map vector
40 template<template<int> class StructForCodim, std::size_t... codim>
41 struct _buildMap<StructForCodim,std::index_sequence<codim...> > {
42 
43   typedef std::tuple<StructForCodim<codim>... > type;
44 
45 };
46 
47 template<template<int> class StructForCodim, int dimension>
48 struct buildMap {
49 
50   typedef typename _buildMap<
51     StructForCodim,
52     decltype(std::make_index_sequence<dimension+1>())
53     >::type type;
54 
55 };
56 
57 //! \internal Helper mechanism for dispatching a call to a possibly non-existent method
58 /**
59  * This trick is necessary because some calls in the indexset (e.g. IndexSet::size(int codim) )
60  * pass the codim as a run-time parameter. But as we do not necessarily support all codimensions,
61  * we have to make sure that we only call the actual method if there is a data structure to
62  * operate on. This is handled by the template parameter doDispatch: The specialisation for
63  * doDispatch == false will simply throw an exception.
64  */
65 template<bool doDispatch, typename Impl, typename resulttype,bool alternate_dispatch>
66 struct invokeIf;
67 
68 template<typename Impl, typename resulttype, bool alternate_dispatch>
69 struct invokeIf<true,Impl,resulttype,alternate_dispatch> {
70 
71   typedef resulttype result_type;
72 
73   template<int codim>
invokeDune::mdgrid::detail::invokeIf74   result_type invoke() {
75     return _impl.template invoke<codim>();
76   }
77 
78   Impl& _impl;
79 
invokeIfDune::mdgrid::detail::invokeIf80   invokeIf(Impl& impl) :
81     _impl(impl)
82   {}
83 
84 };
85 
86 //! \internal
87 template<typename Impl, typename resulttype>
88 struct invokeIf<false,Impl, resulttype,false> {
89 
90   typedef resulttype result_type;
91 
92   template<int codim>
invokeDune::mdgrid::detail::invokeIf93   result_type invoke() {
94     DUNE_THROW(GridError,"codim not supported");
95   }
96 
97   Impl& _impl;
98 
invokeIfDune::mdgrid::detail::invokeIf99   invokeIf(Impl& impl) :
100     _impl(impl)
101   {}
102 
103 };
104 
105 template<typename Impl, typename resulttype>
106 struct invokeIf<false,Impl, resulttype,true> {
107 
108   typedef resulttype result_type;
109 
110   template<int codim>
invokeDune::mdgrid::detail::invokeIf111   result_type invoke() {
112     return _impl.template invoke_unsupported<codim>();
113   }
114 
115   Impl& _impl;
116 
invokeIfDune::mdgrid::detail::invokeIf117   invokeIf(Impl& impl) :
118     _impl(impl)
119   {}
120 
121 };
122 
123 //! \internal Template meta program for dispatching a method to the correctly parameterised template method base on a run-time parameter
124 template<typename Impl, typename resulttype, typename MDGridTraits, int codim, bool protect = true, bool alternate_dispatch = false>
125 struct dispatchToCodim
126   : public dispatchToCodim<Impl,resulttype,MDGridTraits,codim-1,protect,alternate_dispatch> {
127 
128   typedef resulttype result_type;
129 
dispatchDune::mdgrid::detail::dispatchToCodim130   result_type dispatch(int cc) {
131     if (cc == codim)
132       return invokeIf<MDGridTraits::template Codim<codim>::supported,Impl,result_type,alternate_dispatch>(static_cast<Impl&>(*this)).template invoke<codim>();
133     return static_cast<dispatchToCodim<Impl,result_type,MDGridTraits,codim-1,protect,alternate_dispatch>&>(*this).dispatch(cc);
134   }
135 
136 };
137 
138 //! \internal Recursion limit for dispatchToCodim
139 template<typename Impl, typename resulttype, typename MDGridTraits, bool alternate_dispatch>
140 struct dispatchToCodim<Impl,resulttype,MDGridTraits,0,true,alternate_dispatch> {
141 
142   typedef resulttype result_type;
143 
dispatchDune::mdgrid::detail::dispatchToCodim144   result_type dispatch(int cc) {
145     if (cc == 0)
146       return invokeIf<MDGridTraits::template Codim<0>::supported,Impl,result_type,alternate_dispatch>(static_cast<Impl&>(*this)).template invoke<0>();
147     DUNE_THROW(GridError,"invalid codimension specified");
148   }
149 
150 };
151 
152 //! \internal Template meta program for dispatching a method to the correctly parameterised template method base on a run-time parameter
153 template<typename Impl, typename resulttype, typename MDGridTraits, int codim, bool alternate_dispatch>
154 struct dispatchToCodim<Impl,resulttype,MDGridTraits,codim,false,alternate_dispatch>
155   : public dispatchToCodim<Impl,resulttype,MDGridTraits,codim-1,false,alternate_dispatch> {
156 
157   typedef resulttype result_type;
158 
dispatchDune::mdgrid::detail::dispatchToCodim159   result_type dispatch(int cc) {
160     if (cc == codim)
161       return static_cast<Impl&>(*this).template invoke<codim>();
162     return static_cast<dispatchToCodim<Impl,result_type,MDGridTraits,codim-1,false,alternate_dispatch>&>(*this).dispatch(cc);
163   }
164 
165 };
166 
167 //! \internal Recursion limit for dispatchToCodim
168 template<typename Impl, typename resulttype, typename MDGridTraits, bool alternate_dispatch>
169 struct dispatchToCodim<Impl,resulttype,MDGridTraits,0,false,alternate_dispatch> {
170 
171   typedef resulttype result_type;
172 
dispatchDune::mdgrid::detail::dispatchToCodim173   result_type dispatch(int cc) {
174     if (cc == 0)
175       return static_cast<Impl&>(*this).template invoke<0>();
176     DUNE_THROW(GridError,"invalid codimension specified");
177   }
178 
179 };
180 
181 /**
182  * \internal Helper structure for protecting calls at non-supported codims, similar to invokeIf.
183  *
184  * The main difference is that failures are silently ignored and that the called method may not return anything.
185  */
186 template<bool doApply, typename Impl>
187 struct applyIf {
188 
189   template<int codim, typename T>
applyDune::mdgrid::detail::applyIf190   void apply(T& t) const {
191     _impl.template apply<codim>(t);
192   }
193 
194   Impl& _impl;
195 
applyIfDune::mdgrid::detail::applyIf196   applyIf(Impl& impl) :
197     _impl(impl)
198   {}
199 
200 };
201 
202 //! \internal
203 template<typename Impl>
204 struct applyIf<false,Impl> {
205 
206   template<int codim, typename T>
applyDune::mdgrid::detail::applyIf207   void apply(T& t) const {
208   }
209 
210   Impl& _impl;
211 
applyIfDune::mdgrid::detail::applyIf212   applyIf(Impl& impl) :
213     _impl(impl)
214   {}
215 
216 };
217 
218 //! \internal Little helper function for casting away constness. Avoids having to spell out the typename.
219 template<typename T>
rw(const T & t)220 T& rw(const T& t) {
221   return const_cast<T&>(t);
222 }
223 
224 }
225 
226 //! @endcond
227 
228 /**
229  * Index set for the MultiDomainGrid.
230  */
231 template<typename GridImp, typename HostGridViewType>
232 class IndexSetWrapper :
233     public Dune::IndexSet<GridImp,IndexSetWrapper<GridImp,HostGridViewType>,
234                           typename HostGridViewType::IndexSet::IndexType,
235                           typename HostGridViewType::IndexSet::Types>
236 {
237 
238   using Grid = std::remove_const_t<GridImp>;
239 
240   template<typename, typename>
241   friend class IndexSetWrapper;
242 
243   template<typename, typename>
244   friend class MultiDomainGrid;
245 
246   template<typename, typename>
247   friend class subdomain::IndexSetWrapper;
248 
249   template<typename, typename, typename, typename>
250   friend class SubDomainInterface;
251 
252   template<typename>
253   friend class SubDomainToSubDomainController;
254 
255   template<typename>
256   friend class AllInterfacesController;
257 
258   typedef IndexSetWrapper<GridImp,HostGridViewType> ThisType;
259 
260   using HostGrid = typename Grid::HostGrid;
261   typedef HostGridViewType HostGridView;
262   typedef typename HostGridView::IndexSet HostIndexSet;
263   using ctype = typename Grid::ctype;
264   using CellReferenceElement = Dune::ReferenceElement<typename HostGrid::template Codim<0>::Entity::Geometry>;
265 
266   typedef Dune::IndexSet<
267     GridImp,
268     IndexSetWrapper<
269       GridImp,
270       HostGridViewType
271       >,
272     typename HostGridViewType::IndexSet::IndexType,
273     typename HostGridViewType::IndexSet::Types
274     > BaseT;
275 
276 public:
277 
278   typedef typename BaseT::Types Types;
279 
280   using MDGridTraits = typename Grid::MDGridTraits;
281   typedef typename MDGridTraits::template Codim<0>::SubDomainSet SubDomainSet;
282   typedef typename MDGridTraits::SubDomainIndex SubDomainIndex;
283 
284 
285   typedef typename HostIndexSet::IndexType IndexType;
286   static const int dimension = Grid::dimension;
287   static const std::size_t maxSubDomains = SubDomainSet::maxSize;
288 
289 private:
290 
291   typedef typename HostGridView::template Codim<0>::Iterator HostEntityIterator;
292   typedef typename HostGridView::template Codim<0>::Entity HostEntity;
293   using Codim0Entity = typename Grid::Traits::template Codim<0>::Entity;
294 
295   template<int cc>
296   struct MapEntry {
297 
298     typedef typename MDGridTraits::template Codim<cc>::SubDomainSet SubDomainSet;
299 
300     SubDomainSet domains;
301     IndexType index;
302   };
303 
304   //! Placeholder struct for non-supported codimensions in data structures.
305   struct NotSupported {};
306 
307   template<int codim>
308   struct Containers {
309 
310     static const bool supported = Grid::MDGridTraits::template Codim<codim>::supported;
311 
312     static_assert((codim > 0 || supported), "index mapping of codimension 0 must be supported!");
313 
314     using IndexMap = std::conditional_t<
315       supported,
316       std::vector<std::vector<MapEntry<codim> > >,
317       NotSupported
318       >;
319 
320     using SizeMap = std::conditional_t<
321       supported,
322       std::vector<typename Grid::MDGridTraits::template Codim<codim>::SizeContainer>,
323       NotSupported
324       >;
325 
326     using CodimSizeMap = std::conditional_t<
327       supported,
328       typename Grid::MDGridTraits::template Codim<codim>::SizeContainer,
329       NotSupported
330       >;
331 
332     using MultiIndexMap = std::conditional_t<
333       supported,
334       std::vector<typename Grid::MDGridTraits::template Codim<codim>::MultiIndexContainer>,
335       NotSupported
336       >;
337 
338     IndexMap indexMap;
339     SizeMap sizeMap;
340     CodimSizeMap codimSizeMap;
341     MultiIndexMap multiIndexMap;
342 
343     // containers should not be assignable...
344     Containers& operator=(const Containers&) = delete;
345 
346     // ...but must be movable
347     Containers& operator=(Containers&&) = default;
348 
349     // make sure the compiler generates all necessary constructors...
350     Containers(const Containers&) = default;
351     Containers(Containers&&) = default;
352     Containers() = default;
353 
354   };
355 
356   typedef typename detail::buildMap<Containers,dimension>::type ContainerMap;
357 
358   typedef std::vector<std::shared_ptr<IndexSetWrapper<GridImp, typename HostGridView::Grid::LevelGridView> > > LevelIndexSets;
359 
360   //! Convenience subclass of dispatchToCodim for automatically passing in the MDGridTraits and the dimension
361   template<typename Impl,typename result_type, bool protect = true, bool alternate_dispatch = false>
362   struct dispatchToCodim : public detail::dispatchToCodim<Impl,result_type,MDGridTraits,dimension,protect,alternate_dispatch> {};
363 
364 public:
365 
366   //! Returns the index of the entity with codimension codim.
367   template<int codim>
index(const typename Grid::Traits::template Codim<codim>::Entity & e) const368   IndexType index(const typename Grid::Traits::template Codim<codim>::Entity& e) const {
369     return _hostGridView.indexSet().index(_grid.hostEntity(e));
370   }
371 
372   //! Returns the index of the entity.
373   template<typename Entity>
index(const Entity & e) const374   IndexType index(const Entity& e) const {
375     return _hostGridView.indexSet().index(_grid.hostEntity(e));
376   }
377 
378   //! Returns the subdindex of the i-th subentity of e with codimension codim.
379   template<int codim, typename Entity>
subIndex(const Entity & e,int i) const380   IndexType subIndex(const Entity& e, int i) const {
381     return _hostGridView.indexSet().subIndex(_grid.hostEntity(e),i,codim);
382   }
383 
384   //! Returns the subdindex of the i-th subentity of e with codimension codim.
385   template<typename Entity>
subIndex(const Entity & e,int i,unsigned int codim) const386   IndexType subIndex(const Entity& e, int i, unsigned int codim) const {
387     IndexType r = _hostGridView.indexSet().subIndex(_grid.hostEntity(e),i,codim);
388     return r;
389   }
390 
391     //! Returns a list of all geometry types with codimension codim contained in the grid.
types(int codim) const392   Types types(int codim) const {
393     return _hostGridView.indexSet().types(codim);
394   }
395 
396   //! Returns the number of entities with GeometryType type in the grid.
size(GeometryType type) const397   IndexType size(GeometryType type) const {
398     return _hostGridView.indexSet().size(type);
399   }
400 
401   //! Returns the number of entities with codimension codim in the grid.
size(int codim) const402   IndexType size(int codim) const {
403     return _hostGridView.indexSet().size(codim);
404   }
405 
406   //! Returns true if the entity is contained in the grid.
407   template<typename EntityType>
contains(const EntityType & e) const408   bool contains(const EntityType& e) const {
409     return _hostGridView.indexSet().contains(_grid.hostEntity(e));
410   }
411 
412   //! Returns a constant reference to the SubDomainSet of the given entity.
413   template<typename EntityType>
subDomains(const EntityType & e) const414   const typename MapEntry<EntityType::codimension>::SubDomainSet& subDomains(const EntityType& e) const {
415     return subDomainsForHostEntity(_grid.hostEntity(e));
416   }
417 
418   //! Returns a constant reference to the SubDomainSet of the given entity with codimension cc.
419   //! \tparam cc the codimension of the entity.
420   template<int cc>
subDomains(const typename Grid::Traits::template Codim<cc>::Entity & e) const421   const typename MapEntry<cc>::SubDomainSet& subDomains(const typename Grid::Traits::template Codim<cc>::Entity& e) const {
422     return subDomainsForHostEntity<cc>(_grid.hostEntity(e));
423   }
424 
425   //! Returns the index of the entity in a specific subdomain.
426   template<class EntityType>
index(SubDomainIndex subDomain,const EntityType & e) const427   IndexType index(SubDomainIndex subDomain, const EntityType& e) const {
428     return index<EntityType::codimension>(subDomain,e);
429   }
430 
431   //! Returns the index of the entity with codimension cc in a specific subdomain.
432   //! \tparam the codimension of the entity.
433   template<int cc>
index(SubDomainIndex subDomain,const typename Grid::Traits::template Codim<cc>::Entity & e) const434   IndexType index(SubDomainIndex subDomain, const typename Grid::Traits::template Codim<cc>::Entity& e) const {
435     GeometryType gt = e.type();
436     IndexType hostIndex = _hostGridView.indexSet().index(_grid.hostEntity(e));
437     const MapEntry<cc>& me = indexMap<cc>()[LocalGeometryTypeIndex::index(gt)][hostIndex];
438     assert(me.domains.contains(subDomain));
439     if (me.domains.simple()) {
440       return me.index;
441     } else {
442       return multiIndexMap<cc>()[me.index][me.domains.domainOffset(subDomain)];
443     }
444   }
445 
446 private:
447 
448   //! Returns a mutable reference to the SubDomainSet of the given entity.
449   template<typename EntityType>
subDomains(const EntityType & e)450   typename MapEntry<EntityType::codimension>::SubDomainSet& subDomains(const EntityType& e) {
451     return subDomainsForHostEntity(_grid.hostEntity(e));
452   }
453 
454   //! Returns a mutable reference to the SubDomainSet of the given entity with codimension cc.
455   //! \tparam cc the codimension of the entity.
456   template<int cc>
subDomains(const typename Grid::Traits::template Codim<cc>::Entity & e)457   typename MapEntry<cc>::SubDomainSet& subDomains(const typename Grid::Traits::template Codim<cc>::Entity& e) {
458     return subDomainsForHostEntity<cc>(_grid.hostEntity(e));
459   }
460 
461   //! Returns a mutable reference to the SubDomainSet of the given host entity.
462   template<typename HostEntity>
subDomainsForHostEntity(const HostEntity & e)463   typename MapEntry<HostEntity::codimension>::SubDomainSet& subDomainsForHostEntity(const HostEntity& e) {
464     return subDomainsForHostEntity<HostEntity::codimension>(e);
465   }
466 
467   //! Returns a mutable reference to the SubDomainSet of the given entity with codimension cc.
468   //! \tparam cc the codimension of the entity.
469   template<int cc>
subDomainsForHostEntity(const typename Grid::HostGrid::Traits::template Codim<cc>::Entity & he)470   typename MapEntry<cc>::SubDomainSet& subDomainsForHostEntity(const typename Grid::HostGrid::Traits::template Codim<cc>::Entity& he) {
471     return indexMap<cc>()[LocalGeometryTypeIndex::index(he.type())][_hostGridView.indexSet().index(he)].domains;
472   }
473 
474   //! Returns a constant reference to the SubDomainSet of the given host entity.
475   template<typename HostEntity>
subDomainsForHostEntity(const HostEntity & e) const476   const typename MapEntry<HostEntity::codimension>::SubDomainSet& subDomainsForHostEntity(const HostEntity& e) const {
477     return subDomainsForHostEntity<HostEntity::codimension>(e);
478   }
479 
480   //! Returns a constant reference to the SubDomainSet of the given entity with codimension cc.
481   //! \tparam cc the codimension of the entity.
482   template<int cc>
subDomainsForHostEntity(const typename Grid::HostGrid::Traits::template Codim<cc>::Entity & he) const483   const typename MapEntry<cc>::SubDomainSet& subDomainsForHostEntity(const typename Grid::HostGrid::Traits::template Codim<cc>::Entity& he) const {
484     return indexMap<cc>()[LocalGeometryTypeIndex::index(he.type())][_hostGridView.indexSet().index(he)].domains;
485   }
486 
487   template<int cc>
indexForSubDomain(SubDomainIndex subDomain,const typename Grid::HostGrid::Traits::template Codim<cc>::Entity & he) const488   IndexType indexForSubDomain(SubDomainIndex subDomain, const typename Grid::HostGrid::Traits::template Codim<cc>::Entity& he) const {
489     const GeometryType gt = he.type();
490     const IndexType hostIndex = _hostGridView.indexSet().index(he);
491     const MapEntry<cc>& me = indexMap<cc>()[LocalGeometryTypeIndex::index(gt)][hostIndex];
492     assert(me.domains.contains(subDomain));
493     if (me.domains.simple()) {
494       return me.index;
495     } else {
496       return multiIndexMap<cc>()[me.index][me.domains.domainOffset(subDomain)];
497     }
498   }
499 
500   //! functor template for retrieving a subindex.
501   struct getSubIndexForSubDomain : public dispatchToCodim<getSubIndexForSubDomain,IndexType> {
502 
503     template<int codim>
invokeDune::mdgrid::IndexSetWrapper::getSubIndexForSubDomain504     IndexType invoke() const {
505       const MapEntry<codim>& me = _indexSet.indexMap<codim>()[LocalGeometryTypeIndex::index(_gt)][_hostIndex];
506       assert(me.domains.contains(_subDomain));
507       if (me.domains.simple()) {
508         return me.index;
509       } else {
510         return _indexSet.multiIndexMap<codim>()[me.index][me.domains.domainOffset(_subDomain)];
511       }
512     }
513 
514     SubDomainIndex _subDomain;
515     GeometryType _gt;
516     IndexType _hostIndex;
517     const ThisType& _indexSet;
518 
getSubIndexForSubDomainDune::mdgrid::IndexSetWrapper::getSubIndexForSubDomain519     getSubIndexForSubDomain(SubDomainIndex subDomain, GeometryType gt, IndexType hostIndex, const ThisType& indexSet) :
520       _subDomain(subDomain),
521       _gt(gt),
522       _hostIndex(hostIndex),
523       _indexSet(indexSet)
524     {}
525 
526   };
527 
528   template<typename HostEntity>
subIndexForSubDomain(SubDomainIndex subDomain,const HostEntity & he,int i,int codim) const529   IndexType subIndexForSubDomain(SubDomainIndex subDomain, const HostEntity& he, int i, int codim) const {
530     return getSubIndexForSubDomain(subDomain,
531                                    referenceElement(he.geometry()).type(i,codim - he.codimension),
532                                    _hostGridView.indexSet().subIndex(he,i,codim),
533                                    *this).dispatch(codim);
534   }
535 
typesForSubDomain(SubDomainIndex subDomain,int codim) const536   Types typesForSubDomain(SubDomainIndex subDomain, int codim) const {
537     return types(codim);
538   }
539 
540   struct getGeometryTypeSizeForSubDomain : public dispatchToCodim<getGeometryTypeSizeForSubDomain,IndexType,true,true> {
541 
542     template<int codim>
invokeDune::mdgrid::IndexSetWrapper::getGeometryTypeSizeForSubDomain543     IndexType invoke() const {
544       return _indexSet.sizeMap<codim>()[LocalGeometryTypeIndex::index(_gt)][_subDomain];
545     }
546 
547     template<int codim>
invoke_unsupportedDune::mdgrid::IndexSetWrapper::getGeometryTypeSizeForSubDomain548     IndexType invoke_unsupported() const {
549       return 0;
550     }
551 
552     SubDomainIndex _subDomain;
553     GeometryType _gt;
554     const ThisType& _indexSet;
555 
getGeometryTypeSizeForSubDomainDune::mdgrid::IndexSetWrapper::getGeometryTypeSizeForSubDomain556     getGeometryTypeSizeForSubDomain(SubDomainIndex subDomain, GeometryType gt, const ThisType& indexSet) :
557       _subDomain(subDomain),
558       _gt(gt),
559       _indexSet(indexSet)
560     {}
561 
562   };
563 
sizeForSubDomain(SubDomainIndex subDomain,GeometryType type) const564   IndexType sizeForSubDomain(SubDomainIndex subDomain, GeometryType type) const {
565     return getGeometryTypeSizeForSubDomain(subDomain,type,*this).dispatch(dimension-type.dim());
566   }
567 
568   struct getCodimSizeForSubDomain : public dispatchToCodim<getCodimSizeForSubDomain,IndexType,true,true> {
569 
570     template<int codim>
invokeDune::mdgrid::IndexSetWrapper::getCodimSizeForSubDomain571     IndexType invoke() const {
572       return _indexSet.codimSizes<codim>()[_subDomain];
573     }
574 
575     template<int codim>
invoke_unsupportedDune::mdgrid::IndexSetWrapper::getCodimSizeForSubDomain576     IndexType invoke_unsupported() const {
577       return 0;
578     }
579 
580     SubDomainIndex _subDomain;
581     const ThisType& _indexSet;
582 
getCodimSizeForSubDomainDune::mdgrid::IndexSetWrapper::getCodimSizeForSubDomain583     getCodimSizeForSubDomain(SubDomainIndex subDomain, const ThisType& indexSet) :
584       _subDomain(subDomain),
585       _indexSet(indexSet)
586     {}
587 
588   };
589 
sizeForSubDomain(SubDomainIndex subDomain,int codim) const590   IndexType sizeForSubDomain(SubDomainIndex subDomain, int codim) const {
591     return getCodimSizeForSubDomain(subDomain,*this).dispatch(codim);
592   }
593 
594   template<typename EntityType>
containsForSubDomain(SubDomainIndex subDomain,const EntityType & he) const595   bool containsForSubDomain(SubDomainIndex subDomain, const EntityType& he) const {
596     const GeometryType gt = he.type();
597     const IndexType hostIndex = _hostGridView.indexSet().index(he);
598     const MapEntry<EntityType::codimension>& me = indexMap<EntityType::codimension>()[LocalGeometryTypeIndex::index(gt)][hostIndex];
599     return me.domains.contains(subDomain);
600   }
601 
602 public:
603 
604   template<typename SubDomainEntity>
subIndex(SubDomainIndex subDomain,const SubDomainEntity & e,int i,int codim) const605   IndexType subIndex(SubDomainIndex subDomain, const SubDomainEntity& e, int i, int codim) const {
606     return subIndexForSubDomain(subDomain,_grid.hostEntity(e),i,codim);
607   }
608 
types(SubDomainIndex subDomain,int codim) const609   Types types(SubDomainIndex subDomain, int codim) const {
610     return types(codim);
611   }
612 
size(SubDomainIndex subDomain,GeometryType type) const613   IndexType size(SubDomainIndex subDomain, GeometryType type) const {
614     return sizeForSubDomain(subDomain,type);
615   }
616 
size(SubDomainIndex subDomain,int codim) const617   IndexType size(SubDomainIndex subDomain, int codim) const {
618     return sizeForSubDomain(subDomain,codim);
619   }
620 
621   //! Returns true if the entity is contained in a specific subdomain.
622   template<typename EntityType>
contains(SubDomainIndex subDomain,const EntityType & e) const623   bool contains(SubDomainIndex subDomain, const EntityType& e) const {
624     const GeometryType gt = e.type();
625     const IndexType hostIndex = _hostGridView.indexSet().index(_grid.hostEntity(e));
626     const MapEntry<EntityType::codimension>& me = indexMap<EntityType::codimension>()[LocalGeometryTypeIndex::index(gt)][hostIndex];
627     return me.domains.contains(subDomain);
628   }
629 
630 private:
631 
632   const GridImp& _grid;
633   HostGridView _hostGridView;
634   ContainerMap _containers;
635 
swap(ThisType & rhs)636   void swap(ThisType& rhs) {
637     assert(&_grid == &rhs._grid);
638     std::swap(_containers,rhs._containers);
639   }
640 
addToSubDomain(SubDomainIndex subDomain,const Codim0Entity & e)641   void addToSubDomain(SubDomainIndex subDomain, const Codim0Entity& e) {
642     GeometryType gt = e.type();
643     IndexType hostIndex = _hostGridView.indexSet().index(_grid.hostEntity(e));
644     indexMap<0>()[LocalGeometryTypeIndex::index(gt)][hostIndex].domains.add(subDomain);
645   }
646 
removeFromSubDomain(SubDomainIndex subDomain,const Codim0Entity & e)647   void removeFromSubDomain(SubDomainIndex subDomain, const Codim0Entity& e) {
648     GeometryType gt = e.type();
649     IndexType hostIndex = _hostGridView.indexSet().index(_grid.hostEntity(e));
650     indexMap<0>()[LocalGeometryTypeIndex::index(gt)][hostIndex].domains.remove(subDomain);
651   }
652 
removeFromAllSubDomains(const Codim0Entity & e)653   void removeFromAllSubDomains(const Codim0Entity& e) {
654     GeometryType gt = e.type();
655     IndexType hostIndex = _hostGridView.indexSet().index(_grid.hostEntity(e));
656     indexMap<0>()[LocalGeometryTypeIndex::index(gt)][hostIndex].domains.clear();
657   }
658 
assignToSubDomain(SubDomainIndex subDomain,const Codim0Entity & e)659   void assignToSubDomain(SubDomainIndex subDomain, const Codim0Entity& e) {
660     GeometryType gt = e.type();
661     IndexType hostIndex = _hostGridView.indexSet().index(_grid.hostEntity(e));
662     indexMap<0>()[LocalGeometryTypeIndex::index(gt)][hostIndex].domains.set(subDomain);
663   }
664 
addToSubDomains(const typename MDGridTraits::template Codim<0>::SubDomainSet & subDomains,const Codim0Entity & e)665   void addToSubDomains(const typename MDGridTraits::template Codim<0>::SubDomainSet& subDomains, const Codim0Entity& e) {
666     GeometryType gt = e.type();
667     IndexType hostIndex = _hostGridView.indexSet().index(_grid.hostEntity(e));
668     indexMap<0>()[LocalGeometryTypeIndex::index(gt)][hostIndex].domains.addAll(subDomains);
669   }
670 
671 public:
672 
673   // just make these public for std::make_shared() access
674 
IndexSetWrapper(const GridImp & grid,HostGridView hostGridView)675   IndexSetWrapper(const GridImp& grid, HostGridView hostGridView) :
676     _grid(grid),
677     _hostGridView(hostGridView)
678   {}
679 
IndexSetWrapper(const ThisType & rhs)680   explicit IndexSetWrapper(const ThisType& rhs) :
681     _grid(rhs._grid),
682     _hostGridView(rhs._hostGridView),
683     _containers(rhs._containers)
684     {}
685 
686 private:
687 
688   //! Returns the index map for the given codimension.
689   //! \tparam cc The requested codimension.
690   template<int cc>
indexMap()691   typename Containers<cc>::IndexMap& indexMap() {
692     return std::get<cc>(_containers).indexMap;
693   }
694 
695   template<int cc>
sizeMap()696   typename Containers<cc>::SizeMap& sizeMap() {
697     return std::get<cc>(_containers).sizeMap;
698   }
699 
700   template<int cc>
codimSizes()701   typename Containers<cc>::CodimSizeMap& codimSizes() {
702     return std::get<cc>(_containers).codimSizeMap;
703   }
704 
705   template<int cc>
multiIndexMap()706   typename Containers<cc>::MultiIndexMap& multiIndexMap() {
707     return std::get<cc>(_containers).multiIndexMap;
708   }
709 
710   template<int cc>
indexMap() const711   const typename Containers<cc>::IndexMap& indexMap() const {
712     return std::get<cc>(_containers).indexMap;
713   }
714 
715   template<int cc>
sizeMap() const716   const typename Containers<cc>::SizeMap& sizeMap() const {
717     return std::get<cc>(_containers).sizeMap;
718   }
719 
720   template<int cc>
codimSizes() const721   const typename Containers<cc>::CodimSizeMap& codimSizes() const {
722     return std::get<cc>(_containers).codimSizeMap;
723   }
724 
725   template<int cc>
multiIndexMap() const726   const typename Containers<cc>::MultiIndexMap& multiIndexMap() const {
727     return std::get<cc>(_containers).multiIndexMap;
728   }
729 
730   template<typename Functor>
applyToCodims(Functor func) const731   void applyToCodims(Functor func) const {
732     TypeTree::apply_to_tuple(
733       _containers,
734       func,
735       TypeTree::apply_to_tuple_policy::pass_index()
736       );
737   }
738 
739   template<typename Functor>
applyToCodims(Functor func)740   void applyToCodims(Functor func) {
741     TypeTree::apply_to_tuple(
742       _containers,
743       func,
744       TypeTree::apply_to_tuple_policy::pass_index()
745       );
746   }
747 
748   template<typename Impl>
749   struct applyToCodim {
750 
751     template<typename I, typename T>
operator ()Dune::mdgrid::IndexSetWrapper::applyToCodim752     void operator()(I i, T&& t) const {
753       const int codim = I::value;
754       detail::applyIf<MDGridTraits::template Codim<codim>::supported,const Impl>(static_cast<const Impl&>(*this)).template apply<codim>(std::forward<T>(t));
755     }
756 
757   };
758 
759   struct resetPerCodim : public applyToCodim<resetPerCodim> {
760 
761     template<int codim>
applyDune::mdgrid::IndexSetWrapper::resetPerCodim762     void apply(Containers<codim>& c) const {
763       // setup per-codim sizemap
764       _traits.template setupSizeContainer<codim>(c.codimSizeMap);
765       c.indexMap.resize(LocalGeometryTypeIndex::size(dimension-codim));
766       c.sizeMap.resize(LocalGeometryTypeIndex::size(dimension-codim));
767       for (auto gt : _his.types(codim)) {
768         const auto gt_index = LocalGeometryTypeIndex::index(gt);
769         if (_full) {
770           // resize index map
771           c.indexMap[gt_index].resize(_his.size(gt));
772         } else if (codim > 0) {
773           // clear out marked state for codim > 0 (we cannot keep the old
774           // state for subentities, as doing so will leave stale entries if
775           // elements are removed from a subdomain
776           for (auto& mapEntry : c.indexMap[gt_index])
777             mapEntry.domains.clear();
778         }
779         // setup / reset SizeMap counter
780         auto& size_map = c.sizeMap[gt_index];
781         _traits.template setupSizeContainer<codim>(size_map);
782         std::fill(size_map.begin(),size_map.end(),0);
783       }
784       // clear MultiIndexMap
785       c.multiIndexMap.clear();
786     }
787 
resetPerCodimDune::mdgrid::IndexSetWrapper::resetPerCodim788     resetPerCodim(bool full, const HostIndexSet& his, const MDGridTraits& traits) :
789       _full(full),
790       _his(his),
791       _traits(traits)
792     {}
793 
794     const bool _full;
795     const HostIndexSet& _his;
796     const MDGridTraits& _traits;
797   };
798 
reset(bool full)799   void reset(bool full) {
800     const HostIndexSet& his = _hostGridView.indexSet();
801     if (full) {
802       ContainerMap cm = ContainerMap();
803       std::swap(_containers,cm);
804     }
805     applyToCodims(resetPerCodim(full,his,_grid._traits));
806   }
807 
808   struct updatePerCodimSizes : public applyToCodim<updatePerCodimSizes> {
809 
810     template<int codim>
applyDune::mdgrid::IndexSetWrapper::updatePerCodimSizes811     void apply(Containers<codim>& c) const {
812       // reset size for this codim to zero
813       std::fill(c.codimSizeMap.begin(),c.codimSizeMap.end(),0);
814       // collect per-geometrytype sizes into codim size structure
815       std::for_each(c.sizeMap.begin(),
816                     c.sizeMap.end(),
817                     util::collect_elementwise<std::plus<IndexType> >(c.codimSizeMap));
818     }
819 
820   };
821 
update(LevelIndexSets & levelIndexSets,bool full)822   void update(LevelIndexSets& levelIndexSets, bool full) {
823     const HostIndexSet& his = _hostGridView.indexSet();
824     //reset(full);
825     for (typename LevelIndexSets::iterator it = levelIndexSets.begin(); it != levelIndexSets.end(); ++it) {
826       (*it)->reset(full);
827     }
828 
829     this->communicateSubDomainSelection();
830 
831     typename Containers<0>::IndexMap& im = indexMap<0>();
832     typename Containers<0>::SizeMap& sm = sizeMap<0>();
833     for (const auto& he : elements(_hostGridView)) {
834       auto geo = he.geometry();
835       auto hgt = geo.type();
836       const auto hgt_index = LocalGeometryTypeIndex::index(hgt);
837       IndexType hostIndex = his.index(he);
838       MapEntry<0>& me = im[hgt_index][hostIndex];
839 
840       if (_grid.supportLevelIndexSets()) {
841         levelIndexSets[he.level()]->template indexMap<0>()[hgt_index][levelIndexSets[he.level()]->_hostGridView.indexSet().index(he)].domains.addAll(me.domains);
842         markAncestors(levelIndexSets,he,me.domains);
843       }
844       updateMapEntry(me,sm[hgt_index],multiIndexMap<0>());
845       applyToCodims(markSubIndices(he,me.domains,his,geo));
846     }
847 
848     propagateBorderEntitySubDomains();
849 
850     applyToCodims(updateSubIndices(*this));
851     applyToCodims(updatePerCodimSizes());
852     for(typename LevelIndexSets::iterator it = levelIndexSets.begin(); it != levelIndexSets.end(); ++it) {
853       (*it)->updateLevelIndexSet();
854     }
855   }
856 
857 
updateLevelIndexSet()858   void updateLevelIndexSet() {
859     const HostIndexSet& his = _hostGridView.indexSet();
860     typename Containers<0>::IndexMap& im = indexMap<0>();
861     typename Containers<0>::SizeMap& sm = sizeMap<0>();
862 
863     communicateSubDomainSelection();
864 
865     for (const auto& he : elements(_hostGridView)) {
866       auto geo = he.geometry();
867       const GeometryType hgt = geo.type();
868       const auto hgt_index = LocalGeometryTypeIndex::index(hgt);
869       IndexType hostIndex = his.index(he);
870       MapEntry<0>& me = im[hgt_index][hostIndex];
871       updateMapEntry(me,sm[hgt_index],multiIndexMap<0>());
872       applyToCodims(markSubIndices(he,me.domains,his,geo));
873     }
874 
875     propagateBorderEntitySubDomains();
876 
877     applyToCodims(updateSubIndices(*this));
878     applyToCodims(updatePerCodimSizes());
879   }
880 
881   template<int codim, typename SizeContainer, typename MultiIndexContainer>
updateMapEntry(MapEntry<codim> & me,SizeContainer & sizes,std::vector<MultiIndexContainer> & multiIndexMap)882   void updateMapEntry(MapEntry<codim>& me, SizeContainer& sizes, std::vector<MultiIndexContainer>& multiIndexMap) {
883     switch (me.domains.state()) {
884     case MapEntry<codim>::SubDomainSet::emptySet:
885       break;
886     case MapEntry<codim>::SubDomainSet::simpleSet:
887       me.index = sizes[*me.domains.begin()]++;
888       break;
889     case MapEntry<codim>::SubDomainSet::multipleSet:
890       me.index = multiIndexMap.size();
891       multiIndexMap.push_back(MultiIndexContainer());
892       MultiIndexContainer& mic = multiIndexMap.back();
893       for (typename SubDomainSet::Iterator it = me.domains.begin(); it != me.domains.end(); ++it) {
894 	mic[me.domains.domainOffset(*it)] = sizes[*it]++;
895       }
896     }
897   }
898 
899   template<typename SubDomainSet>
markAncestors(LevelIndexSets & levelIndexSets,HostEntity he,const SubDomainSet & domains)900   void markAncestors(LevelIndexSets& levelIndexSets, HostEntity he, const SubDomainSet& domains) {
901     while (he.level() > 0) {
902       he = he.father();
903       SubDomainSet& fatherDomains =
904         levelIndexSets[he.level()]->template indexMap<0>()[LocalGeometryTypeIndex::index(he.type())][levelIndexSets[he.level()]->_hostGridView.indexSet().index(he)].domains;
905       if (fatherDomains.containsAll(domains))
906         break;
907       fatherDomains.addAll(domains);
908     }
909   }
910 
911   struct markSubIndices : public applyToCodim<const markSubIndices> {
912 
913     template<int codim>
applyDune::mdgrid::IndexSetWrapper::markSubIndices914     void apply(Containers<codim>& c) const {
915       if (codim == 0)
916         return;
917       const int size = _refEl.size(codim);
918       for (int i = 0; i < size; ++i) {
919         IndexType hostIndex = _his.subIndex(_he,i,codim);
920         GeometryType gt = _refEl.type(i,codim);
921         c.indexMap[LocalGeometryTypeIndex::index(gt)][hostIndex].domains.addAll(_domains);
922       }
923     }
924 
925     typedef typename MapEntry<0>::SubDomainSet& DomainSet;
926 
927     const HostEntity& _he;
928     DomainSet& _domains;
929     const HostIndexSet& _his;
930     CellReferenceElement _refEl;
931 
markSubIndicesDune::mdgrid::IndexSetWrapper::markSubIndices932     markSubIndices(const HostEntity& he, DomainSet& domains, const HostIndexSet& his, const typename HostEntity::Geometry& geo) :
933       _he(he),
934       _domains(domains),
935       _his(his),
936       _refEl(referenceElement(geo))
937     {}
938 
939   };
940 
941   struct updateSubIndices : public applyToCodim<const updateSubIndices> {
942 
943     template<int codim>
applyDune::mdgrid::IndexSetWrapper::updateSubIndices944     void apply(Containers<codim>& c) const {
945       if (codim == 0)
946         return;
947       for (std::size_t gt_index = 0,
948              gt_end = c.indexMap.size();
949            gt_index != gt_end;
950            ++gt_index)
951         for (auto& im_entry : c.indexMap[gt_index])
952           _indexSet.updateMapEntry(im_entry,c.sizeMap[gt_index],c.multiIndexMap);
953     }
954 
955     ThisType& _indexSet;
956 
updateSubIndicesDune::mdgrid::IndexSetWrapper::updateSubIndices957     updateSubIndices(ThisType& indexSet) :
958       _indexSet(indexSet)
959     {}
960   };
961 
962   //! functor template for retrieving a subindex.
963   struct getSupportsCodim : public dispatchToCodim<getSupportsCodim,bool,false> {
964 
965     template<int codim>
invokeDune::mdgrid::IndexSetWrapper::getSupportsCodim966     bool invoke() const {
967       return MDGridTraits::template Codim<codim>::supported && Dune::Capabilities::hasEntity<HostGrid,codim>::v;
968     }
969 
970   };
971 
supportsCodim(int codim) const972   bool supportsCodim(int codim) const
973   {
974     return getSupportsCodim().dispatch(codim);
975   }
976 
977   template<typename Impl>
978   struct SubDomainSetDataHandleBase
979     : public Dune::CommDataHandleIF<Impl,
980                                     typename MapEntry<0>::SubDomainSet::DataHandle::DataType
981                                     >
982   {
983     typedef typename MapEntry<0>::SubDomainSet SubDomainSet;
984     typedef typename SubDomainSet::DataHandle DataHandle;
985 
fixedSizeDune::mdgrid::IndexSetWrapper::SubDomainSetDataHandleBase986     bool fixedSize(int dim, int codim) const
987     {
988       return DataHandle::fixedSize(dim,codim);
989     }
990 
991     template<typename Entity>
sizeDune::mdgrid::IndexSetWrapper::SubDomainSetDataHandleBase992     std::size_t size(const Entity& e) const
993     {
994       return MapEntry<Entity::codimension>::SubDomainSet::DataHandle::size(_indexSet.subDomainsForHostEntity(e));
995     }
996 
997     template<typename MessageBufferImp, typename Entity>
gatherDune::mdgrid::IndexSetWrapper::SubDomainSetDataHandleBase998     void gather(MessageBufferImp& buf, const Entity& e) const
999     {
1000       MapEntry<Entity::codimension>::SubDomainSet::DataHandle::gather(buf,_indexSet.subDomainsForHostEntity(e));
1001     }
1002 
1003     template<typename MessageBufferImp, typename Entity>
scatterDune::mdgrid::IndexSetWrapper::SubDomainSetDataHandleBase1004     void scatter(MessageBufferImp& buf, const Entity& e, std::size_t n)
1005     {
1006       MapEntry<Entity::codimension>::SubDomainSet::DataHandle::scatter(buf,_indexSet.subDomainsForHostEntity(e),n);
1007     }
1008 
SubDomainSetDataHandleBaseDune::mdgrid::IndexSetWrapper::SubDomainSetDataHandleBase1009     SubDomainSetDataHandleBase(ThisType& indexSet)
1010       : _indexSet(indexSet)
1011     {}
1012 
1013     ThisType& _indexSet;
1014 
1015   };
1016 
1017   struct SelectionDataHandle
1018     : public SubDomainSetDataHandleBase<SelectionDataHandle>
1019   {
1020 
containsDune::mdgrid::IndexSetWrapper::SelectionDataHandle1021     bool contains(int dim, int codim) const
1022     {
1023       return codim == 0;
1024     }
1025 
SelectionDataHandleDune::mdgrid::IndexSetWrapper::SelectionDataHandle1026     SelectionDataHandle(ThisType& indexSet)
1027       : SubDomainSetDataHandleBase<SelectionDataHandle>(indexSet)
1028     {}
1029 
1030   };
1031 
1032   struct BorderPropagationDataHandle
1033     : public SubDomainSetDataHandleBase<BorderPropagationDataHandle>
1034   {
1035 
containsDune::mdgrid::IndexSetWrapper::BorderPropagationDataHandle1036     bool contains(int dim, int codim) const
1037     {
1038       return codim > 0 && this->_indexSet.supportsCodim(codim);
1039     }
1040 
BorderPropagationDataHandleDune::mdgrid::IndexSetWrapper::BorderPropagationDataHandle1041     BorderPropagationDataHandle(ThisType& indexSet)
1042       : SubDomainSetDataHandleBase<BorderPropagationDataHandle>(indexSet)
1043     {}
1044 
1045   };
1046 
1047 
communicateSubDomainSelection()1048   void communicateSubDomainSelection()
1049   {
1050     SelectionDataHandle dh(*this);
1051     _hostGridView.template communicate<SelectionDataHandle>(dh,Dune::InteriorBorder_All_Interface,Dune::ForwardCommunication);
1052   }
1053 
propagateBorderEntitySubDomains()1054   void propagateBorderEntitySubDomains()
1055   {
1056     BorderPropagationDataHandle dh(*this);
1057     _hostGridView.communicate(dh,Dune::InteriorBorder_All_Interface,Dune::ForwardCommunication);
1058   }
1059 
1060 };
1061 
1062 } // namespace mdgrid
1063 
1064 } // namespace Dune
1065 
1066 #endif // DUNE_MULTIDOMAINGRID_INDEXSETS_HH
1067