void FeatureFloodCount::appendPeriodicNeighborNodes(FeatureData & data) const { if (_is_elemental) { for (auto entity : data._local_ids) { Elem * elem = _mesh.elemPtr(entity); for (unsigned int node_n = 0; node_n < elem->n_nodes(); node_n++) { auto iters = _periodic_node_map.equal_range(elem->node(node_n)); for (auto it = iters.first; it != iters.second; ++it) { data._periodic_nodes.insert(it->first); data._periodic_nodes.insert(it->second); } } } } else { for (auto entity : data._local_ids) { auto iters = _periodic_node_map.equal_range(entity); for (auto it = iters.first; it != iters.second; ++it) { data._periodic_nodes.insert(it->first); data._periodic_nodes.insert(it->second); } } } }
void GrainTracker::calculateBubbleVolumes() { Moose::perf_log.push("calculateBubbleVolumes()", "GrainTracker"); // The size of the bubble array will be sized to the max index of the unique grains map unsigned int max_id = _unique_grains.size() ? _unique_grains.rbegin()->first + 1: 0; _all_feature_volumes.resize(max_id, 0); const MeshBase::const_element_iterator el_end = _mesh.getMesh().active_local_elements_end(); for (MeshBase::const_element_iterator el = _mesh.getMesh().active_local_elements_begin(); el != el_end; ++el) { Elem * elem = *el; unsigned int elem_n_nodes = elem->n_nodes(); Real curr_volume = elem->volume(); for (std::map<unsigned int, MooseSharedPointer<FeatureData> >::iterator it = _unique_grains.begin(); it != _unique_grains.end(); ++it) { if (it->second->_status == INACTIVE) continue; if (_is_elemental) { dof_id_type elem_id = elem->id(); if (it->second->_local_ids.find(elem_id) != it->second->_local_ids.end()) { mooseAssert(it->first < _all_feature_volumes.size(), "_all_feature_volumes access out of bounds"); _all_feature_volumes[it->first] += curr_volume; break; } } else { // Count the number of nodes on this element which are flooded. unsigned int flooded_nodes = 0; for (unsigned int node = 0; node < elem_n_nodes; ++node) { dof_id_type node_id = elem->node(node); if (it->second->_local_ids.find(node_id) != it->second->_local_ids.end()) ++flooded_nodes; } // If a majority of the nodes for this element are flooded, // assign its volume to the current bubble_counter entry. if (flooded_nodes >= elem_n_nodes / 2) _all_feature_volumes[it->first] += curr_volume; } } } // do all the sums! _communicator.sum(_all_feature_volumes); Moose::perf_log.pop("calculateBubbleVolumes()", "GrainTracker"); }
void NodalFloodCount::calculateBubbleVolumes() { Moose::perf_log.push("calculateBubbleVolume()", "NodalFloodCount"); // Size our temporary data structure std::vector<std::vector<Real> > bubble_volumes(_maps_size); for (unsigned int map_num = 0; map_num < _maps_size; ++map_num) { bubble_volumes[map_num].resize(_bubble_sets[map_num].size()); } std::vector<unsigned int> flood_nodes(_maps_size); const MeshBase::const_element_iterator el_end = _mesh.getMesh().active_local_elements_end(); for (MeshBase::const_element_iterator el = _mesh.getMesh().active_local_elements_begin(); el != el_end; ++el) { Elem *elem = *el; unsigned int elem_n_nodes = elem->n_nodes(); Real curr_volume = elem->volume(); for (unsigned int map_num = 0; map_num < _maps_size; ++map_num) { unsigned int bubble_counter = 0; std::list<BubbleData>::const_iterator end = _bubble_sets[map_num].end(); for (std::list<BubbleData>::const_iterator bubble_it1 = _bubble_sets[map_num].begin(); bubble_it1 != end; ++bubble_it1) { unsigned int flooded_nodes = 0; for (unsigned int node = 0; node < elem_n_nodes; ++node) { unsigned int node_id = elem->node(node); if (bubble_it1->_nodes.find(node_id) != bubble_it1->_nodes.end()) ++flooded_nodes; } // Are a majority of the nodes flooded for this element? if (flooded_nodes >= elem_n_nodes / 2) bubble_volumes[map_num][bubble_counter] += curr_volume; ++bubble_counter; } } } // Stick all the partial bubble volumes in one long single vector to be gathered on the root processor for (unsigned int map_num = 0; map_num < _maps_size; ++map_num) _all_bubble_volumes.insert(_all_bubble_volumes.end(), bubble_volumes[map_num].begin(), bubble_volumes[map_num].end()); _communicator.sum(_all_bubble_volumes); //do all the sums! std::sort(_all_bubble_volumes.begin(), _all_bubble_volumes.end(), std::greater<Real>()); Moose::perf_log.pop("calculateBubbleVolume()", "NodalFloodCount"); }
void FeatureFloodCount::appendPeriodicNeighborNodes(BubbleData & data) const { // Using a typedef makes the code easier to understand and avoids repeating information. typedef std::multimap<dof_id_type, dof_id_type>::const_iterator IterType; if (_is_elemental) { for (std::set<dof_id_type>::iterator entity_it = data._entity_ids.begin(); entity_it != data._entity_ids.end(); ++entity_it) { Elem * elem = _mesh.elem(*entity_it); for (unsigned int node_n = 0; node_n < elem->n_nodes(); node_n++) { std::pair<IterType, IterType> iters = _periodic_node_map.equal_range(elem->node(node_n)); for (IterType it = iters.first; it != iters.second; ++it) { data._periodic_nodes.insert(it->first); data._periodic_nodes.insert(it->second); } } } } else { for (std::set<dof_id_type>::iterator entity_it = data._entity_ids.begin(); entity_it != data._entity_ids.end(); ++entity_it) { std::pair<IterType, IterType> iters = _periodic_node_map.equal_range(*entity_it); for (IterType it = iters.first; it != iters.second; ++it) { data._periodic_nodes.insert(it->first); data._periodic_nodes.insert(it->second); } } } }
void TetGenMeshInterface::triangulate_conformingDelaunayMesh_carvehole (const std::vector<Point>& holes, double quality_constraint, double volume_constraint) { // Before calling this function, the Mesh must contain a convex hull // of TRI3 elements which define the boundary. unsigned hull_integrity_check = check_hull_integrity(); // Possibly die if hull integrity check failed this->process_hull_integrity_result(hull_integrity_check); // class tetgen_wrapper allows library access on a basic level TetGenWrapper tetgen_wrapper; // Copy Mesh's node points into TetGen data structure this->fill_pointlist(tetgen_wrapper); // >>> fill input structure "tetgenio" with facet data: int facet_num = this->_mesh.n_elem(); // allocate memory in "tetgenio" structure: tetgen_wrapper.allocate_facetlist(facet_num, holes.size()); // Set up tetgen data structures with existing facet information // from the convex hull. { int insertnum = 0; MeshBase::element_iterator it = this->_mesh.elements_begin(); const MeshBase::element_iterator end = this->_mesh.elements_end(); for (; it != end ; ++it) { tetgen_wrapper.allocate_facet_polygonlist(insertnum, 1); tetgen_wrapper.allocate_polygon_vertexlist(insertnum, 0, 3); Elem* elem = *it; for (unsigned int j=0; j<elem->n_nodes(); ++j) { // We need to get the sequential index of elem->get_node(j), but // it should already be stored in _sequential_to_libmesh_node_map... unsigned libmesh_node_id = elem->node(j); // The libmesh node IDs may not be sequential, but can we assume // they are at least in order??? We will do so here. std::vector<unsigned>::iterator node_iter = Utility::binary_find(_sequential_to_libmesh_node_map.begin(), _sequential_to_libmesh_node_map.end(), libmesh_node_id); // Check to see if not found: this could also indicate the sequential // node map is not sorted... if (node_iter == _sequential_to_libmesh_node_map.end()) { libMesh::err << "Global node " << libmesh_node_id << " not found in sequential node map!" << std::endl; libmesh_error(); } std::vector<unsigned>::difference_type sequential_index = std::distance(_sequential_to_libmesh_node_map.begin(), node_iter); // Debugging: // libMesh::out << "libmesh_node_id=" << libmesh_node_id // << ", sequential_index=" << sequential_index // << std::endl; tetgen_wrapper.set_vertex(insertnum, // facet number 0, // polygon (always 0) j, // local vertex index in tetgen input sequential_index); } // Go to next facet in polygonlist insertnum++; } } // fill hole list (if there are holes): if (holes.size() > 0) { std::vector<Point>::const_iterator ihole; unsigned hole_index = 0; for (ihole=holes.begin(); ihole!=holes.end(); ++ihole) tetgen_wrapper.set_hole(hole_index++, (*ihole)(0), (*ihole)(1), (*ihole)(2)); } // Run TetGen triangulation method: // p = tetrahedralizes a piecewise linear complex (see definition in user manual) // Q = quiet, no terminal output // q = specify a minimum radius/edge ratio // a = tetrahedron volume constraint // assemble switches: std::ostringstream oss; // string holding switches oss << "pQ"; if (quality_constraint != 0) oss << "q" << std::fixed << quality_constraint; if (volume_constraint != 0) oss << "a" << std::fixed << volume_constraint; std::string params = oss.str(); tetgen_wrapper.set_switches(params); // TetGen switches: Piecewise linear complex, Quiet mode tetgen_wrapper.run_tetgen(); // => nodes: unsigned int old_nodesnum = this->_mesh.n_nodes(); REAL x=0., y=0., z=0.; const unsigned int num_nodes = tetgen_wrapper.get_numberofpoints(); // Debugging: // libMesh::out << "Original mesh had " << old_nodesnum << " nodes." << std::endl; // libMesh::out << "Reserving space for " << num_nodes << " total nodes." << std::endl; // Reserve space for additional nodes in the node map _sequential_to_libmesh_node_map.reserve(num_nodes); // Add additional nodes to the Mesh. // Original code had i<=num_nodes here (Note: the indexing is: // foo[3*i], [3*i+1], [3*i+2]) But according to the TetGen docs, "In // all cases, the first item in any array is stored starting at // index [0]." for (unsigned int i=old_nodesnum; i<num_nodes; i++) { // Fill in x, y, z values tetgen_wrapper.get_output_node(i, x,y,z); // Catch the node returned by add_point()... this will tell us the ID // assigned by the Mesh. Node* new_node = this->_mesh.add_point ( Point(x,y,z) ); // Store this new ID in our sequential-to-libmesh node mapping array _sequential_to_libmesh_node_map.push_back( new_node->id() ); } // Debugging: // std::copy(_sequential_to_libmesh_node_map.begin(), // _sequential_to_libmesh_node_map.end(), // std::ostream_iterator<unsigned>(std::cout, " ")); // std::cout << std::endl; // => tetrahedra: const unsigned int num_elements = tetgen_wrapper.get_numberoftetrahedra(); // Vector that temporarily holds the node labels defining element connectivity. unsigned int node_labels[4]; for (unsigned int i=0; i<num_elements; i++) { // TetGen only supports Tet4 elements. Elem* elem = new Tet4; // Fill up the the node_labels vector for (unsigned int j=0; j<elem->n_nodes(); j++) node_labels[j] = tetgen_wrapper.get_element_node(i,j); // Associate nodes with this element this->assign_nodes_to_elem(node_labels, elem); // Finally, add this element to the mesh this->_mesh.add_elem(elem); } // Delete original convex hull elements. Is there ever a case where // we should not do this? this->delete_2D_hull_elements(); }
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 VTKIO::cells_to_vtk() { const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkIdList> pts = vtkSmartPointer<vtkIdList>::New(); std::vector<int> types(mesh.n_active_local_elem()); unsigned active_element_counter = 0; vtkSmartPointer<vtkIntArray> elem_id = vtkSmartPointer<vtkIntArray>::New(); elem_id->SetName("libmesh_elem_id"); elem_id->SetNumberOfComponents(1); vtkSmartPointer<vtkIntArray> subdomain_id = vtkSmartPointer<vtkIntArray>::New(); subdomain_id->SetName("subdomain_id"); subdomain_id->SetNumberOfComponents(1); MeshBase::const_element_iterator it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end = mesh.active_local_elements_end(); for (; it != end; ++it, ++active_element_counter) { Elem *elem = *it; pts->SetNumberOfIds(elem->n_nodes()); // get the connectivity for this element std::vector<dof_id_type> conn; elem->connectivity(0, VTK, conn); for (unsigned int i=0; i<conn.size(); ++i) { // If the node ID is not found in the _local_node_map, we'll // add it to the _vtk_grid. NOTE[JWP]: none of the examples // I have actually enters this section of code... if (_local_node_map.find(conn[i]) == _local_node_map.end()) { dof_id_type global_node_id = elem->node(i); const Node* the_node = mesh.node_ptr(global_node_id); // Error checking... if (the_node == NULL) { libMesh::err << "Error getting pointer to node " << global_node_id << "!" << std::endl; libmesh_error(); } // InsertNextPoint accepts either a double or float array of length 3. Real pt[3] = {0., 0., 0.}; for (unsigned int d=0; d<LIBMESH_DIM; ++d) pt[d] = (*the_node)(d); // Insert the point into the _vtk_grid vtkIdType local = _vtk_grid->GetPoints()->InsertNextPoint(pt); // Update the _local_node_map with the ID returned by VTK _local_node_map[global_node_id] = local; } // Otherwise, the node ID was found in the _local_node_map, so // insert it into the vtkIdList. pts->InsertId(i, _local_node_map[conn[i]]); } vtkIdType vtkcellid = cells->InsertNextCell(pts); types[active_element_counter] = this->get_elem_type(elem->type()); elem_id->InsertTuple1(vtkcellid, elem->id()); subdomain_id->InsertTuple1(vtkcellid, elem->subdomain_id()); } // end loop over active elements _vtk_grid->SetCells(&types[0], cells); _vtk_grid->GetCellData()->AddArray(elem_id); _vtk_grid->GetCellData()->AddArray(subdomain_id); }
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 FeatureFloodCount::calculateBubbleVolumes() { Moose::perf_log.push("calculateBubbleVolume()", "FeatureFloodCount"); // Figure out which bubbles intersect the boundary if the user has enabled that capability. if (_compute_boundary_intersecting_volume) { // Create a std::set of node IDs which are on the boundary called all_boundary_node_ids. std::set<dof_id_type> all_boundary_node_ids; // Iterate over the boundary nodes, putting them into the std::set data structure MooseMesh::bnd_node_iterator boundary_nodes_it = _mesh.bndNodesBegin(), boundary_nodes_end = _mesh.bndNodesEnd(); for (; boundary_nodes_it != boundary_nodes_end; ++boundary_nodes_it) { BndNode * boundary_node = *boundary_nodes_it; all_boundary_node_ids.insert(boundary_node->_node->id()); } // For each of the _maps_size BubbleData lists, determine if the set // of nodes includes any boundary nodes. for (unsigned int map_num = 0; map_num < _maps_size; ++map_num) { std::list<BubbleData>::iterator bubble_it = _bubble_sets[map_num].begin(), bubble_end = _bubble_sets[map_num].end(); // Determine boundary intersection for each BubbleData object for (; bubble_it != bubble_end; ++bubble_it) bubble_it->_intersects_boundary = setsIntersect(all_boundary_node_ids.begin(), all_boundary_node_ids.end(), bubble_it->_entity_ids.begin(), bubble_it->_entity_ids.end()); } } // Size our temporary data structure std::vector<std::vector<Real> > bubble_volumes(_maps_size); for (unsigned int map_num = 0; map_num < _maps_size; ++map_num) bubble_volumes[map_num].resize(_bubble_sets[map_num].size()); // Clear pre-existing values and allocate space to store the volume // of the boundary-intersecting grains for each variable. _total_volume_intersecting_boundary.clear(); _total_volume_intersecting_boundary.resize(_maps_size); // Loop over the active local elements. For each variable, and for // each BubbleData object, check whether a majority of the element's // nodes belong to that Bubble, and if so assign the element's full // volume to that bubble. const MeshBase::const_element_iterator el_end = _mesh.getMesh().active_local_elements_end(); for (MeshBase::const_element_iterator el = _mesh.getMesh().active_local_elements_begin(); el != el_end; ++el) { Elem * elem = *el; unsigned int elem_n_nodes = elem->n_nodes(); Real curr_volume = elem->volume(); for (unsigned int map_num = 0; map_num < _maps_size; ++map_num) { std::list<BubbleData>::const_iterator bubble_it = _bubble_sets[map_num].begin(), bubble_end = _bubble_sets[map_num].end(); for (unsigned int bubble_counter = 0; bubble_it != bubble_end; ++bubble_it, ++bubble_counter) { // Count the number of nodes on this element which are flooded. unsigned int flooded_nodes = 0; for (unsigned int node = 0; node < elem_n_nodes; ++node) { dof_id_type node_id = elem->node(node); if (bubble_it->_entity_ids.find(node_id) != bubble_it->_entity_ids.end()) ++flooded_nodes; } // If a majority of the nodes for this element are flooded, // assign its volume to the current bubble_counter entry. if (flooded_nodes >= elem_n_nodes / 2) { bubble_volumes[map_num][bubble_counter] += curr_volume; // If the current bubble also intersects the boundary, also // accumlate the volume into the total volume of bubbles // which intersect the boundary. if (bubble_it->_intersects_boundary) _total_volume_intersecting_boundary[map_num] += curr_volume; } } } } // If we're calculating boundary-intersecting volumes, we have to normalize it by the // volume of the entire domain. if (_compute_boundary_intersecting_volume) { // Compute the total area using a bounding box. FIXME: this // assumes the domain is rectangular and 2D, and is probably a // little expensive so we should only do it once if possible. MeshTools::BoundingBox bbox = MeshTools::bounding_box(_mesh); Real total_volume = (bbox.max()(0)-bbox.min()(0))*(bbox.max()(1)-bbox.min()(1)); // Sum up the partial boundary grain volume contributions from all processors _communicator.sum(_total_volume_intersecting_boundary); // Scale the boundary intersecting grain volumes by the total domain volume for (unsigned int i = 0; i<_total_volume_intersecting_boundary.size(); ++i) _total_volume_intersecting_boundary[i] /= total_volume; } // Stick all the partial bubble volumes in one long single vector to be gathered on the root processor for (unsigned int map_num = 0; map_num < _maps_size; ++map_num) _all_bubble_volumes.insert(_all_bubble_volumes.end(), bubble_volumes[map_num].begin(), bubble_volumes[map_num].end()); // do all the sums! _communicator.sum(_all_bubble_volumes); std::sort(_all_bubble_volumes.begin(), _all_bubble_volumes.end(), std::greater<Real>()); Moose::perf_log.pop("calculateBubbleVolume()", "FeatureFloodCount"); }
//----------------------------------------------------------------- // Mesh refinement methods bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch) { // This function must be run on all processors at once parallel_only(); bool flags_changed = false; // Vector holding the maximum element level that touches a node. std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0); std::vector<unsigned char> max_p_level_at_node (_mesh.n_nodes(), 0); // Loop over all the active elements & fill the vector { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; const unsigned char elem_level = elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0); const unsigned char elem_p_level = elem->p_level() + ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0); // Set the max_level at each node for (unsigned int n=0; n<elem->n_nodes(); n++) { const unsigned int node_number = elem->node(n); libmesh_assert_less (node_number, max_level_at_node.size()); max_level_at_node[node_number] = std::max (max_level_at_node[node_number], elem_level); max_p_level_at_node[node_number] = std::max (max_p_level_at_node[node_number], elem_p_level); } } } // Now loop over the active elements and flag the elements // who violate the requested level mismatch { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; const unsigned int elem_level = elem->level(); const unsigned int elem_p_level = elem->p_level(); // Skip the element if it is already fully flagged if (elem->refinement_flag() == Elem::REFINE && elem->p_refinement_flag() == Elem::REFINE) continue; // Loop over the nodes, check for possible mismatch for (unsigned int n=0; n<elem->n_nodes(); n++) { const unsigned int node_number = elem->node(n); // Flag the element for refinement if it violates // the requested level mismatch if ( (elem_level + max_mismatch) < max_level_at_node[node_number] && elem->refinement_flag() != Elem::REFINE) { elem->set_refinement_flag (Elem::REFINE); flags_changed = true; } if ( (elem_p_level + max_mismatch) < max_p_level_at_node[node_number] && elem->p_refinement_flag() != Elem::REFINE) { elem->set_p_refinement_flag (Elem::REFINE); flags_changed = true; } } } } // If flags changed on any processor then they changed globally CommWorld.max(flags_changed); return flags_changed; }
void MeshBase::detect_interior_parents() { // This requires an inspection on every processor parallel_object_only(); // Check if the mesh contains mixed dimensions. If so, then set interior parents, otherwise return. if (this->elem_dimensions().size() == 1) return; //This map will be used to set interior parents LIBMESH_BEST_UNORDERED_MAP<dof_id_type, std::vector<dof_id_type> > node_to_elem; const_element_iterator el = this->active_elements_begin(); const_element_iterator end = this->active_elements_end(); for (; el!=end; ++el) { const Elem * elem = *el; // Populating the node_to_elem map, same as MeshTools::build_nodes_to_elem_map for (unsigned int n=0; n<elem->n_vertices(); n++) { libmesh_assert_less (elem->id(), this->max_elem_id()); node_to_elem[elem->node(n)].push_back(elem->id()); } } // Automatically set interior parents el = this->elements_begin(); for (; el!=end; ++el) { Elem * element = *el; // Ignore an 3D element or an element that already has an interior parent if (element->dim()>=LIBMESH_DIM || element->interior_parent()) continue; // Start by generating a SET of elements that are dim+1 to the current // element at each vertex of the current element, thus ignoring interior nodes. // If one of the SET of elements is empty, then we will not have an interior parent // since an interior parent must be connected to all vertices of the current element std::vector< std::set<dof_id_type> > neighbors( element->n_vertices() ); bool found_interior_parents = false; for (dof_id_type n=0; n < element->n_vertices(); n++) { std::vector<dof_id_type> & element_ids = node_to_elem[element->node(n)]; for (std::vector<dof_id_type>::iterator e_it = element_ids.begin(); e_it != element_ids.end(); e_it++) { dof_id_type eid = *e_it; if (this->elem(eid)->dim() == element->dim()+1) neighbors[n].insert(eid); } if (neighbors[n].size()>0) { found_interior_parents = true; } else { // We have found an empty set, no reason to continue // Ensure we set this flag to false before the break since it could have // been set to true for previous vertex found_interior_parents = false; break; } } // If we have successfully generated a set of elements for each vertex, we will compare // the set for vertex 0 will the sets for the vertices until we find a id that exists in // all sets. If found, this is our an interior parent id. The interior parent id found // will be the lowest element id if there is potential for multiple interior parents. if (found_interior_parents) { std::set<dof_id_type> & neighbors_0 = neighbors[0]; for (std::set<dof_id_type>::iterator e_it = neighbors_0.begin(); e_it != neighbors_0.end(); e_it++) { found_interior_parents=false; dof_id_type interior_parent_id = *e_it; for (dof_id_type n=1; n < element->n_vertices(); n++) { if (neighbors[n].find(interior_parent_id)!=neighbors[n].end()) { found_interior_parents=true; } else { found_interior_parents=false; break; } } if (found_interior_parents) { element->set_interior_parent(this->elem(interior_parent_id)); break; } } } } }
//----------------------------------------------------------------- // Mesh refinement methods bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch) { // This function must be run on all processors at once parallel_object_only(); bool flags_changed = false; // Vector holding the maximum element level that touches a node. std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0); std::vector<unsigned char> max_p_level_at_node (_mesh.n_nodes(), 0); // Loop over all the active elements & fill the vector { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; const unsigned char elem_level = cast_int<unsigned char>(elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0)); const unsigned char elem_p_level = cast_int<unsigned char>(elem->p_level() + ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0)); // Set the max_level at each node for (unsigned int n=0; n<elem->n_nodes(); n++) { const dof_id_type node_number = elem->node(n); libmesh_assert_less (node_number, max_level_at_node.size()); max_level_at_node[node_number] = std::max (max_level_at_node[node_number], elem_level); max_p_level_at_node[node_number] = std::max (max_p_level_at_node[node_number], elem_p_level); } } } // Now loop over the active elements and flag the elements // who violate the requested level mismatch. Alternatively, if // _enforce_mismatch_limit_prior_to_refinement is true, swap refinement flags // accordingly. { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; const unsigned int elem_level = elem->level(); const unsigned int elem_p_level = elem->p_level(); // Skip the element if it is already fully flagged // unless we are enforcing mismatch prior to refienemnt and may need to // remove the refinement flag(s) if (elem->refinement_flag() == Elem::REFINE && elem->p_refinement_flag() == Elem::REFINE && !_enforce_mismatch_limit_prior_to_refinement) continue; // Loop over the nodes, check for possible mismatch for (unsigned int n=0; n<elem->n_nodes(); n++) { const dof_id_type node_number = elem->node(n); // Flag the element for refinement if it violates // the requested level mismatch if ((elem_level + max_mismatch) < max_level_at_node[node_number] && elem->refinement_flag() != Elem::REFINE) { elem->set_refinement_flag (Elem::REFINE); flags_changed = true; } if ((elem_p_level + max_mismatch) < max_p_level_at_node[node_number] && elem->p_refinement_flag() != Elem::REFINE) { elem->set_p_refinement_flag (Elem::REFINE); flags_changed = true; } // Possibly enforce limit mismatch prior to refinement flags_changed |= this->enforce_mismatch_limit_prior_to_refinement(elem, POINT, max_mismatch); } } } // If flags changed on any processor then they changed globally this->comm().max(flags_changed); return flags_changed; }