Skip to content

Commit 25c7848

Browse files
authored
Merge pull request #1115 from aprokop/custom_distance
Add an example using custom distance for nearest search
2 parents 9b7baae + a2f149b commit 25c7848

File tree

6 files changed

+145
-3
lines changed

6 files changed

+145
-3
lines changed

examples/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ endif()
88
add_subdirectory(access_traits)
99
add_subdirectory(brute_force)
1010
add_subdirectory(callback)
11+
add_subdirectory(custom_distance)
1112
add_subdirectory(dbscan)
1213
add_subdirectory(molecular_dynamics)
1314
add_subdirectory(simple_intersection)

examples/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Directory | Description
55
`access_traits` | provide non-View user data to ArborX
66
`brute_force` | use brute force to solve a problem
77
`callback` | execute search which calls user function on match
8+
`custom_distance` | execute nearest search using a custom distance metric
89
`dbscan` | cluster a set of points using DBSCAN
910
`molecular_dynamics` | do one step of moving particles under forces
1011
`moving_least_squares` | interpolate data between point clouds using MLS
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
add_executable(ArborX_Example_CustomDistance.exe example_custom_distance.cpp)
2+
target_link_libraries(ArborX_Example_CustomDistance.exe ArborX::ArborX)
3+
add_test(NAME ArborX_Example_CustomDistance COMMAND ArborX_Example_CustomDistance.exe)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/****************************************************************************
2+
* Copyright (c) 2025, ArborX authors *
3+
* All rights reserved. *
4+
* *
5+
* This file is part of the ArborX library. ArborX is *
6+
* distributed under a BSD 3-clause license. For the licensing terms see *
7+
* the LICENSE file in the top-level directory. *
8+
* *
9+
* SPDX-License-Identifier: BSD-3-Clause *
10+
****************************************************************************/
11+
#include <ArborX.hpp>
12+
13+
#include <Kokkos_Core.hpp>
14+
15+
#include <algorithm> // copy
16+
#include <iostream> // cout
17+
#include <iterator> // ostream_iterator
18+
19+
// Define custom type that will be used for distance calculations
20+
struct CustomPoint
21+
{
22+
float x;
23+
float y;
24+
25+
KOKKOS_FUNCTION auto operator[](int i) const
26+
{
27+
KOKKOS_ASSERT(i == 0 || i == 1);
28+
return (i == 0 ? x : y);
29+
}
30+
KOKKOS_FUNCTION auto &operator[](int i)
31+
{
32+
KOKKOS_ASSERT(i == 0 || i == 1);
33+
return (i == 0 ? x : y);
34+
}
35+
};
36+
37+
template <>
38+
struct ArborX::GeometryTraits::dimension<CustomPoint>
39+
{
40+
static constexpr int value = 2;
41+
};
42+
template <>
43+
struct ArborX::GeometryTraits::coordinate_type<CustomPoint>
44+
{
45+
using type = float;
46+
};
47+
template <>
48+
struct ArborX::GeometryTraits::tag<CustomPoint>
49+
{
50+
using type = ArborX::GeometryTraits::PointTag;
51+
};
52+
53+
// Provide the distance function between indexable getter geometry and the
54+
// custom data type
55+
KOKKOS_FUNCTION auto distance(CustomPoint const &p, CustomPoint const &q)
56+
{
57+
return Kokkos::abs(p.x - q.x) * 2 + Kokkos::abs(p.y - q.y) / 2;
58+
}
59+
60+
// Provide the distance function between the bounding volume geometry and
61+
// the custom data type
62+
using BoundingVolume = ArborX::Box<2>;
63+
KOKKOS_FUNCTION auto distance(CustomPoint const &point,
64+
BoundingVolume const &box)
65+
{
66+
CustomPoint projected_point{
67+
Kokkos::clamp(point.x, box.minCorner()[0], box.maxCorner()[0]),
68+
Kokkos::clamp(point.y, box.minCorner()[0], box.maxCorner()[0])};
69+
return distance(point, projected_point);
70+
}
71+
72+
// Callback to store the result indices
73+
struct ExtractIndex
74+
{
75+
template <typename Query, typename Value, typename Output>
76+
KOKKOS_FUNCTION void operator()(Query const &, Value const &value,
77+
Output const &out) const
78+
{
79+
out(value.index);
80+
}
81+
};
82+
83+
int main(int argc, char *argv[])
84+
{
85+
Kokkos::ScopeGuard guard(argc, argv);
86+
87+
using ExecutionSpace = Kokkos::DefaultExecutionSpace;
88+
using MemorySpace = ExecutionSpace::memory_space;
89+
90+
ExecutionSpace space;
91+
92+
// In L2 metric, two bottom points are the closest.
93+
// In custom metric, left two points are the closest.
94+
//
95+
// | 1
96+
// |
97+
// | x
98+
// | 2 0
99+
// +-----------
100+
Kokkos::View<CustomPoint *, MemorySpace> points("Example::points", 3);
101+
auto points_host = Kokkos::create_mirror_view(points);
102+
points_host[0] = {1, 0};
103+
points_host[1] = {0, 3};
104+
points_host[2] = {0, 0};
105+
Kokkos::deep_copy(points, points_host);
106+
107+
Kokkos::View<CustomPoint *, MemorySpace> query_points("Example::query_points",
108+
1);
109+
auto query_points_host = Kokkos::create_mirror_view(query_points);
110+
query_points_host[0] = {0, 1};
111+
Kokkos::deep_copy(query_points, query_points_host);
112+
113+
ArborX::BoundingVolumeHierarchy bvh(
114+
space, ArborX::Experimental::attach_indices(points));
115+
116+
Kokkos::View<int *, MemorySpace> offsets("Example::offsets", 0);
117+
Kokkos::View<int *, MemorySpace> indices("Example::indices", 0);
118+
bvh.query(space, ArborX::Experimental::make_nearest(query_points, 2),
119+
ExtractIndex{}, indices, offsets);
120+
121+
auto offsets_host =
122+
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, offsets);
123+
auto indices_host =
124+
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, indices);
125+
126+
// Expected output:
127+
// offsets: 0 2
128+
// indices: 2 1
129+
std::cout << "offsets: ";
130+
std::copy(offsets_host.data(), offsets_host.data() + offsets.size(),
131+
std::ostream_iterator<int>(std::cout, " "));
132+
std::cout << "\nindices: ";
133+
std::copy(indices_host.data(), indices_host.data() + indices.size(),
134+
std::ostream_iterator<int>(std::cout, " "));
135+
std::cout << "\n";
136+
137+
return 0;
138+
}

src/spatial/detail/ArborX_Callbacks.hpp

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#define ARBORX_CALLBACKS_HPP
1313

1414
#include <detail/ArborX_AccessTraits.hpp>
15-
#include <detail/ArborX_PairValueIndex.hpp>
1615
#include <detail/ArborX_Predicates.hpp> // is_valid_predicate_tag
1716

1817
#include <Kokkos_DetectionIdiom.hpp>

src/spatial/detail/ArborX_PairValueIndex.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
#ifndef ARBORX_PAIR_VALUE_INDEX_HPP
1313
#define ARBORX_PAIR_VALUE_INDEX_HPP
1414

15-
#include <detail/ArborX_AccessTraits.hpp>
16-
1715
#include <Kokkos_Macros.hpp>
1816

17+
#include <type_traits>
18+
1919
namespace ArborX
2020
{
2121

0 commit comments

Comments
 (0)