void SerialMesh::renumber_elem(const unsigned int old_id, const unsigned int new_id) { // This doesn't get used in serial yet Elem *elem = _elements[old_id]; libmesh_assert (elem); elem->set_id(new_id); libmesh_assert (!_elements[new_id]); _elements[new_id] = elem; _elements[old_id] = NULL; }
void testPostInitAddElem() { ReplicatedMesh mesh(*TestCommWorld); EquationSystems es(mesh); System &sys = es.add_system<System> ("SimpleSystem"); sys.add_variable("u", FIRST); MeshTools::Generation::build_line (mesh, 10, 0., 1., EDGE2); es.init(); Elem* e = Elem::build(EDGE2).release(); e->set_id(mesh.max_elem_id()); e->processor_id() = 0; e->set_node(0) = mesh.node_ptr(2); e->set_node(1) = mesh.node_ptr(8); mesh.add_elem(e); mesh.prepare_for_use(); es.reinit(); }
void SerialMesh::renumber_nodes_and_elements () { START_LOG("renumber_nodes_and_elem()", "Mesh"); // node and element id counters unsigned int next_free_elem = 0; unsigned int next_free_node = 0; // Will hold the set of nodes that are currently connected to elements LIBMESH_BEST_UNORDERED_SET<Node*> connected_nodes; // Loop over the elements. Note that there may // be NULLs in the _elements vector from the coarsening // process. Pack the elements in to a contiguous array // and then trim any excess. { std::vector<Elem*>::iterator in = _elements.begin(); std::vector<Elem*>::iterator out = _elements.begin(); const std::vector<Elem*>::iterator end = _elements.end(); for (; in != end; ++in) if (*in != NULL) { Elem* elem = *in; *out = *in; ++out; // Increment the element counter elem->set_id (next_free_elem++); if(_skip_renumber_nodes_and_elements) { // Add this elements nodes to the connected list for (unsigned int n=0; n<elem->n_nodes(); n++) connected_nodes.insert(elem->get_node(n)); } else // We DO want node renumbering { // Loop over this element's nodes. Number them, // if they have not been numbered already. Also, // position them in the _nodes vector so that they // are packed contiguously from the beginning. for (unsigned int n=0; n<elem->n_nodes(); n++) if (elem->node(n) == next_free_node) // don't need to process next_free_node++; // [(src == dst) below] else if (elem->node(n) > next_free_node) // need to process { // The source and destination indices // for this node const unsigned int src_idx = elem->node(n); const unsigned int dst_idx = next_free_node++; // ensure we want to swap a valid nodes libmesh_assert (_nodes[src_idx] != NULL); // Swap the source and destination nodes std::swap(_nodes[src_idx], _nodes[dst_idx] ); // Set proper indices where that makes sense if (_nodes[src_idx] != NULL) _nodes[src_idx]->set_id (src_idx); _nodes[dst_idx]->set_id (dst_idx); } } } // Erase any additional storage. These elements have been // copied into NULL voids by the procedure above, and are // thus repeated and unnecessary. _elements.erase (out, end); } if(_skip_renumber_nodes_and_elements) { // Loop over the nodes. Note that there may // be NULLs in the _nodes vector from the coarsening // process. Pack the nodes in to a contiguous array // and then trim any excess. std::vector<Node*>::iterator in = _nodes.begin(); std::vector<Node*>::iterator out = _nodes.begin(); const std::vector<Node*>::iterator end = _nodes.end(); for (; in != end; ++in) if (*in != NULL) { // This is a reference so that if we change the pointer it will change in the vector Node* & node = *in; // If this node is still connected to an elem, put it in the list if(connected_nodes.find(node) != connected_nodes.end()) { *out = node; ++out; // Increment the node counter node->set_id (next_free_node++); } else // This node is orphaned, delete it! { this->boundary_info->remove (node); // delete the node delete node; node = NULL; } } // Erase any additional storage. Whatever was _nodes.erase (out, end); } else // We really DO want node renumbering { // Any nodes in the vector >= _nodes[next_free_node] // are not connected to any elements and may be deleted // if desired. // (This code block will erase the unused nodes) // Now, delete the unused nodes { std::vector<Node*>::iterator nd = _nodes.begin(); const std::vector<Node*>::iterator end = _nodes.end(); std::advance (nd, next_free_node); for (std::vector<Node*>::iterator it=nd; it != end; ++it) { // Mesh modification code might have already deleted some // nodes if (*it == NULL) continue; // remove any boundary information associated with // this node this->boundary_info->remove (*it); // delete the node delete *it; *it = NULL; } _nodes.erase (nd, end); } } libmesh_assert (next_free_elem == _elements.size()); libmesh_assert (next_free_node == _nodes.size()); STOP_LOG("renumber_nodes_and_elem()", "Mesh"); }
void OFFIO::read_stream(std::istream& in) { // This is a serial-only process for now; // the Mesh should be read on processor 0 and // broadcast later libmesh_assert_equal_to (this->mesh().processor_id(), 0); // Get a reference to the mesh MeshBase& the_mesh = MeshInput<MeshBase>::mesh(); // Clear any existing mesh data the_mesh.clear(); // Check the input buffer libmesh_assert (in.good()); unsigned int nn, ne, nf; std::string label; // Read the first string. It should say "OFF" in >> label; libmesh_assert_equal_to (label, "OFF"); // read the number of nodes, faces, and edges in >> nn >> nf >> ne; Real x=0., y=0., z=0.; // Read the nodes for (unsigned int n=0; n<nn; n++) { libmesh_assert (in.good()); in >> x >> y >> z; the_mesh.add_point ( Point(x,y,z), n ); } unsigned int nv, nid; // Read the elements for (unsigned int e=0; e<nf; e++) { libmesh_assert (in.good()); // The number of vertices in the element in >> nv; libmesh_assert(nv == 2 || nv == 3); if (e == 0) { the_mesh.set_mesh_dimension(nv-1); if (nv == 3) { #if LIBMESH_DIM < 2 libMesh::err << "Cannot open dimension 2 mesh file when configured without 2D support." << std::endl; libmesh_error(); #endif } } Elem* elem; switch (nv) { case 2: elem = new Edge2; break; case 3: elem = new Tri3 ; break; default: libmesh_error(); } elem->set_id(e); the_mesh.add_elem (elem); for (unsigned int i=0; i<nv; i++) { in >> nid; elem->set_node(i) = the_mesh.node_ptr(nid); } } }
void VTKIO::read (const std::string& name) { // This is a serial-only process for now; // the Mesh should be read on processor 0 and // broadcast later libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0); // Keep track of what kinds of elements this file contains elems_of_dimension.clear(); elems_of_dimension.resize(4, false); #ifndef LIBMESH_HAVE_VTK libMesh::err << "Cannot read VTK file: " << name << "\nYou must have VTK installed and correctly configured to read VTK meshes." << std::endl; libmesh_error(); #else // Use a typedef, because these names are just crazy typedef vtkSmartPointer<vtkXMLUnstructuredGridReader> MyReader; MyReader reader = MyReader::New(); // Pass the filename along to the reader reader->SetFileName( name.c_str() ); // Force reading reader->Update(); // read in the grid _vtk_grid = reader->GetOutput(); // _vtk_grid->Update(); // FIXME: Necessary? // Get a reference to the mesh MeshBase& mesh = MeshInput<MeshBase>::mesh(); // Clear out any pre-existing data from the Mesh mesh.clear(); // Get the number of points from the _vtk_grid object const unsigned int vtk_num_points = static_cast<unsigned int>(_vtk_grid->GetNumberOfPoints()); // always numbered nicely??, so we can loop like this // I'm pretty sure it is numbered nicely for (unsigned int i=0; i<vtk_num_points; ++i) { // add to the id map // and add the actual point double * pnt = _vtk_grid->GetPoint(static_cast<vtkIdType>(i)); Point xyz(pnt[0], pnt[1], pnt[2]); Node* newnode = mesh.add_point(xyz, i); // Add node to the nodes vector & // tell the MeshData object the foreign node id. if (this->_mesh_data != NULL) this->_mesh_data->add_foreign_node_id (newnode, i); } // Get the number of cells from the _vtk_grid object const unsigned int vtk_num_cells = static_cast<unsigned int>(_vtk_grid->GetNumberOfCells()); for (unsigned int i=0; i<vtk_num_cells; ++i) { vtkCell* cell = _vtk_grid->GetCell(i); Elem* elem = NULL; switch (cell->GetCellType()) { case VTK_LINE: elem = new Edge2; break; case VTK_QUADRATIC_EDGE: elem = new Edge3; break; case VTK_TRIANGLE: elem = new Tri3(); break; case VTK_QUADRATIC_TRIANGLE: elem = new Tri6(); break; case VTK_QUAD: elem = new Quad4(); break; case VTK_QUADRATIC_QUAD: elem = new Quad8(); break; #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_BIQUADRATIC_QUAD: elem = new Quad9(); break; #endif case VTK_TETRA: elem = new Tet4(); break; case VTK_QUADRATIC_TETRA: elem = new Tet10(); break; case VTK_WEDGE: elem = new Prism6(); break; case VTK_QUADRATIC_WEDGE: elem = new Prism15(); break; case VTK_BIQUADRATIC_QUADRATIC_WEDGE: elem = new Prism18(); break; case VTK_HEXAHEDRON: elem = new Hex8(); break; case VTK_QUADRATIC_HEXAHEDRON: elem = new Hex20(); break; case VTK_TRIQUADRATIC_HEXAHEDRON: elem = new Hex27(); break; case VTK_PYRAMID: elem = new Pyramid5(); break; default: libMesh::err << "element type not implemented in vtkinterface " << cell->GetCellType() << std::endl; libmesh_error(); break; } // get the straightforward numbering from the VTK cells for (unsigned int j=0; j<elem->n_nodes(); ++j) elem->set_node(j) = mesh.node_ptr(cell->GetPointId(j)); // then get the connectivity std::vector<dof_id_type> conn; elem->connectivity(0, VTK, conn); // then reshuffle the nodes according to the connectivity, this // two-time-assign would evade the definition of the vtk_mapping for (unsigned int j=0; j<conn.size(); ++j) elem->set_node(j) = mesh.node_ptr(conn[j]); elem->set_id(i); elems_of_dimension[elem->dim()] = true; mesh.add_elem(elem); } // end loop over VTK cells // Set the mesh dimension to the largest encountered for an element for (unsigned int i=0; i!=4; ++i) if (elems_of_dimension[i]) mesh.set_mesh_dimension(i); #if LIBMESH_DIM < 3 if (mesh.mesh_dimension() > LIBMESH_DIM) { libMesh::err << "Cannot open dimension " << mesh.mesh_dimension() << " mesh file when configured without " << mesh.mesh_dimension() << "D support." << std::endl; libmesh_error(); } #endif #endif // LIBMESH_HAVE_VTK }
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 MatlabIO::read_stream(std::istream& in) { // This is a serial-only process for now; // the Mesh should be read on processor 0 and // broadcast later libmesh_assert_equal_to (this->mesh().processor_id(), 0); // Get a reference to the mesh MeshBase& the_mesh = MeshInput<MeshBase>::mesh(); // Clear any existing mesh data the_mesh.clear(); // PDE toolkit only works in 2D the_mesh.set_mesh_dimension(2); #if LIBMESH_DIM < 2 libMesh::err << "Cannot open dimension 2 mesh file when configured without 2D support." << std::endl; libmesh_error(); #endif // Check the input buffer libmesh_assert (in.good()); unsigned int nNodes=0, nElem=0; in >> nNodes // Read the number of nodes >> nElem; // Read the number of elements // Sort of check that it worked libmesh_assert_greater (nNodes, 0); libmesh_assert_greater (nElem, 0); // Read the nodal coordinates { Real x=0., y=0., z=0.; for (unsigned int i=0; i<nNodes; i++) { in >> x // x-coordinate value >> y; // y-coordinate value the_mesh.add_point ( Point(x,y,z), i); } } // Read the elements (elements) { unsigned int node=0, dummy=0; for (unsigned int i=0; i<nElem; i++) { Elem* elem = new Tri3; // Always build a triangle elem->set_id(i); the_mesh.add_elem (elem); for (unsigned int n=0; n<3; n++) // Always read three 3 nodes { in >> node; elem->set_node(n) = the_mesh.node_ptr(node-1); // Assign the node number } // There is an additional subdomain number here, // so we read it and get rid of it! in >> dummy; } } }
void unpack(std::vector<largest_id_type>::const_iterator in, Elem** out, MeshBase* mesh) { #ifndef NDEBUG const std::vector<largest_id_type>::const_iterator original_in = in; const largest_id_type incoming_header = *in++; libmesh_assert_equal_to (incoming_header, elem_magic_header); #endif // int 0: level const unsigned int level = static_cast<unsigned int>(*in++); #ifdef LIBMESH_ENABLE_AMR // int 1: p level const unsigned int p_level = static_cast<unsigned int>(*in++); // int 2: refinement flag const int rflag = *in++; libmesh_assert_greater_equal (rflag, 0); libmesh_assert_less (rflag, Elem::INVALID_REFINEMENTSTATE); const Elem::RefinementState refinement_flag = static_cast<Elem::RefinementState>(rflag); // int 3: p refinement flag const int pflag = *in++; libmesh_assert_greater_equal (pflag, 0); libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE); const Elem::RefinementState p_refinement_flag = static_cast<Elem::RefinementState>(pflag); #else in += 3; #endif // LIBMESH_ENABLE_AMR // int 4: element type const int typeint = *in++; libmesh_assert_greater_equal (typeint, 0); libmesh_assert_less (typeint, INVALID_ELEM); const ElemType type = static_cast<ElemType>(typeint); const unsigned int n_nodes = Elem::type_to_n_nodes_map[type]; // int 5: processor id const processor_id_type processor_id = static_cast<processor_id_type>(*in++); libmesh_assert (processor_id < mesh->n_processors() || processor_id == DofObject::invalid_processor_id); // int 6: subdomain id const subdomain_id_type subdomain_id = static_cast<subdomain_id_type>(*in++); // int 7: dof object id const dof_id_type id = static_cast<dof_id_type>(*in++); libmesh_assert_not_equal_to (id, DofObject::invalid_id); #ifdef LIBMESH_ENABLE_UNIQUE_ID // int 8: dof object unique id const unique_id_type unique_id = static_cast<unique_id_type>(*in++); #endif #ifdef LIBMESH_ENABLE_AMR // int 9: parent dof object id const dof_id_type parent_id = static_cast<dof_id_type>(*in++); libmesh_assert (level == 0 || parent_id != DofObject::invalid_id); libmesh_assert (level != 0 || parent_id == DofObject::invalid_id); // int 10: local child id const unsigned int which_child_am_i = static_cast<unsigned int>(*in++); #else in += 2; #endif // LIBMESH_ENABLE_AMR // Make sure we don't miscount above when adding the "magic" header // plus the real data header libmesh_assert_equal_to (in - original_in, header_size + 1); Elem *elem = mesh->query_elem(id); // if we already have this element, make sure its // properties match, and update any missing neighbor // links, but then go on if (elem) { libmesh_assert_equal_to (elem->level(), level); libmesh_assert_equal_to (elem->id(), id); //#ifdef LIBMESH_ENABLE_UNIQUE_ID // No check for unqiue id sanity //#endif libmesh_assert_equal_to (elem->processor_id(), processor_id); libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id); libmesh_assert_equal_to (elem->type(), type); libmesh_assert_equal_to (elem->n_nodes(), n_nodes); #ifndef NDEBUG // All our nodes should be correct for (unsigned int i=0; i != n_nodes; ++i) libmesh_assert(elem->node(i) == static_cast<dof_id_type>(*in++)); #else in += n_nodes; #endif #ifdef LIBMESH_ENABLE_AMR libmesh_assert_equal_to (elem->p_level(), p_level); libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag); libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag); libmesh_assert (!level || elem->parent() != NULL); libmesh_assert (!level || elem->parent()->id() == parent_id); libmesh_assert (!level || elem->parent()->child(which_child_am_i) == elem); #endif // Our neighbor links should be "close to" correct - we may have // to update them, but we can check for some inconsistencies. for (unsigned int n=0; n != elem->n_neighbors(); ++n) { const dof_id_type neighbor_id = static_cast<dof_id_type>(*in++); // If the sending processor sees a domain boundary here, // we'd better agree. if (neighbor_id == DofObject::invalid_id) { libmesh_assert (!(elem->neighbor(n))); continue; } // If the sending processor has a remote_elem neighbor here, // then all we know is that we'd better *not* have a domain // boundary. if (neighbor_id == remote_elem->id()) { libmesh_assert(elem->neighbor(n)); continue; } Elem *neigh = mesh->query_elem(neighbor_id); // The sending processor sees a neighbor here, so if we // don't have that neighboring element, then we'd better // have a remote_elem signifying that fact. if (!neigh) { libmesh_assert_equal_to (elem->neighbor(n), remote_elem); continue; } // The sending processor has a neighbor here, and we have // that element, but that does *NOT* mean we're already // linking to it. Perhaps we initially received both elem // and neigh from processors on which their mutual link was // remote? libmesh_assert(elem->neighbor(n) == neigh || elem->neighbor(n) == remote_elem); // If the link was originally remote, we should update it, // and make sure the appropriate parts of its family link // back to us. if (elem->neighbor(n) == remote_elem) { elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } } // FIXME: We should add some debug mode tests to ensure that the // encoded indexing and boundary conditions are consistent. } else { // We don't already have the element, so we need to create it. // Find the parent if necessary Elem *parent = NULL; #ifdef LIBMESH_ENABLE_AMR // Find a child element's parent if (level > 0) { // Note that we must be very careful to construct the send // connectivity so that parents are encountered before // children. If we get here and can't find the parent that // is a fatal error. parent = mesh->elem(parent_id); } // Or assert that the sending processor sees no parent else libmesh_assert_equal_to (parent_id, static_cast<dof_id_type>(-1)); #else // No non-level-0 elements without AMR libmesh_assert_equal_to (level, 0); #endif elem = Elem::build(type,parent).release(); libmesh_assert (elem); #ifdef LIBMESH_ENABLE_AMR if (level != 0) { // Since this is a newly created element, the parent must // have previously thought of this child as a remote element. libmesh_assert_equal_to (parent->child(which_child_am_i), remote_elem); parent->add_child(elem, which_child_am_i); } // Assign the refinement flags and levels elem->set_p_level(p_level); elem->set_refinement_flag(refinement_flag); elem->set_p_refinement_flag(p_refinement_flag); libmesh_assert_equal_to (elem->level(), level); // If this element definitely should have children, assign // remote_elem to all of them for now, for consistency. Later // unpacked elements may overwrite that. if (!elem->active()) for (unsigned int c=0; c != elem->n_children(); ++c) elem->add_child(const_cast<RemoteElem*>(remote_elem), c); #endif // LIBMESH_ENABLE_AMR // Assign the IDs elem->subdomain_id() = subdomain_id; elem->processor_id() = processor_id; elem->set_id() = id; #ifdef LIBMESH_ENABLE_UNIQUE_ID elem->set_unique_id() = unique_id; #endif // Assign the connectivity libmesh_assert_equal_to (elem->n_nodes(), n_nodes); for (unsigned int n=0; n != n_nodes; n++) elem->set_node(n) = mesh->node_ptr (static_cast<dof_id_type>(*in++)); for (unsigned int n=0; n<elem->n_neighbors(); n++) { const dof_id_type neighbor_id = static_cast<dof_id_type>(*in++); if (neighbor_id == DofObject::invalid_id) continue; // We may be unpacking an element that was a ghost element on the // sender, in which case the element's neighbors may not all be // known by the packed element. We'll have to set such // neighbors to remote_elem ourselves and wait for a later // packed element to give us better information. if (neighbor_id == remote_elem->id()) { elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem)); continue; } // If we don't have the neighbor element, then it's a // remote_elem until we get it. Elem *neigh = mesh->query_elem(neighbor_id); if (!neigh) { elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem)); continue; } // If we have the neighbor element, then link to it, and // make sure the appropriate parts of its family link back // to us. elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } elem->unpack_indexing(in); } in += elem->packed_indexing_size(); // If this is a coarse element, // add any element side boundary condition ids if (level == 0) for (unsigned int s = 0; s != elem->n_sides(); ++s) { const int num_bcs = *in++; libmesh_assert_greater_equal (num_bcs, 0); for(int bc_it=0; bc_it < num_bcs; bc_it++) mesh->boundary_info->add_side (elem, s, *in++); } // Return the new element *out = elem; }
void UnstructuredMesh::copy_nodes_and_elements(const UnstructuredMesh & other_mesh, const bool skip_find_neighbors) { // We're assuming our subclass data needs no copy libmesh_assert_equal_to (_n_parts, other_mesh._n_parts); libmesh_assert (std::equal(_elem_dims.begin(), _elem_dims.end(), other_mesh._elem_dims.begin())); libmesh_assert_equal_to (_is_prepared, other_mesh._is_prepared); // We're assuming the other mesh has proper element number ordering, // so that we add parents before their children. #ifdef DEBUG MeshTools::libmesh_assert_valid_amr_elem_ids(other_mesh); #endif //Copy in Nodes { //Preallocate Memory if necessary this->reserve_nodes(other_mesh.n_nodes()); const_node_iterator it = other_mesh.nodes_begin(); const_node_iterator end = other_mesh.nodes_end(); for (; it != end; ++it) { const Node * oldn = *it; // Add new nodes in old node Point locations #ifdef LIBMESH_ENABLE_UNIQUE_ID Node *newn = #endif this->add_point(*oldn, oldn->id(), oldn->processor_id()); #ifdef LIBMESH_ENABLE_UNIQUE_ID newn->set_unique_id() = oldn->unique_id(); #endif } } //Copy in Elements { //Preallocate Memory if necessary this->reserve_elem(other_mesh.n_elem()); // Declare a map linking old and new elements, needed to copy the neighbor lists std::map<const Elem *, Elem *> old_elems_to_new_elems; // Loop over the elements MeshBase::const_element_iterator it = other_mesh.elements_begin(); const MeshBase::const_element_iterator end = other_mesh.elements_end(); // FIXME: Where do we set element IDs?? for (; it != end; ++it) { //Look at the old element const Elem * old = *it; //Build a new element Elem * newparent = old->parent() ? this->elem_ptr(old->parent()->id()) : libmesh_nullptr; UniquePtr<Elem> ap = Elem::build(old->type(), newparent); Elem * el = ap.release(); el->subdomain_id() = old->subdomain_id(); for (unsigned int s=0; s != old->n_sides(); ++s) if (old->neighbor_ptr(s) == remote_elem) el->set_neighbor(s, const_cast<RemoteElem *>(remote_elem)); #ifdef LIBMESH_ENABLE_AMR if (old->has_children()) for (unsigned int c=0; c != old->n_children(); ++c) if (old->child_ptr(c) == remote_elem) el->add_child(const_cast<RemoteElem *>(remote_elem), c); //Create the parent's child pointers if necessary if (newparent) { unsigned int oldc = old->parent()->which_child_am_i(old); newparent->add_child(el, oldc); } // Copy the refinement flags el->set_refinement_flag(old->refinement_flag()); // Use hack_p_level since we may not have sibling elements // added yet el->hack_p_level(old->p_level()); el->set_p_refinement_flag(old->p_refinement_flag()); #endif // #ifdef LIBMESH_ENABLE_AMR //Assign all the nodes for(unsigned int i=0;i<el->n_nodes();i++) el->set_node(i) = this->node_ptr(old->node_id(i)); // And start it off in the same subdomain el->processor_id() = old->processor_id(); // Give it the same ids el->set_id(old->id()); #ifdef LIBMESH_ENABLE_UNIQUE_ID el->set_unique_id() = old->unique_id(); #endif //Hold onto it if(!skip_find_neighbors) { this->add_elem(el); } else { Elem * new_el = this->add_elem(el); old_elems_to_new_elems[old] = new_el; } // Add the link between the original element and this copy to the map if(skip_find_neighbors) old_elems_to_new_elems[old] = el; } // Loop (again) over the elements to fill in the neighbors if(skip_find_neighbors) { it = other_mesh.elements_begin(); for (; it != end; ++it) { Elem * old_elem = *it; Elem * new_elem = old_elems_to_new_elems[old_elem]; for (unsigned int s=0; s != old_elem->n_neighbors(); ++s) { const Elem * old_neighbor = old_elem->neighbor_ptr(s); Elem * new_neighbor = old_elems_to_new_elems[old_neighbor]; new_elem->set_neighbor(s, new_neighbor); } } } } //Finally prepare the new Mesh for use. Keep the same numbering and //partitioning but also the same renumbering and partitioning //policies as our source mesh. this->allow_renumbering(false); this->skip_partitioning(true); this->prepare_for_use(false, skip_find_neighbors); this->allow_renumbering(other_mesh.allow_renumbering()); this->skip_partitioning(other_mesh.skip_partitioning()); }
void VTKIO::read (const std::string & name) { // This is a serial-only process for now; // the Mesh should be read on processor 0 and // broadcast later libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0); // Keep track of what kinds of elements this file contains elems_of_dimension.clear(); elems_of_dimension.resize(4, false); // Use a typedef, because these names are just crazy typedef vtkSmartPointer<vtkXMLUnstructuredGridReader> MyReader; MyReader reader = MyReader::New(); // Pass the filename along to the reader reader->SetFileName(name.c_str()); // Force reading reader->Update(); // read in the grid _vtk_grid = reader->GetOutput(); // _vtk_grid->Update(); // FIXME: Necessary? // Get a reference to the mesh MeshBase & mesh = MeshInput<MeshBase>::mesh(); // Clear out any pre-existing data from the Mesh mesh.clear(); // Get the number of points from the _vtk_grid object const unsigned int vtk_num_points = static_cast<unsigned int>(_vtk_grid->GetNumberOfPoints()); // always numbered nicely??, so we can loop like this // I'm pretty sure it is numbered nicely for (unsigned int i=0; i<vtk_num_points; ++i) { // add to the id map // and add the actual point double * pnt = _vtk_grid->GetPoint(static_cast<vtkIdType>(i)); Point xyz(pnt[0], pnt[1], pnt[2]); Node * newnode = mesh.add_point(xyz, i); // Add node to the nodes vector & // tell the MeshData object the foreign node id. if (this->_mesh_data != libmesh_nullptr) this->_mesh_data->add_foreign_node_id (newnode, i); } // Get the number of cells from the _vtk_grid object const unsigned int vtk_num_cells = static_cast<unsigned int>(_vtk_grid->GetNumberOfCells()); for (unsigned int i=0; i<vtk_num_cells; ++i) { vtkCell * cell = _vtk_grid->GetCell(i); // Get the libMesh element type corresponding to this VTK element type. ElemType libmesh_elem_type = _element_maps.find(cell->GetCellType()); Elem * elem = Elem::build(libmesh_elem_type).release(); // get the straightforward numbering from the VTK cells for (unsigned int j=0; j<elem->n_nodes(); ++j) elem->set_node(j) = mesh.node_ptr(cast_int<dof_id_type>(cell->GetPointId(j))); // then get the connectivity std::vector<dof_id_type> conn; elem->connectivity(0, VTK, conn); // then reshuffle the nodes according to the connectivity, this // two-time-assign would evade the definition of the vtk_mapping for (unsigned int j=0; j<conn.size(); ++j) elem->set_node(j) = mesh.node_ptr(conn[j]); elem->set_id(i); elems_of_dimension[elem->dim()] = true; mesh.add_elem(elem); } // end loop over VTK cells // Set the mesh dimension to the largest encountered for an element for (unsigned char i=0; i!=4; ++i) if (elems_of_dimension[i]) mesh.set_mesh_dimension(i); #if LIBMESH_DIM < 3 if (mesh.mesh_dimension() > LIBMESH_DIM) libmesh_error_msg("Cannot open dimension " \ << mesh.mesh_dimension() \ << " mesh file when configured without " \ << mesh.mesh_dimension() \ << "D support."); #endif // LIBMESH_DIM < 3 }
void CheckpointIO::read_connectivity (Xdr & io) { // convenient reference to our mesh MeshBase & mesh = MeshInput<MeshBase>::mesh(); unsigned int n_active_levels; io.data(n_active_levels, "# n_active_levels"); // Keep track of the highest dimensional element we've added to the mesh unsigned int highest_elem_dim = 1; for(unsigned int level=0; level < n_active_levels; level++) { xdr_id_type n_elem_at_level = 0; io.data (n_elem_at_level, ""); for (unsigned int i=0; i<n_elem_at_level; i++) { // id type pid subdomain_id parent_id std::vector<largest_id_type> elem_data(5); io.data_stream (&elem_data[0], cast_int<unsigned int>(elem_data.size()), cast_int<unsigned int>(elem_data.size())); #ifdef LIBMESH_ENABLE_UNIQUE_ID largest_id_type unique_id = 0; io.data(unique_id, "# unique id"); #endif #ifdef LIBMESH_ENABLE_AMR unsigned int p_level = 0; io.data(p_level, "# p_level"); #endif unsigned int n_nodes = Elem::type_to_n_nodes_map[elem_data[1]]; // Snag the node ids this element was connected to std::vector<largest_id_type> conn_data(n_nodes); io.data_stream (&conn_data[0], cast_int<unsigned int>(conn_data.size()), cast_int<unsigned int>(conn_data.size())); const dof_id_type id = cast_int<dof_id_type> (elem_data[0]); const ElemType elem_type = static_cast<ElemType> (elem_data[1]); const processor_id_type proc_id = cast_int<processor_id_type>(elem_data[2]); const subdomain_id_type subdomain_id = cast_int<subdomain_id_type>(elem_data[3]); const dof_id_type parent_id = cast_int<dof_id_type> (elem_data[4]); Elem * parent = (parent_id == DofObject::invalid_processor_id) ? libmesh_nullptr : mesh.elem_ptr(parent_id); // Create the element Elem * elem = Elem::build(elem_type, parent).release(); #ifdef LIBMESH_ENABLE_UNIQUE_ID elem->set_unique_id() = unique_id; #endif if(elem->dim() > highest_elem_dim) highest_elem_dim = elem->dim(); elem->set_id() = id; elem->processor_id() = proc_id; elem->subdomain_id() = subdomain_id; #ifdef LIBMESH_ENABLE_AMR elem->hack_p_level(p_level); // Set parent connections if(parent) { parent->add_child(elem); parent->set_refinement_flag (Elem::INACTIVE); elem->set_refinement_flag (Elem::JUST_REFINED); } #endif libmesh_assert(elem->n_nodes() == conn_data.size()); // Connect all the nodes to this element for (unsigned int n=0; n<conn_data.size(); n++) elem->set_node(n) = mesh.node_ptr(cast_int<dof_id_type>(conn_data[n])); mesh.add_elem(elem); } } mesh.set_mesh_dimension(cast_int<unsigned char>(highest_elem_dim)); }
Elem * Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in, MeshBase * mesh) { #ifndef NDEBUG const std::vector<largest_id_type>::const_iterator original_in = in; const largest_id_type incoming_header = *in++; libmesh_assert_equal_to (incoming_header, elem_magic_header); #endif // int 0: level const unsigned int level = cast_int<unsigned int>(*in++); #ifdef LIBMESH_ENABLE_AMR // int 1: p level const unsigned int p_level = cast_int<unsigned int>(*in++); // int 2: refinement flag and encoded has_children const int rflag = cast_int<int>(*in++); const int invalid_rflag = cast_int<int>(Elem::INVALID_REFINEMENTSTATE); libmesh_assert_greater_equal (rflag, 0); libmesh_assert_less (rflag, invalid_rflag*2+1); const bool has_children = (rflag > invalid_rflag); const Elem::RefinementState refinement_flag = has_children ? cast_int<Elem::RefinementState>(rflag - invalid_rflag - 1) : cast_int<Elem::RefinementState>(rflag); // int 3: p refinement flag const int pflag = cast_int<int>(*in++); libmesh_assert_greater_equal (pflag, 0); libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE); const Elem::RefinementState p_refinement_flag = cast_int<Elem::RefinementState>(pflag); #else in += 3; #endif // LIBMESH_ENABLE_AMR // int 4: element type const int typeint = cast_int<int>(*in++); libmesh_assert_greater_equal (typeint, 0); libmesh_assert_less (typeint, INVALID_ELEM); const ElemType type = cast_int<ElemType>(typeint); const unsigned int n_nodes = Elem::type_to_n_nodes_map[type]; // int 5: processor id const processor_id_type processor_id = cast_int<processor_id_type>(*in++); libmesh_assert (processor_id < mesh->n_processors() || processor_id == DofObject::invalid_processor_id); // int 6: subdomain id const subdomain_id_type subdomain_id = cast_int<subdomain_id_type>(*in++); // int 7: dof object id const dof_id_type id = cast_int<dof_id_type>(*in++); libmesh_assert_not_equal_to (id, DofObject::invalid_id); #ifdef LIBMESH_ENABLE_UNIQUE_ID // int 8: dof object unique id const unique_id_type unique_id = cast_int<unique_id_type>(*in++); #endif #ifdef LIBMESH_ENABLE_AMR // int 9: parent dof object id. // Note: If level==0, then (*in) == invalid_id. In // this case, the equality check in cast_int<unsigned>(*in) will // never succeed. Therefore, we should only attempt the more // rigorous cast verification in cases where level != 0. const dof_id_type parent_id = (level == 0) ? static_cast<dof_id_type>(*in++) : cast_int<dof_id_type>(*in++); libmesh_assert (level == 0 || parent_id != DofObject::invalid_id); libmesh_assert (level != 0 || parent_id == DofObject::invalid_id); // int 10: local child id // Note: If level==0, then which_child_am_i is not valid, so don't // do the more rigorous cast verification. const unsigned int which_child_am_i = (level == 0) ? static_cast<unsigned int>(*in++) : cast_int<unsigned int>(*in++); #else in += 2; #endif // LIBMESH_ENABLE_AMR const dof_id_type interior_parent_id = static_cast<dof_id_type>(*in++); // Make sure we don't miscount above when adding the "magic" header // plus the real data header libmesh_assert_equal_to (in - original_in, header_size + 1); Elem * elem = mesh->query_elem_ptr(id); // if we already have this element, make sure its // properties match, and update any missing neighbor // links, but then go on if (elem) { libmesh_assert_equal_to (elem->level(), level); libmesh_assert_equal_to (elem->id(), id); //#ifdef LIBMESH_ENABLE_UNIQUE_ID // No check for unique id sanity //#endif libmesh_assert_equal_to (elem->processor_id(), processor_id); libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id); libmesh_assert_equal_to (elem->type(), type); libmesh_assert_equal_to (elem->n_nodes(), n_nodes); #ifndef NDEBUG // All our nodes should be correct for (unsigned int i=0; i != n_nodes; ++i) libmesh_assert(elem->node_id(i) == cast_int<dof_id_type>(*in++)); #else in += n_nodes; #endif #ifdef LIBMESH_ENABLE_AMR libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag); libmesh_assert_equal_to (elem->has_children(), has_children); #ifdef DEBUG if (elem->active()) { libmesh_assert_equal_to (elem->p_level(), p_level); libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag); } #endif libmesh_assert (!level || elem->parent() != libmesh_nullptr); libmesh_assert (!level || elem->parent()->id() == parent_id); libmesh_assert (!level || elem->parent()->child_ptr(which_child_am_i) == elem); #endif // Our interior_parent link should be "close to" correct - we // may have to update it, but we can check for some // inconsistencies. { // If the sending processor sees no interior_parent here, we'd // better agree. if (interior_parent_id == DofObject::invalid_id) { if (elem->dim() < LIBMESH_DIM) libmesh_assert (!(elem->interior_parent())); } // If the sending processor has a remote_elem interior_parent, // then all we know is that we'd better have *some* // interior_parent else if (interior_parent_id == remote_elem->id()) { libmesh_assert(elem->interior_parent()); } else { Elem * ip = mesh->query_elem_ptr(interior_parent_id); // The sending processor sees an interior parent here, so // if we don't have that interior element, then we'd // better have a remote_elem signifying that fact. if (!ip) libmesh_assert_equal_to (elem->interior_parent(), remote_elem); else { // The sending processor has an interior_parent here, // and we have that element, but that does *NOT* mean // we're already linking to it. Perhaps we initially // received elem from a processor on which the // interior_parent link was remote? libmesh_assert(elem->interior_parent() == ip || elem->interior_parent() == remote_elem); // If the link was originally remote, update it if (elem->interior_parent() == remote_elem) { elem->set_interior_parent(ip); } } } } // Our neighbor links should be "close to" correct - we may have // to update a remote_elem link, and we can check for possible // inconsistencies along the way. // // For subactive elements, we don't bother keeping neighbor // links in good shape, so there's nothing we need to set or can // safely assert here. if (!elem->subactive()) for (auto n : elem->side_index_range()) { const dof_id_type neighbor_id = cast_int<dof_id_type>(*in++); // If the sending processor sees a domain boundary here, // we'd better agree. if (neighbor_id == DofObject::invalid_id) { libmesh_assert (!(elem->neighbor_ptr(n))); continue; } // If the sending processor has a remote_elem neighbor here, // then all we know is that we'd better *not* have a domain // boundary. if (neighbor_id == remote_elem->id()) { libmesh_assert(elem->neighbor_ptr(n)); continue; } Elem * neigh = mesh->query_elem_ptr(neighbor_id); // The sending processor sees a neighbor here, so if we // don't have that neighboring element, then we'd better // have a remote_elem signifying that fact. if (!neigh) { libmesh_assert_equal_to (elem->neighbor_ptr(n), remote_elem); continue; } // The sending processor has a neighbor here, and we have // that element, but that does *NOT* mean we're already // linking to it. Perhaps we initially received both elem // and neigh from processors on which their mutual link was // remote? libmesh_assert(elem->neighbor_ptr(n) == neigh || elem->neighbor_ptr(n) == remote_elem); // If the link was originally remote, we should update it, // and make sure the appropriate parts of its family link // back to us. if (elem->neighbor_ptr(n) == remote_elem) { elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } } // Our p level and refinement flags should be "close to" correct // if we're not an active element - we might have a p level // increased or decreased by changes in remote_elem children. // // But if we have remote_elem children, then we shouldn't be // doing a projection on this inactive element on this // processor, so we won't need correct p settings. Couldn't // hurt to update, though. #ifdef LIBMESH_ENABLE_AMR if (elem->processor_id() != mesh->processor_id()) { elem->hack_p_level(p_level); elem->set_p_refinement_flag(p_refinement_flag); } #endif // LIBMESH_ENABLE_AMR // FIXME: We should add some debug mode tests to ensure that the // encoded indexing and boundary conditions are consistent. } else { // We don't already have the element, so we need to create it. // Find the parent if necessary Elem * parent = libmesh_nullptr; #ifdef LIBMESH_ENABLE_AMR // Find a child element's parent if (level > 0) { // Note that we must be very careful to construct the send // connectivity so that parents are encountered before // children. If we get here and can't find the parent that // is a fatal error. parent = mesh->elem_ptr(parent_id); } // Or assert that the sending processor sees no parent else libmesh_assert_equal_to (parent_id, DofObject::invalid_id); #else // No non-level-0 elements without AMR libmesh_assert_equal_to (level, 0); #endif elem = Elem::build(type,parent).release(); libmesh_assert (elem); #ifdef LIBMESH_ENABLE_AMR if (level != 0) { // Since this is a newly created element, the parent must // have previously thought of this child as a remote element. libmesh_assert_equal_to (parent->child_ptr(which_child_am_i), remote_elem); parent->add_child(elem, which_child_am_i); } // Assign the refinement flags and levels elem->set_p_level(p_level); elem->set_refinement_flag(refinement_flag); elem->set_p_refinement_flag(p_refinement_flag); libmesh_assert_equal_to (elem->level(), level); // If this element should have children, assign remote_elem to // all of them for now, for consistency. Later unpacked // elements may overwrite that. if (has_children) { const unsigned int nc = elem->n_children(); for (unsigned int c=0; c != nc; ++c) elem->add_child(const_cast<RemoteElem *>(remote_elem), c); } #endif // LIBMESH_ENABLE_AMR // Assign the IDs elem->subdomain_id() = subdomain_id; elem->processor_id() = processor_id; elem->set_id() = id; #ifdef LIBMESH_ENABLE_UNIQUE_ID elem->set_unique_id() = unique_id; #endif // Assign the connectivity libmesh_assert_equal_to (elem->n_nodes(), n_nodes); for (unsigned int n=0; n != n_nodes; n++) elem->set_node(n) = mesh->node_ptr (cast_int<dof_id_type>(*in++)); // Set interior_parent if found { // We may be unpacking an element that was a ghost element on the // sender, in which case the element's interior_parent may not be // known by the packed element. We'll have to set such // interior_parents to remote_elem ourselves and wait for a // later packed element to give us better information. if (interior_parent_id == remote_elem->id()) { elem->set_interior_parent (const_cast<RemoteElem *>(remote_elem)); } else if (interior_parent_id != DofObject::invalid_id) { // If we don't have the interior parent element, then it's // a remote_elem until we get it. Elem * ip = mesh->query_elem_ptr(interior_parent_id); if (!ip ) elem->set_interior_parent (const_cast<RemoteElem *>(remote_elem)); else elem->set_interior_parent(ip); } } for (auto n : elem->side_index_range()) { const dof_id_type neighbor_id = cast_int<dof_id_type>(*in++); if (neighbor_id == DofObject::invalid_id) continue; // We may be unpacking an element that was a ghost element on the // sender, in which case the element's neighbors may not all be // known by the packed element. We'll have to set such // neighbors to remote_elem ourselves and wait for a later // packed element to give us better information. if (neighbor_id == remote_elem->id()) { elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem)); continue; } // If we don't have the neighbor element, then it's a // remote_elem until we get it. Elem * neigh = mesh->query_elem_ptr(neighbor_id); if (!neigh) { elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem)); continue; } // If we have the neighbor element, then link to it, and // make sure the appropriate parts of its family link back // to us. elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } elem->unpack_indexing(in); } in += elem->packed_indexing_size(); // If this is a coarse element, // add any element side or edge boundary condition ids if (level == 0) { for (auto s : elem->side_index_range()) { const boundary_id_type num_bcs = cast_int<boundary_id_type>(*in++); for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++) mesh->get_boundary_info().add_side (elem, s, cast_int<boundary_id_type>(*in++)); } for (auto e : elem->edge_index_range()) { const boundary_id_type num_bcs = cast_int<boundary_id_type>(*in++); for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++) mesh->get_boundary_info().add_edge (elem, e, cast_int<boundary_id_type>(*in++)); } for (unsigned short sf=0; sf != 2; ++sf) { const boundary_id_type num_bcs = cast_int<boundary_id_type>(*in++); for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++) mesh->get_boundary_info().add_shellface (elem, sf, cast_int<boundary_id_type>(*in++)); } } // Return the new element return elem; }
void ExodusII_IO::read (const std::string & fname) { // Get a reference to the mesh we are reading MeshBase & mesh = MeshInput<MeshBase>::mesh(); // Clear any existing mesh data mesh.clear(); // Keep track of what kinds of elements this file contains elems_of_dimension.clear(); elems_of_dimension.resize(4, false); #ifdef DEBUG this->verbose(true); #endif // Instantiate the ElementMaps interface ExodusII_IO_Helper::ElementMaps em(*exio_helper); // Open the exodus file in EX_READ mode exio_helper->open(fname.c_str(), /*read_only=*/true); // Get header information from exodus file exio_helper->read_header(); // Read the QA records exio_helper->read_qa_records(); // Print header information exio_helper->print_header(); // Read nodes from the exodus file exio_helper->read_nodes(); // Reserve space for the nodes. mesh.reserve_nodes(exio_helper->num_nodes); // Read the node number map from the Exodus file. This is // required if we want to preserve the numbering of nodes as it // exists in the Exodus file. If the Exodus file does not contain // a node_num_map, the identity map is returned by this call. exio_helper->read_node_num_map(); // Loop over the nodes, create Nodes with local processor_id 0. for (int i=0; i<exio_helper->num_nodes; i++) { // Use the node_num_map to get the correct ID for Exodus int exodus_id = exio_helper->node_num_map[i]; // Catch the node that was added to the mesh Node * added_node = mesh.add_point (Point(exio_helper->x[i], exio_helper->y[i], exio_helper->z[i]), exodus_id-1); // If the Mesh assigned an ID different from what is in the // Exodus file, we should probably error. if (added_node->id() != static_cast<unsigned>(exodus_id-1)) libmesh_error_msg("Error! Mesh assigned node ID " \ << added_node->id() \ << " which is different from the (zero-based) Exodus ID " \ << exodus_id-1 \ << "!"); } // This assert is no longer valid if the nodes are not numbered // sequentially starting from 1 in the Exodus file. // libmesh_assert_equal_to (static_cast<unsigned int>(exio_helper->num_nodes), mesh.n_nodes()); // Get information about all the blocks exio_helper->read_block_info(); // Reserve space for the elements mesh.reserve_elem(exio_helper->num_elem); // Read the element number map from the Exodus file. This is // required if we want to preserve the numbering of elements as it // exists in the Exodus file. If the Exodus file does not contain // an elem_num_map, the identity map is returned by this call. exio_helper->read_elem_num_map(); // Read in the element connectivity for each block. int nelem_last_block = 0; // Loop over all the blocks for (int i=0; i<exio_helper->num_elem_blk; i++) { // Read the information for block i exio_helper->read_elem_in_block (i); int subdomain_id = exio_helper->get_block_id(i); // populate the map of names std::string subdomain_name = exio_helper->get_block_name(i); if (!subdomain_name.empty()) mesh.subdomain_name(static_cast<subdomain_id_type>(subdomain_id)) = subdomain_name; // Set any relevant node/edge maps for this element const std::string type_str (exio_helper->get_elem_type()); const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(type_str); // Loop over all the faces in this block int jmax = nelem_last_block+exio_helper->num_elem_this_blk; for (int j=nelem_last_block; j<jmax; j++) { Elem * elem = Elem::build (conv.get_canonical_type()).release(); libmesh_assert (elem); elem->subdomain_id() = static_cast<subdomain_id_type>(subdomain_id) ; // Use the elem_num_map to obtain the ID of this element in the Exodus file int exodus_id = exio_helper->elem_num_map[j]; // Assign this element the same ID it had in the Exodus // file, but make it zero-based by subtracting 1. Note: // some day we could use 1-based numbering in libmesh and // thus match the Exodus numbering exactly, but at the // moment libmesh is zero-based. elem->set_id(exodus_id-1); // Record that we have seen an element of dimension elem->dim() elems_of_dimension[elem->dim()] = true; // Catch the Elem pointer that the Mesh throws back elem = mesh.add_elem (elem); // If the Mesh assigned an ID different from what is in the // Exodus file, we should probably error. if (elem->id() != static_cast<unsigned>(exodus_id-1)) libmesh_error_msg("Error! Mesh assigned ID " \ << elem->id() \ << " which is different from the (zero-based) Exodus ID " \ << exodus_id-1 \ << "!"); // Set all the nodes for this element for (int k=0; k<exio_helper->num_nodes_per_elem; k++) { // global index int gi = (j-nelem_last_block)*exio_helper->num_nodes_per_elem + conv.get_node_map(k); // The entries in 'connect' are actually (1-based) // indices into the node_num_map, so to get the right // node ID we: // 1.) Subtract 1 from connect[gi] // 2.) Pass it through node_num_map to get the corresponding Exodus ID // 3.) Subtract 1 from that, since libmesh node numbering is "zero"-based, // even when the Exodus node numbering doesn't start with 1. int libmesh_node_id = exio_helper->node_num_map[exio_helper->connect[gi] - 1] - 1; // Set the node pointer in the Elem elem->set_node(k) = mesh.node_ptr(libmesh_node_id); } } // running sum of # of elements per block, // (should equal total number of elements in the end) nelem_last_block += exio_helper->num_elem_this_blk; } // This assert isn't valid if the Exodus file's numbering doesn't // start with 1! For example, if Exodus's elem_num_map is 21, 22, // 23, 24, 25, 26, 27, 28, 29, 30, ... 84, then by the time you are // done with the loop above, mesh.n_elem() will report 84 and // nelem_last_block will be 64. // libmesh_assert_equal_to (static_cast<unsigned>(nelem_last_block), mesh.n_elem()); // Set the mesh dimension to the largest encountered for an element for (unsigned char i=0; i!=4; ++i) if (elems_of_dimension[i]) mesh.set_mesh_dimension(i); // Read in sideset information -- this is useful for applying boundary conditions { // Get basic information about all sidesets exio_helper->read_sideset_info(); int offset=0; for (int i=0; i<exio_helper->num_side_sets; i++) { // Compute new offset offset += (i > 0 ? exio_helper->num_sides_per_set[i-1] : 0); exio_helper->read_sideset (i, offset); std::string sideset_name = exio_helper->get_side_set_name(i); if (!sideset_name.empty()) mesh.get_boundary_info().sideset_name (cast_int<boundary_id_type>(exio_helper->get_side_set_id(i))) = sideset_name; } for (unsigned int e=0; e<exio_helper->elem_list.size(); e++) { // The numbers in the Exodus file sidesets should be thought // of as (1-based) indices into the elem_num_map array. So, // to get the right element ID we have to: // 1.) Subtract 1 from elem_list[e] (to get a zero-based index) // 2.) Pass it through elem_num_map (to get the corresponding Exodus ID) // 3.) Subtract 1 from that, since libmesh is "zero"-based, // even when the Exodus numbering doesn't start with 1. dof_id_type libmesh_elem_id = cast_int<dof_id_type>(exio_helper->elem_num_map[exio_helper->elem_list[e] - 1] - 1); // Set any relevant node/edge maps for this element Elem * elem = mesh.elem(libmesh_elem_id); const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(elem->type()); // Map the zero-based Exodus side numbering to the libmesh side numbering int mapped_side = conv.get_side_map(exio_helper->side_list[e]-1); // Check for errors if (mapped_side == ExodusII_IO_Helper::Conversion::invalid_id) libmesh_error_msg("Invalid 1-based side id: " \ << exio_helper->side_list[e] \ << " detected for " \ << Utility::enum_to_string(elem->type())); // Add this (elem,side,id) triplet to the BoundaryInfo object. mesh.get_boundary_info().add_side (libmesh_elem_id, cast_int<unsigned short>(mapped_side), cast_int<boundary_id_type>(exio_helper->id_list[e])); } } // Read nodeset info { exio_helper->read_nodeset_info(); for (int nodeset=0; nodeset<exio_helper->num_node_sets; nodeset++) { boundary_id_type nodeset_id = cast_int<boundary_id_type>(exio_helper->nodeset_ids[nodeset]); std::string nodeset_name = exio_helper->get_node_set_name(nodeset); if (!nodeset_name.empty()) mesh.get_boundary_info().nodeset_name(nodeset_id) = nodeset_name; exio_helper->read_nodeset(nodeset); for (unsigned int node=0; node<exio_helper->node_list.size(); node++) { // As before, the entries in 'node_list' are 1-based // indcies into the node_num_map array, so we have to map // them. See comment above. int libmesh_node_id = exio_helper->node_num_map[exio_helper->node_list[node] - 1] - 1; mesh.get_boundary_info().add_node(cast_int<dof_id_type>(libmesh_node_id), nodeset_id); } } } #if LIBMESH_DIM < 3 if (mesh.mesh_dimension() > LIBMESH_DIM) libmesh_error_msg("Cannot open dimension " \ << mesh.mesh_dimension() \ << " mesh file when configured without " \ << mesh.mesh_dimension() \ << "D support."); #endif }
// The actual implementation of building elements. void InfElemBuilder::build_inf_elem(const Point& origin, const bool x_sym, const bool y_sym, const bool z_sym, const bool be_verbose, std::set< std::pair<dof_id_type, unsigned int> >* inner_faces) { if (be_verbose) { #ifdef DEBUG libMesh::out << " Building Infinite Elements:" << std::endl; libMesh::out << " updating element neighbor tables..." << std::endl; #else libMesh::out << " Verbose mode disabled in non-debug mode." << std::endl; #endif } // update element neighbors this->_mesh.find_neighbors(); START_LOG("build_inf_elem()", "InfElemBuilder"); // A set for storing element number, side number pairs. // pair.first == element number, pair.second == side number std::set< std::pair<dof_id_type,unsigned int> > faces; std::set< std::pair<dof_id_type,unsigned int> > ofaces; // A set for storing node numbers on the outer faces. std::set<dof_id_type> onodes; // The distance to the farthest point in the mesh from the origin Real max_r=0.; // The index of the farthest point in the mesh from the origin int max_r_node = -1; #ifdef DEBUG if (be_verbose) { libMesh::out << " collecting boundary sides"; if (x_sym || y_sym || z_sym) libMesh::out << ", skipping sides in symmetry planes..." << std::endl; else libMesh::out << "..." << std::endl; } #endif // Iterate through all elements and sides, collect indices of all active // boundary sides in the faces set. Skip sides which lie in symmetry planes. // Later, sides of the inner boundary will be sorted out. { MeshBase::element_iterator it = this->_mesh.active_elements_begin(); const MeshBase::element_iterator end = this->_mesh.active_elements_end(); for(; it != end; ++it) { Elem* elem = *it; for (unsigned int s=0; s<elem->n_neighbors(); s++) { // check if elem(e) is on the boundary if (elem->neighbor(s) == NULL) { // note that it is safe to use the Elem::side() method, // which gives a non-full-ordered element AutoPtr<Elem> side(elem->build_side(s)); // bool flags for symmetry detection bool sym_side=false; bool on_x_sym=true; bool on_y_sym=true; bool on_z_sym=true; // Loop over the nodes to check whether they are on the symmetry planes, // and therefore sufficient to use a non-full-ordered side element for(unsigned int n=0; n<side->n_nodes(); n++) { const Point dist_from_origin = this->_mesh.point(side->node(n)) - origin; if(x_sym) if( std::abs(dist_from_origin(0)) > 1.e-3 ) on_x_sym=false; if(y_sym) if( std::abs(dist_from_origin(1)) > 1.e-3 ) on_y_sym=false; if(z_sym) if( std::abs(dist_from_origin(2)) > 1.e-3 ) on_z_sym=false; // if(x_sym) // if( std::abs(dist_from_origin(0)) > 1.e-6 ) // on_x_sym=false; // if(y_sym) // if( std::abs(dist_from_origin(1)) > 1.e-6 ) // on_y_sym=false; // if(z_sym) // if( std::abs(dist_from_origin(2)) > 1.e-6 ) // on_z_sym=false; //find the node most distant from origin Real r = dist_from_origin.size(); if (r > max_r) { max_r = r; max_r_node=side->node(n); } } sym_side = (x_sym && on_x_sym) || (y_sym && on_y_sym) || (z_sym && on_z_sym); if (!sym_side) faces.insert( std::make_pair(elem->id(), s) ); } // neighbor(s) == NULL } // sides } // elems } // If a boundary side has one node on the outer boundary, // all points of this side are on the outer boundary. // Start with the node most distant from origin, which has // to be on the outer boundary, then recursively find all // sides and nodes connected to it. Found sides are moved // from faces to ofaces, nodes are collected in onodes. // Here, the search is done iteratively, because, depending on // the mesh, a very high level of recursion might be necessary. if (max_r_node > 0) onodes.insert(max_r_node); { std::set< std::pair<dof_id_type,unsigned int> >::iterator face_it = faces.begin(); unsigned int facesfound=0; while (face_it != faces.end()) { std::pair<dof_id_type, unsigned int> p; p = *face_it; // This has to be a full-ordered side element, // since we need the correct n_nodes, AutoPtr<Elem> side(this->_mesh.elem(p.first)->build_side(p.second)); bool found=false; for(unsigned int sn=0; sn<side->n_nodes(); sn++) if(onodes.count(side->node(sn))) { found=true; break; } // If a new oface is found, include its nodes in onodes if(found) { for(unsigned int sn=0; sn<side->n_nodes(); sn++) onodes.insert(side->node(sn)); ofaces.insert(p); face_it++; // iteration is done here faces.erase(p); facesfound++; } else face_it++; // iteration is done here // If at least one new oface was found in this cycle, // do another search cycle. if(facesfound>0 && face_it == faces.end()) { facesfound = 0; face_it = faces.begin(); } } } #ifdef DEBUG if (be_verbose) libMesh::out << " found " << faces.size() << " inner and " << ofaces.size() << " outer boundary faces" << std::endl; #endif // When the user provided a non-null pointer to // inner_faces, that implies he wants to have // this std::set. For now, simply copy the data. if (inner_faces != NULL) *inner_faces = faces; // free memory, clear our local variable, no need // for it any more. faces.clear(); // outer_nodes maps onodes to their duplicates std::map<dof_id_type, Node *> outer_nodes; // We may need to pick our own object ids in parallel dof_id_type old_max_node_id = _mesh.max_node_id(); dof_id_type old_max_elem_id = _mesh.max_elem_id(); // for each boundary node, add an outer_node with // double distance from origin. std::set<dof_id_type>::iterator on_it = onodes.begin(); for( ; on_it != onodes.end(); ++on_it) { Point p = (Point(this->_mesh.point(*on_it)) * 2) - origin; if (_mesh.is_serial()) { // Add with a default id in serial outer_nodes[*on_it]=this->_mesh.add_point(p); } else { // Pick a unique id in parallel Node &bnode = _mesh.node(*on_it); dof_id_type new_id = bnode.id() + old_max_node_id; outer_nodes[*on_it] = this->_mesh.add_point(p, new_id, bnode.processor_id()); } } #ifdef DEBUG // for verbose, remember n_elem dof_id_type n_conventional_elem = this->_mesh.n_elem(); #endif // build Elems based on boundary side type std::set< std::pair<dof_id_type,unsigned int> >::iterator face_it = ofaces.begin(); for( ; face_it != ofaces.end(); ++face_it) { // Shortcut to the pair being iterated over std::pair<dof_id_type,unsigned int> p = *face_it; // build a full-ordered side element to get the base nodes AutoPtr<Elem> side(this->_mesh.elem(p.first)->build_side(p.second)); // create cell depending on side type, assign nodes, // use braces to force scope. bool is_higher_order_elem = false; { Elem* el; switch(side->type()) { // 3D infinite elements // TRIs case TRI3: el=new InfPrism6; break; case TRI6: el=new InfPrism12; is_higher_order_elem = true; break; // QUADs case QUAD4: el=new InfHex8; break; case QUAD8: el=new InfHex16; is_higher_order_elem = true; break; case QUAD9: el=new InfHex18; // the method of assigning nodes (which follows below) // omits in the case of QUAD9 the bubble node; therefore // we assign these first by hand here. el->set_node(16) = side->get_node(8); el->set_node(17) = outer_nodes[side->node(8)]; is_higher_order_elem=true; break; // 2D infinite elements case EDGE2: el=new InfQuad4; break; case EDGE3: el=new InfQuad6; el->set_node(4) = side->get_node(2); break; // 1D infinite elements not supported default: libMesh::out << "InfElemBuilder::build_inf_elem(Point, bool, bool, bool, bool): " << "invalid face element " << std::endl; continue; } // In parallel, assign unique ids to the new element if (!_mesh.is_serial()) { Elem *belem = _mesh.elem(p.first); el->processor_id() = belem->processor_id(); // We'd better not have elements with more than 6 sides el->set_id (belem->id() * 6 + p.second + old_max_elem_id); } // assign vertices to the new infinite element const unsigned int n_base_vertices = side->n_vertices(); for(unsigned int i=0; i<n_base_vertices; i++) { el->set_node(i ) = side->get_node(i); el->set_node(i+n_base_vertices) = outer_nodes[side->node(i)]; } // when this is a higher order element, // assign also the nodes in between if (is_higher_order_elem) { // n_safe_base_nodes is the number of nodes in \p side // that may be safely assigned using below for loop. // Actually, n_safe_base_nodes is _identical_ with el->n_vertices(), // since for QUAD9, the 9th node was already assigned above const unsigned int n_safe_base_nodes = el->n_vertices(); for(unsigned int i=n_base_vertices; i<n_safe_base_nodes; i++) { el->set_node(i+n_base_vertices) = side->get_node(i); el->set_node(i+n_safe_base_nodes) = outer_nodes[side->node(i)]; } } // add infinite element to mesh this->_mesh.add_elem(el); } // el goes out of scope } // for #ifdef DEBUG _mesh.libmesh_assert_valid_parallel_ids(); if (be_verbose) libMesh::out << " added " << this->_mesh.n_elem() - n_conventional_elem << " infinite elements and " << onodes.size() << " nodes to the mesh" << std::endl << std::endl; #endif STOP_LOG("build_inf_elem()", "InfElemBuilder"); }