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 #2313

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
169 changes: 77 additions & 92 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 All @@ -16,6 +16,7 @@

using namespace dolfinx;
using namespace dolfinx::geometry;
namespace stdex = std::experimental;

namespace
{
Expand All @@ -34,8 +35,8 @@ std::vector<std::int32_t> range(const mesh::Mesh& mesh, int tdim)
}
//-----------------------------------------------------------------------------
// Compute bounding box of mesh entity
jorgensd marked this conversation as resolved.
Show resolved Hide resolved
jorgensd marked this conversation as resolved.
Show resolved Hide resolved
std::array<std::array<double, 3>, 2>
compute_bbox_of_entity(const mesh::Mesh& mesh, int dim, std::int32_t index)
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,78 +46,74 @@ 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;
common::impl::copy_N<3>(std::next(xg.begin(), 3 * vertex_indices.front()),
b.begin());
common::impl::copy_N<3>(std::next(xg.begin(), 3 * vertex_indices.front()),
std::next(b.begin(), 3));
AB_span<2, 3> bsp(b.data());
// Compute min and max over vertices
for (int local_vertex : vertex_indices)
{
for (int 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]);
bsp(0, j) = std::min(bsp(0, j), xg[3 * local_vertex + j]);
bsp(1, j) = std::max(bsp(1, j), xg[3 * local_vertex + j]);
}
}

return b;
}
//-----------------------------------------------------------------------------
// Compute bounding box of bounding boxes
jorgensd marked this conversation as resolved.
Show resolved Hide resolved
std::array<std::array<double, 3>, 2> compute_bbox_of_bboxes(
jorgensd marked this conversation as resolved.
Show resolved Hide resolved
const std::span<const std::pair<std::array<std::array<double, 3>, 2>,
std::int32_t>>& leaf_bboxes)
std::array<double, 6> compute_bbox_of_bboxes(
const std::span<const std::pair<std::array<double, 6>, std::int32_t>>&
jorgensd marked this conversation as resolved.
Show resolved Hide resolved
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];
std::array<double, 6> b = leaf_bboxes[0].first;

for (auto& box : leaf_bboxes)
jorgensd marked this conversation as resolved.
Show resolved Hide resolved
{
std::transform(box.first[0].begin(), box.first[0].end(), b[0].begin(),
b[0].begin(),
std::transform(box.first.begin(), std::next(box.first.begin(), 3),
b.begin(), b.begin(),
SarahRo marked this conversation as resolved.
Show resolved Hide resolved
[](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.first.begin(), 3), box.first.end(),
std::next(b.begin(), 3), std::next(b.begin(), 3),
SarahRo marked this conversation as resolved.
Show resolved Hide resolved
[](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::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[0];
SarahRo marked this conversation as resolved.
Show resolved Hide resolved

// 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);
bbox_coordinates.insert(bbox_coordinates.end(), b.begin(),
std::next(b.begin(), 3));
SarahRo marked this conversation as resolved.
Show resolved Hide resolved
bbox_coordinates.insert(bbox_coordinates.end(), std::next(b.begin(), 3),
b.end());
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::transform(std::next(b.begin(), 3), b.end(), b.begin(), b_diff.begin(),
SarahRo marked this conversation as resolved.
Show resolved Hide resolved
std::minus<double>());
const std::size_t axis = std::distance(
b_diff.begin(), std::max_element(b_diff.begin(), b_diff.end()));
Expand All @@ -125,49 +122,44 @@ int _build_from_leaf(
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];
AB_span<2, 3> p0sp(p0.first.data());
AB_span<2, 3> p1sp(p1.first.data());
double x0 = p0sp(0, axis) + p0sp(1, axis);
double x1 = p1sp(0, axis) + p1sp(1, 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)};
int bbox0
= _build_from_leaf(leaf_bboxes.first(part), bboxes, bbox_coordinates);
int 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);
bbox_coordinates.insert(bbox_coordinates.end(), b.begin(),
std::next(b.begin(), 3));
SarahRo marked this conversation as resolved.
Show resolved Hide resolved
bbox_coordinates.insert(bbox_coordinates.end(), std::next(b.begin(), 3),
b.end());
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::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 +168,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 +197,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 +236,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.begin(), std::next(b.begin(), 3), b.begin(),
SarahRo marked this conversation as resolved.
Show resolved Hide resolved
[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),
SarahRo marked this conversation as resolved.
Show resolved Hide resolved
[padding](double& x) { return x + padding; });
leaf_bboxes.emplace_back(b, e);
}
Expand All @@ -269,16 +261,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 +291,14 @@ 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)
{
common::impl::copy_N<3>(std::next(recv_bbox.begin(), 6 * i),
_recv_bbox[i].first[0].begin());
_recv_bbox[i].first.begin());
common::impl::copy_N<3>(std::next(recv_bbox.begin(), 6 * i + 3),
_recv_bbox[i].first[1].begin());
std::next(_recv_bbox[i].first.begin(), 3));
_recv_bbox[i].second = i;
}

Expand Down Expand Up @@ -362,14 +348,13 @@ 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<double, 6> BoundingBoxTree::get_bbox(std::size_t node) const
SarahRo marked this conversation as resolved.
Show resolved Hide resolved
{
std::array<std::array<double, 3>, 2> x;
std::array<double, 6> x;
common::impl::copy_N<3>(std::next(_bbox_coordinates.begin(), 6 * node),
x[0].begin());
x.begin());
common::impl::copy_N<3>(std::next(_bbox_coordinates.begin(), 6 * node + 3),
x[1].begin());
std::next(x.begin(), 3));
return x;
}
//-----------------------------------------------------------------------------
10 changes: 7 additions & 3 deletions cpp/dolfinx/geometry/BoundingBoxTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
#pragma once

#include <array>
#include <basix/mdspan.hpp>
#include <cassert>
#include <cstdint>
#include <mpi.h>
#include <span>
#include <string>
#include <vector>
namespace stdex = std::experimental;
SarahRo marked this conversation as resolved.
Show resolved Hide resolved

template <std::size_t A, std::size_t B>
using AB_span = stdex::mdspan<double, stdex::extents<std::size_t, A, B>>;
namespace dolfinx::mesh
{
class Mesh;
Expand Down Expand Up @@ -70,9 +74,9 @@ class BoundingBoxTree

/// 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;
/// @return The bounding box [:3] contains the lower corner and [3:] the upper
/// corner
SarahRo marked this conversation as resolved.
Show resolved Hide resolved
std::array<double, 6> get_bbox(std::size_t node) const;

/// Compute a global bounding tree (collective on comm)
/// This can be used to find which process a point might have a
Expand Down
Loading