Skip to main content

Rocky Solver SDK 2024 R2

api_device_grid_search

Last update: 17.07.2025
1#pragma once
2
3#include <rocky20/core/utils/rocky_math.hpp>
4
5#include <cstddef>
6#include <vector_types.h>
7
8using namespace rocky::vector;
9
10template <typename NeighborhoodOperator>
11__host__ __device__ size_t iterate_over_grid_cells(
12 NeighborhoodOperator& neighborhood,
13 const size_t* grid_starting_index,
14 const size_t* grid_to_original_map,
15 const longlong3& block_start,
16 const longlong3& block_end,
17 const longlong3& grid_size,
18 const double3& home_position,
19 const size_t home_entity_id,
20 const double search_radius,
21 const bool not_in_block)
22{
23 const double squared_search_radius = search_radius * search_radius;
24 const size_t grid_volume = grid_size.x * grid_size.y * grid_size.z;
25 const size_t near_count = neighborhood.get_near_count();
26 size_t n_thread_vicinities = 0;
27 for (size_t x = block_start.x; x < block_end.x; ++x)
28 {
29 const size_t x_offset = x * grid_size.y * grid_size.z;
30 for (size_t y = block_start.y; y < block_end.y; ++y)
31 {
32 const size_t xy_offset = x_offset + (y * grid_size.z);
33 const size_t first_cell_id = xy_offset + block_start.z;
34 const size_t last_cell_id = xy_offset + block_end.z;
35 const size_t index_start = grid_starting_index[first_cell_id];
36 const size_t index_end =
37 (last_cell_id < grid_volume) ? grid_starting_index[last_cell_id] : near_count;
38
39 for (size_t prt_id_grid = index_start; prt_id_grid < index_end; ++prt_id_grid)
40 {
41 const size_t near_entity_id = grid_to_original_map[prt_id_grid];
42 if (neighborhood.is_valid(home_entity_id, near_entity_id, not_in_block))
43 {
44 const double3 near_position = neighborhood.get_near_centroid(near_entity_id);
45 const double squared_distance = rocky::vector::dot(home_position - near_position);
46 if (squared_distance <= squared_search_radius)
47 {
48 neighborhood.operate(home_entity_id, near_entity_id);
49 n_thread_vicinities++;
50 }
51 }
52 }
53 }
54 }
55 return n_thread_vicinities;
56}
57
58template <typename NeighborhoodOperator, typename GridStartingIndex>
59__host__ __device__ size_t iterate_over_grid_cells_2(
60 NeighborhoodOperator& neighborhood,
61 const GridStartingIndex grid_starting_index,
62 const unsigned int* __restrict__ grid_to_original_map,
63 const uint3& block_start,
64 const uint3& block_end,
65 const uint3& grid_size,
66 const unsigned int home_entity_id,
67 const bool not_in_block)
68{
69 const size_t grid_volume = size_t(grid_size.x) * grid_size.y * grid_size.z;
70 const unsigned int near_count = neighborhood.get_near_count();
71 unsigned int n_thread_vicinities = 0;
72 for (unsigned int x = block_start.x; x < block_end.x; ++x)
73 {
74 const size_t x_offset = size_t(x) * grid_size.y * grid_size.z;
75 for (unsigned int y = block_start.y; y < block_end.y; ++y)
76 {
77 const size_t xy_offset = x_offset + (size_t(y) * grid_size.z);
78 const size_t first_cell_id = xy_offset + block_start.z;
79 const size_t last_cell_id = xy_offset + block_end.z;
80 unsigned int index_start, index_end;
81 if constexpr (std::is_pointer_v<GridStartingIndex>)
82 {
83 index_start = grid_starting_index[first_cell_id];
84 index_end =
85 (last_cell_id < grid_volume) ? grid_starting_index[last_cell_id] : near_count;
86 }
87 else
88 {
89 grid_starting_index.get_range(
90 first_cell_id, last_cell_id, index_start, index_end, grid_volume);
91 }
92
93 for (unsigned int prt_id_grid = index_start; prt_id_grid < index_end; ++prt_id_grid)
94 {
95 const unsigned int near_entity_id = grid_to_original_map[prt_id_grid];
96 if (neighborhood.is_valid(home_entity_id, near_entity_id, not_in_block))
97 {
98 neighborhood.operate(home_entity_id, near_entity_id);
99 n_thread_vicinities++;
100 }
101 }
102 }
103 }
104 return n_thread_vicinities;
105}
106
123template <typename Backend, typename NeighborhoodOperator>
124__host__ __device__ void travel_vicinities_outsider(
125 NeighborhoodOperator& neighborhood,
126 const size_t* grid_starting_index,
127 const size_t* grid_to_original_map,
128 const double cell_size,
129 const double search_radius,
130 const longlong3 grid_size,
131 double3 grid_start,
132 size_t* n_vicinities)
133{
134 auto clamp_to_grid = [&grid_size](const longlong3& position) -> longlong3 {
135 constexpr longlong3 origin { 0, 0, 0 };
136 return clamp_vector(position, origin, grid_size);
137 };
138
139 // reduce grid start by an epsilon to avoid summing it on every position calculation
140 grid_start -= (cell_size * 0.01);
141 const double cell_size_inverse = 1.0 / cell_size;
142 size_t n_thread_vicinities = 0;
143 int start, step, stop;
144
145 Backend::ThreadIteration(start, step, stop, neighborhood.get_home_count());
146 for (size_t home_entity_id = start; home_entity_id < stop; home_entity_id += step)
147 {
148 const double3 home_position = neighborhood.get_home_centroid(home_entity_id);
149 const auto home_grid_position { rocky::vector::cast<longlong3>(
150 (home_position - grid_start) * cell_size_inverse) };
151
152 const longlong3 block_start = clamp_to_grid(home_grid_position - 2);
153 const longlong3 block_end = clamp_to_grid(home_grid_position + 3);
154
155 n_thread_vicinities += iterate_over_grid_cells(
156 neighborhood,
157 grid_starting_index,
158 grid_to_original_map,
159 block_start,
160 block_end,
161 grid_size,
162 home_position,
163 home_entity_id,
164 search_radius,
165 false);
166 }
167 if (n_vicinities != nullptr && n_thread_vicinities > 0)
168 {
169 Backend::AtomicAdd(n_vicinities, n_thread_vicinities);
170 }
171}
172
189template <typename Backend, typename NeighborhoodOperator>
190__host__ __device__ void travel_vicinities_insider(
191 NeighborhoodOperator& neighborhood,
192 const size_t* grid_starting_index,
193 const size_t* grid_to_original_map,
194 const double cell_size,
195 const double search_radius,
196 const longlong3 grid_size,
197 double3 grid_start,
198 size_t* n_vicinities)
199{
200 // reduce grid start by an epsilon to avoid summing it on every position calculation
201 grid_start -= (cell_size * 0.01);
202 const double cell_size_inverse = 1.0 / cell_size;
203 size_t n_thread_vicinities = 0;
204 int start, step, stop;
205
206 double3 home_position;
207 size_t home_entity_id;
208 auto dispatch_on_block = [&](const longlong3& _block_start,
209 const longlong3& _block_end,
210 const bool different_cells = true) -> void {
211 n_thread_vicinities += iterate_over_grid_cells(
212 neighborhood,
213 grid_starting_index,
214 grid_to_original_map,
215 _block_start,
216 _block_end,
217 grid_size,
218 home_position,
219 home_entity_id,
220 search_radius,
221 different_cells);
222 };
223
224 Backend::ThreadIteration(start, step, stop, neighborhood.get_home_count());
225 for (size_t prt_id_grid = start; prt_id_grid < stop; prt_id_grid += step)
226 {
227 home_entity_id = grid_to_original_map[prt_id_grid];
228 if (home_entity_id == INVALID_ENTITY_ID)
229 {
230 continue;
231 }
232
233 home_position = neighborhood.get_home_centroid(home_entity_id);
234 const auto home_coordinate { rocky::vector::cast<longlong3>(
235 (home_position - grid_start) * cell_size_inverse) };
236
237 const longlong3 block_start { max_vector({ 0ll, 0ll, 0ll }, home_coordinate - 2) };
238 const longlong3 block_diag { min_vector(grid_size, home_coordinate + 1) };
239 const longlong3 block_end { min_vector(grid_size, home_coordinate + 3) };
240
241 // xyz block above
242 dispatch_on_block({ block_diag.x, block_start.y, block_start.z }, block_end);
243 // right side of yz plane
244 dispatch_on_block(
245 { home_coordinate.x, block_diag.y, block_start.z },
246 { block_diag.x, block_end.y, block_end.z });
247 // all the way back to z end on this line
248 dispatch_on_block(
249 { home_coordinate.x, home_coordinate.y, block_diag.z },
250 { block_diag.x, block_diag.y, block_end.z });
251 // same grid cell. Can't skip element ID check to avoid duplicate vicinities.
252 dispatch_on_block(home_coordinate, block_diag, false);
253 }
254 if (n_vicinities != nullptr && n_thread_vicinities > 0)
255 {
256 Backend::AtomicAdd(n_vicinities, n_thread_vicinities);
257 }
258}
259
260template <typename Backend, typename NeighborhoodOperator, typename GridStartingIndex>
261__host__ __device__ unsigned int travel_vicinities_insider_full(
262 NeighborhoodOperator& neighborhood,
263 const GridStartingIndex grid_starting_index,
264 const unsigned int* __restrict__ grid_to_original_map,
265 const float cell_size,
266 const float search_radius,
267 const uint3& grid_size,
268 float3 grid_start)
269{
270 const float epsilon = cell_size * 0.01f;
271 const float cell_size_inverse = 1.f / cell_size;
272 const unsigned int steps = std::ceil(search_radius / cell_size);
273 unsigned int n_thread_vicinities = 0;
274 int start, step, stop;
275
276 unsigned int home_entity_id;
277 auto dispatch_on_block = [&](const uint3& _block_start,
278 const uint3& _block_end,
279 const bool different_cells = true) -> void {
280 n_thread_vicinities += iterate_over_grid_cells_2(
281 neighborhood,
282 grid_starting_index,
283 grid_to_original_map,
284 _block_start,
285 _block_end,
286 grid_size,
287 home_entity_id,
288 different_cells);
289 };
290
291 Backend::ThreadIteration(start, step, stop, neighborhood.get_home_count());
292 for (home_entity_id = start; home_entity_id < stop; home_entity_id += step)
293 {
294 neighborhood.start_element(home_entity_id);
295
296 const auto home_coordinate = rocky::vector::cast<uint3>(
297 ((neighborhood.get_home_centroid(home_entity_id) - grid_start) + epsilon)
298 * cell_size_inverse);
299
300 const uint3 block_start { max_vector(uint3 { steps, steps, steps }, home_coordinate) - steps };
301 const uint3 block_diag { min_vector(grid_size, home_coordinate + 1) };
302 const uint3 block_end { min_vector(grid_size, home_coordinate + (steps + 1)) };
303
304 // xyz block above
305 dispatch_on_block({ block_diag.x, block_start.y, block_start.z }, block_end);
306 // right side of yz plane
307 dispatch_on_block(
308 { home_coordinate.x, block_diag.y, block_start.z },
309 { block_diag.x, block_end.y, block_end.z });
310 // all the way back to z end on this line
311 dispatch_on_block(
312 { home_coordinate.x, home_coordinate.y, block_diag.z },
313 { block_diag.x, block_diag.y, block_end.z });
314 // same grid cell. Can't skip element ID check to avoid duplicate vicinities.
315 dispatch_on_block(home_coordinate, block_diag, false);
316
317 neighborhood.finish_element(home_entity_id);
318 }
319 return n_thread_vicinities;
320}

Connect with Ansys