gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
OctreeInternals.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include <list>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <math.h>
10 #include "GmshMessage.h"
11 #include "OctreeInternals.h"
12 
13 int initializeOctantBuckets(double *_orig, double *_size, int _maxElem,
14  octantBucket **buckets_head,
15  globalInfo **globalPara)
16 // Initialize the buckets
17 // Given by user: orig and size -- information about the domain
18 // maxElem -- maximum number of elements per bucket
19 // Return: buckets -- pointer to the begin of buckets
20 // globalPara -- some info about the buckets
21 // At last, 1 will be returned if succeed, otherwise, return 0
22 {
23  int i, j, k, tmp1;
24  int p = 1;
25  int initial_buckets_num; // which is a number of 8^p form for integer p
26  double tmp[3], error[3];
27  octantBucket *buckets;
28 
29  for(i = 0; i < 3; i++) error[i] = _size[i] * 0.01;
30 
31  initial_buckets_num = (int)pow(8., p); // it is actually 8
32 
33  (*globalPara) = new globalInfo;
34  (*globalPara)->maxPrecision = 1;
35  (*globalPara)->maxElements = _maxElem;
36  (*globalPara)->ptrToPrevElement = nullptr;
37 
38  for(i = 0; i < 3; i++) {
39  (*globalPara)->origin[i] = _orig[i];
40  (*globalPara)->size[i] = _size[i];
41  }
42 
43  (*globalPara)->numBuckets = initial_buckets_num;
44  *buckets_head = new octantBucket;
45  if(!(*buckets_head)) {
46  Msg::Error("Could not allocate octree buckets");
47  return (0);
48  } // if could not allocate buckets
49 
50  buckets = new octantBucket[8];
51  if(!buckets) {
52  Msg::Error("Could not allocate octree buckets");
53  return (0);
54  }
55 
56  (*buckets_head)->next = buckets;
57  (*buckets_head)->parent = nullptr;
58  (*buckets_head)->numElements = 0;
59  (*buckets_head)->lhead = nullptr;
60  (*buckets_head)->precision = 0;
61  for(i = 0; i < 3; i++) {
62  (*buckets_head)->minPt[i] = _orig[i] - error[i];
63  (*buckets_head)->maxPt[i] = _size[i] + _orig[i] + error[i];
64  }
65 
66  for(i = 0; i < (*globalPara)->numBuckets; i++) {
67  buckets[i].numElements = 0;
68  buckets[i].lhead = nullptr;
69  buckets[i].next = nullptr;
70  buckets[i].parent = *buckets_head;
71  buckets[i].precision = 1;
72  }
73 
74  tmp1 = (int)(pow(2., p));
75  for(i = 0; i < 3; i++) {
76  tmp[i] = (double)(_size[i] + 2 * error[i]) / tmp1;
77  }
78 
79  for(k = 0; k < tmp1; k++) {
80  for(j = 0; j < tmp1; j++) {
81  for(i = 0; i < tmp1; i++) {
82  buckets[i + j * tmp1 + k * tmp1 * tmp1].minPt[0] =
83  (*buckets_head)->minPt[0] + tmp[0] * i;
84  buckets[i + j * tmp1 + k * tmp1 * tmp1].minPt[1] =
85  (*buckets_head)->minPt[1] + tmp[1] * j;
86  buckets[i + j * tmp1 + k * tmp1 * tmp1].minPt[2] =
87  (*buckets_head)->minPt[2] + tmp[2] * k;
88  buckets[i + j * tmp1 + k * tmp1 * tmp1].maxPt[0] =
89  (*buckets_head)->minPt[0] + tmp[0] * (i + 1);
90  buckets[i + j * tmp1 + k * tmp1 * tmp1].maxPt[1] =
91  (*buckets_head)->minPt[1] + tmp[1] * (j + 1);
92  buckets[i + j * tmp1 + k * tmp1 * tmp1].maxPt[2] =
93  (*buckets_head)->minPt[2] + tmp[2] * (k + 1);
94  }
95  }
96  }
97 
98 #if 0
99  for (i = 0; i < 8; i++) {
100  printf(" bucket %d : min[0]=%f, min[1]=%f, min[2]=%f, max[0]= %f, max[1]=%f, max[3]=%f\n",
101  i,buckets[i].minPt[0],buckets[i].minPt[1],
102  buckets[i].minPt[2], buckets[i].maxPt[0], buckets[i].maxPt[1],
103  buckets[i].maxPt[2]);
104  printf("bucket elements link list: bucket->lhead = %d\n", buckets[i].lhead);
105  }
106 #endif
107 
108  return (1);
109 }
110 
111 int addElement2Bucket(octantBucket *_bucket, void *_element, double *_minBB,
112  double *_maxBB, double *_ele_centroid,
113  globalInfo *_globalPara)
114 // Add another element to the octant bucket's list.
115 // If the bucket contains too many elements after adding this element,
116 // refine this bucket and reallocate the elements of this bucket
117 // Given:- the octant bucket, - the element
118 // - the element's minimum and maximum x,y,z
119 // - the element's centroid, - global information
120 // Check if element has already been added - if not, return 1
121 // for successfully adding, otherwise return -1
122 {
123  int i, flag = 1;
124  ELink ptr1, ptr2;
125  octantBucket *ptrBucket;
126 
127  // check for duplicates
128  if(checkElementInBucket(_bucket, _element) == 1) return -1;
129 
130  // printf("\n addToBucket...\n");
131  // ptr1 = (ELink) malloc(sizeof(Elem));
132  ptr1 = new Elem;
133  (_globalPara->listAllElements).push_back(_element);
134 
135  ptr1->next = _bucket->lhead;
136  ptr1->region = _element;
137 
138  for(i = 0; i < 3; i++) {
139  ptr1->minPt[i] = _minBB[i];
140  ptr1->maxPt[i] = _maxBB[i];
141  ptr1->centroid[i] = _ele_centroid[i];
142  // printf(" %7.2f->%-7.2f",ptr1->minPt[i], ptr1->maxPt[i]);
143  }
144 
145  _bucket->lhead = ptr1;
146  (_bucket->numElements)++;
147 
148 #if 0
149  printf("bucket element list: bucket->lhead = %d", _bucket->lhead);
150  printf(" numElements = %d\n",_bucket->numElements);
151  printf("the element is add to this bucket: (%f, %f, %f) to (%f, %f, %f)\n",
152  _bucket->minPt[0],_bucket->minPt[1], _bucket->minPt[2], _bucket->maxPt[0],
153  _bucket->maxPt[1], _bucket->maxPt[2]);
154 #endif
155 
156  // check whether the number of elements in the bucket > maxElements
157  // if true, refine the bucket and reallocate the elements
158  while(flag == 1) {
159  flag = 0;
160  if(_bucket->numElements > _globalPara->maxElements) {
161  // printf(" going to subdivide\n");
162 
163  subdivideOctantBucket(_bucket, _globalPara);
164 
165  // printf("finish subdivede \n");
166 
167  ptr1 = _bucket->lhead;
168  while(ptr1 != nullptr) {
169  ptrBucket = findElementBucket(_bucket, ptr1->centroid);
170  ptr2 = ptr1;
171  ptr1 = ptr1->next;
172  if(ptrBucket == nullptr) {
173  Msg::Error("Null bucket in octree");
174  return 0;
175  }
176  ptr2->next = ptrBucket->lhead;
177  ptrBucket->lhead = ptr2;
178  (ptrBucket->numElements)++;
179  if(ptrBucket->numElements > _globalPara->maxElements) {
180  flag = 1;
181  _bucket->lhead = nullptr;
182  _bucket = ptrBucket;
183  }
184  }
185  if(flag == 0) _bucket->lhead = nullptr;
186  }
187  }
188  return 1;
189 }
190 
191 int checkElementInBucket(octantBucket *_bucket, void *_element)
192 // Given an elememt and an octant bucket, check if the element
193 // exists in the bucket's element list. return 1 if already exits,
194 // otherwise, return 0
195 {
196  ELink ptr;
197  for(ptr = _bucket->lhead; ptr != nullptr; ptr = ptr->next) {
198  // changed ****, compare the objected pointed by the void *.
199  if(ptr->region == _element) return 1;
200  }
201  return 0;
202 }
203 
204 octantBucket *findElementBucket(octantBucket *_buckets_head, double *_pt)
205 // Find the leaf bucket which contains the point _pt
206 // given parameter: _buckets --- the point to buckets head
207 // _pt --- the point to find
208 // Return the pointer to the bucket contains the point
209 // if fail, return NULL
210 {
211  int i, j;
212  int num = 8;
213  octantBucket *prevbucket = nullptr;
214  octantBucket *tmpbucket = _buckets_head->next;
215 
216  while(tmpbucket != nullptr) {
217  for(i = 0; i < num; i++) {
218  for(j = 0; j < 3; j++) {
219  if(tmpbucket[i].minPt[j] > _pt[j] || tmpbucket[i].maxPt[j] < _pt[j])
220  break;
221  }
222  if(j == 3) {
223  prevbucket = tmpbucket + i;
224  tmpbucket = tmpbucket[i].next;
225  break;
226  }
227  } // for loop i
228  if(i == num) {
229  // Msg::Error("No bucket contains the given point!");
230  return nullptr;
231  }
232  } // for while loop
233  return prevbucket;
234 }
235 
236 int subdivideOctantBucket(octantBucket *_bucket, globalInfo *_globalPara)
237 // To many elements are in this octant bucket, so try to refine
238 // Returns 1 for success, 0 for failure (no memory left).
239 {
240  int i, j, k, tmp1;
241  int numBuck = 8;
242  double tmp[3];
243 
244  _bucket->next = new octantBucket[8];
245  // _bucket->next = (octantBucket *) calloc(numBuck,sizeof(octantBucket));
246 
247  if(!_bucket->next) {
248  Msg::Error("Could not allocate octree buckets");
249  return 0;
250  }
251 
252  _globalPara->numBuckets += 8;
253  if(_bucket->precision == _globalPara->maxPrecision)
254  _globalPara->maxPrecision++;
255  for(i = 0; i < numBuck; i++) {
256  (_bucket->next[i]).numElements = 0;
257  (_bucket->next[i]).lhead = nullptr;
258  (_bucket->next[i]).next = nullptr;
259  (_bucket->next[i]).parent = _bucket;
260  (_bucket->next[i]).precision = _bucket->precision + 1;
261  }
262 
263  tmp1 = 2;
264  for(i = 0; i < 3; i++) {
265  tmp[i] = ((double)(_bucket->maxPt[i] - _bucket->minPt[i])) / tmp1;
266  }
267 
268  for(k = 0; k < tmp1; k++) {
269  for(j = 0; j < tmp1; j++) {
270  for(i = 0; i < tmp1; i++) {
271  _bucket->next[i + j * tmp1 + k * tmp1 * tmp1].minPt[0] =
272  _bucket->minPt[0] + tmp[0] * i;
273  _bucket->next[i + j * tmp1 + k * tmp1 * tmp1].minPt[1] =
274  _bucket->minPt[1] + tmp[1] * j;
275  _bucket->next[i + j * tmp1 + k * tmp1 * tmp1].minPt[2] =
276  _bucket->minPt[2] + tmp[2] * k;
277  _bucket->next[i + j * tmp1 + k * tmp1 * tmp1].maxPt[0] =
278  _bucket->minPt[0] + tmp[0] * (i + 1);
279  _bucket->next[i + j * tmp1 + k * tmp1 * tmp1].maxPt[1] =
280  _bucket->minPt[1] + tmp[1] * (j + 1);
281  _bucket->next[i + j * tmp1 + k * tmp1 * tmp1].maxPt[2] =
282  _bucket->minPt[2] + tmp[2] * (k + 1);
283  }
284  }
285  }
286 
287  return 1;
288 }
289 
290 void *searchElement(octantBucket *_buckets_head, double *_pt,
291  globalInfo *_globalPara, BBFunction BBElement,
292  InEleFunction xyzInElement)
293 {
294  int flag;
295  octantBucket *ptrBucket;
296  ELink ptr1;
297 
298  void *ptrToEle = nullptr;
299 #pragma omp atomic read
300  ptrToEle = _globalPara->ptrToPrevElement;
301 
302  if(ptrToEle) {
303  flag = xyzInElementBB(_pt, ptrToEle, BBElement);
304  if(flag == 1) flag = xyzInElement(ptrToEle, _pt);
305  if(flag == 1) return ptrToEle;
306  }
307 
308  ptrBucket = findElementBucket(_buckets_head, _pt);
309  if(ptrBucket == nullptr) {
310  // this is not an error
311  // TODO RE ENABLE MSG
312  // Msg::Debug("Could not find point in octree (in search element)");
313  return nullptr;
314  }
315 
316  ptr1 = ptrBucket->lhead;
317 
318 #if 0
319  printf("point %lf %lf %lf has been found in bucket %lf %lf %fl -> %lf %lf %lf %p\n",
320  _pt[0],_pt[1],_pt[2], ptrBucket->minPt[0],ptrBucket->minPt[1],ptrBucket->minPt[2],
321  ptrBucket->maxPt[0],ptrBucket->maxPt[1],ptrBucket->maxPt[2], ptr1);
322  if (ptr1 == nullptr) {
323  printf("empty element list for centroid list!?\n, possible!");
324  }
325 #endif
326 
327  while(ptr1 != nullptr) {
328  flag = xyzInElementBB(_pt, ptr1->region, BBElement);
329  if(flag == 1) flag = xyzInElement(ptr1->region, _pt);
330  if(flag == 1) {
331 #pragma omp atomic write
332  _globalPara->ptrToPrevElement = ptr1->region;
333  return ptr1->region;
334  }
335  ptr1 = ptr1->next;
336  }
337 
338  for(auto iter = (ptrBucket->listBB).begin(); iter != (ptrBucket->listBB).end();
339  iter++) {
340  flag = xyzInElementBB(_pt, *iter, BBElement);
341  if(flag == 1) flag = xyzInElement(*iter, _pt);
342  if(flag == 1) {
343 #pragma omp atomic write
344  _globalPara->ptrToPrevElement = *iter;
345  return *iter;
346  }
347  }
348 
349  // printf("This point is not found in all elements! It is not in the domain
350  // \n");
351  return nullptr;
352 }
353 
354 int xyzInElementBB(double *_xyz, void *_region, BBFunction _bbElement)
355 // Check if xyz is in the region's bounding box, return 1 if true, 0 otherwise
356 // BBElement is the function given by user to find the bounding box
357 {
358  int i;
359  double minPt[3]; // corner with smallest x,y,z coords
360  double maxPt[3]; // corner with largest x,y,z coords
361 
362  (*_bbElement)(_region, minPt, maxPt);
363 
364  for(i = 0; i < 3; i++) {
365  if(_xyz[i] > maxPt[i] || _xyz[i] < minPt[i]) return 0;
366  } // for ith direction
367 
368  return 1;
369 }
370 
371 void insertOneBB(void *_region, double *_minPt, double *_maxPt,
372  octantBucket *_bucket)
373 {
374  int i;
375  ELink ptr;
376  for(i = 0; i < 3; i++) {
377  if(_bucket->minPt[i] > _maxPt[i] || _bucket->maxPt[i] < _minPt[i]) return;
378  }
379  if(_bucket->next == nullptr) {
380  ptr = _bucket->lhead;
381  while(ptr != nullptr) {
382  if(ptr->region == _region) return;
383  ptr = ptr->next;
384  }
385 
386  //_bucket->listBB.insert(_bucket->listBB.end(),_region);
387  _bucket->listBB.push_back(_region);
388  return;
389  }
390 
391  for(i = 0; i < 8; i++)
392  insertOneBB(_region, _minPt, _maxPt, _bucket->next + i);
393  return;
394 }
395 
396 void *searchAllElements(octantBucket *_buckets_head, double *_pt,
397  globalInfo *_globalPara, BBFunction BBElement,
398  InEleFunction xyzInElement,
399  std::vector<void *> *_elements)
400 {
401  int flag, flag1;
402  octantBucket *ptrBucket;
403 
404  ptrBucket = findElementBucket(_buckets_head, _pt);
405  if(ptrBucket == nullptr) {
406  Msg::Debug("Could not find point in octree (in search all elements)");
407  return nullptr;
408  }
409 
410 #if 0
411  printf("point %lf %lf %lf has been found in bucket %lf %lf %fl -> %lf %lf %lf %p\n",
412  _pt[0],_pt[1],_pt[2], ptrBucket->minPt[0],ptrBucket->minPt[1],ptrBucket->minPt[2],
413  ptrBucket->maxPt[0],ptrBucket->maxPt[1],ptrBucket->maxPt[2], ptr1);
414 
415  if (ptr1 == nullptr) {
416  printf("empty element list for centroid list!?\n, possible!");
417  }
418 #endif
419 
420  flag1 = 0;
421  ELink ptr1 = ptrBucket->lhead;
422  while(ptr1 != nullptr) {
423  flag = xyzInElementBB(_pt, ptr1->region, BBElement);
424  if(flag == 1) flag = xyzInElement(ptr1->region, _pt);
425  if(flag == 1) {
426  _elements->push_back(ptr1->region);
427  flag1 = 1;
428  }
429  ptr1 = ptr1->next;
430  }
431 
432  for(auto iter = (ptrBucket->listBB).begin(); iter != (ptrBucket->listBB).end();
433  iter++) {
434  flag = xyzInElementBB(_pt, *iter, BBElement);
435  if(flag == 1) flag = xyzInElement(*iter, _pt);
436  if(flag == 1) {
437  _elements->push_back(*iter);
438  flag1 = 1;
439  }
440  }
441 
442  if(flag1) return (void *)(_elements);
443 
444  // Msg::Warning("This point is not found in any element! It is not in the
445  // domain");
446  return nullptr;
447 }
global
Definition: OctreeInternals.h:40
globalInfo
struct global globalInfo
Definition: OctreeInternals.h:49
OctreeInternals.h
elem::next
struct elem * next
Definition: OctreeInternals.h:22
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
bucket
Definition: OctreeInternals.h:27
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
initializeOctantBuckets
int initializeOctantBuckets(double *_orig, double *_size, int _maxElem, octantBucket **buckets_head, globalInfo **globalPara)
Definition: OctreeInternals.cpp:13
elem::maxPt
double maxPt[3]
Definition: OctreeInternals.h:21
bucket::minPt
double minPt[3]
Definition: OctreeInternals.h:28
GmshMessage.h
addElement2Bucket
int addElement2Bucket(octantBucket *_bucket, void *_element, double *_minBB, double *_maxBB, double *_ele_centroid, globalInfo *_globalPara)
Definition: OctreeInternals.cpp:111
findElementBucket
octantBucket * findElementBucket(octantBucket *_buckets_head, double *_pt)
Definition: OctreeInternals.cpp:204
octantBucket
struct bucket octantBucket
Definition: OctreeInternals.h:37
xyzInElementBB
int xyzInElementBB(double *_xyz, void *_region, BBFunction _bbElement)
Definition: OctreeInternals.cpp:354
InEleFunction
int(* InEleFunction)(void *, double *)
Definition: OctreeInternals.h:13
Elem
struct elem Elem
bucket::lhead
ELink lhead
Definition: OctreeInternals.h:32
elem::region
void * region
Definition: OctreeInternals.h:18
bucket::numElements
int numElements
Definition: OctreeInternals.h:30
global::maxElements
int maxElements
Definition: OctreeInternals.h:42
bucket::next
struct bucket * next
Definition: OctreeInternals.h:34
searchElement
void * searchElement(octantBucket *_buckets_head, double *_pt, globalInfo *_globalPara, BBFunction BBElement, InEleFunction xyzInElement)
Definition: OctreeInternals.cpp:290
bucket::parent
struct bucket * parent
Definition: OctreeInternals.h:35
BBFunction
void(* BBFunction)(void *, double *, double *)
Definition: OctreeInternals.h:12
bucket::listBB
std::vector< void * > listBB
Definition: OctreeInternals.h:33
bucket::maxPt
double maxPt[3]
Definition: OctreeInternals.h:29
subdivideOctantBucket
int subdivideOctantBucket(octantBucket *_bucket, globalInfo *_globalPara)
Definition: OctreeInternals.cpp:236
searchAllElements
void * searchAllElements(octantBucket *_buckets_head, double *_pt, globalInfo *_globalPara, BBFunction BBElement, InEleFunction xyzInElement, std::vector< void * > *_elements)
Definition: OctreeInternals.cpp:396
elem::minPt
double minPt[3]
Definition: OctreeInternals.h:20
global::numBuckets
int numBuckets
Definition: OctreeInternals.h:41
checkElementInBucket
int checkElementInBucket(octantBucket *_bucket, void *_element)
Definition: OctreeInternals.cpp:191
bucket::precision
int precision
Definition: OctreeInternals.h:31
insertOneBB
void insertOneBB(void *_region, double *_minPt, double *_maxPt, octantBucket *_bucket)
Definition: OctreeInternals.cpp:371
elem::centroid
double centroid[3]
Definition: OctreeInternals.h:19
global::ptrToPrevElement
void * ptrToPrevElement
Definition: OctreeInternals.h:46
global::maxPrecision
int maxPrecision
Definition: OctreeInternals.h:43
elem
Definition: OctreeInternals.h:17
global::listAllElements
std::vector< void * > listAllElements
Definition: OctreeInternals.h:47