preCICE
Loading...
Searching...
No Matches
Index.cpp
Go to the documentation of this file.
1#include <Eigen/Core>
2#include <algorithm>
3#include <boost/iterator/function_output_iterator.hpp>
4#include <boost/range/irange.hpp>
5#include <utility>
6
9#include "profiling/Event.hpp"
10#include "query/Index.hpp"
12
13namespace precice::query {
14
15precice::logging::Logger Index::_log{"query::Index"};
16
17namespace bg = boost::geometry;
18namespace bgi = boost::geometry::index;
19
24
31
44
46{
47 if (indices.vertexRTree) {
48 return indices.vertexRTree;
49 }
50
51 precice::profiling::Event e("query.index.getVertexIndexTree." + mesh.getName());
52
53 // Generating the rtree is expensive, so passing everything in the ctor is
54 // the best we can do. Even passing an index range instead of calling
55 // tree->insert repeatedly is about 10x faster.
57 VertexTraits::IndexGetter ind(mesh.vertices());
58 auto tree = std::make_shared<VertexTraits::RTree>(
59 boost::irange<std::size_t>(0lu, mesh.nVertices()), params, ind);
60
61 indices.vertexRTree = std::move(tree);
62 return indices.vertexRTree;
63}
64
66{
67 if (indices.edgeRTree) {
68 return indices.edgeRTree;
69 }
70
71 precice::profiling::Event e("query.index.getEdgeIndexTree." + mesh.getName());
72
73 // Generating the rtree is expensive, so passing everything in the ctor is
74 // the best we can do. Even passing an index range instead of calling
75 // tree->insert repeatedly is about 10x faster.
77 EdgeTraits::IndexGetter ind(mesh.edges());
78
79 auto tree = std::make_shared<EdgeTraits::RTree>(
80 boost::irange<std::size_t>(0lu, mesh.edges().size()), params, ind);
81
82 indices.edgeRTree = std::move(tree);
83 return indices.edgeRTree;
84}
85
87{
88 if (indices.triangleRTree) {
89 return indices.triangleRTree;
90 }
91
92 precice::profiling::Event e("query.index.getTriangleIndexTree." + mesh.getName());
93
94 // We first generate the values for the triangle rtree.
95 // The resulting vector is a random access range, which can be passed to the
96 // constructor of the rtree for more efficient indexing.
97 std::vector<TriangleTraits::IndexType> elements;
98 elements.reserve(mesh.triangles().size());
99 for (size_t i = 0; i < mesh.triangles().size(); ++i) {
100 auto box = bg::return_envelope<RTreeBox>(mesh.triangles()[i]);
101 elements.emplace_back(std::move(box), i);
102 }
103
104 // Generating the rtree is expensive, so passing everything in the ctor is
105 // the best we can do.
108
109 auto tree = std::make_shared<TriangleTraits::RTree>(elements, params, ind);
110 indices.triangleRTree = std::move(tree);
111 return indices.triangleRTree;
112}
113
115{
116 if (indices.tetraRTree) {
117 return indices.tetraRTree;
118 }
119
120 precice::profiling::Event e("query.index.getTetraIndexTree." + mesh.getName());
121
122 // We first generate the values for the tetra rtree.
123 // The resulting vector is a random access range, which can be passed to the
124 // constructor of the rtree for more efficient indexing.
125 std::vector<TetrahedronTraits::IndexType> elements;
126 elements.reserve(mesh.tetrahedra().size());
127 for (size_t i = 0; i < mesh.tetrahedra().size(); ++i) {
128 // We use a custom function to compute the AABB, because
129 // bg::return_envelope was designed for polygons.
130 auto box = makeBox(mesh.tetrahedra()[i]);
131 elements.emplace_back(std::move(box), i);
132 }
133
134 // Generating the rtree is expensive, so passing everything in the ctor is
135 // the best we can do.
138
139 auto tree = std::make_shared<TetrahedronTraits::RTree>(elements, params, ind);
140 indices.tetraRTree = std::move(tree);
141 return indices.tetraRTree;
142}
143
145{
146 indices.vertexRTree.reset();
147 indices.edgeRTree.reset();
148 indices.triangleRTree.reset();
149 indices.tetraRTree.reset();
150}
151
152//
153// query::Index
154//
155
157 : _mesh(mesh.get())
158{
159 _pimpl = std::make_unique<IndexImpl>(IndexImpl{});
160}
161
163 : _mesh(&mesh)
164{
165 _pimpl = std::make_unique<IndexImpl>(IndexImpl{});
166}
167
168// Required for the pimpl idiom to work with std::unique_ptr
169Index::~Index() = default;
170
171VertexMatch Index::getClosestVertex(const Eigen::VectorXd &sourceCoord)
172{
174
175 PRECICE_ASSERT(not _mesh->empty(), _mesh->getName());
176 VertexMatch match;
177 const auto &rtree = _pimpl->getVertexRTree(*_mesh);
178 rtree->query(bgi::nearest(sourceCoord, 1), boost::make_function_output_iterator([&](size_t matchID) {
179 match = VertexMatch(matchID);
180 }));
181 return match;
182}
183
184std::vector<VertexID> Index::getClosestVertices(const Eigen::VectorXd &sourceCoord, int n)
185{
187 PRECICE_ASSERT(!(_mesh->empty()), _mesh->getName());
188 std::vector<VertexID> matches;
189 const auto &rtree = _pimpl->getVertexRTree(*_mesh);
190
191 rtree->query(bgi::nearest(sourceCoord, n), boost::make_function_output_iterator([&](size_t matchID) {
192 matches.emplace_back(matchID);
193 }));
194 return matches;
195}
196
197std::vector<EdgeMatch> Index::getClosestEdges(const Eigen::VectorXd &sourceCoord, int n)
198{
200
201 const auto &rtree = _pimpl->getEdgeRTree(*_mesh);
202
203 std::vector<EdgeMatch> matches;
204 matches.reserve(n);
205 rtree->query(bgi::nearest(sourceCoord, n), boost::make_function_output_iterator([&](size_t matchID) {
206 matches.emplace_back(matchID);
207 }));
208 return matches;
209}
210
211std::vector<TriangleMatch> Index::getClosestTriangles(const Eigen::VectorXd &sourceCoord, int n)
212{
214 const auto &rtree = _pimpl->getTriangleRTree(*_mesh);
215
216 std::vector<TriangleMatch> matches;
217 matches.reserve(n);
218 rtree->query(bgi::nearest(sourceCoord, n),
219 boost::make_function_output_iterator([&](TriangleTraits::IndexType const &match) {
220 matches.emplace_back(match.second);
221 }));
222 return matches;
223}
224
225std::vector<VertexID> Index::getVerticesInsideBox(const mesh::Vertex &centerVertex, double radius)
226{
228
229 // Prepare boost::geometry box
230 auto coords = centerVertex.getCoords();
231 auto searchBox = query::makeBox(coords.array() - radius, coords.array() + radius);
232
233 const auto &rtree = _pimpl->getVertexRTree(*_mesh);
234 std::vector<VertexID> matches;
235 rtree->query(bgi::intersects(searchBox) and bg::index::satisfies([&](size_t const i) { return bg::distance(centerVertex, _mesh->vertex(i)) < radius; }),
236 std::back_inserter(matches));
237 return matches;
238}
239
240bool Index::isAnyVertexInsideBox(const mesh::Vertex &centerVertex, double radius)
241{
243
244 // Prepare boost::geometry box
245 auto coords = centerVertex.getCoords();
246 auto searchBox = query::makeBox(coords.array() - radius, coords.array() + radius);
247
248 const auto &rtree = _pimpl->getVertexRTree(*_mesh);
249
250 auto queryIter = rtree->qbegin(bgi::intersects(searchBox) and bg::index::satisfies([&](size_t const i) { return bg::distance(centerVertex, _mesh->vertex(i)) < radius; }));
251 bool hasMatch = queryIter != rtree->qend();
252 return hasMatch;
253}
254
255std::vector<VertexID> Index::getVerticesInsideBox(const mesh::BoundingBox &bb)
256{
258 // Add tree to the local cache
259 const auto &rtree = _pimpl->getVertexRTree(*_mesh);
260 std::vector<VertexID> matches;
261 rtree->query(bgi::intersects(query::makeBox(bb.minCorner(), bb.maxCorner())), std::back_inserter(matches));
262 return matches;
263}
264
265std::vector<TetrahedronID> Index::getEnclosingTetrahedra(const Eigen::VectorXd &location)
266{
268 const auto &rtree = _pimpl->getTetraRTree(*_mesh);
269
270 std::vector<TetrahedronID> matches;
271 rtree->query(bgi::covers(location), boost::make_function_output_iterator([&](TetrahedronTraits::IndexType const &match) {
272 matches.emplace_back(match.second);
273 }));
274 return matches;
275}
276
277ProjectionMatch Index::findNearestProjection(const Eigen::VectorXd &location, int n)
278{
279 if (_mesh->getDimensions() == 2) {
280 return findEdgeProjection(location, n, findVertexProjection(location));
281 } else {
282 return findTriangleProjection(location, n, findVertexProjection(location));
283 }
284}
285
286ProjectionMatch Index::findCellOrProjection(const Eigen::VectorXd &location, int n)
287{
288 if (_mesh->getDimensions() == 2) {
289 auto matchedTriangles = getClosestTriangles(location, n);
290 for (const auto &match : matchedTriangles) {
291 auto polation = mapping::Polation(location, _mesh->triangles()[match.index]);
292 if (polation.isInterpolation()) {
293 return {std::move(polation)};
294 }
295 }
296
297 // If no triangle is found, fall-back on NP
298 return findNearestProjection(location, n);
299 } else {
300
301 // Find correct tetra, or fall back to NP
302 auto matchedTetra = getEnclosingTetrahedra(location);
303 for (const auto &match : matchedTetra) {
304 // Matches are raw indices, not (indices, distance) pairs
305 auto polation = mapping::Polation(location, _mesh->tetrahedra()[match]);
306 if (polation.isInterpolation()) {
307 return {std::move(polation)};
308 }
309 }
310 return findNearestProjection(location, n);
311 }
312}
313
314ProjectionMatch Index::findVertexProjection(const Eigen::VectorXd &location)
315{
316 auto match = getClosestVertex(location);
317 return {mapping::Polation{location, _mesh->vertex(match.index)}};
318}
319
320ProjectionMatch Index::findEdgeProjection(const Eigen::VectorXd &location, int n, ProjectionMatch closestVertex)
321{
322 std::vector<ProjectionMatch> candidates;
323 candidates.reserve(n);
324 for (const auto &match : getClosestEdges(location, n)) {
325 auto polation = mapping::Polation(location, _mesh->edges()[match.index]);
326 if (polation.isInterpolation()) {
327 candidates.emplace_back(std::move(polation));
328 }
329 }
330
331 // Could not find edge projection element, fall back to vertex projection
332 if (candidates.empty()) {
333 return closestVertex;
334 }
335
336 // Prefer the closest vertex if it closer than the closest edge
337 auto min = std::min_element(candidates.begin(), candidates.end());
338 if (min->polation.distance() > closestVertex.polation.distance()) {
339 return closestVertex;
340 }
341 return *min;
342}
343
344ProjectionMatch Index::findTriangleProjection(const Eigen::VectorXd &location, int n, ProjectionMatch closestVertex)
345{
346 std::vector<ProjectionMatch> candidates;
347 candidates.reserve(n);
348 for (const auto &match : getClosestTriangles(location, n)) {
349 auto polation = mapping::Polation(location, _mesh->triangles()[match.index]);
350 if (polation.isInterpolation()) {
351 candidates.emplace_back(std::move(polation));
352 }
353 }
354
355 // Could not find triangle projection element, fall back to edge projection
356 if (candidates.empty()) {
357 return findEdgeProjection(location, n, std::move(closestVertex));
358 }
359
360 // Fallback to edge projection if a vertex is closer than the best triangle match
361 auto min = std::min_element(candidates.begin(), candidates.end());
362 if (min->polation.distance() > closestVertex.polation.distance()) {
363 return findEdgeProjection(location, n, std::move(closestVertex));
364 }
365
366 return *min;
367}
368
370{
372 // if the mesh is empty, we will most likely hit an assertion in the bounding box class
373 // therefore, we keep the assert here, but might want to return an empty bounding box in case
374 // we want to allow calling this function with empty meshes
375 PRECICE_ASSERT(_mesh->nVertices() > 0);
376
377 auto rtreeBox = _pimpl->getVertexRTree(*_mesh)->bounds();
378 int dim = _mesh->getDimensions();
379 Eigen::VectorXd min(dim), max(dim);
380
381 min[0] = rtreeBox.min_corner().get<0>();
382 min[1] = rtreeBox.min_corner().get<1>();
383 max[0] = rtreeBox.max_corner().get<0>();
384 max[1] = rtreeBox.max_corner().get<1>();
385
386 if (dim > 2) {
387 min[2] = rtreeBox.min_corner().get<2>();
388 max[2] = rtreeBox.max_corner().get<2>();
389 }
390 return mesh::BoundingBox{min, max};
391}
392
394{
395 _pimpl->clear();
396}
397
398} // namespace precice::query
#define PRECICE_TRACE(...)
Definition LogMacros.hpp:92
#define PRECICE_ASSERT(...)
Definition assertion.hpp:85
Calculates the barycentric coordinates of a coordinate on the given vertex/edge/triangle and stores t...
Definition Polation.hpp:23
double distance() const
Returns the projection distance.
Definition Polation.cpp:97
An axis-aligned bounding box around a (partition of a) mesh.
Eigen::VectorXd maxCorner() const
the max corner of the bounding box
Eigen::VectorXd minCorner() const
the min corner of the bounding box
Container and creator for meshes.
Definition Mesh.hpp:38
Vertex of a mesh.
Definition Vertex.hpp:16
Eigen::VectorXd getCoords() const
Returns the coordinates of the vertex.
Definition Vertex.hpp:114
VertexTraits::Ptr getVertexRTree(const mesh::Mesh &mesh)
Definition Index.cpp:45
TetrahedronTraits::Ptr getTetraRTree(const mesh::Mesh &mesh)
Definition Index.cpp:114
TriangleTraits::Ptr getTriangleRTree(const mesh::Mesh &mesh)
Definition Index.cpp:86
EdgeTraits::Ptr getEdgeRTree(const mesh::Mesh &mesh)
Definition Index.cpp:65
mesh::BoundingBox getRtreeBounds()
Definition Index.cpp:369
std::vector< TetrahedronID > getEnclosingTetrahedra(const Eigen::VectorXd &location)
Return all the tetrahedra whose axis-aligned bounding box contains a vertex.
Definition Index.cpp:265
mesh::Mesh * _mesh
The indexed Mesh.
Definition Index.hpp:120
ProjectionMatch findCellOrProjection(const Eigen::VectorXd &location, int n)
Definition Index.cpp:286
VertexMatch getClosestVertex(const Eigen::VectorXd &sourceCoord)
Get the closest vertex to the given vertex.
Definition Index.cpp:171
ProjectionMatch findNearestProjection(const Eigen::VectorXd &location, int n)
Find the closest interpolation element to the given location. If exists, triangle or edge projection ...
Definition Index.cpp:277
bool isAnyVertexInsideBox(const mesh::Vertex &centerVertex, double radius)
Returns.
Definition Index.cpp:240
std::unique_ptr< IndexImpl > _pimpl
Definition Index.hpp:117
std::vector< TriangleMatch > getClosestTriangles(const Eigen::VectorXd &sourceCoord, int n)
Get n number of closest triangles to the given vertex.
Definition Index.cpp:211
std::vector< VertexID > getVerticesInsideBox(const mesh::Vertex &centerVertex, double radius)
Return all the vertices inside the box formed by vertex and radius (boundary exclusive)
Definition Index.cpp:225
void clear()
Clear the index.
Definition Index.cpp:393
ProjectionMatch findEdgeProjection(const Eigen::VectorXd &location, int n, ProjectionMatch closestVertex)
Find closest edge interpolation element. If cannot be found, it falls back to vertex projection.
Definition Index.cpp:320
ProjectionMatch findVertexProjection(const Eigen::VectorXd &location)
Closest vertex projection element is always the nearest neighbor.
Definition Index.cpp:314
Index(mesh::PtrMesh mesh)
Definition Index.cpp:156
std::vector< VertexID > getClosestVertices(const Eigen::VectorXd &sourceCoord, int n)
Get n number of closest vertices to the given vertex.
Definition Index.cpp:184
ProjectionMatch findTriangleProjection(const Eigen::VectorXd &location, int n, ProjectionMatch closestVertex)
Find closest face interpolation element. If cannot be found, it falls back to first edge interpolatio...
Definition Index.cpp:344
std::vector< EdgeMatch > getClosestEdges(const Eigen::VectorXd &sourceCoord, int n)
Get n number of closest edges to the given vertex.
Definition Index.cpp:197
static precice::logging::Logger _log
Definition Index.hpp:122
provides Mesh, Data and primitives.
std::shared_ptr< Mesh > PtrMesh
boost::geometry::index::rstar< 16 > RTreeParameters
The general rtree parameter type used in precice.
contains geometrical queries.
impl::RTreeTraits< mesh::Edge > EdgeTraits
Definition Index.cpp:21
RTreeBox makeBox(const pm::Vertex::RawCoords &min, const pm::Vertex::RawCoords &max)
impl::RTreeTraits< mesh::Vertex > VertexTraits
Definition Index.cpp:20
impl::RTreeTraits< mesh::Triangle > TriangleTraits
Definition Index.cpp:22
impl::RTreeTraits< mesh::Tetrahedron > TetrahedronTraits
Definition Index.cpp:23
MatchType< struct VertexMatchTag > VertexMatch
Definition Index.hpp:38
constexpr auto get(span< E, S > s) -> decltype(s[N])
Definition span.hpp:602
VertexTraits::Ptr vertexRTree
Definition Index.cpp:26
EdgeTraits::Ptr edgeRTree
Definition Index.cpp:27
TetrahedronTraits::Ptr tetraRTree
Definition Index.cpp:29
TriangleTraits::Ptr triangleRTree
Definition Index.cpp:28
Struct representing a projection match.
Definition Index.hpp:44
mapping::Polation polation
Definition Index.hpp:55
The type traits of a rtree based on a Primitive.
typename std::conditional< IsDirectIndexable< mesh::Triangle >::value, MeshContainerIndex, std::pair< RTreeBox, MeshContainerIndex > >::type IndexType
typename std::conditional< IsDirectIndexable< mesh::Vertex >::value, impl::VectorIndexable< MeshContainer >, boost::geometry::index::indexable< IndexType > >::type IndexGetter