Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : #include "EFAFragment3D.h" 11 : 12 : #include "EFAVolumeNode.h" 13 : #include "EFANode.h" 14 : #include "EFAEdge.h" 15 : #include "EFAFace.h" 16 : #include "EFAFuncs.h" 17 : #include "EFAElement3D.h" 18 : #include "EFAError.h" 19 : 20 95385 : EFAFragment3D::EFAFragment3D(EFAElement3D * host, 21 : bool create_faces, 22 : const EFAElement3D * from_host, 23 95385 : unsigned int frag_id) 24 95385 : : EFAFragment(), _host_elem(host) 25 : { 26 95385 : if (create_faces) 27 : { 28 91664 : if (!from_host) 29 0 : EFAError("EFAfragment3D constructor must have a from_host to copy from"); 30 91664 : if (frag_id == std::numeric_limits<unsigned int>::max()) // copy the from_host itself 31 : { 32 480663 : for (unsigned int i = 0; i < from_host->numFaces(); ++i) 33 408534 : _faces.push_back(new EFAFace(*from_host->getFace(i))); 34 : } 35 : else 36 : { 37 19535 : if (frag_id > from_host->numFragments() - 1) 38 0 : EFAError("In EFAfragment3D constructor fragment_copy_index out of bounds"); 39 130514 : for (unsigned int i = 0; i < from_host->getFragment(frag_id)->numFaces(); ++i) 40 110979 : _faces.push_back(new EFAFace(*from_host->getFragmentFace(frag_id, i))); 41 : } 42 91664 : findFacesAdjacentToFaces(); // IMPORTANT 43 : } 44 95385 : } 45 : 46 190770 : EFAFragment3D::~EFAFragment3D() 47 : { 48 635483 : for (unsigned int i = 0; i < _faces.size(); ++i) 49 : { 50 540098 : if (_faces[i]) 51 : { 52 540098 : delete _faces[i]; 53 540098 : _faces[i] = nullptr; 54 : } 55 : } 56 190770 : } 57 : 58 : void 59 650727 : EFAFragment3D::switchNode(EFANode * new_node, EFANode * old_node) 60 : { 61 3957426 : for (unsigned int i = 0; i < _faces.size(); ++i) 62 3306699 : _faces[i]->switchNode(new_node, old_node); 63 650727 : } 64 : 65 : bool 66 3538650 : EFAFragment3D::containsNode(EFANode * node) const 67 : { 68 : bool contains = false; 69 11424989 : for (unsigned int i = 0; i < _faces.size(); ++i) 70 : { 71 10176979 : if (_faces[i]->containsNode(node)) 72 : { 73 : contains = true; 74 : break; 75 : } 76 : } 77 3538650 : return contains; 78 : } 79 : 80 : unsigned int 81 79261 : EFAFragment3D::getNumCuts() const 82 : { 83 : unsigned int num_cut_faces = 0; 84 528327 : for (unsigned int i = 0; i < _faces.size(); ++i) 85 449066 : if (_faces[i]->hasIntersection()) 86 6271 : num_cut_faces += 1; 87 79261 : return num_cut_faces; 88 : } 89 : 90 : unsigned int 91 0 : EFAFragment3D::getNumCutNodes() const 92 : { 93 0 : mooseError("Not implemented yet for 3D."); 94 : } 95 : 96 : std::set<EFANode *> 97 94910 : EFAFragment3D::getAllNodes() const 98 : { 99 : std::set<EFANode *> all_nodes; 100 612003 : for (unsigned int i = 0; i < _faces.size(); ++i) 101 2480715 : for (unsigned int j = 0; j < _faces[i]->numNodes(); ++j) 102 1963622 : all_nodes.insert(_faces[i]->getNode(j)); 103 94910 : return all_nodes; 104 : } 105 : 106 : bool 107 51069 : EFAFragment3D::isConnected(EFAFragment * other_fragment) const 108 : { 109 51069 : EFAFragment3D * other_frag3d = dynamic_cast<EFAFragment3D *>(other_fragment); 110 51069 : if (!other_frag3d) 111 0 : EFAError("in isConnected other_fragment is not of type EFAfragement3D"); 112 : 113 183733 : for (unsigned int i = 0; i < _faces.size(); ++i) 114 1017888 : for (unsigned int j = 0; j < other_frag3d->numFaces(); ++j) 115 885224 : if (_faces[i]->equivalent(other_frag3d->_faces[j])) 116 : return true; 117 : 118 : return false; 119 : } 120 : 121 : bool 122 50812 : EFAFragment3D::isEdgeConnected(EFAFragment * other_fragment) const 123 : { 124 50812 : EFAFragment3D * other_frag3d = dynamic_cast<EFAFragment3D *>(other_fragment); 125 50812 : if (!other_frag3d) 126 0 : EFAError("in isEdgeConnected other_fragment is not of type EFAfragement3D"); 127 : 128 115501 : for (unsigned int i = 0; i < _faces.size(); ++i) 129 420994 : for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j) 130 2082564 : for (unsigned int k = 0; k < other_frag3d->numFaces(); ++k) 131 8385102 : for (unsigned int l = 0; l < other_frag3d->_faces[k]->numEdges(); ++l) 132 6658843 : if (_faces[i]->getEdge(j)->equivalent(*(other_frag3d->_faces[k]->getEdge(l)))) 133 : return true; 134 : 135 : return false; 136 : } 137 : 138 : void 139 7132 : EFAFragment3D::removeInvalidEmbeddedNodes(std::map<unsigned int, EFANode *> & EmbeddedNodes) 140 : { 141 : // N.B. this method is only called before we update fragments 142 : // N.B. an embedded node is valid IF at least one of its host faces is exterior and has more than 143 : // 1 cuts 144 : // TODO: the invalid cases are generalized from 2D. The method may need improvements in 3D 145 7132 : if (hasFaceWithOneCut()) 146 : { 147 : // build a local inverse map for all emb cut nodes in this fragment 148 : std::map<EFANode *, std::vector<EFAFace *>> emb_inverse_map; 149 2486 : for (unsigned int i = 0; i < _faces.size(); ++i) 150 10220 : for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j) 151 8112 : if (_faces[i]->getEdge(j)->hasIntersection()) 152 : { 153 1532 : EFANode * emb_node = _faces[i]->getEdge(j)->getEmbeddedNode(0); 154 1532 : emb_inverse_map[emb_node].push_back(_faces[i]); 155 : } 156 : 157 : // find all invalid embedded nodes 158 : std::vector<EFANode *> invalid_emb; 159 : std::map<EFANode *, std::vector<EFAFace *>>::iterator it; 160 1144 : for (it = emb_inverse_map.begin(); it != emb_inverse_map.end(); ++it) 161 : { 162 766 : EFANode * emb_node = it->first; 163 : std::vector<EFAFace *> & emb_faces = it->second; 164 766 : if (emb_faces.size() != 2) 165 0 : EFAError("one embedded node must be owned by 2 faces"); 166 : unsigned int counter = 0; 167 2298 : for (unsigned int i = 0; i < emb_faces.size(); ++i) 168 : { 169 1532 : unsigned int face_id = getFaceID(emb_faces[i]); 170 1532 : if (!isFaceInterior(face_id) && emb_faces[i]->hasIntersection()) 171 776 : counter += 1; // count the appropriate emb's faces 172 : } 173 766 : if (counter == 0) 174 0 : invalid_emb.push_back(emb_node); 175 : } 176 : 177 : // delete all invalid emb nodes 178 378 : for (unsigned int i = 0; i < invalid_emb.size(); ++i) 179 : { 180 0 : Efa::deleteFromMap(EmbeddedNodes, invalid_emb[i]); 181 0 : _host_elem->removeEmbeddedNode(invalid_emb[i], true); // also remove from neighbors 182 : } // i 183 378 : } 184 7132 : } 185 : 186 : void 187 498 : EFAFragment3D::combine_tip_faces() 188 : { 189 498 : if (!_host_elem) 190 0 : EFAError("In combine_tip_faces() the frag must have host_elem"); 191 : 192 3326 : for (unsigned int i = 0; i < _host_elem->numFaces(); ++i) 193 : { 194 : std::vector<unsigned int> frag_tip_face_id; 195 21205 : for (unsigned int j = 0; j < _faces.size(); ++j) 196 18377 : if (_host_elem->getFace(i)->containsFace(_faces[j])) 197 3336 : frag_tip_face_id.push_back(j); 198 : 199 2828 : if (frag_tip_face_id.size() == 2) // combine the two frag faces on this elem face 200 508 : combine_two_faces(frag_tip_face_id[0], frag_tip_face_id[1], _host_elem->getFace(i)); 201 2828 : } 202 : // TODO: may need to combine other frag faces that have tip edges 203 498 : } 204 : 205 : bool 206 8431081 : EFAFragment3D::isFaceInterior(unsigned int face_id) const 207 : { 208 8431081 : if (!_host_elem) 209 0 : EFAError("in isFaceInterior() fragment must have host elem"); 210 : 211 : bool face_in_elem_face = false; 212 32803523 : for (unsigned int i = 0; i < _host_elem->numFaces(); ++i) 213 31298993 : if (_host_elem->getFace(i)->containsFace(_faces[face_id])) 214 : { 215 : face_in_elem_face = true; 216 : break; 217 : } 218 : 219 : // the face is interior if it does not coincide with an element face 220 8431081 : return !face_in_elem_face; 221 : } 222 : 223 : std::vector<unsigned int> 224 0 : EFAFragment3D::get_interior_face_id() const 225 : { 226 : std::vector<unsigned int> interior_face_id; 227 0 : for (unsigned int i = 0; i < _faces.size(); ++i) 228 0 : if (isFaceInterior(i)) 229 0 : interior_face_id.push_back(i); 230 : 231 0 : return interior_face_id; 232 0 : } 233 : 234 : bool 235 0 : EFAFragment3D::isThirdInteriorFace(unsigned int face_id) const 236 : { 237 0 : if (!_host_elem) 238 0 : EFAError("in isThirdInteriorFace fragment must have host elem"); 239 : 240 0 : for (unsigned int i = 0; i < _host_elem->numInteriorNodes(); ++i) 241 0 : if (_faces[face_id]->containsNode(_host_elem->getInteriorNode(i)->getNode())) 242 : return true; 243 : 244 : return false; 245 : } 246 : 247 : unsigned int 248 14121777 : EFAFragment3D::numFaces() const 249 : { 250 14121777 : return _faces.size(); 251 : } 252 : 253 : EFAFace * 254 2405455 : EFAFragment3D::getFace(unsigned int face_id) const 255 : { 256 2405455 : if (face_id > _faces.size() - 1) 257 0 : EFAError("in EFAfragment3D::get_face, index out of bounds"); 258 2405455 : return _faces[face_id]; 259 : } 260 : 261 : unsigned int 262 1532 : EFAFragment3D::getFaceID(EFAFace * face) const 263 : { 264 5594 : for (unsigned int i = 0; i < _faces.size(); ++i) 265 5594 : if (_faces[i] == face) 266 1532 : return i; 267 0 : EFAError("face not found in get_face_id()"); 268 : } 269 : 270 : void 271 21093 : EFAFragment3D::addFace(EFAFace * new_face) 272 : { 273 21093 : _faces.push_back(new_face); 274 21093 : } 275 : 276 : std::set<EFANode *> 277 0 : EFAFragment3D::getFaceNodes(unsigned int face_id) const 278 : { 279 : std::set<EFANode *> face_nodes; 280 0 : for (unsigned int i = 0; i < _faces[face_id]->numNodes(); ++i) 281 0 : face_nodes.insert(_faces[face_id]->getNode(i)); 282 0 : return face_nodes; 283 : } 284 : 285 : EFAElement3D * 286 0 : EFAFragment3D::getHostElement() const 287 : { 288 0 : return _host_elem; 289 : } 290 : 291 : std::vector<EFAFragment3D *> 292 2221 : EFAFragment3D::split() 293 : { 294 : // This method will split one existing fragment into one or two new fragments 295 : std::vector<EFAFragment3D *> new_fragments; 296 : std::vector<std::vector<EFAFace *>> all_subfaces; 297 14043 : for (unsigned int i = 0; i < _faces.size(); ++i) 298 : { 299 11822 : std::vector<EFAFace *> subfaces = _faces[i]->split(); 300 11822 : all_subfaces.push_back(subfaces); 301 11822 : } 302 : 303 : // build new frags 304 2221 : if (hasFaceWithOneCut()) // "fakely" cut fragment 305 : { 306 721 : EFAFragment3D * new_frag = new EFAFragment3D(_host_elem, false, nullptr); 307 4759 : for (unsigned int i = 0; i < all_subfaces.size(); ++i) 308 8819 : for (unsigned int j = 0; j < all_subfaces[i].size(); ++j) 309 4781 : new_frag->addFace(all_subfaces[i][j]); 310 721 : new_frag->findFacesAdjacentToFaces(); 311 721 : new_fragments.push_back(new_frag); 312 : } 313 : else // thoroughly cut fragment 314 : { 315 : // find the first face with 2 sub-faces 316 : EFAFace * start_face1 = nullptr; 317 : EFAFace * start_face2 = nullptr; 318 : unsigned int startOldFaceID = 0; 319 1673 : for (unsigned int i = 0; i < _faces.size(); ++i) 320 : { 321 1673 : if (all_subfaces[i].size() == 2) 322 : { 323 1500 : start_face1 = all_subfaces[i][0]; 324 1500 : start_face2 = all_subfaces[i][1]; 325 : startOldFaceID = i; 326 1500 : break; 327 : } 328 : } // i 329 1500 : EFAFragment3D * new_frag1 = connectSubfaces(start_face1, startOldFaceID, all_subfaces); 330 1500 : EFAFragment3D * new_frag2 = connectSubfaces(start_face2, startOldFaceID, all_subfaces); 331 1500 : new_fragments.push_back(new_frag1); 332 1500 : new_fragments.push_back(new_frag2); 333 : } 334 2221 : return new_fragments; 335 2221 : } 336 : 337 : void 338 98893 : EFAFragment3D::findFacesAdjacentToFaces() 339 : { 340 98893 : _faces_adjacent_to_faces.clear(); 341 655709 : for (unsigned int i = 0; i < _faces.size(); ++i) 342 : { 343 556816 : std::vector<EFAFace *> face_adjacents(_faces[i]->numEdges(), nullptr); 344 3755210 : for (unsigned int j = 0; j < _faces.size(); ++j) 345 3198394 : if (_faces[j] != _faces[i] && _faces[i]->isAdjacent(_faces[j])) 346 : { 347 2149908 : unsigned int adj_edge = _faces[i]->adjacentCommonEdge(_faces[j]); 348 2149908 : face_adjacents[adj_edge] = _faces[j]; 349 : } 350 : 351 556816 : _faces_adjacent_to_faces.push_back(face_adjacents); 352 556816 : } // i 353 98893 : } 354 : 355 : EFAFace * 356 0 : EFAFragment3D::getAdjacentFace(unsigned int face_id, unsigned int edge_id) const 357 : { 358 0 : return _faces_adjacent_to_faces[face_id][edge_id]; // possibly NULL 359 : } 360 : 361 : void 362 0 : EFAFragment3D::removeEmbeddedNode(EFANode * emb_node) 363 : { 364 0 : for (unsigned int i = 0; i < _faces.size(); ++i) 365 0 : _faces[i]->removeEmbeddedNode(emb_node); 366 0 : } 367 : 368 : bool 369 9353 : EFAFragment3D::hasFaceWithOneCut() const 370 : { 371 : // N.B. this method can only be implemented when the fragment has just been marked 372 55974 : for (unsigned int i = 0; i < _faces.size(); ++i) 373 47720 : if (_faces[i]->getNumCuts() == 1) 374 : return true; 375 : return false; 376 : } 377 : 378 : void 379 90590 : EFAFragment3D::getNodeInfo(std::vector<std::vector<unsigned int>> & face_node_indices, 380 : std::vector<EFANode *> & nodes) const 381 : { 382 : // get all nodes' pointers - a vector 383 90590 : std::set<EFANode *> all_node_set = getAllNodes(); 384 90590 : nodes.resize(all_node_set.size()); 385 90590 : std::copy(all_node_set.begin(), all_node_set.end(), nodes.begin()); 386 : 387 : // get face connectivity 388 90590 : face_node_indices.clear(); 389 581763 : for (unsigned int i = 0; i < _faces.size(); ++i) 390 : { 391 : std::vector<unsigned int> line_face_indices; 392 2351115 : for (unsigned int j = 0; j < _faces[i]->numNodes(); ++j) 393 : { 394 1859942 : EFANode * node = _faces[i]->getNode(j); 395 1859942 : unsigned int vec_index = std::find(nodes.begin(), nodes.end(), node) - nodes.begin(); 396 1859942 : line_face_indices.push_back(vec_index); 397 : } 398 491173 : face_node_indices.push_back(line_face_indices); 399 491173 : } 400 90590 : } 401 : 402 : EFAFragment3D * 403 3000 : EFAFragment3D::connectSubfaces(EFAFace * start_face, 404 : unsigned int startOldFaceID, 405 : std::vector<std::vector<EFAFace *>> & subfaces) 406 : { 407 : // this method is only called in EFAfragment3D::split() 408 3000 : std::vector<bool> contributed(subfaces.size(), false); 409 : contributed[startOldFaceID] = true; 410 : unsigned int num_contrib_faces = 1; 411 : unsigned int old_num_contrib = 1; 412 3000 : std::vector<EFAFace *> frag_faces(1, start_face); 413 : 414 : // collect all subfaces connected to start_face 415 : do 416 : { 417 : old_num_contrib = num_contrib_faces; 418 37220 : for (unsigned int i = 0; i < subfaces.size(); ++i) 419 : { 420 31208 : if (!contributed[i]) // old face not contributed to new fragment yet 421 : { 422 : bool adjacent_found = false; 423 23400 : for (unsigned int j = 0; j < subfaces[i].size(); ++j) 424 : { 425 44509 : for (unsigned int k = 0; k < frag_faces.size(); ++k) 426 : { 427 35945 : if (subfaces[i][j]->isAdjacent(frag_faces[k])) 428 : { 429 : adjacent_found = true; 430 : contributed[i] = true; 431 10312 : frag_faces.push_back(subfaces[i][j]); 432 10312 : num_contrib_faces += 1; 433 : break; 434 : } 435 : } // k 436 : if (adjacent_found) 437 : break; 438 : } // j 439 : } 440 : } // i, loop over all old faces 441 6012 : } while (num_contrib_faces != old_num_contrib); 442 : 443 : // get the cut plane face 444 : std::vector<EFAEdge *> cut_plane_edges; 445 3000 : EFAFragment3D * new_frag = new EFAFragment3D(_host_elem, false, nullptr); 446 16312 : for (unsigned int i = 0; i < frag_faces.size(); ++i) 447 13312 : new_frag->addFace(frag_faces[i]); 448 3000 : new_frag->findFacesAdjacentToFaces(); 449 : 450 16312 : for (unsigned int i = 0; i < new_frag->numFaces(); ++i) 451 : { 452 13312 : EFAEdge * lone_edge = new_frag->loneEdgeOnFace(i); 453 13312 : if (lone_edge != nullptr) // valid edge 454 11056 : cut_plane_edges.push_back(new EFAEdge(*lone_edge)); 455 : } 456 : 457 3000 : EFAFace * cut_face = new EFAFace(cut_plane_edges.size()); 458 14056 : for (unsigned int i = 0; i < cut_plane_edges.size(); ++i) 459 11056 : cut_face->setEdge(i, cut_plane_edges[i]); 460 3000 : cut_face->sortEdges(); 461 3000 : cut_face->reverseEdges(); 462 3000 : cut_face->createNodes(); 463 : 464 : // finalize the new fragment 465 3000 : new_frag->addFace(cut_face); 466 3000 : new_frag->findFacesAdjacentToFaces(); 467 3000 : return new_frag; 468 3000 : } 469 : 470 : EFAEdge * 471 13312 : EFAFragment3D::loneEdgeOnFace(unsigned int face_id) const 472 : { 473 : // if any face edge is not shared by any other face, we call it a lone edge 474 44215 : for (unsigned int i = 0; i < _faces[face_id]->numEdges(); ++i) 475 41959 : if (_faces_adjacent_to_faces[face_id][i] == nullptr) 476 11056 : return _faces[face_id]->getEdge(i); 477 : return nullptr; 478 : } 479 : 480 : void 481 508 : EFAFragment3D::combine_two_faces(unsigned int face_id1, 482 : unsigned int face_id2, 483 : const EFAFace * elem_face) 484 : { 485 : // get the new full face 486 508 : EFAFace * full_face = _faces[face_id1]->combineWithFace(_faces[face_id2]); 487 508 : full_face->resetEdgeIntersection(elem_face); // IMPORTANT 488 : 489 : // take care of the common adjacent faces (combine their tip edges) 490 : std::set<EFAFace *> face1_neigh; 491 508 : face1_neigh.insert(_faces_adjacent_to_faces[face_id1].begin(), 492 : _faces_adjacent_to_faces[face_id1].end()); 493 : std::set<EFAFace *> face2_neigh; 494 508 : face2_neigh.insert(_faces_adjacent_to_faces[face_id2].begin(), 495 : _faces_adjacent_to_faces[face_id2].end()); 496 508 : std::vector<EFAFace *> common_adjacent_faces = Efa::getCommonElems(face1_neigh, face2_neigh); 497 : 498 1514 : for (unsigned int i = 0; i < common_adjacent_faces.size(); ++i) 499 : { 500 1006 : EFAFace * comm_face = common_adjacent_faces[i]; 501 1006 : if (comm_face != nullptr) 502 : { 503 996 : unsigned int edge_id1 = comm_face->adjacentCommonEdge(_faces[face_id1]); 504 996 : unsigned int edge_id2 = comm_face->adjacentCommonEdge(_faces[face_id2]); 505 996 : comm_face->combineTwoEdges(edge_id1, edge_id2); 506 996 : comm_face->resetEdgeIntersection(elem_face); // IMPORTANT 507 : } 508 : } 509 : 510 : // delete old faces and update private members of EFAfragment3D 511 508 : delete _faces[face_id1]; 512 508 : delete _faces[face_id2]; 513 508 : _faces[face_id1] = full_face; 514 508 : _faces.erase(_faces.begin() + face_id2); 515 508 : findFacesAdjacentToFaces(); // rebuild _adjacent_face_ix: IMPORTANT 516 1016 : }