Real InfFE<Dim,T_radial,T_map>::shape(const FEType & fet, const Elem * inf_elem, const unsigned int i, const Point & p) { libmesh_assert(inf_elem); libmesh_assert_not_equal_to (Dim, 0); #ifdef DEBUG // this makes only sense when used for mapping if ((T_radial != INFINITE_MAP) && !_warned_for_shape) { libMesh::err << "WARNING: InfFE<Dim,T_radial,T_map>::shape(...) does _not_" << std::endl << " return the correct trial function! Use " << std::endl << " InfFE<Dim,T_radial,T_map>::compute_data(..) instead!" << std::endl; _warned_for_shape = true; } #endif const Order o_radial (fet.radial_order); const Real v (p(Dim-1)); UniquePtr<const Elem> base_el (inf_elem->build_side_ptr(0)); unsigned int i_base, i_radial; compute_shape_indices(fet, inf_elem->type(), i, i_base, i_radial); if (Dim > 1) return FEInterface::shape(Dim-1, fet, base_el.get(), i_base, p) * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial) * InfFE<Dim,T_radial,T_map>::Radial::decay(v); else return InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial) * InfFE<Dim,T_radial,T_map>::Radial::decay(v); }
Real InfFE<Dim,T_radial,T_map>::shape(const FEType & fet, const ElemType inf_elem_type, const unsigned int i, const Point & p) { libmesh_assert_not_equal_to (Dim, 0); #ifdef DEBUG // this makes only sense when used for mapping if ((T_radial != INFINITE_MAP) && !_warned_for_shape) { libMesh::err << "WARNING: InfFE<Dim,T_radial,T_map>::shape(...) does _not_" << std::endl << " return the correct trial function! Use " << std::endl << " InfFE<Dim,T_radial,T_map>::compute_data(..) instead!" << std::endl; _warned_for_shape = true; } #endif const ElemType base_et (Base::get_elem_type(inf_elem_type)); const Order o_radial (fet.radial_order); const Real v (p(Dim-1)); unsigned int i_base, i_radial; compute_shape_indices(fet, inf_elem_type, i, i_base, i_radial); //TODO:[SP/DD] exp(ikr) is still missing here! if (Dim > 1) return FEInterface::shape(Dim-1, fet, base_et, i_base, p) * InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial) * InfFE<Dim,T_radial,T_map>::Radial::decay(v); else return InfFE<Dim,T_radial,T_map>::eval(v, o_radial, i_radial) * InfFE<Dim,T_radial,T_map>::Radial::decay(v); }
void InfFE<Dim,T_radial,T_map>::init_shape_functions(const Elem * inf_elem) { libmesh_assert(inf_elem); // Start logging the radial shape function initialization START_LOG("init_shape_functions()", "InfFE"); // ----------------------------------------------------------------- // fast access to some const int's for the radial data const unsigned int n_radial_mapping_sf = cast_int<unsigned int>(radial_map.size()); const unsigned int n_radial_approx_sf = cast_int<unsigned int>(mode.size()); const unsigned int n_radial_qp = cast_int<unsigned int>(som.size()); // ----------------------------------------------------------------- // initialize most of the things related to mapping // The element type and order to use in the base map const Order base_mapping_order ( base_elem->default_order() ); const ElemType base_mapping_elem_type ( base_elem->type() ); // the number of base shape functions used to construct the map // (Lagrange shape functions are used for mapping in the base) unsigned int n_base_mapping_shape_functions = Base::n_base_mapping_sf(base_mapping_elem_type, base_mapping_order); const unsigned int n_total_mapping_shape_functions = n_radial_mapping_sf * n_base_mapping_shape_functions; // ----------------------------------------------------------------- // initialize most of the things related to physical approximation unsigned int n_base_approx_shape_functions; if (Dim > 1) n_base_approx_shape_functions = base_fe->n_shape_functions(); else n_base_approx_shape_functions = 1; const unsigned int n_total_approx_shape_functions = n_radial_approx_sf * n_base_approx_shape_functions; // update class member field _n_total_approx_sf = n_total_approx_shape_functions; // The number of the base quadrature points. const unsigned int n_base_qp = base_qrule->n_points(); // The total number of quadrature points. const unsigned int n_total_qp = n_radial_qp * n_base_qp; // update class member field _n_total_qp = n_total_qp; // ----------------------------------------------------------------- // initialize the node and shape numbering maps { // these vectors work as follows: the i-th entry stores // the associated base/radial node number _radial_node_index.resize (n_total_mapping_shape_functions); _base_node_index.resize (n_total_mapping_shape_functions); // similar for the shapes: the i-th entry stores // the associated base/radial shape number _radial_shape_index.resize (n_total_approx_shape_functions); _base_shape_index.resize (n_total_approx_shape_functions); const ElemType inf_elem_type (inf_elem->type()); // fill the node index map for (unsigned int n=0; n<n_total_mapping_shape_functions; n++) { compute_node_indices (inf_elem_type, n, _base_node_index[n], _radial_node_index[n]); libmesh_assert_less (_base_node_index[n], n_base_mapping_shape_functions); libmesh_assert_less (_radial_node_index[n], n_radial_mapping_sf); } // fill the shape index map for (unsigned int n=0; n<n_total_approx_shape_functions; n++) { compute_shape_indices (this->fe_type, inf_elem_type, n, _base_shape_index[n], _radial_shape_index[n]); libmesh_assert_less (_base_shape_index[n], n_base_approx_shape_functions); libmesh_assert_less (_radial_shape_index[n], n_radial_approx_sf); } } // ----------------------------------------------------------------- // resize the base data fields dist.resize(n_base_mapping_shape_functions); // ----------------------------------------------------------------- // resize the total data fields // the phase term varies with xi, eta and zeta(v): store it for _all_ qp // // when computing the phase, we need the base approximations // therefore, initialize the phase here, but evaluate it // in combine_base_radial(). // // the weight, though, is only needed at the radial quadrature points, n_radial_qp. // but for a uniform interface to the protected data fields // the weight data field (which are accessible from the outside) are expanded to n_total_qp. weight.resize (n_total_qp); dweightdv.resize (n_total_qp); dweight.resize (n_total_qp); dphase.resize (n_total_qp); dphasedxi.resize (n_total_qp); dphasedeta.resize (n_total_qp); dphasedzeta.resize (n_total_qp); // this vector contains the integration weights for the combined quadrature rule _total_qrule_weights.resize(n_total_qp); // ----------------------------------------------------------------- // InfFE's data fields phi, dphi, dphidx, phi_map etc hold the _total_ // shape and mapping functions, respectively { phi.resize (n_total_approx_shape_functions); dphi.resize (n_total_approx_shape_functions); dphidx.resize (n_total_approx_shape_functions); dphidy.resize (n_total_approx_shape_functions); dphidz.resize (n_total_approx_shape_functions); dphidxi.resize (n_total_approx_shape_functions); #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES libmesh_do_once(libMesh::err << "Second derivatives for Infinite elements" << " are not yet implemented!" << std::endl); d2phi.resize (n_total_approx_shape_functions); d2phidx2.resize (n_total_approx_shape_functions); d2phidxdy.resize (n_total_approx_shape_functions); d2phidxdz.resize (n_total_approx_shape_functions); d2phidy2.resize (n_total_approx_shape_functions); d2phidydz.resize (n_total_approx_shape_functions); d2phidz2.resize (n_total_approx_shape_functions); d2phidxi2.resize (n_total_approx_shape_functions); if (Dim > 1) { d2phidxideta.resize (n_total_approx_shape_functions); d2phideta2.resize (n_total_approx_shape_functions); } if (Dim > 2) { d2phidetadzeta.resize (n_total_approx_shape_functions); d2phidxidzeta.resize (n_total_approx_shape_functions); d2phidzeta2.resize (n_total_approx_shape_functions); } #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES if (Dim > 1) dphideta.resize (n_total_approx_shape_functions); if (Dim == 3) dphidzeta.resize (n_total_approx_shape_functions); std::vector<std::vector<Real> > & phi_map = this->_fe_map->get_phi_map(); std::vector<std::vector<Real> > & dphidxi_map = this->_fe_map->get_dphidxi_map(); phi_map.resize (n_total_mapping_shape_functions); dphidxi_map.resize (n_total_mapping_shape_functions); #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES std::vector<std::vector<Real> > & d2phidxi2_map = this->_fe_map->get_d2phidxi2_map(); d2phidxi2_map.resize (n_total_mapping_shape_functions); if (Dim > 1) { std::vector<std::vector<Real> > & d2phidxideta_map = this->_fe_map->get_d2phidxideta_map(); std::vector<std::vector<Real> > & d2phideta2_map = this->_fe_map->get_d2phideta2_map(); d2phidxideta_map.resize (n_total_mapping_shape_functions); d2phideta2_map.resize (n_total_mapping_shape_functions); } if (Dim == 3) { std::vector<std::vector<Real> > & d2phidxidzeta_map = this->_fe_map->get_d2phidxidzeta_map(); std::vector<std::vector<Real> > & d2phidetadzeta_map = this->_fe_map->get_d2phidetadzeta_map(); std::vector<std::vector<Real> > & d2phidzeta2_map = this->_fe_map->get_d2phidzeta2_map(); d2phidxidzeta_map.resize (n_total_mapping_shape_functions); d2phidetadzeta_map.resize (n_total_mapping_shape_functions); d2phidzeta2_map.resize (n_total_mapping_shape_functions); } #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES if (Dim > 1) { std::vector<std::vector<Real> > & dphideta_map = this->_fe_map->get_dphideta_map(); dphideta_map.resize (n_total_mapping_shape_functions); } if (Dim == 3) { std::vector<std::vector<Real> > & dphidzeta_map = this->_fe_map->get_dphidzeta_map(); dphidzeta_map.resize (n_total_mapping_shape_functions); } } // ----------------------------------------------------------------- // collect all the for loops, where inner vectors are // resized to the appropriate number of quadrature points { for (unsigned int i=0; i<n_total_approx_shape_functions; i++) { phi[i].resize (n_total_qp); dphi[i].resize (n_total_qp); dphidx[i].resize (n_total_qp); dphidy[i].resize (n_total_qp); dphidz[i].resize (n_total_qp); dphidxi[i].resize (n_total_qp); #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES d2phi[i].resize (n_total_qp); d2phidx2[i].resize (n_total_qp); d2phidxdy[i].resize (n_total_qp); d2phidxdz[i].resize (n_total_qp); d2phidy2[i].resize (n_total_qp); d2phidydz[i].resize (n_total_qp); d2phidy2[i].resize (n_total_qp); d2phidxi2[i].resize (n_total_qp); if (Dim > 1) { d2phidxideta[i].resize (n_total_qp); d2phideta2[i].resize (n_total_qp); } if (Dim > 2) { d2phidxidzeta[i].resize (n_total_qp); d2phidetadzeta[i].resize (n_total_qp); d2phidzeta2[i].resize (n_total_qp); } #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES if (Dim > 1) dphideta[i].resize (n_total_qp); if (Dim == 3) dphidzeta[i].resize (n_total_qp); } for (unsigned int i=0; i<n_total_mapping_shape_functions; i++) { std::vector<std::vector<Real> > & phi_map = this->_fe_map->get_phi_map(); std::vector<std::vector<Real> > & dphidxi_map = this->_fe_map->get_dphidxi_map(); phi_map[i].resize (n_total_qp); dphidxi_map[i].resize (n_total_qp); #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES std::vector<std::vector<Real> > & d2phidxi2_map = this->_fe_map->get_d2phidxi2_map(); d2phidxi2_map[i].resize (n_total_qp); if (Dim > 1) { std::vector<std::vector<Real> > & d2phidxideta_map = this->_fe_map->get_d2phidxideta_map(); std::vector<std::vector<Real> > & d2phideta2_map = this->_fe_map->get_d2phideta2_map(); d2phidxideta_map[i].resize (n_total_qp); d2phideta2_map[i].resize (n_total_qp); } if (Dim > 2) { std::vector<std::vector<Real> > & d2phidxidzeta_map = this->_fe_map->get_d2phidxidzeta_map(); std::vector<std::vector<Real> > & d2phidetadzeta_map = this->_fe_map->get_d2phidetadzeta_map(); std::vector<std::vector<Real> > & d2phidzeta2_map = this->_fe_map->get_d2phidzeta2_map(); d2phidxidzeta_map[i].resize (n_total_qp); d2phidetadzeta_map[i].resize (n_total_qp); d2phidzeta2_map[i].resize (n_total_qp); } #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES if (Dim > 1) { std::vector<std::vector<Real> > & dphideta_map = this->_fe_map->get_dphideta_map(); dphideta_map[i].resize (n_total_qp); } if (Dim == 3) { std::vector<std::vector<Real> > & dphidzeta_map = this->_fe_map->get_dphidzeta_map(); dphidzeta_map[i].resize (n_total_qp); } } } { // ----------------------------------------------------------------- // (a) compute scalar values at _all_ quadrature points -- for uniform // access from the outside to these fields // (b) form a std::vector<Real> which contains the appropriate weights // of the combined quadrature rule! const std::vector<Point> & radial_qp = radial_qrule->get_points(); libmesh_assert_equal_to (radial_qp.size(), n_radial_qp); const std::vector<Real> & radial_qw = radial_qrule->get_weights(); const std::vector<Real> & base_qw = base_qrule->get_weights(); libmesh_assert_equal_to (radial_qw.size(), n_radial_qp); libmesh_assert_equal_to (base_qw.size(), n_base_qp); for (unsigned int rp=0; rp<n_radial_qp; rp++) for (unsigned int bp=0; bp<n_base_qp; bp++) { weight [ bp+rp*n_base_qp ] = Radial::D (radial_qp[rp](0)); dweightdv[ bp+rp*n_base_qp ] = Radial::D_deriv (radial_qp[rp](0)); _total_qrule_weights[ bp+rp*n_base_qp ] = radial_qw[rp] * base_qw[bp]; } } /** * Stop logging the radial shape function initialization */ STOP_LOG("init_shape_functions()", "InfFE"); }
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 }