-
Notifications
You must be signed in to change notification settings - Fork 46
MigrationGuide
APIv2 (used in ArborX 2.x) extensively changed the spatial index API, breaking backwards compatibility. This guide provides motivation behind the change and general tips for migrating an existing APIv1 (ArborX 1.x) code to APIv2.
APIv1 had multiple severe limitations:
-
Dimensionality was hardcoded to 3D
APIv1 only supported 3D objects. 2D objects were treated as 3D through setting
$z = 0$ , at the cost of extra memory storage and slower traversal. -
User-provided data was restricted to points and boxes
Spatial indexes lacked the capability of storing general user data, including non-trivial geometries (e.g., triangles, tetrahedrons, etc) and associated metadata (e.g., global index corresponding to a geometry).
-
Only coarse search was supported
As APIv1 was only able to store user data as points and boxes, the queries were only able to perform coarse search.
For spatial queries, that meant that a user had to provide a callback where the fine search (intersection with user geometries) was performed.
For nearest queries, this meant that ArborX only considered the distances to stored boxes, and not to the user data. This meant that for user geometries other than points and boxes, the results produced by ArborX could be wrong.
-
Callbacks were limited
Signatures of callbacks only took integer as the second argument, requiring user to store more data inside the callback.
In APIv1, ArborX::Point and ArborX::Box were hardcoded to single-precision
3D data. In contrast, all geometries in APIv2 are templated on both the
dimension and the stored type:
template<int DIM, typename Coordinate = float>
struct Geometry;
Some geometries, for example KDOP, may have additional template arguments.
APIv2 removed the second template argument in AccessTraits, which in APIv1
had to be ArborX::PrimitivesTag or ArborX::PredicatesTag.
In most situations, simply removing this argument in the user code is
sufficient. One exception is when the code provided AccessTraits
specialization for the same data structure for both PrimitivesTag and
PredicatesTag. In this case, the simplest approach would be to introduce user
space tags and template user data structure on those.
For example,
struct PrimitivesTag{};
struct PredicatesTag{};
template<typename Tag, typename... Args>
struct UserData {...};
template<typename... Args>
struct ArborX::AccessTraits<UserData<PrimitivesTag, Args...>> {...};
template<typename... Args>
struct ArborX::AccessTraits<UserData<PredicatesTag, Args...>> {...};APIv1 used int as the default returned value or as the second argument to the
callback. To reproduce this behavior, construct an index with attached indexes
and use a callback to extract the index:
struct ExtractIndex
{
template <typename Query, typename Value, typename Output>
KOKKOS_FUNCTION void operator()(Query const &, Value const &value,
Output const &out) const
{
out(value.index);
}
};
Primitives primitives;
using Value = ...; // return type of ArborX::AccessTraits<Primitives>::get()
// The template arguments could be omitted (to make use of deduction guides)
BoundingVolumeHierarchy<MemorySpace, ArborX::PairValueIndex<Value,int>>
bvh(space, ArborX::Experimental::attach_indices(primitives));
Kokkos::View<int*> offsets("offsets", 0);
Kokkos::View<int*> indices("indices", 0);
bvh.query(space, predicates, ExtractIndex{}, indices, offsets);If one desires to be able to build code against both versions of ArborX,
ARBORX_VERSION macro can be used to distinguish whether the code is built
against APIv1 (ARBORX_VERSION < 20000) or APIv2 (ARBORX_VERSION >= 20000).