00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "octreelocalizer.h"
00037 #include "element.h"
00038 #include "domain.h"
00039 #include "integrationrule.h"
00040 #include "gausspnt.h"
00041 #include "dofmanager.h"
00042 #include "node.h"
00043 #include "conTable.h"
00044 #include "mathfem.h"
00045 #ifndef __MAKEDEPEND
00046 #include <time.h>
00047 #endif
00048
00049 oofemOctantRec :: oofemOctantRec(OctreeSpatialLocalizer *loc, oofemOctantRec *parent, FloatArray &origin, double size)
00050 {
00051 int i, j, k;
00052
00053 this->localizer = loc;
00054 this->parent = parent;
00055 this->origin = origin;
00056 this->size = size;
00057 this->nodeList = NULL;
00058 this->elementList = NULL;
00059
00060 for ( i = 0; i <= 1; i++ ) {
00061 for ( j = 0; j <= 1; j++ ) {
00062 for ( k = 0; k <= 1; k++ ) {
00063 this->child [ i ] [ j ] [ k ] = NULL;
00064 }
00065 }
00066 }
00067 }
00068
00069 oofemOctantRec :: ~oofemOctantRec()
00070 {
00071
00072
00073 int i, j, k;
00074 for ( i = 0; i <= 1; i++ ) {
00075 for ( j = 0; j <= 1; j++ ) {
00076 for ( k = 0; k <= 1; k++ ) {
00077 if ( this->child [ i ] [ j ] [ k ] ) {
00078 delete this->child [ i ] [ j ] [ k ];
00079 }
00080 }
00081 }
00082 }
00083
00084 if ( nodeList ) {
00085 delete nodeList;
00086 }
00087
00088 if ( elementList ) {
00089 delete elementList;
00090 }
00091 }
00092
00093 std :: list< int > *
00094 oofemOctantRec :: giveNodeList() {
00095 if ( nodeList == NULL ) {
00096 nodeList = new std :: list< int >;
00097 }
00098
00099 return nodeList;
00100 }
00101
00102 std :: set< int > *
00103 oofemOctantRec :: giveIPElementList() {
00104 if ( elementList == NULL ) {
00105 elementList = new std :: set< int >;
00106 }
00107
00108 return elementList;
00109 }
00110
00111
00112
00113 oofemOctantRec *
00114 oofemOctantRec :: giveChild(int xi, int yi, int zi)
00115 {
00116 if ( ( xi >= 0 ) && ( xi < 2 ) && ( yi >= 0 ) && ( yi < 2 ) && ( zi >= 0 ) && ( zi < 2 ) ) {
00117 return this->child [ xi ] [ yi ] [ zi ];
00118 } else {
00119 OOFEM_ERROR4("oofemOctantRec::giveChild invalid child index (%d,%d,%d)", xi, yi, zi);
00120 }
00121
00122 return NULL;
00123 }
00124
00125
00126 int
00127 oofemOctantRec :: containsPoint(const FloatArray &coords)
00128 {
00129 int i;
00130
00131 for ( i = 1; i <= coords.giveSize(); i++ ) {
00132 if ( localizer->giveOctreeMaskValue(i) ) {
00133 if ( coords.at(i) < this->origin.at(i) ) {
00134 return 0;
00135 }
00136
00137 if ( coords.at(i) > ( this->origin.at(i) + this->size ) ) {
00138 return 0;
00139 }
00140 }
00141 }
00142
00143 return 1;
00144 }
00145
00146
00147 int
00148 oofemOctantRec :: giveChildContainingPoint(oofemOctantRec **child, const FloatArray &coords)
00149 {
00150 int i;
00151 IntArray ind(3);
00152
00153 if ( this->containsPoint(coords) ) {
00154 if ( this->isTerminalOctant() ) {
00155 * child = NULL;
00156 return -1;
00157 }
00158
00159 for ( i = 1; i <= coords.giveSize(); i++ ) {
00160 if ( localizer->giveOctreeMaskValue(i) && ( coords.at(i) > ( this->origin.at(i) + this->size / 2. ) ) ) {
00161 ind.at(i) = 1;
00162 } else {
00163 ind.at(i) = 0;
00164 }
00165 }
00166
00167 * child = this->child [ ind.at(1) ] [ ind.at(2) ] [ ind.at(3) ];
00168 return 1;
00169 } else {
00170 * child = NULL;
00171 return -2;
00172 }
00173 }
00174
00175
00176 int
00177 oofemOctantRec :: isTerminalOctant() {
00178
00179
00180 if ( this->child [ 0 ] [ 0 ] [ 0 ] ) {
00181 return 0;
00182 }
00183
00184 return 1;
00185 }
00186
00187 int
00188 oofemOctantRec :: divideLocally(int level, const IntArray &octantMask)
00189 {
00190 int i, j, k, result = 1;
00191
00192 if ( this->isTerminalOctant() ) {
00193
00194 int i, j, k;
00195 FloatArray childOrigin(3);
00196
00197 for ( i = 0; i <= octantMask.at(1); i++ ) {
00198 for ( j = 0; j <= octantMask.at(2); j++ ) {
00199 for ( k = 0; k <= octantMask.at(3); k++ ) {
00200 childOrigin.at(1) = this->origin.at(1) + i * ( this->size / 2. );
00201 childOrigin.at(2) = this->origin.at(2) + j * ( this->size / 2. );
00202 childOrigin.at(3) = this->origin.at(3) + k * ( this->size / 2. );
00203
00204 this->child [ i ] [ j ] [ k ] = new oofemOctantRec(localizer, this, childOrigin, this->size / 2.0);
00205 }
00206 }
00207 }
00208 }
00209
00210 int newLevel = level - 1;
00211 if ( newLevel > 0 ) {
00212
00213 for ( i = 0; i <= octantMask.at(1); i++ ) {
00214 for ( j = 0; j <= octantMask.at(2); j++ ) {
00215 for ( k = 0; k <= octantMask.at(3); k++ ) {
00216 if ( this->child [ i ] [ j ] [ k ] ) {
00217 result &= this->child [ i ] [ j ] [ k ]->divideLocally(newLevel, octantMask);
00218 }
00219 }
00220 }
00221 }
00222 }
00223
00224 return result;
00225 }
00226
00227
00228 oofemOctantRec :: boundingBoxStatus
00229 oofemOctantRec :: testBoundingBox(const FloatArray &coords, double radius)
00230 {
00231 int i, test = 1, nsd, size = coords.giveSize();
00232 double dist;
00233
00234 nsd = localizer->giveOctreeMaskValue(1) + localizer->giveOctreeMaskValue(2) + localizer->giveOctreeMaskValue(3);
00235
00236 FloatArray cellCenter = this->origin;
00237
00238 double cellRadius = sqrt( nsd * ( this->size / 2.0 ) * ( this->size / 2. ) );
00239 for ( i = 1; i < 4; i++ ) {
00240 cellCenter.at(i) += this->size / 2.0;
00241 }
00242
00243 for ( i = 1, dist = 0.0; i <= size; i++ ) {
00244 if ( localizer->giveOctreeMaskValue(i) ) {
00245 dist += ( cellCenter.at(i) - coords.at(i) ) * ( cellCenter.at(i) - coords.at(i) );
00246 }
00247 }
00248
00249 dist = sqrt(dist);
00250 if ( dist > ( cellRadius + radius ) ) {
00251 return BBS_OUTSIDECELL;
00252 }
00253
00254 int centerInside = this->containsPoint(coords);
00255 if ( centerInside ) {
00256 for ( i = 1; i <= size; i++ ) {
00257 if ( localizer->giveOctreeMaskValue(i) ) {
00258 if ( ( this->origin.at(i) > ( coords.at(i) - radius ) ) || ( ( this->origin.at(i) + this->size ) < ( coords.at(i) + radius ) ) ) {
00259 test = 0;
00260 }
00261 }
00262 }
00263
00264 if ( test ) {
00265 return BBS_INSIDECELL;
00266 } else {
00267 return BBS_CONTAINSCELL;
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277 } else {
00278
00279 int inBounds = 1;
00280 for ( i = 1; i <= size; i++ ) {
00281 if ( localizer->giveOctreeMaskValue(i) && ( fabs( cellCenter.at(i) - coords.at(i) ) > ( this->size / 2. + radius ) ) ) {
00282 inBounds = 0;
00283 }
00284 }
00285
00286 if ( inBounds ) {
00287 return BBS_CONTAINSCELL;
00288 }
00289 }
00290
00291 return BBS_OUTSIDECELL;
00292 }
00293
00294
00295 oofemOctantRec *
00296 OctreeSpatialLocalizer :: findTerminalContaining(oofemOctantRec *startCell, const FloatArray &coords) {
00297 int result;
00298 oofemOctantRec *currCell = startCell;
00299 if ( startCell->containsPoint(coords) ) {
00300
00301 while ( !currCell->isTerminalOctant() ) {
00302 result = currCell->giveChildContainingPoint(& currCell, coords);
00303 if ( result == -2 ) {
00304 _error("findTerminalContaining: internal error - octree inconsistency");
00305 }
00306 }
00307
00308 ;
00309
00310 return currCell;
00311 } else {
00312
00313
00314 return NULL;
00315 }
00316 }
00317
00318
00319 int
00320 OctreeSpatialLocalizer :: buildOctreeDataStructure()
00321 {
00322 int i, j, init = 1, nnode = this->domain->giveNumberOfDofManagers();
00323 double rootSize, resolutionLimit;
00324 FloatArray minc(3), maxc(3), * coords;
00325 DofManager *dman;
00326
00327
00328 if ( rootCell ) {
00329 return 1;
00330 }
00331
00332
00333 clock_t sc = :: clock();
00334 clock_t ec;
00335
00336
00337 for ( i = 1; i <= nnode; i++ ) {
00338 dman = domain->giveDofManager(i);
00339 if ( ( dman->giveClassID() == NodeClass ) || ( dman->giveClassID() == RigidArmNodeClass ) ) {
00340 coords = ( ( ( Node * ) dman )->giveCoordinates() );
00341 if ( init ) {
00342 init = 0;
00343 for ( j = 1; j <= coords->giveSize(); j++ ) {
00344 minc.at(j) = maxc.at(j) = coords->at(j);
00345 }
00346 } else {
00347 for ( j = 1; j <= coords->giveSize(); j++ ) {
00348 if ( coords->at(j) < minc.at(j) ) {
00349 minc.at(j) = coords->at(j);
00350 }
00351
00352 if ( coords->at(j) > maxc.at(j) ) {
00353 maxc.at(j) = coords->at(j);
00354 }
00355 }
00356 }
00357 }
00358 }
00359
00360
00361 rootSize = 0.0;
00362 for ( i = 1; i <= 3; i++ ) {
00363 rootSize = 1.000001 * max( rootSize, maxc.at(i) - minc.at(i) );
00364 }
00365
00366
00367 resolutionLimit = min(1.e-3, rootSize / 1.e6);
00368 for ( i = 1; i <= 3; i++ ) {
00369 if ( ( maxc.at(i) - minc.at(i) ) > resolutionLimit ) {
00370 this->octreeMask.at(i) = 1;
00371 } else {
00372 this->octreeMask.at(i) = 0;
00373 }
00374 }
00375
00376
00377 this->rootCell = new oofemOctantRec(this, NULL, minc, rootSize);
00378
00379
00380 if ( nnode > OCTREE_MAX_NODES_LIMIT ) {
00381 this->rootCell->divideLocally(1, this->octreeMask);
00382 }
00383
00384
00385 for ( i = 1; i <= nnode; i++ ) {
00386 dman = domain->giveDofManager(i);
00387 if ( ( dman->giveClassID() == NodeClass ) || ( dman->giveClassID() == RigidArmNodeClass ) ) {
00388 coords = ( ( ( Node * ) dman )->giveCoordinates() );
00389 this->insertNodeIntoOctree(this->rootCell, i, * coords);
00390 }
00391 }
00392
00393
00394 this->initElementIPDataStructure();
00395
00396 ec = :: clock();
00397
00398
00399 int treeDepth = 0;
00400 this->giveMaxTreeDepthFrom(this->rootCell, treeDepth);
00401
00402 long nsec = ( ec - sc ) / CLOCKS_PER_SEC;
00403 OOFEM_LOG_INFO("Octree init [depth %d in %lds]\n", treeDepth, nsec);
00404
00405 return 1;
00406 }
00407
00408
00409 int
00410 OctreeSpatialLocalizer :: initElementIPDataStructure()
00411 {
00412
00413
00414 int i, j, nip;
00415 int nelems = this->domain->giveNumberOfElements();
00416 Element *ielem;
00417 IntegrationRule *iRule;
00418 GaussPoint *jGp;
00419 FloatArray jGpCoords;
00420
00421 if ( this->elementIPListsInitialized ) {
00422 return 1;
00423 }
00424
00425
00426 for ( i = 1; i <= nelems; i++ ) {
00427
00428 ielem = this->giveDomain()->giveElement(i);
00429 iRule = ielem->giveDefaultIntegrationRulePtr();
00430 nip = iRule->getNumberOfIntegrationPoints();
00431 if ( nip ) {
00432 for ( j = 0; j < iRule->getNumberOfIntegrationPoints(); j++ ) {
00433 jGp = iRule->getIntegrationPoint(j);
00434 if ( ielem->computeGlobalCoordinates( jGpCoords, * ( jGp->giveCoordinates() ) ) ) {
00435 this->insertIPElementIntoOctree(this->rootCell, i, jGpCoords);
00436 } else {
00437 _error("initElementIPDataStructure: computeGlobalCoordinates failed");
00438 }
00439 }
00440 } else {
00441
00442
00443
00444 FloatArray *nc;
00445 for ( j = 1; j <= ielem->giveNumberOfNodes(); j++ ) {
00446 nc = ielem->giveNode(j)->giveCoordinates();
00447 this->insertIPElementIntoOctree(this->rootCell, i, * nc);
00448 }
00449 }
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 this->elementIPListsInitialized = 1;
00468 return 1;
00469 }
00470
00471
00472
00473 int
00474 OctreeSpatialLocalizer :: insertIPElementIntoOctree(oofemOctantRec *rootCell, int elemNum, const FloatArray &coords)
00475 {
00476 oofemOctantRec *currCell;
00477
00478
00479 currCell = this->findTerminalContaining(rootCell, coords);
00480
00481 currCell->addElementIP(elemNum);
00482 return 1;
00483 }
00484
00485 void
00486 OctreeSpatialLocalizer :: insertElementsUsingNodalConnectivitiesIntoOctree(oofemOctantRec *currCell)
00487 {
00488 int i, j, k;
00489
00490 if ( currCell->isTerminalOctant() ) {
00491 nodeContainerType *cellNodes = currCell->giveNodeList();
00492 nodeContainerType :: iterator pos;
00493 const IntArray *dofmanConnectivity;
00494 int size;
00495
00496 if ( !cellNodes->empty() ) {
00497 for ( pos = cellNodes->begin(); pos != cellNodes->end(); ++pos ) {
00498
00499 dofmanConnectivity = domain->giveConnectivityTable()->giveDofManConnectivityArray(* pos);
00500 if ( dofmanConnectivity ) {
00501 size = dofmanConnectivity->giveSize();
00502 for ( i = 1; i <= size; i++ ) {
00503 currCell->addElementIP( dofmanConnectivity->at(i) );
00504 }
00505 }
00506 }
00507 }
00508 } else {
00509 for ( i = 0; i <= octreeMask.at(1); i++ ) {
00510 for ( j = 0; j <= octreeMask.at(2); j++ ) {
00511 for ( k = 0; k <= octreeMask.at(3); k++ ) {
00512 if ( currCell->giveChild(i, j, k) ) {
00513 this->insertElementsUsingNodalConnectivitiesIntoOctree( currCell->giveChild(i, j, k) );
00514 }
00515 }
00516 }
00517 }
00518 }
00519 }
00520
00521
00522 int
00523 OctreeSpatialLocalizer :: insertNodeIntoOctree(oofemOctantRec *rootCell, int nodeNum, const FloatArray &coords)
00524 {
00525 int nCellItems, cellDepth, result;
00526 oofemOctantRec *currCell;
00527 nodeContainerType *cellNodeList;
00528 nodeContainerType :: const_iterator pos;
00529 DofManager *dman;
00530 FloatArray *nodeCoords;
00531
00532
00533 currCell = this->findTerminalContaining(rootCell, coords);
00534
00535 cellNodeList = currCell->giveNodeList();
00536 nCellItems = cellNodeList->size();
00537 cellDepth = this->giveCellDepth(currCell);
00538
00539
00540
00541 if ( ( nCellItems > OCTREE_MAX_NODES_LIMIT ) && ( cellDepth <= OCTREE_MAX_DEPTH ) ) {
00542
00543 currCell->divideLocally(1, this->octreeMask);
00544
00545 for ( pos = cellNodeList->begin(); pos != cellNodeList->end(); ++pos ) {
00546 dman = domain->giveDofManager(* pos);
00547 nodeCoords = ( ( ( Node * ) dman )->giveCoordinates() );
00548 this->insertNodeIntoOctree(currCell, * pos, * nodeCoords);
00549 }
00550
00551
00552 currCell->deleteNodeList();
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564 result = currCell->giveChildContainingPoint(& currCell, coords);
00565 if ( result != 1 ) {
00566 _error("insertNodeIntoOctree: internal error - octree inconsistency");
00567 }
00568 }
00569
00570 currCell->addNode(nodeNum);
00571 return 1;
00572 }
00573
00574
00575
00576
00577 Element *
00578 OctreeSpatialLocalizer :: giveElementContainingPoint(const FloatArray &coords, const IntArray *regionList)
00579 {
00580 Element *answer;
00581
00582 oofemOctantRec *currCell, *childCell = NULL;
00583
00584 this->init();
00585
00586
00587 currCell = this->findTerminalContaining(rootCell, coords);
00588 if ( currCell == NULL ) {
00589 currCell = rootCell;
00590 }
00591
00592 while ( currCell != NULL ) {
00593
00594 answer = this->giveElementContainingPoint(currCell, coords, childCell, regionList);
00595 if ( answer ) {
00596 return answer;
00597 }
00598
00599 childCell = currCell;
00600
00601
00602 currCell = currCell->giveParent();
00603 }
00604
00605
00606 return NULL;
00607 }
00608
00609
00610 Element *
00611 OctreeSpatialLocalizer :: giveElementContainingPoint(oofemOctantRec *cell, const FloatArray &coords,
00612 oofemOctantRec *scannedChild, const IntArray *regionList)
00613 {
00614 elementContainerType *elementList = cell->giveIPElementList();
00615
00616
00617 if ( cell->isTerminalOctant() && ( !elementList->empty() ) ) {
00618 int ielem;
00619 Element *ielemptr;
00620 SpatialLocalizerInterface *interface;
00621 elementContainerType :: iterator pos;
00622
00623 for ( pos = elementList->begin(); pos != elementList->end(); ++pos ) {
00624 ielem = * pos;
00625 ielemptr = this->giveDomain()->giveElement(ielem);
00626
00627
00628 #ifdef __PARALLEL_MODE
00629 if ( ielemptr->giveParallelMode() == Element_remote ) {
00630 continue;
00631 }
00632
00633 #endif
00634
00635 interface = ( SpatialLocalizerInterface * ) ielemptr->giveInterface(SpatialLocalizerInterfaceType);
00636 if ( interface ) {
00637 if ( regionList && ( regionList->findFirstIndexOf( ielemptr->giveRegionNumber() ) == 0 ) ) {
00638 continue;
00639 }
00640
00641 if ( interface->SpatialLocalizerI_BBoxContainsPoint(coords) == 0 ) {
00642 continue;
00643 }
00644
00645 if ( interface->SpatialLocalizerI_containsPoint(coords) ) {
00646 return ielemptr;
00647 }
00648 }
00649 }
00650
00651 return NULL;
00652 } else {
00653 int i, j, k;
00654 Element *answer;
00655
00656 for ( i = 0; i <= octreeMask.at(1); i++ ) {
00657 for ( j = 0; j <= octreeMask.at(2); j++ ) {
00658 for ( k = 0; k <= octreeMask.at(3); k++ ) {
00659 if ( cell->giveChild(i, j, k) ) {
00660 if ( scannedChild == cell->giveChild(i, j, k) ) {
00661 continue;
00662 }
00663
00664 answer = this->giveElementContainingPoint(cell->giveChild(i, j, k), coords, NULL, regionList);
00665 if ( answer ) {
00666 return answer;
00667 }
00668 }
00669 }
00670 }
00671 }
00672 }
00673
00674 return NULL;
00675 }
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686 Element *
00687 OctreeSpatialLocalizer :: giveElementCloseToPoint(const FloatArray &coords, const IntArray *regionList)
00688 {
00689 Element *ielemptr, *answer;
00690 double currDist, minDist = 1.1 * rootCell->giveSize();
00691 elementContainerType :: iterator pos;
00692 elementContainerType *elementList;
00693 oofemOctantRec *currCell;
00694
00695 this->init();
00696
00697
00698 currCell = this->findTerminalContaining(rootCell, coords);
00699
00700 if ( currCell != NULL ) {
00701 elementList = currCell->giveIPElementList();
00702 if ( !elementList->empty() ) {
00703 SpatialLocalizerInterface *interface;
00704
00705 for ( pos = elementList->begin(); pos != elementList->end(); ++pos ) {
00706 ielemptr = this->giveDomain()->giveElement(* pos);
00707
00708
00709 #ifdef __PARALLEL_MODE
00710 if ( ielemptr->giveParallelMode() == Element_remote ) {
00711 continue;
00712 }
00713
00714 #endif
00715
00716 interface = ( SpatialLocalizerInterface * ) ielemptr->giveInterface(SpatialLocalizerInterfaceType);
00717 if ( interface ) {
00718 if ( regionList && ( regionList->findFirstIndexOf( ielemptr->giveRegionNumber() ) == 0 ) ) {
00719 continue;
00720 }
00721
00722 currDist = interface->SpatialLocalizerI_giveDistanceFromParametricCenter(coords);
00723 if ( currDist < minDist ) {
00724 answer = ielemptr;
00725 minDist = currDist;
00726 }
00727 } else {
00728 _error("giveElementCloseToPoint: no interface");
00729 }
00730 }
00731
00732 if ( minDist == 0.0 || currCell == rootCell ) {
00733 return answer;
00734 }
00735 }
00736 }
00737
00738 oofemOctantRec :: boundingBoxStatus BBStatus;
00739 FloatArray bborigin = coords;
00740
00741
00742 BBStatus = currCell->testBoundingBox(bborigin, minDist);
00743 if ( BBStatus == oofemOctantRec :: BBS_INSIDECELL ) {
00744 return answer;
00745 } else if ( BBStatus == oofemOctantRec :: BBS_CONTAINSCELL ) {
00746 std :: list< oofemOctantRec * >cellList;
00747 std :: list< oofemOctantRec * > :: iterator cellListIt;
00748
00749
00750 oofemOctantRec *startCell = this->findTerminalContaining(rootCell, coords);
00751 if ( startCell == NULL ) {
00752 startCell = rootCell;
00753 }
00754
00755
00756 if ( startCell != rootCell ) {
00757 while ( startCell->testBoundingBox(coords, minDist) != oofemOctantRec :: BBS_INSIDECELL ) {
00758 startCell = startCell->giveParent();
00759 if ( startCell == rootCell ) {
00760 break;
00761 }
00762 }
00763 }
00764
00765 this->giveListOfTerminalCellsInBoundingBox(cellList, bborigin, minDist, startCell);
00766
00767 for ( cellListIt = cellList.begin(); cellListIt != cellList.end(); ++cellListIt ) {
00768 if ( currCell == ( * cellListIt ) ) {
00769 continue;
00770 }
00771
00772 this->giveElementCloseToPointWithinOctant( ( * cellListIt ), coords, minDist, & answer, regionList );
00773 }
00774 }
00775
00776 return answer;
00777 }
00778
00779
00780 void
00781 OctreeSpatialLocalizer :: giveElementCloseToPointWithinOctant(oofemOctantRec *cell, const FloatArray &coords,
00782 double &minDist, Element **answer,
00783 const IntArray *regionList)
00784 {
00785 if ( cell->isTerminalOctant() ) {
00786 Element *ielemptr;
00787 SpatialLocalizerInterface *interface;
00788 elementContainerType *elementList = cell->giveIPElementList();
00789 elementContainerType :: iterator pos;
00790 double currDist;
00791
00792 if ( !elementList->empty() ) {
00793 for ( pos = elementList->begin(); pos != elementList->end(); ++pos ) {
00794 ielemptr = this->giveDomain()->giveElement(* pos);
00795
00796
00797 #ifdef __PARALLEL_MODE
00798 if ( ielemptr->giveParallelMode() == Element_remote ) {
00799 continue;
00800 }
00801
00802 #endif
00803
00804 interface = ( SpatialLocalizerInterface * ) ielemptr->giveInterface(SpatialLocalizerInterfaceType);
00805 if ( interface ) {
00806 if ( regionList && ( regionList->findFirstIndexOf( ielemptr->giveRegionNumber() ) == 0 ) ) {
00807 continue;
00808 }
00809
00810 currDist = interface->SpatialLocalizerI_giveDistanceFromParametricCenter(coords);
00811 if ( currDist < minDist ) {
00812 * answer = ielemptr;
00813 minDist = currDist;
00814 }
00815 } else {
00816 _error("giveElementCloseToPointWithinOctant: no interface");
00817 }
00818 }
00819 }
00820
00821 return;
00822 } else {
00823 int i, j, k;
00824 oofemOctantRec :: boundingBoxStatus BBStatus;
00825
00826 for ( i = 0; i <= octreeMask.at(1); i++ ) {
00827 for ( j = 0; j <= octreeMask.at(2); j++ ) {
00828 for ( k = 0; k <= octreeMask.at(3); k++ ) {
00829 if ( cell->giveChild(i, j, k) ) {
00830
00831 BBStatus = cell->giveChild(i, j, k)->testBoundingBox(coords, minDist);
00832 if ( ( BBStatus == oofemOctantRec :: BBS_INSIDECELL ) || ( BBStatus == oofemOctantRec :: BBS_CONTAINSCELL ) ) {
00833
00834 this->giveElementCloseToPointWithinOctant(cell->giveChild(i, j, k), coords, minDist, answer, regionList);
00835 }
00836 }
00837 }
00838 }
00839 }
00840 }
00841
00842 return;
00843 }
00844
00845
00846
00847 GaussPoint *
00848 OctreeSpatialLocalizer :: giveClosestIP(const FloatArray &coords, int region)
00849 {
00850 int j;
00851 double dist, minDist;
00852 oofemOctantRec *currCell;
00853 GaussPoint *nearestGp, *jGp;
00854 oofemOctantRec :: boundingBoxStatus BBStatus;
00855 elementContainerType :: iterator pos;
00856 elementContainerType *elementList;
00857 Element *ielem;
00858 FloatArray jGpCoords;
00859 IntegrationRule *iRule;
00860
00861 this->init();
00862
00863
00864
00865 minDist = 1.1 * rootCell->giveSize();
00866
00867 currCell = this->findTerminalContaining(rootCell, coords);
00868 elementList = currCell->giveIPElementList();
00869
00870 if ( !elementList->empty() ) {
00871 for ( pos = elementList->begin(); pos != elementList->end(); ++pos ) {
00872 ielem = domain->giveElement(* pos);
00873
00874
00875 #ifdef __PARALLEL_MODE
00876 if ( ielem->giveParallelMode() == Element_remote ) {
00877 continue;
00878 }
00879
00880 #endif
00881
00882
00883 if ( ( region > 0 ) && ( region != ielem->giveRegionNumber() ) ) {
00884 continue;
00885 }
00886
00887
00888
00889 iRule = ielem->giveDefaultIntegrationRulePtr();
00890 for ( j = 0; j < iRule->getNumberOfIntegrationPoints(); j++ ) {
00891 jGp = iRule->getIntegrationPoint(j);
00892 if ( ielem->computeGlobalCoordinates( jGpCoords, * ( jGp->giveCoordinates() ) ) ) {
00893
00894 dist = coords.distance(jGpCoords);
00895 if ( dist < minDist ) {
00896 minDist = dist;
00897 nearestGp = jGp;
00898 }
00899 } else {
00900 _error("giveClosestIP: computeGlobalCoordinates failed");
00901 }
00902 }
00903 }
00904 }
00905
00906 FloatArray bborigin = coords;
00907
00908
00909 BBStatus = currCell->testBoundingBox(bborigin, minDist);
00910 if ( BBStatus == oofemOctantRec :: BBS_INSIDECELL ) {
00911 return nearestGp;
00912 } else if ( BBStatus == oofemOctantRec :: BBS_CONTAINSCELL ) {
00913 std :: list< oofemOctantRec * >cellList;
00914 std :: list< oofemOctantRec * > :: iterator cellListIt;
00915
00916
00917 oofemOctantRec *startCell = this->findTerminalContaining(rootCell, coords);
00918
00919 if ( startCell != rootCell ) {
00920 while ( startCell->testBoundingBox(coords, minDist) != oofemOctantRec :: BBS_INSIDECELL ) {
00921 startCell = startCell->giveParent();
00922 if ( startCell == rootCell ) {
00923 break;
00924 }
00925 }
00926 }
00927
00928 this->giveListOfTerminalCellsInBoundingBox(cellList, bborigin, minDist, startCell);
00929
00930 for ( cellListIt = cellList.begin(); cellListIt != cellList.end(); ++cellListIt ) {
00931 if ( currCell == ( * cellListIt ) ) {
00932 continue;
00933 }
00934
00935 this->giveClosestIPWithinOctant( ( * cellListIt ), coords, region, minDist, & nearestGp );
00936 }
00937
00938 return nearestGp;
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987 } else {
00988 _error("giveClosestIP: octree inconsistency found");
00989 }
00990
00991 return NULL;
00992 }
00993
00994 void
00995 OctreeSpatialLocalizer :: giveClosestIPWithinOctant(oofemOctantRec *currentCell,
00996 const FloatArray &coords,
00997 int region, double &dist, GaussPoint **answer)
00998 {
00999 if ( currentCell->isTerminalOctant() ) {
01000 int j;
01001 double currDist;
01002 elementContainerType :: iterator pos;
01003 elementContainerType *elementList;
01004
01005 Element *ielem;
01006 IntegrationRule *iRule;
01007 FloatArray jGpCoords;
01008
01009
01010 elementList = currentCell->giveIPElementList();
01011 if ( !elementList->empty() ) {
01012 for ( pos = elementList->begin(); pos != elementList->end(); ++pos ) {
01013
01014 ielem = domain->giveElement(* pos);
01015
01016
01017 #ifdef __PARALLEL_MODE
01018 if ( ielem->giveParallelMode() == Element_remote ) {
01019 continue;
01020 }
01021
01022 #endif
01023
01024 if ( ( region > 0 ) && ( region != ielem->giveRegionNumber() ) ) {
01025 continue;
01026 }
01027
01028
01029
01030
01031 iRule = ielem->giveDefaultIntegrationRulePtr();
01032 for ( j = 0; j < iRule->getNumberOfIntegrationPoints(); j++ ) {
01033 if ( ielem->computeGlobalCoordinates( jGpCoords, * ( iRule->getIntegrationPoint(j)->giveCoordinates() ) ) ) {
01034 currDist = coords.distance(jGpCoords);
01035
01036 if ( currDist <= dist ) {
01037 dist = currDist;
01038 * answer = iRule->getIntegrationPoint(j);
01039 }
01040 } else {
01041 _error("giveClosestIPWithinOctant: computeGlobalCoordinates failed");
01042 }
01043 }
01044 }
01045 }
01046
01047 return;
01048 } else {
01049 int i, j, k;
01050 oofemOctantRec :: boundingBoxStatus BBStatus;
01051
01052 for ( i = 0; i <= octreeMask.at(1); i++ ) {
01053 for ( j = 0; j <= octreeMask.at(2); j++ ) {
01054 for ( k = 0; k <= octreeMask.at(3); k++ ) {
01055 if ( currentCell->giveChild(i, j, k) ) {
01056
01057 BBStatus = currentCell->giveChild(i, j, k)->testBoundingBox(coords, dist);
01058 if ( ( BBStatus == oofemOctantRec :: BBS_INSIDECELL ) || ( BBStatus == oofemOctantRec :: BBS_CONTAINSCELL ) ) {
01059
01060
01061 this->giveClosestIPWithinOctant(currentCell->giveChild(i, j, k), coords, region, dist, answer);
01062 }
01063 }
01064 }
01065 }
01066 }
01067 }
01068 }
01069
01070
01071
01072
01073 void
01074 OctreeSpatialLocalizer :: giveAllElementsWithIpWithinBox(elementContainerType &elemSet, const FloatArray &coords,
01075 const double radius)
01076 {
01077 this->init();
01078
01079 oofemOctantRec *currCell = this->findTerminalContaining(rootCell, coords);
01080
01081 if ( currCell != rootCell ) {
01082 while ( currCell->testBoundingBox(coords, radius) != oofemOctantRec :: BBS_INSIDECELL ) {
01083 currCell = currCell->giveParent();
01084 if ( currCell == rootCell ) {
01085 break;
01086 }
01087 }
01088 }
01089
01090
01091 this->giveElementsWithIPWithinBox(elemSet, currCell, coords, radius);
01092 if ( elemSet.empty() ) {
01093 _error("OctreeSpatialLocalizer::giveAllElementsWithIpWithinBox empty set found");
01094 }
01095 }
01096
01097
01098
01099 void
01100 OctreeSpatialLocalizer :: giveElementsWithIPWithinBox(elementContainerType &elemSet, oofemOctantRec *currentCell,
01101 const FloatArray &coords, const double radius)
01102 {
01103 if ( currentCell->isTerminalOctant() ) {
01104 int j;
01105 double currDist;
01106 elementContainerType :: iterator pos;
01107 elementContainerType *elementList;
01108
01109 Element *ielem;
01110 IntegrationRule *iRule;
01111 FloatArray jGpCoords;
01112
01113
01114 elementList = currentCell->giveIPElementList();
01115 if ( !elementList->empty() ) {
01116 for ( pos = elementList->begin(); pos != elementList->end(); ++pos ) {
01117
01118 if ( elemSet.find(* pos) != elemSet.end() ) {
01119 continue;
01120 }
01121
01122
01123 ielem = domain->giveElement(* pos);
01124
01125
01126
01127
01128
01129
01130
01131 iRule = ielem->giveDefaultIntegrationRulePtr();
01132 for ( j = 0; j < iRule->getNumberOfIntegrationPoints(); j++ ) {
01133 if ( ielem->computeGlobalCoordinates( jGpCoords, * ( iRule->getIntegrationPoint(j)->giveCoordinates() ) ) ) {
01134 currDist = coords.distance(jGpCoords);
01135
01136 if ( currDist <= radius ) {
01137 elemSet.insert(* pos);
01138 }
01139 } else {
01140 _error("giveElementsWithIPWithinBox: computeGlobalCoordinates failed");
01141 }
01142 }
01143 }
01144 }
01145 } else {
01146 int i, j, k;
01147 oofemOctantRec :: boundingBoxStatus BBStatus;
01148
01149
01150 for ( i = 0; i <= octreeMask.at(1); i++ ) {
01151 for ( j = 0; j <= octreeMask.at(2); j++ ) {
01152 for ( k = 0; k <= octreeMask.at(3); k++ ) {
01153 if ( currentCell->giveChild(i, j, k) ) {
01154
01155 BBStatus = currentCell->giveChild(i, j, k)->testBoundingBox(coords, radius);
01156 if ( ( BBStatus == oofemOctantRec :: BBS_INSIDECELL ) || ( BBStatus == oofemOctantRec :: BBS_CONTAINSCELL ) ) {
01157
01158 this->giveElementsWithIPWithinBox(elemSet, currentCell->giveChild(i, j, k), coords, radius);
01159 }
01160 }
01161 }
01162 }
01163 }
01164 }
01165 }
01166
01167
01168
01169 void
01170 OctreeSpatialLocalizer :: giveAllNodesWithinBox(nodeContainerType &nodeSet, const FloatArray &coords, const double radius)
01171 {
01172 this->init();
01173
01174 oofemOctantRec *currCell = this->findTerminalContaining(rootCell, coords);
01175
01176 if ( currCell != rootCell ) {
01177 while ( currCell->testBoundingBox(coords, radius) != oofemOctantRec :: BBS_INSIDECELL ) {
01178 currCell = currCell->giveParent();
01179 if ( currCell == rootCell ) {
01180 break;
01181 }
01182 }
01183 }
01184
01185
01186 this->giveNodesWithinBox(nodeSet, currCell, coords, radius);
01187 }
01188
01189 void
01190 OctreeSpatialLocalizer :: giveNodesWithinBox(nodeContainerType &nodeList, oofemOctantRec *currentCell,
01191 const FloatArray &coords, const double radius)
01192 {
01193 nodeContainerType *cellNodes = currentCell->giveNodeList();
01194 nodeContainerType :: iterator pos;
01195
01196 if ( currentCell->isTerminalOctant() ) {
01197 FloatArray *nodeCoords;
01198 if ( !cellNodes->empty() ) {
01199 for ( pos = cellNodes->begin(); pos != cellNodes->end(); ++pos ) {
01200
01201 nodeCoords = domain->giveNode(* pos)->giveCoordinates();
01202
01203 if ( nodeCoords->distance(coords) <= radius ) {
01204
01205 nodeList.push_back(* pos);
01206 }
01207 }
01208 }
01209 } else {
01210 int i, j, k;
01211 oofemOctantRec :: boundingBoxStatus BBStatus;
01212
01213 for ( i = 0; i <= octreeMask.at(1); i++ ) {
01214 for ( j = 0; j <= octreeMask.at(2); j++ ) {
01215 for ( k = 0; k <= octreeMask.at(3); k++ ) {
01216 if ( currentCell->giveChild(i, j, k) ) {
01217
01218 BBStatus = currentCell->giveChild(i, j, k)->testBoundingBox(coords, radius);
01219 if ( ( BBStatus == oofemOctantRec :: BBS_INSIDECELL ) || ( BBStatus == oofemOctantRec :: BBS_CONTAINSCELL ) ) {
01220
01221 this->giveNodesWithinBox(nodeList, currentCell->giveChild(i, j, k), coords, radius);
01222 }
01223 }
01224 }
01225 }
01226 }
01227 }
01228 }
01229
01230
01231 int
01232 OctreeSpatialLocalizer :: giveCellDepth(oofemOctantRec *cell)
01233 {
01234 return ( int ) ( log( this->rootCell->giveSize() / cell->giveSize() ) / M_LN2 );
01235 }
01236
01237 void
01238 OctreeSpatialLocalizer :: giveMaxTreeDepthFrom(oofemOctantRec *root, int &maxDepth)
01239 {
01240 int i, j, k, depth = this->giveCellDepth(root);
01241 maxDepth = max(maxDepth, depth);
01242
01243 for ( i = 0; i <= octreeMask.at(1); i++ ) {
01244 for ( j = 0; j <= octreeMask.at(2); j++ ) {
01245 for ( k = 0; k <= octreeMask.at(3); k++ ) {
01246 if ( root->giveChild(i, j, k) ) {
01247 this->giveMaxTreeDepthFrom(root->giveChild(i, j, k), maxDepth);
01248 }
01249 }
01250 }
01251 }
01252 }
01253
01254
01255 void
01256 OctreeSpatialLocalizer :: giveListOfTerminalCellsInBoundingBox(std :: list< oofemOctantRec * > &cellList, const FloatArray &coords,
01257 const double radius, oofemOctantRec *currentCell)
01258 {
01259 int i, j, k;
01260 oofemOctantRec :: boundingBoxStatus BBStatus;
01261
01262 BBStatus = currentCell->testBoundingBox(coords, radius);
01263 if ( ( BBStatus == oofemOctantRec :: BBS_INSIDECELL ) || ( BBStatus == oofemOctantRec :: BBS_CONTAINSCELL ) ) {
01264 if ( currentCell->isTerminalOctant() ) {
01265 cellList.push_back(currentCell);
01266 } else {
01267 for ( i = 0; i <= octreeMask.at(1); i++ ) {
01268 for ( j = 0; j <= octreeMask.at(2); j++ ) {
01269 for ( k = 0; k <= octreeMask.at(3); k++ ) {
01270 if ( currentCell->giveChild(i, j, k) ) {
01271 this->giveListOfTerminalCellsInBoundingBox( cellList, coords, radius, currentCell->giveChild(i, j, k) );
01272 }
01273 }
01274 }
01275 }
01276 }
01277 }
01278 }
01279
01280 int
01281 OctreeSpatialLocalizer::init(bool force)
01282 {
01283 if (force) {
01284 if (rootCell) delete rootCell;
01285 rootCell = NULL;
01286 elementIPListsInitialized = 0;
01287 }
01288 if ( !rootCell ) { return this->buildOctreeDataStructure(); } else { return 0; }
01289 }