void SideSetsGeneratorBase::flood(const Elem * elem, Point normal, boundary_id_type side_id, MeshBase & mesh) { if (elem == nullptr || (_visited[side_id].find(elem) != _visited[side_id].end())) return; _visited[side_id].insert(elem); for (unsigned int side = 0; side < elem->n_sides(); ++side) { if (elem->neighbor_ptr(side)) continue; _fe_face->reinit(elem, side); const std::vector<Point> normals = _fe_face->get_normals(); // We'll just use the normal of the first qp if (std::abs(1.0 - normal * normals[0]) <= _variance) { mesh.get_boundary_info().add_side(elem, side, side_id); for (unsigned int neighbor = 0; neighbor < elem->n_sides(); ++neighbor) { // Flood to the neighboring elements using the current matching side normal from this // element. // This will allow us to tolerate small changes in the normals so we can "paint" around a // curve. flood(elem->neighbor_ptr(neighbor), _fixed_normal ? normal : normals[0], side_id, mesh); } } } }
void MeshExtruderGenerator::changeID(MeshBase & mesh, const std::vector<BoundaryName> & names, BoundaryID old_id) { std::vector<boundary_id_type> boundary_ids = MooseMeshUtils::getBoundaryIDs(mesh, names, true); if (std::find(boundary_ids.begin(), boundary_ids.end(), old_id) == boundary_ids.end()) MooseMeshUtils::changeBoundaryId(mesh, old_id, boundary_ids[0], true); for (unsigned int i = 0; i < boundary_ids.size(); ++i) { mesh.get_boundary_info().sideset_name(boundary_ids[i]) = names[i]; mesh.get_boundary_info().nodeset_name(boundary_ids[i]) = names[i]; } }
void MeshTools::Subdivision::all_subdivision(MeshBase & mesh) { std::vector<Elem *> new_elements; new_elements.reserve(mesh.n_elem()); const bool mesh_has_boundary_data = (mesh.get_boundary_info().n_boundary_ids() > 0); std::vector<Elem *> new_boundary_elements; std::vector<short int> new_boundary_sides; std::vector<boundary_id_type> new_boundary_ids; MeshBase::const_element_iterator el = mesh.elements_begin(); const MeshBase::const_element_iterator end_el = mesh.elements_end(); for (; el != end_el; ++el) { const Elem * elem = *el; libmesh_assert_equal_to(elem->type(), TRI3); Elem * tri = new Tri3Subdivision; tri->set_id(elem->id()); tri->subdomain_id() = elem->subdomain_id(); tri->set_node(0) = (*el)->get_node(0); tri->set_node(1) = (*el)->get_node(1); tri->set_node(2) = (*el)->get_node(2); if (mesh_has_boundary_data) { for (unsigned short side = 0; side < elem->n_sides(); ++side) { const boundary_id_type boundary_id = mesh.get_boundary_info().boundary_id(elem, side); if (boundary_id != BoundaryInfo::invalid_id) { // add the boundary id to the list of new boundary ids new_boundary_ids.push_back(boundary_id); new_boundary_elements.push_back(tri); new_boundary_sides.push_back(side); } } // remove the original element from the BoundaryInfo structure mesh.get_boundary_info().remove(elem); } new_elements.push_back(tri); mesh.insert_elem(tri); } mesh.prepare_for_use(); if (mesh_has_boundary_data) { // If the old mesh had boundary data, the new mesh better have some too. libmesh_assert_greater(new_boundary_elements.size(), 0); // We should also be sure that the lengths of the new boundary data vectors // are all the same. libmesh_assert_equal_to(new_boundary_sides.size(), new_boundary_elements.size()); libmesh_assert_equal_to(new_boundary_sides.size(), new_boundary_ids.size()); // Add the new boundary info to the mesh. for (unsigned int s = 0; s < new_boundary_elements.size(); ++s) mesh.get_boundary_info().add_side(new_boundary_elements[s], new_boundary_sides[s], new_boundary_ids[s]); } mesh.prepare_for_use(); }
void MeshTools::Subdivision::add_boundary_ghosts(MeshBase & mesh) { static const Real tol = 1e-5; // add the mirrored ghost elements (without using iterators, because the mesh is modified in the course) std::vector<Tri3Subdivision *> ghost_elems; std::vector<Node *> ghost_nodes; const unsigned int n_elem = mesh.n_elem(); for (unsigned int eid = 0; eid < n_elem; ++eid) { Elem * elem = mesh.elem(eid); libmesh_assert_equal_to(elem->type(), TRI3SUBDIVISION); // If the triangle happens to be in a corner (two boundary // edges), we perform a counter-clockwise loop by mirroring the // previous triangle until we come back to the original // triangle. This prevents degenerated triangles in the mesh // corners and guarantees that the node in the middle of the // loop is of valence=6. for (unsigned int i = 0; i < elem->n_sides(); ++i) { libmesh_assert_not_equal_to(elem->neighbor(i), elem); if (elem->neighbor(i) == libmesh_nullptr && elem->neighbor(next[i]) == libmesh_nullptr) { Elem * nelem = elem; unsigned int k = i; for (unsigned int l=0;l<4;l++) { // this is the vertex to be mirrored Point point = nelem->point(k) + nelem->point(next[k]) - nelem->point(prev[k]); // Check if the proposed vertex doesn't coincide // with one of the existing vertices. This is // necessary because for some triangulations, it can // happen that two mirrored ghost vertices coincide, // which would then lead to a zero size ghost // element below. Node * node = libmesh_nullptr; for (unsigned int j = 0; j < ghost_nodes.size(); ++j) { if ((*ghost_nodes[j] - point).size() < tol * (elem->point(k) - point).size()) { node = ghost_nodes[j]; break; } } // add the new vertex only if no other is nearby if (node == libmesh_nullptr) { node = mesh.add_point(point); ghost_nodes.push_back(node); } Tri3Subdivision * newelem = new Tri3Subdivision(); // add the first new ghost element to the list just as in the non-corner case if (l == 0) ghost_elems.push_back(newelem); newelem->set_node(0) = nelem->get_node(next[k]); newelem->set_node(1) = nelem->get_node(k); newelem->set_node(2) = node; newelem->set_neighbor(0, nelem); newelem->set_ghost(true); if (l>0) newelem->set_neighbor(2, libmesh_nullptr); nelem->set_neighbor(k, newelem); mesh.add_elem(newelem); mesh.get_boundary_info().add_node(nelem->get_node(k), 1); mesh.get_boundary_info().add_node(nelem->get_node(next[k]), 1); mesh.get_boundary_info().add_node(nelem->get_node(prev[k]), 1); mesh.get_boundary_info().add_node(node, 1); nelem = newelem; k = 2 ; } Tri3Subdivision * newelem = new Tri3Subdivision(); newelem->set_node(0) = elem->get_node(next[i]); newelem->set_node(1) = nelem->get_node(2); newelem->set_node(2) = elem->get_node(prev[i]); newelem->set_neighbor(0, nelem); nelem->set_neighbor(2, newelem); newelem->set_ghost(true); newelem->set_neighbor(2, elem); elem->set_neighbor(next[i],newelem); mesh.add_elem(newelem); break; } } for (unsigned int i = 0; i < elem->n_sides(); ++i) { libmesh_assert_not_equal_to(elem->neighbor(i), elem); if (elem->neighbor(i) == libmesh_nullptr) { // this is the vertex to be mirrored Point point = elem->point(i) + elem->point(next[i]) - elem->point(prev[i]); // Check if the proposed vertex doesn't coincide with // one of the existing vertices. This is necessary // because for some triangulations, it can happen that // two mirrored ghost vertices coincide, which would // then lead to a zero size ghost element below. Node * node = libmesh_nullptr; for (unsigned int j = 0; j < ghost_nodes.size(); ++j) { if ((*ghost_nodes[j] - point).size() < tol * (elem->point(i) - point).size()) { node = ghost_nodes[j]; break; } } // add the new vertex only if no other is nearby if (node == libmesh_nullptr) { node = mesh.add_point(point); ghost_nodes.push_back(node); } Tri3Subdivision * newelem = new Tri3Subdivision(); ghost_elems.push_back(newelem); newelem->set_node(0) = elem->get_node(next[i]); newelem->set_node(1) = elem->get_node(i); newelem->set_node(2) = node; newelem->set_neighbor(0, elem); newelem->set_ghost(true); elem->set_neighbor(i, newelem); mesh.add_elem(newelem); mesh.get_boundary_info().add_node(elem->get_node(i), 1); mesh.get_boundary_info().add_node(elem->get_node(next[i]), 1); mesh.get_boundary_info().add_node(elem->get_node(prev[i]), 1); mesh.get_boundary_info().add_node(node, 1); } } } // add the missing ghost elements (connecting new ghost nodes) std::vector<Tri3Subdivision *> missing_ghost_elems; std::vector<Tri3Subdivision *>::iterator ghost_el = ghost_elems.begin(); const std::vector<Tri3Subdivision *>::iterator end_ghost_el = ghost_elems.end(); for (; ghost_el != end_ghost_el; ++ghost_el) { Tri3Subdivision * elem = *ghost_el; libmesh_assert(elem->is_ghost()); for (unsigned int i = 0; i < elem->n_sides(); ++i) { if (elem->neighbor(i) == libmesh_nullptr && elem->neighbor(prev[i]) != libmesh_nullptr) { // go around counter-clockwise Tri3Subdivision * nb1 = static_cast<Tri3Subdivision *>(elem->neighbor(prev[i])); Tri3Subdivision * nb2 = nb1; unsigned int j = i; unsigned int n_nb = 0; while (nb1 != libmesh_nullptr && nb1->id() != elem->id()) { j = nb1->local_node_number(elem->node(i)); nb2 = nb1; nb1 = static_cast<Tri3Subdivision *>(nb1->neighbor(prev[j])); libmesh_assert(nb1 == libmesh_nullptr || nb1->id() != nb2->id()); n_nb++; } libmesh_assert_not_equal_to(nb2->id(), elem->id()); // Above, we merged coinciding ghost vertices. Therefore, we need // to exclude the case where there is no ghost element to add between // these two (identical) ghost nodes. if (elem->get_node(next[i])->id() == nb2->get_node(prev[j])->id()) break; // If the number of already present neighbors is less than 4, we add another extra element // so that the node in the middle of the loop ends up being of valence=6. // This case usually happens when the middle node corresponds to a corner of the original mesh, // and the extra element below prevents degenerated triangles in the mesh corners. if (n_nb < 4) { // this is the vertex to be mirrored Point point = nb2->point(j) + nb2->point(prev[j]) - nb2->point(next[j]); // Check if the proposed vertex doesn't coincide with one of the existing vertices. // This is necessary because for some triangulations, it can happen that two mirrored // ghost vertices coincide, which would then lead to a zero size ghost element below. Node * node = libmesh_nullptr; for (unsigned int k = 0; k < ghost_nodes.size(); ++k) { if ((*ghost_nodes[k] - point).size() < tol * (nb2->point(j) - point).size()) { node = ghost_nodes[k]; break; } } // add the new vertex only if no other is nearby if (node == libmesh_nullptr) { node = mesh.add_point(point); ghost_nodes.push_back(node); } Tri3Subdivision * newelem = new Tri3Subdivision(); newelem->set_node(0) = nb2->get_node(j); newelem->set_node(1) = nb2->get_node(prev[j]); newelem->set_node(2) = node; newelem->set_neighbor(0, nb2); newelem->set_neighbor(1, libmesh_nullptr); newelem->set_ghost(true); nb2->set_neighbor(prev[j], newelem); mesh.add_elem(newelem); mesh.get_boundary_info().add_node(nb2->get_node(j), 1); mesh.get_boundary_info().add_node(nb2->get_node(prev[j]), 1); mesh.get_boundary_info().add_node(node, 1); nb2 = newelem; j = nb2->local_node_number(elem->node(i)); } Tri3Subdivision * newelem = new Tri3Subdivision(); newelem->set_node(0) = elem->get_node(next[i]); newelem->set_node(1) = elem->get_node(i); newelem->set_node(2) = nb2->get_node(prev[j]); newelem->set_neighbor(0, elem); newelem->set_neighbor(1, nb2); newelem->set_neighbor(2, libmesh_nullptr); newelem->set_ghost(true); elem->set_neighbor(i, newelem); nb2->set_neighbor(prev[j], newelem); missing_ghost_elems.push_back(newelem); break; } } // end side loop } // end ghost element loop // add the missing ghost elements to the mesh std::vector<Tri3Subdivision *>::iterator missing_el = missing_ghost_elems.begin(); const std::vector<Tri3Subdivision *>::iterator end_missing_el = missing_ghost_elems.end(); for (; missing_el != end_missing_el; ++missing_el) mesh.add_elem(*missing_el); }