void Partitioner::set_parent_processor_ids(MeshBase & #ifdef LIBMESH_ENABLE_AMR mesh #endif ) { START_LOG("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 indirecly 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()) { // Loop over all the active elements in the mesh MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for ( ; it!=end; ++it) { Elem * child = *it; // First set descendents std::vector<const Elem *> subactive_family; child->total_family_tree(subactive_family); for (unsigned int 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(unsigned int c=0; c<parent->n_children(); c++) { child = parent->child(c); libmesh_assert(child); 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 MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for ( ; it!=end; ++it) { Elem * child = *it; std::vector<const Elem *> subactive_family; child->total_family_tree(subactive_family); for (unsigned int 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 (unsigned int 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 STOP_LOG("set_parent_processor_ids()","Partitioner"); }
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(); } } 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(); } */ } default: libmesh_error(); } libmesh_error(); }
void InfFE<Dim,T_radial,T_base>::reinit(const Elem* inf_elem, const unsigned int s, const Real tolerance, const std::vector<Point>* const pts, const std::vector<Real>* const weights) { if (weights != NULL) libmesh_not_implemented_msg("ERROR: User-specified weights for infinite elements are not implemented!"); if (pts != NULL) libmesh_not_implemented_msg("ERROR: User-specified points for infinite elements are not implemented!"); // We don't do this for 1D elements! libmesh_assert_not_equal_to (Dim, 1); libmesh_assert(inf_elem); libmesh_assert(qrule); // Don't do this for the base libmesh_assert_not_equal_to (s, 0); // Build the side of interest const AutoPtr<Elem> side(inf_elem->build_side(s)); // set the element type elem_type = inf_elem->type(); // eventually initialize radial quadrature rule bool radial_qrule_initialized = false; if (current_fe_type.radial_order != fe_type.radial_order) { current_fe_type.radial_order = fe_type.radial_order; radial_qrule->init(EDGE2, inf_elem->p_level()); radial_qrule_initialized = true; } // Initialize the face shape functions if (this->get_type() != inf_elem->type() || base_fe->shapes_need_reinit() || radial_qrule_initialized) this->init_face_shape_functions (qrule->get_points(), side.get()); // compute the face map this->_fe_map->compute_face_map(this->dim, _total_qrule_weights, side.get()); // make a copy of the Jacobian for integration const std::vector<Real> JxW_int(this->_fe_map->get_JxW()); // Find where the integration points are located on the // full element. std::vector<Point> qp; this->inverse_map (inf_elem, this->_fe_map->get_xyz(), qp, tolerance); // compute the shape function and derivative values // at the points qp this->reinit (inf_elem, &qp); // copy back old data this->_fe_map->get_JxW() = JxW_int; }
void FE<Dim,T>::edge_reinit(const Elem * elem, const unsigned int e, const Real tolerance, const std::vector<Point> * const pts, const std::vector<Real> * const weights) { libmesh_assert(elem); libmesh_assert (this->qrule != libmesh_nullptr || pts != libmesh_nullptr); // We don't do this for 1D elements! libmesh_assert_not_equal_to (Dim, 1); // Build the side of interest const UniquePtr<Elem> edge(elem->build_edge(e)); // Initialize the shape functions at the user-specified // points if (pts != libmesh_nullptr) { // The shape functions do not correspond to the qrule this->shapes_on_quadrature = false; // Initialize the edge shape functions this->_fe_map->template init_edge_shape_functions<Dim> (*pts, edge.get()); // Compute the Jacobian*Weight on the face for integration if (weights != libmesh_nullptr) { this->_fe_map->compute_edge_map (Dim, *weights, edge.get()); } else { std::vector<Real> dummy_weights (pts->size(), 1.); this->_fe_map->compute_edge_map (Dim, dummy_weights, edge.get()); } } // If there are no user specified points, we use the // quadrature rule else { // initialize quadrature rule this->qrule->init(edge->type(), elem->p_level()); if(this->qrule->shapes_need_reinit()) this->shapes_on_quadrature = false; // We might not need to reinitialize the shape functions if ((this->get_type() != elem->type()) || (edge->type() != static_cast<int>(last_edge)) || // Comparison between enum and unsigned, cast the unsigned to int this->shapes_need_reinit() || !this->shapes_on_quadrature) { // Set the element type this->elem_type = elem->type(); // Set the last_edge last_edge = edge->type(); // Initialize the edge shape functions this->_fe_map->template init_edge_shape_functions<Dim> (this->qrule->get_points(), edge.get()); } // Compute the Jacobian*Weight on the face for integration this->_fe_map->compute_edge_map (Dim, this->qrule->get_weights(), edge.get()); // The shape functions correspond to the qrule this->shapes_on_quadrature = true; } // make a copy of the Jacobian for integration const std::vector<Real> JxW_int(this->_fe_map->get_JxW()); // Find where the integration points are located on the // full element. std::vector<Point> qp; this->inverse_map (elem, this->_fe_map->get_xyz(), qp, tolerance); // compute the shape function and derivative values // at the points qp this->reinit (elem, &qp); // copy back old data this->_fe_map->get_JxW() = JxW_int; }
void QGauss::keast_rule(const Real rule_data[][4], const unsigned int n_pts) { // Like the Dunavant rule, the input data should have 4 columns. These columns // have the following format and implied permutations (w=weight). // {a, 0, 0, w} = 1-permutation (a,a,a) // {a, b, 0, w} = 4-permutation (a,b,b), (b,a,b), (b,b,a), (b,b,b) // {a, 0, b, w} = 6-permutation (a,a,b), (a,b,b), (b,b,a), (b,a,b), (b,a,a), (a,b,a) // {a, b, c, w} = 12-permutation (a,a,b), (a,a,c), (b,a,a), (c,a,a), (a,b,a), (a,c,a) // (a,b,c), (a,c,b), (b,a,c), (b,c,a), (c,a,b), (c,b,a) // Always insert into the points & weights vector relative to the offset unsigned int offset=0; for (unsigned int p=0; p<n_pts; ++p) { // There must always be a non-zero entry to start the row libmesh_assert_not_equal_to (rule_data[p][0], static_cast<Real>(0.0)); // A zero weight may imply you did not set up the raw data correctly libmesh_assert_not_equal_to (rule_data[p][3], static_cast<Real>(0.0)); // What kind of point is this? // One non-zero entry in first 3 cols ? 1-perm (centroid) point = 1 // Two non-zero entries in first 3 cols ? 3-perm point = 3 // Three non-zero entries ? 6-perm point = 6 unsigned int pointtype=1; if (rule_data[p][1] != static_cast<Real>(0.0)) { if (rule_data[p][2] != static_cast<Real>(0.0)) pointtype = 12; else pointtype = 4; } else { // The second entry is zero. What about the third? if (rule_data[p][2] != static_cast<Real>(0.0)) pointtype = 6; } switch (pointtype) { case 1: { // Be sure we have enough space to insert this point libmesh_assert_less (offset + 0, _points.size()); const Real a = rule_data[p][0]; // The point has only a single permutation (the centroid!) _points[offset + 0] = Point(a,a,a); // The weight is always the last entry in the row. _weights[offset + 0] = rule_data[p][3]; offset += pointtype; break; } case 4: { // Be sure we have enough space to insert these points libmesh_assert_less (offset + 3, _points.size()); const Real a = rule_data[p][0]; const Real b = rule_data[p][1]; const Real wt = rule_data[p][3]; // Here it's understood the second entry is to be used twice, and // thus there are three possible permutations. _points[offset + 0] = Point(a,b,b); _points[offset + 1] = Point(b,a,b); _points[offset + 2] = Point(b,b,a); _points[offset + 3] = Point(b,b,b); for (unsigned int j=0; j<pointtype; ++j) _weights[offset + j] = wt; offset += pointtype; break; } case 6: { // Be sure we have enough space to insert these points libmesh_assert_less (offset + 5, _points.size()); const Real a = rule_data[p][0]; const Real b = rule_data[p][2]; const Real wt = rule_data[p][3]; // Three individual entries with six permutations. _points[offset + 0] = Point(a,a,b); _points[offset + 1] = Point(a,b,b); _points[offset + 2] = Point(b,b,a); _points[offset + 3] = Point(b,a,b); _points[offset + 4] = Point(b,a,a); _points[offset + 5] = Point(a,b,a); for (unsigned int j=0; j<pointtype; ++j) _weights[offset + j] = wt; offset += pointtype; break; } case 12: { // Be sure we have enough space to insert these points libmesh_assert_less (offset + 11, _points.size()); const Real a = rule_data[p][0]; const Real b = rule_data[p][1]; const Real c = rule_data[p][2]; const Real wt = rule_data[p][3]; // Three individual entries with six permutations. _points[offset + 0] = Point(a,a,b); _points[offset + 6] = Point(a,b,c); _points[offset + 1] = Point(a,a,c); _points[offset + 7] = Point(a,c,b); _points[offset + 2] = Point(b,a,a); _points[offset + 8] = Point(b,a,c); _points[offset + 3] = Point(c,a,a); _points[offset + 9] = Point(b,c,a); _points[offset + 4] = Point(a,b,a); _points[offset + 10] = Point(c,a,b); _points[offset + 5] = Point(a,c,a); _points[offset + 11] = Point(c,b,a); for (unsigned int j=0; j<pointtype; ++j) _weights[offset + j] = wt; offset += pointtype; break; } default: libmesh_error_msg("Don't know what to do with this many permutation points!"); } } }
Real Hex::quality (const ElemQuality q) const { switch (q) { /** * Compue the min/max diagonal ratio. * Source: CUBIT User's Manual. */ case DIAGONAL: { // Diagonal between node 0 and node 6 const Real d06 = this->length(0,6); // Diagonal between node 3 and node 5 const Real d35 = this->length(3,5); // Diagonal between node 1 and node 7 const Real d17 = this->length(1,7); // Diagonal between node 2 and node 4 const Real d24 = this->length(2,4); // Find the biggest and smallest diagonals const Real min = std::min(d06, std::min(d35, std::min(d17, d24))); const Real max = std::max(d06, std::max(d35, std::max(d17, d24))); libmesh_assert_not_equal_to (max, 0.0); return min / max; break; } /** * Minimum ratio of lengths derived from opposite edges. * Source: CUBIT User's Manual. */ case TAPER: { /** * Compute the side lengths. */ const Real d01 = this->length(0,1); const Real d12 = this->length(1,2); const Real d23 = this->length(2,3); const Real d03 = this->length(0,3); const Real d45 = this->length(4,5); const Real d56 = this->length(5,6); const Real d67 = this->length(6,7); const Real d47 = this->length(4,7); const Real d04 = this->length(0,4); const Real d15 = this->length(1,5); const Real d37 = this->length(3,7); const Real d26 = this->length(2,6); std::vector<Real> edge_ratios(12); // Front edge_ratios[0] = std::min(d01, d45) / std::max(d01, d45); edge_ratios[1] = std::min(d04, d15) / std::max(d04, d15); // Right edge_ratios[2] = std::min(d15, d26) / std::max(d15, d26); edge_ratios[3] = std::min(d12, d56) / std::max(d12, d56); // Back edge_ratios[4] = std::min(d67, d23) / std::max(d67, d23); edge_ratios[5] = std::min(d26, d37) / std::max(d26, d37); // Left edge_ratios[6] = std::min(d04, d37) / std::max(d04, d37); edge_ratios[7] = std::min(d03, d47) / std::max(d03, d47); // Bottom edge_ratios[8] = std::min(d01, d23) / std::max(d01, d23); edge_ratios[9] = std::min(d03, d12) / std::max(d03, d12); // Top edge_ratios[10] = std::min(d45, d67) / std::max(d45, d67); edge_ratios[11] = std::min(d56, d47) / std::max(d56, d47); return *(std::min_element(edge_ratios.begin(), edge_ratios.end())) ; break; } /** * Minimum edge length divided by max diagonal length. * Source: CUBIT User's Manual. */ case STRETCH: { const Real sqrt3 = 1.73205080756888; /** * Compute the maximum diagonal. */ const Real d06 = this->length(0,6); const Real d17 = this->length(1,7); const Real d35 = this->length(3,5); const Real d24 = this->length(2,4); const Real max_diag = std::max(d06, std::max(d17, std::max(d35, d24))); libmesh_assert_not_equal_to ( max_diag, 0.0 ); /** * Compute the minimum edge length. */ std::vector<Real> edges(12); edges[0] = this->length(0,1); edges[1] = this->length(1,2); edges[2] = this->length(2,3); edges[3] = this->length(0,3); edges[4] = this->length(4,5); edges[5] = this->length(5,6); edges[6] = this->length(6,7); edges[7] = this->length(4,7); edges[8] = this->length(0,4); edges[9] = this->length(1,5); edges[10] = this->length(2,6); edges[11] = this->length(3,7); const Real min_edge = *(std::min_element(edges.begin(), edges.end())); return sqrt3 * min_edge / max_diag ; } /** * I don't know what to do for this metric. * Maybe the base class knows... */ default: return Elem::quality(q); } libmesh_error_msg("We'll never get here!"); return 0.; }
Elem * Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in, MeshBase * mesh) { #ifndef NDEBUG const std::vector<largest_id_type>::const_iterator original_in = in; const largest_id_type incoming_header = *in++; libmesh_assert_equal_to (incoming_header, elem_magic_header); #endif // int 0: level const unsigned int level = cast_int<unsigned int>(*in++); #ifdef LIBMESH_ENABLE_AMR // int 1: p level const unsigned int p_level = cast_int<unsigned int>(*in++); // int 2: refinement flag and encoded has_children const int rflag = cast_int<int>(*in++); const int invalid_rflag = cast_int<int>(Elem::INVALID_REFINEMENTSTATE); libmesh_assert_greater_equal (rflag, 0); libmesh_assert_less (rflag, invalid_rflag*2+1); const bool has_children = (rflag > invalid_rflag); const Elem::RefinementState refinement_flag = has_children ? cast_int<Elem::RefinementState>(rflag - invalid_rflag - 1) : cast_int<Elem::RefinementState>(rflag); // int 3: p refinement flag const int pflag = cast_int<int>(*in++); libmesh_assert_greater_equal (pflag, 0); libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE); const Elem::RefinementState p_refinement_flag = cast_int<Elem::RefinementState>(pflag); #else in += 3; #endif // LIBMESH_ENABLE_AMR // int 4: element type const int typeint = cast_int<int>(*in++); libmesh_assert_greater_equal (typeint, 0); libmesh_assert_less (typeint, INVALID_ELEM); const ElemType type = cast_int<ElemType>(typeint); const unsigned int n_nodes = Elem::type_to_n_nodes_map[type]; // int 5: processor id const processor_id_type processor_id = cast_int<processor_id_type>(*in++); libmesh_assert (processor_id < mesh->n_processors() || processor_id == DofObject::invalid_processor_id); // int 6: subdomain id const subdomain_id_type subdomain_id = cast_int<subdomain_id_type>(*in++); // int 7: dof object id const dof_id_type id = cast_int<dof_id_type>(*in++); libmesh_assert_not_equal_to (id, DofObject::invalid_id); #ifdef LIBMESH_ENABLE_UNIQUE_ID // int 8: dof object unique id const unique_id_type unique_id = cast_int<unique_id_type>(*in++); #endif #ifdef LIBMESH_ENABLE_AMR // int 9: parent dof object id. // Note: If level==0, then (*in) == invalid_id. In // this case, the equality check in cast_int<unsigned>(*in) will // never succeed. Therefore, we should only attempt the more // rigorous cast verification in cases where level != 0. const dof_id_type parent_id = (level == 0) ? static_cast<dof_id_type>(*in++) : cast_int<dof_id_type>(*in++); libmesh_assert (level == 0 || parent_id != DofObject::invalid_id); libmesh_assert (level != 0 || parent_id == DofObject::invalid_id); // int 10: local child id // Note: If level==0, then which_child_am_i is not valid, so don't // do the more rigorous cast verification. const unsigned int which_child_am_i = (level == 0) ? static_cast<unsigned int>(*in++) : cast_int<unsigned int>(*in++); #else in += 2; #endif // LIBMESH_ENABLE_AMR const dof_id_type interior_parent_id = static_cast<dof_id_type>(*in++); // Make sure we don't miscount above when adding the "magic" header // plus the real data header libmesh_assert_equal_to (in - original_in, header_size + 1); Elem * elem = mesh->query_elem_ptr(id); // if we already have this element, make sure its // properties match, and update any missing neighbor // links, but then go on if (elem) { libmesh_assert_equal_to (elem->level(), level); libmesh_assert_equal_to (elem->id(), id); //#ifdef LIBMESH_ENABLE_UNIQUE_ID // No check for unique id sanity //#endif libmesh_assert_equal_to (elem->processor_id(), processor_id); libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id); libmesh_assert_equal_to (elem->type(), type); libmesh_assert_equal_to (elem->n_nodes(), n_nodes); #ifndef NDEBUG // All our nodes should be correct for (unsigned int i=0; i != n_nodes; ++i) libmesh_assert(elem->node_id(i) == cast_int<dof_id_type>(*in++)); #else in += n_nodes; #endif #ifdef LIBMESH_ENABLE_AMR libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag); libmesh_assert_equal_to (elem->has_children(), has_children); #ifdef DEBUG if (elem->active()) { libmesh_assert_equal_to (elem->p_level(), p_level); libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag); } #endif libmesh_assert (!level || elem->parent() != libmesh_nullptr); libmesh_assert (!level || elem->parent()->id() == parent_id); libmesh_assert (!level || elem->parent()->child_ptr(which_child_am_i) == elem); #endif // Our interior_parent link should be "close to" correct - we // may have to update it, but we can check for some // inconsistencies. { // If the sending processor sees no interior_parent here, we'd // better agree. if (interior_parent_id == DofObject::invalid_id) { if (elem->dim() < LIBMESH_DIM) libmesh_assert (!(elem->interior_parent())); } // If the sending processor has a remote_elem interior_parent, // then all we know is that we'd better have *some* // interior_parent else if (interior_parent_id == remote_elem->id()) { libmesh_assert(elem->interior_parent()); } else { Elem * ip = mesh->query_elem_ptr(interior_parent_id); // The sending processor sees an interior parent here, so // if we don't have that interior element, then we'd // better have a remote_elem signifying that fact. if (!ip) libmesh_assert_equal_to (elem->interior_parent(), remote_elem); else { // The sending processor has an interior_parent here, // and we have that element, but that does *NOT* mean // we're already linking to it. Perhaps we initially // received elem from a processor on which the // interior_parent link was remote? libmesh_assert(elem->interior_parent() == ip || elem->interior_parent() == remote_elem); // If the link was originally remote, update it if (elem->interior_parent() == remote_elem) { elem->set_interior_parent(ip); } } } } // Our neighbor links should be "close to" correct - we may have // to update a remote_elem link, and we can check for possible // inconsistencies along the way. // // For subactive elements, we don't bother keeping neighbor // links in good shape, so there's nothing we need to set or can // safely assert here. if (!elem->subactive()) for (auto n : elem->side_index_range()) { const dof_id_type neighbor_id = cast_int<dof_id_type>(*in++); // If the sending processor sees a domain boundary here, // we'd better agree. if (neighbor_id == DofObject::invalid_id) { libmesh_assert (!(elem->neighbor_ptr(n))); continue; } // If the sending processor has a remote_elem neighbor here, // then all we know is that we'd better *not* have a domain // boundary. if (neighbor_id == remote_elem->id()) { libmesh_assert(elem->neighbor_ptr(n)); continue; } Elem * neigh = mesh->query_elem_ptr(neighbor_id); // The sending processor sees a neighbor here, so if we // don't have that neighboring element, then we'd better // have a remote_elem signifying that fact. if (!neigh) { libmesh_assert_equal_to (elem->neighbor_ptr(n), remote_elem); continue; } // The sending processor has a neighbor here, and we have // that element, but that does *NOT* mean we're already // linking to it. Perhaps we initially received both elem // and neigh from processors on which their mutual link was // remote? libmesh_assert(elem->neighbor_ptr(n) == neigh || elem->neighbor_ptr(n) == remote_elem); // If the link was originally remote, we should update it, // and make sure the appropriate parts of its family link // back to us. if (elem->neighbor_ptr(n) == remote_elem) { elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } } // Our p level and refinement flags should be "close to" correct // if we're not an active element - we might have a p level // increased or decreased by changes in remote_elem children. // // But if we have remote_elem children, then we shouldn't be // doing a projection on this inactive element on this // processor, so we won't need correct p settings. Couldn't // hurt to update, though. #ifdef LIBMESH_ENABLE_AMR if (elem->processor_id() != mesh->processor_id()) { elem->hack_p_level(p_level); elem->set_p_refinement_flag(p_refinement_flag); } #endif // LIBMESH_ENABLE_AMR // FIXME: We should add some debug mode tests to ensure that the // encoded indexing and boundary conditions are consistent. } else { // We don't already have the element, so we need to create it. // Find the parent if necessary Elem * parent = libmesh_nullptr; #ifdef LIBMESH_ENABLE_AMR // Find a child element's parent if (level > 0) { // Note that we must be very careful to construct the send // connectivity so that parents are encountered before // children. If we get here and can't find the parent that // is a fatal error. parent = mesh->elem_ptr(parent_id); } // Or assert that the sending processor sees no parent else libmesh_assert_equal_to (parent_id, DofObject::invalid_id); #else // No non-level-0 elements without AMR libmesh_assert_equal_to (level, 0); #endif elem = Elem::build(type,parent).release(); libmesh_assert (elem); #ifdef LIBMESH_ENABLE_AMR if (level != 0) { // Since this is a newly created element, the parent must // have previously thought of this child as a remote element. libmesh_assert_equal_to (parent->child_ptr(which_child_am_i), remote_elem); parent->add_child(elem, which_child_am_i); } // Assign the refinement flags and levels elem->set_p_level(p_level); elem->set_refinement_flag(refinement_flag); elem->set_p_refinement_flag(p_refinement_flag); libmesh_assert_equal_to (elem->level(), level); // If this element should have children, assign remote_elem to // all of them for now, for consistency. Later unpacked // elements may overwrite that. if (has_children) { const unsigned int nc = elem->n_children(); for (unsigned int c=0; c != nc; ++c) elem->add_child(const_cast<RemoteElem *>(remote_elem), c); } #endif // LIBMESH_ENABLE_AMR // Assign the IDs elem->subdomain_id() = subdomain_id; elem->processor_id() = processor_id; elem->set_id() = id; #ifdef LIBMESH_ENABLE_UNIQUE_ID elem->set_unique_id() = unique_id; #endif // Assign the connectivity libmesh_assert_equal_to (elem->n_nodes(), n_nodes); for (unsigned int n=0; n != n_nodes; n++) elem->set_node(n) = mesh->node_ptr (cast_int<dof_id_type>(*in++)); // Set interior_parent if found { // We may be unpacking an element that was a ghost element on the // sender, in which case the element's interior_parent may not be // known by the packed element. We'll have to set such // interior_parents to remote_elem ourselves and wait for a // later packed element to give us better information. if (interior_parent_id == remote_elem->id()) { elem->set_interior_parent (const_cast<RemoteElem *>(remote_elem)); } else if (interior_parent_id != DofObject::invalid_id) { // If we don't have the interior parent element, then it's // a remote_elem until we get it. Elem * ip = mesh->query_elem_ptr(interior_parent_id); if (!ip ) elem->set_interior_parent (const_cast<RemoteElem *>(remote_elem)); else elem->set_interior_parent(ip); } } for (auto n : elem->side_index_range()) { const dof_id_type neighbor_id = cast_int<dof_id_type>(*in++); if (neighbor_id == DofObject::invalid_id) continue; // We may be unpacking an element that was a ghost element on the // sender, in which case the element's neighbors may not all be // known by the packed element. We'll have to set such // neighbors to remote_elem ourselves and wait for a later // packed element to give us better information. if (neighbor_id == remote_elem->id()) { elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem)); continue; } // If we don't have the neighbor element, then it's a // remote_elem until we get it. Elem * neigh = mesh->query_elem_ptr(neighbor_id); if (!neigh) { elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem)); continue; } // If we have the neighbor element, then link to it, and // make sure the appropriate parts of its family link back // to us. elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } elem->unpack_indexing(in); } in += elem->packed_indexing_size(); // If this is a coarse element, // add any element side or edge boundary condition ids if (level == 0) { for (auto s : elem->side_index_range()) { const boundary_id_type num_bcs = cast_int<boundary_id_type>(*in++); for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++) mesh->get_boundary_info().add_side (elem, s, cast_int<boundary_id_type>(*in++)); } for (auto e : elem->edge_index_range()) { const boundary_id_type num_bcs = cast_int<boundary_id_type>(*in++); for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++) mesh->get_boundary_info().add_edge (elem, e, cast_int<boundary_id_type>(*in++)); } for (unsigned short sf=0; sf != 2; ++sf) { const boundary_id_type num_bcs = cast_int<boundary_id_type>(*in++); for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++) mesh->get_boundary_info().add_shellface (elem, sf, cast_int<boundary_id_type>(*in++)); } } // Return the new element return elem; }
void Quad9::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); conn.resize(4); switch (iop) { case TECPLOT: { switch(sf) { case 0: // linear sub-quad 0 conn[0] = this->node(0)+1; conn[1] = this->node(4)+1; conn[2] = this->node(8)+1; conn[3] = this->node(7)+1; return; case 1: // linear sub-quad 1 conn[0] = this->node(4)+1; conn[1] = this->node(1)+1; conn[2] = this->node(5)+1; conn[3] = this->node(8)+1; return; case 2: // linear sub-quad 2 conn[0] = this->node(7)+1; conn[1] = this->node(8)+1; conn[2] = this->node(6)+1; conn[3] = this->node(3)+1; return; case 3: // linear sub-quad 3 conn[0] = this->node(8)+1; conn[1] = this->node(5)+1; conn[2] = this->node(2)+1; conn[3] = this->node(6)+1; return; default: libmesh_error(); } } case VTK: { conn.resize(9); 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); return; /* switch(sf) { case 0: // linear sub-quad 0 conn[0] = this->node(0); conn[1] = this->node(4); conn[2] = this->node(8); conn[3] = this->node(7); return; case 1: // linear sub-quad 1 conn[0] = this->node(4); conn[1] = this->node(1); conn[2] = this->node(5); conn[3] = this->node(8); return; case 2: // linear sub-quad 2 conn[0] = this->node(7); conn[1] = this->node(8); conn[2] = this->node(6); conn[3] = this->node(3); return; case 3: // linear sub-quad 3 conn[0] = this->node(8); conn[1] = this->node(5); conn[2] = this->node(2); conn[3] = this->node(6); return; default: libmesh_error(); }*/ } default: { libmesh_error(); } } libmesh_error(); }
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_msg("Invalid sc = " << sc); } } default: libmesh_error_msg("Unsupported IO package " << iop); } }
void InfFE<Dim,T_radial,T_map>::compute_data(const FEType & fet, const Elem * inf_elem, FEComputeData & data) { libmesh_assert(inf_elem); libmesh_assert_not_equal_to (Dim, 0); const Order o_radial (fet.radial_order); const Order radial_mapping_order (Radial::mapping_order()); const Point & p (data.p); const Real v (p(Dim-1)); UniquePtr<const Elem> base_el (inf_elem->build_side_ptr(0)); /* * compute \p interpolated_dist containing the mapping-interpolated * distance of the base point to the origin. This is the same * for all shape functions. Set \p interpolated_dist to 0, it * is added to. */ Real interpolated_dist = 0.; switch (Dim) { case 1: { libmesh_assert_equal_to (inf_elem->type(), INFEDGE2); interpolated_dist = Point(inf_elem->point(0) - inf_elem->point(1)).size(); break; } case 2: { const unsigned int n_base_nodes = base_el->n_nodes(); const Point origin = inf_elem->origin(); const Order base_mapping_order (base_el->default_order()); const ElemType base_mapping_elem_type (base_el->type()); // interpolate the base nodes' distances for (unsigned int n=0; n<n_base_nodes; n++) interpolated_dist += Point(base_el->point(n) - origin).size() * FE<1,LAGRANGE>::shape (base_mapping_elem_type, base_mapping_order, n, p); break; } case 3: { const unsigned int n_base_nodes = base_el->n_nodes(); const Point origin = inf_elem->origin(); const Order base_mapping_order (base_el->default_order()); const ElemType base_mapping_elem_type (base_el->type()); // interpolate the base nodes' distances for (unsigned int n=0; n<n_base_nodes; n++) interpolated_dist += Point(base_el->point(n) - origin).size() * FE<2,LAGRANGE>::shape (base_mapping_elem_type, base_mapping_order, n, p); break; } default: libmesh_error_msg("Unknown Dim = " << Dim); } #ifdef LIBMESH_USE_COMPLEX_NUMBERS // assumption on time-harmonic behavior const short int sign (-1); // the wave number const Real wavenumber = 2. * libMesh::pi * data.frequency / data.speed; // the exponent for time-harmonic behavior const Real exponent = sign /* +1. or -1. */ * wavenumber /* k */ * interpolated_dist /* together with next line: */ * InfFE<Dim,INFINITE_MAP,T_map>::eval(v, radial_mapping_order, 1); /* phase(s,t,v) */ const Number time_harmonic = Number(cos(exponent), sin(exponent)); /* e^(sign*i*k*phase(s,t,v)) */ /* * compute \p shape for all dof in the element */ if (Dim > 1) { const unsigned int n_dof = n_dofs (fet, inf_elem->type()); data.shape.resize(n_dof); for (unsigned int i=0; i<n_dof; i++) { // compute base and radial shape indices unsigned int i_base, i_radial; compute_shape_indices(fet, inf_elem->type(), i, i_base, i_radial); data.shape[i] = (InfFE<Dim,T_radial,T_map>::Radial::decay(v) /* (1.-v)/2. in 3D */ * FEInterface::shape(Dim-1, fet, base_el.get(), i_base, p) /* S_n(s,t) */ * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial)) /* L_n(v) */ * time_harmonic; /* e^(sign*i*k*phase(s,t,v) */ } } else libmesh_error_msg("compute_data() for 1-dimensional InfFE not implemented."); #else const Real speed = data.speed; /* * This is quite weird: the phase is actually * a measure how @e advanced the pressure is that * we compute. In other words: the further away * the node \p data.p is, the further we look into * the future... */ data.phase = interpolated_dist /* phase(s,t,v)/c */ * InfFE<Dim,INFINITE_MAP,T_map>::eval(v, radial_mapping_order, 1) / speed; if (Dim > 1) { const unsigned int n_dof = n_dofs (fet, inf_elem->type()); data.shape.resize(n_dof); for (unsigned int i=0; i<n_dof; i++) { // compute base and radial shape indices unsigned int i_base, i_radial; compute_shape_indices(fet, inf_elem->type(), i, i_base, i_radial); data.shape[i] = InfFE<Dim,T_radial,T_map>::Radial::decay(v) /* (1.-v)/2. in 3D */ * FEInterface::shape(Dim-1, fet, base_el.get(), i_base, p) /* S_n(s,t) */ * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial); /* L_n(v) */ } } else libmesh_error_msg("compute_data() for 1-dimensional InfFE not implemented."); #endif }
void InfFE<Dim,T_radial,T_map>::compute_node_indices_fast (const ElemType inf_elem_type, const unsigned int outer_node_index, unsigned int & base_node, unsigned int & radial_node) { libmesh_assert_not_equal_to (inf_elem_type, INVALID_ELEM); static std::vector<unsigned int> _static_base_node_index; static std::vector<unsigned int> _static_radial_node_index; /* * fast counterpart to compute_node_indices(), uses local static buffers * to store the index maps. The class member * \p _compute_node_indices_fast_current_elem_type remembers * the current element type. * * Note that there exist non-static members storing the * same data. However, you never know what element type * is currently used by the \p InfFE object, and what * request is currently directed to the static \p InfFE * members (which use \p compute_node_indices_fast()). * So separate these. * * check whether the work for this elemtype has already * been done. If so, use this index. Otherwise, refresh * the buffer to this element type. */ if (inf_elem_type==_compute_node_indices_fast_current_elem_type) { base_node = _static_base_node_index [outer_node_index]; radial_node = _static_radial_node_index[outer_node_index]; return; } else { // store the map for _all_ nodes for this element type _compute_node_indices_fast_current_elem_type = inf_elem_type; unsigned int n_nodes = libMesh::invalid_uint; switch (inf_elem_type) { case INFEDGE2: { n_nodes = 2; break; } case INFQUAD4: { n_nodes = 4; break; } case INFQUAD6: { n_nodes = 6; break; } case INFHEX8: { n_nodes = 8; break; } case INFHEX16: { n_nodes = 16; break; } case INFHEX18: { n_nodes = 18; break; } case INFPRISM6: { n_nodes = 6; break; } case INFPRISM12: { n_nodes = 12; break; } default: libmesh_error_msg("ERROR: Bad infinite element type=" << inf_elem_type << ", node=" << outer_node_index); } _static_base_node_index.resize (n_nodes); _static_radial_node_index.resize(n_nodes); for (unsigned int n=0; n<n_nodes; n++) compute_node_indices (inf_elem_type, n, _static_base_node_index [outer_node_index], _static_radial_node_index[outer_node_index]); // and return for the specified node base_node = _static_base_node_index [outer_node_index]; radial_node = _static_radial_node_index[outer_node_index]; return; } }
void Edge3::connectivity(const unsigned int sc, const IOPackage iop, std::vector<dof_id_type>& conn) const { libmesh_assert_less_equal (sc, 1); libmesh_assert_less (sc, this->n_sub_elem()); libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE); // Create storage conn.resize(2); switch (iop) { case TECPLOT: { switch (sc) { case 0: conn[0] = this->node(0)+1; conn[1] = this->node(2)+1; return; case 1: conn[0] = this->node(2)+1; conn[1] = this->node(1)+1; return; default: libmesh_error_msg("Invalid sc = " << sc); } } case VTK: { conn.resize(3); conn[0] = this->node(0); conn[1] = this->node(1); conn[2] = this->node(2); return; /* switch (sc) { case 0: conn[0] = this->node(0); conn[1] = this->node(2); return; case 1: conn[0] = this->node(2); conn[1] = this->node(1); return; default: libmesh_error_msg("Invalid sc = " << sc); } */ } default: libmesh_error_msg("Unsupported IO package " << iop); } }
void unpack(std::vector<largest_id_type>::const_iterator in, Elem** out, MeshBase* mesh) { #ifndef NDEBUG const std::vector<largest_id_type>::const_iterator original_in = in; const largest_id_type incoming_header = *in++; libmesh_assert_equal_to (incoming_header, elem_magic_header); #endif // int 0: level const unsigned int level = static_cast<unsigned int>(*in++); #ifdef LIBMESH_ENABLE_AMR // int 1: p level const unsigned int p_level = static_cast<unsigned int>(*in++); // int 2: refinement flag const int rflag = *in++; libmesh_assert_greater_equal (rflag, 0); libmesh_assert_less (rflag, Elem::INVALID_REFINEMENTSTATE); const Elem::RefinementState refinement_flag = static_cast<Elem::RefinementState>(rflag); // int 3: p refinement flag const int pflag = *in++; libmesh_assert_greater_equal (pflag, 0); libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE); const Elem::RefinementState p_refinement_flag = static_cast<Elem::RefinementState>(pflag); #else in += 3; #endif // LIBMESH_ENABLE_AMR // int 4: element type const int typeint = *in++; libmesh_assert_greater_equal (typeint, 0); libmesh_assert_less (typeint, INVALID_ELEM); const ElemType type = static_cast<ElemType>(typeint); const unsigned int n_nodes = Elem::type_to_n_nodes_map[type]; // int 5: processor id const processor_id_type processor_id = static_cast<processor_id_type>(*in++); libmesh_assert (processor_id < mesh->n_processors() || processor_id == DofObject::invalid_processor_id); // int 6: subdomain id const subdomain_id_type subdomain_id = static_cast<subdomain_id_type>(*in++); // int 7: dof object id const dof_id_type id = static_cast<dof_id_type>(*in++); libmesh_assert_not_equal_to (id, DofObject::invalid_id); #ifdef LIBMESH_ENABLE_UNIQUE_ID // int 8: dof object unique id const unique_id_type unique_id = static_cast<unique_id_type>(*in++); #endif #ifdef LIBMESH_ENABLE_AMR // int 9: parent dof object id const dof_id_type parent_id = static_cast<dof_id_type>(*in++); libmesh_assert (level == 0 || parent_id != DofObject::invalid_id); libmesh_assert (level != 0 || parent_id == DofObject::invalid_id); // int 10: local child id const unsigned int which_child_am_i = static_cast<unsigned int>(*in++); #else in += 2; #endif // LIBMESH_ENABLE_AMR // Make sure we don't miscount above when adding the "magic" header // plus the real data header libmesh_assert_equal_to (in - original_in, header_size + 1); Elem *elem = mesh->query_elem(id); // if we already have this element, make sure its // properties match, and update any missing neighbor // links, but then go on if (elem) { libmesh_assert_equal_to (elem->level(), level); libmesh_assert_equal_to (elem->id(), id); //#ifdef LIBMESH_ENABLE_UNIQUE_ID // No check for unqiue id sanity //#endif libmesh_assert_equal_to (elem->processor_id(), processor_id); libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id); libmesh_assert_equal_to (elem->type(), type); libmesh_assert_equal_to (elem->n_nodes(), n_nodes); #ifndef NDEBUG // All our nodes should be correct for (unsigned int i=0; i != n_nodes; ++i) libmesh_assert(elem->node(i) == static_cast<dof_id_type>(*in++)); #else in += n_nodes; #endif #ifdef LIBMESH_ENABLE_AMR libmesh_assert_equal_to (elem->p_level(), p_level); libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag); libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag); libmesh_assert (!level || elem->parent() != NULL); libmesh_assert (!level || elem->parent()->id() == parent_id); libmesh_assert (!level || elem->parent()->child(which_child_am_i) == elem); #endif // Our neighbor links should be "close to" correct - we may have // to update them, but we can check for some inconsistencies. for (unsigned int n=0; n != elem->n_neighbors(); ++n) { const dof_id_type neighbor_id = static_cast<dof_id_type>(*in++); // If the sending processor sees a domain boundary here, // we'd better agree. if (neighbor_id == DofObject::invalid_id) { libmesh_assert (!(elem->neighbor(n))); continue; } // If the sending processor has a remote_elem neighbor here, // then all we know is that we'd better *not* have a domain // boundary. if (neighbor_id == remote_elem->id()) { libmesh_assert(elem->neighbor(n)); continue; } Elem *neigh = mesh->query_elem(neighbor_id); // The sending processor sees a neighbor here, so if we // don't have that neighboring element, then we'd better // have a remote_elem signifying that fact. if (!neigh) { libmesh_assert_equal_to (elem->neighbor(n), remote_elem); continue; } // The sending processor has a neighbor here, and we have // that element, but that does *NOT* mean we're already // linking to it. Perhaps we initially received both elem // and neigh from processors on which their mutual link was // remote? libmesh_assert(elem->neighbor(n) == neigh || elem->neighbor(n) == remote_elem); // If the link was originally remote, we should update it, // and make sure the appropriate parts of its family link // back to us. if (elem->neighbor(n) == remote_elem) { elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } } // FIXME: We should add some debug mode tests to ensure that the // encoded indexing and boundary conditions are consistent. } else { // We don't already have the element, so we need to create it. // Find the parent if necessary Elem *parent = NULL; #ifdef LIBMESH_ENABLE_AMR // Find a child element's parent if (level > 0) { // Note that we must be very careful to construct the send // connectivity so that parents are encountered before // children. If we get here and can't find the parent that // is a fatal error. parent = mesh->elem(parent_id); } // Or assert that the sending processor sees no parent else libmesh_assert_equal_to (parent_id, static_cast<dof_id_type>(-1)); #else // No non-level-0 elements without AMR libmesh_assert_equal_to (level, 0); #endif elem = Elem::build(type,parent).release(); libmesh_assert (elem); #ifdef LIBMESH_ENABLE_AMR if (level != 0) { // Since this is a newly created element, the parent must // have previously thought of this child as a remote element. libmesh_assert_equal_to (parent->child(which_child_am_i), remote_elem); parent->add_child(elem, which_child_am_i); } // Assign the refinement flags and levels elem->set_p_level(p_level); elem->set_refinement_flag(refinement_flag); elem->set_p_refinement_flag(p_refinement_flag); libmesh_assert_equal_to (elem->level(), level); // If this element definitely should have children, assign // remote_elem to all of them for now, for consistency. Later // unpacked elements may overwrite that. if (!elem->active()) for (unsigned int c=0; c != elem->n_children(); ++c) elem->add_child(const_cast<RemoteElem*>(remote_elem), c); #endif // LIBMESH_ENABLE_AMR // Assign the IDs elem->subdomain_id() = subdomain_id; elem->processor_id() = processor_id; elem->set_id() = id; #ifdef LIBMESH_ENABLE_UNIQUE_ID elem->set_unique_id() = unique_id; #endif // Assign the connectivity libmesh_assert_equal_to (elem->n_nodes(), n_nodes); for (unsigned int n=0; n != n_nodes; n++) elem->set_node(n) = mesh->node_ptr (static_cast<dof_id_type>(*in++)); for (unsigned int n=0; n<elem->n_neighbors(); n++) { const dof_id_type neighbor_id = static_cast<dof_id_type>(*in++); if (neighbor_id == DofObject::invalid_id) continue; // We may be unpacking an element that was a ghost element on the // sender, in which case the element's neighbors may not all be // known by the packed element. We'll have to set such // neighbors to remote_elem ourselves and wait for a later // packed element to give us better information. if (neighbor_id == remote_elem->id()) { elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem)); continue; } // If we don't have the neighbor element, then it's a // remote_elem until we get it. Elem *neigh = mesh->query_elem(neighbor_id); if (!neigh) { elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem)); continue; } // If we have the neighbor element, then link to it, and // make sure the appropriate parts of its family link back // to us. elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } elem->unpack_indexing(in); } in += elem->packed_indexing_size(); // If this is a coarse element, // add any element side or edge boundary condition ids if (level == 0) { for (unsigned int s = 0; s != elem->n_sides(); ++s) { const int num_bcs = *in++; libmesh_assert_greater_equal (num_bcs, 0); for(int bc_it=0; bc_it < num_bcs; bc_it++) mesh->boundary_info->add_side (elem, s, *in++); } for (unsigned int e = 0; e != elem->n_edges(); ++e) { const int num_bcs = *in++; libmesh_assert_greater_equal (num_bcs, 0); for(int bc_it=0; bc_it < num_bcs; bc_it++) mesh->boundary_info->add_edge (elem, e, *in++); } } // Return the new element *out = elem; }
void FEMap::compute_face_map(int dim, const std::vector<Real> & qw, const Elem * side) { libmesh_assert(side); START_LOG("compute_face_map()", "FEMap"); // The number of quadrature points. const unsigned int n_qp = cast_int<unsigned int>(qw.size()); switch (dim) { case 1: { // A 1D finite element, currently assumed to be in 1D space // This means the boundary is a "0D finite element", a // NODEELEM. // Resize the vectors to hold data at the quadrature points { this->xyz.resize(n_qp); normals.resize(n_qp); this->JxW.resize(n_qp); } // If we have no quadrature points, there's nothing else to do if (!n_qp) break; // We need to look back at the full edge to figure out the normal // vector const Elem * elem = side->parent(); libmesh_assert (elem); if (side->node(0) == elem->node(0)) normals[0] = Point(-1.); else { libmesh_assert_equal_to (side->node(0), elem->node(1)); normals[0] = Point(1.); } // Calculate x at the point libmesh_assert_equal_to (this->psi_map.size(), 1); // In the unlikely event we have multiple quadrature // points, they'll be in the same place for (unsigned int p=0; p<n_qp; p++) { this->xyz[p].zero(); this->xyz[p].add_scaled (side->point(0), this->psi_map[0][p]); normals[p] = normals[0]; this->JxW[p] = 1.0*qw[p]; } // done computing the map break; } case 2: { // A 2D finite element living in either 2D or 3D space. // This means the boundary is a 1D finite element, i.e. // and EDGE2 or EDGE3. // Resize the vectors to hold data at the quadrature points { this->xyz.resize(n_qp); this->dxyzdxi_map.resize(n_qp); this->d2xyzdxi2_map.resize(n_qp); this->tangents.resize(n_qp); this->normals.resize(n_qp); this->curvatures.resize(n_qp); this->JxW.resize(n_qp); } // Clear the entities that will be summed // Compute the tangent & normal at the quadrature point for (unsigned int p=0; p<n_qp; p++) { this->tangents[p].resize(LIBMESH_DIM-1); // 1 Tangent in 2D, 2 in 3D this->xyz[p].zero(); this->dxyzdxi_map[p].zero(); this->d2xyzdxi2_map[p].zero(); } // compute x, dxdxi at the quadrature points for (unsigned int i=0; i<this->psi_map.size(); i++) // sum over the nodes { const Point & side_point = side->point(i); for (unsigned int p=0; p<n_qp; p++) // for each quadrature point... { this->xyz[p].add_scaled (side_point, this->psi_map[i][p]); this->dxyzdxi_map[p].add_scaled (side_point, this->dpsidxi_map[i][p]); this->d2xyzdxi2_map[p].add_scaled(side_point, this->d2psidxi2_map[i][p]); } } // Compute the tangent & normal at the quadrature point for (unsigned int p=0; p<n_qp; p++) { // The first tangent comes from just the edge's Jacobian this->tangents[p][0] = this->dxyzdxi_map[p].unit(); #if LIBMESH_DIM == 2 // For a 2D element living in 2D, the normal is given directly // from the entries in the edge Jacobian. this->normals[p] = (Point(this->dxyzdxi_map[p](1), -this->dxyzdxi_map[p](0), 0.)).unit(); #elif LIBMESH_DIM == 3 // For a 2D element living in 3D, there is a second tangent. // For the second tangent, we need to refer to the full // element's (not just the edge's) Jacobian. const Elem * elem = side->parent(); libmesh_assert(elem); // Inverse map xyz[p] to a reference point on the parent... Point reference_point = FE<2,LAGRANGE>::inverse_map(elem, this->xyz[p]); // Get dxyz/dxi and dxyz/deta from the parent map. Point dx_dxi = FE<2,LAGRANGE>::map_xi (elem, reference_point); Point dx_deta = FE<2,LAGRANGE>::map_eta(elem, reference_point); // The second tangent vector is formed by crossing these vectors. tangents[p][1] = dx_dxi.cross(dx_deta).unit(); // Finally, the normal in this case is given by crossing these // two tangents. normals[p] = tangents[p][0].cross(tangents[p][1]).unit(); #endif // The curvature is computed via the familiar Frenet formula: // curvature = [d^2(x) / d (xi)^2] dot [normal] // For a reference, see: // F.S. Merritt, Mathematics Manual, 1962, McGraw-Hill, p. 310 // // Note: The sign convention here is different from the // 3D case. Concave-upward curves (smiles) have a positive // curvature. Concave-downward curves (frowns) have a // negative curvature. Be sure to take that into account! const Real numerator = this->d2xyzdxi2_map[p] * this->normals[p]; const Real denominator = this->dxyzdxi_map[p].norm_sq(); libmesh_assert_not_equal_to (denominator, 0); curvatures[p] = numerator / denominator; } // compute the jacobian at the quadrature points for (unsigned int p=0; p<n_qp; p++) { const Real the_jac = this->dxyzdxi_map[p].norm(); libmesh_assert_greater (the_jac, 0.); this->JxW[p] = the_jac*qw[p]; } // done computing the map break; } case 3: { // A 3D finite element living in 3D space. // Resize the vectors to hold data at the quadrature points { this->xyz.resize(n_qp); this->dxyzdxi_map.resize(n_qp); this->dxyzdeta_map.resize(n_qp); this->d2xyzdxi2_map.resize(n_qp); this->d2xyzdxideta_map.resize(n_qp); this->d2xyzdeta2_map.resize(n_qp); this->tangents.resize(n_qp); this->normals.resize(n_qp); this->curvatures.resize(n_qp); this->JxW.resize(n_qp); } // Clear the entities that will be summed for (unsigned int p=0; p<n_qp; p++) { this->tangents[p].resize(LIBMESH_DIM-1); // 1 Tangent in 2D, 2 in 3D this->xyz[p].zero(); this->dxyzdxi_map[p].zero(); this->dxyzdeta_map[p].zero(); this->d2xyzdxi2_map[p].zero(); this->d2xyzdxideta_map[p].zero(); this->d2xyzdeta2_map[p].zero(); } // compute x, dxdxi at the quadrature points for (unsigned int i=0; i<this->psi_map.size(); i++) // sum over the nodes { const Point & side_point = side->point(i); for (unsigned int p=0; p<n_qp; p++) // for each quadrature point... { this->xyz[p].add_scaled (side_point, this->psi_map[i][p]); this->dxyzdxi_map[p].add_scaled (side_point, this->dpsidxi_map[i][p]); this->dxyzdeta_map[p].add_scaled(side_point, this->dpsideta_map[i][p]); this->d2xyzdxi2_map[p].add_scaled (side_point, this->d2psidxi2_map[i][p]); this->d2xyzdxideta_map[p].add_scaled(side_point, this->d2psidxideta_map[i][p]); this->d2xyzdeta2_map[p].add_scaled (side_point, this->d2psideta2_map[i][p]); } } // Compute the tangents, normal, and curvature at the quadrature point for (unsigned int p=0; p<n_qp; p++) { const Point n = this->dxyzdxi_map[p].cross(this->dxyzdeta_map[p]); this->normals[p] = n.unit(); this->tangents[p][0] = this->dxyzdxi_map[p].unit(); this->tangents[p][1] = n.cross(this->dxyzdxi_map[p]).unit(); // Compute curvature using the typical nomenclature // of the first and second fundamental forms. // For reference, see: // 1) http://mathworld.wolfram.com/MeanCurvature.html // (note -- they are using inward normal) // 2) F.S. Merritt, Mathematics Manual, 1962, McGraw-Hill const Real L = -this->d2xyzdxi2_map[p] * this->normals[p]; const Real M = -this->d2xyzdxideta_map[p] * this->normals[p]; const Real N = -this->d2xyzdeta2_map[p] * this->normals[p]; const Real E = this->dxyzdxi_map[p].norm_sq(); const Real F = this->dxyzdxi_map[p] * this->dxyzdeta_map[p]; const Real G = this->dxyzdeta_map[p].norm_sq(); const Real numerator = E*N -2.*F*M + G*L; const Real denominator = E*G - F*F; libmesh_assert_not_equal_to (denominator, 0.); curvatures[p] = 0.5*numerator/denominator; } // compute the jacobian at the quadrature points, see // http://sp81.msi.umn.edu:999/fluent/fidap/help/theory/thtoc.htm for (unsigned int p=0; p<n_qp; p++) { const Real g11 = (dxdxi_map(p)*dxdxi_map(p) + dydxi_map(p)*dydxi_map(p) + dzdxi_map(p)*dzdxi_map(p)); const Real g12 = (dxdxi_map(p)*dxdeta_map(p) + dydxi_map(p)*dydeta_map(p) + dzdxi_map(p)*dzdeta_map(p)); const Real g21 = g12; const Real g22 = (dxdeta_map(p)*dxdeta_map(p) + dydeta_map(p)*dydeta_map(p) + dzdeta_map(p)*dzdeta_map(p)); const Real the_jac = std::sqrt(g11*g22 - g12*g21); libmesh_assert_greater (the_jac, 0.); this->JxW[p] = the_jac*qw[p]; } // done computing the map break; } default: libmesh_error_msg("Invalid dimension dim = " << dim); } STOP_LOG("compute_face_map()", "FEMap"); }
void Partitioner::set_node_processor_ids(MeshBase & mesh) { START_LOG("set_node_processor_ids()","Partitioner"); // This function must be run on all processors at once libmesh_parallel_only(mesh.comm()); // If we have any unpartitioned elements at this // stage there is a problem libmesh_assert (MeshTools::n_elem(mesh.unpartitioned_elements_begin(), mesh.unpartitioned_elements_end()) == 0); // const dof_id_type orig_n_local_nodes = mesh.n_local_nodes(); // libMesh::err << "[" << mesh.processor_id() << "]: orig_n_local_nodes=" // << orig_n_local_nodes << std::endl; // Build up request sets. Each node is currently owned by a processor because // it is connected to an element owned by that processor. However, during the // repartitioning phase that element may have been assigned a new processor id, but // it is still resident on the original processor. We need to know where to look // for new ids before assigning new ids, otherwise we may be asking the wrong processors // for the wrong information. // // The only remaining issue is what to do with unpartitioned nodes. Since they are required // to live on all processors we can simply rely on ourselves to number them properly. std::vector<std::vector<dof_id_type> > requested_node_ids(mesh.n_processors()); // Loop over all the nodes, count the ones on each processor. We can skip ourself std::vector<dof_id_type> ghost_nodes_from_proc(mesh.n_processors(), 0); MeshBase::node_iterator node_it = mesh.nodes_begin(); const MeshBase::node_iterator node_end = mesh.nodes_end(); for (; node_it != node_end; ++node_it) { Node * node = *node_it; libmesh_assert(node); const processor_id_type current_pid = node->processor_id(); if (current_pid != mesh.processor_id() && current_pid != DofObject::invalid_processor_id) { libmesh_assert_less (current_pid, ghost_nodes_from_proc.size()); ghost_nodes_from_proc[current_pid]++; } } // We know how many objects live on each processor, so reserve() // space for each. for (processor_id_type pid=0; pid != mesh.n_processors(); ++pid) requested_node_ids[pid].reserve(ghost_nodes_from_proc[pid]); // We need to get the new pid for each node from the processor // which *currently* owns the node. We can safely skip ourself for (node_it = mesh.nodes_begin(); node_it != node_end; ++node_it) { Node * node = *node_it; libmesh_assert(node); const processor_id_type current_pid = node->processor_id(); if (current_pid != mesh.processor_id() && current_pid != DofObject::invalid_processor_id) { libmesh_assert_less (current_pid, requested_node_ids.size()); libmesh_assert_less (requested_node_ids[current_pid].size(), ghost_nodes_from_proc[current_pid]); requested_node_ids[current_pid].push_back(node->id()); } // Unset any previously-set node processor ids node->invalidate_processor_id(); } // Loop over all the active elements MeshBase::element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = mesh.active_elements_end(); for ( ; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; libmesh_assert(elem); libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id); // For each node, set the processor ID to the min of // its current value and this Element's processor id. // // TODO: we would probably get better parallel partitioning if // we did something like "min for even numbered nodes, max for // odd numbered". We'd need to be careful about how that would // affect solution ordering for I/O, though. for (unsigned int n=0; n<elem->n_nodes(); ++n) elem->get_node(n)->processor_id() = std::min(elem->get_node(n)->processor_id(), elem->processor_id()); } // And loop over the subactive elements, but don't reassign // nodes that are already active on another processor. MeshBase::element_iterator sub_it = mesh.subactive_elements_begin(); const MeshBase::element_iterator sub_end = mesh.subactive_elements_end(); for ( ; sub_it != sub_end; ++sub_it) { Elem * elem = *sub_it; libmesh_assert(elem); libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id); for (unsigned int n=0; n<elem->n_nodes(); ++n) if (elem->get_node(n)->processor_id() == DofObject::invalid_processor_id) elem->get_node(n)->processor_id() = elem->processor_id(); } // Same for the inactive elements -- we will have already gotten most of these // nodes, *except* for the case of a parent with a subset of children which are // ghost elements. In that case some of the parent nodes will not have been // properly handled yet MeshBase::element_iterator not_it = mesh.not_active_elements_begin(); const MeshBase::element_iterator not_end = mesh.not_active_elements_end(); for ( ; not_it != not_end; ++not_it) { Elem * elem = *not_it; libmesh_assert(elem); libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id); for (unsigned int n=0; n<elem->n_nodes(); ++n) if (elem->get_node(n)->processor_id() == DofObject::invalid_processor_id) elem->get_node(n)->processor_id() = elem->processor_id(); } // We can't assert that all nodes are connected to elements, because // a ParallelMesh with NodeConstraints might have pulled in some // remote nodes solely for evaluating those constraints. // MeshTools::libmesh_assert_connected_nodes(mesh); // For such nodes, we'll do a sanity check later when making sure // that we successfully reset their processor ids to something // valid. // Next set node ids from other processors, excluding self for (processor_id_type p=1; p != mesh.n_processors(); ++p) { // Trade my requests with processor procup and procdown processor_id_type procup = cast_int<processor_id_type> ((mesh.processor_id() + p) % mesh.n_processors()); processor_id_type procdown = cast_int<processor_id_type> ((mesh.n_processors() + mesh.processor_id() - p) % mesh.n_processors()); std::vector<dof_id_type> request_to_fill; mesh.comm().send_receive(procup, requested_node_ids[procup], procdown, request_to_fill); // Fill those requests in-place for (std::size_t i=0; i != request_to_fill.size(); ++i) { Node * node = mesh.node_ptr(request_to_fill[i]); libmesh_assert(node); const processor_id_type new_pid = node->processor_id(); // We may have an invalid processor_id() on nodes that have been // "detatched" from coarsened-away elements but that have not yet // themselves been removed. // libmesh_assert_not_equal_to (new_pid, DofObject::invalid_processor_id); // libmesh_assert_less (new_pid, mesh.n_partitions()); // this is the correct test -- request_to_fill[i] = new_pid; // the number of partitions may } // not equal the number of processors // Trade back the results std::vector<dof_id_type> filled_request; mesh.comm().send_receive(procdown, request_to_fill, procup, filled_request); libmesh_assert_equal_to (filled_request.size(), requested_node_ids[procup].size()); // And copy the id changes we've now been informed of for (std::size_t i=0; i != filled_request.size(); ++i) { Node * node = mesh.node_ptr(requested_node_ids[procup][i]); libmesh_assert(node); // this is the correct test -- the number of partitions may // not equal the number of processors // But: we may have an invalid processor_id() on nodes that // have been "detatched" from coarsened-away elements but // that have not yet themselves been removed. // libmesh_assert_less (filled_request[i], mesh.n_partitions()); node->processor_id(cast_int<processor_id_type>(filled_request[i])); } } #ifdef DEBUG MeshTools::libmesh_assert_valid_procids<Node>(mesh); #endif STOP_LOG("set_node_processor_ids()","Partitioner"); }
bool FEMPhysics::eulerian_residual (bool request_jacobian, DiffContext & /*c*/) { // Only calculate a mesh movement residual if it's necessary if (!_mesh_sys) return request_jacobian; libmesh_not_implemented(); #if 0 FEMContext & context = cast_ref<FEMContext &>(c); // This function only supports fully coupled mesh motion for now libmesh_assert_equal_to (_mesh_sys, this); unsigned int n_qpoints = (context.get_element_qrule())->n_points(); const unsigned int n_x_dofs = (_mesh_x_var == libMesh::invalid_uint) ? 0 : context.dof_indices_var[_mesh_x_var].size(); const unsigned int n_y_dofs = (_mesh_y_var == libMesh::invalid_uint) ? 0 : context.dof_indices_var[_mesh_y_var].size(); const unsigned int n_z_dofs = (_mesh_z_var == libMesh::invalid_uint) ? 0 : context.dof_indices_var[_mesh_z_var].size(); const unsigned int mesh_xyz_var = n_x_dofs ? _mesh_x_var : (n_y_dofs ? _mesh_y_var : (n_z_dofs ? _mesh_z_var : libMesh::invalid_uint)); // If we're our own _mesh_sys, we'd better be in charge of // at least one coordinate, and we'd better have the same // FE type for all coordinates we are in charge of libmesh_assert_not_equal_to (mesh_xyz_var, libMesh::invalid_uint); libmesh_assert(!n_x_dofs || context.element_fe_var[_mesh_x_var] == context.element_fe_var[mesh_xyz_var]); libmesh_assert(!n_y_dofs || context.element_fe_var[_mesh_y_var] == context.element_fe_var[mesh_xyz_var]); libmesh_assert(!n_z_dofs || context.element_fe_var[_mesh_z_var] == context.element_fe_var[mesh_xyz_var]); const std::vector<std::vector<Real>> & psi = context.element_fe_var[mesh_xyz_var]->get_phi(); for (unsigned int var = 0; var != context.n_vars(); ++var) { // Mesh motion only affects time-evolving variables if (this->is_time_evolving(var)) continue; // The mesh coordinate variables themselves are Lagrangian, // not Eulerian, and no convective term is desired. if (/*_mesh_sys == this && */ (var == _mesh_x_var || var == _mesh_y_var || var == _mesh_z_var)) continue; // Some of this code currently relies on the assumption that // we can pull mesh coordinate data from our own system if (_mesh_sys != this) libmesh_not_implemented(); // This residual should only be called by unsteady solvers: // if the mesh is steady, there's no mesh convection term! UnsteadySolver * unsteady; if (this->time_solver->is_steady()) return request_jacobian; else unsteady = cast_ptr<UnsteadySolver*>(this->time_solver.get()); const std::vector<Real> & JxW = context.element_fe_var[var]->get_JxW(); const std::vector<std::vector<Real>> & phi = context.element_fe_var[var]->get_phi(); const std::vector<std::vector<RealGradient>> & dphi = context.element_fe_var[var]->get_dphi(); const unsigned int n_u_dofs = context.dof_indices_var[var].size(); DenseSubVector<Number> & Fu = *context.elem_subresiduals[var]; DenseSubMatrix<Number> & Kuu = *context.elem_subjacobians[var][var]; DenseSubMatrix<Number> * Kux = n_x_dofs ? context.elem_subjacobians[var][_mesh_x_var] : nullptr; DenseSubMatrix<Number> * Kuy = n_y_dofs ? context.elem_subjacobians[var][_mesh_y_var] : nullptr; DenseSubMatrix<Number> * Kuz = n_z_dofs ? context.elem_subjacobians[var][_mesh_z_var] : nullptr; std::vector<Real> delta_x(n_x_dofs, 0.); std::vector<Real> delta_y(n_y_dofs, 0.); std::vector<Real> delta_z(n_z_dofs, 0.); for (unsigned int i = 0; i != n_x_dofs; ++i) { unsigned int j = context.dof_indices_var[_mesh_x_var][i]; delta_x[i] = libmesh_real(this->current_solution(j)) - libmesh_real(unsteady->old_nonlinear_solution(j)); } for (unsigned int i = 0; i != n_y_dofs; ++i) { unsigned int j = context.dof_indices_var[_mesh_y_var][i]; delta_y[i] = libmesh_real(this->current_solution(j)) - libmesh_real(unsteady->old_nonlinear_solution(j)); } for (unsigned int i = 0; i != n_z_dofs; ++i) { unsigned int j = context.dof_indices_var[_mesh_z_var][i]; delta_z[i] = libmesh_real(this->current_solution(j)) - libmesh_real(unsteady->old_nonlinear_solution(j)); } for (unsigned int qp = 0; qp != n_qpoints; ++qp) { Gradient grad_u = context.interior_gradient(var, qp); RealGradient convection(0.); for (unsigned int i = 0; i != n_x_dofs; ++i) convection(0) += delta_x[i] * psi[i][qp]; for (unsigned int i = 0; i != n_y_dofs; ++i) convection(1) += delta_y[i] * psi[i][qp]; for (unsigned int i = 0; i != n_z_dofs; ++i) convection(2) += delta_z[i] * psi[i][qp]; for (unsigned int i = 0; i != n_u_dofs; ++i) { Number JxWxPhiI = JxW[qp] * phi[i][qp]; Fu(i) += (convection * grad_u) * JxWxPhiI; if (request_jacobian) { Number JxWxPhiI = JxW[qp] * phi[i][qp]; for (unsigned int j = 0; j != n_u_dofs; ++j) Kuu(i,j) += JxWxPhiI * (convection * dphi[j][qp]); Number JxWxPhiIoverDT = JxWxPhiI/this->deltat; Number JxWxPhiIxDUDXoverDT = JxWxPhiIoverDT * grad_u(0); for (unsigned int j = 0; j != n_x_dofs; ++j) (*Kux)(i,j) += JxWxPhiIxDUDXoverDT * psi[j][qp]; Number JxWxPhiIxDUDYoverDT = JxWxPhiIoverDT * grad_u(1); for (unsigned int j = 0; j != n_y_dofs; ++j) (*Kuy)(i,j) += JxWxPhiIxDUDYoverDT * psi[j][qp]; Number JxWxPhiIxDUDZoverDT = JxWxPhiIoverDT * grad_u(2); for (unsigned int j = 0; j != n_z_dofs; ++j) (*Kuz)(i,j) += JxWxPhiIxDUDZoverDT * psi[j][qp]; } } } } #endif // 0 return request_jacobian; }
Point FE<Dim,T>::inverse_map (const Elem* elem, const Point& physical_point, const Real tolerance, const bool secure) { libmesh_assert(elem); libmesh_assert_greater_equal (tolerance, 0.); // Start logging the map inversion. START_LOG("inverse_map()", "FE"); // How much did the point on the reference // element change by in this Newton step? Real inverse_map_error = 0.; // The point on the reference element. This is // the "initial guess" for Newton's method. The // centroid seems like a good idea, but computing // it is a little more intensive than, say taking // the zero point. // // Convergence should be insensitive of this choice // for "good" elements. Point p; // the zero point. No computation required // The number of iterations in the map inversion process. unsigned int cnt = 0; // The number of iterations after which we give up and declare // divergence const unsigned int max_cnt = 10; // The distance (in master element space) beyond which we give up // and declare divergence. This is no longer used... // Real max_step_length = 4.; // Newton iteration loop. do { // Where our current iterate \p p maps to. const Point physical_guess = FE<Dim,T>::map (elem, p); // How far our current iterate is from the actual point. const Point delta = physical_point - physical_guess; // Increment in current iterate \p p, will be computed. Point dp; // The form of the map and how we invert it depends // on the dimension that we are in. switch (Dim) { // ------------------------------------------------------------------ // 0D map inversion is trivial case 0: { break; } // ------------------------------------------------------------------ // 1D map inversion // // Here we find the point on a 1D reference element that maps to // the point \p physical_point in the domain. This is a bit tricky // since we do not want to assume that the point \p physical_point // is also in a 1D domain. In particular, this method might get // called on the edge of a 3D element, in which case // \p physical_point actually lives in 3D. case 1: { const Point dxi = FE<Dim,T>::map_xi (elem, p); // Newton's method in this case looks like // // {X} - {X_n} = [J]*dp // // Where {X}, {X_n} are 3x1 vectors, [J] is a 3x1 matrix // d(x,y,z)/dxi, and we seek dp, a scalar. Since the above // system is either overdetermined or rank-deficient, we will // solve the normal equations for this system // // [J]^T ({X} - {X_n}) = [J]^T [J] {dp} // // which involves the trivial inversion of the scalar // G = [J]^T [J] const Real G = dxi*dxi; if (secure) libmesh_assert_greater (G, 0.); const Real Ginv = 1./G; const Real dxidelta = dxi*delta; dp(0) = Ginv*dxidelta; // No master elements have radius > 4, but sometimes we // can take a step that big while still converging // if (secure) // libmesh_assert_less (dp.size(), max_step_length); break; } // ------------------------------------------------------------------ // 2D map inversion // // Here we find the point on a 2D reference element that maps to // the point \p physical_point in the domain. This is a bit tricky // since we do not want to assume that the point \p physical_point // is also in a 2D domain. In particular, this method might get // called on the face of a 3D element, in which case // \p physical_point actually lives in 3D. case 2: { const Point dxi = FE<Dim,T>::map_xi (elem, p); const Point deta = FE<Dim,T>::map_eta (elem, p); // Newton's method in this case looks like // // {X} - {X_n} = [J]*{dp} // // Where {X}, {X_n} are 3x1 vectors, [J] is a 3x2 matrix // d(x,y,z)/d(xi,eta), and we seek {dp}, a 2x1 vector. Since // the above system is either overdermined or rank-deficient, // we will solve the normal equations for this system // // [J]^T ({X} - {X_n}) = [J]^T [J] {dp} // // which involves the inversion of the 2x2 matrix // [G] = [J]^T [J] const Real G11 = dxi*dxi, G12 = dxi*deta, G21 = dxi*deta, G22 = deta*deta; const Real det = (G11*G22 - G12*G21); if (secure) libmesh_assert_not_equal_to (det, 0.); const Real inv_det = 1./det; const Real Ginv11 = G22*inv_det, Ginv12 = -G12*inv_det, Ginv21 = -G21*inv_det, Ginv22 = G11*inv_det; const Real dxidelta = dxi*delta; const Real detadelta = deta*delta; dp(0) = (Ginv11*dxidelta + Ginv12*detadelta); dp(1) = (Ginv21*dxidelta + Ginv22*detadelta); // No master elements have radius > 4, but sometimes we // can take a step that big while still converging // if (secure) // libmesh_assert_less (dp.size(), max_step_length); break; } // ------------------------------------------------------------------ // 3D map inversion // // Here we find the point in a 3D reference element that maps to // the point \p physical_point in a 3D domain. Nothing special // has to happen here, since (unless the map is singular because // you have a BAD element) the map will be invertable and we can // apply Newton's method directly. case 3: { const Point dxi = FE<Dim,T>::map_xi (elem, p); const Point deta = FE<Dim,T>::map_eta (elem, p); const Point dzeta = FE<Dim,T>::map_zeta (elem, p); // Newton's method in this case looks like // // {X} = {X_n} + [J]*{dp} // // Where {X}, {X_n} are 3x1 vectors, [J] is a 3x3 matrix // d(x,y,z)/d(xi,eta,zeta), and we seek {dp}, a 3x1 vector. // Since the above system is nonsingular for invertable maps // we will solve // // {dp} = [J]^-1 ({X} - {X_n}) // // which involves the inversion of the 3x3 matrix [J] const Real J11 = dxi(0), J12 = deta(0), J13 = dzeta(0), J21 = dxi(1), J22 = deta(1), J23 = dzeta(1), J31 = dxi(2), J32 = deta(2), J33 = dzeta(2); const Real det = (J11*(J22*J33 - J23*J32) + J12*(J23*J31 - J21*J33) + J13*(J21*J32 - J22*J31)); if (secure) libmesh_assert_not_equal_to (det, 0.); const Real inv_det = 1./det; const Real Jinv11 = (J22*J33 - J23*J32)*inv_det, Jinv12 = -(J12*J33 - J13*J32)*inv_det, Jinv13 = (J12*J23 - J13*J22)*inv_det, Jinv21 = -(J21*J33 - J23*J31)*inv_det, Jinv22 = (J11*J33 - J13*J31)*inv_det, Jinv23 = -(J11*J23 - J13*J21)*inv_det, Jinv31 = (J21*J32 - J22*J31)*inv_det, Jinv32 = -(J11*J32 - J12*J31)*inv_det, Jinv33 = (J11*J22 - J12*J21)*inv_det; dp(0) = (Jinv11*delta(0) + Jinv12*delta(1) + Jinv13*delta(2)); dp(1) = (Jinv21*delta(0) + Jinv22*delta(1) + Jinv23*delta(2)); dp(2) = (Jinv31*delta(0) + Jinv32*delta(1) + Jinv33*delta(2)); // No master elements have radius > 4, but sometimes we // can take a step that big while still converging // if (secure) // libmesh_assert_less (dp.size(), max_step_length); break; } // Some other dimension? default: libmesh_error(); } // end switch(Dim), dp now computed // ||P_n+1 - P_n|| inverse_map_error = dp.size(); // P_n+1 = P_n + dp p.add (dp); // Increment the iteration count. cnt++; // Watch for divergence of Newton's // method. Here's how it goes: // (1) For good elements, we expect convergence in 10 // iterations, with no too-large steps. // - If called with (secure == true) and we have not yet converged // print out a warning message. // - If called with (secure == true) and we have not converged in // 20 iterations abort // (2) This method may be called in cases when the target point is not // inside the element and we have no business expecting convergence. // For these cases if we have not converged in 10 iterations forget // about it. if (cnt > max_cnt) { // Warn about divergence when secure is true - this // shouldn't happen if (secure) { // Print every time in devel/dbg modes #ifndef NDEBUG libmesh_here(); libMesh::err << "WARNING: Newton scheme has not converged in " << cnt << " iterations:" << std::endl << " physical_point=" << physical_point << " physical_guess=" << physical_guess << " dp=" << dp << " p=" << p << " error=" << inverse_map_error << " in element " << elem->id() << std::endl; elem->print_info(libMesh::err); #else // In optimized mode, just print once that an inverse_map() call // had trouble converging its Newton iteration. libmesh_do_once(libMesh::err << "WARNING: At least one element took more than " << max_cnt << " iterations to converge in inverse_map()...\n" << "Rerun in devel/dbg mode for more details." << std::endl;); #endif // NDEBUG if (cnt > 2*max_cnt) { libMesh::err << "ERROR: Newton scheme FAILED to converge in " << cnt << " iterations!" << " in element " << elem->id() << std::endl; elem->print_info(libMesh::err); libmesh_error(); } } // Return a far off point when secure is false - this // should only happen when we're trying to map a point // that's outside the element else { for (unsigned int i=0; i != Dim; ++i) p(i) = 1e6; STOP_LOG("inverse_map()", "FE"); return p; } }
void Quad8::connectivity(const unsigned int sf, const IOPackage iop, std::vector<unsigned int>& conn) const { libmesh_assert_less (sf, this->n_sub_elem()); libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE); switch (iop) { // Note: TECPLOT connectivity is output as four triangles with // a central quadrilateral. Therefore, the first four connectivity // arrays are degenerate quads (triangles in Tecplot). case TECPLOT: { // Create storage conn.resize(4); switch(sf) { case 0: // linear sub-tri 0 conn[0] = this->node(0)+1; conn[1] = this->node(4)+1; conn[2] = this->node(7)+1; conn[3] = this->node(7)+1; return; case 1: // linear sub-tri 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; return; case 2: // linear sub-tri 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; return; case 3: // linear sub-tri 3 conn[0] = this->node(7)+1; conn[1] = this->node(6)+1; conn[2] = this->node(3)+1; conn[3] = this->node(3)+1; return; case 4: // linear sub-quad conn[0] = this->node(4)+1; conn[1] = this->node(5)+1; conn[2] = this->node(6)+1; conn[3] = this->node(7)+1; return; default: libmesh_error(); } } // Note: VTK connectivity is output as four triangles with // a central quadrilateral. Therefore most of the connectivity // arrays have length three. case VTK: { // Create storage conn.resize(8); 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); return; /* conn.resize(3); switch (sf) { case 0: // linear sub-tri 0 conn[0] = this->node(0); conn[1] = this->node(4); conn[2] = this->node(7); return; case 1: // linear sub-tri 1 conn[0] = this->node(4); conn[1] = this->node(1); conn[2] = this->node(5); return; case 2: // linear sub-tri 2 conn[0] = this->node(5); conn[1] = this->node(2); conn[2] = this->node(6); return; case 3: // linear sub-tri 3 conn[0] = this->node(7); conn[1] = this->node(6); conn[2] = this->node(3); return; case 4: conn.resize(4); // linear sub-quad conn[0] = this->node(4); conn[1] = this->node(5); conn[2] = this->node(6); conn[3] = this->node(7); */ // return; // default: // libmesh_error(); // } } default: libmesh_error(); } libmesh_error(); }
Real InfHex::quality (const ElemQuality q) const { switch (q) { /** * Compue the min/max diagonal ratio. * Source: CUBIT User's Manual. * * For infinite elements, we just only compute * the diagonal in the face... * Don't know whether this makes sense, * but should be a feasible way. */ case DIAGONAL: { // Diagonal between node 0 and node 2 const Real d02 = this->length(0,2); // Diagonal between node 1 and node 3 const Real d13 = this->length(1,3); // Find the biggest and smallest diagonals const Real min = std::min(d02, d13); const Real max = std::max(d02, d13); libmesh_assert_not_equal_to (max, 0.0); return min / max; break; } /** * Minimum ratio of lengths derived from opposite edges. * Source: CUBIT User's Manual. * * For IFEMs, do this only for the base face... * Does this make sense? */ case TAPER: { /** * Compute the side lengths. */ const Real d01 = this->length(0,1); const Real d12 = this->length(1,2); const Real d23 = this->length(2,3); const Real d03 = this->length(0,3); std::vector<Real> edge_ratios(2); // Bottom edge_ratios[8] = std::min(d01, d23) / std::max(d01, d23); edge_ratios[9] = std::min(d03, d12) / std::max(d03, d12); return *(std::min_element(edge_ratios.begin(), edge_ratios.end())) ; break; } /** * Minimum edge length divided by max diagonal length. * Source: CUBIT User's Manual. * * And again, we mess around a bit, for the IFEMs... * Do this only for the base. */ case STRETCH: { /** * Should this be a sqrt2, when we do this for the base only? */ const Real sqrt3 = 1.73205080756888; /** * Compute the maximum diagonal in the base. */ const Real d02 = this->length(0,2); const Real d13 = this->length(1,3); const Real max_diag = std::max(d02, d13); libmesh_assert_not_equal_to ( max_diag, 0.0 ); /** * Compute the minimum edge length in the base. */ std::vector<Real> edges(4); edges[0] = this->length(0,1); edges[1] = this->length(1,2); edges[2] = this->length(2,3); edges[3] = this->length(0,3); const Real min_edge = *(std::min_element(edges.begin(), edges.end())); return sqrt3 * min_edge / max_diag ; } /** * I don't know what to do for this metric. * Maybe the base class knows... */ default: return Elem::quality(q); } libmesh_error_msg("We'll never get here!"); return 0.; }
void QGauss::dunavant_rule(const Real rule_data[][4], const unsigned int n_pts) { // The input data array has 4 columns. The first 3 are the permutation points. // The last column is the weights for a given set of permutation points. A zero // in two of the first 3 columns implies the point is a 1-permutation (centroid). // A zero in one of the first 3 columns implies the point is a 3-permutation. // Otherwise each point is assumed to be a 6-permutation. // Always insert into the points & weights vector relative to the offset unsigned int offset=0; for (unsigned int p=0; p<n_pts; ++p) { // There must always be a non-zero entry to start the row libmesh_assert_not_equal_to ( rule_data[p][0], static_cast<Real>(0.0) ); // A zero weight may imply you did not set up the raw data correctly libmesh_assert_not_equal_to ( rule_data[p][3], static_cast<Real>(0.0) ); // What kind of point is this? // One non-zero entry in first 3 cols ? 1-perm (centroid) point = 1 // Two non-zero entries in first 3 cols ? 3-perm point = 3 // Three non-zero entries ? 6-perm point = 6 unsigned int pointtype=1; if (rule_data[p][1] != static_cast<Real>(0.0)) { if (rule_data[p][2] != static_cast<Real>(0.0)) pointtype = 6; else pointtype = 3; } switch (pointtype) { case 1: { // Be sure we have enough space to insert this point libmesh_assert_less (offset + 0, _points.size()); // The point has only a single permutation (the centroid!) _points[offset + 0] = Point(rule_data[p][0], rule_data[p][0]); // The weight is always the last entry in the row. _weights[offset + 0] = rule_data[p][3]; offset += 1; break; } case 3: { // Be sure we have enough space to insert these points libmesh_assert_less (offset + 2, _points.size()); // Here it's understood the second entry is to be used twice, and // thus there are three possible permutations. _points[offset + 0] = Point(rule_data[p][0], rule_data[p][1]); _points[offset + 1] = Point(rule_data[p][1], rule_data[p][0]); _points[offset + 2] = Point(rule_data[p][1], rule_data[p][1]); for (unsigned int j=0; j<3; ++j) _weights[offset + j] = rule_data[p][3]; offset += 3; break; } case 6: { // Be sure we have enough space to insert these points libmesh_assert_less (offset + 5, _points.size()); // Three individual entries with six permutations. _points[offset + 0] = Point(rule_data[p][0], rule_data[p][1]); _points[offset + 1] = Point(rule_data[p][0], rule_data[p][2]); _points[offset + 2] = Point(rule_data[p][1], rule_data[p][0]); _points[offset + 3] = Point(rule_data[p][1], rule_data[p][2]); _points[offset + 4] = Point(rule_data[p][2], rule_data[p][0]); _points[offset + 5] = Point(rule_data[p][2], rule_data[p][1]); for (unsigned int j=0; j<6; ++j) _weights[offset + j] = rule_data[p][3]; offset += 6; break; } default: libmesh_error_msg("Don't know what to do with this many permutation points!"); } } }
void JumpErrorEstimator::estimate_error (const System& system, ErrorVector& error_per_cell, const NumericVector<Number>* solution_vector, bool estimate_parent_error) { START_LOG("estimate_error()", "JumpErrorEstimator"); /* Conventions for assigning the direction of the normal: - e & f are global element ids Case (1.) Elements are at the same level, e<f Compute the flux jump on the face and add it as a contribution to error_per_cell[e] and error_per_cell[f] ---------------------- | | | | | f | | | | | e |---> n | | | | | | | ---------------------- Case (2.) The neighbor is at a higher level. Compute the flux jump on e's face and add it as a contribution to error_per_cell[e] and error_per_cell[f] ---------------------- | | | | | | e |---> n | | | | | |-----------| f | | | | | | | | | | | | | ---------------------- */ // The current mesh const MeshBase& mesh = system.get_mesh(); // The number of variables in the system const unsigned int n_vars = system.n_vars(); // The DofMap for this system const DofMap& dof_map = system.get_dof_map(); // Resize the error_per_cell vector to be // the number of elements, initialize it to 0. error_per_cell.resize (mesh.max_elem_id()); std::fill (error_per_cell.begin(), error_per_cell.end(), 0.); // Declare a vector of floats which is as long as // error_per_cell above, and fill with zeros. This vector will be // used to keep track of the number of edges (faces) on each active // element which are either: // 1) an internal edge // 2) an edge on a Neumann boundary for which a boundary condition // function has been specified. // The error estimator can be scaled by the number of flux edges (faces) // which the element actually has to obtain a more uniform measure // of the error. Use floats instead of ints since in case 2 (above) // f gets 1/2 of a flux face contribution from each of his // neighbors std::vector<float> n_flux_faces; if (scale_by_n_flux_faces) n_flux_faces.resize(error_per_cell.size(), 0); // Prepare current_local_solution to localize a non-standard // solution vector if necessary if (solution_vector && solution_vector != system.solution.get()) { NumericVector<Number>* newsol = const_cast<NumericVector<Number>*>(solution_vector); System &sys = const_cast<System&>(system); newsol->swap(*sys.solution); sys.update(); } fine_context.reset(new FEMContext(system)); coarse_context.reset(new FEMContext(system)); // Loop over all the variables we've been requested to find jumps in, to // pre-request for (var=0; var<n_vars; var++) { // Possibly skip this variable if (error_norm.weight(var) == 0.0) continue; // FIXME: Need to generalize this to vector-valued elements. [PB] FEBase* side_fe = NULL; const std::set<unsigned char>& elem_dims = fine_context->elem_dimensions(); for (std::set<unsigned char>::const_iterator dim_it = elem_dims.begin(); dim_it != elem_dims.end(); ++dim_it) { const unsigned char dim = *dim_it; fine_context->get_side_fe( var, side_fe, dim ); libmesh_assert_not_equal_to(side_fe->get_fe_type().family, SCALAR); side_fe->get_xyz(); } } this->init_context(*fine_context); this->init_context(*coarse_context); // Iterate over all the active elements in the mesh // that live on this processor. MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { // e is necessarily an active element on the local processor const Elem* e = *elem_it; const dof_id_type e_id = e->id(); #ifdef LIBMESH_ENABLE_AMR // See if the parent of element e has been examined yet; // if not, we may want to compute the estimator on it const Elem* parent = e->parent(); // We only can compute and only need to compute on // parents with all active children bool compute_on_parent = true; if (!parent || !estimate_parent_error) compute_on_parent = false; else for (unsigned int c=0; c != parent->n_children(); ++c) if (!parent->child(c)->active()) compute_on_parent = false; if (compute_on_parent && !error_per_cell[parent->id()]) { // Compute a projection onto the parent DenseVector<Number> Uparent; FEBase::coarsened_dof_values (*(system.solution), dof_map, parent, Uparent, false); // Loop over the neighbors of the parent for (unsigned int n_p=0; n_p<parent->n_neighbors(); n_p++) { if (parent->neighbor(n_p) != NULL) // parent has a neighbor here { // Find the active neighbors in this direction std::vector<const Elem*> active_neighbors; parent->neighbor(n_p)-> active_family_tree_by_neighbor(active_neighbors, parent); // Compute the flux to each active neighbor for (unsigned int a=0; a != active_neighbors.size(); ++a) { const Elem *f = active_neighbors[a]; // FIXME - what about when f->level < // parent->level()?? if (f->level() >= parent->level()) { fine_context->pre_fe_reinit(system, f); coarse_context->pre_fe_reinit(system, parent); libmesh_assert_equal_to (coarse_context->get_elem_solution().size(), Uparent.size()); coarse_context->get_elem_solution() = Uparent; this->reinit_sides(); // Loop over all significant variables in the system for (var=0; var<n_vars; var++) if (error_norm.weight(var) != 0.0) { this->internal_side_integration(); error_per_cell[fine_context->get_elem().id()] += static_cast<ErrorVectorReal>(fine_error); error_per_cell[coarse_context->get_elem().id()] += static_cast<ErrorVectorReal>(coarse_error); } // Keep track of the number of internal flux // sides found on each element if (scale_by_n_flux_faces) { n_flux_faces[fine_context->get_elem().id()]++; n_flux_faces[coarse_context->get_elem().id()] += this->coarse_n_flux_faces_increment(); } } } } else if (integrate_boundary_sides) { fine_context->pre_fe_reinit(system, parent); libmesh_assert_equal_to (fine_context->get_elem_solution().size(), Uparent.size()); fine_context->get_elem_solution() = Uparent; fine_context->side = n_p; fine_context->side_fe_reinit(); // If we find a boundary flux for any variable, // let's just count it as a flux face for all // variables. Otherwise we'd need to keep track of // a separate n_flux_faces and error_per_cell for // every single var. bool found_boundary_flux = false; for (var=0; var<n_vars; var++) if (error_norm.weight(var) != 0.0) { if (this->boundary_side_integration()) { error_per_cell[fine_context->get_elem().id()] += static_cast<ErrorVectorReal>(fine_error); found_boundary_flux = true; } } if (scale_by_n_flux_faces && found_boundary_flux) n_flux_faces[fine_context->get_elem().id()]++; } } } #endif // #ifdef LIBMESH_ENABLE_AMR // If we do any more flux integration, e will be the fine element fine_context->pre_fe_reinit(system, e); // Loop over the neighbors of element e for (unsigned int n_e=0; n_e<e->n_neighbors(); n_e++) { if ((e->neighbor(n_e) != NULL) || integrate_boundary_sides) { fine_context->side = n_e; fine_context->side_fe_reinit(); } if (e->neighbor(n_e) != NULL) // e is not on the boundary { const Elem* f = e->neighbor(n_e); const dof_id_type f_id = f->id(); // Compute flux jumps if we are in case 1 or case 2. if ((f->active() && (f->level() == e->level()) && (e_id < f_id)) || (f->level() < e->level())) { // f is now the coarse element coarse_context->pre_fe_reinit(system, f); this->reinit_sides(); // Loop over all significant variables in the system for (var=0; var<n_vars; var++) if (error_norm.weight(var) != 0.0) { this->internal_side_integration(); error_per_cell[fine_context->get_elem().id()] += static_cast<ErrorVectorReal>(fine_error); error_per_cell[coarse_context->get_elem().id()] += static_cast<ErrorVectorReal>(coarse_error); } // Keep track of the number of internal flux // sides found on each element if (scale_by_n_flux_faces) { n_flux_faces[fine_context->get_elem().id()]++; n_flux_faces[coarse_context->get_elem().id()] += this->coarse_n_flux_faces_increment(); } } // end if (case1 || case2) } // if (e->neigbor(n_e) != NULL) // Otherwise, e is on the boundary. If it happens to // be on a Dirichlet boundary, we need not do anything. // On the other hand, if e is on a Neumann (flux) boundary // with grad(u).n = g, we need to compute the additional residual // (h * \int |g - grad(u_h).n|^2 dS)^(1/2). // We can only do this with some knowledge of the boundary // conditions, i.e. the user must have attached an appropriate // BC function. else if (integrate_boundary_sides) { bool found_boundary_flux = false; for (var=0; var<n_vars; var++) if (error_norm.weight(var) != 0.0) if (this->boundary_side_integration()) { error_per_cell[fine_context->get_elem().id()] += static_cast<ErrorVectorReal>(fine_error); found_boundary_flux = true; } if (scale_by_n_flux_faces && found_boundary_flux) n_flux_faces[fine_context->get_elem().id()]++; } // end if (e->neighbor(n_e) == NULL) } // end loop over neighbors } // End loop over active local elements // Each processor has now computed the error contribuions // for its local elements. We need to sum the vector // and then take the square-root of each component. Note // that we only need to sum if we are running on multiple // processors, and we only need to take the square-root // if the value is nonzero. There will in general be many // zeros for the inactive elements. // First sum the vector of estimated error values this->reduce_error(error_per_cell, system.comm()); // Compute the square-root of each component. for (std::size_t i=0; i<error_per_cell.size(); i++) if (error_per_cell[i] != 0.) error_per_cell[i] = std::sqrt(error_per_cell[i]); if (this->scale_by_n_flux_faces) { // Sum the vector of flux face counts this->reduce_error(n_flux_faces, system.comm()); // Sanity check: Make sure the number of flux faces is // always an integer value #ifdef DEBUG for (unsigned int i=0; i<n_flux_faces.size(); ++i) libmesh_assert_equal_to (n_flux_faces[i], static_cast<float>(static_cast<unsigned int>(n_flux_faces[i])) ); #endif // Scale the error by the number of flux faces for each element for (unsigned int i=0; i<n_flux_faces.size(); ++i) { if (n_flux_faces[i] == 0.0) // inactive or non-local element continue; //libMesh::out << "Element " << i << " has " << n_flux_faces[i] << " flux faces." << std::endl; error_per_cell[i] /= static_cast<ErrorVectorReal>(n_flux_faces[i]); } } // If we used a non-standard solution before, now is the time to fix // the current_local_solution if (solution_vector && solution_vector != system.solution.get()) { NumericVector<Number>* newsol = const_cast<NumericVector<Number>*>(solution_vector); System &sys = const_cast<System&>(system); newsol->swap(*sys.solution); sys.update(); } STOP_LOG("estimate_error()", "JumpErrorEstimator"); }
void Prism18::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: { 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(9)+1; conn[5] = this->node(15)+1; conn[6] = this->node(17)+1; conn[7] = this->node(17)+1; return; } case 1: { 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(15)+1; conn[5] = this->node(10)+1; conn[6] = this->node(16)+1; conn[7] = this->node(16)+1; return; } case 2: { 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(17)+1; conn[5] = this->node(16)+1; conn[6] = this->node(11)+1; conn[7] = this->node(11)+1; return; } case 3: { 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(15)+1; conn[5] = this->node(16)+1; conn[6] = this->node(17)+1; conn[7] = this->node(17)+1; return; } case 4: { conn[0] = this->node(9)+1; conn[1] = this->node(15)+1; conn[2] = this->node(17)+1; conn[3] = this->node(17)+1; conn[4] = this->node(3)+1; conn[5] = this->node(12)+1; conn[6] = this->node(14)+1; conn[7] = this->node(14)+1; return; } case 5: { conn[0] = this->node(15)+1; conn[1] = this->node(10)+1; conn[2] = this->node(16)+1; conn[3] = this->node(16)+1; conn[4] = this->node(12)+1; conn[5] = this->node(4)+1; conn[6] = this->node(13)+1; conn[7] = this->node(13)+1; return; } case 6: { conn[0] = this->node(17)+1; conn[1] = this->node(16)+1; conn[2] = this->node(11)+1; conn[3] = this->node(11)+1; conn[4] = this->node(14)+1; conn[5] = this->node(13)+1; conn[6] = this->node(5)+1; conn[7] = this->node(5)+1; return; } case 7: { conn[0] = this->node(15)+1; conn[1] = this->node(16)+1; conn[2] = this->node(17)+1; conn[3] = this->node(17)+1; conn[4] = this->node(12)+1; conn[5] = this->node(13)+1; conn[6] = this->node(14)+1; conn[7] = this->node(14)+1; return; } default: libmesh_error_msg("Invalid sc = " << sc); } } case VTK: { // VTK now supports VTK_BIQUADRATIC_QUADRATIC_WEDGE directly conn.resize(18); // VTK's VTK_BIQUADRATIC_QUADRATIC_WEDGE first 9 (vertex) and // last 3 (mid-face) nodes match. The middle and top layers // of mid-edge nodes are reversed from LibMesh's. for (unsigned i=0; i<conn.size(); ++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; /* conn.resize(6); switch (sc) { case 0: { conn[0] = this->node(0); conn[1] = this->node(6); conn[2] = this->node(8); conn[3] = this->node(9); conn[4] = this->node(15); conn[5] = this->node(17); return; } case 1: { conn[0] = this->node(6); conn[1] = this->node(1); conn[2] = this->node(7); conn[3] = this->node(15); conn[4] = this->node(10); conn[5] = this->node(16); return; } case 2: { conn[0] = this->node(8); conn[1] = this->node(7); conn[2] = this->node(2); conn[3] = this->node(17); conn[4] = this->node(16); conn[5] = this->node(11); return; } case 3: { conn[0] = this->node(6); conn[1] = this->node(7); conn[2] = this->node(8); conn[3] = this->node(15); conn[4] = this->node(16); conn[5] = this->node(17); return; } case 4: { conn[0] = this->node(9); conn[1] = this->node(15); conn[2] = this->node(17); conn[3] = this->node(3); conn[4] = this->node(12); conn[5] = this->node(14); return; } case 5: { conn[0] = this->node(15); conn[1] = this->node(10); conn[2] = this->node(16); conn[3] = this->node(12); conn[4] = this->node(4); conn[5] = this->node(13); return; } case 6: { conn[0] = this->node(17); conn[1] = this->node(16); conn[2] = this->node(11); conn[3] = this->node(14); conn[4] = this->node(13); conn[5] = this->node(5); return; } case 7: { conn[0] = this->node(15); conn[1] = this->node(16); conn[2] = this->node(17); conn[3] = this->node(12); conn[4] = this->node(13); conn[5] = this->node(14); return; } default: libmesh_error_msg("Invalid sc = " << sc); } */ } default: libmesh_error_msg("Unsupported IO package " << iop); } }