Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flatten data structures in geometry #2 #2359

Merged
merged 34 commits into from
Sep 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9927e10
flatten std::array<std::array 2>, 3>
SarahRo Aug 3, 2022
039828b
fix compile error
SarahRo Aug 3, 2022
5617d88
fix wrapper
SarahRo Aug 3, 2022
6bae2dc
try to fix compute_collisions
SarahRo Aug 3, 2022
313888e
geometry: flatten std::vector<std::array<int, 2>>
SarahRo Aug 4, 2022
6729eac
fix seg fault
SarahRo Aug 4, 2022
2447aee
simplify data structures
SarahRo Aug 5, 2022
e42d17c
Merge branch 'main' into sarah/geometry-flatten-data-structures
SarahRo Aug 9, 2022
b7792d6
apply suggestions from code review
SarahRo Aug 9, 2022
37e58d7
minor improvements
SarahRo Aug 9, 2022
9535595
Add more spans
jorgensd Aug 9, 2022
c2a4b33
Merge branch 'main' into sarah/geometry-flatten-data-structures
jorgensd Aug 24, 2022
e27cd38
Fix compile time constant sub spans
jorgensd Sep 7, 2022
0d4a4c8
Merge branch 'main' into sarah/geometry-flatten-data-structures
jorgensd Sep 7, 2022
059ae73
Subspan fixes
jorgensd Sep 7, 2022
0bf24e5
Apply suggestions from code review
jorgensd Sep 7, 2022
9f4a1aa
Apply suggestions from code review
jorgensd Sep 7, 2022
f1f24e7
Minor fix
jorgensd Sep 7, 2022
2667010
Improve readability
jorgensd Sep 7, 2022
06bef94
Remove comment
jorgensd Sep 7, 2022
d9e31f7
Sizes
jorgensd Sep 7, 2022
1ea3e8e
Remove span functions for copies
jorgensd Sep 7, 2022
88e4868
Remove spans, regression observed
jorgensd Sep 7, 2022
162d9ae
Merge branch 'main' into sarah/geometry-flatten-data-structures
jorgensd Sep 8, 2022
3925537
Fixes for pybind
jorgensd Sep 8, 2022
84f6202
Performance updates
jorgensd Sep 8, 2022
258824c
Remove copy bbox
jorgensd Sep 8, 2022
d8e0811
Fix docstring
garth-wells Sep 9, 2022
526ba8f
Simplifications
garth-wells Sep 9, 2022
38f1a2b
Simplifiations
garth-wells Sep 9, 2022
f2e755a
Merge branch 'main' into dokken/flatten-geometry-span-2
jorgensd Sep 9, 2022
3427084
Tidy up int types
garth-wells Sep 9, 2022
b37cb29
Merge branch 'main' into dokken/flatten-geometry-span-2
garth-wells Sep 9, 2022
3a486cd
Merge branch 'main' into dokken/flatten-geometry-span-2
garth-wells Sep 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 75 additions & 109 deletions cpp/dolfinx/geometry/BoundingBoxTree.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2013-2021 Chris N. Richardson, Anders Logg, Garth N. Wells and
// Jørgen S. Dokken
// Copyright (C) 2013-2022 Chris N. Richardson, Anders Logg, Garth N. Wells,
// Jørgen S. Dokken, Sarah Roggendorf
//
// This file is part of DOLFINx (https://www.fenicsproject.org)
//
Expand Down Expand Up @@ -33,9 +33,10 @@ std::vector<std::int32_t> range(const mesh::Mesh& mesh, int tdim)
return r;
}
//-----------------------------------------------------------------------------
// Compute bounding box of mesh entity
std::array<std::array<double, 3>, 2>
compute_bbox_of_entity(const mesh::Mesh& mesh, int dim, std::int32_t index)
// Compute bounding box of mesh entity. The bounding box is defined by (lower
// left corner, top right corner). Storage flattened row-major
std::array<double, 6> compute_bbox_of_entity(const mesh::Mesh& mesh, int dim,
std::int32_t index)
{
// Get the geometrical indices for the mesh entity
std::span<const double> xg = mesh.geometry().x();
Expand All @@ -45,129 +46,112 @@ compute_bbox_of_entity(const mesh::Mesh& mesh, int dim, std::int32_t index)
const std::vector<std::int32_t> vertex_indices
= mesh::entities_to_geometry(mesh, dim, entity, false);

std::array<std::array<double, 3>, 2> b;
b[0] = {xg[3 * vertex_indices.front()], xg[3 * vertex_indices.front() + 1],
xg[3 * vertex_indices.front() + 2]};
b[1] = b[0];
std::array<double, 6> b;
auto b0 = std::span(b).subspan<0, 3>();
auto b1 = std::span(b).subspan<3, 3>();
std::copy_n(std::next(xg.begin(), 3 * vertex_indices.front()), 3, b0.begin());
std::copy_n(std::next(xg.begin(), 3 * vertex_indices.front()), 3, b1.begin());

// Compute min and max over vertices
for (int local_vertex : vertex_indices)
for (std::int32_t local_vertex : vertex_indices)
{
for (int j = 0; j < 3; ++j)
for (std::size_t j = 0; j < 3; ++j)
{
b[0][j] = std::min(b[0][j], xg[3 * local_vertex + j]);
b[1][j] = std::max(b[1][j], xg[3 * local_vertex + j]);
b0[j] = std::min(b0[j], xg[3 * local_vertex + j]);
b1[j] = std::max(b1[j], xg[3 * local_vertex + j]);
}
}

return b;
}
//-----------------------------------------------------------------------------
// Compute bounding box of bounding boxes
std::array<std::array<double, 3>, 2> compute_bbox_of_bboxes(
const std::span<const std::pair<std::array<std::array<double, 3>, 2>,
std::int32_t>>& leaf_bboxes)
// Compute bounding box of bounding boxes. Each bounding box is defined as a
// tuple (corners, entity_index). The corners of the bounding box is flattened
// row-major as (lower left corner, top right corner).
std::array<double, 6> compute_bbox_of_bboxes(
std::span<const std::pair<std::array<double, 6>, std::int32_t>> leaf_bboxes)
{
// Compute min and max over remaining boxes
std::array<std::array<double, 3>, 2> b;
b[0] = leaf_bboxes[0].first[0];
b[1] = leaf_bboxes[0].first[1];
for (auto& box : leaf_bboxes)
std::array<double, 6> b = leaf_bboxes.front().first;
for (auto [box, _] : leaf_bboxes)
{
std::transform(box.first[0].begin(), box.first[0].end(), b[0].begin(),
b[0].begin(),
std::transform(box.cbegin(), std::next(box.cbegin(), 3), b.cbegin(),
b.begin(),
[](double a, double b) { return std::min(a, b); });
std::transform(box.first[1].begin(), box.first[1].end(), b[1].begin(),
b[1].begin(),
std::transform(std::next(box.cbegin(), 3), box.cend(),
std::next(b.cbegin(), 3), std::next(b.begin(), 3),
[](double a, double b) { return std::max(a, b); });
}

return b;
}
//------------------------------------------------------------------------------
int _build_from_leaf(
std::span<std::pair<std::array<std::array<double, 3>, 2>, std::int32_t>>
leaf_bboxes,
std::vector<std::array<int, 2>>& bboxes,
std::vector<double>& bbox_coordinates)
std::int32_t _build_from_leaf(
std::span<std::pair<std::array<double, 6>, std::int32_t>> leaf_bboxes,
std::vector<int>& bboxes, std::vector<double>& bbox_coordinates)
{
if (leaf_bboxes.size() == 1)
{
// Reached leaf

// Get bounding box coordinates for leaf
const std::int32_t entity_index = leaf_bboxes[0].second;
const std::array<double, 3> b0 = leaf_bboxes[0].first[0];
const std::array<double, 3> b1 = leaf_bboxes[0].first[1];
const auto [b, entity_index] = leaf_bboxes.front();

// Store bounding box data
bboxes.push_back({entity_index, entity_index});
bbox_coordinates.insert(bbox_coordinates.end(), b0.begin(), b0.end());
bbox_coordinates.insert(bbox_coordinates.end(), b1.begin(), b1.end());
return bboxes.size() - 1;
bboxes.push_back(entity_index);
bboxes.push_back(entity_index);
std::copy_n(b.begin(), 6, std::back_inserter(bbox_coordinates));
return bboxes.size() / 2 - 1;
}
else
{
// Compute bounding box of all bounding boxes
std::array<std::array<double, 3>, 2> b
= compute_bbox_of_bboxes(leaf_bboxes);
std::array<double, 3> b0 = b[0];
std::array<double, 3> b1 = b[1];
std::array<double, 6> b = compute_bbox_of_bboxes(leaf_bboxes);

// Sort bounding boxes along longest axis
std::array<double, 3> b_diff;
std::transform(b1.begin(), b1.end(), b0.begin(), b_diff.begin(),
std::minus<double>());
std::transform(std::next(b.cbegin(), 3), b.cend(), b.cbegin(),
b_diff.begin(), std::minus<double>());
const std::size_t axis = std::distance(
b_diff.begin(), std::max_element(b_diff.begin(), b_diff.end()));

auto middle = std::next(leaf_bboxes.begin(), leaf_bboxes.size() / 2);
std::nth_element(leaf_bboxes.begin(), middle, leaf_bboxes.end(),
[axis](auto& p0, auto& p1) -> bool
{
double x0 = p0.first[0][axis] + p0.first[1][axis];
double x1 = p1.first[0][axis] + p1.first[1][axis];
double x0 = p0.first[axis] + p0.first[3 + axis];
double x1 = p1.first[axis] + p1.first[3 + axis];
return x0 < x1;
});

// Split bounding boxes into two groups and call recursively
assert(!leaf_bboxes.empty());
std::size_t part = leaf_bboxes.size() / 2;
std::array bbox{
_build_from_leaf(leaf_bboxes.first(part), bboxes, bbox_coordinates),
_build_from_leaf(leaf_bboxes.last(leaf_bboxes.size() - part), bboxes,
bbox_coordinates)};
std::int32_t bbox0
= _build_from_leaf(leaf_bboxes.first(part), bboxes, bbox_coordinates);
std::int32_t bbox1 = _build_from_leaf(
leaf_bboxes.last(leaf_bboxes.size() - part), bboxes, bbox_coordinates);

// Store bounding box data. Note that root box will be added last.
bboxes.push_back(bbox);
bbox_coordinates.insert(bbox_coordinates.end(), b0.begin(), b0.end());
bbox_coordinates.insert(bbox_coordinates.end(), b1.begin(), b1.end());
return bboxes.size() - 1;
bboxes.push_back(bbox0);
bboxes.push_back(bbox1);
std::copy_n(b.begin(), 6, std::back_inserter(bbox_coordinates));
return bboxes.size() / 2 - 1;
}
}
//-----------------------------------------------------------------------------
std::pair<std::vector<std::int32_t>, std::vector<double>> build_from_leaf(
std::vector<std::pair<std::array<std::array<double, 3>, 2>, std::int32_t>>
leaf_bboxes)
std::vector<std::pair<std::array<double, 6>, std::int32_t>>& leaf_bboxes)
{
std::vector<std::array<std::int32_t, 2>> bboxes;
std::vector<std::int32_t> bboxes;
std::vector<double> bbox_coordinates;
_build_from_leaf(leaf_bboxes, bboxes, bbox_coordinates);

std::vector<std::int32_t> bbox_array(2 * bboxes.size());
for (std::size_t i = 0; i < bboxes.size(); ++i)
{
bbox_array[2 * i] = bboxes[i][0];
bbox_array[2 * i + 1] = bboxes[i][1];
}

return {std::move(bbox_array), std::move(bbox_coordinates)};
return {std::move(bboxes), std::move(bbox_coordinates)};
}
//-----------------------------------------------------------------------------
int _build_from_point(
std::int32_t _build_from_point(
std::span<std::pair<std::array<double, 3>, std::int32_t>> points,
std::vector<std::array<std::int32_t, 2>>& bboxes,
std::vector<double>& bbox_coordinates)
std::vector<std::int32_t>& bboxes, std::vector<double>& bbox_coordinates)
{
// Reached leaf
if (points.size() == 1)
Expand All @@ -176,12 +160,13 @@ int _build_from_point(

// Index of entity contained in leaf
const std::int32_t c1 = points[0].second;
bboxes.push_back({c1, c1});
bboxes.push_back(c1);
bboxes.push_back(c1);
bbox_coordinates.insert(bbox_coordinates.end(), points[0].first.begin(),
points[0].first.end());
bbox_coordinates.insert(bbox_coordinates.end(), points[0].first.begin(),
points[0].first.end());
return bboxes.size() - 1;
return bboxes.size() / 2 - 1;
}

// Compute bounding box of all points
Expand All @@ -204,16 +189,17 @@ int _build_from_point(
// Split bounding boxes into two groups and call recursively
assert(!points.empty());
std::size_t part = points.size() / 2;
std::array bbox{
_build_from_point(points.first(part), bboxes, bbox_coordinates),
_build_from_point(points.last(points.size() - part), bboxes,
bbox_coordinates)};
std::int32_t bbox0
= _build_from_point(points.first(part), bboxes, bbox_coordinates);
std::int32_t bbox1 = _build_from_point(points.last(points.size() - part),
bboxes, bbox_coordinates);

// Store bounding box data. Note that root box will be added last.
bboxes.push_back(bbox);
bboxes.push_back(bbox0);
bboxes.push_back(bbox1);
bbox_coordinates.insert(bbox_coordinates.end(), b0.begin(), b0.end());
bbox_coordinates.insert(bbox_coordinates.end(), b1.begin(), b1.end());
return bboxes.size() - 1;
return bboxes.size() / 2 - 1;
}
//-----------------------------------------------------------------------------
} // namespace
Expand Down Expand Up @@ -242,16 +228,14 @@ BoundingBoxTree::BoundingBoxTree(const mesh::Mesh& mesh, int tdim,
mesh.topology_mutable().create_connectivity(tdim, mesh.topology().dim());

// Create bounding boxes for all mesh entities (leaves)
std::vector<std::pair<std::array<std::array<double, 3>, 2>, std::int32_t>>
leaf_bboxes;
std::vector<std::pair<std::array<double, 6>, std::int32_t>> leaf_bboxes;
leaf_bboxes.reserve(entities.size());
for (std::int32_t e : entities)
{
std::array<std::array<double, 3>, 2> b
= compute_bbox_of_entity(mesh, tdim, e);
std::transform(b[0].begin(), b[0].end(), b[0].begin(),
std::array<double, 6> b = compute_bbox_of_entity(mesh, tdim, e);
std::transform(b.cbegin(), std::next(b.cbegin(), 3), b.begin(),
[padding](double x) { return x - padding; });
std::transform(b[1].begin(), b[1].end(), b[1].begin(),
std::transform(std::next(b.begin(), 3), b.end(), std::next(b.begin(), 3),
[padding](double& x) { return x + padding; });
leaf_bboxes.emplace_back(b, e);
}
Expand All @@ -269,16 +253,10 @@ BoundingBoxTree::BoundingBoxTree(
: _tdim(0)
{
// Recursively build the bounding box tree from the leaves
std::vector<std::array<int, 2>> bboxes;
if (!points.empty())
{
_build_from_point(std::span(points), bboxes, _bbox_coordinates);
_bboxes.resize(2 * bboxes.size());
for (std::size_t i = 0; i < bboxes.size(); ++i)
{
_bboxes[2 * i] = bboxes[i][0];
_bboxes[2 * i + 1] = bboxes[i][1];
}
_bboxes.clear();
_build_from_point(std::span(points), _bboxes, _bbox_coordinates);
}

LOG(INFO) << "Computed bounding box tree with " << num_bboxes()
Expand All @@ -305,14 +283,12 @@ BoundingBoxTree BoundingBoxTree::create_global_tree(MPI_Comm comm) const
MPI_Allgather(send_bbox.data(), 6, MPI_DOUBLE, recv_bbox.data(), 6,
MPI_DOUBLE, comm);

std::vector<std::pair<std::array<std::array<double, 3>, 2>, std::int32_t>>
_recv_bbox(mpi_size);
std::vector<std::pair<std::array<double, 6>, std::int32_t>> _recv_bbox(
mpi_size);
for (std::size_t i = 0; i < _recv_bbox.size(); ++i)
{
std::copy_n(std::next(recv_bbox.begin(), 6 * i), 3,
_recv_bbox[i].first[0].begin());
std::copy_n(std::next(recv_bbox.begin(), 6 * i + 3), 3,
_recv_bbox[i].first[1].begin());
std::copy_n(std::next(recv_bbox.begin(), 6 * i), 6,
_recv_bbox[i].first.begin());
_recv_bbox[i].second = i;
}

Expand All @@ -337,12 +313,12 @@ std::string BoundingBoxTree::str() const
//-----------------------------------------------------------------------------
int BoundingBoxTree::tdim() const { return _tdim; }
//-----------------------------------------------------------------------------
void BoundingBoxTree::tree_print(std::stringstream& s, int i) const
void BoundingBoxTree::tree_print(std::stringstream& s, std::int32_t i) const
{
s << "[";
for (int j = 0; j < 2; ++j)
for (std::size_t j = 0; j < 2; ++j)
{
for (int k = 0; k < 3; ++k)
for (std::size_t k = 0; k < 3; ++k)
s << _bbox_coordinates[6 * i + j * 3 + k] << " ";
if (j == 0)
s << "]->"
Expand All @@ -362,13 +338,3 @@ void BoundingBoxTree::tree_print(std::stringstream& s, int i) const
}
}
//-----------------------------------------------------------------------------
std::array<std::array<double, 3>, 2>
BoundingBoxTree::get_bbox(std::size_t node) const
{
std::array<std::array<double, 3>, 2> x;
std::copy_n(std::next(_bbox_coordinates.begin(), 6 * node), 3, x[0].begin());
std::copy_n(std::next(_bbox_coordinates.begin(), 6 * node + 3), 3,
x[1].begin());
return x;
}
//-----------------------------------------------------------------------------
21 changes: 14 additions & 7 deletions cpp/dolfinx/geometry/BoundingBoxTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#pragma once

#include <algorithm>
#include <array>
#include <cassert>
#include <cstdint>
Expand Down Expand Up @@ -68,11 +69,17 @@ class BoundingBoxTree
/// Destructor
~BoundingBoxTree() = default;

/// Return bounding box coordinates for a given node in the tree
/// @param[in] node The bounding box node index
/// @return The bounding box where [0] is the lower corner and [1] is
/// the upper corner
std::array<std::array<double, 3>, 2> get_bbox(std::size_t node) const;
/// @brief Return bounding box coordinates for a given node in the
/// tree,
/// @param[in] node The bounding box node index.
/// @return Bounding box coordinates (lower_corner, upper_corner).
/// Shape is (2, 3), row-major storage.
std::array<double, 6> get_bbox(std::size_t node) const
{
std::array<double, 6> x;
std::copy_n(_bbox_coordinates.data() + 6 * node, 6, x.begin());
return x;
}

/// Compute a global bounding tree (collective on comm)
/// This can be used to find which process a point might have a
Expand All @@ -97,7 +104,7 @@ class BoundingBoxTree
/// nodes, then the values in the returned array are equal and
/// correspond to the index of the entity that the leaf node bounds,
/// e.g. the index of the cell that it bounds.
std::array<int, 2> bbox(std::size_t node) const
std::array<std::int32_t, 2> bbox(std::size_t node) const
{
assert(2 * node + 1 < _bboxes.size());
return {_bboxes[2 * node], _bboxes[2 * node + 1]};
Expand All @@ -112,7 +119,7 @@ class BoundingBoxTree
int _tdim;

// Print out recursively, for debugging
void tree_print(std::stringstream& s, int i) const;
void tree_print(std::stringstream& s, std::int32_t i) const;

// List of bounding boxes (parent-child-entity relations)
std::vector<std::int32_t> _bboxes;
Expand Down
Loading