void EpetraVector<T>::localize (std::vector<T>& v_local) const { // This function must be run on all processors at once parallel_object_only(); const unsigned int n = this->size(); const unsigned int nl = this->local_size(); libmesh_assert(this->_vec); v_local.clear(); v_local.reserve(n); // build up my local part for (unsigned int i=0; i<nl; i++) v_local.push_back((*this->_vec)[i]); this->comm().allgather (v_local); }
unsigned int MeshBase::recalculate_n_partitions() { // This requires an inspection on every processor parallel_object_only(); const_element_iterator el = this->active_local_elements_begin(); const_element_iterator end = this->active_local_elements_end(); unsigned int max_proc_id=0; for (; el!=end; ++el) max_proc_id = std::max(max_proc_id, static_cast<unsigned int>((*el)->processor_id())); // The number of partitions is one more than the max processor ID. _n_parts = max_proc_id+1; this->comm().max(_n_parts); return _n_parts; }
std::unique_ptr<PointLocatorBase> MeshBase::sub_point_locator () const { // If there's no master point locator, then we need one. if (_point_locator.get() == nullptr) { // PointLocator construction may not be safe within threads libmesh_assert(!Threads::in_threads); // And it may require parallel communication parallel_object_only(); _point_locator = PointLocatorBase::build(TREE_ELEMENTS, *this); if (_point_locator_close_to_point_tol > 0.) _point_locator->set_close_to_point_tol(_point_locator_close_to_point_tol); } // Otherwise there was a master point locator, and we can grab a // sub-locator easily. return PointLocatorBase::build(TREE_ELEMENTS, *this, _point_locator.get()); }
Real DistributedVector<T>::linfty_norm () const { // This function must be run on all processors at once parallel_object_only(); libmesh_assert (this->initialized()); libmesh_assert_equal_to (_values.size(), _local_size); libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size); Real local_linfty = 0.; for (numeric_index_type i=0; i<local_size(); i++) local_linfty = std::max(local_linfty, static_cast<Real>(std::abs(_values[i])) ); // Note we static_cast so that both // types are the same, as required // by std::max this->comm().max(local_linfty); return local_linfty; }
T DistributedVector<T>::dot (const NumericVector<T>& V) const { // This function must be run on all processors at once parallel_object_only(); // Make sure the NumericVector passed in is really a DistributedVector const DistributedVector<T>* v = libmesh_cast_ptr<const DistributedVector<T>*>(&V); // Make sure that the two vectors are distributed in the same way. libmesh_assert_equal_to ( this->first_local_index(), v->first_local_index() ); libmesh_assert_equal_to ( this->last_local_index(), v->last_local_index() ); // The result of dotting together the local parts of the vector. T local_dot = 0; for (std::size_t i=0; i<this->local_size(); i++) local_dot += this->_values[i] * v->_values[i]; // The local dot products are now summed via MPI this->comm().sum(local_dot); return local_dot; }
void UnstructuredMesh::find_neighbors (const bool reset_remote_elements, const bool reset_current_list) { // We might actually want to run this on an empty mesh // (e.g. the boundary mesh for a nonexistant bcid!) // libmesh_assert_not_equal_to (this->n_nodes(), 0); // libmesh_assert_not_equal_to (this->n_elem(), 0); // This function must be run on all processors at once parallel_object_only(); LOG_SCOPE("find_neighbors()", "Mesh"); const element_iterator el_end = this->elements_end(); //TODO:[BSK] This should be removed later?! if (reset_current_list) for (element_iterator el = this->elements_begin(); el != el_end; ++el) { Elem * e = *el; for (unsigned int s=0; s<e->n_neighbors(); s++) if (e->neighbor_ptr(s) != remote_elem || reset_remote_elements) e->set_neighbor(s, libmesh_nullptr); } // Find neighboring elements by first finding elements // with identical side keys and then check to see if they // are neighbors { // data structures -- Use the hash_multimap if available typedef unsigned int key_type; typedef std::pair<Elem *, unsigned char> val_type; typedef std::pair<key_type, val_type> key_val_pair; typedef LIBMESH_BEST_UNORDERED_MULTIMAP<key_type, val_type> map_type; // A map from side keys to corresponding elements & side numbers map_type side_to_elem_map; for (element_iterator el = this->elements_begin(); el != el_end; ++el) { Elem * element = *el; for (unsigned char ms=0; ms<element->n_neighbors(); ms++) { next_side: // If we haven't yet found a neighbor on this side, try. // Even if we think our neighbor is remote, that // information may be out of date. if (element->neighbor_ptr(ms) == libmesh_nullptr || element->neighbor_ptr(ms) == remote_elem) { // Get the key for the side of this element const unsigned int key = element->key(ms); // Look for elements that have an identical side key std::pair <map_type::iterator, map_type::iterator> bounds = side_to_elem_map.equal_range(key); // May be multiple keys, check all the possible // elements which _might_ be neighbors. if (bounds.first != bounds.second) { // Get the side for this element const UniquePtr<Elem> my_side(element->side_ptr(ms)); // Look at all the entries with an equivalent key while (bounds.first != bounds.second) { // Get the potential element Elem * neighbor = bounds.first->second.first; // Get the side for the neighboring element const unsigned int ns = bounds.first->second.second; const UniquePtr<Elem> their_side(neighbor->side_ptr(ns)); //libmesh_assert(my_side.get()); //libmesh_assert(their_side.get()); // If found a match with my side // // We need special tests here for 1D: // since parents and children have an equal // side (i.e. a node), we need to check // ns != ms, and we also check level() to // avoid setting our neighbor pointer to // any of our neighbor's descendants if( (*my_side == *their_side) && (element->level() == neighbor->level()) && ((element->dim() != 1) || (ns != ms)) ) { // So share a side. Is this a mixed pair // of subactive and active/ancestor // elements? // If not, then we're neighbors. // If so, then the subactive's neighbor is if (element->subactive() == neighbor->subactive()) { // an element is only subactive if it has // been coarsened but not deleted element->set_neighbor (ms,neighbor); neighbor->set_neighbor(ns,element); } else if (element->subactive()) { element->set_neighbor(ms,neighbor); } else if (neighbor->subactive()) { neighbor->set_neighbor(ns,element); } side_to_elem_map.erase (bounds.first); // get out of this nested crap goto next_side; } ++bounds.first; } } // didn't find a match... // Build the map entry for this element key_val_pair kvp; kvp.first = key; kvp.second.first = element; kvp.second.second = ms; // use the lower bound as a hint for // where to put it. #if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP) side_to_elem_map.insert (kvp); #else side_to_elem_map.insert (bounds.first,kvp); #endif } } } } #ifdef LIBMESH_ENABLE_AMR /** * Here we look at all of the child elements which * don't already have valid neighbors. * * If a child element has a NULL neighbor it is * either because it is on the boundary or because * its neighbor is at a different level. In the * latter case we must get the neighbor from the * parent. * * If a child element has a remote_elem neighbor * on a boundary it shares with its parent, that * info may have become out-dated through coarsening * of the neighbor's parent. In this case, if the * parent's neighbor is active then the child should * share it. * * Furthermore, that neighbor better be active, * otherwise we missed a child somewhere. * * * We also need to look through children ordered by increasing * refinement level in order to add new interior_parent() links in * boundary elements which have just been generated by refinement, * and fix links in boundary elements whose previous * interior_parent() has just been coarsened away. */ const unsigned int n_levels = MeshTools::n_levels(*this); for (unsigned int level = 1; level < n_levels; ++level) { element_iterator end = this->level_elements_end(level); for (element_iterator el = this->level_elements_begin(level); el != end; ++el) { Elem * current_elem = *el; libmesh_assert(current_elem); Elem * parent = current_elem->parent(); libmesh_assert(parent); const unsigned int my_child_num = parent->which_child_am_i(current_elem); for (unsigned int s=0; s < current_elem->n_neighbors(); s++) { if (current_elem->neighbor_ptr(s) == libmesh_nullptr || (current_elem->neighbor_ptr(s) == remote_elem && parent->is_child_on_side(my_child_num, s))) { Elem * neigh = parent->neighbor_ptr(s); // If neigh was refined and had non-subactive children // made remote earlier, then a non-subactive elem should // actually have one of those remote children as a // neighbor if (neigh && (neigh->ancestor()) && (!current_elem->subactive())) { #ifdef DEBUG // Let's make sure that "had children made remote" // situation is actually the case libmesh_assert(neigh->has_children()); bool neigh_has_remote_children = false; for (unsigned int c = 0; c != neigh->n_children(); ++c) { if (neigh->child_ptr(c) == remote_elem) neigh_has_remote_children = true; } libmesh_assert(neigh_has_remote_children); // And let's double-check that we don't have // a remote_elem neighboring a local element libmesh_assert_not_equal_to (current_elem->processor_id(), this->processor_id()); #endif // DEBUG neigh = const_cast<RemoteElem *>(remote_elem); } if (!current_elem->subactive()) current_elem->set_neighbor(s, neigh); #ifdef DEBUG if (neigh != libmesh_nullptr && neigh != remote_elem) // We ignore subactive elements here because // we don't care about neighbors of subactive element. if ((!neigh->active()) && (!current_elem->subactive())) { libMesh::err << "On processor " << this->processor_id() << std::endl; libMesh::err << "Bad element ID = " << current_elem->id() << ", Side " << s << ", Bad neighbor ID = " << neigh->id() << std::endl; libMesh::err << "Bad element proc_ID = " << current_elem->processor_id() << ", Bad neighbor proc_ID = " << neigh->processor_id() << std::endl; libMesh::err << "Bad element size = " << current_elem->hmin() << ", Bad neighbor size = " << neigh->hmin() << std::endl; libMesh::err << "Bad element center = " << current_elem->centroid() << ", Bad neighbor center = " << neigh->centroid() << std::endl; libMesh::err << "ERROR: " << (current_elem->active()?"Active":"Ancestor") << " Element at level " << current_elem->level() << std::endl; libMesh::err << "with " << (parent->active()?"active": (parent->subactive()?"subactive":"ancestor")) << " parent share " << (neigh->subactive()?"subactive":"ancestor") << " neighbor at level " << neigh->level() << std::endl; NameBasedIO(*this).write ("bad_mesh.gmv"); libmesh_error_msg("Problematic mesh written to bad_mesh.gmv."); } #endif // DEBUG } } // We can skip to the next element if we're full-dimension // and therefore don't have any interior parents if (current_elem->dim() >= LIBMESH_DIM) continue; // We have no interior parents unless we can find one later current_elem->set_interior_parent(libmesh_nullptr); Elem * pip = parent->interior_parent(); if (!pip) continue; // If there's no interior_parent children, whether due to a // remote element or a non-conformity, then there's no // children to search. if (pip == remote_elem || pip->active()) { current_elem->set_interior_parent(pip); continue; } // For node comparisons we'll need a sensible tolerance Real node_tolerance = current_elem->hmin() * TOLERANCE; // Otherwise our interior_parent should be a child of our // parent's interior_parent. for (unsigned int c=0; c != pip->n_children(); ++c) { Elem * child = pip->child_ptr(c); // If we have a remote_elem, that might be our // interior_parent. We'll set it provisionally now and // keep trying to find something better. if (child == remote_elem) { current_elem->set_interior_parent (const_cast<RemoteElem *>(remote_elem)); continue; } bool child_contains_our_nodes = true; for (unsigned int n=0; n != current_elem->n_nodes(); ++n) { bool child_contains_this_node = false; for (unsigned int cn=0; cn != child->n_nodes(); ++cn) if (child->point(cn).absolute_fuzzy_equals (current_elem->point(n), node_tolerance)) { child_contains_this_node = true; break; } if (!child_contains_this_node) { child_contains_our_nodes = false; break; } } if (child_contains_our_nodes) { current_elem->set_interior_parent(child); break; } } // We should have found *some* interior_parent at this // point, whether semilocal or remote. libmesh_assert(current_elem->interior_parent()); } } #endif // AMR #ifdef DEBUG MeshTools::libmesh_assert_valid_neighbors(*this, !reset_remote_elements); MeshTools::libmesh_assert_valid_amr_interior_parents(*this); #endif }
void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors) { parallel_object_only(); libmesh_assert(this->comm().verify(this->is_serial())); // A distributed mesh may have processors with no elements (or // processors with no elements of higher dimension, if we ever // support mixed-dimension meshes), but we want consistent // mesh_dimension anyways. // // cache_elem_dims() should get the elem_dimensions() and // mesh_dimension() correct later, and we don't need it earlier. // Renumber the nodes and elements so that they in contiguous // blocks. By default, _skip_renumber_nodes_and_elements is false. // // We may currently change that by passing // skip_renumber_nodes_and_elements==true to this function, but we // should use the allow_renumbering() accessor instead. // // Instances where you if prepare_for_use() should not renumber the nodes // and elements include reading in e.g. an xda/r or gmv file. In // this case, the ordering of the nodes may depend on an accompanying // solution, and the node ordering cannot be changed. if (skip_renumber_nodes_and_elements) { libmesh_deprecated(); this->allow_renumbering(false); } // Mesh modification operations might not leave us with consistent // id counts, but our partitioner might need that consistency. if(!_skip_renumber_nodes_and_elements) this->renumber_nodes_and_elements(); else this->update_parallel_id_counts(); // Let all the elements find their neighbors if(!skip_find_neighbors) this->find_neighbors(); // Partition the mesh. this->partition(); // If we're using ParallelMesh, we'll want it parallelized. this->delete_remote_elements(); #ifdef LIBMESH_ENABLE_UNIQUE_ID // Assign DOF object unique ids this->assign_unique_ids(); #endif if(!_skip_renumber_nodes_and_elements) this->renumber_nodes_and_elements(); // Search the mesh for all the dimensions of the elements // and cache them. this->cache_elem_dims(); // Reset our PointLocator. This needs to happen any time the elements // in the underlying elements in the mesh have changed, so we do it here. this->clear_point_locator(); // The mesh is now prepared for use. _is_prepared = true; }
//----------------------------------------------------------------- // 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; }
void EquationSystems::get_solution (std::vector<Number>& soln, std::vector<std::string> & names ) const { // This function must be run on all processors at once parallel_object_only(); libmesh_assert (this->n_systems()); const dof_id_type ne = _mesh.n_elem(); libmesh_assert_equal_to (ne, _mesh.max_elem_id()); // Get the number of local elements dof_id_type n_local_elems = cast_int<dof_id_type> (std::distance(_mesh.local_elements_begin(), _mesh.local_elements_end())); // If the names vector has entries, we will only populate the soln vector // with names included in that list. Note: The names vector may be // reordered upon exiting this function std::vector<std::string> filter_names = names; bool is_filter_names = ! filter_names.empty(); soln.clear(); names.clear(); const FEType type(CONSTANT, MONOMIAL); dof_id_type nv = 0; // Find the total number of variables to output { const_system_iterator pos = _systems.begin(); const const_system_iterator end = _systems.end(); for (; pos != end; ++pos) { const System& system = *(pos->second); const unsigned int nv_sys = system.n_vars(); for (unsigned int var=0; var < nv_sys; ++var) { if ( system.variable_type( var ) != type || ( is_filter_names && std::find(filter_names.begin(), filter_names.end(), system.variable_name( var )) == filter_names.end()) ) continue; nv++; } } } if(!nv) // If there are no variables to write out don't do anything... return; // Create a NumericVector to hold the parallel solution UniquePtr<NumericVector<Number> > parallel_soln_ptr = NumericVector<Number>::build(_communicator); NumericVector<Number> ¶llel_soln = *parallel_soln_ptr; parallel_soln.init(ne*nv, n_local_elems*nv, false, PARALLEL); dof_id_type var_num = 0; // For each system in this EquationSystems object, // update the global solution and collect the // CONSTANT MONOMIALs. The entries are in variable-major // format. const_system_iterator pos = _systems.begin(); const const_system_iterator end = _systems.end(); for (; pos != end; ++pos) { const System& system = *(pos->second); const unsigned int nv_sys = system.n_vars(); // Update the current_local_solution { System & non_const_sys = const_cast<System &>(system); non_const_sys.solution->close(); non_const_sys.update(); } NumericVector<Number> & sys_soln(*system.current_local_solution); std::vector<dof_id_type> dof_indices; // The DOF indices for the finite element // Loop over the variable names and load them in order for (unsigned int var=0; var < nv_sys; ++var) { if ( system.variable_type( var ) != type || ( is_filter_names && std::find(filter_names.begin(), filter_names.end(), system.variable_name( var )) == filter_names.end()) ) continue; names.push_back( system.variable_name( var ) ); const Variable & variable = system.variable(var); const DofMap & dof_map = system.get_dof_map(); MeshBase::element_iterator it = _mesh.active_local_elements_begin(); const MeshBase::element_iterator end_elem = _mesh.active_local_elements_end(); for ( ; it != end_elem; ++it) { if (variable.active_on_subdomain((*it)->subdomain_id())) { const Elem* elem = *it; dof_map.dof_indices (elem, dof_indices, var); libmesh_assert_equal_to ( 1, dof_indices.size() ); parallel_soln.set((ne*var_num)+elem->id(), sys_soln(dof_indices[0])); } } var_num++; } // end loop on variables in this system } // end loop over systems parallel_soln.close(); parallel_soln.localize_to_one(soln); }
void SparseMatrix<T>::print(std::ostream & os, const bool sparse) const { parallel_object_only(); libmesh_assert (this->initialized()); if(!this->_dof_map) libmesh_error_msg("Error! Trying to print a matrix with no dof_map set!"); // We'll print the matrix from processor 0 to make sure // it's serialized properly if (this->processor_id() == 0) { libmesh_assert_equal_to (this->_dof_map->first_dof(), 0); for (numeric_index_type i=this->_dof_map->first_dof(); i!=this->_dof_map->end_dof(); ++i) { if(sparse) { for (numeric_index_type j=0; j<this->n(); j++) { T c = (*this)(i,j); if (c != static_cast<T>(0.0)) { os << i << " " << j << " " << c << std::endl; } } } else { for (numeric_index_type j=0; j<this->n(); j++) os << (*this)(i,j) << " "; os << std::endl; } } std::vector<numeric_index_type> ibuf, jbuf; std::vector<T> cbuf; numeric_index_type currenti = this->_dof_map->end_dof(); for (processor_id_type p=1; p < this->n_processors(); ++p) { this->comm().receive(p, ibuf); this->comm().receive(p, jbuf); this->comm().receive(p, cbuf); libmesh_assert_equal_to (ibuf.size(), jbuf.size()); libmesh_assert_equal_to (ibuf.size(), cbuf.size()); if (ibuf.empty()) continue; libmesh_assert_greater_equal (ibuf.front(), currenti); libmesh_assert_greater_equal (ibuf.back(), ibuf.front()); std::size_t currentb = 0; for (;currenti <= ibuf.back(); ++currenti) { if(sparse) { for (numeric_index_type j=0; j<this->n(); j++) { if (currentb < ibuf.size() && ibuf[currentb] == currenti && jbuf[currentb] == j) { os << currenti << " " << j << " " << cbuf[currentb] << std::endl; currentb++; } } } else { for (numeric_index_type j=0; j<this->n(); j++) { if (currentb < ibuf.size() && ibuf[currentb] == currenti && jbuf[currentb] == j) { os << cbuf[currentb] << " "; currentb++; } else os << static_cast<T>(0.0) << " "; } os << std::endl; } } } if(!sparse) { for (; currenti != this->m(); ++currenti) { for (numeric_index_type j=0; j<this->n(); j++) os << static_cast<T>(0.0) << " "; os << std::endl; } } } else { std::vector<numeric_index_type> ibuf, jbuf; std::vector<T> cbuf; // We'll assume each processor has access to entire // matrix rows, so (*this)(i,j) is valid if i is a local index. for (numeric_index_type i=this->_dof_map->first_dof(); i!=this->_dof_map->end_dof(); ++i) { for (numeric_index_type j=0; j<this->n(); j++) { T c = (*this)(i,j); if (c != static_cast<T>(0.0)) { ibuf.push_back(i); jbuf.push_back(j); cbuf.push_back(c); } } } this->comm().send(0,ibuf); this->comm().send(0,jbuf); this->comm().send(0,cbuf); } }
bool MeshRefinement::eliminate_unrefined_patches () { // This function must be run on all processors at once parallel_object_only(); bool flags_changed = false; 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; // First assume that we'll have to flag this element for both h // and p refinement, then change our minds if we see any // neighbors that are as coarse or coarser than us. bool h_flag_me = true, p_flag_me = true; // Skip the element if it is already fully flagged for refinement if (elem->p_refinement_flag() == Elem::REFINE) p_flag_me = false; if (elem->refinement_flag() == Elem::REFINE) { h_flag_me = false; if (!p_flag_me) continue; } // Test the parent if that is already flagged for coarsening else if (elem->refinement_flag() == Elem::COARSEN) { libmesh_assert(elem->parent()); elem = elem->parent(); // FIXME - this doesn't seem right - RHS if (elem->refinement_flag() != Elem::COARSEN_INACTIVE) continue; p_flag_me = false; } const unsigned int my_level = elem->level(); int my_p_adjustment = 0; if (elem->p_refinement_flag() == Elem::REFINE) my_p_adjustment = 1; else if (elem->p_refinement_flag() == Elem::COARSEN) { libmesh_assert_greater (elem->p_level(), 0); my_p_adjustment = -1; } const unsigned int my_new_p_level = elem->p_level() + my_p_adjustment; // Check all the element neighbors for (unsigned int n=0; n<elem->n_neighbors(); n++) { const Elem *neighbor = elem->neighbor(n); // Quit if the element is on a local boundary if (neighbor == NULL || neighbor == remote_elem) { h_flag_me = false; p_flag_me = false; break; } // if the neighbor will be equally or less refined than // we are, then we will not become an unrefined island. // So if we are still considering h refinement: if (h_flag_me && // If our neighbor is already at a lower level, // it can't end up at a higher level even if it // is flagged for refinement once ((neighbor->level() < my_level) || // If our neighbor is at the same level but isn't // flagged for refinement, it won't end up at a // higher level ((neighbor->active()) && (neighbor->refinement_flag() != Elem::REFINE)) || // If our neighbor is currently more refined but is // a parent flagged for coarsening, it will end up // at the same level. (neighbor->refinement_flag() == Elem::COARSEN_INACTIVE))) { // We've proven we won't become an unrefined island, // so don't h refine to avoid that. h_flag_me = false; // If we've also proven we don't need to p refine, // we don't need to check more neighbors if (!p_flag_me) break; } if (p_flag_me) { // if active neighbors will have a p level // equal to or lower than ours, then we do not need to p // refine ourselves. if (neighbor->active()) { int p_adjustment = 0; if (neighbor->p_refinement_flag() == Elem::REFINE) p_adjustment = 1; else if (neighbor->p_refinement_flag() == Elem::COARSEN) { libmesh_assert_greater (neighbor->p_level(), 0); p_adjustment = -1; } if (my_new_p_level >= neighbor->p_level() + p_adjustment) { p_flag_me = false; if (!h_flag_me) break; } } // If we have inactive neighbors, we need to // test all their active descendants which neighbor us else if (neighbor->ancestor()) { if (neighbor->min_new_p_level_by_neighbor(elem, my_new_p_level + 2) <= my_new_p_level) { p_flag_me = false; if (!h_flag_me) break; } } } } if (h_flag_me) { // Parents that would create islands should no longer // coarsen if (elem->refinement_flag() == Elem::COARSEN_INACTIVE) { for (unsigned int c=0; c<elem->n_children(); c++) { libmesh_assert_equal_to (elem->child(c)->refinement_flag(), Elem::COARSEN); elem->child(c)->set_refinement_flag(Elem::DO_NOTHING); } elem->set_refinement_flag(Elem::INACTIVE); } else elem->set_refinement_flag(Elem::REFINE); flags_changed = true; } if (p_flag_me) { if (elem->p_refinement_flag() == Elem::COARSEN) elem->set_p_refinement_flag(Elem::DO_NOTHING); else elem->set_p_refinement_flag(Elem::REFINE); flags_changed = true; } } // If flags changed on any processor then they changed globally this->comm().max(flags_changed); return flags_changed; }
void EquationSystems::build_solution_vector (std::vector<Number>& soln, const std::set<std::string>* system_names) const { START_LOG("build_solution_vector()", "EquationSystems"); // This function must be run on all processors at once parallel_object_only(); libmesh_assert (this->n_systems()); const unsigned int dim = _mesh.mesh_dimension(); const dof_id_type nn = _mesh.n_nodes(); // We'd better have a contiguous node numbering libmesh_assert_equal_to (nn, _mesh.max_node_id()); // allocate storage to hold // (number_of_nodes)*(number_of_variables) entries. // We have to differentiate between between scalar and vector // variables. We intercept vector variables and treat each // component as a scalar variable (consistently with build_solution_names). unsigned int nv = 0; //Could this be replaced by a/some convenience methods?[PB] { unsigned int n_scalar_vars = 0; unsigned int n_vector_vars = 0; const_system_iterator pos = _systems.begin(); const const_system_iterator end = _systems.end(); for (; pos != end; ++pos) { // Check current system is listed in system_names, and skip pos if not bool use_current_system = (system_names == NULL); if (!use_current_system) use_current_system = system_names->count(pos->first); if (!use_current_system) continue; for (unsigned int vn=0; vn<pos->second->n_vars(); vn++) { if( FEInterface::field_type(pos->second->variable_type(vn)) == TYPE_VECTOR ) n_vector_vars++; else n_scalar_vars++; } } // Here, we're assuming the number of vector components is the same // as the mesh dimension. Will break for mixed dimension meshes. nv = n_scalar_vars + dim*n_vector_vars; } // Get the number of elements that share each node. We will // compute the average value at each node. This is particularly // useful for plotting discontinuous data. MeshBase::element_iterator e_it = _mesh.active_local_elements_begin(); const MeshBase::element_iterator e_end = _mesh.active_local_elements_end(); // Get the number of local nodes dof_id_type n_local_nodes = cast_int<dof_id_type> (std::distance(_mesh.local_nodes_begin(), _mesh.local_nodes_end())); // Create a NumericVector to hold the parallel solution UniquePtr<NumericVector<Number> > parallel_soln_ptr = NumericVector<Number>::build(_communicator); NumericVector<Number> ¶llel_soln = *parallel_soln_ptr; parallel_soln.init(nn*nv, n_local_nodes*nv, false, PARALLEL); // Create a NumericVector to hold the "repeat_count" for each node - this is essentially // the number of elements contributing to that node's value UniquePtr<NumericVector<Number> > repeat_count_ptr = NumericVector<Number>::build(_communicator); NumericVector<Number> &repeat_count = *repeat_count_ptr; repeat_count.init(nn*nv, n_local_nodes*nv, false, PARALLEL); repeat_count.close(); unsigned int var_num=0; // For each system in this EquationSystems object, // update the global solution and if we are on processor 0, // loop over the elements and build the nodal solution // from the element solution. Then insert this nodal solution // into the vector passed to build_solution_vector. const_system_iterator pos = _systems.begin(); const const_system_iterator end = _systems.end(); for (; pos != end; ++pos) { // Check current system is listed in system_names, and skip pos if not bool use_current_system = (system_names == NULL); if (!use_current_system) use_current_system = system_names->count(pos->first); if (!use_current_system) continue; const System& system = *(pos->second); const unsigned int nv_sys = system.n_vars(); const unsigned int sys_num = system.number(); //Could this be replaced by a/some convenience methods?[PB] unsigned int n_scalar_vars = 0; unsigned int n_vector_vars = 0; for (unsigned int vn=0; vn<pos->second->n_vars(); vn++) { if( FEInterface::field_type(pos->second->variable_type(vn)) == TYPE_VECTOR ) n_vector_vars++; else n_scalar_vars++; } // Here, we're assuming the number of vector components is the same // as the mesh dimension. Will break for mixed dimension meshes. unsigned int nv_sys_split = n_scalar_vars + dim*n_vector_vars; // Update the current_local_solution { System & non_const_sys = const_cast<System &>(system); non_const_sys.solution->close(); non_const_sys.update(); } NumericVector<Number> & sys_soln(*system.current_local_solution); std::vector<Number> elem_soln; // The finite element solution std::vector<Number> nodal_soln; // The FE solution interpolated to the nodes std::vector<dof_id_type> dof_indices; // The DOF indices for the finite element for (unsigned int var=0; var<nv_sys; var++) { const FEType& fe_type = system.variable_type(var); const Variable &var_description = system.variable(var); const DofMap &dof_map = system.get_dof_map(); unsigned int n_vec_dim = FEInterface::n_vec_dim( pos->second->get_mesh(), fe_type ); MeshBase::element_iterator it = _mesh.active_local_elements_begin(); const MeshBase::element_iterator end_elem = _mesh.active_local_elements_end(); for ( ; it != end_elem; ++it) { const Elem* elem = *it; if (var_description.active_on_subdomain((*it)->subdomain_id())) { dof_map.dof_indices (elem, dof_indices, var); elem_soln.resize(dof_indices.size()); for (unsigned int i=0; i<dof_indices.size(); i++) elem_soln[i] = sys_soln(dof_indices[i]); FEInterface::nodal_soln (dim, fe_type, elem, elem_soln, nodal_soln); #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS // infinite elements should be skipped... if (!elem->infinite()) #endif { libmesh_assert_equal_to (nodal_soln.size(), n_vec_dim*elem->n_nodes()); for (unsigned int n=0; n<elem->n_nodes(); n++) { for( unsigned int d=0; d < n_vec_dim; d++ ) { // For vector-valued elements, all components are in nodal_soln. For each // node, the components are stored in order, i.e. node_0 -> s0_x, s0_y, s0_z parallel_soln.add(nv*(elem->node(n)) + (var+d + var_num), nodal_soln[n_vec_dim*n+d]); // Increment the repeat count for this position repeat_count.add(nv*(elem->node(n)) + (var+d + var_num), 1); } } } } else // If this variable doesn't exist on this subdomain we have to still increment repeat_count so that we won't divide by 0 later: for (unsigned int n=0; n<elem->n_nodes(); n++) // Only do this if this variable has NO DoFs at this node... it might have some from an ajoining element... if(!elem->get_node(n)->n_dofs(sys_num, var)) for( unsigned int d=0; d < n_vec_dim; d++ ) repeat_count.add(nv*(elem->node(n)) + (var+d + var_num), 1); } // end loop over elements } // end loop on variables in this system var_num += nv_sys_split; } // end loop over systems parallel_soln.close(); repeat_count.close(); // Divide to get the average value at the nodes parallel_soln /= repeat_count; parallel_soln.localize_to_one(soln); STOP_LOG("build_solution_vector()", "EquationSystems"); }
void MeshBase::cache_elem_dims() { // This requires an inspection on every processor parallel_object_only(); // Need to clear _elem_dims first in case all elements of a // particular dimension have been deleted. _elem_dims.clear(); const_element_iterator el = this->active_elements_begin(); const_element_iterator end = this->active_elements_end(); for (; el!=end; ++el) _elem_dims.insert((*el)->dim()); // Some different dimension elements may only live on other processors this->comm().set_union(_elem_dims); // If the largest element dimension found is larger than the current // _spatial_dimension, increase _spatial_dimension. unsigned int max_dim = this->mesh_dimension(); if (max_dim > _spatial_dimension) _spatial_dimension = cast_int<unsigned char>(max_dim); // _spatial_dimension may need to increase from 1->2 or 2->3 if the // mesh is full of 1D elements but they are not x-aligned, or the // mesh is full of 2D elements but they are not in the x-y plane. // If the mesh is x-aligned or x-y planar, we will end up checking // every node's coordinates and not breaking out of the loop // early... if (_spatial_dimension < 3) { const_node_iterator node_it = this->nodes_begin(); const_node_iterator node_end = this->nodes_end(); for (; node_it != node_end; ++node_it) { Node & node = **node_it; #if LIBMESH_DIM > 1 // Note: the exact floating point comparison is intentional, // we don't want to get tripped up by tolerances. if (node(1) != 0.) { _spatial_dimension = 2; #if LIBMESH_DIM == 2 // If libmesh is compiled in 2D mode, this is the // largest spatial dimension possible so we can break // out. break; #endif } #endif #if LIBMESH_DIM > 2 if (node(2) != 0.) { // Spatial dimension can't get any higher than this, so // we can break out. _spatial_dimension = 3; break; } #endif } } }
void MeshBase::detect_interior_parents() { // This requires an inspection on every processor parallel_object_only(); // Check if the mesh contains mixed dimensions. If so, then set interior parents, otherwise return. if (this->elem_dimensions().size() == 1) return; //This map will be used to set interior parents LIBMESH_BEST_UNORDERED_MAP<dof_id_type, std::vector<dof_id_type> > node_to_elem; const_element_iterator el = this->active_elements_begin(); const_element_iterator end = this->active_elements_end(); for (; el!=end; ++el) { const Elem * elem = *el; // Populating the node_to_elem map, same as MeshTools::build_nodes_to_elem_map for (unsigned int n=0; n<elem->n_vertices(); n++) { libmesh_assert_less (elem->id(), this->max_elem_id()); node_to_elem[elem->node(n)].push_back(elem->id()); } } // Automatically set interior parents el = this->elements_begin(); for (; el!=end; ++el) { Elem * element = *el; // Ignore an 3D element or an element that already has an interior parent if (element->dim()>=LIBMESH_DIM || element->interior_parent()) continue; // Start by generating a SET of elements that are dim+1 to the current // element at each vertex of the current element, thus ignoring interior nodes. // If one of the SET of elements is empty, then we will not have an interior parent // since an interior parent must be connected to all vertices of the current element std::vector< std::set<dof_id_type> > neighbors( element->n_vertices() ); bool found_interior_parents = false; for (dof_id_type n=0; n < element->n_vertices(); n++) { std::vector<dof_id_type> & element_ids = node_to_elem[element->node(n)]; for (std::vector<dof_id_type>::iterator e_it = element_ids.begin(); e_it != element_ids.end(); e_it++) { dof_id_type eid = *e_it; if (this->elem(eid)->dim() == element->dim()+1) neighbors[n].insert(eid); } if (neighbors[n].size()>0) { found_interior_parents = true; } else { // We have found an empty set, no reason to continue // Ensure we set this flag to false before the break since it could have // been set to true for previous vertex found_interior_parents = false; break; } } // If we have successfully generated a set of elements for each vertex, we will compare // the set for vertex 0 will the sets for the vertices until we find a id that exists in // all sets. If found, this is our an interior parent id. The interior parent id found // will be the lowest element id if there is potential for multiple interior parents. if (found_interior_parents) { std::set<dof_id_type> & neighbors_0 = neighbors[0]; for (std::set<dof_id_type>::iterator e_it = neighbors_0.begin(); e_it != neighbors_0.end(); e_it++) { found_interior_parents=false; dof_id_type interior_parent_id = *e_it; for (dof_id_type n=1; n < element->n_vertices(); n++) { if (neighbors[n].find(interior_parent_id)!=neighbors[n].end()) { found_interior_parents=true; } else { found_interior_parents=false; break; } } if (found_interior_parents) { element->set_interior_parent(this->elem(interior_parent_id)); break; } } } } }
void MeshRefinement::flag_elements_by_elem_fraction (const ErrorVector& error_per_cell, const Real refine_frac, const Real coarsen_frac, const unsigned int max_l) { parallel_object_only(); // The function arguments are currently just there for // backwards_compatibility if (!_use_member_parameters) { // If the user used non-default parameters, lets warn // that they're deprecated if (refine_frac != 0.3 || coarsen_frac != 0.0 || max_l != libMesh::invalid_uint) libmesh_deprecated(); _refine_fraction = refine_frac; _coarsen_fraction = coarsen_frac; _max_h_level = max_l; } // Check for valid fractions.. // The fraction values must be in [0,1] libmesh_assert_greater_equal (_refine_fraction, 0); libmesh_assert_less_equal (_refine_fraction, 1); libmesh_assert_greater_equal (_coarsen_fraction, 0); libmesh_assert_less_equal (_coarsen_fraction, 1); // The number of active elements in the mesh const dof_id_type n_active_elem = _mesh.n_elem(); // The number of elements to flag for coarsening const dof_id_type n_elem_coarsen = static_cast<dof_id_type>(_coarsen_fraction * n_active_elem); // The number of elements to flag for refinement const dof_id_type n_elem_refine = static_cast<dof_id_type>(_refine_fraction * n_active_elem); // Clean up the refinement flags. These could be left // over from previous refinement steps. this->clean_refinement_flags(); // This vector stores the error and element number for all the // active elements. It will be sorted and the top & bottom // elements will then be flagged for coarsening & refinement std::vector<ErrorVectorReal> sorted_error; sorted_error.reserve (n_active_elem); // Loop over the active elements and create the entry // in the sorted_error vector MeshBase::element_iterator elem_it = _mesh.active_local_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) sorted_error.push_back (error_per_cell[(*elem_it)->id()]); this->comm().allgather(sorted_error); // Now sort the sorted_error vector std::sort (sorted_error.begin(), sorted_error.end()); // If we're coarsening by parents: // Create a sorted error vector with coarsenable parent elements // only, sorted by lowest errors first ErrorVector error_per_parent, sorted_parent_error; if (_coarsen_by_parents) { Real parent_error_min, parent_error_max; create_parent_error_vector(error_per_cell, error_per_parent, parent_error_min, parent_error_max); sorted_parent_error = error_per_parent; std::sort (sorted_parent_error.begin(), sorted_parent_error.end()); // All the other error values will be 0., so get rid of them. sorted_parent_error.erase (std::remove(sorted_parent_error.begin(), sorted_parent_error.end(), 0.), sorted_parent_error.end()); } ErrorVectorReal top_error= 0., bottom_error = 0.; // Get the maximum error value corresponding to the // bottom n_elem_coarsen elements if (_coarsen_by_parents && n_elem_coarsen) { const unsigned int dim = _mesh.mesh_dimension(); unsigned int twotodim = 1; for (unsigned int i=0; i!=dim; ++i) twotodim *= 2; dof_id_type n_parent_coarsen = n_elem_coarsen / (twotodim - 1); if (n_parent_coarsen) bottom_error = sorted_parent_error[n_parent_coarsen - 1]; } else if (n_elem_coarsen) { bottom_error = sorted_error[n_elem_coarsen - 1]; } if (n_elem_refine) top_error = sorted_error[sorted_error.size() - n_elem_refine]; // Finally, let's do the element flagging elem_it = _mesh.active_elements_begin(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; Elem* parent = elem->parent(); if (_coarsen_by_parents && parent && n_elem_coarsen && error_per_parent[parent->id()] <= bottom_error) elem->set_refinement_flag(Elem::COARSEN); if (!_coarsen_by_parents && n_elem_coarsen && error_per_cell[elem->id()] <= bottom_error) elem->set_refinement_flag(Elem::COARSEN); if (n_elem_refine && elem->level() < _max_h_level && error_per_cell[elem->id()] >= top_error) elem->set_refinement_flag(Elem::REFINE); } }
bool MeshRefinement::limit_level_mismatch_at_edge (const unsigned int max_mismatch) { // This function must be run on all processors at once parallel_object_only(); bool flags_changed = false; // Maps holding the maximum element level that touches an edge std::map<std::pair<unsigned int, unsigned int>, unsigned char> max_level_at_edge; std::map<std::pair<unsigned int, unsigned int>, unsigned char> max_p_level_at_edge; // Loop over all the active elements & fill the maps { 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 edge for (unsigned int n=0; n<elem->n_edges(); n++) { UniquePtr<Elem> edge = elem->build_edge(n); dof_id_type childnode0 = edge->node(0); dof_id_type childnode1 = edge->node(1); if (childnode1 < childnode0) std::swap(childnode0, childnode1); for (const Elem *p = elem; p != NULL; p = p->parent()) { UniquePtr<Elem> pedge = p->build_edge(n); dof_id_type node0 = pedge->node(0); dof_id_type node1 = pedge->node(1); if (node1 < node0) std::swap(node0, node1); // If elem does not share this edge with its ancestor // p, refinement levels of elements sharing p's edge // are not restricted by refinement levels of elem. // Furthermore, elem will not share this edge with any // of p's ancestors, so we can safely break out of the // for loop early. if (node0 != childnode0 && node1 != childnode1) break; childnode0 = node0; childnode1 = node1; std::pair<unsigned int, unsigned int> edge_key = std::make_pair(node0, node1); if (max_level_at_edge.find(edge_key) == max_level_at_edge.end()) { max_level_at_edge[edge_key] = elem_level; max_p_level_at_edge[edge_key] = elem_p_level; } else { max_level_at_edge[edge_key] = std::max (max_level_at_edge[edge_key], elem_level); max_p_level_at_edge[edge_key] = std::max (max_p_level_at_edge[edge_key], 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 && !_enforce_mismatch_limit_prior_to_refinement) continue; // Loop over the nodes, check for possible mismatch for (unsigned int n=0; n<elem->n_edges(); n++) { UniquePtr<Elem> edge = elem->build_edge(n); dof_id_type node0 = edge->node(0); dof_id_type node1 = edge->node(1); if (node1 < node0) std::swap(node0, node1); std::pair<dof_id_type, dof_id_type> edge_key = std::make_pair(node0, node1); // Flag the element for refinement if it violates // the requested level mismatch if ((elem_level + max_mismatch) < max_level_at_edge[edge_key] && elem->refinement_flag() != Elem::REFINE) { elem->set_refinement_flag (Elem::REFINE); flags_changed = true; } if ((elem_p_level + max_mismatch) < max_p_level_at_edge[edge_key] && 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, EDGE, max_mismatch); } // loop over edges } // loop over active elements } // If flags changed on any processor then they changed globally this->comm().max(flags_changed); return flags_changed; }
//----------------------------------------------------------------- // Mesh refinement methods void MeshRefinement::flag_elements_by_error_fraction (const ErrorVector& error_per_cell, const Real refine_frac, const Real coarsen_frac, const unsigned int max_l) { parallel_object_only(); // The function arguments are currently just there for // backwards_compatibility if (!_use_member_parameters) { // If the user used non-default parameters, lets warn // that they're deprecated if (refine_frac != 0.3 || coarsen_frac != 0.0 || max_l != libMesh::invalid_uint) libmesh_deprecated(); _refine_fraction = refine_frac; _coarsen_fraction = coarsen_frac; _max_h_level = max_l; } // Check for valid fractions.. // The fraction values must be in [0,1] libmesh_assert_greater_equal (_refine_fraction, 0); libmesh_assert_less_equal (_refine_fraction, 1); libmesh_assert_greater_equal (_coarsen_fraction, 0); libmesh_assert_less_equal (_coarsen_fraction, 1); // Clean up the refinement flags. These could be left // over from previous refinement steps. this->clean_refinement_flags(); // We're getting the minimum and maximum error values // for the ACTIVE elements Real error_min = 1.e30; Real error_max = 0.; // And, if necessary, for their parents Real parent_error_min = 1.e30; Real parent_error_max = 0.; // Prepare another error vector if we need to sum parent errors ErrorVector error_per_parent; if (_coarsen_by_parents) { create_parent_error_vector(error_per_cell, error_per_parent, parent_error_min, parent_error_max); } // We need to loop over all active elements to find the minimum MeshBase::element_iterator el_it = _mesh.active_local_elements_begin(); const MeshBase::element_iterator el_end = _mesh.active_local_elements_end(); for (; el_it != el_end; ++el_it) { const dof_id_type id = (*el_it)->id(); libmesh_assert_less (id, error_per_cell.size()); error_max = std::max (error_max, error_per_cell[id]); error_min = std::min (error_min, error_per_cell[id]); } this->comm().max(error_max); this->comm().min(error_min); // Compute the cutoff values for coarsening and refinement const Real error_delta = (error_max - error_min); const Real parent_error_delta = parent_error_max - parent_error_min; const Real refine_cutoff = (1.- _refine_fraction)*error_max; const Real coarsen_cutoff = _coarsen_fraction*error_delta + error_min; const Real parent_cutoff = _coarsen_fraction*parent_error_delta + error_min; // // Print information about the error // libMesh::out << " Error Information:" << std::endl // << " ------------------" << std::endl // << " min: " << error_min << std::endl // << " max: " << error_max << std::endl // << " delta: " << error_delta << std::endl // << " refine_cutoff: " << refine_cutoff << std::endl // << " coarsen_cutoff: " << coarsen_cutoff << std::endl; // Loop over the elements and flag them for coarsening or // refinement based on the element error MeshBase::element_iterator e_it = _mesh.active_elements_begin(); const MeshBase::element_iterator e_end = _mesh.active_elements_end(); for (; e_it != e_end; ++e_it) { Elem* elem = *e_it; const dof_id_type id = elem->id(); libmesh_assert_less (id, error_per_cell.size()); const ErrorVectorReal elem_error = error_per_cell[id]; if (_coarsen_by_parents) { Elem* parent = elem->parent(); if (parent) { const dof_id_type parentid = parent->id(); if (error_per_parent[parentid] >= 0. && error_per_parent[parentid] <= parent_cutoff) elem->set_refinement_flag(Elem::COARSEN); } } // Flag the element for coarsening if its error // is <= coarsen_fraction*delta + error_min else if (elem_error <= coarsen_cutoff) { elem->set_refinement_flag(Elem::COARSEN); } // Flag the element for refinement if its error // is >= refinement_cutoff. if (elem_error >= refine_cutoff) if (elem->level() < _max_h_level) elem->set_refinement_flag(Elem::REFINE); } }
bool MeshRefinement::flag_elements_by_nelem_target (const ErrorVector& error_per_cell) { parallel_object_only(); // Check for valid fractions.. // The fraction values must be in [0,1] libmesh_assert_greater_equal (_refine_fraction, 0); libmesh_assert_less_equal (_refine_fraction, 1); libmesh_assert_greater_equal (_coarsen_fraction, 0); libmesh_assert_less_equal (_coarsen_fraction, 1); // This function is currently only coded to work when coarsening by // parents - it's too hard to guess how many coarsenings will be // performed otherwise. libmesh_assert (_coarsen_by_parents); // The number of active elements in the mesh - hopefully less than // 2 billion on 32 bit machines const dof_id_type n_active_elem = _mesh.n_active_elem(); // The maximum number of active elements to flag for coarsening const dof_id_type max_elem_coarsen = static_cast<dof_id_type>(_coarsen_fraction * n_active_elem) + 1; // The maximum number of elements to flag for refinement const dof_id_type max_elem_refine = static_cast<dof_id_type>(_refine_fraction * n_active_elem) + 1; // Clean up the refinement flags. These could be left // over from previous refinement steps. this->clean_refinement_flags(); // The target number of elements to add or remove const std::ptrdiff_t n_elem_new = _nelem_target - n_active_elem; // Create an vector with active element errors and ids, // sorted by highest errors first const dof_id_type max_elem_id = _mesh.max_elem_id(); std::vector<std::pair<ErrorVectorReal, dof_id_type> > sorted_error; sorted_error.reserve (n_active_elem); // On a ParallelMesh, we need to communicate to know which remote ids // correspond to active elements. { std::vector<bool> is_active(max_elem_id, false); MeshBase::element_iterator elem_it = _mesh.active_local_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { const dof_id_type eid = (*elem_it)->id(); is_active[eid] = true; libmesh_assert_less (eid, error_per_cell.size()); sorted_error.push_back (std::make_pair(error_per_cell[eid], eid)); } this->comm().max(is_active); this->comm().allgather(sorted_error); } // Default sort works since pairs are sorted lexicographically std::sort (sorted_error.begin(), sorted_error.end()); std::reverse (sorted_error.begin(), sorted_error.end()); // Create a sorted error vector with coarsenable parent elements // only, sorted by lowest errors first ErrorVector error_per_parent; std::vector<std::pair<ErrorVectorReal, dof_id_type> > sorted_parent_error; Real parent_error_min, parent_error_max; create_parent_error_vector(error_per_cell, error_per_parent, parent_error_min, parent_error_max); // create_parent_error_vector sets values for non-parents and // non-coarsenable parents to -1. Get rid of them. for (dof_id_type i=0; i != error_per_parent.size(); ++i) if (error_per_parent[i] != -1) sorted_parent_error.push_back(std::make_pair(error_per_parent[i], i)); std::sort (sorted_parent_error.begin(), sorted_parent_error.end()); // Keep track of how many elements we plan to coarsen & refine dof_id_type coarsen_count = 0; dof_id_type refine_count = 0; const unsigned int dim = _mesh.mesh_dimension(); unsigned int twotodim = 1; for (unsigned int i=0; i!=dim; ++i) twotodim *= 2; // First, let's try to get our element count to target_nelem if (n_elem_new >= 0) { // Every element refinement creates at least // 2^dim-1 new elements refine_count = std::min(libmesh_cast_int<dof_id_type>(n_elem_new / (twotodim-1)), max_elem_refine); } else { // Every successful element coarsening is likely to destroy // 2^dim-1 net elements. coarsen_count = std::min(libmesh_cast_int<dof_id_type>(-n_elem_new / (twotodim-1)), max_elem_coarsen); } // Next, let's see if we can trade any refinement for coarsening while (coarsen_count < max_elem_coarsen && refine_count < max_elem_refine && coarsen_count < sorted_parent_error.size() && refine_count < sorted_error.size() && sorted_error[refine_count].first > sorted_parent_error[coarsen_count].first * _coarsen_threshold) { coarsen_count++; refine_count++; } // On a ParallelMesh, we need to communicate to know which remote ids // correspond to refinable elements dof_id_type successful_refine_count = 0; { std::vector<bool> is_refinable(max_elem_id, false); for (dof_id_type i=0; i != sorted_error.size(); ++i) { dof_id_type eid = sorted_error[i].second; Elem *elem = _mesh.query_elem(eid); if (elem && elem->level() < _max_h_level) is_refinable[eid] = true; } this->comm().max(is_refinable); if (refine_count > max_elem_refine) refine_count = max_elem_refine; for (dof_id_type i=0; i != sorted_error.size(); ++i) { if (successful_refine_count >= refine_count) break; dof_id_type eid = sorted_error[i].second; Elem *elem = _mesh.query_elem(eid); if (is_refinable[eid]) { if (elem) elem->set_refinement_flag(Elem::REFINE); successful_refine_count++; } } } // If we couldn't refine enough elements, don't coarsen too many // either if (coarsen_count < (refine_count - successful_refine_count)) coarsen_count = 0; else coarsen_count -= (refine_count - successful_refine_count); if (coarsen_count > max_elem_coarsen) coarsen_count = max_elem_coarsen; dof_id_type successful_coarsen_count = 0; if (coarsen_count) { for (dof_id_type i=0; i != sorted_parent_error.size(); ++i) { if (successful_coarsen_count >= coarsen_count * twotodim) break; dof_id_type parent_id = sorted_parent_error[i].second; Elem *parent = _mesh.query_elem(parent_id); // On a ParallelMesh we skip remote elements if (!parent) continue; libmesh_assert(parent->has_children()); for (unsigned int c=0; c != parent->n_children(); ++c) { Elem *elem = parent->child(c); if (elem && elem != remote_elem) { libmesh_assert(elem->active()); elem->set_refinement_flag(Elem::COARSEN); successful_coarsen_count++; } } } } // Return true if we've done all the AMR/C we can if (!successful_coarsen_count && !successful_refine_count) return true; // And false if there may still be more to do. return false; }
void MeshRefinement::flag_elements_by_error_tolerance (const ErrorVector& error_per_cell_in) { parallel_object_only(); libmesh_assert_greater (_coarsen_threshold, 0); // Check for valid fractions.. // The fraction values must be in [0,1] libmesh_assert_greater_equal (_refine_fraction, 0); libmesh_assert_less_equal (_refine_fraction, 1); libmesh_assert_greater_equal (_coarsen_fraction, 0); libmesh_assert_less_equal (_coarsen_fraction, 1); // How much error per cell will we tolerate? const Real local_refinement_tolerance = _absolute_global_tolerance / std::sqrt(static_cast<Real>(_mesh.n_active_elem())); const Real local_coarsening_tolerance = local_refinement_tolerance * _coarsen_threshold; // Prepare another error vector if we need to sum parent errors ErrorVector error_per_parent; if (_coarsen_by_parents) { Real parent_error_min, parent_error_max; create_parent_error_vector(error_per_cell_in, error_per_parent, parent_error_min, parent_error_max); } 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; Elem* parent = elem->parent(); const dof_id_type elem_number = elem->id(); const ErrorVectorReal elem_error = error_per_cell_in[elem_number]; if (elem_error > local_refinement_tolerance && elem->level() < _max_h_level) elem->set_refinement_flag(Elem::REFINE); if (!_coarsen_by_parents && elem_error < local_coarsening_tolerance) elem->set_refinement_flag(Elem::COARSEN); if (_coarsen_by_parents && parent) { ErrorVectorReal parent_error = error_per_parent[parent->id()]; if (parent_error >= 0.) { const Real parent_coarsening_tolerance = std::sqrt(parent->n_children() * local_coarsening_tolerance * local_coarsening_tolerance); if (parent_error < parent_coarsening_tolerance) elem->set_refinement_flag(Elem::COARSEN); } } } }
bool MeshRefinement::limit_underrefined_boundary(const unsigned int max_mismatch) { // This function must be run on all processors at once parallel_object_only(); bool flags_changed = false; // Loop over all the active elements & look for mismatches to fix. { 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; // If we don't have an interior_parent then there's nothing to // be mismatched with. if ((elem->dim() >= LIBMESH_DIM) || !elem->interior_parent()) continue; // get all relevant interior elements std::set<const Elem*> neighbor_set; elem->find_interior_neighbors(neighbor_set); std::set<const Elem*>::iterator n_it = neighbor_set.begin(); for (; n_it != neighbor_set.end(); ++n_it) { // FIXME - non-const versions of the Elem set methods // would be nice const Elem* neighbor = *n_it; const unsigned char neighbor_level = cast_int<unsigned char> (neighbor->level() + ((neighbor->refinement_flag() == Elem::REFINE) ? 1 : 0)); const unsigned char neighbor_p_level = cast_int<unsigned char> (neighbor->p_level() + ((neighbor->p_refinement_flag() == Elem::REFINE) ? 1 : 0)); if (((neighbor_level + 1 - max_mismatch) > elem->level()) && (elem->refinement_flag() != Elem::REFINE)) { elem->set_refinement_flag(Elem::REFINE); flags_changed = true; } if (((neighbor_p_level + 1 - max_mismatch) > elem->p_level()) && (elem->p_refinement_flag() != Elem::REFINE)) { elem->set_p_refinement_flag(Elem::REFINE); flags_changed = true; } } // loop over interior neighbors } } return flags_changed; }
void EquationSystems::reinit () { parallel_object_only(); const unsigned int n_sys = this->n_systems(); libmesh_assert_not_equal_to (n_sys, 0); // We may have added new systems since our last // EquationSystems::(re)init call bool _added_new_systems = false; for (unsigned int i=0; i != n_sys; ++i) if (!this->get_system(i).is_initialized()) _added_new_systems = true; if (_added_new_systems) { // Our DofObjects will need space for the additional systems 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_it)->set_n_systems(n_sys); 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_it)->set_n_systems(n_sys); // And any new systems will need initialization for (unsigned int i=0; i != n_sys; ++i) if (!this->get_system(i).is_initialized()) this->get_system(i).init(); } #ifdef DEBUG // Make sure all the \p DofObject entities know how many systems // there are. { // All the nodes 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_equal_to (node->n_systems(), this->n_systems()); } // All the 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; libmesh_assert_equal_to (elem->n_systems(), this->n_systems()); } } #endif // Localize each system's vectors for (unsigned int i=0; i != this->n_systems(); ++i) this->get_system(i).re_update(); #ifdef LIBMESH_ENABLE_AMR bool dof_constraints_created = false; bool mesh_changed = false; // FIXME: For backwards compatibility, assume // refine_and_coarsen_elements or refine_uniformly have already // been called { for (unsigned int i=0; i != this->n_systems(); ++i) { System &sys = this->get_system(i); // Even if the system doesn't have any variables in it we want // consistent behavior; e.g. distribute_dofs should have the // opportunity to count up zero dofs on each processor. // // Who's been adding zero-var systems anyway, outside of my // unit tests? - RHS // if(!sys.n_vars()) // continue; sys.get_dof_map().distribute_dofs(_mesh); // Recreate any user or internal constraints sys.reinit_constraints(); sys.prolong_vectors(); } mesh_changed = true; dof_constraints_created = true; } // FIXME: Where should the user set maintain_level_one now?? // Don't override previous settings, for now MeshRefinement mesh_refine(_mesh); mesh_refine.face_level_mismatch_limit() = false; // Try to coarsen the mesh, then restrict each system's vectors // if necessary if (mesh_refine.coarsen_elements()) { for (unsigned int i=0; i != this->n_systems(); ++i) { System &sys = this->get_system(i); if (!dof_constraints_created) { sys.get_dof_map().distribute_dofs(_mesh); sys.reinit_constraints(); } sys.restrict_vectors(); } mesh_changed = true; dof_constraints_created = true; } // Once vectors are all restricted, we can delete // children of coarsened elements if (mesh_changed) this->get_mesh().contract(); // Try to refine the mesh, then prolong each system's vectors // if necessary if (mesh_refine.refine_elements()) { for (unsigned int i=0; i != this->n_systems(); ++i) { System &sys = this->get_system(i); if (!dof_constraints_created) { sys.get_dof_map().distribute_dofs(_mesh); sys.reinit_constraints(); } sys.prolong_vectors(); } mesh_changed = true; // dof_constraints_created = true; } // If the mesh has changed, systems will need to create new dof // constraints and update their global solution vectors if (mesh_changed) { for (unsigned int i=0; i != this->n_systems(); ++i) this->get_system(i).reinit(); } #endif // #ifdef LIBMESH_ENABLE_AMR }
void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors) { parallel_object_only(); libmesh_assert(this->comm().verify(this->is_serial())); // A distributed mesh may have processors with no elements (or // processors with no elements of higher dimension, if we ever // support mixed-dimension meshes), but we want consistent // mesh_dimension anyways. // // cache_elem_dims() should get the elem_dimensions() and // mesh_dimension() correct later, and we don't need it earlier. // Renumber the nodes and elements so that they in contiguous // blocks. By default, _skip_renumber_nodes_and_elements is false. // // We may currently change that by passing // skip_renumber_nodes_and_elements==true to this function, but we // should use the allow_renumbering() accessor instead. // // Instances where you if prepare_for_use() should not renumber the nodes // and elements include reading in e.g. an xda/r or gmv file. In // this case, the ordering of the nodes may depend on an accompanying // solution, and the node ordering cannot be changed. if (skip_renumber_nodes_and_elements) { libmesh_deprecated(); this->allow_renumbering(false); } // Mesh modification operations might not leave us with consistent // id counts, but our partitioner might need that consistency. if(!_skip_renumber_nodes_and_elements) this->renumber_nodes_and_elements(); else this->update_parallel_id_counts(); // Let all the elements find their neighbors if(!skip_find_neighbors) this->find_neighbors(); // The user may have set boundary conditions. We require that the // boundary conditions were set consistently. Because we examine // neighbors when evaluating non-raw boundary condition IDs, this // assert is only valid when our neighbor links are in place. #ifdef DEBUG MeshTools::libmesh_assert_valid_boundary_ids(*this); #endif // Search the mesh for all the dimensions of the elements // and cache them. this->cache_elem_dims(); // Search the mesh for elements that have a neighboring element // of dim+1 and set that element as the interior parent this->detect_interior_parents(); // Fix up node unique ids in case mesh generation code didn't take // exceptional care to do so. // MeshCommunication().make_node_unique_ids_parallel_consistent(*this); // We're going to still require that mesh generation code gets // element unique ids consistent. #if defined(DEBUG) && defined(LIBMESH_ENABLE_UNIQUE_ID) MeshTools::libmesh_assert_valid_unique_ids(*this); #endif // Reset our PointLocator. Any old locator is invalidated any time // the elements in the underlying elements in the mesh have changed, // so we clear it here. this->clear_point_locator(); // Allow our GhostingFunctor objects to reinit if necessary. // Do this before partitioning and redistributing, and before // deleting remote elements. std::set<GhostingFunctor *>::iterator gf_it = this->ghosting_functors_begin(); const std::set<GhostingFunctor *>::iterator gf_end = this->ghosting_functors_end(); for (; gf_it != gf_end; ++gf_it) { GhostingFunctor *gf = *gf_it; libmesh_assert(gf); gf->mesh_reinit(); } // Partition the mesh. this->partition(); // If we're using DistributedMesh, we'll probably want it // parallelized. if (this->_allow_remote_element_removal) this->delete_remote_elements(); if(!_skip_renumber_nodes_and_elements) this->renumber_nodes_and_elements(); // The mesh is now prepared for use. _is_prepared = true; #if defined(DEBUG) && defined(LIBMESH_ENABLE_UNIQUE_ID) MeshTools::libmesh_assert_valid_unique_ids(*this); #endif }
void MeshfreeInterpolation::gather_remote_data () { #ifndef LIBMESH_HAVE_MPI // no MPI -- no-op return; #else // This function must be run on all processors at once parallel_object_only(); START_LOG ("gather_remote_data()", "MeshfreeInterpolation"); // block to avoid incorrect completion if called in quick succession on // two different MeshfreeInterpolation objects this->comm().barrier(); std::vector<Real> send_buf, recv_buf; libmesh_assert_equal_to (_src_vals.size(), _src_pts.size()*this->n_field_variables()); send_buf.reserve (_src_pts.size()*(3 + this->n_field_variables())); // Everyone packs their data at the same time for (unsigned int p_idx=0, v_idx=0; p_idx<_src_pts.size(); p_idx++) { const Point &pt(_src_pts[p_idx]); send_buf.push_back(pt(0)); send_buf.push_back(pt(1)); send_buf.push_back(pt(2)); for (unsigned int var=0; var<this->n_field_variables(); var++) { libmesh_assert_less (v_idx, _src_vals.size()); #ifdef LIBMESH_USE_COMPLEX_NUMBERS send_buf.push_back (_src_vals[v_idx].real()); send_buf.push_back (_src_vals[v_idx].imag()); v_idx++; #else send_buf.push_back (_src_vals[v_idx++]); #endif } } // Send our data to everyone else. Note that MPI-1 said you could not // use the same buffer in nonblocking sends, but that restriction has // recently been removed. std::vector<Parallel::Request> send_request(this->n_processors()-1); // Use a tag for best practices. In debug mode parallel_only() blocks above // so we can be sure there is no other shenanigarry going on, but in optimized // mode there is no such guarantee - other prcoessors could be somewhere else // completing some other communication, and we don't want to intercept that. Parallel::MessageTag tag = this->comm().get_unique_tag ( 6000 ); for (unsigned int proc=0, cnt=0; proc<this->n_processors(); proc++) if (proc != this->processor_id()) this->comm().send (proc, send_buf, send_request[cnt++], tag); // All data has been sent. Receive remote data in any order for (processor_id_type comm_step=0; comm_step<(this->n_processors()-1); comm_step++) { // blocking receive this->comm().receive (Parallel::any_source, recv_buf, tag); // Add their data to our list Point pt; Number val; std::vector<Real>::const_iterator it=recv_buf.begin(); while (it != recv_buf.end()) { pt(0) = *it, ++it; pt(1) = *it, ++it; pt(2) = *it, ++it; _src_pts.push_back(pt); for (unsigned int var=0; var<this->n_field_variables(); var++) { #ifdef LIBMESH_USE_COMPLEX_NUMBERS Real re = *it; ++it; Real im = *it; ++it; val = Number(re,im); #else val = *it, ++it; #endif _src_vals.push_back(val); } } } Parallel::wait (send_request); STOP_LOG ("gather_remote_data()", "MeshfreeInterpolation"); #endif // LIBMESH_HAVE_MPI }