//----------------------------------------------------------------- // 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_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 unsigned int 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]); } CommWorld.max(error_max); CommWorld.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 unsigned int id = elem->id(); libmesh_assert_less (id, error_per_cell.size()); const float elem_error = error_per_cell[id]; if (_coarsen_by_parents) { Elem* parent = elem->parent(); if (parent) { const unsigned int 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); } }
void InfPrism12::connectivity(const unsigned int sc, const IOPackage iop, std::vector<dof_id_type>& conn) const { libmesh_assert(_nodes); libmesh_assert_less (sc, this->n_sub_elem()); libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE); switch (iop) { case TECPLOT: { conn.resize(8); switch (sc) { case 0: // guess this is a collapsed hex8 conn[0] = this->node(0)+1; conn[1] = this->node(6)+1; conn[2] = this->node(8)+1; conn[3] = this->node(8)+1; conn[4] = this->node(3)+1; conn[5] = this->node(9)+1; conn[6] = this->node(11)+1; conn[7] = this->node(11)+1; return; case 1: conn[0] = this->node(6)+1; conn[1] = this->node(7)+1; conn[2] = this->node(8)+1; conn[3] = this->node(8)+1; conn[4] = this->node(9)+1; conn[5] = this->node(10)+1; conn[6] = this->node(11)+1; conn[7] = this->node(11)+1; return; case 2: conn[0] = this->node(6)+1; conn[1] = this->node(1)+1; conn[2] = this->node(7)+1; conn[3] = this->node(7)+1; conn[4] = this->node(9)+1; conn[5] = this->node(4)+1; conn[6] = this->node(10)+1; conn[7] = this->node(10)+1; return; case 3: conn[0] = this->node(8)+1; conn[1] = this->node(7)+1; conn[2] = this->node(2)+1; conn[3] = this->node(2)+1; conn[4] = this->node(11)+1; conn[5] = this->node(10)+1; conn[6] = this->node(5)+1; conn[7] = this->node(5)+1; return; default: libmesh_error(); } } default: libmesh_error(); } libmesh_error(); }
RealGradient FE<2,NEDELEC_ONE>::shape_second_deriv(const Elem* elem, const Order order, const unsigned int i, const unsigned int j, const Point&) { #if LIBMESH_DIM > 1 libmesh_assert(elem); // j = 0 ==> d^2 phi / dxi^2 // j = 1 ==> d^2 phi / dxi deta // j = 2 ==> d^2 phi / deta^2 libmesh_assert_less (j, 3); const Order total_order = static_cast<Order>(order + elem->p_level()); switch (total_order) { // linear Lagrange shape functions case FIRST: { switch (elem->type()) { case QUAD8: case QUAD9: { libmesh_assert_less (i, 4); // All second derivatives for linear quads are zero. return RealGradient(); } case TRI6: { libmesh_assert_less (i, 3); // All second derivatives for linear triangles are zero. return RealGradient(); } default: { libMesh::err << "ERROR: Unsupported 2D element type!: " << elem->type() << std::endl; libmesh_error(); } } // end switch (type) } // end case FIRST // unsupported order default: { libMesh::err << "ERROR: Unsupported 2D FE order!: " << total_order << std::endl; libmesh_error(); } } // end switch (order) #endif // LIBMESH_DIM > 1 libmesh_error(); return RealGradient(); }
void InfHex18::connectivity(const unsigned int sc, const IOPackage iop, std::vector<dof_id_type>& conn) const { libmesh_assert(_nodes); libmesh_assert_less (sc, this->n_sub_elem()); libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE); switch (iop) { case TECPLOT: { switch (sc) { case 0: conn[0] = this->node(0)+1; conn[1] = this->node(8)+1; conn[2] = this->node(16)+1; conn[3] = this->node(11)+1; conn[4] = this->node(4)+1; conn[5] = this->node(12)+1; conn[6] = this->node(17)+1; conn[7] = this->node(15)+1; return; case 1: conn[0] = this->node(8)+1; conn[1] = this->node(1)+1; conn[2] = this->node(9)+1; conn[3] = this->node(16)+1; conn[4] = this->node(12)+1; conn[5] = this->node(5)+1; conn[6] = this->node(13)+1; conn[7] = this->node(17)+1; return; case 2: conn[0] = this->node(11)+1; conn[1] = this->node(16)+1; conn[2] = this->node(10)+1; conn[3] = this->node(3)+1; conn[4] = this->node(15)+1; conn[5] = this->node(17)+1; conn[6] = this->node(14)+1; conn[7] = this->node(7)+1; return; case 3: conn[0] = this->node(16)+1; conn[1] = this->node(9)+1; conn[2] = this->node(2)+1; conn[3] = this->node(10)+1; conn[4] = this->node(17)+1; conn[5] = this->node(13)+1; conn[6] = this->node(6)+1; conn[7] = this->node(14)+1; return; default: libmesh_error_msg("Invalid sc = " << sc); } } default: libmesh_error_msg("Unsupported IO package " << iop); } }
bool InfEdge2::is_node_on_side(const unsigned int n, const unsigned int s) const { libmesh_assert_less (s, 1); return (s == n); }
AutoPtr<Elem> Tet10::build_side (const unsigned int i, bool proxy) const { libmesh_assert_less (i, this->n_sides()); if (proxy) { AutoPtr<Elem> ap(new Side<Tri6,Tet10>(this,i)); return ap; } else { AutoPtr<Elem> face(new Tri6); switch (i) { case 0: { face->set_node(0) = this->get_node(0); face->set_node(1) = this->get_node(2); face->set_node(2) = this->get_node(1); face->set_node(3) = this->get_node(6); face->set_node(4) = this->get_node(5); face->set_node(5) = this->get_node(4); return face; } case 1: { face->set_node(0) = this->get_node(0); face->set_node(1) = this->get_node(1); face->set_node(2) = this->get_node(3); face->set_node(3) = this->get_node(4); face->set_node(4) = this->get_node(8); face->set_node(5) = this->get_node(7); return face; } case 2: { face->set_node(0) = this->get_node(1); face->set_node(1) = this->get_node(2); face->set_node(2) = this->get_node(3); face->set_node(3) = this->get_node(5); face->set_node(4) = this->get_node(9); face->set_node(5) = this->get_node(8); return face; } case 3: { face->set_node(0) = this->get_node(2); face->set_node(1) = this->get_node(0); face->set_node(2) = this->get_node(3); face->set_node(3) = this->get_node(6); face->set_node(4) = this->get_node(7); face->set_node(5) = this->get_node(9); return face; } default: { libmesh_error(); } } } // We'll never get here. libmesh_error(); AutoPtr<Elem> ap(NULL); return ap; }
void Tet10::connectivity(const unsigned int sc, const IOPackage iop, std::vector<unsigned int>& conn) const { libmesh_assert(_nodes); libmesh_assert_less (sc, this->n_sub_elem()); libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE); switch (iop) { case TECPLOT: { conn.resize(8); switch (sc) { // Linear sub-tet 0 case 0: conn[0] = this->node(0)+1; conn[1] = this->node(4)+1; conn[2] = this->node(6)+1; conn[3] = this->node(6)+1; conn[4] = this->node(7)+1; conn[5] = this->node(7)+1; conn[6] = this->node(7)+1; conn[7] = this->node(7)+1; return; // Linear sub-tet 1 case 1: conn[0] = this->node(4)+1; conn[1] = this->node(1)+1; conn[2] = this->node(5)+1; conn[3] = this->node(5)+1; conn[4] = this->node(8)+1; conn[5] = this->node(8)+1; conn[6] = this->node(8)+1; conn[7] = this->node(8)+1; return; // Linear sub-tet 2 case 2: conn[0] = this->node(5)+1; conn[1] = this->node(2)+1; conn[2] = this->node(6)+1; conn[3] = this->node(6)+1; conn[4] = this->node(9)+1; conn[5] = this->node(9)+1; conn[6] = this->node(9)+1; conn[7] = this->node(9)+1; return; // Linear sub-tet 3 case 3: conn[0] = this->node(7)+1; conn[1] = this->node(8)+1; conn[2] = this->node(9)+1; conn[3] = this->node(9)+1; conn[4] = this->node(3)+1; conn[5] = this->node(3)+1; conn[6] = this->node(3)+1; conn[7] = this->node(3)+1; return; // Linear sub-tet 4 case 4: conn[0] = this->node(4)+1; conn[1] = this->node(8)+1; conn[2] = this->node(6)+1; conn[3] = this->node(6)+1; conn[4] = this->node(7)+1; conn[5] = this->node(7)+1; conn[6] = this->node(7)+1; conn[7] = this->node(7)+1; return; // Linear sub-tet 5 case 5: conn[0] = this->node(4)+1; conn[1] = this->node(5)+1; conn[2] = this->node(6)+1; conn[3] = this->node(6)+1; conn[4] = this->node(8)+1; conn[5] = this->node(8)+1; conn[6] = this->node(8)+1; conn[7] = this->node(8)+1; return; // Linear sub-tet 6 case 6: conn[0] = this->node(5)+1; conn[1] = this->node(9)+1; conn[2] = this->node(6)+1; conn[3] = this->node(6)+1; conn[4] = this->node(8)+1; conn[5] = this->node(8)+1; conn[6] = this->node(8)+1; conn[7] = this->node(8)+1; return; // Linear sub-tet 7 case 7: conn[0] = this->node(7)+1; conn[1] = this->node(6)+1; conn[2] = this->node(9)+1; conn[3] = this->node(9)+1; conn[4] = this->node(8)+1; conn[5] = this->node(8)+1; conn[6] = this->node(8)+1; conn[7] = this->node(8)+1; return; default: libmesh_error(); } } case VTK: { conn.resize(10); conn[0] = this->node(0); conn[1] = this->node(1); conn[2] = this->node(2); conn[3] = this->node(3); conn[4] = this->node(4); conn[5] = this->node(5); conn[6] = this->node(6); conn[7] = this->node(7); conn[8] = this->node(8); conn[9] = this->node(9); return; /* conn.resize(4); switch (sc) { // Linear sub-tet 0 case 0: conn[0] = this->node(0); conn[1] = this->node(4); conn[2] = this->node(6); conn[3] = this->node(7); return; // Linear sub-tet 1 case 1: conn[0] = this->node(4); conn[1] = this->node(1); conn[2] = this->node(5); conn[3] = this->node(8); return; // Linear sub-tet 2 case 2: conn[0] = this->node(5); conn[1] = this->node(2); conn[2] = this->node(6); conn[3] = this->node(9); return; // Linear sub-tet 3 case 3: conn[0] = this->node(7); conn[1] = this->node(8); conn[2] = this->node(9); conn[3] = this->node(3); return; // Linear sub-tet 4 case 4: conn[0] = this->node(4); conn[1] = this->node(8); conn[2] = this->node(6); conn[3] = this->node(7); return; // Linear sub-tet 5 case 5: conn[0] = this->node(4); conn[1] = this->node(5); conn[2] = this->node(6); conn[3] = this->node(8); return; // Linear sub-tet 6 case 6: conn[0] = this->node(5); conn[1] = this->node(9); conn[2] = this->node(6); conn[3] = this->node(8); return; // Linear sub-tet 7 case 7: conn[0] = this->node(7); conn[1] = this->node(6); conn[2] = this->node(9); conn[3] = this->node(8); return; default: libmesh_error(); } */ } default: libmesh_error(); } libmesh_error(); }
AutoPtr<Elem> Prism15::build_side (const unsigned int i, bool proxy) const { libmesh_assert_less (i, this->n_sides()); if (proxy) { switch (i) { case 0: // the triangular face at z=-1 case 4: { AutoPtr<Elem> face(new Side<Tri6,Prism15>(this,i)); return face; } case 1: case 2: case 3: { AutoPtr<Elem> face(new Side<Quad8,Prism15>(this,i)); return face; } default: { libmesh_error(); } } } else { // Create NULL pointer to be initialized, returned later. AutoPtr<Elem> face(NULL); switch (i) { case 0: // the triangular face at z=-1 { face.reset(new Tri6); face->set_node(0) = this->get_node(0); face->set_node(1) = this->get_node(2); face->set_node(2) = this->get_node(1); face->set_node(3) = this->get_node(8); face->set_node(4) = this->get_node(7); face->set_node(5) = this->get_node(6); break; } case 1: // the quad face at y=0 { face.reset(new Quad8); face->set_node(0) = this->get_node(0); face->set_node(1) = this->get_node(1); face->set_node(2) = this->get_node(4); face->set_node(3) = this->get_node(3); face->set_node(4) = this->get_node(6); face->set_node(5) = this->get_node(10); face->set_node(6) = this->get_node(12); face->set_node(7) = this->get_node(9); break; } case 2: // the other quad face { face.reset(new Quad8); face->set_node(0) = this->get_node(1); face->set_node(1) = this->get_node(2); face->set_node(2) = this->get_node(5); face->set_node(3) = this->get_node(4); face->set_node(4) = this->get_node(7); face->set_node(5) = this->get_node(11); face->set_node(6) = this->get_node(13); face->set_node(7) = this->get_node(10); break; } case 3: // the quad face at x=0 { face.reset(new Quad8); face->set_node(0) = this->get_node(2); face->set_node(1) = this->get_node(0); face->set_node(2) = this->get_node(3); face->set_node(3) = this->get_node(5); face->set_node(4) = this->get_node(8); face->set_node(5) = this->get_node(9); face->set_node(6) = this->get_node(14); face->set_node(7) = this->get_node(11); break; } case 4: // the triangular face at z=1 { face.reset(new Tri6); face->set_node(0) = this->get_node(3); face->set_node(1) = this->get_node(4); face->set_node(2) = this->get_node(5); face->set_node(3) = this->get_node(12); face->set_node(4) = this->get_node(13); face->set_node(5) = this->get_node(14); break; } default: { libmesh_error(); } } face->subdomain_id() = this->subdomain_id(); return face; } // We'll never get here. libmesh_error(); AutoPtr<Elem> ap(NULL); return ap; }
void Prism15::connectivity(const unsigned int libmesh_dbg_var(sc), const IOPackage iop, std::vector<dof_id_type>& conn) const { libmesh_assert(_nodes); libmesh_assert_less (sc, this->n_sub_elem()); libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE); switch (iop) { case TECPLOT: { conn.resize(8); conn[0] = this->node(0)+1; conn[1] = this->node(1)+1; conn[2] = this->node(2)+1; conn[3] = this->node(2)+1; conn[4] = this->node(3)+1; conn[5] = this->node(4)+1; conn[6] = this->node(5)+1; conn[7] = this->node(5)+1; return; } case VTK: { /* conn.resize(6); conn[0] = this->node(0); conn[1] = this->node(2); conn[2] = this->node(1); conn[3] = this->node(3); conn[4] = this->node(5); conn[5] = this->node(4); */ // VTK's VTK_QUADRATIC_WEDGE first 9 nodes match, then their // middle and top layers of mid-edge nodes are reversed from // LibMesh's. conn.resize(15); for (unsigned i=0; i<9; ++i) conn[i] = this->node(i); // top "ring" of mid-edge nodes conn[9] = this->node(12); conn[10] = this->node(13); conn[11] = this->node(14); // middle "ring" of mid-edge nodes conn[12] = this->node(9); conn[13] = this->node(10); conn[14] = this->node(11); return; } default: libmesh_error(); } libmesh_error(); }
// ------------------------------------------------------------ // MetisPartitioner implementation void MetisPartitioner::_do_partition (MeshBase & mesh, const unsigned int n_pieces) { libmesh_assert_greater (n_pieces, 0); libmesh_assert (mesh.is_serial()); // Check for an easy return if (n_pieces == 1) { this->single_partition (mesh); return; } // What to do if the Metis library IS NOT present #ifndef LIBMESH_HAVE_METIS libmesh_here(); libMesh::err << "ERROR: The library has been built without" << std::endl << "Metis support. Using a space-filling curve" << std::endl << "partitioner instead!" << std::endl; SFCPartitioner sfcp; sfcp.partition (mesh, n_pieces); // What to do if the Metis library IS present #else LOG_SCOPE("partition()", "MetisPartitioner"); const dof_id_type n_active_elem = mesh.n_active_elem(); // build the graph // std::vector<Metis::idx_t> options(5); std::vector<Metis::idx_t> vwgt(n_active_elem); std::vector<Metis::idx_t> part(n_active_elem); Metis::idx_t n = static_cast<Metis::idx_t>(n_active_elem), // number of "nodes" (elements) // in the graph // wgtflag = 2, // weights on vertices only, // // none on edges // numflag = 0, // C-style 0-based numbering nparts = static_cast<Metis::idx_t>(n_pieces), // number of subdomains to create edgecut = 0; // the numbers of edges cut by the // resulting partition // Set the options // options[0] = 0; // use default options // Metis will only consider the active elements. // We need to map the active element ids into a // contiguous range. Further, we want the unique range indexing to be // independent of the element ordering, otherwise a circular dependency // can result in which the partitioning depends on the ordering which // depends on the partitioning... vectormap<dof_id_type, dof_id_type> global_index_map; global_index_map.reserve (n_active_elem); { std::vector<dof_id_type> global_index; MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); MeshCommunication().find_global_indices (mesh.comm(), MeshTools::bounding_box(mesh), it, end, global_index); libmesh_assert_equal_to (global_index.size(), n_active_elem); for (std::size_t cnt=0; it != end; ++it) { const Elem * elem = *it; global_index_map.insert (std::make_pair(elem->id(), global_index[cnt++])); } libmesh_assert_equal_to (global_index_map.size(), n_active_elem); } // If we have boundary elements in this mesh, we want to account for // the connectivity between them and interior elements. We can find // interior elements from boundary elements, but we need to build up // a lookup map to do the reverse. typedef LIBMESH_BEST_UNORDERED_MULTIMAP<const Elem *, const Elem *> map_type; map_type interior_to_boundary_map; { MeshBase::const_element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem * elem = *elem_it; // If we don't have an interior_parent then there's nothing to look us // up. 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 Elem * neighbor = const_cast<Elem *>(*n_it); #if defined(LIBMESH_HAVE_UNORDERED_MULTIMAP) || \ defined(LIBMESH_HAVE_TR1_UNORDERED_MULTIMAP) || \ defined(LIBMESH_HAVE_HASH_MULTIMAP) || \ defined(LIBMESH_HAVE_EXT_HASH_MULTIMAP) interior_to_boundary_map.insert (std::make_pair(neighbor, elem)); #else interior_to_boundary_map.insert (interior_to_boundary_map.begin(), std::make_pair(neighbor, elem)); #endif } } } // Invoke METIS, but only on processor 0. // Then broadcast the resulting decomposition if (mesh.processor_id() == 0) { METIS_CSR_Graph<Metis::idx_t> csr_graph; csr_graph.offsets.resize(n_active_elem+1, 0); // Local scope for these { // build the graph in CSR format. Note that // the edges in the graph will correspond to // face neighbors #ifdef LIBMESH_ENABLE_AMR std::vector<const Elem *> neighbors_offspring; #endif MeshBase::element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = mesh.active_elements_end(); #ifndef NDEBUG std::size_t graph_size=0; #endif // (1) first pass - get the row sizes for each element by counting the number // of face neighbors. Also populate the vwght array if necessary for (; elem_it != elem_end; ++elem_it) { const Elem * elem = *elem_it; const dof_id_type elem_global_index = global_index_map[elem->id()]; libmesh_assert_less (elem_global_index, vwgt.size()); // maybe there is a better weight? // The weight is used to define what a balanced graph is if(!_weights) vwgt[elem_global_index] = elem->n_nodes(); else vwgt[elem_global_index] = static_cast<Metis::idx_t>((*_weights)[elem->id()]); unsigned int num_neighbors = 0; // Loop over the element's neighbors. An element // adjacency corresponds to a face neighbor for (unsigned int ms=0; ms<elem->n_neighbors(); ms++) { const Elem * neighbor = elem->neighbor(ms); if (neighbor != libmesh_nullptr) { // If the neighbor is active treat it // as a connection if (neighbor->active()) num_neighbors++; #ifdef LIBMESH_ENABLE_AMR // Otherwise we need to find all of the // neighbor's children that are connected to // us and add them else { // The side of the neighbor to which // we are connected const unsigned int ns = neighbor->which_neighbor_am_i (elem); libmesh_assert_less (ns, neighbor->n_neighbors()); // Get all the active children (& grandchildren, etc...) // of the neighbor. // FIXME - this is the wrong thing, since we // should be getting the active family tree on // our side only. But adding too many graph // links may cause hanging nodes to tend to be // on partition interiors, which would reduce // communication overhead for constraint // equations, so we'll leave it. neighbor->active_family_tree (neighbors_offspring); // Get all the neighbor's children that // live on that side and are thus connected // to us for (unsigned int nc=0; nc<neighbors_offspring.size(); nc++) { const Elem * child = neighbors_offspring[nc]; // This does not assume a level-1 mesh. // Note that since children have sides numbered // coincident with the parent then this is a sufficient test. if (child->neighbor(ns) == elem) { libmesh_assert (child->active()); num_neighbors++; } } } #endif /* ifdef LIBMESH_ENABLE_AMR */ } } // Check for any interior neighbors if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent()) { // get all relevant interior elements std::set<const Elem *> neighbor_set; elem->find_interior_neighbors(neighbor_set); num_neighbors += neighbor_set.size(); } // Check for any boundary neighbors typedef map_type::iterator map_it_type; std::pair<map_it_type, map_it_type> bounds = interior_to_boundary_map.equal_range(elem); num_neighbors += std::distance(bounds.first, bounds.second); csr_graph.prep_n_nonzeros(elem_global_index, num_neighbors); #ifndef NDEBUG graph_size += num_neighbors; #endif } csr_graph.prepare_for_use(); // (2) second pass - fill the compressed adjacency array elem_it = mesh.active_elements_begin(); for (; elem_it != elem_end; ++elem_it) { const Elem * elem = *elem_it; const dof_id_type elem_global_index = global_index_map[elem->id()]; unsigned int connection=0; // Loop over the element's neighbors. An element // adjacency corresponds to a face neighbor for (unsigned int ms=0; ms<elem->n_neighbors(); ms++) { const Elem * neighbor = elem->neighbor(ms); if (neighbor != libmesh_nullptr) { // If the neighbor is active treat it // as a connection if (neighbor->active()) csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()]; #ifdef LIBMESH_ENABLE_AMR // Otherwise we need to find all of the // neighbor's children that are connected to // us and add them else { // The side of the neighbor to which // we are connected const unsigned int ns = neighbor->which_neighbor_am_i (elem); libmesh_assert_less (ns, neighbor->n_neighbors()); // Get all the active children (& grandchildren, etc...) // of the neighbor. neighbor->active_family_tree (neighbors_offspring); // Get all the neighbor's children that // live on that side and are thus connected // to us for (unsigned int nc=0; nc<neighbors_offspring.size(); nc++) { const Elem * child = neighbors_offspring[nc]; // This does not assume a level-1 mesh. // Note that since children have sides numbered // coincident with the parent then this is a sufficient test. if (child->neighbor(ns) == elem) { libmesh_assert (child->active()); csr_graph(elem_global_index, connection++) = global_index_map[child->id()]; } } } #endif /* ifdef LIBMESH_ENABLE_AMR */ } } if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent()) { // 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 Elem * neighbor = const_cast<Elem *>(*n_it); csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()]; } } // Check for any boundary neighbors typedef map_type::iterator map_it_type; std::pair<map_it_type, map_it_type> bounds = interior_to_boundary_map.equal_range(elem); for (map_it_type it = bounds.first; it != bounds.second; ++it) { const Elem * neighbor = it->second; csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()]; } } // We create a non-empty vals for a disconnected graph, to // work around a segfault from METIS. libmesh_assert_equal_to (csr_graph.vals.size(), std::max(graph_size,std::size_t(1))); } // done building the graph Metis::idx_t ncon = 1; // Select which type of partitioning to create // Use recursive if the number of partitions is less than or equal to 8 if (n_pieces <= 8) Metis::METIS_PartGraphRecursive(&n, &ncon, &csr_graph.offsets[0], &csr_graph.vals[0], &vwgt[0], libmesh_nullptr, libmesh_nullptr, &nparts, libmesh_nullptr, libmesh_nullptr, libmesh_nullptr, &edgecut, &part[0]); // Otherwise use kway else Metis::METIS_PartGraphKway(&n, &ncon, &csr_graph.offsets[0], &csr_graph.vals[0], &vwgt[0], libmesh_nullptr, libmesh_nullptr, &nparts, libmesh_nullptr, libmesh_nullptr, libmesh_nullptr, &edgecut, &part[0]); } // end processor 0 part // Broadcase the resutling partition mesh.comm().broadcast(part); // Assign the returned processor ids. The part array contains // the processor id for each active element, but in terms of // the contiguous indexing we defined above { MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for (; it!=end; ++it) { Elem * elem = *it; libmesh_assert (global_index_map.count(elem->id())); const dof_id_type elem_global_index = global_index_map[elem->id()]; libmesh_assert_less (elem_global_index, part.size()); const processor_id_type elem_procid = static_cast<processor_id_type>(part[elem_global_index]); elem->processor_id() = elem_procid; } } #endif }
Real FE<3,HERMITE>::shape_second_deriv(const Elem* elem, const Order order, const unsigned int i, const unsigned int j, const Point& p) { libmesh_assert(elem); hermite_compute_coefs(elem); #ifdef LIBMESH_HAVE_TBB_API std::vector<std::vector<Real> > & dxdxi = dxdxi_tls.local(); #endif const ElemType type = elem->type(); const Order totalorder = static_cast<Order>(order + elem->p_level()); switch (totalorder) { // 3rd-order tricubic Hermite functions case THIRD: { switch (type) { case HEX8: case HEX20: case HEX27: { libmesh_assert_less (i, 64); std::vector<unsigned int> bases1D; Real coef = hermite_bases_3D(bases1D, dxdxi, totalorder, i); switch (j) // Derivative type { case 0: return coef * FEHermite<1>::hermite_raw_shape_second_deriv(bases1D[0],p(0)) * FEHermite<1>::hermite_raw_shape(bases1D[1],p(1)) * FEHermite<1>::hermite_raw_shape(bases1D[2],p(2)); break; case 1: return coef * FEHermite<1>::hermite_raw_shape_deriv(bases1D[0],p(0)) * FEHermite<1>::hermite_raw_shape_deriv(bases1D[1],p(1)) * FEHermite<1>::hermite_raw_shape(bases1D[2],p(2)); break; case 2: return coef * FEHermite<1>::hermite_raw_shape(bases1D[0],p(0)) * FEHermite<1>::hermite_raw_shape_second_deriv(bases1D[1],p(1)) * FEHermite<1>::hermite_raw_shape(bases1D[2],p(2)); break; case 3: return coef * FEHermite<1>::hermite_raw_shape_deriv(bases1D[0],p(0)) * FEHermite<1>::hermite_raw_shape(bases1D[1],p(1)) * FEHermite<1>::hermite_raw_shape_deriv(bases1D[2],p(2)); break; case 4: return coef * FEHermite<1>::hermite_raw_shape(bases1D[0],p(0)) * FEHermite<1>::hermite_raw_shape_deriv(bases1D[1],p(1)) * FEHermite<1>::hermite_raw_shape_deriv(bases1D[2],p(2)); break; case 5: return coef * FEHermite<1>::hermite_raw_shape(bases1D[0],p(0)) * FEHermite<1>::hermite_raw_shape(bases1D[1],p(1)) * FEHermite<1>::hermite_raw_shape_second_deriv(bases1D[2],p(2)); break; } } default: libMesh::err << "ERROR: Unsupported element type!" << std::endl; libmesh_error(); } } // by default throw an error default: libMesh::err << "ERROR: Unsupported polynomial order!" << std::endl; libmesh_error(); } libmesh_error(); return 0.; }
Real FE<2,HIERARCHIC>::shape(const Elem * elem, const Order order, const unsigned int i, const Point & p) { libmesh_assert(elem); const Order totalorder = static_cast<Order>(order+elem->p_level()); libmesh_assert_greater (totalorder, 0); switch (elem->type()) { case TRI3: case TRISHELL3: case TRI6: { const Real zeta1 = p(0); const Real zeta2 = p(1); const Real zeta0 = 1. - zeta1 - zeta2; libmesh_assert_less (i, (totalorder+1u)*(totalorder+2u)/2); libmesh_assert (elem->type() == TRI6 || totalorder < 2); // Vertex DoFs if (i == 0) return zeta0; else if (i == 1) return zeta1; else if (i == 2) return zeta2; // Edge DoFs else if (i < totalorder + 2u) { // Avoid returning NaN on vertices! if (zeta0 + zeta1 == 0.) return 0.; const unsigned int basisorder = i - 1; // Get factors to account for edge-flipping Real f0 = 1; if (basisorder%2 && (elem->point(0) > elem->point(1))) f0 = -1.; Real edgeval = (zeta1 - zeta0) / (zeta1 + zeta0); Real crossfunc = zeta0 + zeta1; for (unsigned int n=1; n != basisorder; ++n) crossfunc *= (zeta0 + zeta1); return f0 * crossfunc * FE<1,HIERARCHIC>::shape(EDGE3, totalorder, basisorder, edgeval); } else if (i < 2u*totalorder + 1) { // Avoid returning NaN on vertices! if (zeta1 + zeta2 == 0.) return 0.; const unsigned int basisorder = i - totalorder; // Get factors to account for edge-flipping Real f1 = 1; if (basisorder%2 && (elem->point(1) > elem->point(2))) f1 = -1.; Real edgeval = (zeta2 - zeta1) / (zeta2 + zeta1); Real crossfunc = zeta2 + zeta1; for (unsigned int n=1; n != basisorder; ++n) crossfunc *= (zeta2 + zeta1); return f1 * crossfunc * FE<1,HIERARCHIC>::shape(EDGE3, totalorder, basisorder, edgeval); } else if (i < 3u*totalorder) { // Avoid returning NaN on vertices! if (zeta0 + zeta2 == 0.) return 0.; const unsigned int basisorder = i - (2u*totalorder) + 1; // Get factors to account for edge-flipping Real f2 = 1; if (basisorder%2 && (elem->point(2) > elem->point(0))) f2 = -1.; Real edgeval = (zeta0 - zeta2) / (zeta0 + zeta2); Real crossfunc = zeta0 + zeta2; for (unsigned int n=1; n != basisorder; ++n) crossfunc *= (zeta0 + zeta2); return f2 * crossfunc * FE<1,HIERARCHIC>::shape(EDGE3, totalorder, basisorder, edgeval); } // Interior DoFs else { const unsigned int basisnum = i - (3u*totalorder); unsigned int exp0 = triangular_number_column[basisnum] + 1; unsigned int exp1 = triangular_number_row[basisnum] + 1 - triangular_number_column[basisnum]; Real returnval = 1; for (unsigned int n = 0; n != exp0; ++n) returnval *= zeta0; for (unsigned int n = 0; n != exp1; ++n) returnval *= zeta1; returnval *= zeta2; return returnval; } } // Hierarchic shape functions on the quadrilateral. case QUAD4: case QUADSHELL4: libmesh_assert_less (totalorder, 2); libmesh_fallthrough(); case QUAD8: case QUADSHELL8: case QUAD9: { // Compute quad shape functions as a tensor-product const Real xi = p(0); const Real eta = p(1); libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)); // Example i, i0, i1 values for totalorder = 5: // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 // static const unsigned int i0[] = {0, 1, 1, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 2, 3, 3, 2, 4, 4, 4, 3, 2, 5, 5, 5, 5, 4, 3, 2}; // static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 0, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 2, 2, 3, 3, 2, 3, 4, 4, 4, 2, 3, 4, 5, 5, 5, 5}; unsigned int i0, i1; // Vertex DoFs if (i == 0) { i0 = 0; i1 = 0; } else if (i == 1) { i0 = 1; i1 = 0; } else if (i == 2) { i0 = 1; i1 = 1; } else if (i == 3) { i0 = 0; i1 = 1; } // Edge DoFs else if (i < totalorder + 3u) { i0 = i - 2; i1 = 0; } else if (i < 2u*totalorder + 2) { i0 = 1; i1 = i - totalorder - 1; } else if (i < 3u*totalorder + 1) { i0 = i - 2u*totalorder; i1 = 1; } else if (i < 4u*totalorder) { i0 = 0; i1 = i - 3u*totalorder + 1; } // Interior DoFs else { unsigned int basisnum = i - 4*totalorder; i0 = square_number_column[basisnum] + 2; i1 = square_number_row[basisnum] + 2; } // Flip odd degree of freedom values if necessary // to keep continuity on sides Real f = 1.; if ((i0%2) && (i0 > 2) && (i1 == 0)) f = (elem->point(0) > elem->point(1))?-1.:1.; else if ((i0%2) && (i0>2) && (i1 == 1)) f = (elem->point(3) > elem->point(2))?-1.:1.; else if ((i0 == 0) && (i1%2) && (i1>2)) f = (elem->point(0) > elem->point(3))?-1.:1.; else if ((i0 == 1) && (i1%2) && (i1>2)) f = (elem->point(1) > elem->point(2))?-1.:1.; return f*(FE<1,HIERARCHIC>::shape(EDGE3, totalorder, i0, xi)* FE<1,HIERARCHIC>::shape(EDGE3, totalorder, i1, eta)); } default: libmesh_error_msg("ERROR: Unsupported element type = " << elem->type()); } return 0.; }
Real FE<2,HIERARCHIC>::shape_deriv(const Elem * elem, const Order order, const unsigned int i, const unsigned int j, const Point & p) { libmesh_assert(elem); const ElemType type = elem->type(); const Order totalorder = static_cast<Order>(order+elem->p_level()); libmesh_assert_greater (totalorder, 0); switch (type) { // 1st & 2nd-order Hierarchics. case TRI3: case TRISHELL3: case TRI6: { const Real eps = 1.e-6; libmesh_assert_less (j, 2); switch (j) { // d()/dxi case 0: { const Point pp(p(0)+eps, p(1)); const Point pm(p(0)-eps, p(1)); return (FE<2,HIERARCHIC>::shape(elem, order, i, pp) - FE<2,HIERARCHIC>::shape(elem, order, i, pm))/2./eps; } // d()/deta case 1: { const Point pp(p(0), p(1)+eps); const Point pm(p(0), p(1)-eps); return (FE<2,HIERARCHIC>::shape(elem, order, i, pp) - FE<2,HIERARCHIC>::shape(elem, order, i, pm))/2./eps; } default: libmesh_error_msg("Invalid derivative index j = " << j); } } case QUAD4: case QUADSHELL4: libmesh_assert_less (totalorder, 2); libmesh_fallthrough(); case QUAD8: case QUADSHELL8: case QUAD9: { // Compute quad shape functions as a tensor-product const Real xi = p(0); const Real eta = p(1); libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)); // Example i, i0, i1 values for totalorder = 5: // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 // static const unsigned int i0[] = {0, 1, 1, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5}; // static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 0, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}; unsigned int i0, i1; // Vertex DoFs if (i == 0) { i0 = 0; i1 = 0; } else if (i == 1) { i0 = 1; i1 = 0; } else if (i == 2) { i0 = 1; i1 = 1; } else if (i == 3) { i0 = 0; i1 = 1; } // Edge DoFs else if (i < totalorder + 3u) { i0 = i - 2; i1 = 0; } else if (i < 2u*totalorder + 2) { i0 = 1; i1 = i - totalorder - 1; } else if (i < 3u*totalorder + 1u) { i0 = i - 2u*totalorder; i1 = 1; } else if (i < 4u*totalorder) { i0 = 0; i1 = i - 3u*totalorder + 1; } // Interior DoFs else { unsigned int basisnum = i - 4*totalorder; i0 = square_number_column[basisnum] + 2; i1 = square_number_row[basisnum] + 2; } // Flip odd degree of freedom values if necessary // to keep continuity on sides Real f = 1.; if ((i0%2) && (i0 > 2) && (i1 == 0)) f = (elem->point(0) > elem->point(1))?-1.:1.; else if ((i0%2) && (i0>2) && (i1 == 1)) f = (elem->point(3) > elem->point(2))?-1.:1.; else if ((i0 == 0) && (i1%2) && (i1>2)) f = (elem->point(0) > elem->point(3))?-1.:1.; else if ((i0 == 1) && (i1%2) && (i1>2)) f = (elem->point(1) > elem->point(2))?-1.:1.; switch (j) { // d()/dxi case 0: return f*(FE<1,HIERARCHIC>::shape_deriv(EDGE3, totalorder, i0, 0, xi)* FE<1,HIERARCHIC>::shape (EDGE3, totalorder, i1, eta)); // d()/deta case 1: return f*(FE<1,HIERARCHIC>::shape (EDGE3, totalorder, i0, xi)* FE<1,HIERARCHIC>::shape_deriv(EDGE3, totalorder, i1, 0, eta)); default: libmesh_error_msg("Invalid derivative index j = " << j); } } default: libmesh_error_msg("ERROR: Unsupported element type = " << type); } return 0.; }
void MeshRefinement::flag_elements_by_mean_stddev (const ErrorVector& error_per_cell, const Real refine_frac, const Real coarsen_frac, const unsigned int max_l) { // 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; } // Get the mean value from the error vector const Real mean = error_per_cell.mean(); // Get the standard deviation. This equals the // square-root of the variance const Real stddev = std::sqrt (error_per_cell.variance()); // Check for valid fractions 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 refine and coarsen cutoff const Real refine_cutoff = mean + _refine_fraction * stddev; const Real coarsen_cutoff = std::max(mean - _coarsen_fraction * stddev, 0.); // Loop over the elements and flag them for coarsening or // refinement based on the element error 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 id = elem->id(); libmesh_assert_less (id, error_per_cell.size()); const float elem_error = error_per_cell[id]; // Possibly flag the element for coarsening ... if (elem_error <= coarsen_cutoff) elem->set_refinement_flag(Elem::COARSEN); // ... or refinement if ((elem_error >= refine_cutoff) && (elem->level() < _max_h_level)) elem->set_refinement_flag(Elem::REFINE); } }
UniquePtr<Elem> InfHex16::build_side (const unsigned int i, bool proxy) const { libmesh_assert_less (i, this->n_sides()); if (proxy) { switch (i) { // base case 0: return UniquePtr<Elem>(new Side<Quad8,InfHex16>(this,i)); // ifem sides case 1: case 2: case 3: case 4: return UniquePtr<Elem>(new Side<InfQuad6,InfHex16>(this,i)); default: libmesh_error_msg("Invalid side i = " << i); } } else { // Create NULL pointer to be initialized, returned later. Elem* face = NULL; // Think of a unit cube: (-1,1) x (-1,1) x (1,1) switch (i) { case 0: // the base face { face = new Quad8; // Only here, the face element's normal points inward face->set_node(0) = this->get_node(0); face->set_node(1) = this->get_node(1); face->set_node(2) = this->get_node(2); face->set_node(3) = this->get_node(3); face->set_node(4) = this->get_node(8); face->set_node(5) = this->get_node(9); face->set_node(6) = this->get_node(10); face->set_node(7) = this->get_node(11); break; } case 1: // connecting to another infinite element { face = new InfQuad6; face->set_node(0) = this->get_node(0); face->set_node(1) = this->get_node(1); face->set_node(2) = this->get_node(4); face->set_node(3) = this->get_node(5); face->set_node(4) = this->get_node(8); face->set_node(5) = this->get_node(12); break; } case 2: // connecting to another infinite element { face = new InfQuad6; face->set_node(0) = this->get_node(1); face->set_node(1) = this->get_node(2); face->set_node(2) = this->get_node(5); face->set_node(3) = this->get_node(6); face->set_node(4) = this->get_node(9); face->set_node(5) = this->get_node(13); break; } case 3: // connecting to another infinite element { face = new InfQuad6; face->set_node(0) = this->get_node(2); face->set_node(1) = this->get_node(3); face->set_node(2) = this->get_node(6); face->set_node(3) = this->get_node(7); face->set_node(4) = this->get_node(10); face->set_node(5) = this->get_node(14); break; } case 4: // connecting to another infinite element { face = new InfQuad6; face->set_node(0) = this->get_node(3); face->set_node(1) = this->get_node(0); face->set_node(2) = this->get_node(7); face->set_node(3) = this->get_node(4); face->set_node(4) = this->get_node(11); face->set_node(5) = this->get_node(15); break; } default: libmesh_error_msg("Invalid side i = " << i); } face->subdomain_id() = this->subdomain_id(); return UniquePtr<Elem>(face); } libmesh_error_msg("We'll never get here!"); return UniquePtr<Elem>(); }
NumericVector<Number>& RBEvaluation::get_basis_function(unsigned int i) { libmesh_assert_less (i, basis_functions.size()); return *(basis_functions[i]); }
void Tri6::connectivity(const unsigned int sf, const IOPackage iop, std::vector<dof_id_type>& conn) const { libmesh_assert_less (sf, this->n_sub_elem()); libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE); switch (iop) { case TECPLOT: { conn.resize(4); switch(sf) { case 0: // linear sub-triangle 0 conn[0] = this->node(0)+1; conn[1] = this->node(3)+1; conn[2] = this->node(5)+1; conn[3] = this->node(5)+1; return; case 1: // linear sub-triangle 1 conn[0] = this->node(3)+1; conn[1] = this->node(1)+1; conn[2] = this->node(4)+1; conn[3] = this->node(4)+1; return; case 2: // linear sub-triangle 2 conn[0] = this->node(5)+1; conn[1] = this->node(4)+1; conn[2] = this->node(2)+1; conn[3] = this->node(2)+1; return; case 3: // linear sub-triangle 3 conn[0] = this->node(3)+1; conn[1] = this->node(4)+1; conn[2] = this->node(5)+1; conn[3] = this->node(5)+1; return; default: libmesh_error_msg("Invalid sf = " << sf); } } case VTK: { // VTK_QUADRATIC_TRIANGLE has same numbering as libmesh TRI6 conn.resize(6); conn[0] = this->node(0); conn[1] = this->node(1); conn[2] = this->node(2); conn[3] = this->node(3); conn[4] = this->node(4); conn[5] = this->node(5); return; // Used to write out linear sub-triangles for VTK... /* conn.resize(3); switch(sf) { case 0: // linear sub-triangle 0 conn[0] = this->node(0); conn[1] = this->node(3); conn[2] = this->node(5); return; case 1: // linear sub-triangle 1 conn[0] = this->node(3); conn[1] = this->node(1); conn[2] = this->node(4); return; case 2: // linear sub-triangle 2 conn[0] = this->node(5); conn[1] = this->node(4); conn[2] = this->node(2); return; case 3: // linear sub-triangle 3 conn[0] = this->node(3); conn[1] = this->node(4); conn[2] = this->node(5); return; default: libmesh_error_msg("Invalid sf = " << sf); } */ } default: libmesh_error_msg("Unsupported IO package " << iop); } }
std::string AntiochChemistry::species_name( unsigned int species_index ) const { libmesh_assert_less(species_index, _antioch_gas->n_species()); return _antioch_gas->species_inverse_name_map().find(species_index)->second; }
AutoPtr<Elem> Tet10::build_edge (const unsigned int i) const { libmesh_assert_less (i, this->n_edges()); return AutoPtr<Elem>(new SideEdge<Edge3,Tet10>(this,i)); }
void Partitioner::partition_unpartitioned_elements (MeshBase & mesh, const unsigned int n_subdomains) { MeshBase::element_iterator it = mesh.unpartitioned_elements_begin(); const MeshBase::element_iterator end = mesh.unpartitioned_elements_end(); const dof_id_type n_unpartitioned_elements = MeshTools::n_elem (it, end); // the unpartitioned elements must exist on all processors. If the range is empty on one // it is empty on all, and we can quit right here. if (!n_unpartitioned_elements) return; // find the target subdomain sizes std::vector<dof_id_type> subdomain_bounds(mesh.n_processors()); for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { dof_id_type tgt_subdomain_size = 0; // watch out for the case that n_subdomains < n_processors if (pid < n_subdomains) { tgt_subdomain_size = n_unpartitioned_elements/n_subdomains; if (pid < n_unpartitioned_elements%n_subdomains) tgt_subdomain_size++; } //libMesh::out << "pid, #= " << pid << ", " << tgt_subdomain_size << std::endl; if (pid == 0) subdomain_bounds[0] = tgt_subdomain_size; else subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size; } libmesh_assert_equal_to (subdomain_bounds.back(), n_unpartitioned_elements); // create the unique mapping for all unpartitioned elements independent of partitioning // determine the global indexing for all the unpartitioned elements std::vector<dof_id_type> global_indices; // Calling this on all processors a unique range in [0,n_unpartitioned_elements) is constructed. // Only the indices for the elements we pass in are returned in the array. MeshCommunication().find_global_indices (mesh.comm(), MeshTools::create_bounding_box(mesh), it, end, global_indices); for (dof_id_type cnt=0; it != end; ++it) { Elem * elem = *it; libmesh_assert_less (cnt, global_indices.size()); const dof_id_type global_index = global_indices[cnt++]; libmesh_assert_less (global_index, subdomain_bounds.back()); libmesh_assert_less (global_index, n_unpartitioned_elements); const processor_id_type subdomain_id = cast_int<processor_id_type> (std::distance(subdomain_bounds.begin(), std::upper_bound(subdomain_bounds.begin(), subdomain_bounds.end(), global_index))); libmesh_assert_less (subdomain_id, n_subdomains); elem->processor_id() = subdomain_id; //libMesh::out << "assigning " << global_index << " to " << subdomain_id << std::endl; } }
AutoPtr<Elem> InfHex18::build_side (const unsigned int i, bool proxy) const { libmesh_assert_less (i, this->n_sides()); if (proxy) { switch (i) { // base case 0: { AutoPtr<Elem> ap(new Side<Quad9,InfHex18>(this,i)); return ap; } // ifem sides case 1: case 2: case 3: case 4: { AutoPtr<Elem> ap(new Side<InfQuad6,InfHex18>(this,i)); return ap; } default: libmesh_error_msg("Invalid side i = " << i); } } else { // Create NULL pointer to be initialized, returned later. AutoPtr<Elem> face(NULL); // Think of a unit cube: (-1,1) x (-1,1) x (1,1) switch (i) { case 0: // the base face { face.reset(new Quad9); // This is the exception: all other face elements' normals // point outwards; but the base element's normal points inward face->set_node(0) = this->get_node(0); face->set_node(1) = this->get_node(1); face->set_node(2) = this->get_node(2); face->set_node(3) = this->get_node(3); face->set_node(4) = this->get_node(8); face->set_node(5) = this->get_node(9); face->set_node(6) = this->get_node(10); face->set_node(7) = this->get_node(11); face->set_node(8) = this->get_node(16); break; } case 1: // connecting to another infinite element { face.reset(new InfQuad6); face->set_node(0) = this->get_node(0); face->set_node(1) = this->get_node(1); face->set_node(2) = this->get_node(4); face->set_node(3) = this->get_node(5); face->set_node(4) = this->get_node(8); face->set_node(5) = this->get_node(12); break; } case 2: // connecting to another infinite element { face.reset(new InfQuad6); face->set_node(0) = this->get_node(1); face->set_node(1) = this->get_node(2); face->set_node(2) = this->get_node(5); face->set_node(3) = this->get_node(6); face->set_node(4) = this->get_node(9); face->set_node(5) = this->get_node(13); break; } case 3: // connecting to another infinite element { face.reset(new InfQuad6); face->set_node(0) = this->get_node(2); face->set_node(1) = this->get_node(3); face->set_node(2) = this->get_node(6); face->set_node(3) = this->get_node(7); face->set_node(4) = this->get_node(10); face->set_node(5) = this->get_node(14); break; } case 4: // connecting to another infinite element { face.reset(new InfQuad6); face->set_node(0) = this->get_node(3); face->set_node(1) = this->get_node(0); face->set_node(2) = this->get_node(7); face->set_node(3) = this->get_node(4); face->set_node(4) = this->get_node(11); face->set_node(5) = this->get_node(15); break; } default: libmesh_error_msg("Invalid side i = " << i); } face->subdomain_id() = this->subdomain_id(); return face; } libmesh_error_msg("We'll never get here!"); AutoPtr<Elem> ap(NULL); return ap; }
void Partitioner::set_parent_processor_ids(MeshBase & mesh) { // Ignore the parameter when !LIBMESH_ENABLE_AMR libmesh_ignore(mesh); LOG_SCOPE("set_parent_processor_ids()", "Partitioner"); #ifdef LIBMESH_ENABLE_AMR // If the mesh is serial we have access to all the elements, // in particular all the active ones. We can therefore set // the parent processor ids indirectly through their children, and // set the subactive processor ids while examining their active // ancestors. // By convention a parent is assigned to the minimum processor // of all its children, and a subactive is assigned to the processor // of its active ancestor. if (mesh.is_serial()) { for (auto & child : mesh.active_element_ptr_range()) { // First set descendents std::vector<const Elem *> subactive_family; child->total_family_tree(subactive_family); for (std::size_t i = 0; i != subactive_family.size(); ++i) const_cast<Elem *>(subactive_family[i])->processor_id() = child->processor_id(); // Then set ancestors Elem * parent = child->parent(); while (parent) { // invalidate the parent id, otherwise the min below // will not work if the current parent id is less // than all the children! parent->invalidate_processor_id(); for (auto & child : parent->child_ref_range()) { libmesh_assert(!child.is_remote()); libmesh_assert_not_equal_to (child.processor_id(), DofObject::invalid_processor_id); parent->processor_id() = std::min(parent->processor_id(), child.processor_id()); } parent = parent->parent(); } } } // When the mesh is parallel we cannot guarantee that parents have access to // all their children. else { // Setting subactive processor ids is easy: we can guarantee // that children have access to all their parents. // Loop over all the active elements in the mesh for (auto & child : mesh.active_element_ptr_range()) { std::vector<const Elem *> subactive_family; child->total_family_tree(subactive_family); for (std::size_t i = 0; i != subactive_family.size(); ++i) const_cast<Elem *>(subactive_family[i])->processor_id() = child->processor_id(); } // When the mesh is parallel we cannot guarantee that parents have access to // all their children. // We will use a brute-force approach here. Each processor finds its parent // elements and sets the parent pid to the minimum of its // semilocal descendants. // A global reduction is then performed to make sure the true minimum is found. // As noted, this is required because we cannot guarantee that a parent has // access to all its children on any single processor. libmesh_parallel_only(mesh.comm()); libmesh_assert(MeshTools::n_elem(mesh.unpartitioned_elements_begin(), mesh.unpartitioned_elements_end()) == 0); const dof_id_type max_elem_id = mesh.max_elem_id(); std::vector<processor_id_type> parent_processor_ids (std::min(communication_blocksize, max_elem_id)); for (dof_id_type blk=0, last_elem_id=0; last_elem_id<max_elem_id; blk++) { last_elem_id = std::min(static_cast<dof_id_type>((blk+1)*communication_blocksize), max_elem_id); const dof_id_type first_elem_id = blk*communication_blocksize; std::fill (parent_processor_ids.begin(), parent_processor_ids.end(), DofObject::invalid_processor_id); // first build up local contributions to parent_processor_ids MeshBase::element_iterator not_it = mesh.ancestor_elements_begin(); const MeshBase::element_iterator not_end = mesh.ancestor_elements_end(); bool have_parent_in_block = false; for ( ; not_it != not_end; ++not_it) { Elem * parent = *not_it; const dof_id_type parent_idx = parent->id(); libmesh_assert_less (parent_idx, max_elem_id); if ((parent_idx >= first_elem_id) && (parent_idx < last_elem_id)) { have_parent_in_block = true; processor_id_type parent_pid = DofObject::invalid_processor_id; std::vector<const Elem *> active_family; parent->active_family_tree(active_family); for (std::size_t i = 0; i != active_family.size(); ++i) parent_pid = std::min (parent_pid, active_family[i]->processor_id()); const dof_id_type packed_idx = parent_idx - first_elem_id; libmesh_assert_less (packed_idx, parent_processor_ids.size()); parent_processor_ids[packed_idx] = parent_pid; } } // then find the global minimum mesh.comm().min (parent_processor_ids); // and assign the ids, if we have a parent in this block. if (have_parent_in_block) for (not_it = mesh.ancestor_elements_begin(); not_it != not_end; ++not_it) { Elem * parent = *not_it; const dof_id_type parent_idx = parent->id(); if ((parent_idx >= first_elem_id) && (parent_idx < last_elem_id)) { const dof_id_type packed_idx = parent_idx - first_elem_id; libmesh_assert_less (packed_idx, parent_processor_ids.size()); const processor_id_type parent_pid = parent_processor_ids[packed_idx]; libmesh_assert_not_equal_to (parent_pid, DofObject::invalid_processor_id); parent->processor_id() = parent_pid; } } } } #endif // LIBMESH_ENABLE_AMR }
UniquePtr<Elem> InfPrism12::build_side_ptr (const unsigned int i, bool proxy) { libmesh_assert_less (i, this->n_sides()); if (proxy) { switch (i) { // base case 0: return UniquePtr<Elem>(new Side<Tri6,InfPrism12>(this,i)); // ifem sides case 1: case 2: case 3: return UniquePtr<Elem>(new Side<InfQuad6,InfPrism12>(this,i)); default: libmesh_error_msg("Invalid side i = " << i); } } else { // Create NULL pointer to be initialized, returned later. Elem * face = libmesh_nullptr; switch (i) { case 0: // the triangular face at z=-1, base face { face = new Tri6; break; } case 1: // the quad face at y=0 case 2: // the other quad face case 3: // the quad face at x=0 { face = new InfQuad6; break; } default: libmesh_error_msg("Invalid side i = " << i); } face->subdomain_id() = this->subdomain_id(); // Set the nodes for (unsigned n=0; n<face->n_nodes(); ++n) face->set_node(n) = this->node_ptr(InfPrism12::side_nodes_map[i][n]); return UniquePtr<Elem>(face); } libmesh_error_msg("We'll never get here!"); return UniquePtr<Elem>(); }
void Partitioner::set_node_processor_ids(MeshBase & mesh) { LOG_SCOPE("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); for (auto & node : mesh.node_ptr_range()) { 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 (auto & node : mesh.node_ptr_range()) { 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 for (auto & elem : mesh.active_element_ptr_range()) { 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->node_ptr(n)->processor_id() = std::min(elem->node_ptr(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->node_ptr(n)->processor_id() == DofObject::invalid_processor_id) elem->node_ptr(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->node_ptr(n)->processor_id() == DofObject::invalid_processor_id) elem->node_ptr(n)->processor_id() = elem->processor_id(); } // We can't assert that all nodes are connected to elements, because // a DistributedMesh 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_ref(request_to_fill[i]); const processor_id_type new_pid = node.processor_id(); // We may have an invalid processor_id() on nodes that have been // "detached" 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_ref(requested_node_ids[procup][i]); // 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 "detached" 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 }
AutoPtr<Elem> InfPrism12::build_side (const unsigned int i, bool proxy) const { libmesh_assert_less (i, this->n_sides()); if (proxy) { switch (i) { // base case 0: { AutoPtr<Elem> ap(new Side<Tri6,InfPrism12>(this,i)); return ap; } // ifem sides case 1: case 2: case 3: { AutoPtr<Elem> ap(new Side<InfQuad6,InfPrism12>(this,i)); return ap; } default: libmesh_error(); } } else { // Create NULL pointer to be initialized, returned later. AutoPtr<Elem> face(NULL); switch (i) { case 0: // the triangular face at z=-1, base face { face.reset(new Tri6); // Note that for this face element, the normal points inward face->set_node(0) = this->get_node(0); face->set_node(1) = this->get_node(1); face->set_node(2) = this->get_node(2); face->set_node(3) = this->get_node(6); face->set_node(4) = this->get_node(7); face->set_node(5) = this->get_node(8); break; } case 1: // the quad face at y=0 { face.reset(new InfQuad6); face->set_node(0) = this->get_node(0); face->set_node(1) = this->get_node(1); face->set_node(2) = this->get_node(3); face->set_node(3) = this->get_node(4); face->set_node(4) = this->get_node(6); face->set_node(5) = this->get_node(9); break; } case 2: // the other quad face { face.reset(new InfQuad6); face->set_node(0) = this->get_node(1); face->set_node(1) = this->get_node(2); face->set_node(2) = this->get_node(4); face->set_node(3) = this->get_node(5); face->set_node(4) = this->get_node(7); face->set_node(5) = this->get_node(10); break; } case 3: // the quad face at x=0 { face.reset(new InfQuad6); face->set_node(0) = this->get_node(2); face->set_node(1) = this->get_node(0); face->set_node(2) = this->get_node(5); face->set_node(3) = this->get_node(3); face->set_node(4) = this->get_node(8); face->set_node(5) = this->get_node(11); break; } default: { libmesh_error(); } } face->subdomain_id() = this->subdomain_id(); return face; } // We'll never get here. libmesh_error(); AutoPtr<Elem> ap(NULL); return ap; }
AutoPtr<Elem> Quad4::build_side (const unsigned int i, bool proxy) const { libmesh_assert_less (i, this->n_sides()); if (proxy) { AutoPtr<Elem> ap(new Side<Edge2,Quad4>(this,i)); return ap; } else { switch (i) { case 0: { Edge2* edge = new Edge2; edge->set_node(0) = this->get_node(0); edge->set_node(1) = this->get_node(1); AutoPtr<Elem> ap(edge); return ap; } case 1: { Edge2* edge = new Edge2; edge->set_node(0) = this->get_node(1); edge->set_node(1) = this->get_node(2); AutoPtr<Elem> ap(edge); return ap; } case 2: { Edge2* edge = new Edge2; edge->set_node(0) = this->get_node(2); edge->set_node(1) = this->get_node(3); AutoPtr<Elem> ap(edge); return ap; } case 3: { Edge2* edge = new Edge2; edge->set_node(0) = this->get_node(3); edge->set_node(1) = this->get_node(0); AutoPtr<Elem> ap(edge); return ap; } default: { libmesh_error(); } } } // We will never get here... AutoPtr<Elem> ap(NULL); return ap; }
RealGradient FE<2,NEDELEC_ONE>::shape_deriv(const Elem* elem, const Order order, const unsigned int i, const unsigned int j, const Point&) { #if LIBMESH_DIM > 1 libmesh_assert(elem); libmesh_assert_less (j, 2); const Order total_order = static_cast<Order>(order + elem->p_level()); switch (total_order) { // linear Lagrange shape functions case FIRST: { switch (elem->type()) { case QUAD8: case QUAD9: { libmesh_assert_less (i, 4); switch (j) { // d()/dxi case 0: { switch(i) { case 0: case 2: return RealGradient(); case 1: { if( elem->point(1) > elem->point(2) ) return RealGradient( 0.0, -0.25 ); else return RealGradient( 0.0, 0.25 ); } case 3: { if( elem->point(3) > elem->point(0) ) return RealGradient( 0.0, -0.25 ); else return RealGradient( 0.0, 0.25 ); } default: libmesh_error(); } } // j=0 // d()/deta case 1: { switch(i) { case 1: case 3: return RealGradient(); case 0: { if( elem->point(0) > elem->point(1) ) return RealGradient( 0.25 ); else return RealGradient( -0.25 ); } case 2: { if( elem->point(2) > elem->point(3) ) return RealGradient( 0.25 ); else return RealGradient( -0.25 ); } default: libmesh_error(); } } // j=1 default: libmesh_error(); } return RealGradient(); } case TRI6: { libmesh_assert_less (i, 3); // Account for edge flipping Real f = 1.0; switch(i) { case 0: { if( elem->point(0) > elem->point(1) ) f = -1.0; break; } case 1: { if( elem->point(1) > elem->point(2) ) f = -1.0; break; } case 2: { if( elem->point(2) > elem->point(0) ) f = -1.0; break; } default: libmesh_error(); } switch (j) { // d()/dxi case 0: { return RealGradient( 0.0, f*1.0); } // d()/deta case 1: { return RealGradient( f*(-1.0) ); } default: libmesh_error(); } } default: { libMesh::err << "ERROR: Unsupported 2D element type!: " << elem->type() << std::endl; libmesh_error(); } } } // unsupported order default: { libMesh::err << "ERROR: Unsupported 2D FE order!: " << total_order << std::endl; libmesh_error(); } } #endif // LIBMESH_DIM > 1 libmesh_error(); return RealGradient(); }
Real FE<2,XYZ>::shape(const Elem* elem, const Order libmesh_dbg_var(order), const unsigned int i, const Point& point_in) { #if LIBMESH_DIM > 1 libmesh_assert(elem); // Only recompute the centroid if the element // has changed from the last one we computed. // This avoids repeated centroid calculations // when called in succession with the same element. if (elem->id() != old_elem_id) { centroid = elem->centroid(); old_elem_id = elem->id(); max_distance = Point(0.,0.,0.); for (unsigned int p = 0; p < elem->n_nodes(); p++) for (unsigned int d = 0; d < 2; d++) { const Real distance = std::abs(centroid(d) - elem->point(p)(d)); max_distance(d) = std::max(distance, max_distance(d)); } } // Using static globals for old_elem_id, etc. will fail // horribly with more than one thread. libmesh_assert_equal_to (libMesh::n_threads(), 1); const Real x = point_in(0); const Real y = point_in(1); const Real xc = centroid(0); const Real yc = centroid(1); const Real distx = max_distance(0); const Real disty = max_distance(1); const Real dx = (x - xc)/distx; const Real dy = (y - yc)/disty; #ifndef NDEBUG // totalorder is only used in the assertion below, so // we avoid declaring it when asserts are not active. const unsigned int totalorder = order + elem->p_level(); #endif libmesh_assert_less (i, (totalorder+1)*(totalorder+2)/2); // monomials. since they are hierarchic we only need one case block. switch (i) { // constant case 0: return 1.; // linear case 1: return dx; case 2: return dy; // quadratics case 3: return dx*dx; case 4: return dx*dy; case 5: return dy*dy; // cubics case 6: return dx*dx*dx; case 7: return dx*dx*dy; case 8: return dx*dy*dy; case 9: return dy*dy*dy; // quartics case 10: return dx*dx*dx*dx; case 11: return dx*dx*dx*dy; case 12: return dx*dx*dy*dy; case 13: return dx*dy*dy*dy; case 14: return dy*dy*dy*dy; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)/2; o++) { } unsigned int i2 = i - (o*(o+1)/2); Real val = 1.; for (unsigned int index=i2; index != o; index++) val *= dx; for (unsigned int index=0; index != i2; index++) val *= dy; return val; } libmesh_error(); return 0.; #endif }
RealGradient FE<2,NEDELEC_ONE>::shape(const Elem* elem, const Order order, const unsigned int i, const Point& p) { #if LIBMESH_DIM > 1 libmesh_assert(elem); const Order total_order = static_cast<Order>(order + elem->p_level()); switch (total_order) { case FIRST: { switch (elem->type()) { case QUAD8: case QUAD9: { libmesh_assert_less (i, 4); const Real xi = p(0); const Real eta = p(1); // Even with a loose inverse_map tolerance we ought to // be nearly on the element interior in master // coordinates libmesh_assert_less_equal ( std::fabs(xi), 1.0+10*TOLERANCE ); libmesh_assert_less_equal ( std::fabs(eta), 1.0+10*TOLERANCE ); switch(i) { case 0: { if( elem->point(0) > elem->point(1) ) return RealGradient( -0.25*(1.0-eta), 0.0 ); else return RealGradient( 0.25*(1.0-eta), 0.0 ); } case 1: { if( elem->point(1) > elem->point(2) ) return RealGradient( 0.0, -0.25*(1.0+xi) ); else return RealGradient( 0.0, 0.25*(1.0+xi) ); } case 2: { if( elem->point(2) > elem->point(3) ) return RealGradient( 0.25*(1.0+eta), 0.0 ); else return RealGradient( -0.25*(1.0+eta), 0.0 ); } case 3: { if( elem->point(3) > elem->point(0) ) return RealGradient( 0.0, -0.25*(xi-1.0) ); else return RealGradient( 0.0, 0.25*(xi-1.0) ); } default: libmesh_error(); } return RealGradient(); } case TRI6: { const Real xi = p(0); const Real eta = p(1); libmesh_assert_less (i, 3); switch(i) { case 0: { if( elem->point(0) > elem->point(1) ) return RealGradient( -1.0+eta, -xi ); else return RealGradient( 1.0-eta, xi ); } case 1: { if( elem->point(1) > elem->point(2) ) return RealGradient( eta, -xi ); else return RealGradient( -eta, xi ); } case 2: { if( elem->point(2) > elem->point(0) ) return RealGradient( eta, -xi+1.0 ); else return RealGradient( -eta, xi-1.0 ); } default: libmesh_error(); } } default: { libMesh::err << "ERROR: Unsupported 2D element type!: " << elem->type() << std::endl; libmesh_error(); } } } // unsupported order default: { libMesh::err << "ERROR: Unsupported 2D FE order!: " << total_order << std::endl; libmesh_error(); } } #endif // LIBMESH_DIM > 1 libmesh_error(); return RealGradient(); }
bool MeshRefinement::flag_elements_by_nelem_target (const ErrorVector& error_per_cell) { parallel_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 unsigned int n_active_elem = _mesh.n_active_elem(); // The maximum number of active elements to flag for coarsening const unsigned int max_elem_coarsen = static_cast<unsigned int>(_coarsen_fraction * n_active_elem) + 1; // The maximum number of elements to flag for refinement const unsigned int max_elem_refine = static_cast<unsigned int>(_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 int n_elem_new = _nelem_target - n_active_elem; // Create an vector with active element errors and ids, // sorted by highest errors first const unsigned int max_elem_id = _mesh.max_elem_id(); std::vector<std::pair<float, unsigned int> > 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 unsigned int 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)); } CommWorld.max(is_active); CommWorld.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<float, unsigned int> > 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 (unsigned int 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 unsigned int coarsen_count = 0; unsigned int 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(static_cast<unsigned int>(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(static_cast<unsigned int>(-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 unsigned int successful_refine_count = 0; { std::vector<bool> is_refinable(max_elem_id, false); for (unsigned int i=0; i != sorted_error.size(); ++i) { unsigned int eid = sorted_error[i].second; Elem *elem = _mesh.query_elem(eid); if (elem && elem->level() < _max_h_level) is_refinable[eid] = true; } CommWorld.max(is_refinable); if (refine_count > max_elem_refine) refine_count = max_elem_refine; for (unsigned int i=0; i != sorted_error.size(); ++i) { if (successful_refine_count >= refine_count) break; unsigned int 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; unsigned int successful_coarsen_count = 0; if (coarsen_count) { for (unsigned int i=0; i != sorted_parent_error.size(); ++i) { if (successful_coarsen_count >= coarsen_count * twotodim) break; unsigned int 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; }