void SystemBase::augmentSendList(std::vector<dof_id_type> & send_list) { std::set<dof_id_type> & ghosted_elems = _subproblem.ghostedElems(); DofMap & dof_map = dofMap(); std::vector<dof_id_type> dof_indices; System & sys = system(); unsigned int sys_num = sys.number(); unsigned int n_vars = sys.n_vars(); for (std::set<dof_id_type>::iterator elem_id = ghosted_elems.begin(); elem_id != ghosted_elems.end(); ++elem_id) { Elem * elem = _mesh.elem(*elem_id); if (elem->active()) { dof_map.dof_indices(elem, dof_indices); for (unsigned int i=0; i<dof_indices.size(); i++) { dof_id_type dof = dof_indices[i]; // Only need to ghost it if it's actually not on this processor if (dof < dof_map.first_dof() || dof >= dof_map.end_dof()) send_list.push_back(dof); } // Now add the DoFs from all of the nodes. This is necessary because of block // restricted variables. A variable might not live _on_ this element but it // might live on nodes connected to this element. for (unsigned int n=0; n<elem->n_nodes(); n++) { Node * node = elem->get_node(n); // Have to get each variable's dofs for (unsigned int v=0; v<n_vars; v++) { const Variable & var = sys.variable(v); unsigned int var_num = var.number(); unsigned int n_comp = var.n_components(); // See if this variable has any dofs at this node if (node->n_dofs(sys_num, var_num) > 0) { // Loop over components of the variable for (unsigned int c=0; c<n_comp; c++) send_list.push_back(node->dof_number(sys_num, var_num, c)); } } } } } }
void GrainTracker::swapSolutionValues(MooseSharedPointer<FeatureData> grain, unsigned int var_idx, std::map<Node *, CacheValues> & cache, REMAP_CACHE_MODE cache_mode, unsigned int depth) { 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->_local_ids.begin(); entity_it != grain->_local_ids.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, grain->_var_idx, var_idx, cache, cache_mode); } } } else swapSolutionValuesHelper(mesh.query_node_ptr(*entity_it), grain->_var_idx, var_idx, cache, cache_mode); } // Update the variable index in the unique grain datastructure grain->_var_idx = var_idx; // Close all of the solution vectors (we only need to do this once after all swaps are complete) if (depth == 0) { _nl.solution().close(); _nl.solutionOld().close(); _nl.solutionOlder().close(); _fe_problem.getNonlinearSystem().sys().update(); } }
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 Elem::refine (MeshRefinement& mesh_refinement) { libmesh_assert (this->refinement_flag() == Elem::REFINE); libmesh_assert (this->active()); // Create my children if necessary if (!_children) { _children = new Elem*[this->n_children()]; unsigned int parent_p_level = this->p_level(); for (unsigned int c=0; c<this->n_children(); c++) { _children[c] = Elem::build(this->type(), this).release(); _children[c]->set_refinement_flag(Elem::JUST_REFINED); _children[c]->set_p_level(parent_p_level); _children[c]->set_p_refinement_flag(this->p_refinement_flag()); } // Compute new nodal locations // and asssign nodes to children // Make these static. It is unlikely the // sizes will change from call to call, so having these // static should save on reallocations std::vector<std::vector<Point> > p (this->n_children()); std::vector<std::vector<Node*> > nodes(this->n_children()); // compute new nodal locations for (unsigned int c=0; c<this->n_children(); c++) { Elem *child = this->child(c); p[c].resize (child->n_nodes()); nodes[c].resize(child->n_nodes()); for (unsigned int nc=0; nc<child->n_nodes(); nc++) { // zero entries p[c][nc].zero(); nodes[c][nc] = NULL; 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); if (em_val != 0.) { p[c][nc].add_scaled (this->point(n), em_val); // We may have found the node, in which case we // won't need to look it up later. if (em_val == 1.) nodes[c][nc] = this->get_node(n); } } } // assign nodes to children & add them to the mesh const Real pointtol = this->hmin() * TOLERANCE; for (unsigned int nc=0; nc<child->n_nodes(); nc++) { if (nodes[c][nc] != NULL) { child->set_node(nc) = nodes[c][nc]; } else { child->set_node(nc) = mesh_refinement.add_point(p[c][nc], child->processor_id(), pointtol); child->get_node(nc)->set_n_systems (this->n_systems()); } } mesh_refinement.add_elem (child); child->set_n_systems(this->n_systems()); } } else { unsigned int parent_p_level = this->p_level(); for (unsigned int c=0; c<this->n_children(); c++) { Elem *child = this->child(c); libmesh_assert(child->subactive()); child->set_refinement_flag(Elem::JUST_REFINED); child->set_p_level(parent_p_level); child->set_p_refinement_flag(this->p_refinement_flag()); } } // Un-set my refinement flag now this->set_refinement_flag(Elem::INACTIVE); this->set_p_refinement_flag(Elem::INACTIVE); for (unsigned int c=0; c<this->n_children(); c++) { libmesh_assert(this->child(c)->parent() == this); libmesh_assert(this->child(c)->active()); } libmesh_assert (this->ancestor()); }
void Elem::coarsen() { libmesh_assert (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 (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 MeshTools::Subdivision::add_boundary_ghosts(MeshBase & mesh) { static const Real tol = 1e-5; // add the mirrored ghost elements (without using iterators, because the mesh is modified in the course) std::vector<Tri3Subdivision *> ghost_elems; std::vector<Node *> ghost_nodes; const unsigned int n_elem = mesh.n_elem(); for (unsigned int eid = 0; eid < n_elem; ++eid) { Elem * elem = mesh.elem(eid); libmesh_assert_equal_to(elem->type(), TRI3SUBDIVISION); // If the triangle happens to be in a corner (two boundary // edges), we perform a counter-clockwise loop by mirroring the // previous triangle until we come back to the original // triangle. This prevents degenerated triangles in the mesh // corners and guarantees that the node in the middle of the // loop is of valence=6. for (unsigned int i = 0; i < elem->n_sides(); ++i) { libmesh_assert_not_equal_to(elem->neighbor(i), elem); if (elem->neighbor(i) == libmesh_nullptr && elem->neighbor(next[i]) == libmesh_nullptr) { Elem * nelem = elem; unsigned int k = i; for (unsigned int l=0;l<4;l++) { // this is the vertex to be mirrored Point point = nelem->point(k) + nelem->point(next[k]) - nelem->point(prev[k]); // Check if the proposed vertex doesn't coincide // with one of the existing vertices. This is // necessary because for some triangulations, it can // happen that two mirrored ghost vertices coincide, // which would then lead to a zero size ghost // element below. Node * node = libmesh_nullptr; for (unsigned int j = 0; j < ghost_nodes.size(); ++j) { if ((*ghost_nodes[j] - point).size() < tol * (elem->point(k) - point).size()) { node = ghost_nodes[j]; break; } } // add the new vertex only if no other is nearby if (node == libmesh_nullptr) { node = mesh.add_point(point); ghost_nodes.push_back(node); } Tri3Subdivision * newelem = new Tri3Subdivision(); // add the first new ghost element to the list just as in the non-corner case if (l == 0) ghost_elems.push_back(newelem); newelem->set_node(0) = nelem->get_node(next[k]); newelem->set_node(1) = nelem->get_node(k); newelem->set_node(2) = node; newelem->set_neighbor(0, nelem); newelem->set_ghost(true); if (l>0) newelem->set_neighbor(2, libmesh_nullptr); nelem->set_neighbor(k, newelem); mesh.add_elem(newelem); mesh.get_boundary_info().add_node(nelem->get_node(k), 1); mesh.get_boundary_info().add_node(nelem->get_node(next[k]), 1); mesh.get_boundary_info().add_node(nelem->get_node(prev[k]), 1); mesh.get_boundary_info().add_node(node, 1); nelem = newelem; k = 2 ; } Tri3Subdivision * newelem = new Tri3Subdivision(); newelem->set_node(0) = elem->get_node(next[i]); newelem->set_node(1) = nelem->get_node(2); newelem->set_node(2) = elem->get_node(prev[i]); newelem->set_neighbor(0, nelem); nelem->set_neighbor(2, newelem); newelem->set_ghost(true); newelem->set_neighbor(2, elem); elem->set_neighbor(next[i],newelem); mesh.add_elem(newelem); break; } } for (unsigned int i = 0; i < elem->n_sides(); ++i) { libmesh_assert_not_equal_to(elem->neighbor(i), elem); if (elem->neighbor(i) == libmesh_nullptr) { // this is the vertex to be mirrored Point point = elem->point(i) + elem->point(next[i]) - elem->point(prev[i]); // Check if the proposed vertex doesn't coincide with // one of the existing vertices. This is necessary // because for some triangulations, it can happen that // two mirrored ghost vertices coincide, which would // then lead to a zero size ghost element below. Node * node = libmesh_nullptr; for (unsigned int j = 0; j < ghost_nodes.size(); ++j) { if ((*ghost_nodes[j] - point).size() < tol * (elem->point(i) - point).size()) { node = ghost_nodes[j]; break; } } // add the new vertex only if no other is nearby if (node == libmesh_nullptr) { node = mesh.add_point(point); ghost_nodes.push_back(node); } Tri3Subdivision * newelem = new Tri3Subdivision(); ghost_elems.push_back(newelem); newelem->set_node(0) = elem->get_node(next[i]); newelem->set_node(1) = elem->get_node(i); newelem->set_node(2) = node; newelem->set_neighbor(0, elem); newelem->set_ghost(true); elem->set_neighbor(i, newelem); mesh.add_elem(newelem); mesh.get_boundary_info().add_node(elem->get_node(i), 1); mesh.get_boundary_info().add_node(elem->get_node(next[i]), 1); mesh.get_boundary_info().add_node(elem->get_node(prev[i]), 1); mesh.get_boundary_info().add_node(node, 1); } } } // add the missing ghost elements (connecting new ghost nodes) std::vector<Tri3Subdivision *> missing_ghost_elems; std::vector<Tri3Subdivision *>::iterator ghost_el = ghost_elems.begin(); const std::vector<Tri3Subdivision *>::iterator end_ghost_el = ghost_elems.end(); for (; ghost_el != end_ghost_el; ++ghost_el) { Tri3Subdivision * elem = *ghost_el; libmesh_assert(elem->is_ghost()); for (unsigned int i = 0; i < elem->n_sides(); ++i) { if (elem->neighbor(i) == libmesh_nullptr && elem->neighbor(prev[i]) != libmesh_nullptr) { // go around counter-clockwise Tri3Subdivision * nb1 = static_cast<Tri3Subdivision *>(elem->neighbor(prev[i])); Tri3Subdivision * nb2 = nb1; unsigned int j = i; unsigned int n_nb = 0; while (nb1 != libmesh_nullptr && nb1->id() != elem->id()) { j = nb1->local_node_number(elem->node(i)); nb2 = nb1; nb1 = static_cast<Tri3Subdivision *>(nb1->neighbor(prev[j])); libmesh_assert(nb1 == libmesh_nullptr || nb1->id() != nb2->id()); n_nb++; } libmesh_assert_not_equal_to(nb2->id(), elem->id()); // Above, we merged coinciding ghost vertices. Therefore, we need // to exclude the case where there is no ghost element to add between // these two (identical) ghost nodes. if (elem->get_node(next[i])->id() == nb2->get_node(prev[j])->id()) break; // If the number of already present neighbors is less than 4, we add another extra element // so that the node in the middle of the loop ends up being of valence=6. // This case usually happens when the middle node corresponds to a corner of the original mesh, // and the extra element below prevents degenerated triangles in the mesh corners. if (n_nb < 4) { // this is the vertex to be mirrored Point point = nb2->point(j) + nb2->point(prev[j]) - nb2->point(next[j]); // Check if the proposed vertex doesn't coincide with one of the existing vertices. // This is necessary because for some triangulations, it can happen that two mirrored // ghost vertices coincide, which would then lead to a zero size ghost element below. Node * node = libmesh_nullptr; for (unsigned int k = 0; k < ghost_nodes.size(); ++k) { if ((*ghost_nodes[k] - point).size() < tol * (nb2->point(j) - point).size()) { node = ghost_nodes[k]; break; } } // add the new vertex only if no other is nearby if (node == libmesh_nullptr) { node = mesh.add_point(point); ghost_nodes.push_back(node); } Tri3Subdivision * newelem = new Tri3Subdivision(); newelem->set_node(0) = nb2->get_node(j); newelem->set_node(1) = nb2->get_node(prev[j]); newelem->set_node(2) = node; newelem->set_neighbor(0, nb2); newelem->set_neighbor(1, libmesh_nullptr); newelem->set_ghost(true); nb2->set_neighbor(prev[j], newelem); mesh.add_elem(newelem); mesh.get_boundary_info().add_node(nb2->get_node(j), 1); mesh.get_boundary_info().add_node(nb2->get_node(prev[j]), 1); mesh.get_boundary_info().add_node(node, 1); nb2 = newelem; j = nb2->local_node_number(elem->node(i)); } Tri3Subdivision * newelem = new Tri3Subdivision(); newelem->set_node(0) = elem->get_node(next[i]); newelem->set_node(1) = elem->get_node(i); newelem->set_node(2) = nb2->get_node(prev[j]); newelem->set_neighbor(0, elem); newelem->set_neighbor(1, nb2); newelem->set_neighbor(2, libmesh_nullptr); newelem->set_ghost(true); elem->set_neighbor(i, newelem); nb2->set_neighbor(prev[j], newelem); missing_ghost_elems.push_back(newelem); break; } } // end side loop } // end ghost element loop // add the missing ghost elements to the mesh std::vector<Tri3Subdivision *>::iterator missing_el = missing_ghost_elems.begin(); const std::vector<Tri3Subdivision *>::iterator end_missing_el = missing_ghost_elems.end(); for (; missing_el != end_missing_el; ++missing_el) mesh.add_elem(*missing_el); }
void LinearElasticityWithContact::move_mesh( MeshBase& input_mesh, const NumericVector<Number>& input_solution) { // Maintain a set of node ids that we've encountered. LIBMESH_BEST_UNORDERED_SET<dof_id_type> encountered_node_ids; // Localize input_solution so that we have the data to move all // elements (not just elements local to this processor). UniquePtr< NumericVector<Number> > localized_input_solution = NumericVector<Number>::build(input_solution.comm()); localized_input_solution->init ( input_solution.size(), false, SERIAL); input_solution.localize(*localized_input_solution); MeshBase::const_element_iterator el = input_mesh.active_elements_begin(); const MeshBase::const_element_iterator end_el = input_mesh.active_elements_end(); for ( ; el != end_el; ++el) { Elem* elem = *el; Elem* orig_elem = _sys.get_mesh().elem(elem->id()); for(unsigned int node_id=0; node_id<elem->n_nodes(); node_id++) { Node* node = elem->get_node(node_id); if(encountered_node_ids.find(node->id()) != encountered_node_ids.end()) { continue; } encountered_node_ids.insert(node->id()); std::vector<std::string> uvw_names(3); uvw_names[0] = "u"; uvw_names[1] = "v"; uvw_names[2] = "w"; { // Inverse map node to reference element // Get local coordinates to feed these into compute_data(). // Note that the fe_type can safely be used from the 0-variable, // since the inverse mapping is the same for all FEFamilies. const Point reference_point ( FEInterface::inverse_map ( elem->dim(), _sys.get_dof_map().variable_type(0), elem, *node)); Point uvw; for (unsigned int index=0; index<uvw_names.size(); index++) { const unsigned int var = _sys.variable_number(uvw_names[index]); const FEType& fe_type = _sys.get_dof_map().variable_type(var); FEComputeData data (_sys.get_equation_systems(), reference_point); FEInterface::compute_data(elem->dim(), fe_type, elem, data); std::vector<dof_id_type> dof_indices_var; _sys.get_dof_map().dof_indices (orig_elem, dof_indices_var, var); for (unsigned int i=0; i<dof_indices_var.size(); i++) { Number value = (*localized_input_solution)(dof_indices_var[i]) * data.shape[i]; #ifdef LIBMESH_USE_COMPLEX_NUMBERS // We explicitly store the real part in uvw uvw(index) += value.real(); #else uvw(index) += value; #endif } } // Update the node's location *node += uvw; } } } }
void FeatureFloodCount::FeatureData::updateBBoxExtremes(MeshTools::BoundingBox & bbox, const Elem & elem) { for (unsigned int node_n = 0; node_n < elem.n_nodes(); ++node_n) updateBBoxExtremes(bbox, *(elem.get_node(node_n))); }
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 setUp() { mesh.reset(new Mesh(*TestCommWorld)); MeshTools::Generation::build_cube(*mesh, 1, 1, 1); es.reset(new EquationSystems(*mesh)); sys = &(es->add_system<System> ("SimpleSystem")); sys->add_variable("x2"); sys->add_variable("x3"); sys->add_variable("c05"); sys->add_variable("y4"); sys->add_variable("xy"); sys->add_variable("yz"); sys->add_variable("xyz"); es->init(); NumericVector<Number> & sol = *sys->solution; Elem *elem = mesh->query_elem(0); if (elem && elem->processor_id() == TestCommWorld->rank()) { // Set x2 = 2*x sol.set(elem->get_node(1)->dof_number(0,0,0), 2); sol.set(elem->get_node(2)->dof_number(0,0,0), 2); sol.set(elem->get_node(5)->dof_number(0,0,0), 2); sol.set(elem->get_node(6)->dof_number(0,0,0), 2); // Set x3 = 3*x sol.set(elem->get_node(1)->dof_number(0,1,0), 3); sol.set(elem->get_node(2)->dof_number(0,1,0), 3); sol.set(elem->get_node(5)->dof_number(0,1,0), 3); sol.set(elem->get_node(6)->dof_number(0,1,0), 3); // Set c05 = 0.5 sol.set(elem->get_node(0)->dof_number(0,2,0), 0.5); sol.set(elem->get_node(1)->dof_number(0,2,0), 0.5); sol.set(elem->get_node(2)->dof_number(0,2,0), 0.5); sol.set(elem->get_node(3)->dof_number(0,2,0), 0.5); sol.set(elem->get_node(4)->dof_number(0,2,0), 0.5); sol.set(elem->get_node(5)->dof_number(0,2,0), 0.5); sol.set(elem->get_node(6)->dof_number(0,2,0), 0.5); sol.set(elem->get_node(7)->dof_number(0,2,0), 0.5); // Set y4 = 4*y sol.set(elem->get_node(2)->dof_number(0,3,0), 4); sol.set(elem->get_node(3)->dof_number(0,3,0), 4); sol.set(elem->get_node(6)->dof_number(0,3,0), 4); sol.set(elem->get_node(7)->dof_number(0,3,0), 4); // Set xy = x*y sol.set(elem->get_node(2)->dof_number(0,4,0), 1); sol.set(elem->get_node(6)->dof_number(0,4,0), 1); // Set yz = y*z sol.set(elem->get_node(6)->dof_number(0,5,0), 1); sol.set(elem->get_node(7)->dof_number(0,5,0), 1); // Set xyz = x*y*z sol.set(elem->get_node(6)->dof_number(0,6,0), 1); } sol.close(); sys->update(); c.reset(new FEMContext(*sys)); if (elem && elem->processor_id() == TestCommWorld->rank()) { c->pre_fe_reinit(*sys, elem); c->elem_fe_reinit(); } }
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"); }
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(); }