1 #ifndef ALUGRID_COMPATIBILITY_CHECK_HH_INCLUDED 2 #define ALUGRID_COMPATIBILITY_CHECK_HH_INCLUDED 3 4 #include <iostream> 5 #include <array> 6 #include <map> 7 #include <list> 8 #include <vector> 9 #include <algorithm> 10 #include <assert.h> 11 #include <random> 12 13 #include <dune/common/timer.hh> 14 15 struct BisectionCompatibilityParameters 16 { variantBisectionCompatibilityParameters17 static int& variant () 18 { 19 static int var = 0; // default is every vertex in set V0 20 return var; 21 } 22 thresholdBisectionCompatibilityParameters23 static int& threshold () 24 { 25 static int var = 2; // default is 2 for threshold 26 return var; 27 } 28 useAnnouncedEdgeBisectionCompatibilityParameters29 static int& useAnnouncedEdge () 30 { 31 static int var = 1 ; // default is use announced edges 32 return var; 33 } 34 }; 35 36 //Class to correct the element orientation to make bisection work in 3d 37 // It provides different algorithms to orientate a grid. 38 // Also implements checks for compatibility. 39 template <class VertexVector> 40 class BisectionCompatibility 41 { 42 typedef BisectionCompatibility< VertexVector > ThisType; 43 public: 44 // type of vertex coordinates stored inside the factory 45 typedef VertexVector VertexVectorType; 46 47 typedef std::array<unsigned int, 3> FaceType; 48 typedef std::vector< unsigned int > ElementType; 49 typedef std::array<unsigned int, 2> EdgeType; 50 typedef std::map< FaceType, EdgeType > FaceMapType; 51 typedef std::pair< FaceType, EdgeType > FaceElementType; 52 53 protected: 54 const VertexVectorType& vertices_; 55 56 //the elements to be renumbered 57 std::vector<ElementType> elements_; 58 std::vector<bool> elementOrientation_; 59 //the neighbouring structure 60 FaceMapType neighbours_; 61 // the number of vertices 62 const size_t nVertices_; 63 //A tag vector for vertices to 64 //decide whether they are in V_1 or v_0 65 std::vector<bool> containedInV0_; 66 //the element types 67 std::vector<int> types_; 68 //true if stevenson notation is used 69 //false for ALBERTA 70 bool stevensonRefinement_; 71 72 //the 2 nodes of the refinement edge 73 EdgeType type0nodes_; // = stevensonRefinement_ ? 0,3 : 0,1 ; 74 //the faces opposite of type 0 nodes 75 EdgeType type0faces_; 76 //The interior node of a type 1 element 77 unsigned int type1node_; // = stevensonRefinement_ ? 1 : 2; 78 //the face opposite of the interior node 79 unsigned int type1face_; // = 3 - type1node_ ; 80 81 // 0 = put all vertices in V0, 82 // 1 = longest edge, 83 // 2 = least adjacent elements, 84 // 3 = random ordering 85 const int variant_ = BisectionCompatibilityParameters::variant() ; 86 const int threshold_ = BisectionCompatibilityParameters::threshold() ; 87 const bool useAnnouncedEdge_ = BisectionCompatibilityParameters::useAnnouncedEdge(); 88 89 public: 90 //constructor taking elements 91 //assumes standard orientation elemIndex % 2 BisectionCompatibility(const VertexVectorType & vertices,const std::vector<ElementType> & elements,const bool stevenson)92 BisectionCompatibility( const VertexVectorType& vertices, 93 const std::vector<ElementType>& elements, 94 const bool stevenson) 95 : vertices_( vertices ), 96 elements_( elements ), 97 elementOrientation_(elements_.size(), true), 98 nVertices_( vertices_.size() ), 99 containedInV0_(nVertices_,true), 100 types_(elements_.size(), 0), 101 stevensonRefinement_(stevenson), 102 type0nodes_( stevensonRefinement_ ? EdgeType{0,3} : EdgeType{0,1} ), 103 type0faces_( stevensonRefinement_ ? EdgeType{3,0} : EdgeType{3,2} ), 104 type1node_( stevensonRefinement_ ? 1 : 2 ), 105 type1face_( 3 - type1node_ ) 106 { 107 //build the information about neighbours 108 Dune::Timer timer; 109 buildNeighbors(); 110 std::cout << "Build neighbors took " << timer.elapsed() << " sec." << std::endl; 111 } 112 113 //check for strong compatibility stronglyCompatibleFaces()114 int stronglyCompatibleFaces () 115 { 116 int result = 0; 117 bool verbose = false; 118 unsigned int bndFaces = 0; 119 std::vector<int> nonCompatFacesAtVertex(nVertices_, 0 ); 120 for(auto&& face : neighbours_) 121 { 122 if( face.second[0] == face.second[1] ) 123 { 124 bndFaces++; 125 } 126 else if(! checkStrongCompatibility(face, verbose)) 127 { 128 ++result; 129 for(size_t i =0; i < 3; ++i) 130 { 131 ++(nonCompatFacesAtVertex[face.first[i]]); 132 } 133 } 134 } 135 std::cout << "NotStrongCompatibleMacroFaces" << " InnerFaces " << " TotalFaces " << "Maximum/Vertex " << " Minimum/Vertex " << std::endl; 136 std::cout << result << " " << neighbours_.size() - bndFaces << " " << neighbours_.size() << " " << *(std::max_element(nonCompatFacesAtVertex.begin(), nonCompatFacesAtVertex.end())) << " " << *(std::min_element(nonCompatFacesAtVertex.begin(), nonCompatFacesAtVertex.end())) << std::endl << std::endl; 137 return result; 138 } 139 140 //check grid for compatibility 141 //i.e. walk over all faces and check their compatibility. compatibilityCheck()142 bool compatibilityCheck () 143 { 144 for(auto&& face : neighbours_) 145 { 146 if(!checkFaceCompatibility(face)) return false; 147 } 148 return true; 149 } 150 make6CompatibilityCheck()151 bool make6CompatibilityCheck() 152 { 153 //set types to 0, and switch vertices 2,3 for elemIndex % 2 154 applyStandardOrientation(); 155 bool result = compatibilityCheck(); 156 //set types to 0, and switch vertices 2,3 for elemIndex % 2 157 applyStandardOrientation(); 158 return result; 159 } 160 161 //print the neighbouring structure printNB()162 void printNB() 163 { 164 for(auto&& face : neighbours_) 165 { 166 std::cout << face.first[0] << "," << face.first[1] << "," << face.first[2] << " : " << face.second[0] << ", " << face.second[1] << std::endl; 167 } 168 } 169 170 //print an element with orientation and all refinement edges printElement(int index)171 void printElement(int index) 172 { 173 ElementType el = elements_[index]; 174 EdgeType edge; 175 std::cout << "[" << el[0] ; 176 for(int i=1; i < 4; ++i) 177 std::cout << ","<< el[i] ; 178 std::cout << "] Refinement Edges: "; 179 for(int i=0; i< 4; ++i) 180 { 181 getRefinementEdge(el, i, edge, types_[index]); 182 std::cout << "[" << edge[0] << "," << edge[1] << "] "; 183 } 184 std::cout << " Type: " << types_[ index ] << " V1: "; 185 for (size_t i = 0; i < 4; ++i) { 186 if( ! containedInV0_[ el [ i ] ] ) 187 std::cout << el[i] << "," ; 188 } 189 std::cout << std::endl; 190 } 191 192 //an algorithm using only elements of type 0 193 //it works by sorting the vertices in a global ordering 194 //and tries to make as many reflected neighbors as possible. type0Algorithm()195 bool type0Algorithm( ) 196 { 197 // convert ordering of refinement edge to stevenson 198 alberta2Stevenson(); 199 200 //calculate the sets V0 and V1 201 calculateV0( variant_, threshold_ ); 202 const bool useAnnounced = useAnnouncedEdge_; 203 204 // all elements are type 0 205 std::fill( types_.begin(), types_.end(), 0 ); 206 207 std::list<std::pair<FaceType, EdgeType> > activeFaceList; // use std::find to find 208 std::vector<bool> doneElements(elements_.size(), false); 209 210 std::vector< std::pair< double, std::pair< int,int > > > vertexOrder( nVertices_ , std::make_pair(-1.0, std::make_pair(-1,-2) ) ); 211 const double eps = std::numeric_limits< double >::epsilon() * double(nVertices_) * 10.0; 212 213 214 const unsigned int l1 = -1; 215 //create the vertex priority List 216 const int numberOfElements = elements_.size(); 217 Dune::Timer timer; 218 for(int counter = 0; counter < numberOfElements ; ++counter) 219 { 220 FaceElementType faceElement = std::make_pair( FaceType{l1,l1,l1}, EdgeType{l1,l1} ); 221 if(counter == 0) 222 { 223 FaceType face; 224 const ElementType& el0 = elements_[0]; 225 getFace(el0, type0faces_[0], face); 226 faceElement = FaceElementType(std::make_pair( face , EdgeType{0,0} ) ); 227 228 //orientate E_0 (add vertices to vertexPriorityList) 229 for(unsigned int i=0 ; i < 4 ; ++i) 230 { 231 int vtx = el0[ i ]; 232 vertexOrder[ vtx ].first = i+1; 233 // previous vertex index or -1 234 vertexOrder[ vtx ].second.first = i > 0 ? el0[ i-1 ] : -1; 235 vertexOrder[ vtx ].second.second = i < 3 ? el0[ i+1 ] : -2; 236 } 237 } 238 else 239 { 240 assert( ! activeFaceList.empty() ); 241 //take element at first face from activeFaceList 242 auto it = activeFaceList.begin(); 243 int el1 = it->second[ 0 ]; 244 int el2 = it->second[ 1 ]; 245 246 while( doneElements[ el1 ] && doneElements[ el2 ] ) 247 { 248 activeFaceList.erase( it++ ); 249 /* 250 if( it == activeFaceList.end() ) 251 { 252 FaceType face; 253 const ElementType& el0 = elements_[0]; 254 getFace(el0, type0faces_[0], face); 255 faceElement = FaceElementType(std::make_pair( face , EdgeType( {0,0} ) ) ); 256 257 //orientate E_0 (add vertices to vertexPriorityList) 258 for(unsigned int i=0 ; i < 4 ; ++i) 259 { 260 int vtx = el0[ i ]; 261 vertexOrder[ vtx ].first = i+1; 262 // previous vertex index or -1 263 vertexOrder[ vtx ].second.first = i > 0 ? el0[ i-1 ] : -1; 264 vertexOrder[ vtx ].second.second = i < 3 ? el0[ i+1 ] : -2; 265 } 266 } 267 */ 268 269 assert( it != activeFaceList.end() ); 270 el1 = it->second[ 0 ]; 271 el2 = it->second[ 1 ]; 272 } 273 274 faceElement = *it; 275 } 276 277 //el has been worked on 278 int elIndex = faceElement.second[0]; 279 280 //neigh is to be worked on 281 int neighIndex = faceElement.second[1]; 282 if(!doneElements[elIndex]) 283 { 284 assert(doneElements[neighIndex] || counter == 0 ); 285 std::swap(elIndex, neighIndex); 286 } 287 288 assert(!doneElements[neighIndex] || counter == 0); 289 doneElements[neighIndex] = true; 290 ElementType el = elements_[elIndex]; 291 ElementType & neigh = elements_[neighIndex]; 292 unsigned int faceInEl = getFaceIndex(el, faceElement.first); 293 unsigned int nodeInEl = 3 - faceInEl; 294 unsigned int faceInNeigh = getFaceIndex(neigh, faceElement.first); 295 unsigned int nodeInNeigh = 3 - faceInNeigh; 296 297 //helper element that contains neigh 298 // in the ordering of vertexPriorityList 299 ElementType newNeigh(el); 300 301 //insertion of new vertex before nodeInEl 302 if( vertexOrder[ neigh [ nodeInNeigh ] ].first < 0 ) 303 { 304 int vxIndex = el[ nodeInEl ]; 305 306 //this takes care that the children will be reflected neighbors 307 //if nodeInNeigh = 3 && nodeInEl = 0 insert after el[3] 308 if( useAnnounced && (nodeInEl == type0nodes_[0] && nodeInNeigh == type0nodes_[1] ) ) 309 { 310 auto& vxPair = vertexOrder[ el[ nodeInNeigh ] ]; 311 // got to next vertex 312 vxIndex = vxPair.second.second; 313 if( vxIndex == -2 ) 314 { 315 vertexOrder[ neigh [ nodeInNeigh ] ] = std::make_pair( vxPair.first+1.0, std::make_pair( el[ nodeInNeigh ], -2 ) ); 316 vxPair.second.second = neigh [ nodeInNeigh ]; 317 } 318 } 319 320 if( vxIndex >= 0 ) 321 { 322 //if nodeInNeigh = 0 && nodeInEl = 3 insert before el[0] 323 if ( useAnnounced && ( nodeInEl == type0nodes_[1] && nodeInNeigh == type0nodes_[0] ) ) 324 { 325 vxIndex = el[ nodeInNeigh ]; 326 } 327 328 auto& vxPair = vertexOrder[ vxIndex ]; 329 assert( vxPair.first >= 0 ); 330 331 // new vertex weight is average between previous and this one 332 const int prevIdx = vxPair.second.first ; 333 double prevOrder = ( prevIdx == -1 ) ? 0.0 : vertexOrder[ prevIdx ].first; 334 double newOrder = 0.5 * (vxPair.first + prevOrder); 335 336 vertexOrder[ neigh [ nodeInNeigh ] ] = std::make_pair( newOrder, std::make_pair( prevIdx, vxIndex ) ); 337 if( prevIdx >= 0 ) 338 vertexOrder[ prevIdx ].second.second = neigh [ nodeInNeigh ]; 339 vxPair.second.first = neigh [ nodeInNeigh ]; 340 assert( vxPair.first > newOrder ); 341 342 if( (vxPair.first - newOrder) < eps ) 343 { 344 #ifndef NDEBUG 345 Dune::Timer restimer; 346 std::cout << "Rescale vertex order weights." << std::endl; 347 #endif 348 std::map< double, int > newVertexOrder; 349 const int size = vertexOrder.size(); 350 for( int j=0; j<size; ++j ) 351 { 352 if( vertexOrder[ j ].first > 0.0 ) 353 { 354 newVertexOrder.insert( std::make_pair( vertexOrder[ j ].first, j ) ); 355 } 356 } 357 358 int count = 1; 359 for( const auto& vx: newVertexOrder ) 360 { 361 assert( vx.second >=0 && vx.second < size ); 362 vertexOrder[ vx.second ].first = count++ ; 363 } 364 365 for( int j=0; j<size; ++j ) 366 { 367 if( vertexOrder[ j ].first > 0.0 && vertexOrder[ j ].second.first >= 0 ) 368 { 369 if( vertexOrder[ j ].first <= vertexOrder[ vertexOrder[ j ].second.first ].first ) 370 std::abort(); 371 } 372 } 373 #ifndef NDEBUG 374 std::cout << "Rescale done, time = " << restimer.elapsed() << std::endl; 375 #endif 376 } 377 } 378 } 379 380 { 381 // sort vertices in ascending order 382 std::map< double, int > vx; 383 for( int j=0; j<4; ++j ) 384 { 385 assert( vertexOrder[ neigh[ j ] ].first > 0 ); 386 vx.insert( std::make_pair( vertexOrder[ neigh[ j ] ].first, j ) ); 387 } 388 389 int count = 0; 390 for( const auto& vxItem : vx ) 391 { 392 newNeigh[ count++ ] = neigh[ vxItem.second ] ; 393 } 394 } 395 396 //adjust type of newNeigh 397 unsigned int type = 0; 398 bool contained[4]; 399 for(unsigned int i =0; i < 4; ++i) 400 { 401 contained[i] = containedInV0_[newNeigh[i]]; 402 } 403 //if all are in V0 or all are V1 404 //we do nothing, set type to 0 and keep the order 405 if( ( contained[0] && contained[1] && contained[2] && contained[3] ) || ( !contained[0] && !contained[1] && !contained[2] && !contained[3] ) ) 406 { 407 //do nothing 408 ; 409 } 410 else 411 { 412 ElementType V0Part(newNeigh); 413 ElementType V1Part(newNeigh); 414 for(unsigned int i = 0 ; i < 4; ++i) 415 { 416 if( contained[ i ] ) 417 { 418 auto it = std::find(V1Part.begin(),V1Part.end(),newNeigh[i]); 419 V1Part.erase( it ); 420 } 421 else 422 { 423 auto it = std::find(V0Part.begin(),V0Part.end(),newNeigh[i]); 424 V0Part.erase( it ); 425 ++type; 426 } 427 } 428 for(unsigned int i = 0; i < 4; ++i) 429 { 430 if(i == 0) 431 newNeigh[ i ] = V0Part[ i ]; 432 else if( i <= type ) 433 newNeigh[ i ] = V1Part[ i - 1 ] ; 434 else if( i > type) 435 newNeigh[ i ] = V0Part[ i - type]; 436 } 437 } 438 types_[neighIndex] = type % 3; 439 440 //reorientate neigh using the helper element newNeigh 441 //we use swaps to be able to track the elementOrientation_ 442 bool neighOrientation = elementOrientation_[neighIndex]; 443 for(unsigned int i =0 ; i < 3; ++i) 444 { 445 if( newNeigh[i] != neigh[i] ) 446 { 447 auto neighIt = std::find(neigh.begin() + i,neigh.end(),newNeigh[i]); 448 std::swap(*neighIt,neigh[i]); 449 neighOrientation = ! neighOrientation; 450 } 451 } 452 elementOrientation_[neighIndex] = neighOrientation; 453 //add and remove faces from activeFaceList 454 for(unsigned int i = 0; i < 4 ; ++i) 455 { 456 getFace(neigh, i, faceElement); 457 //do nothing for boundary 458 if(faceElement.second[0] == faceElement.second[1]) 459 continue; 460 461 //if face does not contain ref Edge 462 if(i != type0faces_[0] && i != type0faces_[1] ) 463 activeFaceList.push_back(faceElement); 464 else 465 activeFaceList.push_front(faceElement); 466 } 467 468 #ifndef NDEBUG 469 const int onePercent = numberOfElements / 100 ; 470 if( onePercent > 0 && counter % onePercent == 0 ) 471 { 472 std::cout << "Done: element " << counter << " of " << numberOfElements << " time used = " << timer.elapsed() << std::endl; 473 timer.reset(); 474 } 475 #endif 476 }// end elements ? 477 478 return compatibilityCheck(); 479 } 480 481 482 //An algorithm using only elements of type 1 type1Algorithm()483 bool type1Algorithm() 484 { 485 // convert to stevenson ordering 486 alberta2Stevenson(); 487 488 //set all types to 1 489 std::fill( types_.begin(), types_.end(), 1 ); 490 491 //the currently active Faces. 492 //and the free faces that can still be adjusted at the end. 493 FaceMapType activeFaces, freeFaces; 494 //the finished elements. The number indicates the fixed node 495 //if it is -1, the element has not been touched yet. 496 std::vector<int> nodePriority; 497 nodePriority.resize(nVertices_ , -1); 498 int currNodePriority =nVertices_; 499 500 const unsigned int numberOfElements = elements_.size(); 501 //walk over all elements 502 for(unsigned int elIndex =0 ; elIndex < numberOfElements; ++elIndex) 503 { 504 //if no node is constrained and no face is active, fix one (e.g. smallest index) 505 ElementType & el = elements_[elIndex]; 506 int priorityNode = -1; 507 FaceType face; 508 int freeNode = -1; 509 for(int i = 0; i < 4; ++i) 510 { 511 int tmpPrio = nodePriority[el[i]]; 512 //if a node has positive priority 513 if( tmpPrio > -1 ) 514 { 515 if( priorityNode < 0 || tmpPrio > nodePriority[el[priorityNode]] ) 516 priorityNode = i; 517 } 518 getFace(el,3 - i,face ); 519 //if we have a free face, the opposite node is good to be fixed 520 if(freeFaces.find(face) != freeFaces.end()) 521 freeNode = i; 522 } 523 if(priorityNode > -1) 524 { 525 fixNode(el, priorityNode); 526 } 527 else if(freeNode > -1) 528 { 529 nodePriority[el[freeNode]] = currNodePriority; 530 fixNode(el, freeNode); 531 --currNodePriority; 532 } 533 else //fix a random node 534 { 535 nodePriority[el[type1node_]] = currNodePriority; 536 fixNode(el, type1node_); 537 --currNodePriority; 538 } 539 540 FaceElementType faceElement; 541 //walk over all faces 542 //add face 2 to freeFaces - if already free -great, match and keep, if active and not free, match and erase 543 getFace(el,type1face_, faceElement); 544 getFace(el,type1face_, face); 545 546 const auto freeFacesEnd = freeFaces.end(); 547 const auto freeFaceIt = freeFaces.find(face); 548 if( freeFaceIt != freeFacesEnd) 549 { 550 while(!checkFaceCompatibility(faceElement)) 551 { 552 rotate(el); 553 } 554 freeFaceIt->second[1] = elIndex; 555 } 556 else if(activeFaces.find(face) != activeFaces.end()) 557 { 558 while(!checkFaceCompatibility(faceElement)) 559 { 560 rotate(el); 561 } 562 activeFaces.erase(face); 563 } 564 else 565 { 566 freeFaces.insert({{face,{elIndex,elIndex}}}); 567 } 568 //add others to activeFaces - if already there, delete, if already free, match and erase 569 //for(int i=0; i<4; ++i ) //auto&& i : {0,1,2,3}) 570 for(auto&& i : {0,1,2,3}) 571 { 572 if (i == type1face_) continue; 573 574 getFace(el,i,face); 575 getFace(el,i,faceElement); 576 577 unsigned int neighborIndex = faceElement.second[0] == elIndex ? faceElement.second[1] : faceElement.second[0]; 578 if(freeFaces.find(face) != freeFacesEnd) 579 { 580 while(!checkFaceCompatibility(faceElement)) 581 { 582 rotate(elements_[neighborIndex]); 583 } 584 } 585 else if(activeFaces.find(face) != activeFaces.end()) 586 { 587 if(!checkFaceCompatibility(faceElement)) 588 { 589 checkFaceCompatibility(faceElement,true) ; 590 return false; 591 } 592 activeFaces.erase(face); 593 } 594 else 595 { 596 activeFaces.insert({{face,{elIndex,elIndex}}}); 597 } 598 } 599 } 600 601 //now postprocessing of freeFaces. possibly - not really necessary, has to be thought about 602 //useful for parallelization . 603 /* 604 for(auto&& face : freeFaces) 605 { 606 unsigned int elementIndex = face.second[0]; 607 unsigned int neighborIndex = face.second[1]; 608 //give refinement edge positive priority 609 //and non-refinement edge negative priority less than -1 and counting 610 } 611 */ 612 return true; 613 } 614 returnElements(std::vector<ElementType> & elements,std::vector<bool> & elementOrientation,std::vector<int> & types,const bool stevenson=false)615 void returnElements(std::vector<ElementType> & elements, 616 std::vector<bool>& elementOrientation, 617 std::vector<int>& types, 618 const bool stevenson = false ) 619 { 620 if( stevenson ) 621 { 622 alberta2Stevenson(); 623 } 624 else 625 { 626 stevenson2Alberta(); 627 } 628 629 //This needs to happen, before the boundaryIds are 630 //recreated in the GridFactory 631 const int nElements = elements_.size(); 632 for( int el = 0; el<nElements; ++el ) 633 { 634 // in ALU only elements with negative orientation can be inserted 635 if( ! elementOrientation_[ el ] ) 636 { 637 // the refinement edge is 0 -- 1, so we can swap 2 and 3 638 std::swap( elements_[ el ][ 2 ], elements_[ el ][ 3 ] ); 639 } 640 } 641 642 elements = elements_; 643 elementOrientation = elementOrientation_; 644 types = types_; 645 } 646 stevenson2Alberta()647 void stevenson2Alberta() 648 { 649 if( stevensonRefinement_ ) 650 { 651 swapRefinementType(); 652 } 653 } 654 alberta2Stevenson()655 void alberta2Stevenson() 656 { 657 if( ! stevensonRefinement_ ) 658 { 659 swapRefinementType(); 660 } 661 } 662 663 private: swapRefinementType()664 void swapRefinementType() 665 { 666 const int nElements = elements_.size(); 667 for( int el = 0; el<nElements; ++el ) 668 { 669 elementOrientation_[ el ] = !elementOrientation_[ el ]; 670 std::swap(elements_[ el ][ 1 ], elements_[ el ][ 3 ]); 671 } 672 673 // swap refinement flags 674 stevensonRefinement_ = ! stevensonRefinement_; 675 type0nodes_ = stevensonRefinement_ ? EdgeType{0,3} : EdgeType{0,1} ; 676 type0faces_ = stevensonRefinement_ ? EdgeType{3,0} : EdgeType{3,2} ; 677 type1node_ = stevensonRefinement_ ? 1 : 2 ; 678 type1face_ = ( 3 - type1node_ ); 679 } 680 681 //switch vertices 2,3 for all elements with elemIndex % 2 applyStandardOrientation()682 void applyStandardOrientation () 683 { 684 int i = 0; 685 for(auto & element : elements_ ) 686 { 687 if ( i % 2 == 0 ) 688 { 689 std::swap(element[2],element[3]); 690 elementOrientation_[i] = ! elementOrientation_[i]; 691 } 692 ++i; 693 } 694 types_.resize(elements_.size(), 0); 695 } 696 697 //check face for compatibility checkFaceCompatibility(std::pair<FaceType,EdgeType> face,bool verbose=false)698 bool checkFaceCompatibility(std::pair<FaceType, EdgeType> face, bool verbose = false) 699 { 700 EdgeType edge1,edge2; 701 int elIndex = face.second[0]; 702 int neighIndex = face.second[1]; 703 if(elIndex != neighIndex) 704 { 705 getRefinementEdge(elements_[elIndex], face.first, edge1, types_[elIndex]); 706 getRefinementEdge(elements_[neighIndex], face.first, edge2, types_[neighIndex]); 707 if(edge1 != edge2) 708 { 709 if (verbose) 710 { 711 /* std::cerr << "Face: " << face.first[0] << ", " << face.first[1] << ", " << face.first[2] 712 << " has refinement edge: " << edge1[0] << ", " << edge1[1] << 713 " from one side and: " << edge2[0] << ", " << edge2[1] << 714 " from the other." << std::endl; */ 715 printElement(elIndex); 716 printElement(neighIndex); 717 } 718 return false; 719 } 720 } 721 return true; 722 } 723 724 //check face for strong compatibility checkStrongCompatibility(std::pair<FaceType,EdgeType> face,bool verbose=false)725 bool checkStrongCompatibility(std::pair<FaceType, EdgeType> face, bool verbose = false) 726 { 727 int elIndex = face.second[0]; 728 int neighIndex = face.second[1]; 729 bool result = false; 730 //if we are not boundary 731 if(elIndex != neighIndex) 732 { 733 int elType = types_[elIndex]; 734 int neighType = types_[neighIndex]; 735 unsigned int elFaceIndex = getFaceIndex(elements_[elIndex], face.first); 736 unsigned int elNodeIndex = 3 - elFaceIndex; 737 unsigned int neighFaceIndex = getFaceIndex(elements_[neighIndex], face.first); 738 unsigned int neighNodeIndex = 3 - neighFaceIndex; 739 if(elType == neighType) 740 { 741 //if the local face indices coincide, they are reflected neighbors 742 // if the refinement edge is not contained in the shared face, we 743 // have reflected neighbors of the children, if the face is in the same direction 744 // and the other edge of the refinement edge is the missing one. 745 if( elNodeIndex == neighNodeIndex || 746 (elNodeIndex == type0nodes_[0] && neighNodeIndex == type0nodes_[1]) || 747 (elNodeIndex == type0nodes_[1] && neighNodeIndex == type0nodes_[0]) ) 748 { result = true; } 749 } 750 else 751 { 752 if( elType % 3 == (neighType +1) %3 ) 753 { 754 std::swap(elType, neighType); 755 std::swap(elNodeIndex, neighNodeIndex); 756 std::swap(elFaceIndex, neighFaceIndex); 757 std::swap(elIndex, neighIndex); 758 } 759 switch (elType) { 760 case 0: 761 assert(neighType == 1); 762 if( ( neighNodeIndex == type1node_ ) && ( elNodeIndex == type0nodes_[0] || elNodeIndex == type0nodes_[1] ) ) 763 { result = true; } 764 break; 765 case 1: 766 assert(neighType == 2); 767 if( ( neighNodeIndex == type1node_ ) && ( elNodeIndex == type0nodes_[0] || elNodeIndex == type0nodes_[1] ) ) 768 { result = true; } 769 break; 770 case 2: 771 assert(neighType == 0); 772 if( ( neighNodeIndex == type1node_ ) && ( elNodeIndex == type0nodes_[0] || elNodeIndex == type0nodes_[1] ) ) 773 { result = true; } 774 break; 775 default: 776 std::cerr << "No other types than 0,1,2 implemented. Aborting" << std::endl; 777 abort(); 778 } 779 } 780 } 781 else //boundary faces 782 { 783 result =true; 784 } 785 if (verbose && result == false ) 786 { 787 /* std::cerr << "Face: " << face.first[0] << ", " << face.first[1] << ", " << face.first[2] 788 << " has refinement edge: " << edge1[0] << ", " << edge1[1] << 789 " from one side and: " << edge2[0] << ", " << edge2[1] << 790 " from the other." << std::endl; */ 791 printElement(elIndex); 792 printElement(neighIndex); 793 } 794 return result; 795 } 796 fixNode(ElementType & el,int node)797 void fixNode(ElementType& el, int node) 798 { 799 if(!(node == type1node_)) 800 { 801 //swap the node at the right position 802 std::swap(el[node],el[type1node_]); 803 //also swap two other nodes to keep the volume positive 804 //2 and 0 are never type1node_ 805 std::swap(el[(type1node_+1)%4],el[(type1node_+2)%4]); 806 } 807 } 808 809 //The rotations that keep the type 1 node fixed rotate(ElementType & el)810 void rotate(ElementType& el) 811 { 812 std::swap(el[(type1node_+1)%4],el[(type1node_+2)%4]); 813 std::swap(el[(type1node_+1)%4],el[(type1node_+3)%4]); 814 } 815 816 //get the sorted face of an element to a corresponding index 817 //the index coincides with the missing vertex getFace(ElementType el,int faceIndex,FaceType & face)818 void getFace(ElementType el, int faceIndex, FaceType & face ) 819 { 820 switch(faceIndex) 821 { 822 case 3 : 823 face = {el[1],el[2],el[3]}; 824 break; 825 case 2 : 826 face = {el[0],el[2],el[3]}; 827 break; 828 case 1 : 829 face = {el[0],el[1],el[3]}; 830 break; 831 case 0 : 832 face = {el[0],el[1],el[2]}; 833 break; 834 default : 835 std::cerr << "index " << faceIndex << " NOT IMPLEMENTED FOR TETRAHEDRONS" << std::endl; 836 std::abort(); 837 } 838 std::sort(face.begin(), face.end()); 839 return; 840 } 841 getFace(ElementType el,int faceIndex,FaceElementType & faceElement)842 void getFace(ElementType el, int faceIndex, FaceElementType & faceElement) 843 { 844 FaceType face; 845 getFace(el, faceIndex, face); 846 faceElement = *neighbours_.find(face); 847 } 848 849 //get the sorted initial refinement edge of a face of an element 850 //this has to be adjusted, when using stevensonRefinement 851 //orientation switches indices 2 and 3 in the internal ordering getRefinementEdge(ElementType el,int faceIndex,EdgeType & edge,int type)852 void getRefinementEdge(ElementType el, int faceIndex, EdgeType & edge, int type ) 853 { 854 if(type == 0) 855 { 856 if(stevensonRefinement_) 857 { 858 switch(faceIndex) 859 { 860 case 0 : 861 edge = {el[0],el[2]}; 862 break; 863 case 1 : 864 edge = {el[0],el[3]}; 865 break; 866 case 2 : 867 edge = {el[0],el[3]}; 868 break; 869 case 3 : 870 edge = {el[1],el[3]}; 871 break; 872 default : 873 std::cerr << "index " << faceIndex << " NOT IMPLEMENTED FOR TETRAHEDRONS" << std::endl; 874 std::abort(); 875 } 876 } 877 else //ALBERTA Refinement 878 { 879 switch(faceIndex) 880 { 881 case 0 : 882 edge = {el[0],el[1]}; 883 break; 884 case 1 : 885 edge = {el[0],el[1]}; 886 break; 887 case 2 : 888 edge = {el[0],el[2]}; 889 break; 890 case 3 : 891 edge = {el[1],el[3]}; 892 break; 893 default : 894 std::cerr << "index " << faceIndex << " NOT IMPLEMENTED FOR TETRAHEDRONS" << std::endl; 895 std::abort(); 896 } 897 } 898 } 899 else if(type == 1 || type == 2) 900 { 901 if(stevensonRefinement_) 902 { 903 switch(faceIndex) 904 { 905 case 0 : 906 edge = {el[0],el[2]}; 907 break; 908 case 1 : 909 edge = {el[0],el[3]}; 910 break; 911 case 2 : 912 edge = {el[0],el[3]}; 913 break; 914 case 3 : 915 edge = {el[2],el[3]}; 916 break; 917 default : 918 std::cerr << "index " << faceIndex << " NOT IMPLEMENTED FOR TETRAHEDRONS" << std::endl; 919 std::abort(); 920 } 921 } 922 else //ALBERTA Refinement 923 { 924 switch(faceIndex) 925 { 926 case 0 : 927 edge = {el[0],el[1]}; 928 break; 929 case 1 : 930 edge = {el[0],el[1]}; 931 break; 932 case 2 : 933 edge = {el[0],el[3]}; 934 break; 935 case 3 : 936 edge = {el[1],el[3]}; 937 break; 938 default : 939 std::cerr << "index " << faceIndex << " NOT IMPLEMENTED FOR TETRAHEDRONS" << std::endl; 940 std::abort(); 941 } 942 } 943 } 944 else 945 { 946 std::cerr << "no other types than 0, 1, 2 implemented." << std::endl; 947 std::abort(); 948 } 949 std::sort(edge.begin(),edge.end()); 950 return; 951 } 952 953 //get the sorted initial refinement edge of a face of an element getRefinementEdge(ElementType el,FaceType face,EdgeType & edge,int type)954 void getRefinementEdge(ElementType el, FaceType face, EdgeType & edge, int type ) 955 { 956 getRefinementEdge(el, getFaceIndex(el, face), edge, type); 957 return; 958 } 959 960 //get the index of a face in an elements 961 //this could be improved by exploiting that faces are sorted getFaceIndex(ElementType el,FaceType face)962 int getFaceIndex(ElementType el, FaceType face) 963 { 964 for(int i =0; i<4 ; ++i) 965 { 966 if(!( el[i] == face[0] || el[i] == face[1] || el[i] == face[2] ) ) 967 return 3 - i ; 968 } 969 return -1; 970 } 971 972 //build the structure containing the neighbors 973 //consists of a face and the two indices belonging to 974 //the elements that share said face 975 //boundary faces have two times the same index 976 //this is executed in the constructor buildNeighbors()977 void buildNeighbors() 978 { 979 // clear existing structures 980 neighbours_.clear(); 981 982 FaceType face; 983 EdgeType indexPair; 984 985 unsigned int index = 0; 986 const auto nend = neighbours_.end(); 987 for(auto&& el : elements_) 988 { 989 for(int i = 0; i< 4; ++i) 990 { 991 getFace(el, i, face); 992 auto faceInList = neighbours_.find(face); 993 if(faceInList == nend) 994 { 995 indexPair = {index, index}; 996 neighbours_.insert(std::make_pair (face, indexPair ) ); 997 } 998 else 999 { 1000 assert(faceInList != neighbours_.end()); 1001 faceInList->second[1] = index; 1002 } 1003 } 1004 ++index; 1005 } 1006 } 1007 1008 /*! 1009 \brief This method is supposed to calculate V0 and V1 1010 \param variante : 1011 1 means collect all longest edges into V0, rest in V1 1012 2 means vertices with #(adjacent elements ) < threshold are in V1 1013 3 means random vertices are in V1 (for test purposes) 1014 everyhting else means V0 = all vertices 1015 */ calculateV0(int variante,int threshold)1016 void calculateV0(int variante, int threshold) 1017 { 1018 //For now, everything is in V0 1019 switch (variante) { 1020 case 1: 1021 { 1022 std::fill(containedInV0_.begin(),containedInV0_.end(), false); 1023 std::vector<int> numberOfAdjacentRefEdges(nVertices_, 0); 1024 //we assume that the edges have been sorted and 1025 //the refinement edge is, where it belongs 1026 for(auto&& el : elements_) 1027 { 1028 numberOfAdjacentRefEdges [ el [ type0nodes_[ 0 ] ] ] ++; 1029 numberOfAdjacentRefEdges [ el [ type0nodes_[ 1 ] ] ] ++; 1030 } 1031 for(unsigned int i = 0; i <nVertices_ ; ++i) 1032 { 1033 if(numberOfAdjacentRefEdges[ i ] >= threshold ) 1034 { 1035 containedInV0_[ i ] = true; 1036 } 1037 } 1038 } 1039 break; 1040 case 2: 1041 { 1042 std::vector<int> numberOfAdjacentElements(nVertices_, 0); 1043 std::vector<bool> vertexOnBoundary(nVertices_, false); 1044 for(auto&& neigh : neighbours_) 1045 { 1046 //We want to treat boundary vertices differently 1047 if(neigh.second[1] == neigh.second[0]) 1048 { 1049 for(unsigned int i =0; i < 3 ; ++i) 1050 { 1051 vertexOnBoundary[ neigh.first [ i ] ] =true; 1052 } 1053 } 1054 } 1055 //calculate numberOfAdjacentElements 1056 for(auto&& el : elements_) 1057 { 1058 for(unsigned int i =0; i < 4; ++i) 1059 { 1060 numberOfAdjacentElements[ el [ i ] ] ++; 1061 } 1062 } 1063 for(unsigned int i = 0; i <nVertices_ ; ++i) 1064 { 1065 double bound = vertexOnBoundary[ i ] ? threshold / 2. : threshold ; 1066 if(numberOfAdjacentElements[ i ] < bound ) 1067 { 1068 containedInV0_[ i ] = false; 1069 } 1070 } 1071 1072 } 1073 break; 1074 case 3: 1075 { 1076 std::default_random_engine generator; 1077 std::uniform_int_distribution<int> distribution(1,6); 1078 for(unsigned int i = 0; i < nVertices_; ++i) 1079 { 1080 int roll = distribution(generator); // generates number in the range 1..6 1081 if(roll < 3) 1082 { 1083 containedInV0_[ i ] = false; 1084 } 1085 } 1086 } 1087 break; 1088 default: ; 1089 } 1090 int sizeOfV1 = 0; 1091 int sizeOfV0 = 0; 1092 for(unsigned int i =0 ; i < nVertices_; ++i) 1093 { 1094 if( containedInV0_ [ i ] ) 1095 { 1096 ++sizeOfV0; 1097 } 1098 else 1099 { 1100 ++sizeOfV1; 1101 } 1102 } 1103 #ifndef NDEBUG 1104 std::cout << "#V0 #V1" << std::endl << sizeOfV0 << " " << sizeOfV1 << std::endl; 1105 #endif 1106 } 1107 1108 }; //class bisectioncompatibility 1109 1110 1111 1112 #endif //ALUGRID_COMPATIBILITY_CHECK_HH_INCLUDED 1113