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) ? NULL : mesh.elem(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)); }
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 FeatureData lists, determine if the set // of nodes includes any boundary nodes. for (auto map_num = decltype(_maps_size)(0); map_num < _maps_size; ++map_num) // Determine boundary intersection for each FeatureData object for (auto & feature : _feature_sets[map_num]) feature._intersects_boundary = setsIntersect(all_boundary_node_ids.begin(), all_boundary_node_ids.end(), feature._local_ids.begin(), feature._local_ids.end()); } // Size our temporary data structure std::vector<std::vector<Real> > bubble_volumes(_maps_size); for (auto map_num = decltype(_maps_size)(0); map_num < _maps_size; ++map_num) bubble_volumes[map_num].resize(_feature_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 FeatureData 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; auto elem_n_nodes = elem->n_nodes(); auto curr_volume = elem->volume(); for (auto map_num = decltype(_maps_size)(0); map_num < _maps_size; ++map_num) { auto bubble_it = _feature_sets[map_num].cbegin(); auto bubble_end = _feature_sets[map_num].cend(); 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 (auto node = decltype(elem_n_nodes)(0); node < elem_n_nodes; ++node) { auto node_id = elem->node(node); if ((*bubble_it)._local_ids.find(node_id) != (*bubble_it)._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) { 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. auto bbox = MeshTools::bounding_box(_mesh); auto 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 (auto & total_volume_intersecting_boundary_item : _total_volume_intersecting_boundary) total_volume_intersecting_boundary_item /= total_volume; } // Stick all the partial bubble volumes in one long single vector to be gathered on the root processor for (auto map_num = decltype(_maps_size)(0); map_num < _maps_size; ++map_num) _all_feature_volumes.insert(_all_feature_volumes.end(), bubble_volumes[map_num].begin(), bubble_volumes[map_num].end()); // do all the sums! _communicator.sum(_all_feature_volumes); std::sort(_all_feature_volumes.begin(), _all_feature_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; }
UniquePtr<Elem> InfHex18::build_side (const unsigned int i, bool proxy) const { libmesh_assert_less (i, this->n_sides()); if (proxy) { switch (i) { // base case 0: return UniquePtr<Elem>(new Side<Quad9,InfHex18>(this,i)); // ifem sides case 1: case 2: case 3: case 4: return UniquePtr<Elem>(new Side<InfQuad6,InfHex18>(this,i)); default: libmesh_error_msg("Invalid side i = " << i); } } else { // Create NULL pointer to be initialized, returned later. Elem* face = NULL; // Think of a unit cube: (-1,1) x (-1,1) x (1,1) switch (i) { // the base face case 0: { face = new Quad9; break; } // connecting to another infinite element case 1: case 2: case 3: case 4: { face = new InfQuad6; break; } default: libmesh_error_msg("Invalid side i = " << i); } face->subdomain_id() = this->subdomain_id(); // Set the nodes for (unsigned n=0; n<face->n_nodes(); ++n) face->set_node(n) = this->get_node(InfHex18::side_nodes_map[i][n]); return UniquePtr<Elem>(face); } libmesh_error_msg("We'll never get here!"); return UniquePtr<Elem>(); }
void FeatureFloodCount::FeatureData::updateBBoxExtremes(MeshTools::BoundingBox & bbox, const Elem & elem) { for (auto node_n = decltype(elem.n_nodes())(0); node_n < elem.n_nodes(); ++node_n) updateBBoxExtremes(bbox, *(elem.get_node(node_n))); }
void Elem::coarsen() { libmesh_assert_equal_to (this->refinement_flag(), Elem::COARSEN_INACTIVE); libmesh_assert (!this->active()); // We no longer delete children until MeshRefinement::contract() // delete [] _children; // _children = NULL; unsigned int parent_p_level = 0; // re-compute hanging node nodal locations for (unsigned int c=0; c<this->n_children(); c++) { Elem *mychild = this->child(c); if (mychild == remote_elem) continue; for (unsigned int nc=0; nc<mychild->n_nodes(); nc++) { Point new_pos; bool calculated_new_pos = false; for (unsigned int n=0; n<this->n_nodes(); n++) { // The value from the embedding matrix const float em_val = this->embedding_matrix(c,nc,n); // The node location is somewhere between existing vertices if ((em_val != 0.) && (em_val != 1.)) { new_pos.add_scaled (this->point(n), em_val); calculated_new_pos = true; } } if(calculated_new_pos) { //Move the existing node back into it's original location for(unsigned int i=0; i<LIBMESH_DIM; i++) { Point & child_node = *(mychild->get_node(nc)); child_node(i)=new_pos(i); } } } } for (unsigned int c=0; c<this->n_children(); c++) { Elem *mychild = this->child(c); if (mychild == remote_elem) continue; libmesh_assert_equal_to (mychild->refinement_flag(), Elem::COARSEN); mychild->set_refinement_flag(Elem::INACTIVE); if (mychild->p_level() > parent_p_level) parent_p_level = mychild->p_level(); } this->set_refinement_flag(Elem::JUST_COARSENED); this->set_p_level(parent_p_level); libmesh_assert (this->active()); }
void unpack(std::vector<int>::const_iterator in, Elem** out, MeshBase* mesh) { #ifndef NDEBUG const std::vector<int>::const_iterator original_in = in; const int incoming_header = *in++; libmesh_assert (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(rflag >= 0); libmesh_assert(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(pflag >= 0); libmesh_assert(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(typeint >= 0); libmesh_assert(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 unsigned int processor_id = static_cast<unsigned int>(*in++); libmesh_assert (processor_id < libMesh::n_processors() || processor_id == DofObject::invalid_processor_id); // int 6: subdomain id const unsigned int subdomain_id = static_cast<unsigned int>(*in++); // int 7: dof object id const unsigned int id = static_cast<unsigned int>(*in++); libmesh_assert (id != DofObject::invalid_id); #ifdef LIBMESH_ENABLE_AMR // int 8: parent dof object id const unsigned int parent_id = static_cast<unsigned int>(*in++); libmesh_assert (level == 0 || parent_id != DofObject::invalid_id); libmesh_assert (level != 0 || parent_id == DofObject::invalid_id); // int 9: 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(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 (elem->level() == level); libmesh_assert (elem->id() == id); libmesh_assert (elem->processor_id() == processor_id); libmesh_assert (elem->subdomain_id() == subdomain_id); libmesh_assert (elem->type() == type); libmesh_assert (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<unsigned int>(*in++)); #else in += n_nodes; #endif #ifdef LIBMESH_ENABLE_AMR libmesh_assert (elem->p_level() == p_level); libmesh_assert (elem->refinement_flag() == refinement_flag); libmesh_assert (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 unsigned int neighbor_id = static_cast<unsigned int>(*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) == NULL); 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) != NULL); 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(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 (parent_id == static_cast<unsigned int>(-1)); #else // No non-level-0 elements without AMR libmesh_assert (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 (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 (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; // Assign the connectivity libmesh_assert (elem->n_nodes() == n_nodes); for (unsigned int n=0; n != n_nodes; n++) elem->set_node(n) = mesh->node_ptr (static_cast<unsigned int>(*in++)); for (unsigned int n=0; n<elem->n_neighbors(); n++) { const unsigned int neighbor_id = static_cast<unsigned int>(*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 (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; }
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 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 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 }
UniquePtr<Elem> InfPrism6::build_side (const unsigned int i, bool proxy) const { libmesh_assert_less (i, this->n_sides()); if (proxy) { switch (i) { // base case 0: return UniquePtr<Elem>(new Side<Tri3,InfPrism6>(this,i)); // ifem sides case 1: case 2: case 3: return UniquePtr<Elem>(new Side<InfQuad4,InfPrism6>(this,i)); default: libmesh_error_msg("Invalid side i = " << i); } } else { // Create NULL pointer to be initialized, returned later. Elem * face = NULL; switch (i) { case 0: // the triangular face at z=-1, base face { face = new Tri3; break; } case 1: // the quad face at y=0 case 2: // the other quad face case 3: // the quad face at x=0 { face = new InfQuad4; break; } default: libmesh_error_msg("Invalid side i = " << i); } face->subdomain_id() = this->subdomain_id(); // Set the nodes for (unsigned n=0; n<face->n_nodes(); ++n) face->set_node(n) = this->get_node(InfPrism6::side_nodes_map[i][n]); return UniquePtr<Elem>(face); } libmesh_error_msg("We'll never get here!"); return UniquePtr<Elem>(); }
void Partitioner::set_node_processor_ids(MeshBase & mesh) { START_LOG("set_node_processor_ids()","Partitioner"); // This function must be run on all processors at once libmesh_parallel_only(mesh.comm()); // If we have any unpartitioned elements at this // stage there is a problem libmesh_assert (MeshTools::n_elem(mesh.unpartitioned_elements_begin(), mesh.unpartitioned_elements_end()) == 0); // const dof_id_type orig_n_local_nodes = mesh.n_local_nodes(); // libMesh::err << "[" << mesh.processor_id() << "]: orig_n_local_nodes=" // << orig_n_local_nodes << std::endl; // Build up request sets. Each node is currently owned by a processor because // it is connected to an element owned by that processor. However, during the // repartitioning phase that element may have been assigned a new processor id, but // it is still resident on the original processor. We need to know where to look // for new ids before assigning new ids, otherwise we may be asking the wrong processors // for the wrong information. // // The only remaining issue is what to do with unpartitioned nodes. Since they are required // to live on all processors we can simply rely on ourselves to number them properly. std::vector<std::vector<dof_id_type> > requested_node_ids(mesh.n_processors()); // Loop over all the nodes, count the ones on each processor. We can skip ourself std::vector<dof_id_type> ghost_nodes_from_proc(mesh.n_processors(), 0); MeshBase::node_iterator node_it = mesh.nodes_begin(); const MeshBase::node_iterator node_end = mesh.nodes_end(); for (; node_it != node_end; ++node_it) { Node * node = *node_it; libmesh_assert(node); const processor_id_type current_pid = node->processor_id(); if (current_pid != mesh.processor_id() && current_pid != DofObject::invalid_processor_id) { libmesh_assert_less (current_pid, ghost_nodes_from_proc.size()); ghost_nodes_from_proc[current_pid]++; } } // We know how many objects live on each processor, so reserve() // space for each. for (processor_id_type pid=0; pid != mesh.n_processors(); ++pid) requested_node_ids[pid].reserve(ghost_nodes_from_proc[pid]); // We need to get the new pid for each node from the processor // which *currently* owns the node. We can safely skip ourself for (node_it = mesh.nodes_begin(); node_it != node_end; ++node_it) { Node * node = *node_it; libmesh_assert(node); const processor_id_type current_pid = node->processor_id(); if (current_pid != mesh.processor_id() && current_pid != DofObject::invalid_processor_id) { libmesh_assert_less (current_pid, requested_node_ids.size()); libmesh_assert_less (requested_node_ids[current_pid].size(), ghost_nodes_from_proc[current_pid]); requested_node_ids[current_pid].push_back(node->id()); } // Unset any previously-set node processor ids node->invalidate_processor_id(); } // Loop over all the active elements 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; libmesh_assert(elem); libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id); // For each node, set the processor ID to the min of // its current value and this Element's processor id. // // TODO: we would probably get better parallel partitioning if // we did something like "min for even numbered nodes, max for // odd numbered". We'd need to be careful about how that would // affect solution ordering for I/O, though. for (unsigned int n=0; n<elem->n_nodes(); ++n) elem->get_node(n)->processor_id() = std::min(elem->get_node(n)->processor_id(), elem->processor_id()); } // And loop over the subactive elements, but don't reassign // nodes that are already active on another processor. MeshBase::element_iterator sub_it = mesh.subactive_elements_begin(); const MeshBase::element_iterator sub_end = mesh.subactive_elements_end(); for ( ; sub_it != sub_end; ++sub_it) { Elem * elem = *sub_it; libmesh_assert(elem); libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id); for (unsigned int n=0; n<elem->n_nodes(); ++n) if (elem->get_node(n)->processor_id() == DofObject::invalid_processor_id) elem->get_node(n)->processor_id() = elem->processor_id(); } // Same for the inactive elements -- we will have already gotten most of these // nodes, *except* for the case of a parent with a subset of children which are // ghost elements. In that case some of the parent nodes will not have been // properly handled yet MeshBase::element_iterator not_it = mesh.not_active_elements_begin(); const MeshBase::element_iterator not_end = mesh.not_active_elements_end(); for ( ; not_it != not_end; ++not_it) { Elem * elem = *not_it; libmesh_assert(elem); libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id); for (unsigned int n=0; n<elem->n_nodes(); ++n) if (elem->get_node(n)->processor_id() == DofObject::invalid_processor_id) elem->get_node(n)->processor_id() = elem->processor_id(); } // We can't assert that all nodes are connected to elements, because // a ParallelMesh with NodeConstraints might have pulled in some // remote nodes solely for evaluating those constraints. // MeshTools::libmesh_assert_connected_nodes(mesh); // For such nodes, we'll do a sanity check later when making sure // that we successfully reset their processor ids to something // valid. // Next set node ids from other processors, excluding self for (processor_id_type p=1; p != mesh.n_processors(); ++p) { // Trade my requests with processor procup and procdown processor_id_type procup = cast_int<processor_id_type> ((mesh.processor_id() + p) % mesh.n_processors()); processor_id_type procdown = cast_int<processor_id_type> ((mesh.n_processors() + mesh.processor_id() - p) % mesh.n_processors()); std::vector<dof_id_type> request_to_fill; mesh.comm().send_receive(procup, requested_node_ids[procup], procdown, request_to_fill); // Fill those requests in-place for (std::size_t i=0; i != request_to_fill.size(); ++i) { Node * node = mesh.node_ptr(request_to_fill[i]); libmesh_assert(node); const processor_id_type new_pid = node->processor_id(); // We may have an invalid processor_id() on nodes that have been // "detatched" from coarsened-away elements but that have not yet // themselves been removed. // libmesh_assert_not_equal_to (new_pid, DofObject::invalid_processor_id); // libmesh_assert_less (new_pid, mesh.n_partitions()); // this is the correct test -- request_to_fill[i] = new_pid; // the number of partitions may } // not equal the number of processors // Trade back the results std::vector<dof_id_type> filled_request; mesh.comm().send_receive(procdown, request_to_fill, procup, filled_request); libmesh_assert_equal_to (filled_request.size(), requested_node_ids[procup].size()); // And copy the id changes we've now been informed of for (std::size_t i=0; i != filled_request.size(); ++i) { Node * node = mesh.node_ptr(requested_node_ids[procup][i]); libmesh_assert(node); // this is the correct test -- the number of partitions may // not equal the number of processors // But: we may have an invalid processor_id() on nodes that // have been "detatched" from coarsened-away elements but // that have not yet themselves been removed. // libmesh_assert_less (filled_request[i], mesh.n_partitions()); node->processor_id(cast_int<processor_id_type>(filled_request[i])); } } #ifdef DEBUG MeshTools::libmesh_assert_valid_procids<Node>(mesh); #endif STOP_LOG("set_node_processor_ids()","Partitioner"); }
// Begin the main program. int main (int argc, char ** argv) { // Initialize libMesh and any dependent libaries, like in example 2. LibMeshInit init (argc, argv); // Only our PETSc interface currently supports solves restricted to // subdomains libmesh_example_requires(libMesh::default_solver_package() == PETSC_SOLVERS, "--enable-petsc"); // Skip adaptive examples on a non-adaptive libMesh build #ifndef LIBMESH_ENABLE_AMR libmesh_example_requires(false, "--enable-amr"); #else // Declare a performance log for the main program // PerfLog perf_main("Main Program"); // Create a GetPot object to parse the command line GetPot command_line (argc, argv); // Check for proper calling arguments. if (argc < 3) { // This handy function will print the file name, line number, // specified message, and then throw an exception. libmesh_error_msg("Usage:\n" << "\t " << argv[0] << " -d 2(3)" << " -n 15"); } // Brief message to the user regarding the program name // and command line arguments. else { libMesh::out << "Running " << argv[0]; for (int i=1; i<argc; i++) libMesh::out << " " << argv[i]; libMesh::out << std::endl << std::endl; } // Read problem dimension from command line. Use int // instead of unsigned since the GetPot overload is ambiguous // otherwise. int dim = 2; if (command_line.search(1, "-d")) dim = command_line.next(dim); // Skip higher-dimensional examples on a lower-dimensional libMesh build libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support"); // Create a mesh with user-defined dimension. // Read number of elements from command line int ps = 15; if (command_line.search(1, "-n")) ps = command_line.next(ps); // Read FE order from command line std::string order = "FIRST"; if (command_line.search(2, "-Order", "-o")) order = command_line.next(order); // Read FE Family from command line std::string family = "LAGRANGE"; if (command_line.search(2, "-FEFamily", "-f")) family = command_line.next(family); // Cannot use discontinuous basis. if ((family == "MONOMIAL") || (family == "XYZ")) libmesh_error_msg("This example requires a C^0 (or higher) FE basis."); // Create a mesh, with dimension to be overridden later, on the // default MPI communicator. Mesh mesh(init.comm()); // Use the MeshTools::Generation mesh generator to create a uniform // grid on the square [-1,1]^D. We instruct the mesh generator // to build a mesh of 8x8 \p Quad9 elements in 2D, or \p Hex27 // elements in 3D. Building these higher-order elements allows // us to use higher-order approximation, as in example 3. Real halfwidth = dim > 1 ? 1. : 0.; Real halfheight = dim > 2 ? 1. : 0.; if ((family == "LAGRANGE") && (order == "FIRST")) { // No reason to use high-order geometric elements if we are // solving with low-order finite elements. MeshTools::Generation::build_cube (mesh, ps, (dim>1) ? ps : 0, (dim>2) ? ps : 0, -1., 1., -halfwidth, halfwidth, -halfheight, halfheight, (dim==1) ? EDGE2 : ((dim == 2) ? QUAD4 : HEX8)); } else { MeshTools::Generation::build_cube (mesh, ps, (dim>1) ? ps : 0, (dim>2) ? ps : 0, -1., 1., -halfwidth, halfwidth, -halfheight, halfheight, (dim==1) ? EDGE3 : ((dim == 2) ? QUAD9 : HEX27)); } // To demonstate solving on a subdomain, we will solve only on the // interior of a circle (ball in 3d) with radius 0.8. So show that // this also works well on locally refined meshes, we refine once // all elements that are located on the boundary of this circle (or // ball). { // A MeshRefinement object is needed to refine meshes. MeshRefinement meshRefinement(mesh); // Loop over all elements. MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; if (elem->active()) { // Just check whether the current element has at least one // node inside and one node outside the circle. bool node_in = false; bool node_out = false; for (unsigned int i=0; i<elem->n_nodes(); i++) { double d = elem->point(i).size(); if (d<0.8) { node_in = true; } else { node_out = true; } } if (node_in && node_out) { elem->set_refinement_flag(Elem::REFINE); } else { elem->set_refinement_flag(Elem::DO_NOTHING); } } else { elem->set_refinement_flag(Elem::INACTIVE); } } // Now actually refine. meshRefinement.refine_elements(); } // Print information about the mesh to the screen. mesh.print_info(); // Now set the subdomain_id of all elements whose centroid is inside // the circle to 1. { // Loop over all elements. MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; double d = elem->centroid().size(); if (d<0.8) { elem->subdomain_id() = 1; } } } // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system and its variables. // Create a system named "Poisson" LinearImplicitSystem & system = equation_systems.add_system<LinearImplicitSystem> ("Poisson"); // Add the variable "u" to "Poisson". "u" // will be approximated using second-order approximation. system.add_variable("u", Utility::string_to_enum<Order> (order), Utility::string_to_enum<FEFamily>(family)); // Give the system a pointer to the matrix assembly // function. system.attach_assemble_function (assemble_poisson); // Initialize the data structures for the equation system. equation_systems.init(); // Print information about the system to the screen. equation_systems.print_info(); mesh.print_info(); // Restrict solves to those elements that have subdomain_id set to 1. std::set<subdomain_id_type> id_list; id_list.insert(1); SystemSubsetBySubdomain::SubdomainSelectionByList selection(id_list); SystemSubsetBySubdomain subset(system, selection); system.restrict_solve_to(&subset, SUBSET_ZERO); // Note that using \p SUBSET_ZERO will cause all dofs outside the // subdomain to be cleared. This will, however, cause some hanging // nodes outside the subdomain to have inconsistent values. // Solve the system "Poisson", just like example 2. equation_systems.get_system("Poisson").solve(); // After solving the system write the solution // to a GMV-formatted plot file. if (dim == 1) { GnuPlotIO plot(mesh, "Subdomains Example 1, 1D", GnuPlotIO::GRID_ON); plot.write_equation_systems("gnuplot_script", equation_systems); } else { GMVIO (mesh).write_equation_systems ((dim == 3) ? "out_3.gmv" : "out_2.gmv", equation_systems); #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO (mesh).write_equation_systems ((dim == 3) ? "out_3.e" : "out_2.e", equation_systems); #endif // #ifdef LIBMESH_HAVE_EXODUS_API } #endif // #ifndef LIBMESH_ENABLE_AMR // All done. return 0; }
void GrainTracker::swapSolutionValues(std::map<unsigned int, UniqueGrain *>::iterator & grain_it1, std::map<unsigned int, UniqueGrain *>::iterator & grain_it2, unsigned int attempt_number) { NumericVector<Real> & solution = _nl.solution(); NumericVector<Real> & solution_old = _nl.solutionOld(); NumericVector<Real> & solution_older = _nl.solutionOlder(); unsigned int curr_var_idx = grain_it1->second->variable_idx; /** * We have two grains that are getting close represented by the same order parameter. * We need to map to the variable whose closest grain to this one is furthest away by sphere to sphere distance. */ std::vector<Real> min_distances(_vars.size(), std::numeric_limits<Real>::max()); // Make sure that we don't attempt to remap to the same variable min_distances[curr_var_idx] = -std::numeric_limits<Real>::max(); for (std::map<unsigned int, UniqueGrain *>::iterator grain_it3 = _unique_grains.begin(); grain_it3 != _unique_grains.end(); ++grain_it3) { if (grain_it3->second->status == INACTIVE || grain_it3->second->variable_idx == curr_var_idx) continue; unsigned int potential_var_idx = grain_it3->second->variable_idx; Real curr_bounding_sphere_diff = boundingRegionDistance(grain_it1->second->sphere_ptrs, grain_it3->second->sphere_ptrs, false); if (curr_bounding_sphere_diff < min_distances[potential_var_idx]) min_distances[potential_var_idx] = curr_bounding_sphere_diff; } /** * We have a vector of the distances to the closest grains represented by each of our variables. We just need to pick * a suitable grain to replace with. We will start with the maximum of this this list: (max of the mins), but will settle * for next to largest and so forth as we make more attempts at remapping grains. This is a graph coloring problem so * more work will be required to optimize this process. * Note: We don't have an explicit check here to avoid remapping a variable to itself. This is unecessary since the * min_distance of a variable is explicitly set up above. */ unsigned int nth_largest_idx = min_distances.size() - attempt_number - 1; // nth element destroys the original array so we need to copy it first std::vector<Real> min_distances_copy(min_distances); std::nth_element(min_distances_copy.begin(), min_distances_copy.end()+nth_largest_idx, min_distances_copy.end()); // Now find the location of the nth element in the original vector unsigned int new_variable_idx = std::distance(min_distances.begin(), std::find(min_distances.begin(), min_distances.end(), min_distances_copy[nth_largest_idx])); Moose::out << COLOR_YELLOW << "Grain #: " << grain_it1->first << " intersects Grain #: " << grain_it2->first << " (variable index: " << grain_it1->second->variable_idx << ")\n" << COLOR_DEFAULT; if (min_distances[new_variable_idx] < 0) { Moose::out << COLOR_YELLOW << "*****************************************************************************************************\n" << "Warning: No suitable variable found for remapping. Will attempt to remap in next loop if necessary...\n" << "*****************************************************************************************************\n" << COLOR_DEFAULT; return; } Moose::out << COLOR_GREEN << "Remapping to: " << new_variable_idx << " whose closest grain is at a distance of " << min_distances[new_variable_idx] << "\n" << COLOR_DEFAULT; MeshBase & mesh = _mesh.getMesh(); // Remap the grain std::set<Node *> updated_nodes_tmp; // Used only in the elemental case for (std::set<dof_id_type>::const_iterator entity_it = grain_it1->second->entities_ptr->begin(); entity_it != grain_it1->second->entities_ptr->end(); ++entity_it) { if (_is_elemental) { Elem *elem = mesh.query_elem(*entity_it); if (!elem) continue; for (unsigned int i=0; i < elem->n_nodes(); ++i) { Node *curr_node = elem->get_node(i); if (updated_nodes_tmp.find(curr_node) == updated_nodes_tmp.end()) { updated_nodes_tmp.insert(curr_node); // cache this node so we don't attempt to remap it again within this loop swapSolutionValuesHelper(curr_node, curr_var_idx, new_variable_idx, solution, solution_old, solution_older); } } } else swapSolutionValuesHelper(mesh.query_node_ptr(*entity_it), curr_var_idx, new_variable_idx, solution, solution_old, solution_older); } // Update the variable index in the unique grain datastructure grain_it1->second->variable_idx = new_variable_idx; // Close all of the solution vectors solution.close(); solution_old.close(); solution_older.close(); _fe_problem.getNonlinearSystem().sys().update(); }
//----------------------------------------------------------------- // 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; }