preCICE
Loading...
Searching...
No Matches
Mesh.cpp
Go to the documentation of this file.
1#include <Eigen/Core>
2#include <algorithm>
3#include <array>
4#include <boost/container/flat_map.hpp>
5#include <functional>
6#include <memory>
7#include <ostream>
8#include <type_traits>
9#include <utility>
10#include <vector>
11
12#include "Edge.hpp"
13#include "Mesh.hpp"
14#include "Tetrahedron.hpp"
15#include "Triangle.hpp"
16#include "logging/LogMacros.hpp"
17#include "math/geometry.hpp"
18#include "mesh/Data.hpp"
19#include "mesh/Vertex.hpp"
21#include "query/Index.hpp"
22#include "utils/assertion.hpp"
23
24namespace precice::mesh {
25
27 std::string name,
28 int dimensions,
29 MeshID id,
30 bool isJustInTime)
31 : _name(std::move(name)),
32 _dimensions(dimensions),
33 _id(id),
35 _boundingBox(dimensions),
36 _index(*this)
37{
39 PRECICE_ASSERT(_name != std::string(""));
40}
41
43{
45 return _vertices.at(id);
46}
47
49{
51 return _vertices.at(id);
52}
53
58
60{
61 return _vertices;
62}
63
64std::size_t Mesh::nVertices() const
65{
66 return _vertices.size();
67}
68
73
75{
76 return _edges;
77}
78
83
85{
86 return _triangles;
87}
88
90{
91 return _tetrahedra;
92}
93
98
100{
101 return _dimensions;
102}
103
104Vertex &Mesh::createVertex(const Eigen::Ref<const Eigen::VectorXd> &coords)
105{
106 PRECICE_ASSERT(coords.size() == _dimensions, coords.size(), _dimensions);
107 auto nextID = _vertices.size();
108 _vertices.emplace_back(coords, nextID);
109 return _vertices.back();
110}
111
113 Vertex &vertexOne,
114 Vertex &vertexTwo)
115{
116 _edges.emplace_back(vertexOne, vertexTwo);
117 return _edges.back();
118}
119
121 Edge &edgeOne,
122 Edge &edgeTwo,
123 Edge &edgeThree)
124{
126 edgeOne.connectedTo(edgeTwo) &&
127 edgeTwo.connectedTo(edgeThree) &&
128 edgeThree.connectedTo(edgeOne));
129 _triangles.emplace_back(edgeOne, edgeTwo, edgeThree);
130 return _triangles.back();
131}
132
134 Vertex &vertexOne,
135 Vertex &vertexTwo,
136 Vertex &vertexThree)
137{
138 _triangles.emplace_back(vertexOne, vertexTwo, vertexThree);
139 return _triangles.back();
140}
141
143 Vertex &vertexOne,
144 Vertex &vertexTwo,
145 Vertex &vertexThree,
146 Vertex &vertexFour)
147{
148 _tetrahedra.emplace_back(vertexOne, vertexTwo, vertexThree, vertexFour);
149 return _tetrahedra.back();
150}
151
153 const std::string &name,
154 int dimension,
155 DataID id,
156 int waveformDegree)
157{
158 PRECICE_TRACE(name, dimension);
159 for (const PtrData &data : _data) {
160 PRECICE_CHECK(data->getName() != name,
161 "Data \"{}\" cannot be created twice for mesh \"{}\". "
162 "Please rename or remove one of the use-data tags with name \"{}\".",
163 name, _name, name);
164 }
165 // #rows = dimensions of current mesh #columns = dimensions of corresponding data set
166 std::vector<std::optional<double>> lowerBound = std::vector<std::optional<double>>(dimension);
167 std::vector<std::optional<double>> upperBound = std::vector<std::optional<double>>(dimension);
168 PtrData data(new Data(name, id, dimension, _dimensions, waveformDegree, lowerBound, upperBound));
169 _data.push_back(data);
170 return _data.back();
171}
172
174 const std::string &name,
175 int dimension,
176 DataID id,
177 int waveformDegree,
178 std::vector<std::optional<double>> lowerBound,
179 std::vector<std::optional<double>> upperBound)
180{
181 PRECICE_TRACE(name, dimension);
182 for (const PtrData &data : _data) {
183 PRECICE_CHECK(data->getName() != name,
184 "Data \"{}\" cannot be created twice for mesh \"{}\". "
185 "Please rename or remove one of the use-data tags with name \"{}\".",
186 name, _name, name);
187 }
188 // #rows = dimensions of current mesh #columns = dimensions of corresponding data set
189 PtrData data(new Data(name, id, dimension, _dimensions, waveformDegree, lowerBound, upperBound));
190 _data.push_back(data);
191 return _data.back();
192}
193
195{
196 return _data;
197}
198
199bool Mesh::hasDataID(DataID dataID) const
200{
201 auto iter = std::find_if(_data.begin(), _data.end(), [dataID](const auto &dptr) {
202 return dptr->getID() == dataID;
203 });
204 return iter != _data.end(); // if id was not found in mesh, iter == _data.end()
205}
206
207const PtrData &Mesh::data(DataID dataID) const
208{
209 auto iter = std::find_if(_data.begin(), _data.end(), [dataID](const auto &dptr) {
210 return dptr->getID() == dataID;
211 });
212 PRECICE_ASSERT(iter != _data.end(), "Data with id not found in mesh.", dataID, _name);
213 return *iter;
214}
215
216bool Mesh::hasDataName(std::string_view dataName) const
217{
218 auto iter = std::find_if(_data.begin(), _data.end(), [&dataName](const auto &dptr) {
219 return dptr->getName() == dataName;
220 });
221 return iter != _data.end(); // if name was not found in mesh, iter == _data.end()
222}
223
224std::vector<std::string> Mesh::availableData() const
225{
226 std::vector<std::string> names;
227 for (const auto &data : _data) {
228 names.push_back(data->getName());
229 }
230 return names;
231}
232
233const PtrData &Mesh::data(std::string_view dataName) const
234{
235 auto iter = std::find_if(_data.begin(), _data.end(), [&dataName](const auto &dptr) {
236 return dptr->getName() == dataName;
237 });
238 PRECICE_ASSERT(iter != _data.end(), "Data not found in mesh", dataName, _name);
239 return *iter;
240}
241
242const std::string &Mesh::getName() const
243{
244 return _name;
245}
246
248{
249 return _id;
250}
251
252bool Mesh::isValidVertexID(VertexID vertexID) const
253{
254 return (0 <= vertexID) && (static_cast<size_t>(vertexID) < nVertices());
255}
256
258{
259 PRECICE_TRACE(_vertices.size());
260 const auto expectedCount = _vertices.size();
261 for (PtrData &data : _data) {
262 data->allocateValues(expectedCount);
263 }
264}
265
267{
269
270 // Keep the bounding box if set via the API function.
272
273 for (const Vertex &vertex : _vertices) {
274 bb.expandBy(vertex);
275 }
276 _boundingBox = std::move(bb);
277 PRECICE_DEBUG("Bounding Box, {}", _boundingBox);
278}
279
281{
282 _triangles.clear();
283 _edges.clear();
284 _vertices.clear();
285 _tetrahedra.clear();
286 _index.clear();
287
289 for (mesh::PtrData &data : _data) {
290 data->values().resize(0);
291 }
292}
293
296{
297 _connectedRanks.clear();
298 _communicationMap.clear();
299 _vertexDistribution.clear();
300 _vertexOffsets.clear();
302}
303
305{
306 for (mesh::PtrData &data : _data) {
307 data->waveform().clear();
308 }
309}
310
312{
313 // Without offset data, we assume non-empty partitions
314 if (_vertexOffsets.empty()) {
315 return false;
316 }
317 PRECICE_ASSERT(_vertexOffsets.size() >= static_cast<std::size_t>(rank));
318 if (rank == 0) {
319 return _vertexOffsets[0] == 0;
320 }
321 return _vertexOffsets[rank] - _vertexOffsets[rank - 1] == 0;
322}
323
324Eigen::VectorXd Mesh::getOwnedVertexData(const Eigen::VectorXd &values)
325{
326 std::vector<double> ownedDataVector;
327 PRECICE_ASSERT(static_cast<std::size_t>(values.size()) >= nVertices());
328 if (empty()) {
329 return {};
330 }
331 int valueDim = values.size() / nVertices();
332 int index = 0;
333
334 for (const auto &vertex : vertices()) {
335 if (vertex.isOwner()) {
336 for (int dim = 0; dim < valueDim; ++dim) {
337 ownedDataVector.push_back(values[index * valueDim + dim]);
338 }
339 }
340 ++index;
341 }
342 Eigen::Map<Eigen::VectorXd> ownedData(ownedDataVector.data(), ownedDataVector.size());
343
344 return ownedData;
345}
346
348{
349 for (auto &vertex : _vertices) {
350 vertex.tag();
351 }
352}
353
355 Mesh &deltaMesh)
356{
359
360 boost::container::flat_map<VertexID, Vertex *> vertexMap;
361 vertexMap.reserve(deltaMesh.nVertices());
362 Eigen::VectorXd coords(_dimensions);
363 for (const Vertex &vertex : deltaMesh.vertices()) {
364 coords = vertex.getCoords();
365 Vertex &v = createVertex(coords);
366 v.setGlobalIndex(vertex.getGlobalIndex());
367 if (vertex.isTagged())
368 v.tag();
369 v.setOwner(vertex.isOwner());
370 PRECICE_ASSERT(vertex.getID() >= 0, vertex.getID());
371 vertexMap[vertex.getID()] = &v;
372 }
373
374 // you cannot just take the vertices from the edge and add them,
375 // since you need the vertices from the new mesh
376 // (which may differ in IDs)
377 for (const Edge &edge : deltaMesh.edges()) {
378 VertexID vertexIndex1 = edge.vertex(0).getID();
379 VertexID vertexIndex2 = edge.vertex(1).getID();
380 PRECICE_ASSERT((vertexMap.count(vertexIndex1) == 1) &&
381 (vertexMap.count(vertexIndex2) == 1));
382 createEdge(*vertexMap[vertexIndex1], *vertexMap[vertexIndex2]);
383 }
384
385 for (const Triangle &triangle : deltaMesh.triangles()) {
386 VertexID vertexIndex1 = triangle.vertex(0).getID();
387 VertexID vertexIndex2 = triangle.vertex(1).getID();
388 VertexID vertexIndex3 = triangle.vertex(2).getID();
389 PRECICE_ASSERT((vertexMap.count(vertexIndex1) == 1) &&
390 (vertexMap.count(vertexIndex2) == 1) &&
391 (vertexMap.count(vertexIndex3) == 1));
392 createTriangle(*vertexMap[vertexIndex1], *vertexMap[vertexIndex2], *vertexMap[vertexIndex3]);
393 }
394
395 for (const Tetrahedron &tetra : deltaMesh.tetrahedra()) {
396 VertexID vertexIndex1 = tetra.vertex(0).getID();
397 VertexID vertexIndex2 = tetra.vertex(1).getID();
398 VertexID vertexIndex3 = tetra.vertex(2).getID();
399 VertexID vertexIndex4 = tetra.vertex(3).getID();
400
401 PRECICE_ASSERT((vertexMap.count(vertexIndex1) == 1) &&
402 (vertexMap.count(vertexIndex2) == 1) &&
403 (vertexMap.count(vertexIndex3) == 1) &&
404 (vertexMap.count(vertexIndex4) == 1));
405 createTetrahedron(*vertexMap[vertexIndex1], *vertexMap[vertexIndex2], *vertexMap[vertexIndex3], *vertexMap[vertexIndex4]);
406 }
407 _index.clear();
408}
409
411{
412 return _boundingBox;
413}
414
415void Mesh::expandBoundingBox(const BoundingBox &boundingBox)
416{
417 _boundingBox.expandBy(boundingBox);
418}
419
425
427{
428 // Remove duplicate tetrahedra
429 auto tetrahedraCnt = _tetrahedra.size();
430 std::sort(_tetrahedra.begin(), _tetrahedra.end());
431 auto lastTetrahedron = std::unique(_tetrahedra.begin(), _tetrahedra.end());
432 _tetrahedra = TetraContainer{_tetrahedra.begin(), lastTetrahedron};
433
434 // Remove duplicate triangles
435 auto triangleCnt = _triangles.size();
436 std::sort(_triangles.begin(), _triangles.end());
437 auto lastTriangle = std::unique(_triangles.begin(), _triangles.end());
438 _triangles = TriangleContainer{_triangles.begin(), lastTriangle};
439
440 // Remove duplicate edges
441 auto edgeCnt = _edges.size();
442 std::sort(_edges.begin(), _edges.end());
443 auto lastEdge = std::unique(_edges.begin(), _edges.end());
444 _edges = EdgeContainer{_edges.begin(), lastEdge};
445
446 PRECICE_DEBUG("Compression removed {} tetrahedra ({} to {}), {} triangles ({} to {}), and {} edges ({} to {})",
447 tetrahedraCnt - _tetrahedra.size(), tetrahedraCnt, _tetrahedra.size(),
448 triangleCnt - _triangles.size(), triangleCnt, _triangles.size(),
449 edgeCnt - _edges.size(), edgeCnt, _edges.size());
450}
451
452namespace {
453
454template <class Primitive, int... Indices>
455auto sortedVertexPtrsForImpl(Primitive &p, std::integer_sequence<int, Indices...>)
456{
457 std::array<Vertex *, Primitive::vertexCount> vs{&p.vertex(Indices)...};
458 std::sort(vs.begin(), vs.end());
459 return std::tuple_cat(vs);
460}
461
470template <class Primitive>
471auto sortedVertexPtrsFor(Primitive &p)
472{
473 return sortedVertexPtrsForImpl(p, std::make_integer_sequence<int, Primitive::vertexCount>{});
474}
475} // namespace
476
478{
479 if (_triangles.empty() && _tetrahedra.empty()) {
480 PRECICE_DEBUG("No implicit primitives required");
481 return; // no implicit primitives
482 }
483
484 // count explicit primitives for debug
485 const auto explTriangles = _triangles.size();
486 const auto explEdges = _triangles.size();
487
488 // First handle all explicit tetrahedra
489
490 // Build a set of all explicit triangles
491 using ExisitingTriangle = std::tuple<Vertex *, Vertex *, Vertex *>;
492 std::set<ExisitingTriangle> triangles;
493 for (auto &t : _triangles) {
494 triangles.insert(sortedVertexPtrsFor(t));
495 }
496
497 // Generate all missing implicit triangles of explicit tetrahedra
498 // Update the triangles set used by the implicit edge generation
499 auto createTriangleIfMissing = [&](Vertex *a, Vertex *b, Vertex *c) {
500 if (triangles.count({a, b, c}) == 0) {
501 triangles.emplace(a, b, c);
502 createTriangle(*a, *b, *c);
503 };
504 };
505 for (auto &t : _tetrahedra) {
506 auto [a, b, c, d] = sortedVertexPtrsFor(t);
507 // Make sure these are in the same order as above
508 createTriangleIfMissing(a, b, c);
509 createTriangleIfMissing(a, b, d);
510 createTriangleIfMissing(a, c, d);
511 createTriangleIfMissing(b, c, d);
512 }
513
514 // Second handle all triangles, both explicit and implicit from the tetrahedron phase
515 // Build an set of all explicit triangles
516 using ExisitingEdge = std::tuple<Vertex *, Vertex *>;
517 std::set<ExisitingEdge> edges;
518 for (auto &e : _edges) {
519 edges.emplace(sortedVertexPtrsFor(e));
520 }
521
522 // generate all missing implicit edges of implicit and explicit triangles
523 auto createEdgeIfMissing = [&](Vertex *a, Vertex *b) {
524 if (edges.count({a, b}) == 0) {
525 edges.emplace(a, b);
526 createEdge(*a, *b);
527 };
528 };
529 for (auto &t : _triangles) {
530 auto [a, b, c] = sortedVertexPtrsFor(t);
531 // Make sure these are in the same order as above
532 createEdgeIfMissing(a, b);
533 createEdgeIfMissing(a, c);
534 createEdgeIfMissing(b, c);
535 }
536
537 PRECICE_DEBUG("Generated {} implicit triangles and {} implicit edges",
538 _triangles.size() - explTriangles,
539 _edges.size() - explEdges);
540}
541
542bool Mesh::operator==(const Mesh &other) const
543{
544 bool equal = true;
545 equal &= _vertices.size() == other._vertices.size() &&
546 std::is_permutation(_vertices.begin(), _vertices.end(), other._vertices.begin());
547 equal &= _edges.size() == other._edges.size() &&
548 std::is_permutation(_edges.begin(), _edges.end(), other._edges.begin());
549 equal &= _triangles.size() == other._triangles.size() &&
550 std::is_permutation(_triangles.begin(), _triangles.end(), other._triangles.begin());
551 return equal;
552}
553
554bool Mesh::operator!=(const Mesh &other) const
555{
556 return !(*this == other);
557}
558
559std::ostream &operator<<(std::ostream &os, const Mesh &m)
560{
561 os << "Mesh \"" << m.getName() << "\", dimensionality = " << m.getDimensions() << ":\n";
562 os << "GEOMETRYCOLLECTION(\n";
563 const auto token = ", ";
564 const auto *sep = "";
565 for (auto &vertex : m.vertices()) {
566 os << sep << vertex;
567 sep = token;
568 }
569 sep = ",\n";
570 for (auto &edge : m.edges()) {
571 os << sep << edge;
572 sep = token;
573 }
574 sep = ",\n";
575 for (auto &triangle : m.triangles()) {
576 os << sep << triangle;
577 sep = token;
578 }
579 os << "\n)";
580 return os;
581}
582
583} // namespace precice::mesh
#define PRECICE_DEBUG(...)
Definition LogMacros.hpp:61
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:92
#define PRECICE_CHECK(check,...)
Definition LogMacros.hpp:32
#define PRECICE_ASSERT(...)
Definition assertion.hpp:85
An axis-aligned bounding box around a (partition of a) mesh.
void expandBy(const BoundingBox &otherBB)
Expand bounding box using another bounding box.
Describes a set of data values belonging to the vertices of a mesh.
Definition Data.hpp:26
Linear edge of a mesh, defined by two Vertex objects.
Definition Edge.hpp:15
bool connectedTo(const Edge &other) const
Checks whether both edges share a vertex.
Definition Edge.cpp:39
Container and creator for meshes.
Definition Mesh.hpp:38
void expandBoundingBox(const BoundingBox &bounding_box)
Definition Mesh.cpp:415
Triangle & createTriangle(Edge &edgeOne, Edge &edgeTwo, Edge &edgeThree)
Creates and initializes a Triangle object.
Definition Mesh.cpp:120
MeshID _id
The ID of this mesh.
Definition Mesh.hpp:365
MeshID getID() const
Returns the base ID of the mesh.
Definition Mesh.cpp:247
std::string _name
Name of the mesh.
Definition Mesh.hpp:359
BoundingBox _boundingBox
Definition Mesh.hpp:412
std::deque< Triangle > TriangleContainer
Definition Mesh.hpp:42
int _globalNumberOfVertices
Number of unique vertices for complete distributed mesh.
Definition Mesh.hpp:395
int getDimensions() const
Definition Mesh.cpp:99
VertexContainer & vertices()
Returns modifieable container holding all vertices.
Definition Mesh.cpp:54
void clearDataStamples()
Clears all data stamples.
Definition Mesh.cpp:304
std::vector< PtrData > DataContainer
Definition Mesh.hpp:44
bool hasDataID(DataID dataID) const
Returns whether Mesh has Data with the matchingID.
Definition Mesh.cpp:199
Eigen::VectorXd getOwnedVertexData(const Eigen::VectorXd &values)
Definition Mesh.cpp:324
void clear()
Removes all mesh elements and data values (does not remove data or the bounding boxes).
Definition Mesh.cpp:280
DataContainer _data
Data hold by the vertices of the mesh.
Definition Mesh.hpp:374
void addMesh(Mesh &deltaMesh)
Definition Mesh.cpp:354
bool operator!=(const Mesh &other) const
Definition Mesh.cpp:554
std::vector< std::string > availableData() const
Returns the names of all available data.
Definition Mesh.cpp:224
const std::string & getName() const
Returns the name of the mesh, as set in the config file.
Definition Mesh.cpp:242
void removeDuplicates()
Removes all duplicate connectivity.
Definition Mesh.cpp:426
std::size_t nVertices() const
Returns the number of vertices.
Definition Mesh.cpp:64
VertexDistribution _vertexDistribution
Vertex distribution for the primary rank, holding for each secondary rank all vertex IDs it owns.
Definition Mesh.hpp:381
TetraContainer & tetrahedra()
Returns modifiable container holding all tetrahedra.
Definition Mesh.cpp:94
std::deque< Tetrahedron > TetraContainer
Definition Mesh.hpp:43
bool operator==(const Mesh &other) const
Definition Mesh.cpp:542
std::vector< Rank > _connectedRanks
each rank stores list of connected remote ranks. In the m2n package, this is used to create the initi...
Definition Mesh.hpp:401
bool _isJustInTime
for just-in-time mapping, we need an artificial mesh, which we can use
Definition Mesh.hpp:410
TetraContainer _tetrahedra
Definition Mesh.hpp:371
Vertex & vertex(VertexID id)
Mutable access to a vertex by VertexID.
Definition Mesh.cpp:42
bool isJustInTime() const
Definition Mesh.hpp:340
Mesh(std::string name, int dimensions, MeshID id, bool isJustInTime=false)
Constructor.
Definition Mesh.cpp:26
const query::Index & index() const
Call preprocess() before index() to ensure correct projection handling.
Definition Mesh.hpp:329
query::Index _index
Definition Mesh.hpp:414
VertexContainer _vertices
Holds vertices, edges, triangles and tetrahedra.
Definition Mesh.hpp:368
bool hasDataName(std::string_view dataName) const
Returns whether Mesh has Data with the dataName.
Definition Mesh.cpp:216
std::deque< Edge > EdgeContainer
Definition Mesh.hpp:41
PtrData & createData(const std::string &name, int dimension, DataID id, int waveformDegree=time::Time::DEFAULT_WAVEFORM_DEGREE)
Create only data for vertex.
Definition Mesh.cpp:152
CommunicationMap _communicationMap
each rank stores list of connected ranks and corresponding vertex IDs here. In the m2n package,...
Definition Mesh.hpp:407
bool empty() const
Does the mesh contain any vertices?
Definition Mesh.hpp:88
void generateImplictPrimitives()
Definition Mesh.cpp:477
void clearPartitioning()
Clears the partitioning information.
Definition Mesh.cpp:295
void computeBoundingBox()
Computes the boundingBox for the vertices.
Definition Mesh.cpp:266
TriangleContainer _triangles
Definition Mesh.hpp:370
bool isPartitionEmpty(Rank rank) const
checks if the given ranks partition is empty
Definition Mesh.cpp:311
Tetrahedron & createTetrahedron(Vertex &vertexOne, Vertex &vertexTwo, Vertex &vertexThree, Vertex &vertexFour)
Creates and initializes a Tetrahedron object.
Definition Mesh.cpp:142
VertexOffsets _vertexOffsets
Holds the index of the last vertex for each rank.
Definition Mesh.hpp:388
bool isValidVertexID(VertexID vertexID) const
Returns true if the given vertexID is valid.
Definition Mesh.cpp:252
EdgeContainer _edges
Definition Mesh.hpp:369
const DataContainer & data() const
Allows access to all data.
Definition Mesh.cpp:194
TriangleContainer & triangles()
Returns modifiable container holding all triangles.
Definition Mesh.cpp:79
const BoundingBox & getBoundingBox() const
Returns the bounding box of the mesh.
Definition Mesh.cpp:410
std::deque< Vertex > VertexContainer
Definition Mesh.hpp:40
Edge & createEdge(Vertex &vertexOne, Vertex &vertexTwo)
Creates and initializes an Edge object.
Definition Mesh.cpp:112
Vertex & createVertex(const Eigen::Ref< const Eigen::VectorXd > &coords)
Creates and initializes a Vertex object.
Definition Mesh.cpp:104
EdgeContainer & edges()
Returns modifiable container holding all edges.
Definition Mesh.cpp:69
void allocateDataValues()
Allocates memory for the vertex data values and corresponding gradient values.
Definition Mesh.cpp:257
int _dimensions
Dimension of mesh.
Definition Mesh.hpp:362
Tetrahedron of a mesh, defined by 4 vertices.
Triangle of a mesh, defined by three vertices.
Definition Triangle.hpp:24
Vertex of a mesh.
Definition Vertex.hpp:16
void setGlobalIndex(int globalIndex)
Definition Vertex.cpp:17
void setOwner(bool owner)
Definition Vertex.cpp:27
provides Mesh, Data and primitives.
std::shared_ptr< Data > PtrData
std::ostream & operator<<(std::ostream &os, const BoundingBox &bb)
int MeshID
Definition Types.hpp:30
int VertexID
Definition Types.hpp:13
int Rank
Definition Types.hpp:37
int DataID
Definition Types.hpp:25
STL namespace.