InfFE<Dim,T_radial,T_map>::InfFE (const FEType & fet) : FEBase (Dim, fet), _n_total_approx_sf (0), _n_total_qp (0), base_qrule (libmesh_nullptr), radial_qrule (libmesh_nullptr), base_elem (libmesh_nullptr), base_fe (libmesh_nullptr), // initialize the current_fe_type to all the same // values as \p fet (since the FE families and coordinate // map type should @e not change), but use an invalid order // for the radial part (since this is the only order // that may change!). // the data structures like \p phi etc are not initialized // through the constructor, but throught reinit() current_fe_type ( FEType(fet.order, fet.family, INVALID_ORDER, fet.radial_family, fet.inf_map) ) { // Sanity checks libmesh_assert_equal_to (T_radial, fe_type.radial_family); libmesh_assert_equal_to (T_map, fe_type.inf_map); // build the base_fe object, handle the UniquePtr if (Dim != 1) { UniquePtr<FEBase> ap_fb(FEBase::build(Dim-1, fet)); base_fe = ap_fb.release(); } }
void InfFE<Dim,T_radial,T_base>::init_face_shape_functions(const std::vector<Point>&, const Elem* inf_side) { libmesh_assert(inf_side); // Currently, this makes only sense in 3-D! libmesh_assert_equal_to (Dim, 3); // Initialiize the radial shape functions this->init_radial_shape_functions(inf_side); // Initialize the base shape functions this->update_base_elem(inf_side); // Initialize the base quadratur rule base_qrule->init(base_elem->type(), inf_side->p_level()); // base_fe still corresponds to the (dim-1)-dimensional base of the InfFE object, // so update the fe_base. { libmesh_assert_equal_to (Dim, 3); AutoPtr<FEBase> ap_fb(FEBase::build(Dim-2, this->fe_type)); if (base_fe != NULL) delete base_fe; base_fe = ap_fb.release(); base_fe->attach_quadrature_rule(base_qrule); } // initialize the shape functions on the base base_fe->init_base_shape_functions(base_fe->qrule->get_points(), base_elem); // the number of quadrature points const unsigned int n_radial_qp = libmesh_cast_int<unsigned int>(som.size()); const unsigned int n_base_qp = base_qrule->n_points(); const unsigned int n_total_qp = n_radial_qp * n_base_qp; // the quadratur weigths _total_qrule_weights.resize(n_total_qp); // now inite the shapes for boundary work { // 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 mapping shape functions // (Lagrange shape functions are used for mapping in the base) const unsigned int n_radial_mapping_sf = libmesh_cast_int<unsigned int>(radial_map.size()); const 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 the node and shape numbering maps { _radial_node_index.resize (n_total_mapping_shape_functions); _base_node_index.resize (n_total_mapping_shape_functions); const ElemType inf_face_elem_type (inf_side->type()); // fill the node index map for (unsigned int n=0; n<n_total_mapping_shape_functions; n++) { compute_node_indices (inf_face_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); } } // rezise map data fields { std::vector<std::vector<Real> >& psi_map = this->_fe_map->get_psi(); std::vector<std::vector<Real> >& dpsidxi_map = this->_fe_map->get_dpsidxi(); std::vector<std::vector<Real> >& d2psidxi2_map = this->_fe_map->get_d2psidxi2(); psi_map.resize (n_total_mapping_shape_functions); dpsidxi_map.resize (n_total_mapping_shape_functions); d2psidxi2_map.resize (n_total_mapping_shape_functions); // if (Dim == 3) { std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta(); std::vector<std::vector<Real> >& d2psidxideta_map = this->_fe_map->get_d2psidxideta(); std::vector<std::vector<Real> >& d2psideta2_map = this->_fe_map->get_d2psideta2(); dpsideta_map.resize (n_total_mapping_shape_functions); d2psidxideta_map.resize (n_total_mapping_shape_functions); d2psideta2_map.resize (n_total_mapping_shape_functions); } for (unsigned int i=0; i<n_total_mapping_shape_functions; i++) { psi_map[i].resize (n_total_qp); dpsidxi_map[i].resize (n_total_qp); d2psidxi2_map[i].resize (n_total_qp); // if (Dim == 3) { std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta(); std::vector<std::vector<Real> >& d2psidxideta_map = this->_fe_map->get_d2psidxideta(); std::vector<std::vector<Real> >& d2psideta2_map = this->_fe_map->get_d2psideta2(); dpsideta_map[i].resize (n_total_qp); d2psidxideta_map[i].resize (n_total_qp); d2psideta2_map[i].resize (n_total_qp); } } } // compute shape maps { const std::vector<std::vector<Real> >& S_map = (base_fe->get_fe_map()).get_phi_map(); const std::vector<std::vector<Real> >& Ss_map = (base_fe->get_fe_map()).get_dphidxi_map(); std::vector<std::vector<Real> >& psi_map = this->_fe_map->get_psi(); std::vector<std::vector<Real> >& dpsidxi_map = this->_fe_map->get_dpsidxi(); std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta(); for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qp's for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qp's for (unsigned int ti=0; ti<n_total_mapping_shape_functions; ti++) // over all mapping shapes { // let the index vectors take care of selecting the appropriate base/radial mapping shape const unsigned int bi = _base_node_index [ti]; const unsigned int ri = _radial_node_index[ti]; psi_map [ti][bp+rp*n_base_qp] = S_map [bi][bp] * radial_map [ri][rp]; dpsidxi_map [ti][bp+rp*n_base_qp] = Ss_map[bi][bp] * radial_map [ri][rp]; dpsideta_map [ti][bp+rp*n_base_qp] = S_map [bi][bp] * dradialdv_map[ri][rp]; // second derivatives are not implemented for infinite elements // d2psidxi2_map [ti][bp+rp*n_base_qp] = 0.; // d2psidxideta_map [ti][bp+rp*n_base_qp] = 0.; // d2psideta2_map [ti][bp+rp*n_base_qp] = 0.; } } } // quadrature rule weights { 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++) { _total_qrule_weights[ bp+rp*n_base_qp ] = radial_qw[rp] * base_qw[bp]; } } }
void InfFE<Dim,T_radial,T_map>::reinit(const Elem * inf_elem, const std::vector<Point> * const pts, const std::vector<Real> * const weights) { libmesh_assert(base_fe); libmesh_assert(base_fe->qrule); libmesh_assert_equal_to (base_fe->qrule, base_qrule); libmesh_assert(radial_qrule); libmesh_assert(inf_elem); if (pts == libmesh_nullptr) { bool init_shape_functions_required = false; // ----------------------------------------------------------------- // init the radial data fields only when the radial order changes if (current_fe_type.radial_order != fe_type.radial_order) { current_fe_type.radial_order = fe_type.radial_order; // Watch out: this call to QBase->init() only works for // current_fe_type = const! To allow variable Order, // the init() of QBase has to be modified... radial_qrule->init(EDGE2); // initialize the radial shape functions this->init_radial_shape_functions(inf_elem); init_shape_functions_required=true; } bool update_base_elem_required=true; // ----------------------------------------------------------------- // update the type in accordance to the current cell // and reinit if the cell type has changed or (as in // the case of the hierarchics) the shape functions // depend on the particular element and need a reinit if ( ( Dim != 1) && ( (this->get_type() != inf_elem->type()) || (base_fe->shapes_need_reinit()) ) ) { // store the new element type, update base_elem // here. Through \p update_base_elem_required, // remember whether it has to be updated (see below). elem_type = inf_elem->type(); this->update_base_elem(inf_elem); update_base_elem_required=false; // initialize the base quadrature rule for the new element base_qrule->init(base_elem->type()); // initialize the shape functions in the base base_fe->init_base_shape_functions(base_fe->qrule->get_points(), base_elem); init_shape_functions_required=true; } // when either the radial or base part change, // we have to init the whole fields if (init_shape_functions_required) this->init_shape_functions (inf_elem); // computing the distance only works when we have the current // base_elem stored. This happens when fe_type is const, // the inf_elem->type remains the same. Then we have to // update the base elem _here_. if (update_base_elem_required) this->update_base_elem(inf_elem); // compute dist (depends on geometry, therefore has to be updated for // each and every new element), throw radial and base part together this->combine_base_radial (inf_elem); this->_fe_map->compute_map (this->dim, _total_qrule_weights, inf_elem, this->calculate_d2phi); // Compute the shape functions and the derivatives // at all quadrature points. this->compute_shape_functions (inf_elem,base_fe->qrule->get_points()); } else // if pts != libmesh_nullptr { // update the elem_type elem_type = inf_elem->type(); // init radial shapes this->init_radial_shape_functions(inf_elem); // update the base this->update_base_elem(inf_elem); // the finite element on the ifem base { UniquePtr<FEBase> ap_fb(FEBase::build(Dim-1, this->fe_type)); if (base_fe != libmesh_nullptr) delete base_fe; base_fe = ap_fb.release(); } // inite base shapes base_fe->init_base_shape_functions(*pts, base_elem); this->init_shape_functions (inf_elem); // combine the base and radial shapes this->combine_base_radial (inf_elem); // weights if (weights != libmesh_nullptr) { this->_fe_map->compute_map (this->dim, *weights, inf_elem, this->calculate_d2phi); } else { std::vector<Real> dummy_weights (pts->size(), 1.); this->_fe_map->compute_map (this->dim, dummy_weights, inf_elem, this->calculate_d2phi); } // finally compute the ifem shapes this->compute_shape_functions (inf_elem,*pts); } }