dune-pdelab 2.10-git
Loading...
Searching...
No Matches
uncolored.hh
Go to the documentation of this file.
1#ifndef DUNE_PDELAB_COMMON_PARTITION_HALO_UNCOLORED_HH
2#define DUNE_PDELAB_COMMON_PARTITION_HALO_UNCOLORED_HH
3
5
7#include <dune/grid/concepts/gridview.hh>
8
11
12#include <vector>
13#include <memory>
14#include <atomic>
15#include <version>
16
17#if __cpp_lib_execution >= 201603L
18#include <execution>
19#endif
20
21namespace Dune::PDELab::EntitySetPartition::Impl {
22
28template<Dune::Concept::GridView GV>
29class UncoloredHaloMixin {
30public:
31
32 explicit UncoloredHaloMixin(std::size_t halo_distance)
33 : _halo_distance{halo_distance}
34 {}
35
40 template<Dune::Concept::Entity Entity>
41 requires (Entity::codimension == 0)
42 [[nodiscard]] HaloRegion haloRegion(const Entity& entity) const {
43 if (_halo_distance == all_overlap_halo_region)
45 else if (_halo_distance == all_interior_halo_region)
47 else
48 return (*_entity_in_halo)[_element_mapper->index(entity)]
51 }
52
53protected:
54
56 template<class Super>
57 requires std::is_base_of_v<UncoloredHaloMixin<GV>, Super>
58 void updateHalo(const Super& super) {
59 static_assert(std::same_as<GV, typename Super::EntitySet>);
60 static_assert(Super::Element::dimension == Super::EntitySet::dimension,
61 "Not implemented: Partition overlap information is only available on codim == 0 entities");
62
63 using Element = typename Super::Element;
64
65 _element_mapper = std::make_shared<Dune::MultipleCodimMultipleGeomTypeMapper<GV>>(super.entitySet(), mcmgElementLayout());
66
67 // if halo is too big or too small, no need to store region
68 if (_halo_distance == all_overlap_halo_region or _halo_distance == all_interior_halo_region) {
69 _entity_in_halo = nullptr;
70 _element_mapper = nullptr;
71 return;
72 }
73
74 auto all_entities_layout = [](GeometryType gt, int dimgrid) { return true; };
75 Dune::MultipleCodimMultipleGeomTypeMapper<GV> all_mapper(super.entitySet(), all_entities_layout);
76
77 // temporary storage where every entry can be updated concurrently
78 // note that proxy objects in std::vector<bool> are not thread-safe
79 std::vector<char> entity_in_halo(_element_mapper->size(), false);
80 std::vector<std::size_t> entity_owner;
81 std::vector<char> entity_in_overlap;
82
83 // clang (<19) still does not support std::atomic_ref, so use __atomic builtins if not available
84#if __cpp_lib_atomic_ref >= 201806L
87 constexpr auto atomic_load_relaxed = []<class T>(T& obj) {
88 return std::atomic_ref<T>{obj}.load(std::memory_order::relaxed);
89 };
90 constexpr auto atomic_store_relaxed = []<class T>(T& obj, T val) {
91 std::atomic_ref{obj}.store(val, std::memory_order::relaxed);
92 };
93#else
94 static_assert(__atomic_always_lock_free(sizeof(char), 0));
95 static_assert(__atomic_always_lock_free(sizeof(std::size_t), 0));
96 constexpr auto atomic_load_relaxed = []<class T>(T& obj) {
97 T tmp{};
98 __atomic_load(&obj, &tmp, __ATOMIC_RELAXED);
99 return tmp;
100 };
101 constexpr auto atomic_store_relaxed = []<class T>(T& obj, T val) {
102 __atomic_store(&obj, &val, __ATOMIC_RELAXED);
103 };
104#endif
105
106 // mark every entity with a unique owner
107 auto mark_owner = [&](const Element& entity, std::size_t id, auto) {
109 for (const auto& sub_entity : subEntities(entity, Dune::Codim<codim>{})) {
110 auto entity_index = all_mapper.index(sub_entity);
111 atomic_store_relaxed(entity_owner[entity_index], id);
112 }
113 });
114 };
115
116 // if an entity is owned by different patches, it is in the overlap
117 auto mark_entity_overlap = [&](const Element& entity, std::size_t id) {
119 for (const auto& sub_entity : subEntities(entity, Dune::Codim<codim>{})) {
120 auto entity_index = all_mapper.index(sub_entity);
121 auto owner = atomic_load_relaxed(entity_owner[entity_index]);
122 if (owner != id)
123 atomic_store_relaxed(entity_in_overlap[entity_index], char{true});
124 }
125 });
126 };
127
128 // propagate the overlap on neighboring entities recursively until the halo distance is reached
129 std::function<void(const Element&,std::size_t,std::size_t)> mark_overlap;
130 mark_overlap = [&](const Element& entity, std::size_t id, std::size_t halo_distance) {
131 mark_entity_overlap(entity, id);
132 if (halo_distance != 0) {
133 for (const auto& intersection : intersections(super.entitySet(), entity))
134 if (intersection.neighbor())
135 mark_overlap(intersection.outside(), id, halo_distance-1);
136 }
137 };
138
139 // if any of the sub-entities is in the overlap, the entity is in the halo
140 auto propagate_overlap = [&](const Element& entity, auto, auto) {
141 auto entity_index = _element_mapper->index(entity);
143 for (const auto& sub_entity : subEntities(entity, Dune::Codim<codim>{})) {
144 auto sub_entity_index = all_mapper.index(sub_entity);
145 bool in_overlap = atomic_load_relaxed(entity_in_overlap[sub_entity_index]);
146 if (in_overlap) {
147 atomic_store_relaxed(entity_in_halo[entity_index], char{true});
148 }
149 }
150 });
151 };
152
153 // helper to run a function on all entities of all patches in parallel
154 auto for_each_element = [halo_distance = _halo_distance](const auto& entity_sets, auto apply){
155 auto patches = std::distance(entity_sets.begin(), entity_sets.end());
156 auto partitions = Dune::range(std::size_t{0}, static_cast<std::size_t>(patches));
158#if __cpp_lib_execution >= 201603L
159 std::execution::par,
160#endif
161 partitions.begin(), partitions.end(), [&](auto patch_id){
162 for (const auto& entity : entity_sets[patch_id])
163 apply(entity, patch_id, halo_distance);
164 });
165 };
166
167 for (const auto& concurrent_entity_sets : super) {
168 // clean up overlap info
169 entity_owner.assign(all_mapper.size(), std::numeric_limits<std::size_t>::max());
170 entity_in_overlap.assign(all_mapper.size(), false);
171
172 // phase 1: assign an owner to each used sub-entity
173 for_each_element(concurrent_entity_sets, mark_owner);
174
175 // phase 2: mark the overlap based in incompatible owners
176 for_each_element(concurrent_entity_sets, mark_overlap);
177
178 // phase 3: entities with an overlap are marked as shared region
179 for_each_element(concurrent_entity_sets, propagate_overlap);
180 }
181
182 _entity_in_halo = std::make_shared<std::vector<bool>>(entity_in_halo.size());
183 std::copy(entity_in_halo.begin(), entity_in_halo.end(), _entity_in_halo->begin());
184 }
185
186private:
188 std::shared_ptr<std::vector<bool>> _entity_in_halo;
189 std::size_t _halo_distance;
190};
191
192} // namespace Dune::PDELab::EntitySetPartition::Impl
193
194#endif // DUNE_PDELAB_COMMON_PARTITION_HALO_UNCOLORED_HH
int id()
static constexpr IntegralRange< std::decay_t< T > > range(T &&from, U &&to) noexcept
static Type apply(T &t)
constexpr void forEach(Range &&range, F &&f)
bool gt(const T &first, const T &second, typename EpsilonType< T >::Type epsilon=DefaultEpsilon< T, style >::value())
For backward compatibility – Do not use this!
HaloRegion
Possible halo regions of an entity in a partition.
Definition region.hh:12
static constexpr std::size_t all_overlap_halo_region
Constant for a halo distance with all halo regions being in the overlap.
Definition region.hh:24
static constexpr std::size_t all_interior_halo_region
Constant for a halo distance with all halo regions being in the interior.
Definition region.hh:21
IteratorRange<... > intersections(const GV &gv, const Entity &e)
IteratorRange<... > subEntities(const E &e, Codim< codim > c)
MCMGLayout mcmgElementLayout()
ALBERTA EL Element
GridImp::template Codim< cd >::Entity Entity
T assign(T... args)
T copy(T... args)
T distance(T... args)
T for_each(T... args)
T load(T... args)
T store(T... args)