TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Octree_Int.cpp
1/****************************************************************************
2* Copyright (c) 2024, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15#include <Octree_Int.h>
16
17static constexpr int max_levels_ = 32; // 1 more than the number of bits=1 in coords_max
18// The following value must be a power of two
19template<> const int Octree_Int_32_64<int>::root_octree_half_width_ = 1073741824; /* 2^30 = 0100 0000 0000 0000 0000 0000 0000 0000b */
20// The following value must be equal to (root_octree_half_width_ * 2 - 1)
21template<> const int Octree_Int_32_64<int>::coord_max_ = 2147483647; /* 2^31-1 = 0111 1111 1111 1111 1111 1111 1111 1111b */
22
23
24#if INT_is_64_ == 2
25template<> const int Octree_Int_32_64<trustIdType>::root_octree_half_width_ = 1073741824;
26template<> const int Octree_Int_32_64<trustIdType>::coord_max_ = 2147483647;
27#endif
28
29/*! @brief builds an octree_id (see octree_structure_)
30 *
31 * If type==EMPTY, the octree_id is 0
32 * If type==OCTREE, index is assumed to be an index into octree_structure_
33 * If type==FLOOR, index is assumed to be an index into floor_elements_
34 */
35template <typename _SIZE_>
37{
38 switch(type)
39 {
40 case EMPTY:
41 return 0;
42 case OCTREE:
43 return index + 1;
44 case FLOOR:
45 return - index - 1;
46 }
47 return -1;
48}
49
50/*! @brief computes the index of the octree in octree_structure or floor_elements based on the type of the octree and its octree_id.
51 *
52 * In general the type is already known, so it is passed as a parameter for efficiency.
53 *
54 */
55template <typename _SIZE_>
57{
58 assert(type==octree_type(octree_id));
59 switch(type)
60 {
61 case EMPTY:
62 return -1;
63 case OCTREE:
64 return octree_id - 1;
65 case FLOOR:
66 return - octree_id - 1;
67 }
68 return -1;
69}
70
71/*! @brief Returns the type of an octree based on its octree_id.
72 *
73 */
74template <typename _SIZE_>
76{
77 if (octree_id > 0)
78 return OCTREE;
79 else if (octree_id == 0)
80 return EMPTY;
81 else
82 return FLOOR;
83}
84
85/*! @brief builds the octree.
86 *
87 * The dimension (1, 2 or 3) and an array of elements to store in the octree are given. Two possibilities:
88 * 1) elements are point-like if elements_boxes.dimension(1) == dimension.
89 * In this case, each element belongs to exactly one octree_floor
90 * 2) elements are parallelepipeds, if elements_boxes.dimension(1) == dimension*2
91 * The first "dimension" columns are the lower coordinates,
92 * the next "dimension" columns are the upper coordinates.
93 * A parallelepiped may be assigned to several octree_floors.
94 * Coordinates stored in elements_boxes range from 0 to coord_max_ inclusive.
95 * It is best to use the full integer range by multiplying by an appropriate factor.
96 *
97 */
98template <typename _SIZE_>
99void Octree_Int_32_64<_SIZE_>::build(const int dimension, const IntTab_t& elements_boxes)
100{
101 assert(dimension >= 1 && dimension <= 3);
102 assert(elements_boxes.dimension(1) == dimension
103 || elements_boxes.dimension(1) == dimension * 2 );
104
105 const int_t nb_elems = elements_boxes.dimension(0);
106 nb_elements_ = nb_elems;
107
108 floor_elements_.resize_array(0);
109 const int nb_octrees = 1 << dimension; // = 2^dim
110 octree_structure_.resize(0, nb_octrees);
111
112 assert(elements_boxes.size_array() == 0
113 || (min_array(elements_boxes) >= 0 && max_array(elements_boxes) <= coord_max_));
114
115 AOFlagS_ tmp_elem_flags(max_levels_);
116 ArrsOfInt_t tmp_elem_list(max_levels_);
117 ArrOfInt_t& elements_list = tmp_elem_list[0];
118 elements_list.resize_array(nb_elems, RESIZE_OPTIONS::NOCOPY_NOINIT);
119 for (int_t i = 0; i < nb_elems; i++)
120 elements_list[i] = i;
121
124 elements_boxes,
125 tmp_elem_list,
126 0,
127 tmp_elem_flags);
128}
129
130/*! @brief returns the list of elements potentially containing the point (x,y,z). Returns n=number of elements in the list, and the elements are in
131 *
132 * floor_elements()[index+i] for 0 <= i < n.
133 * In practice, all elements with a non-empty intersection with the octree_floor
134 * containing the point (x,y,z) are returned.
135 *
136 */
137template <typename _SIZE_>
139{
140 const int nb_octrees = octree_structure_.dimension_int(1);
141 if (nb_octrees == 2)
142 y = 0; // important to avoid landing on non-existent cubes
143 if (nb_octrees <= 4)
144 z = 0; // same
145 assert(x >= 0 && x <= coord_max_);
146 assert(y >= 0 && y <= coord_max_);
147 assert(z >= 0 && z <= coord_max_);
148
149 const int_t my_octree_id = search_octree_floor(x, y, z);
150
151 if (octree_type(my_octree_id) == EMPTY)
152 return 0;
153
154 const int_t idx = octree_index(my_octree_id, FLOOR);
155 const int_t n = floor_elements_[idx];
156 index = idx + 1;
157 return n;
158}
159
160template <typename _SIZE_>
162{
163 using ArrOfInt_t = ArrOfInt_T<_SIZE_>;
165
166 IntBoxData(int xmin, int ymin, int zmin,
167 int xmax, int ymax, int zmax,
168 ArrOfInt_t& elements,
169 AOBit_ *markers) :
170 xmin_(xmin), ymin_(ymin), zmin_(zmin),
171 xmax_(xmax), ymax_(ymax), zmax_(zmax),
172 elements_(elements),
173 markers_(markers) { };
178};
179
180/*! @brief searches for elements potentially having a non-empty intersection
181 * with the box xmin..zmax.
182 * Elements may appear more than once in the "elements" array.
183 */
184template <typename _SIZE_>
186 int xmax, int ymax, int zmax,
187 ArrOfInt_t& elements) const
188{
189 const int nb_octrees = octree_structure_.dimension_int(1);
190 if (nb_octrees == 2)
191 ymin = ymax = 0; // important to avoid landing on non-existent cubes
192 if (nb_octrees <= 4)
193 zmin = zmax = 0; // same
194 assert(xmin >= 0 && xmin <= coord_max_);
195 assert(ymin >= 0 && ymin <= coord_max_);
196 assert(zmin >= 0 && zmin <= coord_max_);
197 assert(xmax >= 0 && xmax <= coord_max_);
198 assert(ymax >= 0 && ymax <= coord_max_);
199 assert(zmax >= 0 && zmax <= coord_max_);
200
201 elements.resize_array(0);
202 IntBoxData<_SIZE_> boxdata(xmin, ymin, zmin, xmax, ymax, zmax, elements, 0);
204 {
205 case FLOOR:
207 break;
208 case OCTREE:
212 break;
213 case EMPTY:
214 break;
215 }
216 const int_t n = elements.size_array();
217 return n;
218}
219
220/*! @brief adds elements from the octree_floor to boxdata.
221 *
222 * elements_
223 *
224 */
225template <typename _SIZE_>
227 int_t octree_floor_id) const
228{
229 const int_t idx = octree_index(octree_floor_id, FLOOR);
230 const int_t n = floor_elements_[idx];
231 if (boxdata.markers_)
232 for (int_t i = 0; i < n; i++)
233 {
234 const int_t elem = floor_elements_[idx+1+i];
235 if (!boxdata.markers_->testsetbit(elem))
236 boxdata.elements_.append_array(elem);
237 }
238 else
239 for (int_t i = 0; i < n; i++)
240 {
241 const int_t elem = floor_elements_[idx+1+i];
242 boxdata.elements_.append_array(elem);
243 }
244}
245
246// For each direction, flags of the cubes in the lower row
247static int sub_cube_flags_min[3] = { 1+4+16+64, /* flags of cubes 0,2,4,6 */
248 1+2+16+32, /* flags of cubes 0,1,4,5 */
249 1+2+4+8 /* flags of cubes 0,1,2,3 */
250 };
251static int sub_cube_flags_max[3] = { 2+8+32+128, /* flags of cubes 1,3,5,7 */
252 4+8+64+128, /* flags of cubes 2,3,7,8 */
253 16+32+64+128 /* flags of cubes 4,5,6,7 */
254 };
255
256/*! @brief recursively searches for elements included in the box boxdata for the given octree_id, centred at cx, cy, cz.
257 *
258 */
259template <typename _SIZE_>
261 int_t the_octree_id,
262 int cx, int cy, int cz,
263 int half_width) const
264{
265 int flags = 255;
266 if (cx > boxdata.xmax_) // upper cubes in x are not inside
267 flags &= sub_cube_flags_min[0];
268 if (cx <= boxdata.xmin_) // lower cubes are not inside
269 flags &= sub_cube_flags_max[0];
270 if (cy > boxdata.ymax_)
271 flags &= sub_cube_flags_min[1];
272 if (cy <= boxdata.ymin_)
273 flags &= sub_cube_flags_max[1];
274 if (cz > boxdata.zmax_)
275 flags &= sub_cube_flags_min[2];
276 if (cz <= boxdata.zmin_)
277 flags &= sub_cube_flags_max[2];
278 int test_flag = 1;
279 const int_t idx = octree_index(the_octree_id, OCTREE);
280 const int half_width_2 = half_width >> 1;
281 const int mhalf_width = - half_width_2;
282 int cx2, cy2, cz2;
283 for (int i = 0; i < 8; i++, test_flag <<= 1)
284 {
285 if ((flags & test_flag) != 0)
286 {
287 const int_t id = octree_structure_(idx, i);
288 switch(octree_type(id))
289 {
290 case FLOOR:
291 search_elements_box_floor(boxdata, id);
292 break;
293 case OCTREE:
294 cx2 = cx + ((i & 1) ? half_width_2 : mhalf_width);
295 cy2 = cy + ((i & 2) ? half_width_2 : mhalf_width);
296 cz2 = cz + ((i & 4) ? half_width_2 : mhalf_width);
298 cx2, cy2, cz2,
299 half_width_2);
300 break;
301 case EMPTY:
302 break;
303 }
304 }
305 }
306}
307
308template <typename _SIZE_>
316
317/*! @brief builds an octree_floor with the given list of elements and returns the octree_id of that octree_floor
318 *
319 */
320template <typename _SIZE_>
322{
323 const int_t nb_elems = elements_list.size_array();
324 const int_t index = floor_elements_.size_array();
325 floor_elements_.resize_array(index + nb_elems + 1, RESIZE_OPTIONS::COPY_NOINIT);
326 floor_elements_[index] = nb_elems;
327 for (int_t i = 0; i < nb_elems; i++)
328 floor_elements_[index + 1 + i] = elements_list[i];
329 return octree_id(index, FLOOR);
330}
331
332/*! @brief octree_center_i is the first int of the upper half of the octree in direction i.
333 *
334 * octree_half_width is a power of 2 equal to octree_center_i-octree_min_i (octree_min_i
335 * is the first int included in this octree in direction i)
336 * Return value: octree_id of the built octree (see octree_structure_)
337 *
338 */
339template <typename _SIZE_>
341 const int octree_center_y,
342 const int octree_center_z,
343 const int octree_half_width,
344 const IntTab_t& elements_boxes,
345 ArrsOfInt_t& vect_elements_list,
346 const int level,
347 AOFlagS_& tmp_elem_flags)
348{
349 // Stopping criteria for subdivision:
350 // Maximum number of elements in a floor sub-cube
351 constexpr int OCTREE_FLOOR_MAX_ELEMS = 8;
352 // If there are many duplicate elements, but not too many, and the number of elements
353 // in the octree is above this value, we still subdivide
354 constexpr int OCTREE_DUPLICATE_ELEMENTS_LIMIT = 64;
355 const ArrOfInt_t& elements_list = vect_elements_list[level];
356 // If the number of elements is below the limit, create a floor_element,
357 // otherwise subdivide
358 const int_t nb_elems = elements_list.size_array();
359 if (nb_elems == 0)
360 return octree_id(0, EMPTY);
361
362 if (nb_elems < OCTREE_FLOOR_MAX_ELEMS || octree_half_width == 1 /* last level */)
363 {
364 const int_t the_octree_id = build_octree_floor(elements_list);
365 return the_octree_id;
366 }
367
368 AOFlag_& elem_flags = tmp_elem_flags[level];
369 elem_flags.resize_array(nb_elems, RESIZE_OPTIONS::NOCOPY_NOINIT);
370
371 const int nb_octrees = octree_structure_.dimension_int(1);
372 assert(nb_octrees == 2 || nb_octrees == 4 || nb_octrees == 8);
373 const int elem_box_dim = elements_boxes.dimension_int(1);
374 // Either elements_boxes contains dimension columns, or dimension*2
375 const int box_delta = (elem_box_dim > 3) ? (elem_box_dim >> 1) : 0;
376 // Number of elements stored twice in the octree (due to elements straddling
377 // several sub-octrees)
378 int_t nb_duplicate_elements = 0;
379 // Assign the elements of the list to 8 sub-cubes (filling elem_flags)
380 for (int_t i_elem = 0; i_elem < nb_elems; i_elem++)
381 {
382 const int_t elem = elements_list[i_elem];
383 // dir_flag is 1 for direction x, 2 for y and 4 for z
384 int dir_flag = 1;
385 // sub_cube_flags contains 2^dim binary flags (1 per sub-cube),
386 // indicating which sub-cubes are crossed by the element
387 int octree_flags = 255;
388 // in how many sub-octrees is this element stored?
389 int_t nb_duplicates = 1;
390
391 for (int direction = 0; direction < 3; direction++)
392 {
393 const int_t elem_min = elements_boxes(elem, direction);
394 const int_t elem_max = elements_boxes(elem, box_delta+direction);
395 assert(elem_max >= elem_min);
396 // coordinate of the cube center in direction j:
397 const int center = (direction==0) ? octree_center_x : ((direction==1) ? octree_center_y : octree_center_z);
398 // Does the element cut both the lower and upper parts of the cube in "direction"?
399 if (elem_min >= center) // no -> remove flags of cubes in the lower part
400 octree_flags &= sub_cube_flags_max[direction];
401 else if (elem_max < center) // no -> remove flags of cubes in the upper part
402 octree_flags &= sub_cube_flags_min[direction];
403 else
404 nb_duplicates <<= 1; // the element crosses both parts!
405 dir_flag = dir_flag << 1;
406 if (dir_flag == nb_octrees)
407 break;
408 }
409 elem_flags[i_elem] = octree_flags;
410 nb_duplicate_elements += nb_duplicates - 1;
411 }
412
413 // Slightly complex criterion: if there are really many elements
414 // in this octree, we allow duplicating all elements,
415 // which handles very elongated elements that are necessarily
416 // duplicated in one direction (>OCTREE_DUPLICATE_ELEMENTS_LIMIT).
417 if ((nb_duplicate_elements * 2 >= nb_elems && nb_elems < OCTREE_DUPLICATE_ELEMENTS_LIMIT)
418 || nb_duplicate_elements > nb_elems)
419 {
420 const int_t the_octree_id = build_octree_floor(elements_list);
421 // Return an octreefloor index
422 return the_octree_id;
423 }
424
425 // Reserve a slot at the end of octree_structure to store this octree:
426 const int_t index_octree = octree_structure_.dimension(0);
427 octree_structure_.resize_dim0(index_octree + 1, RESIZE_OPTIONS::COPY_NOINIT);
428 ArrOfInt_t& new_liste_elems = vect_elements_list[level+1];
429 new_liste_elems.resize_array(0);
430 const int width = octree_half_width >> 1;
431 const int m_width = - width;
432 // Recursive processing of the sub-cubes of the octree:
433 for (int i_cube = 0; i_cube < nb_octrees; i_cube++)
434 {
435 const int octree_flag = 1 << i_cube;
436 new_liste_elems.resize_array(nb_elems, RESIZE_OPTIONS::NOCOPY_NOINIT);
437 int_t count = 0;
438 // List of elements included in the sub-cube:
439 for (int_t i_elem = 0; i_elem < nb_elems; i_elem++)
440 if ((elem_flags[i_elem] & octree_flag) != 0)
441 new_liste_elems[count++] = elements_list[i_elem];
442 new_liste_elems.resize_array(count);
443
444 int_t sub_octree_id;
445 if (new_liste_elems.size_array() == 0)
446 sub_octree_id = octree_id(-1, EMPTY);
447 else
448 {
449 // Coordinates of the new sub-cube
450 const int cx = octree_center_x + ((i_cube&1) ? width : m_width);
451 const int cy = octree_center_y + ((i_cube&2) ? width : m_width);
452 const int cz = octree_center_z + ((i_cube&4) ? width : m_width);
453 sub_octree_id = build_octree_recursively(cx, cy, cz, width,
454 elements_boxes,
455 vect_elements_list,
456 level+1,
457 tmp_elem_flags);
458 }
459 octree_structure_(index_octree, i_cube) = sub_octree_id;
460 }
461
462 return octree_id(index_octree, OCTREE);
463}
464
465/*! @brief returns the octree_id of the octree_floor containing the vertex (x,y,z) (may return the EMPTY octree)
466 *
467 */
468template <typename _SIZE_>
470{
472 return root_octree_id_;
473 // The test to determine whether we are in the upper or lower part of an octree at level i
474 // simply consists of testing the i-th bit of the position.
475 int flag = root_octree_half_width_;
476
478
479 // Descend the hierarchy of subdivided octrees down to the smallest cube
480 while (1)
481 {
482 // Index of the sub-cube containing the vertex x,y,z
483 const int ix = (x & flag) ? 1 : 0;
484 const int iy = (y & flag) ? 2 : 0;
485 const int iz = (z & flag) ? 4 : 0;
486 int i_sous_cube = ix + iy + iz;
487 // Enter the sub-cube:
488 const int_t the_octree_id = octree_structure_(index, i_sous_cube);
489 if (octree_type(the_octree_id) != OCTREE) // floor or empty
490 return the_octree_id;
491
492 index = octree_index(the_octree_id, OCTREE);
493 flag >>= 1;
494 }
495 //return -1; // We never reach here!
496}
497
498
499
500template class Octree_Int_32_64<int>;
501#if INT_is_64_ == 2
502template class Octree_Int_32_64<trustIdType>;
503#endif
int testsetbit(int_t i) const
Returns the value of bit e, then sets bit e to 1.
Definition ArrOfBit.h:85
: An octree allowing retrieval of point-like or parallelepiped-shaped objects in 1D,...
Definition Octree_Int.h:28
int_t search_octree_floor(int x_pos, int y_pos, int z_pos) const
returns the octree_id of the octree_floor containing the vertex (x,y,z) (may return the EMPTY octree)
static Octree_Type octree_type(int_t octree_id)
Returns the type of an octree based on its octree_id.
void search_elements_box_recursively(IntBoxData< _SIZE_ > &boxdata, int_t octree_id, int cx, int cy, int cz, int half_width) const
recursively searches for elements included in the box boxdata for the given octree_id,...
int_t search_elements_box(int xmin, int ymin, int zmin, int xmax, int ymax, int zmax, ArrOfInt_t &elements) const
searches for elements potentially having a non-empty intersection with the box xmin....
ArrOfInt_T< _SIZE_ > ArrOfInt_t
Definition Octree_Int.h:31
IntTab_T< _SIZE_ > IntTab_t
Definition Octree_Int.h:32
ArrOfInt_t floor_elements_
Definition Octree_Int.h:88
int_t build_octree_recursively(const int octree_center_x, const int octree_center_y, const int octree_center_z, const int octree_half_width, const IntTab_t &elements_boxes, ArrsOfInt_t &vect_elements_list, const int level, AOFlagS_ &tmp_elem_flags)
octree_center_i is the first int of the upper half of the octree in direction i.
static const int root_octree_half_width_
Definition Octree_Int.h:50
static int_t octree_id(int_t index, Octree_Type type)
builds an octree_id (see octree_structure_)
TRUSTArray< int, _SIZE_ > AOFlag_
Definition Octree_Int.h:36
int_t root_octree_id_
Definition Octree_Int.h:73
IntTab_t octree_structure_
Definition Octree_Int.h:82
ArrsOfInt_T< _SIZE_ > ArrsOfInt_t
Definition Octree_Int.h:35
int_t search_elements(int x, int y, int z, int_t &floor_elements_index) const
returns the list of elements potentially containing the point (x,y,z). Returns n=number of elements i...
static int_t octree_index(int_t octree_id, Octree_Type type)
computes the index of the octree in octree_structure or floor_elements based on the type of the octre...
void search_elements_box_floor(IntBoxData< _SIZE_ > &boxdata, int_t octree_floor_id) const
adds elements from the octree_floor to boxdata.
TRUST_Vector< AOFlag_ > AOFlagS_
Definition Octree_Int.h:37
static const int coord_max_
Definition Octree_Int.h:48
int_t build_octree_floor(const ArrOfInt_t &elements_list)
builds an octree_floor with the given list of elements and returns the octree_id of that octree_floor
void build(const int dimension, const IntTab_t &elements_boxes)
builds the octree.
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
int dimension_int(int d) const
Definition TRUSTTab.tpp:152
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
ArrOfInt_T< _SIZE_ > ArrOfInt_t
ArrOfInt_t & elements_
ArrOfBit_32_64< _SIZE_ > AOBit_
IntBoxData(int xmin, int ymin, int zmin, int xmax, int ymax, int zmax, ArrOfInt_t &elements, AOBit_ *markers)
AOBit_ * markers_