$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 00020 // Local includes 00021 #include "libmesh/libmesh_config.h" 00022 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00023 #include "libmesh/inf_fe.h" 00024 #include "libmesh/quadrature_gauss.h" 00025 #include "libmesh/elem.h" 00026 #include "libmesh/libmesh_logging.h" 00027 00028 namespace libMesh 00029 { 00030 00031 00032 00033 // ------------------------------------------------------------ 00034 // InfFE class members 00035 00036 00037 00038 // Constructor 00039 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map> 00040 InfFE<Dim,T_radial,T_map>::InfFE (const FEType& fet) : 00041 FEBase (Dim, fet), 00042 00043 _n_total_approx_sf (0), 00044 _n_total_qp (0), 00045 00046 base_qrule (NULL), 00047 radial_qrule (NULL), 00048 base_elem (NULL), 00049 base_fe (NULL), 00050 00051 // initialize the current_fe_type to all the same 00052 // values as \p fet (since the FE families and coordinate 00053 // map type should @e not change), but use an invalid order 00054 // for the radial part (since this is the only order 00055 // that may change!). 00056 // the data structures like \p phi etc are not initialized 00057 // through the constructor, but throught reinit() 00058 current_fe_type ( FEType(fet.order, 00059 fet.family, 00060 INVALID_ORDER, 00061 fet.radial_family, 00062 fet.inf_map) ) 00063 00064 { 00065 // Sanity checks 00066 libmesh_assert_equal_to (T_radial, fe_type.radial_family); 00067 libmesh_assert_equal_to (T_map, fe_type.inf_map); 00068 00069 // build the base_fe object, handle the UniquePtr 00070 if (Dim != 1) 00071 { 00072 UniquePtr<FEBase> ap_fb(FEBase::build(Dim-1, fet)); 00073 base_fe = ap_fb.release(); 00074 } 00075 } 00076 00077 00078 00079 00080 // Destructor 00081 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map> 00082 InfFE<Dim,T_radial,T_map>::~InfFE () 00083 { 00084 // delete pointers, if necessary 00085 delete base_qrule; 00086 base_qrule = NULL; 00087 00088 delete radial_qrule; 00089 radial_qrule = NULL; 00090 00091 delete base_elem; 00092 base_elem = NULL; 00093 00094 delete base_fe; 00095 base_fe = NULL; 00096 } 00097 00098 00099 00100 00101 00102 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map> 00103 void InfFE<Dim,T_radial,T_map>:: attach_quadrature_rule (QBase* q) 00104 { 00105 libmesh_assert(q); 00106 libmesh_assert(base_fe); 00107 00108 const Order base_int_order = q->get_order(); 00109 const Order radial_int_order = static_cast<Order>(2 * (static_cast<unsigned int>(fe_type.radial_order) + 1) +2); 00110 const unsigned int qrule_dim = q->get_dim(); 00111 00112 if (Dim != 1) 00113 { 00114 // build a Dim-1 quadrature rule of the type that we received 00115 UniquePtr<QBase> apq( QBase::build(q->type(), qrule_dim-1, base_int_order) ); 00116 base_qrule = apq.release(); 00117 base_fe->attach_quadrature_rule(base_qrule); 00118 } 00119 00120 // in radial direction, always use Gauss quadrature 00121 radial_qrule = new QGauss(1, radial_int_order); 00122 00123 // currently not used. But maybe helpful to store the QBase* 00124 // with which we initialized our own quadrature rules 00125 qrule = q; 00126 } 00127 00128 00129 00130 00131 00132 template <unsigned int Dim, FEFamily T_radial, InfMapType T_base> 00133 void InfFE<Dim,T_radial,T_base>::update_base_elem (const Elem* inf_elem) 00134 { 00135 if (base_elem != NULL) 00136 delete base_elem; 00137 base_elem = Base::build_elem(inf_elem); 00138 } 00139 00140 00141 00142 00143 00144 00145 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map> 00146 void InfFE<Dim,T_radial,T_map>::reinit(const Elem* inf_elem, 00147 const std::vector<Point>* const pts, 00148 const std::vector<Real>* const weights) 00149 { 00150 libmesh_assert(base_fe); 00151 libmesh_assert(base_fe->qrule); 00152 libmesh_assert_equal_to (base_fe->qrule, base_qrule); 00153 libmesh_assert(radial_qrule); 00154 libmesh_assert(inf_elem); 00155 00156 if (pts == NULL) 00157 { 00158 bool init_shape_functions_required = false; 00159 00160 // ----------------------------------------------------------------- 00161 // init the radial data fields only when the radial order changes 00162 if (current_fe_type.radial_order != fe_type.radial_order) 00163 { 00164 current_fe_type.radial_order = fe_type.radial_order; 00165 00166 // Watch out: this call to QBase->init() only works for 00167 // current_fe_type = const! To allow variable Order, 00168 // the init() of QBase has to be modified... 00169 radial_qrule->init(EDGE2); 00170 00171 // initialize the radial shape functions 00172 this->init_radial_shape_functions(inf_elem); 00173 00174 init_shape_functions_required=true; 00175 } 00176 00177 00178 bool update_base_elem_required=true; 00179 00180 // ----------------------------------------------------------------- 00181 // update the type in accordance to the current cell 00182 // and reinit if the cell type has changed or (as in 00183 // the case of the hierarchics) the shape functions 00184 // depend on the particular element and need a reinit 00185 if ( ( Dim != 1) && 00186 ( (this->get_type() != inf_elem->type()) || 00187 (base_fe->shapes_need_reinit()) ) ) 00188 { 00189 // store the new element type, update base_elem 00190 // here. Through \p update_base_elem_required, 00191 // remember whether it has to be updated (see below). 00192 elem_type = inf_elem->type(); 00193 this->update_base_elem(inf_elem); 00194 update_base_elem_required=false; 00195 00196 // initialize the base quadrature rule for the new element 00197 base_qrule->init(base_elem->type()); 00198 00199 // initialize the shape functions in the base 00200 base_fe->init_base_shape_functions(base_fe->qrule->get_points(), 00201 base_elem); 00202 00203 init_shape_functions_required=true; 00204 } 00205 00206 00207 // when either the radial or base part change, 00208 // we have to init the whole fields 00209 if (init_shape_functions_required) 00210 this->init_shape_functions (inf_elem); 00211 00212 // computing the distance only works when we have the current 00213 // base_elem stored. This happens when fe_type is const, 00214 // the inf_elem->type remains the same. Then we have to 00215 // update the base elem _here_. 00216 if (update_base_elem_required) 00217 this->update_base_elem(inf_elem); 00218 00219 // compute dist (depends on geometry, therefore has to be updated for 00220 // each and every new element), throw radial and base part together 00221 this->combine_base_radial (inf_elem); 00222 00223 this->_fe_map->compute_map (this->dim,_total_qrule_weights, inf_elem); 00224 00225 // Compute the shape functions and the derivatives 00226 // at all quadrature points. 00227 this->compute_shape_functions (inf_elem,base_fe->qrule->get_points()); 00228 } 00229 00230 else // if pts != NULL 00231 { 00232 // update the elem_type 00233 elem_type = inf_elem->type(); 00234 00235 // init radial shapes 00236 this->init_radial_shape_functions(inf_elem); 00237 00238 // update the base 00239 this->update_base_elem(inf_elem); 00240 00241 // the finite element on the ifem base 00242 { 00243 UniquePtr<FEBase> ap_fb(FEBase::build(Dim-1, this->fe_type)); 00244 if (base_fe != NULL) 00245 delete base_fe; 00246 base_fe = ap_fb.release(); 00247 } 00248 00249 // inite base shapes 00250 base_fe->init_base_shape_functions(*pts, 00251 base_elem); 00252 00253 this->init_shape_functions (inf_elem); 00254 00255 // combine the base and radial shapes 00256 this->combine_base_radial (inf_elem); 00257 00258 // weights 00259 if (weights != NULL) 00260 { 00261 this->_fe_map->compute_map (this->dim, *weights, inf_elem); 00262 } 00263 else 00264 { 00265 std::vector<Real> dummy_weights (pts->size(), 1.); 00266 this->_fe_map->compute_map (this->dim, dummy_weights, inf_elem); 00267 } 00268 00269 // finally compute the ifem shapes 00270 this->compute_shape_functions (inf_elem,*pts); 00271 } 00272 00273 } 00274 00275 00276 00277 00278 00279 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map> 00280 void InfFE<Dim,T_radial,T_map>::init_radial_shape_functions(const Elem* libmesh_dbg_var(inf_elem)) 00281 { 00282 libmesh_assert(radial_qrule); 00283 libmesh_assert(inf_elem); 00284 00285 00289 START_LOG("init_radial_shape_functions()", "InfFE"); 00290 00291 00292 // ----------------------------------------------------------------- 00293 // initialize most of the things related to mapping 00294 00295 // The order to use in the radial map (currently independent of the element type) 00296 const Order radial_mapping_order (Radial::mapping_order()); 00297 const unsigned int n_radial_mapping_shape_functions (Radial::n_dofs(radial_mapping_order)); 00298 00299 00300 00301 // ----------------------------------------------------------------- 00302 // initialize most of the things related to physical approximation 00303 00304 const Order radial_approx_order (fe_type.radial_order); 00305 const unsigned int n_radial_approx_shape_functions (Radial::n_dofs(radial_approx_order)); 00306 00307 const unsigned int n_radial_qp = radial_qrule->n_points(); 00308 const std::vector<Point>& radial_qp = radial_qrule->get_points(); 00309 00310 00311 00312 // ----------------------------------------------------------------- 00313 // resize the radial data fields 00314 00315 mode.resize (n_radial_approx_shape_functions); // the radial polynomials (eval) 00316 dmodedv.resize (n_radial_approx_shape_functions); 00317 00318 som.resize (n_radial_qp); // the (1-v)/2 weight 00319 dsomdv.resize (n_radial_qp); 00320 00321 radial_map.resize (n_radial_mapping_shape_functions); // the radial map 00322 dradialdv_map.resize (n_radial_mapping_shape_functions); 00323 00324 00325 for (unsigned int i=0; i<n_radial_mapping_shape_functions; i++) 00326 { 00327 radial_map[i].resize (n_radial_qp); 00328 dradialdv_map[i].resize (n_radial_qp); 00329 } 00330 00331 00332 for (unsigned int i=0; i<n_radial_approx_shape_functions; i++) 00333 { 00334 mode[i].resize (n_radial_qp); 00335 dmodedv[i].resize (n_radial_qp); 00336 } 00337 00338 00339 // compute scalar values at radial quadrature points 00340 for (unsigned int p=0; p<n_radial_qp; p++) 00341 { 00342 som[p] = Radial::decay (radial_qp[p](0)); 00343 dsomdv[p] = Radial::decay_deriv (radial_qp[p](0)); 00344 } 00345 00346 00347 // evaluate the mode shapes in radial direction at radial quadrature points 00348 for (unsigned int i=0; i<n_radial_approx_shape_functions; i++) 00349 for (unsigned int p=0; p<n_radial_qp; p++) 00350 { 00351 mode[i][p] = InfFE<Dim,T_radial,T_map>::eval (radial_qp[p](0), radial_approx_order, i); 00352 dmodedv[i][p] = InfFE<Dim,T_radial,T_map>::eval_deriv (radial_qp[p](0), radial_approx_order, i); 00353 } 00354 00355 00356 // evaluate the mapping functions in radial direction at radial quadrature points 00357 for (unsigned int i=0; i<n_radial_mapping_shape_functions; i++) 00358 for (unsigned int p=0; p<n_radial_qp; p++) 00359 { 00360 radial_map[i][p] = InfFE<Dim,INFINITE_MAP,T_map>::eval (radial_qp[p](0), radial_mapping_order, i); 00361 dradialdv_map[i][p] = InfFE<Dim,INFINITE_MAP,T_map>::eval_deriv (radial_qp[p](0), radial_mapping_order, i); 00362 } 00363 00367 STOP_LOG("init_radial_shape_functions()", "InfFE"); 00368 00369 } 00370 00371 00372 00373 00374 00375 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map> 00376 void InfFE<Dim,T_radial,T_map>::init_shape_functions(const Elem* inf_elem) 00377 { 00378 libmesh_assert(inf_elem); 00379 00380 00381 // Start logging the radial shape function initialization 00382 START_LOG("init_shape_functions()", "InfFE"); 00383 00384 00385 // ----------------------------------------------------------------- 00386 // fast access to some const int's for the radial data 00387 const unsigned int n_radial_mapping_sf = 00388 cast_int<unsigned int>(radial_map.size()); 00389 const unsigned int n_radial_approx_sf = 00390 cast_int<unsigned int>(mode.size()); 00391 const unsigned int n_radial_qp = 00392 cast_int<unsigned int>(som.size()); 00393 00394 00395 // ----------------------------------------------------------------- 00396 // initialize most of the things related to mapping 00397 00398 // The element type and order to use in the base map 00399 const Order base_mapping_order ( base_elem->default_order() ); 00400 const ElemType base_mapping_elem_type ( base_elem->type() ); 00401 00402 // the number of base shape functions used to construct the map 00403 // (Lagrange shape functions are used for mapping in the base) 00404 unsigned int n_base_mapping_shape_functions = Base::n_base_mapping_sf(base_mapping_elem_type, 00405 base_mapping_order); 00406 00407 const unsigned int n_total_mapping_shape_functions = 00408 n_radial_mapping_sf * n_base_mapping_shape_functions; 00409 00410 00411 00412 // ----------------------------------------------------------------- 00413 // initialize most of the things related to physical approximation 00414 00415 unsigned int n_base_approx_shape_functions; 00416 if (Dim > 1) 00417 n_base_approx_shape_functions = base_fe->n_shape_functions(); 00418 else 00419 n_base_approx_shape_functions = 1; 00420 00421 00422 const unsigned int n_total_approx_shape_functions = 00423 n_radial_approx_sf * n_base_approx_shape_functions; 00424 00425 // update class member field 00426 _n_total_approx_sf = n_total_approx_shape_functions; 00427 00428 00429 // The number of the base quadrature points. 00430 const unsigned int n_base_qp = base_qrule->n_points(); 00431 00432 // The total number of quadrature points. 00433 const unsigned int n_total_qp = n_radial_qp * n_base_qp; 00434 00435 00436 // update class member field 00437 _n_total_qp = n_total_qp; 00438 00439 00440 00441 // ----------------------------------------------------------------- 00442 // initialize the node and shape numbering maps 00443 { 00444 // these vectors work as follows: the i-th entry stores 00445 // the associated base/radial node number 00446 _radial_node_index.resize (n_total_mapping_shape_functions); 00447 _base_node_index.resize (n_total_mapping_shape_functions); 00448 00449 // similar for the shapes: the i-th entry stores 00450 // the associated base/radial shape number 00451 _radial_shape_index.resize (n_total_approx_shape_functions); 00452 _base_shape_index.resize (n_total_approx_shape_functions); 00453 00454 const ElemType inf_elem_type (inf_elem->type()); 00455 00456 // fill the node index map 00457 for (unsigned int n=0; n<n_total_mapping_shape_functions; n++) 00458 { 00459 compute_node_indices (inf_elem_type, 00460 n, 00461 _base_node_index[n], 00462 _radial_node_index[n]); 00463 libmesh_assert_less (_base_node_index[n], n_base_mapping_shape_functions); 00464 libmesh_assert_less (_radial_node_index[n], n_radial_mapping_sf); 00465 } 00466 00467 // fill the shape index map 00468 for (unsigned int n=0; n<n_total_approx_shape_functions; n++) 00469 { 00470 compute_shape_indices (this->fe_type, 00471 inf_elem_type, 00472 n, 00473 _base_shape_index[n], 00474 _radial_shape_index[n]); 00475 libmesh_assert_less (_base_shape_index[n], n_base_approx_shape_functions); 00476 libmesh_assert_less (_radial_shape_index[n], n_radial_approx_sf); 00477 } 00478 } 00479 00480 00481 00482 00483 00484 // ----------------------------------------------------------------- 00485 // resize the base data fields 00486 dist.resize(n_base_mapping_shape_functions); 00487 00488 00489 00490 // ----------------------------------------------------------------- 00491 // resize the total data fields 00492 00493 // the phase term varies with xi, eta and zeta(v): store it for _all_ qp 00494 // 00495 // when computing the phase, we need the base approximations 00496 // therefore, initialize the phase here, but evaluate it 00497 // in combine_base_radial(). 00498 // 00499 // the weight, though, is only needed at the radial quadrature points, n_radial_qp. 00500 // but for a uniform interface to the protected data fields 00501 // the weight data field (which are accessible from the outside) are expanded to n_total_qp. 00502 weight.resize (n_total_qp); 00503 dweightdv.resize (n_total_qp); 00504 dweight.resize (n_total_qp); 00505 00506 dphase.resize (n_total_qp); 00507 dphasedxi.resize (n_total_qp); 00508 dphasedeta.resize (n_total_qp); 00509 dphasedzeta.resize (n_total_qp); 00510 00511 // this vector contains the integration weights for the combined quadrature rule 00512 _total_qrule_weights.resize(n_total_qp); 00513 00514 00515 // ----------------------------------------------------------------- 00516 // InfFE's data fields phi, dphi, dphidx, phi_map etc hold the _total_ 00517 // shape and mapping functions, respectively 00518 { 00519 phi.resize (n_total_approx_shape_functions); 00520 dphi.resize (n_total_approx_shape_functions); 00521 dphidx.resize (n_total_approx_shape_functions); 00522 dphidy.resize (n_total_approx_shape_functions); 00523 dphidz.resize (n_total_approx_shape_functions); 00524 dphidxi.resize (n_total_approx_shape_functions); 00525 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00526 libmesh_do_once(libMesh::err << "Second derivatives for Infinite elements" 00527 << " are not yet implemented!" 00528 << std::endl); 00529 00530 d2phi.resize (n_total_approx_shape_functions); 00531 d2phidx2.resize (n_total_approx_shape_functions); 00532 d2phidxdy.resize (n_total_approx_shape_functions); 00533 d2phidxdz.resize (n_total_approx_shape_functions); 00534 d2phidy2.resize (n_total_approx_shape_functions); 00535 d2phidydz.resize (n_total_approx_shape_functions); 00536 d2phidz2.resize (n_total_approx_shape_functions); 00537 d2phidxi2.resize (n_total_approx_shape_functions); 00538 00539 if (Dim > 1) 00540 { 00541 d2phidxideta.resize (n_total_approx_shape_functions); 00542 d2phideta2.resize (n_total_approx_shape_functions); 00543 } 00544 00545 if (Dim > 2) 00546 { 00547 d2phidetadzeta.resize (n_total_approx_shape_functions); 00548 d2phidxidzeta.resize (n_total_approx_shape_functions); 00549 d2phidzeta2.resize (n_total_approx_shape_functions); 00550 } 00551 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00552 00553 if (Dim > 1) 00554 dphideta.resize (n_total_approx_shape_functions); 00555 00556 if (Dim == 3) 00557 dphidzeta.resize (n_total_approx_shape_functions); 00558 00559 00560 00561 std::vector<std::vector<Real> >& phi_map = this->_fe_map->get_phi_map(); 00562 std::vector<std::vector<Real> >& dphidxi_map = this->_fe_map->get_dphidxi_map(); 00563 00564 phi_map.resize (n_total_mapping_shape_functions); 00565 dphidxi_map.resize (n_total_mapping_shape_functions); 00566 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00567 std::vector<std::vector<Real> >& d2phidxi2_map = this->_fe_map->get_d2phidxi2_map(); 00568 d2phidxi2_map.resize (n_total_mapping_shape_functions); 00569 00570 if (Dim > 1) 00571 { 00572 std::vector<std::vector<Real> >& d2phidxideta_map = this->_fe_map->get_d2phidxideta_map(); 00573 std::vector<std::vector<Real> >& d2phideta2_map = this->_fe_map->get_d2phideta2_map(); 00574 d2phidxideta_map.resize (n_total_mapping_shape_functions); 00575 d2phideta2_map.resize (n_total_mapping_shape_functions); 00576 } 00577 00578 if (Dim == 3) 00579 { 00580 std::vector<std::vector<Real> >& d2phidxidzeta_map = this->_fe_map->get_d2phidxidzeta_map(); 00581 std::vector<std::vector<Real> >& d2phidetadzeta_map = this->_fe_map->get_d2phidetadzeta_map(); 00582 std::vector<std::vector<Real> >& d2phidzeta2_map = this->_fe_map->get_d2phidzeta2_map(); 00583 d2phidxidzeta_map.resize (n_total_mapping_shape_functions); 00584 d2phidetadzeta_map.resize (n_total_mapping_shape_functions); 00585 d2phidzeta2_map.resize (n_total_mapping_shape_functions); 00586 } 00587 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00588 00589 if (Dim > 1) 00590 { 00591 std::vector<std::vector<Real> >& dphideta_map = this->_fe_map->get_dphideta_map(); 00592 dphideta_map.resize (n_total_mapping_shape_functions); 00593 } 00594 00595 if (Dim == 3) 00596 { 00597 std::vector<std::vector<Real> >& dphidzeta_map = this->_fe_map->get_dphidzeta_map(); 00598 dphidzeta_map.resize (n_total_mapping_shape_functions); 00599 } 00600 } 00601 00602 00603 00604 // ----------------------------------------------------------------- 00605 // collect all the for loops, where inner vectors are 00606 // resized to the appropriate number of quadrature points 00607 { 00608 for (unsigned int i=0; i<n_total_approx_shape_functions; i++) 00609 { 00610 phi[i].resize (n_total_qp); 00611 dphi[i].resize (n_total_qp); 00612 dphidx[i].resize (n_total_qp); 00613 dphidy[i].resize (n_total_qp); 00614 dphidz[i].resize (n_total_qp); 00615 dphidxi[i].resize (n_total_qp); 00616 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00617 d2phi[i].resize (n_total_qp); 00618 d2phidx2[i].resize (n_total_qp); 00619 d2phidxdy[i].resize (n_total_qp); 00620 d2phidxdz[i].resize (n_total_qp); 00621 d2phidy2[i].resize (n_total_qp); 00622 d2phidydz[i].resize (n_total_qp); 00623 d2phidy2[i].resize (n_total_qp); 00624 d2phidxi2[i].resize (n_total_qp); 00625 00626 if (Dim > 1) 00627 { 00628 d2phidxideta[i].resize (n_total_qp); 00629 d2phideta2[i].resize (n_total_qp); 00630 } 00631 if (Dim > 2) 00632 { 00633 d2phidxidzeta[i].resize (n_total_qp); 00634 d2phidetadzeta[i].resize (n_total_qp); 00635 d2phidzeta2[i].resize (n_total_qp); 00636 } 00637 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00638 00639 if (Dim > 1) 00640 dphideta[i].resize (n_total_qp); 00641 00642 if (Dim == 3) 00643 dphidzeta[i].resize (n_total_qp); 00644 00645 } 00646 00647 for (unsigned int i=0; i<n_total_mapping_shape_functions; i++) 00648 { 00649 std::vector<std::vector<Real> >& phi_map = this->_fe_map->get_phi_map(); 00650 std::vector<std::vector<Real> >& dphidxi_map = this->_fe_map->get_dphidxi_map(); 00651 phi_map[i].resize (n_total_qp); 00652 dphidxi_map[i].resize (n_total_qp); 00653 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00654 std::vector<std::vector<Real> >& d2phidxi2_map = this->_fe_map->get_d2phidxi2_map(); 00655 d2phidxi2_map[i].resize (n_total_qp); 00656 if (Dim > 1) 00657 { 00658 std::vector<std::vector<Real> >& d2phidxideta_map = this->_fe_map->get_d2phidxideta_map(); 00659 std::vector<std::vector<Real> >& d2phideta2_map = this->_fe_map->get_d2phideta2_map(); 00660 d2phidxideta_map[i].resize (n_total_qp); 00661 d2phideta2_map[i].resize (n_total_qp); 00662 } 00663 00664 if (Dim > 2) 00665 { 00666 std::vector<std::vector<Real> >& d2phidxidzeta_map = this->_fe_map->get_d2phidxidzeta_map(); 00667 std::vector<std::vector<Real> >& d2phidetadzeta_map = this->_fe_map->get_d2phidetadzeta_map(); 00668 std::vector<std::vector<Real> >& d2phidzeta2_map = this->_fe_map->get_d2phidzeta2_map(); 00669 d2phidxidzeta_map[i].resize (n_total_qp); 00670 d2phidetadzeta_map[i].resize (n_total_qp); 00671 d2phidzeta2_map[i].resize (n_total_qp); 00672 } 00673 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00674 00675 if (Dim > 1) 00676 { 00677 std::vector<std::vector<Real> >& dphideta_map = this->_fe_map->get_dphideta_map(); 00678 dphideta_map[i].resize (n_total_qp); 00679 } 00680 00681 if (Dim == 3) 00682 { 00683 std::vector<std::vector<Real> >& dphidzeta_map = this->_fe_map->get_dphidzeta_map(); 00684 dphidzeta_map[i].resize (n_total_qp); 00685 } 00686 } 00687 } 00688 00689 00690 00691 { 00692 // ----------------------------------------------------------------- 00693 // (a) compute scalar values at _all_ quadrature points -- for uniform 00694 // access from the outside to these fields 00695 // (b) form a std::vector<Real> which contains the appropriate weights 00696 // of the combined quadrature rule! 00697 const std::vector<Point>& radial_qp = radial_qrule->get_points(); 00698 libmesh_assert_equal_to (radial_qp.size(), n_radial_qp); 00699 00700 const std::vector<Real>& radial_qw = radial_qrule->get_weights(); 00701 const std::vector<Real>& base_qw = base_qrule->get_weights(); 00702 libmesh_assert_equal_to (radial_qw.size(), n_radial_qp); 00703 libmesh_assert_equal_to (base_qw.size(), n_base_qp); 00704 00705 for (unsigned int rp=0; rp<n_radial_qp; rp++) 00706 for (unsigned int bp=0; bp<n_base_qp; bp++) 00707 { 00708 weight [ bp+rp*n_base_qp ] = Radial::D (radial_qp[rp](0)); 00709 dweightdv[ bp+rp*n_base_qp ] = Radial::D_deriv (radial_qp[rp](0)); 00710 00711 _total_qrule_weights[ bp+rp*n_base_qp ] = radial_qw[rp] * base_qw[bp]; 00712 } 00713 } 00714 00715 00719 STOP_LOG("init_shape_functions()", "InfFE"); 00720 00721 } 00722 00723 00724 00725 00726 00727 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map> 00728 void InfFE<Dim,T_radial,T_map>::combine_base_radial(const Elem* inf_elem) 00729 { 00730 libmesh_assert(inf_elem); 00731 // at least check whether the base element type is correct. 00732 // otherwise this version of computing dist would give problems 00733 libmesh_assert_equal_to (base_elem->type(), Base::get_elem_type(inf_elem->type())); 00734 00735 00739 START_LOG("combine_base_radial()", "InfFE"); 00740 00741 00742 // zero the phase, since it is to be summed up 00743 std::fill (dphasedxi.begin(), dphasedxi.end(), 0.); 00744 std::fill (dphasedeta.begin(), dphasedeta.end(), 0.); 00745 std::fill (dphasedzeta.begin(), dphasedzeta.end(), 0.); 00746 00747 00748 const unsigned int n_base_mapping_sf = 00749 cast_int<unsigned int>(dist.size()); 00750 const Point origin = inf_elem->origin(); 00751 00752 // for each new infinite element, compute the radial distances 00753 for (unsigned int n=0; n<n_base_mapping_sf; n++) 00754 dist[n] = Point(base_elem->point(n) - origin).size(); 00755 00756 00757 switch (Dim) 00758 { 00759 00760 //------------------------------------------------------------ 00761 // 1D 00762 case 1: 00763 { 00764 libmesh_not_implemented(); 00765 break; 00766 } 00767 00768 00769 00770 //------------------------------------------------------------ 00771 // 2D 00772 case 2: 00773 { 00774 libmesh_not_implemented(); 00775 break; 00776 } 00777 00778 00779 00780 //------------------------------------------------------------ 00781 // 3D 00782 case 3: 00783 { 00784 // fast access to the approximation and mapping shapes of base_fe 00785 const std::vector<std::vector<Real> >& S = base_fe->phi; 00786 const std::vector<std::vector<Real> >& Ss = base_fe->dphidxi; 00787 const std::vector<std::vector<Real> >& St = base_fe->dphideta; 00788 const std::vector<std::vector<Real> >& S_map = (base_fe->get_fe_map()).get_phi_map(); 00789 const std::vector<std::vector<Real> >& Ss_map = (base_fe->get_fe_map()).get_dphidxi_map(); 00790 const std::vector<std::vector<Real> >& St_map = (base_fe->get_fe_map()).get_dphideta_map(); 00791 00792 const unsigned int n_radial_qp = radial_qrule->n_points(); 00793 const unsigned int n_base_qp = base_qrule-> n_points(); 00794 00795 const unsigned int n_total_mapping_sf = 00796 cast_int<unsigned int>(radial_map.size()) * n_base_mapping_sf; 00797 00798 const unsigned int n_total_approx_sf = Radial::n_dofs(fe_type.radial_order) * base_fe->n_shape_functions(); 00799 00800 00801 // compute the phase term derivatives 00802 { 00803 unsigned int tp=0; 00804 for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qp's 00805 for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qp's 00806 { 00807 // sum over all base shapes, to get the average distance 00808 for (unsigned int i=0; i<n_base_mapping_sf; i++) 00809 { 00810 dphasedxi[tp] += Ss_map[i][bp] * dist[i] * radial_map [1][rp]; 00811 dphasedeta[tp] += St_map[i][bp] * dist[i] * radial_map [1][rp]; 00812 dphasedzeta[tp] += S_map [i][bp] * dist[i] * dradialdv_map[1][rp]; 00813 } 00814 00815 tp++; 00816 00817 } // loop radial and base qp's 00818 00819 } 00820 00821 libmesh_assert_equal_to (phi.size(), n_total_approx_sf); 00822 libmesh_assert_equal_to (dphidxi.size(), n_total_approx_sf); 00823 libmesh_assert_equal_to (dphideta.size(), n_total_approx_sf); 00824 libmesh_assert_equal_to (dphidzeta.size(), n_total_approx_sf); 00825 00826 // compute the overall approximation shape functions, 00827 // pick the appropriate radial and base shapes through using 00828 // _base_shape_index and _radial_shape_index 00829 for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qp's 00830 for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qp's 00831 for (unsigned int ti=0; ti<n_total_approx_sf; ti++) // over _all_ approx_sf 00832 { 00833 // let the index vectors take care of selecting the appropriate base/radial shape 00834 const unsigned int bi = _base_shape_index [ti]; 00835 const unsigned int ri = _radial_shape_index[ti]; 00836 phi [ti][bp+rp*n_base_qp] = S [bi][bp] * mode[ri][rp] * som[rp]; 00837 dphidxi [ti][bp+rp*n_base_qp] = Ss[bi][bp] * mode[ri][rp] * som[rp]; 00838 dphideta [ti][bp+rp*n_base_qp] = St[bi][bp] * mode[ri][rp] * som[rp]; 00839 dphidzeta[ti][bp+rp*n_base_qp] = S [bi][bp] 00840 * (dmodedv[ri][rp] * som[rp] + mode[ri][rp] * dsomdv[rp]); 00841 } 00842 00843 std::vector<std::vector<Real> >& phi_map = this->_fe_map->get_phi_map(); 00844 std::vector<std::vector<Real> >& dphidxi_map = this->_fe_map->get_dphidxi_map(); 00845 std::vector<std::vector<Real> >& dphideta_map = this->_fe_map->get_dphideta_map(); 00846 std::vector<std::vector<Real> >& dphidzeta_map = this->_fe_map->get_dphidzeta_map(); 00847 00848 libmesh_assert_equal_to (phi_map.size(), n_total_mapping_sf); 00849 libmesh_assert_equal_to (dphidxi_map.size(), n_total_mapping_sf); 00850 libmesh_assert_equal_to (dphideta_map.size(), n_total_mapping_sf); 00851 libmesh_assert_equal_to (dphidzeta_map.size(), n_total_mapping_sf); 00852 00853 // compute the overall mapping functions, 00854 // pick the appropriate radial and base entries through using 00855 // _base_node_index and _radial_node_index 00856 for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qp's 00857 for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qp's 00858 for (unsigned int ti=0; ti<n_total_mapping_sf; ti++) // over all mapping shapes 00859 { 00860 // let the index vectors take care of selecting the appropriate base/radial mapping shape 00861 const unsigned int bi = _base_node_index [ti]; 00862 const unsigned int ri = _radial_node_index[ti]; 00863 phi_map [ti][bp+rp*n_base_qp] = S_map [bi][bp] * radial_map [ri][rp]; 00864 dphidxi_map [ti][bp+rp*n_base_qp] = Ss_map[bi][bp] * radial_map [ri][rp]; 00865 dphideta_map [ti][bp+rp*n_base_qp] = St_map[bi][bp] * radial_map [ri][rp]; 00866 dphidzeta_map[ti][bp+rp*n_base_qp] = S_map [bi][bp] * dradialdv_map[ri][rp]; 00867 } 00868 00869 00870 break; 00871 } 00872 00873 default: 00874 libmesh_error_msg("Unsupported Dim = " << Dim); 00875 } 00876 00877 00881 STOP_LOG("combine_base_radial()", "InfFE"); 00882 } 00883 00884 00885 00886 00887 00888 00889 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map> 00890 void InfFE<Dim,T_radial,T_map>::compute_shape_functions(const Elem*, const std::vector<Point>&) 00891 { 00892 libmesh_assert(radial_qrule); 00893 00894 // Start logging the overall computation of shape functions 00895 START_LOG("compute_shape_functions()", "InfFE"); 00896 00897 00898 const unsigned int n_total_qp = _n_total_qp; 00899 00900 00901 //------------------------------------------------------------------------- 00902 // Compute the shape function values (and derivatives) 00903 // at the Quadrature points. Note that the actual values 00904 // have already been computed via init_shape_functions 00905 00906 // Compute the value of the derivative shape function i at quadrature point p 00907 switch (dim) 00908 { 00909 00910 case 1: 00911 { 00912 libmesh_not_implemented(); 00913 break; 00914 } 00915 00916 case 2: 00917 { 00918 libmesh_not_implemented(); 00919 break; 00920 } 00921 00922 case 3: 00923 { 00924 const std::vector<Real>& dxidx_map = this->_fe_map->get_dxidx(); 00925 const std::vector<Real>& dxidy_map = this->_fe_map->get_dxidy(); 00926 const std::vector<Real>& dxidz_map = this->_fe_map->get_dxidz(); 00927 00928 const std::vector<Real>& detadx_map = this->_fe_map->get_detadx(); 00929 const std::vector<Real>& detady_map = this->_fe_map->get_detady(); 00930 const std::vector<Real>& detadz_map = this->_fe_map->get_detadz(); 00931 00932 const std::vector<Real>& dzetadx_map = this->_fe_map->get_dzetadx(); 00933 const std::vector<Real>& dzetady_map = this->_fe_map->get_dzetady(); 00934 const std::vector<Real>& dzetadz_map = this->_fe_map->get_dzetadz(); 00935 00936 // These are _all_ shape functions of this infinite element 00937 for (unsigned int i=0; i<phi.size(); i++) 00938 for (unsigned int p=0; p<n_total_qp; p++) 00939 { 00940 // dphi/dx = (dphi/dxi)*(dxi/dx) + (dphi/deta)*(deta/dx) + (dphi/dzeta)*(dzeta/dx); 00941 dphi[i][p](0) = 00942 dphidx[i][p] = (dphidxi[i][p]*dxidx_map[p] + 00943 dphideta[i][p]*detadx_map[p] + 00944 dphidzeta[i][p]*dzetadx_map[p]); 00945 00946 // dphi/dy = (dphi/dxi)*(dxi/dy) + (dphi/deta)*(deta/dy) + (dphi/dzeta)*(dzeta/dy); 00947 dphi[i][p](1) = 00948 dphidy[i][p] = (dphidxi[i][p]*dxidy_map[p] + 00949 dphideta[i][p]*detady_map[p] + 00950 dphidzeta[i][p]*dzetady_map[p]); 00951 00952 // dphi/dz = (dphi/dxi)*(dxi/dz) + (dphi/deta)*(deta/dz) + (dphi/dzeta)*(dzeta/dz); 00953 dphi[i][p](2) = 00954 dphidz[i][p] = (dphidxi[i][p]*dxidz_map[p] + 00955 dphideta[i][p]*detadz_map[p] + 00956 dphidzeta[i][p]*dzetadz_map[p]); 00957 } 00958 00959 00960 // This is the derivative of the phase term of this infinite element 00961 for (unsigned int p=0; p<n_total_qp; p++) 00962 { 00963 // the derivative of the phase term 00964 dphase[p](0) = (dphasedxi[p] * dxidx_map[p] + 00965 dphasedeta[p] * detadx_map[p] + 00966 dphasedzeta[p] * dzetadx_map[p]); 00967 00968 dphase[p](1) = (dphasedxi[p] * dxidy_map[p] + 00969 dphasedeta[p] * detady_map[p] + 00970 dphasedzeta[p] * dzetady_map[p]); 00971 00972 dphase[p](2) = (dphasedxi[p] * dxidz_map[p] + 00973 dphasedeta[p] * detadz_map[p] + 00974 dphasedzeta[p] * dzetadz_map[p]); 00975 00976 // the derivative of the radial weight - varies only in radial direction, 00977 // therefore dweightdxi = dweightdeta = 0. 00978 dweight[p](0) = dweightdv[p] * dzetadx_map[p]; 00979 00980 dweight[p](1) = dweightdv[p] * dzetady_map[p]; 00981 00982 dweight[p](2) = dweightdv[p] * dzetadz_map[p]; 00983 00984 } 00985 00986 break; 00987 } 00988 00989 default: 00990 libmesh_error_msg("Unsupported dim = " << dim); 00991 } 00992 00993 // Stop logging the overall computation of shape functions 00994 STOP_LOG("compute_shape_functions()", "InfFE"); 00995 } 00996 00997 00998 00999 template <unsigned int Dim, FEFamily T_radial, InfMapType T_map> 01000 bool InfFE<Dim,T_radial,T_map>::shapes_need_reinit() const 01001 { 01002 return false; 01003 } 01004 01005 } // namespace libMesh 01006 01007 01008 //-------------------------------------------------------------- 01009 // Explicit instantiations 01010 #include "libmesh/inf_fe_instantiate_1D.h" 01011 #include "libmesh/inf_fe_instantiate_2D.h" 01012 #include "libmesh/inf_fe_instantiate_3D.h" 01013 01014 01015 01016 #endif //ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS