|
| 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 | +} |
0 commit comments