OOFEM  2.4
OOFEM.org - Object Oriented Finite Element Solver
octreelocalizer.C
Go to the documentation of this file.
1 /*
2  *
3  * ##### ##### ###### ###### ### ###
4  * ## ## ## ## ## ## ## ### ##
5  * ## ## ## ## #### #### ## # ##
6  * ## ## ## ## ## ## ## ##
7  * ## ## ## ## ## ## ## ##
8  * ##### ##### ## ###### ## ##
9  *
10  *
11  * OOFEM : Object Oriented Finite Element Code
12  *
13  * Copyright (C) 1993 - 2013 Borek Patzak
14  *
15  *
16  *
17  * Czech Technical University, Faculty of Civil Engineering,
18  * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19  *
20  * This library is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2.1 of the License, or (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * Lesser General Public License for more details.
29  *
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the Free Software
32  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33  */
34 
35 #include "octreelocalizer.h"
36 #include "element.h"
37 #include "domain.h"
38 #include "integrationrule.h"
39 #include "gausspoint.h"
40 #include "dofmanager.h"
41 #include "node.h"
42 #include "connectivitytable.h"
43 #include "mathfem.h"
44 #include "timer.h"
45 #include "error.h"
47 
48 #include <iostream>
49 
50 namespace oofem {
51 OctantRec :: OctantRec(OctreeSpatialLocalizer *loc, OctantRec *parent, FloatArray &origin, double halfWidth) :
52  localizer(loc),
53  parent(parent),
54  origin(origin),
55  halfWidth(halfWidth)
56 {
57  this->depth = parent ? parent->giveCellDepth() + 1 : 0;
58 
59  for ( int i = 0; i <= 1; i++ ) {
60  for ( int j = 0; j <= 1; j++ ) {
61  for ( int k = 0; k <= 1; k++ ) {
62  this->child [ i ] [ j ] [ k ] = NULL;
63  }
64  }
65  }
66 }
67 
69 {
70  // destructor - delete all receivers children recursively
71  // delete children first, then itself
72  for ( int i = 0; i <= 1; i++ ) {
73  for ( int j = 0; j <= 1; j++ ) {
74  for ( int k = 0; k <= 1; k++ ) {
75  if ( this->child [ i ] [ j ] [ k ] ) {
76  delete this->child [ i ] [ j ] [ k ];
77  }
78  }
79  }
80  }
81 }
82 
83 std :: list< int > &
85 {
86  return nodeList;
87 }
88 
89 IntArray &
91 {
92  return elementIPList;
93 }
94 
95 std :: list< int > &
97 {
98  if ( (int)elementList.size() < region + 1 ) {
99  elementList.resize(region + 1);
100  }
101  return elementList[region];
102 }
103 
104 
105 OctantRec *
106 OctantRec :: giveChild(int xi, int yi, int zi)
107 {
108  if ( ( xi >= 0 ) && ( xi < 2 ) && ( yi >= 0 ) && ( yi < 2 ) && ( zi >= 0 ) && ( zi < 2 ) ) {
109  return this->child [ xi ] [ yi ] [ zi ];
110  } else {
111  OOFEM_ERROR("invalid child index (%d,%d,%d)", xi, yi, zi);
112  }
113 
114  return NULL;
115 }
116 
117 
120 {
121  IntArray ind(3);
122 
123  if ( this->isTerminalOctant() ) {
124  * child = NULL;
125  return CS_NoChild;
126  }
127 
128  for ( int i = 1; i <= coords.giveSize(); ++i ) {
129  ind.at(i) = localizer->giveOctreeMaskValue(i) && coords.at(i) > this->origin.at(i);
130  }
131 
132  * child = this->child [ ind.at(1) ] [ ind.at(2) ] [ ind.at(3) ];
133  return CS_ChildFound;
134 }
135 
136 
137 bool
139 {
140  // This implementation is relying on fact, that child [0][0][0]
141  // is created even for all degenerated trees
142  if ( this->child [ 0 ] [ 0 ] [ 0 ] ) {
143  return false;
144  }
145 
146  return true;
147 }
148 
149 
150 void
151 OctantRec :: divideLocally(int level, const IntArray &octantMask)
152 {
153  if ( this->isTerminalOctant() ) {
154  // create corresponding child octants
155  FloatArray childOrigin(3);
156 
157  for ( int i = 0; i <= octantMask.at(1); i++ ) {
158  for ( int j = 0; j <= octantMask.at(2); j++ ) {
159  for ( int k = 0; k <= octantMask.at(3); k++ ) {
160  childOrigin.at(1) = this->origin.at(1) + ( i - 0.5 ) * this->halfWidth * octantMask.at(1);
161  childOrigin.at(2) = this->origin.at(2) + ( j - 0.5 ) * this->halfWidth * octantMask.at(2);
162  childOrigin.at(3) = this->origin.at(3) + ( k - 0.5 ) * this->halfWidth * octantMask.at(3);
163  this->child [ i ] [ j ] [ k ] = new OctantRec(localizer, this, childOrigin, this->halfWidth * 0.5);
164  }
165  }
166  }
167  }
168 
169  int newLevel = level - 1;
170  if ( newLevel > 0 ) {
171  // propagate message to children recursively with level param decreased
172  for ( int i = 0; i <= octantMask.at(1); i++ ) {
173  for ( int j = 0; j <= octantMask.at(2); j++ ) {
174  for ( int k = 0; k <= octantMask.at(3); k++ ) {
175  if ( this->child [ i ] [ j ] [ k ] ) {
176  this->child [ i ] [ j ] [ k ]->divideLocally(newLevel, octantMask);
177  }
178  }
179  }
180  }
181  }
182 }
183 
184 
186 OctantRec :: testBoundingBox(const FloatArray &coords, double radius)
187 {
188  int size = coords.giveSize();
189  double bb0, bb1;
190  double oct0, oct1;
191  bool bbInside = true;
192 
193  for ( int i = 1; i <= size; i++ ) {
194  if ( localizer->giveOctreeMaskValue(i) ) {
195  bb0 = coords.at(i) - radius;
196  bb1 = coords.at(i) + radius;
197  oct0 = this->origin.at(i) - this->halfWidth;
198  oct1 = this->origin.at(i) + this->halfWidth;
199 
200  if ( oct1 < bb0 || oct0 > bb1 ) { // Then its definitely outside, no need to go on
201  return BBS_OutsideCell;
202  }
203  // Other cases; We first check if bb is completely inside the cell, in every spatial dimension
204  bbInside = bbInside && oct0 < bb0 && oct1 > bb1;
205  }
206  }
207  return bbInside ? BBS_InsideCell : BBS_ContainsCell;
208 }
209 
210 
212 {
213  if ( this->isTerminalOctant() ) {
214  std :: cout << " center = {" << this->origin.at(1) << "," << this->origin.at(2) << "," << this->origin.at(3)
215  << "} size = " << ( this->halfWidth * 2. ) << " nodes = " << this->nodeList.size() << " elem_ips = " << this->elementIPList.giveSize() << "\n";
216  } else {
217  if ( this->depth == 0 ) {
218  printf("*ROOTCELL*");
219  }
220  printf("\n");
221  for ( int i = 0; i <= 1; i++ ) {
222  for ( int j = 0; j <= 1; j++ ) {
223  for ( int k = 0; k <= 1; k++ ) {
224  if ( this->child [ i ] [ j ] [ k ] ) {
225  for ( int q = 0; q < this->depth - 1; q++ ) {
226  printf(" ");
227  }
228  printf("+");
229  this->child [ i ] [ j ] [ k ]->printYourself();
230  }
231  }
232  }
233  }
234  }
235 }
236 
237 
238 
239 
241 {
242  rootCell = NULL;
245 }
246 
247 
249 {
250  delete rootCell;
251 }
252 
253 
254 OctantRec *
256 {
258  OctantRec *currCell = startCell;
259  // found terminal octant containing node
260  while ( !currCell->isTerminalOctant() ) {
261  result = currCell->giveChildContainingPoint(& currCell, coords);
262  if ( result == OctantRec :: CS_NoChild ) {
263  OOFEM_ERROR("internal error - octree inconsistency");
264  }
265  }
266  return currCell;
267 }
268 
269 
270 bool
272 {
273 // OOFEM_LOG_INFO("Initializing Octree structure\n");
274  int init = 1, nnode = this->domain->giveNumberOfDofManagers();
275  double rootSize, resolutionLimit;
276  FloatArray minc(3), maxc(3), * coords;
277  DofManager *dman;
278  Node *node;
279 
280  // test if tree already built
281  if ( rootCell ) {
282  return true;
283  }
284 
287  this->elementIPListsInitialized = false;
288 
289  // measure time consumed by octree build phase
290  Timer timer;
291  timer.startTimer();
292 
293  // first determine domain extends (bounding box), and check for degenerated domain type
294  for ( int i = 1; i <= nnode; i++ ) {
295  dman = domain->giveDofManager(i);
296  node = dynamic_cast< Node * >(dman);
297  if ( node ) {
298  coords = node->giveCoordinates();
299  if ( init ) {
300  init = 0;
301  for ( int j = 1; j <= coords->giveSize(); j++ ) {
302  minc.at(j) = maxc.at(j) = coords->at(j);
303  }
304  } else {
305  for ( int j = 1; j <= coords->giveSize(); j++ ) {
306  if ( coords->at(j) < minc.at(j) ) {
307  minc.at(j) = coords->at(j);
308  }
309 
310  if ( coords->at(j) > maxc.at(j) ) {
311  maxc.at(j) = coords->at(j);
312  }
313  }
314  }
315  }
316  } // end loop over nodes
317 
318  // determine root size
319  rootSize = 0.0;
320  for ( int i = 1; i <= 3; i++ ) {
321  rootSize = 1.000001 * max( rootSize, maxc.at(i) - minc.at(i) );
322  }
323 
324  // check for degenerated domain
325  resolutionLimit = min(1.e-3, rootSize / 1.e6);
326  for ( int i = 1; i <= 3; i++ ) {
327  if ( ( maxc.at(i) - minc.at(i) ) > resolutionLimit ) {
328  this->octreeMask.at(i) = 1;
329  } else {
330  this->octreeMask.at(i) = 0;
331  }
332  }
333 
334  // Create root Octant
335  FloatArray center = minc;
336  center.add(maxc);
337  center.times(0.5);
338  this->rootCell = new OctantRec(this, NULL, center, rootSize * 0.5);
339 
340  // Build octree tree
341  if ( nnode > OCTREE_MAX_NODES_LIMIT ) {
342  this->rootCell->divideLocally(1, this->octreeMask);
343  }
344 
345  // insert domain nodes into tree
346  for ( int i = 1; i <= nnode; i++ ) {
347  dman = domain->giveDofManager(i);
348  node = dynamic_cast< Node * >(dman);
349  if ( node ) {
350  coords = node->giveCoordinates();
351  this->insertNodeIntoOctree(this->rootCell, i, * coords);
352  }
353  }
354 
355  timer.stopTimer();
356 
357  // compute max. tree depth
358  int treeDepth = 0;
359  this->giveMaxTreeDepthFrom(this->rootCell, treeDepth);
360  OOFEM_LOG_DEBUG( "Octree init [depth %d in %.2fs]\n", treeDepth, timer.getUtime() );
361 
362  return true;
363 }
364 
365 
366 void
368 {
369  // Original implementation
370  //
371  int nelems = this->domain->giveNumberOfElements();
372  FloatArray jGpCoords;
373 
374  if ( this->elementIPListsInitialized ) {
375  return;
376  }
377 
378  // insert IP records into tree (the tree topology is determined by nodes)
379  for ( int i = 1; i <= nelems; i++ ) {
380  // only default IP are taken into account
381  Element *ielem = this->giveDomain()->giveElement(i);
382  if ( ielem->giveNumberOfIntegrationRules() > 0 ) {
383  for ( GaussPoint *jGp: *ielem->giveDefaultIntegrationRulePtr() ) {
384  if ( ielem->computeGlobalCoordinates( jGpCoords, jGp->giveNaturalCoordinates() ) ) {
385  this->insertIPElementIntoOctree(this->rootCell, i, jGpCoords);
386  } else {
387  OOFEM_ERROR("computeGlobalCoordinates failed");
388  }
389  }
390  }
391  // there are no IP (belonging to default integration rule of an element)
392  // but the element should be present in octree data structure
393  // this is needed by some services (giveElementContainingPoint, for example)
394  for ( int j = 1; j <= ielem->giveNumberOfNodes(); j++ ) {
395  FloatArray *nc = ielem->giveNode(j)->giveCoordinates();
396  this->insertIPElementIntoOctree(this->rootCell, i, * nc);
397  }
398  }
399 
400  // Initializes the element lists in octree data structure.
401  // This implementation requires that the list of nodes in terminate cells exists
402  // simply all shared elements to nodes in terminal cell are added.
403  // If this is added to existing implementation based on adding elements only if integration point is in the cell
404  // This leads to more complete element list in terminal cell.
405  // Can improve the searching for background element, but will deteriorate
406  // the performance of closest IP search and search of elements in given volume.
407 
408  // Note: since in general, the integration point of an element may fall into
409  // an octant, where are not the element nodes, the original algorithm is
410  // necessary.
411 
412  //this->insertElementsUsingNodalConnectivitiesIntoOctree (this->rootCell);
413  this->elementIPListsInitialized = true;
414 }
415 
416 
417 void
419 {
420  OctantRec *currCell;
421  // found terminal octant containing IP
422  currCell = this->findTerminalContaining(rootCell, coords);
423  currCell->addElementIP(elemNum);
424 }
425 
426 
427 void
429 {
430  FloatArray b0, b1;
431 
432  this->init();
433  if ( this->elementListsInitialized.giveSize() >= region + 1 && this->elementListsInitialized(region) ) {
434  return;
435  }
436 
437  for ( int i = 1; i <= this->domain->giveNumberOfElements(); i++ ) {
438  Element *ielem = this->giveDomain()->giveElement(i);
439  if ( ielem->giveRegionNumber() == region || region == 0 ) {
440  SpatialLocalizerInterface *interface = static_cast< SpatialLocalizerInterface * >( ielem->giveInterface(SpatialLocalizerInterfaceType) );
441  if ( interface ) {
442  interface->SpatialLocalizerI_giveBBox(b0, b1);
443  this->insertElementIntoOctree(this->rootCell, region, i, b0, b1);
444  }
445  }
446  }
447  this->elementListsInitialized(region) = true;
448 }
449 
450 
451 void
453 {
454  // Compare the bounding box corners to the center to determine which region is overlaps
455  // Checks: b0 <= center, b1 >= center for each entry.
456  // This is bundled into an array for more convenient code in the loop.
457  IntArray bbc [ 2 ] = {
458  IntArray(3), IntArray(3)
459  };
460  FloatArray origin = rootCell->giveOrigin();
461  for ( int i = 1; i <= b0.giveSize(); i++ ) {
462  if ( this->octreeMask.at(i) ) {
463  bbc [ 0 ].at(i) = b0.at(i) <= origin.at(i);
464  bbc [ 1 ].at(i) = b1.at(i) >= origin.at(i);
465  } else {
466  bbc [ 0 ].at(i) = bbc [ 1 ].at(i) = true;
467  }
468  }
469  for ( int i = b0.giveSize() + 1; i <= 3; i++ ) {
470  bbc [ 0 ].at(i) = bbc [ 1 ].at(i) = true;
471  }
472  // Check terminal or recurse
473  if ( rootCell->isTerminalOctant() ) {
474  rootCell->addElement(region, elemNum);
475  } else {
476  // The for loops below check if the bounding box overlaps the region before or after the cell center
477  // e.g. when i = 0, then we check for the children that have x-coordinate <= than root center
478  for ( int i = 0; i <= octreeMask.at(1); i++ ) {
479  if ( bbc [ i ].at(1) ) {
480  for ( int j = 0; j <= octreeMask.at(2); j++ ) {
481  if ( bbc [ j ].at(2) ) {
482  for ( int k = 0; k <= octreeMask.at(3); k++ ) {
483  if ( bbc [ k ].at(3) && rootCell->giveChild(i, j, k) ) {
484  this->insertElementIntoOctree(rootCell->giveChild(i, j, k), region, elemNum, b0, b1);
485  }
486  }
487  }
488  }
489  }
490  }
491  }
492 }
493 
494 
495 void
497 {
498  if ( currCell->isTerminalOctant() ) {
499  for ( int inod: currCell->giveNodeList() ) {
500  // loop over cell nodes and ask connectivity table for shared elements
501  const IntArray *dofmanConnectivity = domain->giveConnectivityTable()->giveDofManConnectivityArray(inod);
502  if ( dofmanConnectivity ) {
503  for ( int d: *dofmanConnectivity ) {
504  currCell->addElementIP( d );
505  }
506  }
507  }
508  } else {
509  for ( int i = 0; i <= octreeMask.at(1); i++ ) {
510  for ( int j = 0; j <= octreeMask.at(2); j++ ) {
511  for ( int k = 0; k <= octreeMask.at(3); k++ ) {
512  if ( currCell->giveChild(i, j, k) ) {
514  }
515  }
516  }
517  }
518  }
519 }
520 
521 
522 void
524 {
525  int nCellItems, cellDepth;
527  OctantRec *currCell;
528 
529  // found terminal octant containing node
530  currCell = this->findTerminalContaining(rootCell, coords);
531  // request cell node list
532  nodeContainerType &cellNodeList = currCell->giveNodeList();
533  nCellItems = cellNodeList.size();
534  cellDepth = currCell->giveCellDepth();
535  // check for refinement criteria
536  // should also include max refinement level criteria
537  //
538  if ( ( nCellItems > OCTREE_MAX_NODES_LIMIT ) && ( cellDepth <= OCTREE_MAX_DEPTH ) ) {
539  // refine tree one level
540  currCell->divideLocally(1, this->octreeMask);
541  // propagate all nodes already assigned to currCell to children
542  for ( int inod: cellNodeList ) {
543  Node *node = domain->giveNode(inod);
544  FloatArray *nodeCoords = node->giveCoordinates();
545  this->insertNodeIntoOctree(currCell, inod, * nodeCoords);
546  }
547 
548  // remove node list at relative root cell
549  currCell->deleteNodeList();
550  // now the new node record is saved simply to one of created children.
551  // Generally, one has to check if child is candidate for further refinement
552  // (case, when all parent nodes are belonging to particular child), refine it
553  // and check children again. This can be implemented by recursive procedure, but
554  // probability of this case is relatively small.
555  // Current implementation simply insert node to child created in first refinement,
556  // which can lead ne node violation of refinement criteria.
557  // But implementation is simple and effective.
558  // Please note, that the next insertion in particular cell cause the refinement.
559 
560  // find child containing new node
561  result = currCell->giveChildContainingPoint(& currCell, coords);
562  if ( result != OctantRec :: CS_ChildFound ) {
563  OOFEM_ERROR("internal error - octree inconsistency");
564  }
565  this->insertNodeIntoOctree(currCell, nodeNum, coords);
566  } else {
567  currCell->addNode(nodeNum);
568  }
569 }
570 
571 
572 Element *
574 {
575  OctantRec *currCell, *childCell = NULL;
576 
577  this->init();
579 
580  // found terminal octant containing point
581  currCell = this->findTerminalContaining(rootCell, coords);
582 
583  while ( currCell != NULL ) {
584  // loop over all elements in currCell, skip search on child cell already scanned
585  Element *answer = this->giveElementContainingPoint(currCell, coords, childCell, regionList);
586  if ( answer ) {
587  return answer;
588  }
589 
590  childCell = currCell;
591  // terminal cell does not contain node and its connected elements containing the given point
592  // search at parent level
593  currCell = currCell->giveParent();
594  }
595 
596  // there isn't any element containing point.
597  return NULL;
598 }
599 
600 Element *
602 {
603  OctantRec *currCell, *childCell = NULL;
604 
605  this->init();
607 
608  // found terminal octant containing point
609  currCell = this->findTerminalContaining(rootCell, coords);
610 
611  while ( currCell != NULL ) {
612  // loop over all elements in currCell, skip search on child cell already scanned
613  Element *answer = this->giveElementContainingPoint(currCell, coords, childCell, & eset);
614  if ( answer ) {
615  return answer;
616  }
617 
618  childCell = currCell;
619  // terminal cell does not contain node and its connected elements containing the given point
620  // search at parent level
621  currCell = currCell->giveParent();
622  }
623 
624  // there isn't any element containing point.
625  return NULL;
626 }
627 
628 
629 Element *
631  OctantRec *scannedChild, const IntArray *regionList)
632 {
633  elementContainerType &elementList = cell->giveIPElementList();
634 
635  // recursive implementation
636  if ( cell->isTerminalOctant() && ( !elementList.isEmpty() ) ) {
637 
638  for ( int iel: elementList ) {
639  Element *ielemptr = this->giveDomain()->giveElement(iel);
640 
641  /* HUHU CHEATING */
642  if ( ielemptr->giveParallelMode() == Element_remote ) {
643  continue;
644  }
645 
646  SpatialLocalizerInterface *interface = static_cast< SpatialLocalizerInterface * >( ielemptr->giveInterface(SpatialLocalizerInterfaceType) );
647  if ( interface ) {
648  if ( regionList && ( regionList->findFirstIndexOf( ielemptr->giveRegionNumber() ) == 0 ) ) {
649  continue;
650  }
651 
652  if ( interface->SpatialLocalizerI_BBoxContainsPoint(coords) == 0 ) {
653  continue;
654  }
655 
656  if ( interface->SpatialLocalizerI_containsPoint(coords) ) {
657  return ielemptr;
658  }
659  }
660  }
661 
662  return NULL;
663  } else {
664  Element *answer;
665  // receiver is not terminal octant -> call same service on childs
666  for ( int i = 0; i <= octreeMask.at(1); i++ ) {
667  for ( int j = 0; j <= octreeMask.at(2); j++ ) {
668  for ( int k = 0; k <= octreeMask.at(3); k++ ) {
669  if ( cell->giveChild(i, j, k) ) {
670  if ( scannedChild == cell->giveChild(i, j, k) ) {
671  continue;
672  }
673 
674  answer = this->giveElementContainingPoint(cell->giveChild(i, j, k), coords, NULL, regionList);
675  if ( answer ) {
676  return answer;
677  }
678  }
679  }
680  }
681  }
682  }
683 
684  return NULL;
685 }
686 
687 Element *
689  OctantRec *scannedChild, const Set *eset)
690 {
691  elementContainerType &elementList = cell->giveIPElementList();
692 
693  // recursive implementation
694  if ( cell->isTerminalOctant() && ( !elementList.isEmpty() ) ) {
695 
696  for ( int iel: elementList ) {
697  Element *ielemptr = this->giveDomain()->giveElement(iel);
698 
699  /* HUHU CHEATING */
700  if ( ielemptr->giveParallelMode() == Element_remote ) {
701  continue;
702  }
703 
704  SpatialLocalizerInterface *interface = static_cast< SpatialLocalizerInterface * >( ielemptr->giveInterface(SpatialLocalizerInterfaceType) );
705  if ( interface ) {
706  if ( eset && ( !eset->hasElement( ielemptr->giveNumber() ) ) ) {
707  continue;
708  }
709 
710  if ( interface->SpatialLocalizerI_BBoxContainsPoint(coords) == 0 ) {
711  continue;
712  }
713 
714  if ( interface->SpatialLocalizerI_containsPoint(coords) ) {
715  return ielemptr;
716  }
717  }
718  }
719 
720  return NULL;
721  } else {
722  // receiver is not terminal octant -> call same service on childs
723  for ( int i = 0; i <= octreeMask.at(1); i++ ) {
724  for ( int j = 0; j <= octreeMask.at(2); j++ ) {
725  for ( int k = 0; k <= octreeMask.at(3); k++ ) {
726  if ( cell->giveChild(i, j, k) ) {
727  if ( scannedChild == cell->giveChild(i, j, k) ) {
728  continue;
729  }
730 
731  Element *answer = this->giveElementContainingPoint(cell->giveChild(i, j, k), coords, NULL, eset);
732  if ( answer ) {
733  return answer;
734  }
735  }
736  }
737  }
738  }
739  }
740 
741  return NULL;
742 }
743 
744 
745 Element *
747  const FloatArray &gcoords, int region)
748 {
749  Element *answer = NULL;
750  std :: list< OctantRec * >cellList;
751  OctantRec *currCell;
752  double radius, prevRadius;
753  FloatArray c = this->rootCell->giveOrigin();
754 
755  this->initElementDataStructure(region);
756 
757  // Maximum distance given coordinate and furthest terminal cell ( center_distance + width/2*sqrt(3) )
758  double minDist = c.distance(gcoords) + this->rootCell->giveWidth() * 0.87;
759 
760 
761  // found terminal octant containing point
762  currCell = this->findTerminalContaining(rootCell, gcoords);
763 
764  // Look in center, then expand.
765  this->giveElementClosestToPointWithinOctant(currCell, gcoords, minDist, lcoords, closest, answer, region);
766  prevRadius = 0.;
767  radius = currCell->giveWidth();
768  while ( radius < minDist ) {
769  this->giveListOfTerminalCellsInBoundingBox(cellList, gcoords, radius, prevRadius, this->rootCell);
770  for ( OctantRec *icell: cellList ) {
771  this->giveElementClosestToPointWithinOctant(icell, gcoords, minDist, lcoords, closest, answer, region);
772  }
773  prevRadius = radius;
774  radius *= 2.; // Keep expanding the scope until the radius is larger than the entire root cell, then give up (because we have checked every possible cell)
775  }
776  return answer;
777 }
778 
779 
780 void
782  double &minDist, FloatArray &lcoords, FloatArray &closest, Element * &answer, int region)
783 {
784  double currDist;
785  FloatArray currLcoords;
786  FloatArray currClosest;
787 
788  std :: list<int> &elementList = currCell->giveElementList(region);
789  if ( !elementList.empty() ) {
790  for ( int iel: elementList ) {
791  Element *ielemptr = this->giveDomain()->giveElement(iel);
792 
793  if ( ielemptr->giveParallelMode() == Element_remote ) {
794  continue;
795  }
796 
797  SpatialLocalizerInterface *interface = static_cast< SpatialLocalizerInterface * >( ielemptr->giveInterface(SpatialLocalizerInterfaceType) );
798  if ( region > 0 && ielemptr->giveRegionNumber() != region ) {
799  continue;
800  }
801  currDist = interface->SpatialLocalizerI_giveClosestPoint(currLcoords, currClosest, gcoords);
802  if ( currDist < minDist ) {
803  lcoords = currLcoords;
804  closest = currClosest;
805  answer = ielemptr;
806  minDist = currDist;
807  }
808  }
809  if ( minDist == 0.0 ) {
810  return;
811  }
812  }
813 }
814 
815 
816 GaussPoint *
817 OctreeSpatialLocalizer :: giveClosestIP(const FloatArray &coords, int region, bool iCohesiveZoneGP)
818 {
819  double minDist;
820  OctantRec *currCell;
821  GaussPoint *nearestGp = NULL;
823  FloatArray jGpCoords;
824 
825  this->init();
827 
828  // list of already tested elements
829  // elementContainerType visitedElems;
830  minDist = 1.1 * rootCell->giveWidth();
831  // found terminal octant containing point
832  currCell = this->findTerminalContaining(rootCell, coords);
833  elementContainerType &elementList = currCell->giveIPElementList();
834  // find nearest ip in this terminal cell
835 
836  for ( int iel: elementList ) {
837  Element *ielem = domain->giveElement(iel);
838 
839  /* HUHU CHEATING */
840  if ( ielem->giveParallelMode() == Element_remote ) {
841  continue;
842  }
843 
844  //igp = ipContainer[i].giveGp();
845  if ( ( region > 0 ) && ( region != ielem->giveRegionNumber() ) ) {
846  continue;
847  }
848 
849  if ( !iCohesiveZoneGP ) {
850  // test if element already visited
851  // if (!visitedElems.insert(*pos).second) continue;
852  for ( GaussPoint *jGp: *ielem->giveDefaultIntegrationRulePtr() ) {
853  if ( ielem->computeGlobalCoordinates( jGpCoords, jGp->giveNaturalCoordinates() ) ) {
854  // compute distance
855  double dist = coords.distance(jGpCoords);
856  if ( dist < minDist ) {
857  minDist = dist;
858  nearestGp = jGp;
859  }
860  } else {
861  OOFEM_ERROR("computeGlobalCoordinates failed");
862  }
863  }
864  } else {
866  // Check for cohesive zone Gauss points
867  XfemElementInterface *xFemEl = dynamic_cast< XfemElementInterface * >(ielem);
868 
869  if ( xFemEl != NULL ) {
870  size_t numCZRules = xFemEl->mpCZIntegrationRules.size();
871  for ( size_t czRuleIndex = 0; czRuleIndex < numCZRules; czRuleIndex++ ) {
872  std :: unique_ptr< IntegrationRule > &iRule = xFemEl->mpCZIntegrationRules [ czRuleIndex ];
873  if ( iRule ) {
874  for ( GaussPoint *jGp: *iRule ) {
875  if ( ielem->computeGlobalCoordinates( jGpCoords, jGp->giveNaturalCoordinates() ) ) {
876  // compute distance
877  double dist = coords.distance(jGpCoords);
878  //printf("czRuleIndex: %d j: %d dist: %e\n", czRuleIndex, j, dist);
879  if ( dist < minDist ) {
880  minDist = dist;
881  nearestGp = jGp;
882  }
883  } else {
884  OOFEM_ERROR("computeGlobalCoordinates failed");
885  }
886  }
887  } else {
888  OOFEM_ERROR("iRule == NULL");
889  }
890  }
891  }
893  }
894  }
895 
896  FloatArray bborigin = coords;
897  // all cell element ip's scanned
898  // construct bounding box and test its position within currCell
899  BBStatus = currCell->testBoundingBox(bborigin, minDist);
900  if ( BBStatus == OctantRec :: BBS_InsideCell ) {
901  return nearestGp;
902  } else if ( BBStatus == OctantRec :: BBS_ContainsCell ) {
903  std :: list< OctantRec * >cellList;
904 
905  // found terminal octant containing point
906  OctantRec *startCell = this->findTerminalContaining(rootCell, coords);
907  // go up, until cell containing bbox is found
908  if ( startCell != rootCell ) {
909  while ( startCell->testBoundingBox(coords, minDist) != OctantRec :: BBS_InsideCell ) {
910  startCell = startCell->giveParent();
911  if ( startCell == rootCell ) {
912  break;
913  }
914  }
915  }
916 
917  this->giveListOfTerminalCellsInBoundingBox(cellList, bborigin, minDist, 0, startCell);
918 
919  for ( OctantRec *icell: cellList ) {
920  if ( currCell == icell ) {
921  continue;
922  }
923 
924  this->giveClosestIPWithinOctant( icell, coords, region, minDist, & nearestGp, iCohesiveZoneGP );
925  }
926 
927  return nearestGp;
928 
929 #if 0
930  // found terminal octant containing point
931  OctantRec *startCell = this->findTerminalContaining(rootCell, coords);
932  // go up, until cell containing bbox is found
933  if ( startCell != rootCell ) {
934  while ( startCell->testBoundingBox(coords, minDist) != OctantRec :: BBS_InsideCell ) {
935  startCell = startCell->giveParent();
936  if ( startCell == rootCell ) {
937  break;
938  }
939  }
940  }
941  // loop over all child (if any) and found all nodes meeting the criteria
942  // this->giveClosestIPWithinOctant (startCell, visitedElems, coords, region, minDist, &nearestGp);
943  this->giveClosestIPWithinOctant(startCell, coords, region, minDist, & nearestGp);
944  return nearestGp;
945 
946 #endif
947 
948 
949 #if 0
950  set< int >nearElementList;
951  // find all elements within bbox and find nearest ip
952  this->giveAllElementsWithIpWithinBox(nearElementList, bborigin, minDist);
953  // loop over those elements and find nearest ip and return it
954  // check for region also
955  if ( !nearElementList.empty() ) {
956  for ( int elnum: nearElementList ) {
957  ielem = domain->giveElement(elnum);
958  //igp = ipContainer[i].giveGp();
959  if ( region == ielem->giveRegionNumber() ) {
960  iRule = ielem->giveDefaultIntegrationRulePtr();
961  for ( GaussPoint *jGp: *iRule ) {
962  if ( ielem->computeGlobalCoordinates( jGpCoords, * ( jGp->giveCoordinates() ) ) ) {
963  // compute distance
964  double dist = coords.distance(jGpCoords);
965  if ( dist < minDist ) {
966  minDist = dist;
967  nearestGp = jGp;
968  }
969  } else {
970  OOFEM_ERROR("computeGlobalCoordinates failed");
971  }
972  }
973  }
974  }
975  }
976 #endif
977  } else {
978  printf("coords: ");
979  coords.printYourself();
980  OOFEM_ERROR("octree inconsistency found");
981  }
982 
983  return NULL;
984 }
985 
986 
987 void
988 OctreeSpatialLocalizer :: giveClosestIPWithinOctant(OctantRec *currentCell, //elementContainerType& visitedElems,
989  const FloatArray &coords,
990  int region, double &dist, GaussPoint **answer, bool iCohesiveZoneGP)
991 {
992  if ( currentCell->isTerminalOctant() ) {
993  double currDist;
994  FloatArray jGpCoords;
995 
996  // loop over cell elements and check if they meet the criteria
997  elementContainerType &elementList = currentCell->giveIPElementList();
998  for ( int iel: elementList ) {
999  // ask for element
1000  Element *ielem = domain->giveElement(iel);
1001 
1002  /* HUHU CHEATING */
1003  if ( ielem->giveParallelMode() == Element_remote ) {
1004  continue;
1005  }
1006 
1007  if ( ( region > 0 ) && ( region != ielem->giveRegionNumber() ) ) {
1008  continue;
1009  }
1010 
1011  if ( !iCohesiveZoneGP ) {
1012  // test if element already visited
1013  // if (!visitedElems.insert(*pos).second) continue;
1014  // is one of his ip's within given bbox -> inset it into elemSet
1015  for ( GaussPoint *gp: *ielem->giveDefaultIntegrationRulePtr() ) {
1016  if ( ielem->computeGlobalCoordinates( jGpCoords, gp->giveNaturalCoordinates() ) ) {
1017  currDist = coords.distance(jGpCoords);
1018  // multiple insertion are handled by STL set implementation
1019  if ( currDist <= dist ) {
1020  dist = currDist;
1021  * answer = gp;
1022  }
1023  } else {
1024  OOFEM_ERROR("computeGlobalCoordinates failed");
1025  }
1026  }
1027  } else {
1029  // Check for cohesive zone Gauss points
1030  XfemElementInterface *xFemEl = dynamic_cast< XfemElementInterface * >(ielem);
1031 
1032  if ( xFemEl != NULL ) {
1033  size_t numCZRules = xFemEl->mpCZIntegrationRules.size();
1034  for ( size_t czRuleIndex = 0; czRuleIndex < numCZRules; czRuleIndex++ ) {
1035  std :: unique_ptr< IntegrationRule > &iRule = xFemEl->mpCZIntegrationRules [ czRuleIndex ];
1036  if ( iRule ) {
1037  for ( GaussPoint *gp: *iRule ) {
1038  if ( ielem->computeGlobalCoordinates( jGpCoords, gp->giveNaturalCoordinates() ) ) {
1039  currDist = coords.distance(jGpCoords);
1040  // multiple insertion are handled by STL set implementation
1041  if ( currDist <= dist ) {
1042  dist = currDist;
1043  * answer = gp;
1044  }
1045  } else {
1046  OOFEM_ERROR("computeGlobalCoordinates failed");
1047  }
1048  }
1049  }
1050  }
1051  }
1053  }
1054  }
1055 
1056  return;
1057  } else {
1059 
1060  for ( int i = 0; i <= octreeMask.at(1); i++ ) {
1061  for ( int j = 0; j <= octreeMask.at(2); j++ ) {
1062  for ( int k = 0; k <= octreeMask.at(3); k++ ) {
1063  if ( currentCell->giveChild(i, j, k) ) {
1064  // test if box hits the cell
1065  BBStatus = currentCell->giveChild(i, j, k)->testBoundingBox(coords, dist);
1066  if ( ( BBStatus == OctantRec :: BBS_InsideCell ) || ( BBStatus == OctantRec :: BBS_ContainsCell ) ) {
1067  // if yes call this method for such cell
1068  //this->giveClosestIPWithinOctant (currentCell->giveChild(i,j,k), visitedElems, coords, region, dist, answer);
1069  this->giveClosestIPWithinOctant(currentCell->giveChild(i, j, k), coords, region, dist, answer, iCohesiveZoneGP);
1070  }
1071  }
1072  }
1073  }
1074  }
1075  }
1076 }
1077 
1078 
1079 GaussPoint *
1080 OctreeSpatialLocalizer :: giveClosestIP(const FloatArray &coords, Set &elementSet, bool iCohesiveZoneGP)
1081 {
1082  double minDist;
1083  OctantRec *currCell;
1084  GaussPoint *nearestGp = NULL;
1086  FloatArray jGpCoords;
1087 
1088  this->init();
1090 
1091  // list of already tested elements
1092  // elementContainerType visitedElems;
1093  minDist = 1.1 * rootCell->giveWidth();
1094  // found terminal octant containing point
1095  currCell = this->findTerminalContaining(rootCell, coords);
1096  elementContainerType &elementList = currCell->giveIPElementList();
1097  // find nearest ip in this terminal cell
1098  for ( int iel: elementList) {
1099  Element *ielem = domain->giveElement(iel);
1100 
1101  /* HUHU CHEATING */
1102  if ( ielem->giveParallelMode() == Element_remote ) {
1103  continue;
1104  }
1105 
1106  //igp = ipContainer[i].giveGp();
1107  if ( !elementSet.hasElement( ielem->giveNumber() ) ) {
1108  continue;
1109  }
1110 
1111  if ( !iCohesiveZoneGP ) {
1112  // test if element already visited
1113  // if (!visitedElems.insert(ielem).second) continue;
1114  for ( GaussPoint *jGp: *ielem->giveDefaultIntegrationRulePtr() ) {
1115  if ( ielem->computeGlobalCoordinates( jGpCoords, jGp->giveNaturalCoordinates() ) ) {
1116  // compute distance
1117  double dist = coords.distance(jGpCoords);
1118  if ( dist < minDist ) {
1119  minDist = dist;
1120  nearestGp = jGp;
1121  }
1122  } else {
1123  OOFEM_ERROR("computeGlobalCoordinates failed");
1124  }
1125  }
1126  } else {
1128  // Check for cohesive zone Gauss points
1129  XfemElementInterface *xFemEl = dynamic_cast< XfemElementInterface * >(ielem);
1130 
1131  if ( xFemEl != NULL ) {
1132  size_t numCZRules = xFemEl->mpCZIntegrationRules.size();
1133  for ( size_t czRuleIndex = 0; czRuleIndex < numCZRules; czRuleIndex++ ) {
1134  std :: unique_ptr< IntegrationRule > &iRule = xFemEl->mpCZIntegrationRules [ czRuleIndex ];
1135  if ( iRule ) {
1136  for ( GaussPoint *jGp: *iRule ) {
1137  if ( ielem->computeGlobalCoordinates( jGpCoords, jGp->giveNaturalCoordinates() ) ) {
1138  // compute distance
1139  double dist = coords.distance(jGpCoords);
1140  //printf("czRuleIndex: %d j: %d dist: %e\n", czRuleIndex, j, dist);
1141  if ( dist < minDist ) {
1142  minDist = dist;
1143  nearestGp = jGp;
1144  }
1145  } else {
1146  OOFEM_ERROR("computeGlobalCoordinates failed");
1147  }
1148  }
1149  } else {
1150  OOFEM_ERROR("iRule == NULL");
1151  }
1152  }
1153  }
1155  }
1156  }
1157 
1158  FloatArray bborigin = coords;
1159  // all cell element ip's scanned
1160  // construct bounding box and test its position within currCell
1161  BBStatus = currCell->testBoundingBox(bborigin, minDist);
1162  if ( BBStatus == OctantRec :: BBS_InsideCell ) {
1163  return nearestGp;
1164  } else if ( BBStatus == OctantRec :: BBS_ContainsCell ) {
1165  std :: list< OctantRec * >cellList;
1166 
1167  // found terminal octant containing point
1168  OctantRec *startCell = this->findTerminalContaining(rootCell, coords);
1169  // go up, until cell containing bbox is found
1170  if ( startCell != rootCell ) {
1171  while ( startCell->testBoundingBox(coords, minDist) != OctantRec :: BBS_InsideCell ) {
1172  startCell = startCell->giveParent();
1173  if ( startCell == rootCell ) {
1174  break;
1175  }
1176  }
1177  }
1178 
1179  this->giveListOfTerminalCellsInBoundingBox(cellList, bborigin, minDist, 0, startCell);
1180 
1181  for ( OctantRec *icell: cellList ) {
1182  if ( currCell == icell ) {
1183  continue;
1184  }
1185 
1186  this->giveClosestIPWithinOctant( icell, coords, elementSet, minDist, & nearestGp, iCohesiveZoneGP );
1187  }
1188 
1189  return nearestGp;
1190 
1191 #if 0
1192  // found terminal octant containing point
1193  OctantRec *startCell = this->findTerminalContaining(rootCell, coords);
1194  // go up, until cell containing bbox is found
1195  if ( startCell != rootCell ) {
1196  while ( startCell->testBoundingBox(coords, minDist) != OctantRec :: BBS_InsideCell ) {
1197  startCell = startCell->giveParent();
1198  if ( startCell == rootCell ) {
1199  break;
1200  }
1201  }
1202  }
1203  // loop over all child (if any) and found all nodes meeting the criteria
1204  // this->giveClosestIPWithinOctant (startCell, visitedElems, coords, region, minDist, &nearestGp);
1205  this->giveClosestIPWithinOctant(startCell, coords, region, minDist, & nearestGp);
1206  return nearestGp;
1207 
1208 #endif
1209 
1210 
1211 #if 0
1212  set< int >nearElementList;
1213  // find all elements within bbox and find nearest ip
1214  this->giveAllElementsWithIpWithinBox(nearElementList, bborigin, minDist);
1215  // loop over those elements and find nearest ip and return it
1216  // check for region also
1217  if ( !nearElementList.empty() ) {
1218  for ( int iel: nearElementList ) {
1219  Element *ielem = domain->giveElement(iel);
1220  //igp = ipContainer[i].giveGp();
1221  if ( region == ielem->giveRegionNumber() ) {
1222  for ( GaussPoint *jGp: *ielem->giveDefaultIntegrationRulePtr() ) {
1223  if ( ielem->computeGlobalCoordinates( jGpCoords, * ( jGp->giveCoordinates() ) ) ) {
1224  // compute distance
1225  double dist = coords.distance(jGpCoords);
1226  if ( dist < minDist ) {
1227  minDist = dist;
1228  nearestGp = jGp;
1229  }
1230  } else {
1231  OOFEM_ERROR("computeGlobalCoordinates failed");
1232  }
1233  }
1234  }
1235  }
1236  }
1237 #endif
1238  } else {
1239  printf("coords: ");
1240  coords.printYourself();
1241  OOFEM_ERROR("octree inconsistency found");
1242  }
1243 
1244  return NULL;
1245 }
1246 
1247 
1248 void
1249 OctreeSpatialLocalizer :: giveClosestIPWithinOctant(OctantRec *currentCell, //elementContainerType& visitedElems,
1250  const FloatArray &coords,
1251  Set &elementSet, double &dist, GaussPoint **answer, bool iCohesiveZoneGP)
1252 {
1253  if ( currentCell->isTerminalOctant() ) {
1254  double currDist;
1255  FloatArray jGpCoords;
1256 
1257  // loop over cell elements and check if they meet the criteria
1258  elementContainerType &elementList = currentCell->giveIPElementList();
1259  for ( int iel: elementList ) {
1260  // ask for element
1261  Element *ielem = domain->giveElement(iel);
1262 
1263  /* HUHU CHEATING */
1264  if ( ielem->giveParallelMode() == Element_remote ) {
1265  continue;
1266  }
1267 
1268  if ( !elementSet.hasElement( ielem->giveNumber() ) ) {
1269  continue;
1270  }
1271 
1272  if ( !iCohesiveZoneGP ) {
1273  // test if element already visited
1274  // if (!visitedElems.insert(iel).second) continue;
1275  // is one of his ip's within given bbox -> inset it into elemSet
1276  for ( GaussPoint *gp: *ielem->giveDefaultIntegrationRulePtr() ) {
1277  if ( ielem->computeGlobalCoordinates( jGpCoords, gp->giveNaturalCoordinates() ) ) {
1278  currDist = coords.distance(jGpCoords);
1279  // multiple insertion are handled by STL set implementation
1280  if ( currDist <= dist ) {
1281  dist = currDist;
1282  * answer = gp;
1283  }
1284  } else {
1285  OOFEM_ERROR("computeGlobalCoordinates failed");
1286  }
1287  }
1288  } else {
1290  // Check for cohesive zone Gauss points
1291  XfemElementInterface *xFemEl = dynamic_cast< XfemElementInterface * >(ielem);
1292 
1293  if ( xFemEl != NULL ) {
1294  size_t numCZRules = xFemEl->mpCZIntegrationRules.size();
1295  for ( size_t czRuleIndex = 0; czRuleIndex < numCZRules; czRuleIndex++ ) {
1296  std :: unique_ptr< IntegrationRule > &iRule = xFemEl->mpCZIntegrationRules [ czRuleIndex ];
1297  if ( iRule ) {
1298  for ( GaussPoint *gp: *iRule ) {
1299  if ( ielem->computeGlobalCoordinates( jGpCoords, gp->giveNaturalCoordinates() ) ) {
1300  currDist = coords.distance(jGpCoords);
1301  // multiple insertion are handled by STL set implementation
1302  if ( currDist <= dist ) {
1303  dist = currDist;
1304  * answer = gp;
1305  }
1306  } else {
1307  OOFEM_ERROR("computeGlobalCoordinates failed");
1308  }
1309  }
1310  }
1311  }
1312  }
1314  }
1315  }
1316 
1317  return;
1318  } else {
1320 
1321  for ( int i = 0; i <= octreeMask.at(1); i++ ) {
1322  for ( int j = 0; j <= octreeMask.at(2); j++ ) {
1323  for ( int k = 0; k <= octreeMask.at(3); k++ ) {
1324  if ( currentCell->giveChild(i, j, k) ) {
1325  // test if box hits the cell
1326  BBStatus = currentCell->giveChild(i, j, k)->testBoundingBox(coords, dist);
1327  if ( ( BBStatus == OctantRec :: BBS_InsideCell ) || ( BBStatus == OctantRec :: BBS_ContainsCell ) ) {
1328  // if yes call this method for such cell
1329  //this->giveClosestIPWithinOctant (currentCell->giveChild(i,j,k), visitedElems, coords, region, dist, answer);
1330  this->giveClosestIPWithinOctant(currentCell->giveChild(i, j, k), coords, elementSet, dist, answer, iCohesiveZoneGP);
1331  }
1332  }
1333  }
1334  }
1335  }
1336  }
1337 }
1338 
1339 
1340 void
1342  const double radius, bool iCohesiveZoneGP)
1343 {
1344  this->init();
1346  // found terminal octant containing point
1347  OctantRec *currCell = this->findTerminalContaining(rootCell, coords);
1348  // go up, until cell containing bbox is found
1349  if ( currCell != rootCell ) {
1350  while ( currCell->testBoundingBox(coords, radius) != OctantRec :: BBS_InsideCell ) {
1351  currCell = currCell->giveParent();
1352  if ( currCell == rootCell ) {
1353  break;
1354  }
1355  }
1356  }
1357 
1358  // loop over all child (if any) and found all nodes meeting the criteria
1359  this->giveElementsWithIPWithinBox(elemSet, currCell, coords, radius, iCohesiveZoneGP);
1360 }
1361 
1362 
1363 void
1365  const double radius, bool iCohesiveZoneGP)
1366 {
1367  this->giveAllElementsWithIpWithinBox_EvenIfEmpty(elemSet, coords, radius, iCohesiveZoneGP);
1368  if ( elemSet.isEmpty() ) {
1369  OOFEM_ERROR("empty set found");
1370  }
1371 }
1372 
1373 
1374 void
1376  const FloatArray &coords, const double radius, bool iCohesiveZoneGP)
1377 {
1378  if ( currentCell->isTerminalOctant() ) {
1379  double currDist;
1380  FloatArray jGpCoords;
1381 
1382  // loop over cell elements and check if they meet the criteria
1383  elementContainerType &elementList = currentCell->giveIPElementList();
1384  for ( int iel: elementList ) {
1385  // test if element is already present
1386  if ( elemSet.findSorted(iel) ) {
1387  continue;
1388  }
1389 
1390  // ask for element
1391  Element *ielem = domain->giveElement(iel);
1392 
1393  //if(ielem -> giveParallelMode() == Element_remote)continue;
1394  if ( !iCohesiveZoneGP ) {
1395  // is one of his ip's within given bbox -> inset it into elemSet
1396  for ( auto &gp: *ielem->giveDefaultIntegrationRulePtr() ) {
1397  if ( ielem->computeGlobalCoordinates( jGpCoords, gp->giveNaturalCoordinates() ) ) {
1398  currDist = coords.distance(jGpCoords);
1399  // multiple insertion are handled by STL set implementation
1400  if ( currDist <= radius ) {
1401  elemSet.insertSortedOnce(iel);
1402  break;
1403  }
1404  } else {
1405  OOFEM_ERROR("computeGlobalCoordinates failed");
1406  }
1407  }
1408  } else {
1410 
1411  XfemElementInterface *xFemEl = dynamic_cast< XfemElementInterface * >(ielem);
1412 
1413  if ( xFemEl != NULL ) {
1414  size_t numCZRules = xFemEl->mpCZIntegrationRules.size();
1415  for ( size_t czRuleIndex = 0; czRuleIndex < numCZRules; czRuleIndex++ ) {
1416  std :: unique_ptr< IntegrationRule > &iRule = xFemEl->mpCZIntegrationRules [ czRuleIndex ];
1417  if ( iRule ) {
1418  for ( auto &gp: *iRule ) {
1419  if ( ielem->computeGlobalCoordinates( jGpCoords, gp->giveNaturalCoordinates() ) ) {
1420  currDist = coords.distance(jGpCoords);
1421  // multiple insertion are handled by STL set implementation
1422  if ( currDist <= radius ) {
1423  elemSet.insertSortedOnce(iel);
1424  czRuleIndex = numCZRules;
1425  break;
1426  }
1427  } else {
1428  OOFEM_ERROR("computeGlobalCoordinates failed");
1429  }
1430  }
1431  }
1432  }
1433  }
1435  }
1436  }
1437  } else {
1439 
1440 
1441  for ( int i = 0; i <= octreeMask.at(1); i++ ) {
1442  for ( int j = 0; j <= octreeMask.at(2); j++ ) {
1443  for ( int k = 0; k <= octreeMask.at(3); k++ ) {
1444  if ( currentCell->giveChild(i, j, k) ) {
1445  // test if box hits the cell
1446  BBStatus = currentCell->giveChild(i, j, k)->testBoundingBox(coords, radius);
1447  if ( ( BBStatus == OctantRec :: BBS_InsideCell ) || ( BBStatus == OctantRec :: BBS_ContainsCell ) ) {
1448  // if yes call this method for such cell
1449  this->giveElementsWithIPWithinBox(elemSet, currentCell->giveChild(i, j, k), coords, radius, iCohesiveZoneGP);
1450  }
1451  }
1452  }
1453  }
1454  }
1455  }
1456 }
1457 
1458 
1459 void
1461 {
1462  this->init();
1463  // found terminal octant containing point
1464  OctantRec *currCell = this->findTerminalContaining(rootCell, coords);
1465  // go up, until cell containing bbox is found
1466  if ( currCell != rootCell ) {
1467  while ( currCell->testBoundingBox(coords, radius) != OctantRec :: BBS_InsideCell ) {
1468  currCell = currCell->giveParent();
1469  if ( currCell == rootCell ) {
1470  break;
1471  }
1472  }
1473  }
1474 
1475  // loop over all child (if any) and found all nodes meeting the criteria
1476  this->giveNodesWithinBox(nodeSet, currCell, coords, radius);
1477 }
1478 
1479 
1480 Node *
1482 {
1483  Node *answer = NULL;
1484  std :: list< OctantRec * >cellList;
1485  OctantRec *currCell;
1486  double radius, prevRadius;
1487 
1488  // Maximum distance given coordinate and furthest terminal cell ( center_distance + width/2*sqrt(3) )
1489  double minDist = maxDist;
1490 
1491  // found terminal octant containing point
1492  currCell = this->findTerminalContaining(rootCell, gcoords);
1493 
1494  // Look in center, then expand.
1495  this->giveNodeClosestToPointWithinOctant(currCell, gcoords, minDist, answer);
1496  prevRadius = 0.;
1497  radius = min(currCell->giveWidth(), minDist);
1498  do {
1499  this->giveListOfTerminalCellsInBoundingBox(cellList, gcoords, radius, prevRadius, this->rootCell);
1500  for ( OctantRec *cell: cellList ) {
1501  this->giveNodeClosestToPointWithinOctant(cell, gcoords, minDist, answer);
1502  }
1503  prevRadius = radius;
1504  radius *= 2.; // Keep expanding the scope until the radius is larger than the entire root cell, then give up (because we have checked every possible cell)
1505  } while ( prevRadius < minDist );
1506  return answer;
1507 }
1508 
1509 
1510 void
1512  double &minDist, Node * &answer)
1513 {
1514  double minDist2 = minDist*minDist;
1515  for ( auto &inod : currCell->giveNodeList() ) {
1516  Node *node = domain->giveNode(inod);
1517 
1518  double currDist2 = gcoords.distance_square(*node->giveCoordinates());
1519 
1520  if ( currDist2 < minDist2 ) {
1521  answer = node;
1522  minDist2 = currDist2;
1523  }
1524  }
1525  minDist = sqrt(minDist2);
1526 }
1527 
1528 
1529 void
1531  const FloatArray &coords, const double radius)
1532 {
1533  nodeContainerType &cellNodes = currentCell->giveNodeList();
1534 
1535  if ( currentCell->isTerminalOctant() ) {
1536  FloatArray *nodeCoords;
1537  if ( !cellNodes.empty() ) {
1538  for ( int inod: cellNodes ) {
1539  // loop over cell nodes and check if they meet the criteria
1540  nodeCoords = domain->giveNode(inod)->giveCoordinates();
1541  // is node within bbox
1542  if ( nodeCoords->distance(coords) <= radius ) {
1543  // if yes, append them into set
1544  nodeList.push_back(inod);
1545  }
1546  }
1547  }
1548  } else {
1550 
1551  for ( int i = 0; i <= octreeMask.at(1); i++ ) {
1552  for ( int j = 0; j <= octreeMask.at(2); j++ ) {
1553  for ( int k = 0; k <= octreeMask.at(3); k++ ) {
1554  if ( currentCell->giveChild(i, j, k) ) {
1555  // test if box hits the cell
1556  BBStatus = currentCell->giveChild(i, j, k)->testBoundingBox(coords, radius);
1557  if ( ( BBStatus == OctantRec :: BBS_InsideCell ) || ( BBStatus == OctantRec :: BBS_ContainsCell ) ) {
1558  // if yes call this method for such cell
1559  this->giveNodesWithinBox(nodeList, currentCell->giveChild(i, j, k), coords, radius);
1560  }
1561  }
1562  }
1563  }
1564  }
1565  }
1566 }
1567 
1568 
1569 void
1571 {
1572  int depth = root->giveCellDepth();
1573  maxDepth = max(maxDepth, depth);
1574 
1575  for ( int i = 0; i <= octreeMask.at(1); i++ ) {
1576  for ( int j = 0; j <= octreeMask.at(2); j++ ) {
1577  for ( int k = 0; k <= octreeMask.at(3); k++ ) {
1578  if ( root->giveChild(i, j, k) ) {
1579  this->giveMaxTreeDepthFrom(root->giveChild(i, j, k), maxDepth);
1580  }
1581  }
1582  }
1583  }
1584 }
1585 
1586 
1587 void
1588 OctreeSpatialLocalizer :: giveListOfTerminalCellsInBoundingBox(std :: list< OctantRec * > &cellList, const FloatArray &coords,
1589  double radius, double innerRadius, OctantRec *currentCell)
1590 {
1592 
1593  BBStatus = currentCell->testBoundingBox(coords, radius);
1594  if ( BBStatus != OctantRec :: BBS_OutsideCell ) {
1595  if ( currentCell->isTerminalOctant() ) {
1596  //if ( currentCell->testBoundingBox(coords, innerRadius) == OctantRec :: BBS_OutsideCell ) {
1597  cellList.push_back(currentCell);
1598  //}
1599  } else {
1600  for ( int i = 0; i <= octreeMask.at(1); i++ ) {
1601  for ( int j = 0; j <= octreeMask.at(2); j++ ) {
1602  for ( int k = 0; k <= octreeMask.at(3); k++ ) {
1603  if ( currentCell->giveChild(i, j, k) ) {
1604  this->giveListOfTerminalCellsInBoundingBox( cellList, coords, radius, innerRadius, currentCell->giveChild(i, j, k) );
1605  }
1606  }
1607  }
1608  }
1609  }
1610  }
1611 }
1612 
1613 
1614 int
1616 {
1617  if ( force ) {
1618  if ( rootCell ) {
1619  delete rootCell;
1620  }
1621  rootCell = NULL;
1622  elementIPListsInitialized = false;
1624  }
1625 
1626  if ( !rootCell ) {
1627  return this->buildOctreeDataStructure();
1628  } else {
1629  return 0;
1630  }
1631 }
1632 } // end namespace oofem
virtual Element * giveElementClosestToPoint(FloatArray &lcoords, FloatArray &closest, const FloatArray &gcoords, int region)
Returns the element closest to a given point.
void giveClosestIPWithinOctant(OctantRec *currentCell, const FloatArray &coords, int region, double &dist, GaussPoint **answer, bool iCohesiveZoneGP)
Returns closest IP to given point contained within given octree cell.
The base class for all spatial localizers.
virtual ~OctreeSpatialLocalizer()
Destructor - deletes the octree tree.
int depth
Tree depth.
int giveRegionNumber()
Definition: element.C:507
void giveNodeClosestToPointWithinOctant(OctantRec *cell, const FloatArray &gcoords, double &minDist, Node *&answer)
Returns the node closest to the given point within the cell.
Class and object Domain.
Definition: domain.h:115
virtual IntegrationRule * giveDefaultIntegrationRulePtr()
Access method for default integration rule.
Definition: element.h:822
void insertElementIntoOctree(OctantRec *rootCell, int region, int elemNum, const FloatArray &b0, const FloatArray &b1)
Inserts an element with the given bounding box.
The implementation of spatial localizer based on octree technique.
void insertNodeIntoOctree(OctantRec *rootCell, int nodeNum, const FloatArray &coords)
Inserts the given node (identified by its number and position) to the octree structure.
int giveNumberOfDofManagers() const
Returns number of dof managers in domain.
Definition: domain.h:432
Provides Xfem interface for an element.
std::list< int > nodeList
Octant node list.
bool isEmpty() const
Checks if receiver is empty (i.e., zero sized).
Definition: intarray.h:208
OctreeSpatialLocalizer * localizer
Link to octree class.
void zero()
Sets all component to zero.
Definition: intarray.C:52
double & at(int i)
Coefficient access function.
Definition: floatarray.h:131
int max(int i, int j)
Returns bigger value form two given decimals.
Definition: mathfem.h:71
OctreeSpatialLocalizer(Domain *d)
Constructor.
std::list< int > & giveNodeList()
ConnectivityTable * giveConnectivityTable()
Returns receiver&#39;s associated connectivity table.
Definition: domain.C:1170
bool insertSortedOnce(int value, int allocChunk=0)
Inserts given value into a receiver, which is assumed to be sorted.
Definition: intarray.C:360
FloatArray origin
Octant origin coordinates (lower corner)
int giveOctreeMaskValue(int indx)
Returns the octreeMask value given by the index.
Abstract base class for all finite elements.
Definition: element.h:145
void deleteNodeList()
Clears and deletes the nodeList.
Base class for dof managers.
Definition: dofmanager.h:113
int giveNumberOfElements() const
Returns number of elements in domain.
Definition: domain.h:434
Class representing the octant of octree.
std::list< int > & giveElementList(int region)
#define OOFEM_LOG_DEBUG(...)
Definition: logger.h:128
Class implementing an array of integers.
Definition: intarray.h:61
int & at(int i)
Coefficient access function.
Definition: intarray.h:103
Domain * domain
Link to domain object.
int giveNumberOfIntegrationRules()
Definition: element.h:830
#define OCTREE_MAX_NODES_LIMIT
Max desired number of nodes per octant.
virtual int giveNumberOfNodes() const
Returns number of nodes of receiver.
Definition: element.h:662
std::list< int > nodeContainerType
Typedefs to introduce the container type for nodal numbers, returned by some services.
double distance(const FloatArray &x) const
Computes the distance between position represented by receiver and position given as parameter...
Definition: floatarray.C:489
virtual double SpatialLocalizerI_giveClosestPoint(FloatArray &lcoords, FloatArray &closest, const FloatArray &gcoords)
Gives the closest point on the element.
void printYourself()
Recursively prints structure.
BoundingBoxStatus testBoundingBox(const FloatArray &coords, double radius)
Test if receiver within bounding box (sphere).
Element * giveElement(int n)
Service for accessing particular domain fe element.
Definition: domain.C:160
#define OOFEM_ERROR(...)
Definition: error.h:61
#define OCTREE_MAX_DEPTH
Max octree depth.
IntArray & giveIPElementList()
ChildStatus giveChildContainingPoint(OctantRec **child, const FloatArray &coords)
Returns the child containing given point.
void clear()
Clears the array (zero size).
Definition: intarray.h:177
Set of elements, boundaries, edges and/or nodes.
Definition: set.h:66
void insertIPElementIntoOctree(OctantRec *rootCell, int elemNum, const FloatArray &coords)
Inserts the given integration point (or more precisely the element owning it) to the octree data stru...
void giveListOfTerminalCellsInBoundingBox(std::list< OctantRec * > &cellList, const FloatArray &coords, const double radius, double innerRadius, OctantRec *currentCell)
Builds the list of terminal cells contained within given box (coords, radius), starting from given cu...
bool elementIPListsInitialized
Flag indicating elementIP tables are initialized.
OctantRec * rootCell
Root cell of octree.
IntArray octreeMask
Octree degenerate mask.
virtual void SpatialLocalizerI_giveBBox(FloatArray &bb0, FloatArray &bb1)
Creates a bounding box of the nodes and checks if it includes the given coordinate.
double distance_square(const FloatArray &iP1, const FloatArray &iP2, double &oXi, double &oXiUnbounded) const
Definition: floatarray.C:499
void resize(int n)
Checks size of receiver towards requested bounds.
Definition: intarray.C:124
virtual Node * giveNodeClosestToPoint(const FloatArray &coords, double maxDist)
Returns the node closest to the given coordinate.
std::vector< std::unique_ptr< IntegrationRule > > mpCZIntegrationRules
virtual void giveAllElementsWithIpWithinBox_EvenIfEmpty(elementContainerType &elemSet, const FloatArray &coords, const double radius)
Returns container (set) of all domain elements having integration point within given box...
virtual int init(bool force=false)
Initialize receiver data structure if not done previously.
virtual Element * giveElementContainingPoint(const FloatArray &coords, const IntArray *regionList=NULL)
Returns the element, containing given point and belonging to one of the region in region list...
void addElement(int region, int elementNum)
Adds given element to cell list of elements having IP within this cell.
Class representing vector of real numbers.
Definition: floatarray.h:82
elementParallelMode giveParallelMode() const
Return elementParallelMode of receiver.
Definition: element.h:1069
int findSorted(int value) const
Finds the first occurrence of given value, assuming that the receiver is sorted.
Definition: intarray.C:344
void addNode(int nodeNum)
Adds given Node to node list of nodes contained by receiver.
const IntArray * giveDofManConnectivityArray(int dofman)
bool buildOctreeDataStructure()
Builds the underlying octree data structure.
virtual GaussPoint * giveClosestIP(const FloatArray &coords, int region, bool iCohesiveZoneGP=false)
Returns the integration point in associated domain, which is closest to given point.
virtual void printYourself() const
Print receiver on stdout.
Definition: floatarray.C:747
OctantRec(OctreeSpatialLocalizer *loc, OctantRec *parent, FloatArray &origin, double halfWidth)
Constructor.
OctantRec * giveChild(int xi, int yi, int zi)
Gives the Child at given local indices.
virtual void giveAllNodesWithinBox(nodeContainerType &nodeList, const FloatArray &coords, const double radius)
Returns container (list) of all domain nodes within given box.
virtual void giveAllElementsWithIpWithinBox(elementContainerType &elemSet, const FloatArray &coords, const double radius)
Returns container (set) of all domain elements having integration point within given box...
Class implementing single timer, providing wall clock and user time capabilities. ...
Definition: timer.h:46
double halfWidth
Octant size.
std::vector< std::list< int > > elementList
Element list of all elements close to the cell.
virtual Interface * giveInterface(InterfaceType t)
Interface requesting service.
Definition: femcmpnn.h:179
void times(double s)
Multiplies receiver with scalar.
Definition: floatarray.C:818
int giveNumberOfRegions() const
Returns number of regions. Currently regions corresponds to cross section models. ...
Definition: domain.h:446
The spatial localizer element interface associated to spatial localizer.
Element in active domain is only mirror of some remote element.
Definition: element.h:102
virtual FloatArray * giveCoordinates()
Definition: node.h:114
void insertElementsUsingNodalConnectivitiesIntoOctree(OctantRec *rootCell)
Initializes the element lists in octree data structure.
IntArray elementIPList
Element list, containing all elements having IP in cell.
int min(int i, int j)
Returns smaller value from two given decimals.
Definition: mathfem.h:59
void giveMaxTreeDepthFrom(OctantRec *root, int &maxDepth)
Determines the max tree depth computed for given tree cell and its children.
void push_back(const double &iVal)
Add one element.
Definition: floatarray.h:118
const FloatArray & giveOrigin()
Gives the cell origin.
void divideLocally(int level, const IntArray &octantMask)
Divide receiver further, creating corresponding children.
void giveElementsWithIPWithinBox(elementContainerType &elemSet, OctantRec *currentCell, const FloatArray &coords, const double radius, bool iCohesiveZoneGP=false)
Returns container (set) of elements having integration point within given box and given root cell...
void initElementDataStructure(int region=0)
Insert element into tree (the tree topology is determined by nodes).
OctantRec * child[2][2][2]
Link to octant children.
int giveSize() const
Definition: intarray.h:203
int giveSize() const
Returns the size of receiver.
Definition: floatarray.h:218
Node * giveNode(int n)
Service for accessing particular domain node.
Definition: domain.h:371
the oofem namespace is to define a context or scope in which all oofem names are defined.
Class implementing node in finite element mesh.
Definition: node.h:87
Domain * giveDomain()
Returns the domain that localizer acts on.
int giveNumber() const
Definition: femcmpnn.h:107
DofManager * giveDofManager(int n)
Service for accessing particular domain dof manager.
Definition: domain.C:314
void addElementIP(int elementNum)
Adds given element to cell list of elements having IP within this cell.
void giveNodesWithinBox(nodeContainerType &nodeList, OctantRec *currentCell, const FloatArray &coords, const double radius)
Returns container (list) of nodes within given box and given root cell.
Node * giveNode(int i) const
Returns reference to the i-th node of element.
Definition: element.h:610
~OctantRec()
Destructor.
void startTimer()
Definition: timer.C:69
double getUtime()
Returns total user time elapsed in seconds.
Definition: timer.C:105
void giveElementClosestToPointWithinOctant(OctantRec *currCell, const FloatArray &gcoords, double &minDist, FloatArray &lcoords, FloatArray &closest, Element *&answer, int region)
Returns the element closest to the given point within the cell.
OctantRec * giveParent()
Class representing integration point in finite element program.
Definition: gausspoint.h:93
bool hasElement(int elem) const
Return True if given element is contained.
Definition: set.C:218
OctantRec * findTerminalContaining(OctantRec *startCell, const FloatArray &coords)
Finds the terminal octant containing the given point.
virtual int computeGlobalCoordinates(FloatArray &answer, const FloatArray &lcoords)
Computes the global coordinates from given element&#39;s local coordinates.
Definition: element.C:1207
void stopTimer()
Definition: timer.C:77
void add(const FloatArray &src)
Adds array src to receiver.
Definition: floatarray.C:156
void initElementIPDataStructure()
Insert IP records into tree (the tree topology is determined by nodes).
int findFirstIndexOf(int value) const
Finds index of first occurrence of given value in array.
Definition: intarray.C:331

This page is part of the OOFEM documentation. Copyright (c) 2011 Borek Patzak
Project e-mail: info@oofem.org
Generated at Tue Jan 2 2018 20:07:30 for OOFEM by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2011