Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
PolyhedralMeshImplementation.h
Go to the documentation of this file.
1/* Dimension-generic template definitions for PolyhedralMesh. */
2#ifndef model_PolyhedralMeshImplementation_H_
3#define model_PolyhedralMeshImplementation_H_
4namespace model
5{
6 // Only normal orientation and the corresponding grain checks are specialized.
7 template <> void PolyhedralMesh<3>::orientMeshFaces();
8 template <> void PolyhedralMesh<3>::validate() const;
9 template <int dim> std::shared_ptr<Polyhedron<dim, 0>> PolyhedralFaceIncidence<dim>::source() const
10 {
11 return reversed ? edge->children.rbegin()->second : edge->children.begin()->second;
12 }
13 template <int dim> std::shared_ptr<Polyhedron<dim, 0>> PolyhedralFaceIncidence<dim>::sink() const
14 {
15 return reversed ? edge->children.begin()->second : edge->children.rbegin()->second;
16 }
17 template <int dim> Eigen::Matrix<double, dim, 1> PolyhedralFaceIncidence<dim>::tangent() const
18 {
19 return (sink()->position - source()->position).normalized();
20 }
22 {
23 const auto owner = face.lock();
24 if (!owner)
25 {
26 throw std::runtime_error("Expired polyhedral face incidence");
27 }
28 return owner->perimeter.at((index + 1) % owner->perimeter.size());
29 }
31 {
32 const auto owner = face.lock();
33 if (!owner)
34 {
35 throw std::runtime_error("Expired polyhedral face incidence");
36 }
37 return owner->perimeter.at((index + owner->perimeter.size() - 1) % owner->perimeter.size());
38 }
39 template <int dim> const Polyhedron<dim, dim> &PolyhedralMesh<dim>::region(size_t regionID) const
40 {
41 return *factory<dim>().at({regionID});
42 }
43 template <int dim> const Polyhedron<dim, dim - 1> &PolyhedralMesh<dim>::face(size_t faceID) const
44 {
45 return *factory<dim - 1>().at({faceID});
46 }
47
48 template <int dim>
49 template <int order>
50 void PolyhedralMesh<dim>::buildBoundary(const std::shared_ptr<Polyhedron<dim, order>> &cell,
51 const std::vector<std::vector<size_t>> &simplices,
52 const std::map<size_t, Vector> &positions)
53 {
54 if constexpr (order == 0)
55 {
56 if (simplices.size() != 1 || simplices.front().size() != 1)
57 {
58 throw std::runtime_error("A polyhedral vertex requires one mesh vertex");
59 }
60 cell->position = positions.at(simplices.front().front());
61 }
62 else
63 {
64 using Key = std::vector<size_t>;
65 std::map<Key, size_t> counts;
66 std::set<Key> unique;
67 for (auto simplex : simplices)
68 {
69 std::sort(simplex.begin(), simplex.end());
70 if (simplex.size() != order + 1 ||
71 std::adjacent_find(simplex.begin(), simplex.end()) != simplex.end() ||
72 !unique.insert(simplex).second)
73 {
74 throw std::runtime_error("Invalid or duplicate boundary simplex");
75 }
76 for (const auto id : simplex)
77 {
78 positions.at(id);
79 }
80 for (size_t k = 0; k < simplex.size(); ++k)
81 {
82 auto child = simplex;
83 child.erase(child.begin() + k);
84 ++counts[child];
85 }
86 }
87 for (const auto &entry : counts)
88 {
89 if (entry.second > 2)
90 {
91 throw std::runtime_error("Non-manifold boundary simplex");
92 }
93 if (entry.second == 1)
94 {
95 const auto child = std::get<order - 1>(factories).get(entry.first);
96 cell->children.emplace(child->key, child);
97 child->parents.emplace(cell->key, cell);
98 buildBoundary<order - 1>(child, {entry.first}, positions);
99 }
100 }
101 if constexpr (order == 1)
102 {
103 if (cell->children.size() != 2)
104 {
105 throw std::runtime_error("A polyhedral edge requires two endpoints");
106 }
107 // Reject disconnected cycles hidden beside a valid open chain.
108 std::map<size_t, std::set<size_t>> adjacency;
109 for (const auto &simplex : simplices)
110 {
111 adjacency[simplex[0]].insert(simplex[1]);
112 adjacency[simplex[1]].insert(simplex[0]);
113 }
114 std::set<size_t> visited;
115 std::vector<size_t> pending{simplices.front().front()};
116 while (!pending.empty())
117 {
118 const auto id = pending.back();
119 pending.pop_back();
120 if (visited.insert(id).second)
121 {
122 if (adjacency.at(id).size() > 2)
123 {
124 throw std::runtime_error("Branched polyhedral edge");
125 }
126 for (const auto neighbor : adjacency.at(id))
127 {
128 pending.push_back(neighbor);
129 }
130 }
131 }
132 if (visited.size() != adjacency.size())
133 {
134 throw std::runtime_error("Disconnected polyhedral edge");
135 }
136 }
137 if constexpr (order == 2)
138 {
139 buildPerimeter(cell);
140 }
141 }
142 }
143
144 template <int dim> void PolyhedralMesh<dim>::buildPerimeter(const std::shared_ptr<Polyhedron<dim, 2>> &cell)
145 {
146 using Key = PolyhedronKey<dim, 0>;
147 if (cell->perimeter.empty())
148 {
149 std::map<Key, std::vector<std::shared_ptr<Polyhedron<dim, 1>>>> adjacency;
150 for (const auto &entry : cell->children)
151 {
152 for (const auto &vertex : entry.second->children)
153 {
154 adjacency[vertex.first].push_back(entry.second);
155 }
156 }
157 for (const auto &entry : adjacency)
158 {
159 if (entry.second.size() != 2)
160 {
161 throw std::runtime_error("Open or branched polygon perimeter");
162 }
163 }
164 if (cell->children.size() < 3)
165 {
166 throw std::runtime_error("Polygon requires at least three edges");
167 }
168 const auto first = cell->children.begin()->second;
169 auto edge = first;
170 auto vertex = first->children.begin()->second;
171 const auto start = vertex;
172 std::set<PolyhedronKey<dim, 1>> visited;
173 do
174 {
175 if (!visited.insert(edge->key).second)
176 {
177 throw std::runtime_error("Polygon perimeter repeats an edge");
178 }
179 cell->perimeter.push_back(
180 {cell, edge, cell->perimeter.size(), vertex != edge->children.begin()->second});
181 edge->faceIncidences.emplace(cell->key, cell->perimeter.size() - 1);
182 vertex = cell->perimeter.back().sink();
183 const auto &neighbors = adjacency.at(vertex->key);
184 edge = neighbors[0] == edge ? neighbors[1] : neighbors[0];
185 } while (edge != first);
186 if (vertex != start || visited.size() != cell->children.size())
187 {
188 throw std::runtime_error("Polygon requires one closed perimeter");
189 }
190 if constexpr (dim == 2)
191 {
192 double area = 0;
193 const auto origin = start->position;
194 for (const auto &incidence : cell->perimeter)
195 {
196 const Vector a = incidence.source()->position - origin;
197 const Vector b = incidence.sink()->position - origin;
198 area += a[0] * b[1] - a[1] * b[0];
199 }
200 if (area < 0)
201 {
202 std::reverse(cell->perimeter.begin(), cell->perimeter.end());
203 for (auto &incidence : cell->perimeter)
204 {
205 incidence.reversed = !incidence.reversed;
206 }
207 }
208 for (size_t k = 0; k < cell->perimeter.size(); ++k)
209 {
210 cell->perimeter[k].index = k;
211 cell->perimeter[k].edge->faceIncidences.at(cell->key) = k;
212 }
213 }
214 }
215 }
216 template <int dim> void PolyhedralMesh<dim>::orientMeshFaces()
217 {
218 // Higher-dimensional orientation is not needed for parent/child topology.
219 }
220
221 template <int dim>
222 PolyhedralMesh<dim>::PolyhedralMesh(const std::map<size_t, Vector> &positions, const std::vector<FaceInput> &faces)
224 {
225 std::set<size_t> ids;
226 for (const auto &input : faces)
227 {
228 if (!ids.insert(input.id).second || input.regions.empty() || input.regions.size() > 2 ||
229 (input.regions.size() == 2 && input.regions[0] == input.regions[1]) || input.simplices.empty())
230 {
231 throw std::runtime_error("Invalid polyhedral face input");
232 }
233 const auto face = std::get<dim - 1>(factories).get({input.id});
234 std::vector<std::vector<size_t>> simplices;
235 for (const auto &simplex : input.simplices)
236 {
237 simplices.emplace_back(simplex.begin(), simplex.end());
238 }
239 buildBoundary<dim - 1>(face, simplices, positions);
240 for (const auto id : input.regions)
241 {
242 const auto region = std::get<dim>(factories).get({id});
243 region->children.emplace(face->key, face);
244 face->parents.emplace(region->key, region);
245 }
246 }
247 if constexpr (dim == 2)
248 {
249 for (const auto &region : factory<2>())
250 {
251 buildPerimeter(region.second);
252 }
253 }
254 validateLevel<dim>();
255 }
256
257 template <int dim>
258 std::shared_ptr<Polyhedron<dim, dim - 1>> PolyhedralMesh<dim>::createFace(const Simplex<dim, dim - 1> *simplex)
259 {
260 const StaticID<Polyhedron<dim, dim - 1>> identifier;
261 const size_t id = identifier.sID;
262 const auto face = std::get<dim - 1>(factories).get(id);
263 face->initialize(simplex);
264 for (const auto regionID : simplex->regionIDs())
265 {
266 const auto region = getRegion(regionID);
267 face->parents.emplace(regionID, region);
268 region->children.emplace(id, face);
269 }
270 return face;
271 }
272 template <int dim> template <int order> void PolyhedralMesh<dim>::attachSimplex(const Simplex<dim, order> *simplex)
273 {
274 if constexpr (order < dim - 1)
275 {
276 const std::vector<size_t> key(simplex->xID.begin(), simplex->xID.end());
277 const auto found = std::get<order>(factories).find(key);
278 if (found != std::get<order>(factories).end())
279 {
280 found->second->simplices().insert(simplex);
281 }
282 }
283 if constexpr (order > 0)
284 {
285 for (const auto &child : simplex->children())
286 {
287 attachSimplex<order - 1>(child.get());
288 }
289 }
290 }
291 template <int dim> void PolyhedralMesh<dim>::buildTopology()
292 {
293 for (const auto &entry : factory<dim - 1>())
294 {
295 const auto &face = entry.second;
296 std::map<size_t, Vector> positions;
297 std::vector<std::vector<size_t>> simplices;
298 for (const auto *simplex : face->simplices())
299 {
300 simplices.emplace_back(simplex->xID.begin(), simplex->xID.end());
301 for (const auto *vertex : simplex->vertices())
302 {
303 positions.emplace(vertex->xID[0], vertex->P0);
304 }
305 }
306 buildBoundary<dim - 1>(face, simplices, positions);
307 for (const auto *simplex : face->simplices())
308 {
309 attachSimplex<dim - 1>(simplex);
310 }
311 }
312 if constexpr (dim == 2)
313 {
314 for (const auto &region : factory<dim>())
315 {
316 buildPerimeter(region.second);
317 }
318 }
319 orientMeshFaces();
320 validate();
321 }
322
323 template <int dim> template <int order> void PolyhedralMesh<dim>::validateLevel() const
324 {
325 for (const auto &entry : factory<order>())
326 {
327 const auto &cell = *entry.second;
328 if constexpr (order > 0)
329 {
330 if (cell.children.size() < size_t(order + 1))
331 {
332 throw std::runtime_error("Polyhedral cell has too few boundary cells");
333 }
334 for (const auto &child : cell.children)
335 {
336 if (factory<order - 1>().at(child.first) != child.second ||
337 child.second->parents.at(cell.key).lock() != entry.second)
338 {
339 throw std::runtime_error("Nonreciprocal polyhedral child incidence");
340 }
341 }
342 if constexpr (order > 1)
343 {
344 std::map<PolyhedronKey<dim, order - 2>, size_t> counts;
345 for (const auto &child : cell.children)
346 {
347 for (const auto &grandchild : child.second->children)
348 {
349 ++counts[grandchild.first];
350 }
351 }
352 for (const auto &count : counts)
353 {
354 if (count.second != 2)
355 {
356 throw std::runtime_error("Open or non-manifold polyhedral cell boundary");
357 }
358 }
359 }
360 }
361 if constexpr (order < dim)
362 {
363 if (cell.parents.empty() || (order == dim - 1 && cell.parents.size() > 2))
364 {
365 throw std::runtime_error("Invalid polyhedral parent count");
366 }
367 for (const auto &parent : cell.parents)
368 {
369 const auto owner = parent.second.lock();
370 if (!owner || factory<order + 1>().at(parent.first) != owner ||
371 owner->children.at(cell.key) != entry.second)
372 {
373 throw std::runtime_error("Nonreciprocal polyhedral parent incidence");
374 }
375 }
376 }
377 }
378 if constexpr (order > 0)
379 {
380 validateLevel<order - 1>();
381 }
382 }
383 template <int dim> void PolyhedralMesh<dim>::validate() const
384 {
385 validateLevel<dim>();
386 }
387} // namespace model
388#endif
const Polyhedron< dim, dim - 1 > & face(size_t id) const
std::shared_ptr< Polyhedron< dim, dim - 1 > > createFace(const Simplex< dim, dim - 1 > *simplex)
const PolyhedronFactory< dim, order > & factory() const
const Polyhedron< dim, dim > & region(size_t id) const
std::shared_ptr< Polyhedron< dim, dim > > getRegion(size_t id)
A class template that implements a counter of the number of instances of Derived type that are create...
Definition StaticID.h:29
a
Definition int_R.m:14
b
Definition int_R.m:16
size_t InstanceCount< Derived >::count
std::conditional_t<(order >=dim - 1), size_t, std::vector< size_t > > PolyhedronKey
Definition Polyhedron.h:22
std::weak_ptr< Polyhedron< dim, 2 > > face
Definition Polyhedron.h:45
PolyhedralFaceIncidence prev() const
PolyhedralFaceIncidence next() const
std::shared_ptr< Polyhedron< dim, 0 > > sink() const
std::shared_ptr< Polyhedron< dim, 0 > > source() const
Eigen::Matrix< double, dim, 1 > tangent() const
std::shared_ptr< Polyhedron< dim, 1 > > edge
Definition Polyhedron.h:46
int end[2]
struct otri neighbor
int parent
b order
int k
newbad key
REAL * vertex
Definition triangle.cpp:542
REAL area
vertex first