ViennaLS
Loading...
Searching...
No Matches
lsMesh.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <array>
6#include <cmath>
7#include <functional>
8#include <iostream>
9#include <stdexcept>
10#include <unordered_map>
11#include <vector>
12
13#include <vcPointData.hpp>
14#include <vcSmartPointer.hpp>
15#include <vcVectorType.hpp>
16
17namespace viennals {
18
19using namespace viennacore;
20
25template <class T = double> class Mesh {
26public:
27 std::vector<Vec3D<T>> nodes;
28 std::vector<std::array<unsigned, 1>> vertices;
29 std::vector<std::array<unsigned, 2>> lines;
30 std::vector<std::array<unsigned, 3>> triangles;
31 std::vector<std::array<unsigned, 4>> tetras;
32 std::vector<std::array<unsigned, 8>> hexas;
33 PointData<T> pointData;
34 PointData<T> cellData;
35 Vec3D<T> minimumExtent{};
36 Vec3D<T> maximumExtent{};
37
38 constexpr static const char *materialIdsLabel = "MaterialIds";
39 constexpr static const char *normalsLabel = "Normals";
40
41 // Convenience function to create a new mesh smart pointer.
42 static auto New() { return SmartPointer<Mesh>::New(); }
43
44 const std::vector<Vec3D<T>> &getNodes() const { return nodes; }
45
46 std::vector<Vec3D<T>> &getNodes() { return nodes; }
47
48 template <int D, std::enable_if_t<D == 1, int> = 0>
49 std::vector<std::array<unsigned, D>> &getElements() {
50 return vertices;
51 }
52
53 template <int D, std::enable_if_t<D == 2, int> = 0>
54 std::vector<std::array<unsigned, D>> &getElements() {
55 return lines;
56 }
57
58 template <int D, std::enable_if_t<D == 3, int> = 0>
59 std::vector<std::array<unsigned, D>> &getElements() {
60 return triangles;
61 }
62
63 template <int D, std::enable_if_t<D == 4, int> = 0>
64 std::vector<std::array<unsigned, D>> &getElements() {
65 return tetras;
66 }
67
68 template <int D, std::enable_if_t<D == 8, int> = 0>
69 std::vector<std::array<unsigned, D>> &getElements() {
70 return hexas;
71 }
72
73 PointData<T> &getPointData() { return pointData; }
74
75 const PointData<T> &getPointData() const { return pointData; }
76
77 PointData<T> &getCellData() { return cellData; }
78
79 const PointData<T> &getCellData() const { return cellData; }
80
81 // helper function to get normals
82 std::vector<Vec3D<T>> *getNormals(const char *label = normalsLabel) {
83 return cellData.getVectorData(label);
84 }
85
86 // helper function to get material ids
87 std::vector<T> *getMaterialIds(const char *label = materialIdsLabel) {
88 return cellData.getScalarData(label);
89 }
90
91 unsigned insertNextNode(const Vec3D<T> &node) {
92 nodes.push_back(node);
93 return nodes.size() - 1;
94 }
95
96 unsigned insertNextVertex(const std::array<unsigned, 1> &vertex) {
97 vertices.push_back(vertex);
98 return vertices.size() - 1;
99 }
100
101 unsigned insertNextLine(const std::array<unsigned, 2> &line) {
102 lines.push_back(line);
103 return lines.size() - 1;
104 }
105
106 unsigned insertNextTriangle(const std::array<unsigned, 3> &triangle) {
107 triangles.push_back(triangle);
108 return triangles.size() - 1;
109 }
110
111 unsigned insertNextTetra(const std::array<unsigned, 4> &tetra) {
112 tetras.push_back(tetra);
113 return tetras.size() - 1;
114 }
115
116 unsigned insertNextHexa(const std::array<unsigned, 8> &hexa) {
117 hexas.push_back(hexa);
118 return hexas.size() - 1;
119 }
120
121 unsigned insertNextElement(const std::array<unsigned, 1> &vertex) {
122 vertices.push_back(vertex);
123 return vertices.size() - 1;
124 }
125
126 unsigned insertNextElement(const std::array<unsigned, 2> &line) {
127 lines.push_back(line);
128 return lines.size() - 1;
129 }
130
131 unsigned insertNextElement(const std::array<unsigned, 3> &triangle) {
132 triangles.push_back(triangle);
133 return triangles.size() - 1;
134 }
135
136 unsigned insertNextElement(const std::array<unsigned, 4> &tetra) {
137 tetras.push_back(tetra);
138 return tetras.size() - 1;
139 }
140
141 unsigned insertNextElement(const std::array<unsigned, 8> &hexa) {
142 hexas.push_back(hexa);
143 return hexas.size() - 1;
144 }
145
155 if (nodes.size() < 2)
156 return;
157
158 struct NodeHash {
159 std::size_t operator()(const Vec3D<T> &node) const {
160 std::size_t seed = 0;
161 for (const T coordinate : node) {
162 seed ^= std::hash<T>{}(coordinate) + std::size_t(0x9e3779b9) +
163 (seed << 6) + (seed >> 2);
164 }
165 return seed;
166 }
167 };
168
169 // Keep full coordinates as keys so hash collisions cannot merge nodes.
170 // std::hash<T> also gives equal hashes for +0 and -0, which compare equal.
171 std::unordered_map<Vec3D<T>, unsigned, NodeHash> uniqueNodes;
172 uniqueNodes.reserve(nodes.size());
173 std::vector<Vec3D<T>> newNodes;
174 newNodes.reserve(nodes.size());
175 std::vector<unsigned> oldToNew(nodes.size());
176 std::vector<unsigned> retainedIndices;
177 retainedIndices.reserve(nodes.size());
178
179 for (std::size_t i = 0; i < nodes.size(); ++i) {
180 const auto &node = nodes[i];
181 const auto newId = static_cast<unsigned>(newNodes.size());
182 // NaNs are not equal to themselves and cannot serve as hash-table keys.
183 if (!std::isnan(node[0]) && !std::isnan(node[1]) &&
184 !std::isnan(node[2])) {
185 const auto result = uniqueNodes.try_emplace(node, newId);
186 oldToNew[i] = result.first->second;
187 if (!result.second)
188 continue;
189 } else {
190 oldToNew[i] = newId;
191 }
192 newNodes.push_back(node);
193 retainedIndices.push_back(static_cast<unsigned>(i));
194 }
195
196 if (newNodes.size() == nodes.size())
197 return;
198
199 // Validate before translating data or changing any mesh connectivity.
200 const auto validateData = [this](const auto &arrays) {
201 for (const auto &data : arrays) {
202 if (data.size() != nodes.size()) {
203 throw std::invalid_argument(
204 "Mesh::removeDuplicateNodes: point-data size must match the "
205 "number of nodes.");
206 }
207 }
208 };
209 validateData(pointData.getScalarData());
210 validateData(pointData.getVectorData());
211 PointData<T> newPointData;
212 newPointData.translateFromData(pointData, retainedIndices);
213
214 const auto remapElements = [&oldToNew](auto &elements) {
215 for (auto &element : elements) {
216 for (auto &nodeId : element)
217 nodeId = oldToNew[nodeId];
218 }
219 };
220 remapElements(vertices);
221 remapElements(lines);
222 remapElements(triangles);
223 remapElements(tetras);
224 remapElements(hexas);
225
226 nodes = std::move(newNodes);
227 pointData = std::move(newPointData);
228 }
229
230 void append(const Mesh<T> &passedMesh) {
231 const unsigned numberOfOldNodes = nodes.size();
232
233 // append new nodes
234 nodes.insert(nodes.end(), passedMesh.nodes.begin(), passedMesh.nodes.end());
235
236 // go through all elements and increase node IDs to match new IDS
237 const unsigned numberOfVertices = vertices.size();
238 vertices.insert(vertices.end(), passedMesh.vertices.begin(),
239 passedMesh.vertices.end());
240 for (unsigned i = numberOfVertices;
241 i < passedMesh.vertices.size() + numberOfVertices; ++i) {
242 vertices[i][0] += numberOfOldNodes;
243 }
244
245 const unsigned numberOfLines = lines.size();
246 lines.insert(lines.end(), passedMesh.lines.begin(), passedMesh.lines.end());
247 for (unsigned i = numberOfLines;
248 i < passedMesh.lines.size() + numberOfLines; ++i) {
249 for (unsigned d = 0; d < 2; ++d) {
250 lines[i][d] += numberOfOldNodes;
251 }
252 }
253
254 const unsigned numberOfTriangles = triangles.size();
255 triangles.insert(triangles.end(), passedMesh.triangles.begin(),
256 passedMesh.triangles.end());
257 for (unsigned i = numberOfTriangles;
258 i < passedMesh.triangles.size() + numberOfTriangles; ++i) {
259 for (unsigned d = 0; d < 3; ++d) {
260 triangles[i][d] += numberOfOldNodes;
261 }
262 }
263
264 const unsigned numberOfTetras = tetras.size();
265 tetras.insert(tetras.end(), passedMesh.tetras.begin(),
266 passedMesh.tetras.end());
267 for (unsigned i = numberOfTetras;
268 i < passedMesh.tetras.size() + numberOfTetras; ++i) {
269 for (unsigned d = 0; d < 4; ++d) {
270 tetras[i][d] += numberOfOldNodes;
271 }
272 }
273
274 const unsigned numberOfHexas = hexas.size();
275 hexas.insert(hexas.end(), passedMesh.hexas.begin(), passedMesh.hexas.end());
276 for (unsigned i = numberOfHexas;
277 i < passedMesh.hexas.size() + numberOfHexas; ++i) {
278 for (unsigned d = 0; d < 8; ++d) {
279 hexas[i][d] += numberOfOldNodes;
280 }
281 }
282
283 // Append data
284 // TODO need to adjust lsVTKWriter to deal with different data correctly
285 // currently this only works for vertex only meshes
286 pointData.append(passedMesh.pointData);
287 cellData.append(passedMesh.cellData);
288
289 // if(lsPointData<T>::scalarData.size() < nodes.size())
290 for (unsigned i = 0; i < pointData.getScalarDataSize(); ++i) {
291 pointData.getScalarData(i)->resize(vertices.size());
292 }
293 for (unsigned i = 0; i < pointData.getVectorDataSize(); ++i) {
294 pointData.getVectorData(i)->resize(vertices.size());
295 }
296
297 for (unsigned i = 0; i < cellData.getScalarDataSize(); ++i) {
298 cellData.getScalarData(i)->resize(vertices.size());
299 }
300 for (unsigned i = 0; i < cellData.getVectorDataSize(); ++i) {
301 cellData.getVectorData(i)->resize(vertices.size());
302 }
303 }
304
305 void clear() {
306 nodes.clear();
307 vertices.clear();
308 lines.clear();
309 triangles.clear();
310 tetras.clear();
311 hexas.clear();
312 pointData.clear();
313 cellData.clear();
314 minimumExtent = Vec3D<T>{};
315 maximumExtent = Vec3D<T>{};
316 }
317
318 void print() {
319 std::cout << "Mesh:" << std::endl;
320 std::cout << "Number of Nodes: " << nodes.size() << std::endl;
321 if (!vertices.empty())
322 std::cout << "Number of Vertices: " << vertices.size() << std::endl;
323 if (!lines.empty())
324 std::cout << "Number of Lines: " << lines.size() << std::endl;
325 if (!triangles.empty())
326 std::cout << "Number of Triangles: " << triangles.size() << std::endl;
327 if (!tetras.empty())
328 std::cout << "Number of Tetrahedrons: " << tetras.size() << std::endl;
329 if (!hexas.empty())
330 std::cout << "Number of Hexas: " << hexas.size() << std::endl;
331 // pointData
332 if (pointData.getScalarDataSize() > 0) {
333 std::cout << "Scalar data:" << std::endl;
334 for (unsigned i = 0; i < pointData.getScalarDataSize(); ++i) {
335 std::cout << " \"" << pointData.getScalarDataLabel(i) << "\" of size "
336 << pointData.getScalarData(i)->size() << std::endl;
337 }
338 }
339 if (pointData.getVectorDataSize() > 0) {
340 std::cout << "Vector data:" << std::endl;
341 for (unsigned i = 0; i < pointData.getVectorDataSize(); ++i) {
342 std::cout << " \"" << pointData.getVectorDataLabel(i) << "\" of size "
343 << pointData.getVectorData(i)->size() << std::endl;
344 }
345 }
346
347 // cellData
348 if (cellData.getScalarDataSize() > 0) {
349 std::cout << "Scalar data:" << std::endl;
350 for (unsigned i = 0; i < cellData.getScalarDataSize(); ++i) {
351 std::cout << " \"" << cellData.getScalarDataLabel(i) << "\" of size "
352 << cellData.getScalarData(i)->size() << std::endl;
353 }
354 }
355 if (cellData.getVectorDataSize() > 0) {
356 std::cout << "Vector data:" << std::endl;
357 for (unsigned i = 0; i < cellData.getVectorDataSize(); ++i) {
358 std::cout << " \"" << cellData.getVectorDataLabel(i) << "\" of size "
359 << cellData.getVectorData(i)->size() << std::endl;
360 }
361 }
362 }
363};
364
365// add all template specialisations for this class
367
368} // namespace viennals
double T
Definition Epitaxy.cpp:13
This class holds an explicit mesh, which is always given in 3 dimensions. If it describes a 2D mesh,...
Definition lsMesh.hpp:25
PointData< T > pointData
Definition lsMesh.hpp:33
unsigned insertNextElement(const std::array< unsigned, 3 > &triangle)
Definition lsMesh.hpp:131
unsigned insertNextElement(const std::array< unsigned, 4 > &tetra)
Definition lsMesh.hpp:136
const PointData< T > & getPointData() const
Definition lsMesh.hpp:75
static constexpr const char * normalsLabel
Definition lsMesh.hpp:39
std::vector< std::array< unsigned, 8 > > hexas
Definition lsMesh.hpp:32
unsigned insertNextNode(const Vec3D< T > &node)
Definition lsMesh.hpp:91
void removeDuplicateNodes()
Remove exactly equal nodes, preserving first-occurrence order and the first node's scalar/vector poin...
Definition lsMesh.hpp:154
Vec3D< T > minimumExtent
Definition lsMesh.hpp:35
PointData< T > cellData
Definition lsMesh.hpp:34
std::vector< Vec3D< T > > & getNodes()
Definition lsMesh.hpp:46
std::vector< std::array< unsigned, 1 > > vertices
Definition lsMesh.hpp:28
static auto New()
Definition lsMesh.hpp:42
std::vector< std::array< unsigned, 2 > > lines
Definition lsMesh.hpp:29
unsigned insertNextTriangle(const std::array< unsigned, 3 > &triangle)
Definition lsMesh.hpp:106
std::vector< T > * getMaterialIds(const char *label=materialIdsLabel)
Definition lsMesh.hpp:87
unsigned insertNextHexa(const std::array< unsigned, 8 > &hexa)
Definition lsMesh.hpp:116
void print()
Definition lsMesh.hpp:318
Vec3D< T > maximumExtent
Definition lsMesh.hpp:36
std::vector< std::array< unsigned, 4 > > tetras
Definition lsMesh.hpp:31
std::vector< Vec3D< T > > nodes
Definition lsMesh.hpp:27
unsigned insertNextTetra(const std::array< unsigned, 4 > &tetra)
Definition lsMesh.hpp:111
void clear()
Definition lsMesh.hpp:305
const PointData< T > & getCellData() const
Definition lsMesh.hpp:79
std::vector< Vec3D< T > > * getNormals(const char *label=normalsLabel)
Definition lsMesh.hpp:82
unsigned insertNextElement(const std::array< unsigned, 1 > &vertex)
Definition lsMesh.hpp:121
static constexpr const char * materialIdsLabel
Definition lsMesh.hpp:38
PointData< T > & getPointData()
Definition lsMesh.hpp:73
void append(const Mesh< T > &passedMesh)
Definition lsMesh.hpp:230
PointData< T > & getCellData()
Definition lsMesh.hpp:77
const std::vector< Vec3D< T > > & getNodes() const
Definition lsMesh.hpp:44
unsigned insertNextElement(const std::array< unsigned, 2 > &line)
Definition lsMesh.hpp:126
std::vector< std::array< unsigned, 3 > > triangles
Definition lsMesh.hpp:30
unsigned insertNextVertex(const std::array< unsigned, 1 > &vertex)
Definition lsMesh.hpp:96
unsigned insertNextElement(const std::array< unsigned, 8 > &hexa)
Definition lsMesh.hpp:141
unsigned insertNextLine(const std::array< unsigned, 2 > &line)
Definition lsMesh.hpp:101
std::vector< std::array< unsigned, D > > & getElements()
Definition lsMesh.hpp:49
Definition lsAdvect.hpp:41
PRECOMPILE_PRECISION(Extrude)