$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/elem.h" 00022 #include "libmesh/fe.h" 00023 #include "libmesh/fe_interface.h" 00024 #include "libmesh/fe_macro.h" 00025 #include "libmesh/libmesh_logging.h" 00026 #include "libmesh/quadrature.h" 00027 #include "libmesh/tensor_value.h" 00028 00029 namespace libMesh 00030 { 00031 00032 00033 // ------------------------------------------------------------ 00034 // FE class members 00035 template <unsigned int Dim, FEFamily T> 00036 unsigned int FE<Dim,T>::n_shape_functions () const 00037 { 00038 return FE<Dim,T>::n_dofs (this->elem_type, 00039 static_cast<Order>(this->fe_type.order + this->_p_level)); 00040 } 00041 00042 00043 template <unsigned int Dim, FEFamily T> 00044 void FE<Dim,T>::attach_quadrature_rule (QBase* q) 00045 { 00046 libmesh_assert(q); 00047 this->qrule = q; 00048 // make sure we don't cache results from a previous quadrature rule 00049 this->elem_type = INVALID_ELEM; 00050 return; 00051 } 00052 00053 00054 template <unsigned int Dim, FEFamily T> 00055 unsigned int FE<Dim,T>::n_quadrature_points () const 00056 { 00057 libmesh_assert(this->qrule); 00058 return this->qrule->n_points(); 00059 } 00060 00061 00062 template <unsigned int Dim, FEFamily T> 00063 void FE<Dim,T>::dofs_on_side(const Elem* const elem, 00064 const Order o, 00065 unsigned int s, 00066 std::vector<unsigned int>& di) 00067 { 00068 libmesh_assert(elem); 00069 libmesh_assert_less (s, elem->n_sides()); 00070 00071 di.clear(); 00072 unsigned int nodenum = 0; 00073 const unsigned int n_nodes = elem->n_nodes(); 00074 for (unsigned int n = 0; n != n_nodes; ++n) 00075 { 00076 const unsigned int n_dofs = n_dofs_at_node(elem->type(), 00077 static_cast<Order>(o + elem->p_level()), n); 00078 if (elem->is_node_on_side(n, s)) 00079 for (unsigned int i = 0; i != n_dofs; ++i) 00080 di.push_back(nodenum++); 00081 else 00082 nodenum += n_dofs; 00083 } 00084 } 00085 00086 00087 00088 template <unsigned int Dim, FEFamily T> 00089 void FE<Dim,T>::dofs_on_edge(const Elem* const elem, 00090 const Order o, 00091 unsigned int e, 00092 std::vector<unsigned int>& di) 00093 { 00094 libmesh_assert(elem); 00095 libmesh_assert_less (e, elem->n_edges()); 00096 00097 di.clear(); 00098 unsigned int nodenum = 0; 00099 const unsigned int n_nodes = elem->n_nodes(); 00100 for (unsigned int n = 0; n != n_nodes; ++n) 00101 { 00102 const unsigned int n_dofs = n_dofs_at_node(elem->type(), 00103 static_cast<Order>(o + elem->p_level()), n); 00104 if (elem->is_node_on_edge(n, e)) 00105 for (unsigned int i = 0; i != n_dofs; ++i) 00106 di.push_back(nodenum++); 00107 else 00108 nodenum += n_dofs; 00109 } 00110 } 00111 00112 00113 00114 template <unsigned int Dim, FEFamily T> 00115 void FE<Dim,T>::reinit(const Elem* elem, 00116 const std::vector<Point>* const pts, 00117 const std::vector<Real>* const weights) 00118 { 00119 // We can be called with no element. If we're evaluating SCALAR 00120 // dofs we'll still have work to do. 00121 // libmesh_assert(elem); 00122 00123 // Try to avoid calling init_shape_functions 00124 // even when shapes_need_reinit 00125 bool cached_nodes_still_fit = false; 00126 00127 // Most of the hard work happens when we have an actual element 00128 if (elem) 00129 { 00130 // Initialize the shape functions at the user-specified 00131 // points 00132 if (pts != NULL) 00133 { 00134 // Set the type and p level for this element 00135 this->elem_type = elem->type(); 00136 this->_p_level = elem->p_level(); 00137 00138 // Initialize the shape functions 00139 this->_fe_map->template init_reference_to_physical_map<Dim> 00140 (*pts, elem); 00141 this->init_shape_functions (*pts, elem); 00142 00143 // The shape functions do not correspond to the qrule 00144 this->shapes_on_quadrature = false; 00145 } 00146 00147 // If there are no user specified points, we use the 00148 // quadrature rule 00149 00150 // update the type in accordance to the current cell 00151 // and reinit if the cell type has changed or (as in 00152 // the case of the hierarchics) the shape functions need 00153 // reinit, since they depend on the particular element shape 00154 else 00155 { 00156 libmesh_assert(this->qrule); 00157 this->qrule->init(elem->type(), elem->p_level()); 00158 00159 if(this->qrule->shapes_need_reinit()) 00160 this->shapes_on_quadrature = false; 00161 00162 if (this->elem_type != elem->type() || 00163 this->_p_level != elem->p_level() || 00164 !this->shapes_on_quadrature) 00165 { 00166 // Set the type and p level for this element 00167 this->elem_type = elem->type(); 00168 this->_p_level = elem->p_level(); 00169 // Initialize the shape functions 00170 this->_fe_map->template init_reference_to_physical_map<Dim> 00171 (this->qrule->get_points(), elem); 00172 this->init_shape_functions (this->qrule->get_points(), elem); 00173 00174 if (this->shapes_need_reinit()) 00175 { 00176 cached_nodes.resize(elem->n_nodes()); 00177 for (unsigned int n = 0; n != elem->n_nodes(); ++n) 00178 { 00179 cached_nodes[n] = elem->point(n); 00180 } 00181 } 00182 } 00183 else 00184 { 00185 // libmesh_assert_greater (elem->n_nodes(), 1); 00186 00187 cached_nodes_still_fit = true; 00188 if (cached_nodes.size() != elem->n_nodes()) 00189 cached_nodes_still_fit = false; 00190 else 00191 for (unsigned int n = 1; n < elem->n_nodes(); ++n) 00192 { 00193 if (!(elem->point(n) - elem->point(0)).relative_fuzzy_equals 00194 ((cached_nodes[n] - cached_nodes[0]), 1e-13)) 00195 { 00196 cached_nodes_still_fit = false; 00197 break; 00198 } 00199 } 00200 00201 if (this->shapes_need_reinit() && !cached_nodes_still_fit) 00202 { 00203 this->_fe_map->template init_reference_to_physical_map<Dim> 00204 (this->qrule->get_points(), elem); 00205 this->init_shape_functions (this->qrule->get_points(), elem); 00206 cached_nodes.resize(elem->n_nodes()); 00207 for (unsigned int n = 0; n != elem->n_nodes(); ++n) 00208 cached_nodes[n] = elem->point(n); 00209 } 00210 } 00211 00212 // The shape functions correspond to the qrule 00213 this->shapes_on_quadrature = true; 00214 } 00215 } 00216 else // With no defined elem, so mapping or caching to 00217 // be done, and our "quadrature rule" is one point for nonlocal 00218 // (SCALAR) variables and zero points for local variables. 00219 { 00220 this->elem_type = INVALID_ELEM; 00221 this->_p_level = 0; 00222 00223 if (!pts) 00224 { 00225 if (T == SCALAR) 00226 { 00227 this->qrule->get_points() = 00228 std::vector<Point>(1,Point(0)); 00229 00230 this->qrule->get_weights() = 00231 std::vector<Real>(1,1); 00232 } 00233 else 00234 { 00235 this->qrule->get_points().clear(); 00236 this->qrule->get_weights().clear(); 00237 } 00238 00239 this->init_shape_functions (this->qrule->get_points(), elem); 00240 } 00241 else 00242 this->init_shape_functions (*pts, elem); 00243 } 00244 00245 // Compute the map for this element. 00246 if (pts != NULL) 00247 { 00248 if (weights != NULL) 00249 { 00250 this->_fe_map->compute_map (this->dim,*weights, elem); 00251 } 00252 else 00253 { 00254 std::vector<Real> dummy_weights (pts->size(), 1.); 00255 this->_fe_map->compute_map (this->dim,dummy_weights, elem); 00256 } 00257 } 00258 else 00259 { 00260 this->_fe_map->compute_map (this->dim,this->qrule->get_weights(), elem); 00261 } 00262 00263 // Compute the shape functions and the derivatives at all of the 00264 // quadrature points. 00265 if (!cached_nodes_still_fit) 00266 { 00267 if (pts != NULL) 00268 this->compute_shape_functions (elem,*pts); 00269 else 00270 this->compute_shape_functions(elem,this->qrule->get_points()); 00271 } 00272 } 00273 00274 00275 00276 template <unsigned int Dim, FEFamily T> 00277 void FE<Dim,T>::init_shape_functions(const std::vector<Point>& qp, 00278 const Elem* elem) 00279 { 00280 // We can be called with no element. If we're evaluating SCALAR 00281 // dofs we'll still have work to do. 00282 // libmesh_assert(elem); 00283 00284 this->calculations_started = true; 00285 00286 // If the user forgot to request anything, we'll be safe and 00287 // calculate everything: 00288 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00289 if (!this->calculate_phi && !this->calculate_dphi && !this->calculate_d2phi 00290 && !this->calculate_curl_phi && !this->calculate_div_phi) 00291 { 00292 this->calculate_phi = this->calculate_dphi = this->calculate_d2phi = this->calculate_dphiref = true; 00293 if( FEInterface::field_type(T) == TYPE_VECTOR ) 00294 { 00295 this->calculate_curl_phi = true; 00296 this->calculate_div_phi = true; 00297 } 00298 } 00299 #else 00300 if (!this->calculate_phi && !this->calculate_dphi && !this->calculate_curl_phi && !this->calculate_div_phi) 00301 { 00302 this->calculate_phi = this->calculate_dphi = this->calculate_dphiref = true; 00303 if( FEInterface::field_type(T) == TYPE_VECTOR ) 00304 { 00305 this->calculate_curl_phi = true; 00306 this->calculate_div_phi = true; 00307 } 00308 } 00309 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES 00310 00311 // Start logging the shape function initialization 00312 START_LOG("init_shape_functions()", "FE"); 00313 00314 00315 // The number of quadrature points. 00316 const unsigned int n_qp = cast_int<unsigned int>(qp.size()); 00317 00318 // Number of shape functions in the finite element approximation 00319 // space. 00320 const unsigned int n_approx_shape_functions = 00321 this->n_shape_functions(this->get_type(), 00322 this->get_order()); 00323 00324 // resize the vectors to hold current data 00325 // Phi are the shape functions used for the FE approximation 00326 // Phi_map are the shape functions used for the FE mapping 00327 if (this->calculate_phi) 00328 this->phi.resize (n_approx_shape_functions); 00329 00330 if (this->calculate_dphi) 00331 { 00332 this->dphi.resize (n_approx_shape_functions); 00333 this->dphidx.resize (n_approx_shape_functions); 00334 this->dphidy.resize (n_approx_shape_functions); 00335 this->dphidz.resize (n_approx_shape_functions); 00336 } 00337 00338 if(this->calculate_dphiref) 00339 { 00340 if (Dim > 0) 00341 this->dphidxi.resize (n_approx_shape_functions); 00342 00343 if (Dim > 1) 00344 this->dphideta.resize (n_approx_shape_functions); 00345 00346 if (Dim > 2) 00347 this->dphidzeta.resize (n_approx_shape_functions); 00348 } 00349 00350 if( this->calculate_curl_phi && (FEInterface::field_type(T) == TYPE_VECTOR) ) 00351 this->curl_phi.resize(n_approx_shape_functions); 00352 00353 if( this->calculate_div_phi && (FEInterface::field_type(T) == TYPE_VECTOR) ) 00354 this->div_phi.resize(n_approx_shape_functions); 00355 00356 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00357 if (this->calculate_d2phi) 00358 { 00359 this->d2phi.resize (n_approx_shape_functions); 00360 this->d2phidx2.resize (n_approx_shape_functions); 00361 this->d2phidxdy.resize (n_approx_shape_functions); 00362 this->d2phidxdz.resize (n_approx_shape_functions); 00363 this->d2phidy2.resize (n_approx_shape_functions); 00364 this->d2phidydz.resize (n_approx_shape_functions); 00365 this->d2phidz2.resize (n_approx_shape_functions); 00366 00367 if (Dim > 0) 00368 this->d2phidxi2.resize (n_approx_shape_functions); 00369 00370 if (Dim > 1) 00371 { 00372 this->d2phidxideta.resize (n_approx_shape_functions); 00373 this->d2phideta2.resize (n_approx_shape_functions); 00374 } 00375 if (Dim > 2) 00376 { 00377 this->d2phidxidzeta.resize (n_approx_shape_functions); 00378 this->d2phidetadzeta.resize (n_approx_shape_functions); 00379 this->d2phidzeta2.resize (n_approx_shape_functions); 00380 } 00381 } 00382 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00383 00384 for (unsigned int i=0; i<n_approx_shape_functions; i++) 00385 { 00386 if (this->calculate_phi) 00387 this->phi[i].resize (n_qp); 00388 if (this->calculate_dphi) 00389 { 00390 this->dphi[i].resize (n_qp); 00391 this->dphidx[i].resize (n_qp); 00392 this->dphidy[i].resize (n_qp); 00393 this->dphidz[i].resize (n_qp); 00394 } 00395 00396 if(this->calculate_dphiref) 00397 { 00398 if (Dim > 0) 00399 this->dphidxi[i].resize(n_qp); 00400 00401 if (Dim > 1) 00402 this->dphideta[i].resize(n_qp); 00403 00404 if (Dim > 2) 00405 this->dphidzeta[i].resize(n_qp); 00406 } 00407 00408 if(this->calculate_curl_phi && (FEInterface::field_type(T) == TYPE_VECTOR) ) 00409 this->curl_phi[i].resize(n_qp); 00410 00411 if(this->calculate_div_phi && (FEInterface::field_type(T) == TYPE_VECTOR) ) 00412 this->div_phi[i].resize(n_qp); 00413 00414 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00415 if (this->calculate_d2phi) 00416 { 00417 this->d2phi[i].resize (n_qp); 00418 this->d2phidx2[i].resize (n_qp); 00419 this->d2phidxdy[i].resize (n_qp); 00420 this->d2phidxdz[i].resize (n_qp); 00421 this->d2phidy2[i].resize (n_qp); 00422 this->d2phidydz[i].resize (n_qp); 00423 this->d2phidz2[i].resize (n_qp); 00424 if (Dim > 0) 00425 this->d2phidxi2[i].resize (n_qp); 00426 if (Dim > 1) 00427 { 00428 this->d2phidxideta[i].resize (n_qp); 00429 this->d2phideta2[i].resize (n_qp); 00430 } 00431 if (Dim > 2) 00432 { 00433 this->d2phidxidzeta[i].resize (n_qp); 00434 this->d2phidetadzeta[i].resize (n_qp); 00435 this->d2phidzeta2[i].resize (n_qp); 00436 } 00437 } 00438 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00439 } 00440 00441 00442 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00443 //------------------------------------------------------------ 00444 // Initialize the data fields, which should only be used for infinite 00445 // elements, to some sensible values, so that using a FE with the 00446 // variational formulation of an InfFE, correct element matrices are 00447 // returned 00448 00449 { 00450 this->weight.resize (n_qp); 00451 this->dweight.resize (n_qp); 00452 this->dphase.resize (n_qp); 00453 00454 for (unsigned int p=0; p<n_qp; p++) 00455 { 00456 this->weight[p] = 1.; 00457 this->dweight[p].zero(); 00458 this->dphase[p].zero(); 00459 } 00460 00461 } 00462 #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00463 00464 switch (Dim) 00465 { 00466 00467 //------------------------------------------------------------ 00468 // 0D 00469 case 0: 00470 { 00471 break; 00472 } 00473 00474 //------------------------------------------------------------ 00475 // 1D 00476 case 1: 00477 { 00478 // Compute the value of the approximation shape function i at quadrature point p 00479 if (this->calculate_dphiref) 00480 for (unsigned int i=0; i<n_approx_shape_functions; i++) 00481 for (unsigned int p=0; p<n_qp; p++) 00482 this->dphidxi[i][p] = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 0, qp[p]); 00483 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00484 if (this->calculate_d2phi) 00485 for (unsigned int i=0; i<n_approx_shape_functions; i++) 00486 for (unsigned int p=0; p<n_qp; p++) 00487 this->d2phidxi2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 0, qp[p]); 00488 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00489 00490 break; 00491 } 00492 00493 00494 00495 //------------------------------------------------------------ 00496 // 2D 00497 case 2: 00498 { 00499 // Compute the value of the approximation shape function i at quadrature point p 00500 if (this->calculate_dphiref) 00501 for (unsigned int i=0; i<n_approx_shape_functions; i++) 00502 for (unsigned int p=0; p<n_qp; p++) 00503 { 00504 this->dphidxi[i][p] = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 0, qp[p]); 00505 this->dphideta[i][p] = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 1, qp[p]); 00506 } 00507 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00508 if (this->calculate_d2phi) 00509 for (unsigned int i=0; i<n_approx_shape_functions; i++) 00510 for (unsigned int p=0; p<n_qp; p++) 00511 { 00512 this->d2phidxi2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 0, qp[p]); 00513 this->d2phidxideta[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 1, qp[p]); 00514 this->d2phideta2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 2, qp[p]); 00515 } 00516 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00517 00518 00519 break; 00520 } 00521 00522 00523 00524 //------------------------------------------------------------ 00525 // 3D 00526 case 3: 00527 { 00528 // Compute the value of the approximation shape function i at quadrature point p 00529 if (this->calculate_dphiref) 00530 for (unsigned int i=0; i<n_approx_shape_functions; i++) 00531 for (unsigned int p=0; p<n_qp; p++) 00532 { 00533 this->dphidxi[i][p] = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 0, qp[p]); 00534 this->dphideta[i][p] = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 1, qp[p]); 00535 this->dphidzeta[i][p] = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 2, qp[p]); 00536 } 00537 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00538 if (this->calculate_d2phi) 00539 for (unsigned int i=0; i<n_approx_shape_functions; i++) 00540 for (unsigned int p=0; p<n_qp; p++) 00541 { 00542 this->d2phidxi2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 0, qp[p]); 00543 this->d2phidxideta[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 1, qp[p]); 00544 this->d2phideta2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 2, qp[p]); 00545 this->d2phidxidzeta[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 3, qp[p]); 00546 this->d2phidetadzeta[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 4, qp[p]); 00547 this->d2phidzeta2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 5, qp[p]); 00548 } 00549 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00550 00551 break; 00552 } 00553 00554 00555 default: 00556 libmesh_error_msg("Invalid dimension Dim = " << Dim); 00557 } 00558 00559 // Stop logging the shape function initialization 00560 STOP_LOG("init_shape_functions()", "FE"); 00561 } 00562 00563 00564 00565 00566 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00567 00568 template <unsigned int Dim, FEFamily T> 00569 void FE<Dim,T>::init_base_shape_functions(const std::vector<Point>& qp, 00570 const Elem* e) 00571 { 00572 // I don't understand infinite elements well enough to risk 00573 // calculating too little. :-( RHS 00574 this->calculate_phi = this->calculate_dphi = this->calculate_d2phi = true; 00575 00576 this->elem_type = e->type(); 00577 this->_fe_map->template init_reference_to_physical_map<Dim>(qp, e); 00578 init_shape_functions(qp, e); 00579 } 00580 00581 #endif // LIBMESH_ENABLE_INFINITE_ELEMENTS 00582 00583 00584 00585 //-------------------------------------------------------------- 00586 // Explicit instantiations using macro from fe_macro.h 00587 00588 INSTANTIATE_FE(0); 00589 00590 INSTANTIATE_FE(1); 00591 00592 INSTANTIATE_FE(2); 00593 00594 INSTANTIATE_FE(3); 00595 00596 INSTANTIATE_SUBDIVISION_FE; 00597 00598 } // namespace libMesh