unsigned int FEInterface::n_dofs(const unsigned int dim, const FEType& fe_t, const ElemType t) { #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS if ( is_InfFE_elem(t) ) return ifem_n_dofs(dim, fe_t, t); #endif const Order o = fe_t.order; fe_with_vec_switch(n_dofs(t, o)); libmesh_error(); return 0; }
void InfFE<Dim,T_radial,T_map>::compute_shape_indices (const FEType & fet, const ElemType inf_elem_type, const unsigned int i, unsigned int & base_shape, unsigned int & radial_shape) { /* * An example is provided: the numbers in comments refer to * a fictitious InfHex18. The numbers are chosen as exemplary * values. There is currently no base approximation that * requires this many dof's at nodes, sides, faces and in the element. * * the order of the shape functions is heavily related with the * order the dofs are assigned in \p DofMap::distributed_dofs(). * Due to the infinite elements with higher-order base approximation, * some more effort is necessary. * * numbering scheme: * 1. all vertices in the base, assign node->n_comp() dofs to each vertex * 2. all vertices further out: innermost loop: radial shapes, * then the base approximation shapes * 3. all side nodes in the base, assign node->n_comp() dofs to each side node * 4. all side nodes further out: innermost loop: radial shapes, * then the base approximation shapes * 5. (all) face nodes in the base, assign node->n_comp() dofs to each face node * 6. (all) face nodes further out: innermost loop: radial shapes, * then the base approximation shapes * 7. element-associated dof in the base * 8. element-associated dof further out */ const unsigned int radial_order = static_cast<unsigned int>(fet.radial_order.get_order()); // 4 const unsigned int radial_order_p_one = radial_order+1; // 5 const ElemType base_elem_type (Base::get_elem_type(inf_elem_type)); // QUAD9 // assume that the number of dof is the same for all vertices unsigned int n_base_vertices = libMesh::invalid_uint; // 4 const unsigned int n_base_vertex_dof = FEInterface::n_dofs_at_node (Dim-1, fet, base_elem_type, 0);// 2 unsigned int n_base_side_nodes = libMesh::invalid_uint; // 4 unsigned int n_base_side_dof = libMesh::invalid_uint; // 3 unsigned int n_base_face_nodes = libMesh::invalid_uint; // 1 unsigned int n_base_face_dof = libMesh::invalid_uint; // 5 const unsigned int n_base_elem_dof = FEInterface::n_dofs_per_elem (Dim-1, fet, base_elem_type);// 9 switch (inf_elem_type) { case INFEDGE2: { n_base_vertices = 1; n_base_side_nodes = 0; n_base_face_nodes = 0; n_base_side_dof = 0; n_base_face_dof = 0; break; } case INFQUAD4: { n_base_vertices = 2; n_base_side_nodes = 0; n_base_face_nodes = 0; n_base_side_dof = 0; n_base_face_dof = 0; break; } case INFQUAD6: { n_base_vertices = 2; n_base_side_nodes = 1; n_base_face_nodes = 0; n_base_side_dof = FEInterface::n_dofs_at_node (Dim-1, fet,base_elem_type, n_base_vertices); n_base_face_dof = 0; break; } case INFHEX8: { n_base_vertices = 4; n_base_side_nodes = 0; n_base_face_nodes = 0; n_base_side_dof = 0; n_base_face_dof = 0; break; } case INFHEX16: { n_base_vertices = 4; n_base_side_nodes = 4; n_base_face_nodes = 0; n_base_side_dof = FEInterface::n_dofs_at_node (Dim-1, fet,base_elem_type, n_base_vertices); n_base_face_dof = 0; break; } case INFHEX18: { n_base_vertices = 4; n_base_side_nodes = 4; n_base_face_nodes = 1; n_base_side_dof = FEInterface::n_dofs_at_node (Dim-1, fet,base_elem_type, n_base_vertices); n_base_face_dof = FEInterface::n_dofs_at_node (Dim-1, fet,base_elem_type, 8); break; } case INFPRISM6: { n_base_vertices = 3; n_base_side_nodes = 0; n_base_face_nodes = 0; n_base_side_dof = 0; n_base_face_dof = 0; break; } case INFPRISM12: { n_base_vertices = 3; n_base_side_nodes = 3; n_base_face_nodes = 0; n_base_side_dof = FEInterface::n_dofs_at_node (Dim-1, fet,base_elem_type, n_base_vertices); n_base_face_dof = 0; break; } default: libmesh_error_msg("Unrecognized inf_elem_type = " << inf_elem_type); } { // these are the limits describing the intervals where the shape function lies const unsigned int n_dof_at_base_vertices = n_base_vertices*n_base_vertex_dof; // 8 const unsigned int n_dof_at_all_vertices = n_dof_at_base_vertices*radial_order_p_one; // 40 const unsigned int n_dof_at_base_sides = n_base_side_nodes*n_base_side_dof; // 12 const unsigned int n_dof_at_all_sides = n_dof_at_base_sides*radial_order_p_one; // 60 const unsigned int n_dof_at_base_face = n_base_face_nodes*n_base_face_dof; // 5 const unsigned int n_dof_at_all_faces = n_dof_at_base_face*radial_order_p_one; // 25 // start locating the shape function if (i < n_dof_at_base_vertices) // range of i: 0..7 { // belongs to vertex in the base radial_shape = 0; base_shape = i; } else if (i < n_dof_at_all_vertices) // range of i: 8..39 { /* belongs to vertex in the outer shell * * subtract the number of dof already counted, * so that i_offset contains only the offset for the base */ const unsigned int i_offset = i - n_dof_at_base_vertices; // 0..31 // first the radial dof are counted, then the base dof radial_shape = (i_offset % radial_order) + 1; base_shape = i_offset / radial_order; } else if (i < n_dof_at_all_vertices+n_dof_at_base_sides) // range of i: 40..51 { // belongs to base, is a side node radial_shape = 0; base_shape = i - radial_order * n_dof_at_base_vertices; // 8..19 } else if (i < n_dof_at_all_vertices+n_dof_at_all_sides) // range of i: 52..99 { // belongs to side node in the outer shell const unsigned int i_offset = i - (n_dof_at_all_vertices + n_dof_at_base_sides); // 0..47 radial_shape = (i_offset % radial_order) + 1; base_shape = (i_offset / radial_order) + n_dof_at_base_vertices; } else if (i < n_dof_at_all_vertices+n_dof_at_all_sides+n_dof_at_base_face) // range of i: 100..104 { // belongs to the node in the base face radial_shape = 0; base_shape = i - radial_order*(n_dof_at_base_vertices + n_dof_at_base_sides); // 20..24 } else if (i < n_dof_at_all_vertices+n_dof_at_all_sides+n_dof_at_all_faces) // range of i: 105..124 { // belongs to the node in the outer face const unsigned int i_offset = i - (n_dof_at_all_vertices + n_dof_at_all_sides + n_dof_at_base_face); // 0..19 radial_shape = (i_offset % radial_order) + 1; base_shape = (i_offset / radial_order) + n_dof_at_base_vertices + n_dof_at_base_sides; } else if (i < n_dof_at_all_vertices+n_dof_at_all_sides+n_dof_at_all_faces+n_base_elem_dof) // range of i: 125..133 { // belongs to the base and is an element associated shape radial_shape = 0; base_shape = i - (n_dof_at_all_vertices + n_dof_at_all_sides + n_dof_at_all_faces); // 0..8 } else // range of i: 134..169 { libmesh_assert_less (i, n_dofs(fet, inf_elem_type)); // belongs to the outer shell and is an element associated shape const unsigned int i_offset = i - (n_dof_at_all_vertices + n_dof_at_all_sides + n_dof_at_all_faces + n_base_elem_dof); // 0..19 radial_shape = (i_offset % radial_order) + 1; base_shape = (i_offset / radial_order) + n_dof_at_base_vertices + n_dof_at_base_sides + n_dof_at_base_face; } } return; }
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 }