fe_lagrange.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 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/dof_map.h" 00022 #include "libmesh/fe.h" 00023 #include "libmesh/fe_interface.h" 00024 #include "libmesh/elem.h" 00025 #include "libmesh/threads.h" 00026 00027 namespace libMesh 00028 { 00029 00030 // ------------------------------------------------------------ 00031 // Lagrange-specific implementations 00032 00033 00034 // Anonymous namespace for local helper functions 00035 namespace { 00036 void lagrange_nodal_soln(const Elem* elem, 00037 const Order order, 00038 const std::vector<Number>& elem_soln, 00039 std::vector<Number>& nodal_soln) 00040 { 00041 const unsigned int n_nodes = elem->n_nodes(); 00042 const ElemType type = elem->type(); 00043 00044 const Order totalorder = static_cast<Order>(order+elem->p_level()); 00045 00046 nodal_soln.resize(n_nodes); 00047 00048 00049 00050 switch (totalorder) 00051 { 00052 // linear Lagrange shape functions 00053 case FIRST: 00054 { 00055 switch (type) 00056 { 00057 case EDGE3: 00058 { 00059 libmesh_assert_equal_to (elem_soln.size(), 2); 00060 libmesh_assert_equal_to (nodal_soln.size(), 3); 00061 00062 nodal_soln[0] = elem_soln[0]; 00063 nodal_soln[1] = elem_soln[1]; 00064 nodal_soln[2] = .5*(elem_soln[0] + elem_soln[1]); 00065 00066 return; 00067 } 00068 00069 case EDGE4: 00070 { 00071 libmesh_assert_equal_to (elem_soln.size(), 2); 00072 libmesh_assert_equal_to (nodal_soln.size(), 4); 00073 00074 nodal_soln[0] = elem_soln[0]; 00075 nodal_soln[1] = elem_soln[1]; 00076 nodal_soln[2] = (2.*elem_soln[0] + elem_soln[1])/3.; 00077 nodal_soln[3] = (elem_soln[0] + 2.*elem_soln[1])/3.; 00078 00079 return; 00080 } 00081 00082 00083 case TRI6: 00084 { 00085 libmesh_assert_equal_to (elem_soln.size(), 3); 00086 libmesh_assert_equal_to (nodal_soln.size(), 6); 00087 00088 nodal_soln[0] = elem_soln[0]; 00089 nodal_soln[1] = elem_soln[1]; 00090 nodal_soln[2] = elem_soln[2]; 00091 nodal_soln[3] = .5*(elem_soln[0] + elem_soln[1]); 00092 nodal_soln[4] = .5*(elem_soln[1] + elem_soln[2]); 00093 nodal_soln[5] = .5*(elem_soln[2] + elem_soln[0]); 00094 00095 return; 00096 } 00097 00098 00099 case QUAD8: 00100 case QUAD9: 00101 { 00102 libmesh_assert_equal_to (elem_soln.size(), 4); 00103 00104 if (type == QUAD8) 00105 libmesh_assert_equal_to (nodal_soln.size(), 8); 00106 else 00107 libmesh_assert_equal_to (nodal_soln.size(), 9); 00108 00109 00110 nodal_soln[0] = elem_soln[0]; 00111 nodal_soln[1] = elem_soln[1]; 00112 nodal_soln[2] = elem_soln[2]; 00113 nodal_soln[3] = elem_soln[3]; 00114 nodal_soln[4] = .5*(elem_soln[0] + elem_soln[1]); 00115 nodal_soln[5] = .5*(elem_soln[1] + elem_soln[2]); 00116 nodal_soln[6] = .5*(elem_soln[2] + elem_soln[3]); 00117 nodal_soln[7] = .5*(elem_soln[3] + elem_soln[0]); 00118 00119 if (type == QUAD9) 00120 nodal_soln[8] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3]); 00121 00122 return; 00123 } 00124 00125 00126 case TET10: 00127 { 00128 libmesh_assert_equal_to (elem_soln.size(), 4); 00129 libmesh_assert_equal_to (nodal_soln.size(), 10); 00130 00131 nodal_soln[0] = elem_soln[0]; 00132 nodal_soln[1] = elem_soln[1]; 00133 nodal_soln[2] = elem_soln[2]; 00134 nodal_soln[3] = elem_soln[3]; 00135 nodal_soln[4] = .5*(elem_soln[0] + elem_soln[1]); 00136 nodal_soln[5] = .5*(elem_soln[1] + elem_soln[2]); 00137 nodal_soln[6] = .5*(elem_soln[2] + elem_soln[0]); 00138 nodal_soln[7] = .5*(elem_soln[3] + elem_soln[0]); 00139 nodal_soln[8] = .5*(elem_soln[3] + elem_soln[1]); 00140 nodal_soln[9] = .5*(elem_soln[3] + elem_soln[2]); 00141 00142 return; 00143 } 00144 00145 00146 case HEX20: 00147 case HEX27: 00148 { 00149 libmesh_assert_equal_to (elem_soln.size(), 8); 00150 00151 if (type == HEX20) 00152 libmesh_assert_equal_to (nodal_soln.size(), 20); 00153 else 00154 libmesh_assert_equal_to (nodal_soln.size(), 27); 00155 00156 nodal_soln[0] = elem_soln[0]; 00157 nodal_soln[1] = elem_soln[1]; 00158 nodal_soln[2] = elem_soln[2]; 00159 nodal_soln[3] = elem_soln[3]; 00160 nodal_soln[4] = elem_soln[4]; 00161 nodal_soln[5] = elem_soln[5]; 00162 nodal_soln[6] = elem_soln[6]; 00163 nodal_soln[7] = elem_soln[7]; 00164 nodal_soln[8] = .5*(elem_soln[0] + elem_soln[1]); 00165 nodal_soln[9] = .5*(elem_soln[1] + elem_soln[2]); 00166 nodal_soln[10] = .5*(elem_soln[2] + elem_soln[3]); 00167 nodal_soln[11] = .5*(elem_soln[3] + elem_soln[0]); 00168 nodal_soln[12] = .5*(elem_soln[0] + elem_soln[4]); 00169 nodal_soln[13] = .5*(elem_soln[1] + elem_soln[5]); 00170 nodal_soln[14] = .5*(elem_soln[2] + elem_soln[6]); 00171 nodal_soln[15] = .5*(elem_soln[3] + elem_soln[7]); 00172 nodal_soln[16] = .5*(elem_soln[4] + elem_soln[5]); 00173 nodal_soln[17] = .5*(elem_soln[5] + elem_soln[6]); 00174 nodal_soln[18] = .5*(elem_soln[6] + elem_soln[7]); 00175 nodal_soln[19] = .5*(elem_soln[4] + elem_soln[7]); 00176 00177 if (type == HEX27) 00178 { 00179 nodal_soln[20] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3]); 00180 nodal_soln[21] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[4] + elem_soln[5]); 00181 nodal_soln[22] = .25*(elem_soln[1] + elem_soln[2] + elem_soln[5] + elem_soln[6]); 00182 nodal_soln[23] = .25*(elem_soln[2] + elem_soln[3] + elem_soln[6] + elem_soln[7]); 00183 nodal_soln[24] = .25*(elem_soln[3] + elem_soln[0] + elem_soln[7] + elem_soln[4]); 00184 nodal_soln[25] = .25*(elem_soln[4] + elem_soln[5] + elem_soln[6] + elem_soln[7]); 00185 00186 nodal_soln[26] = .125*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3] + 00187 elem_soln[4] + elem_soln[5] + elem_soln[6] + elem_soln[7]); 00188 } 00189 00190 return; 00191 } 00192 00193 00194 case PRISM15: 00195 case PRISM18: 00196 { 00197 libmesh_assert_equal_to (elem_soln.size(), 6); 00198 00199 if (type == PRISM15) 00200 libmesh_assert_equal_to (nodal_soln.size(), 15); 00201 else 00202 libmesh_assert_equal_to (nodal_soln.size(), 18); 00203 00204 nodal_soln[0] = elem_soln[0]; 00205 nodal_soln[1] = elem_soln[1]; 00206 nodal_soln[2] = elem_soln[2]; 00207 nodal_soln[3] = elem_soln[3]; 00208 nodal_soln[4] = elem_soln[4]; 00209 nodal_soln[5] = elem_soln[5]; 00210 nodal_soln[6] = .5*(elem_soln[0] + elem_soln[1]); 00211 nodal_soln[7] = .5*(elem_soln[1] + elem_soln[2]); 00212 nodal_soln[8] = .5*(elem_soln[0] + elem_soln[2]); 00213 nodal_soln[9] = .5*(elem_soln[0] + elem_soln[3]); 00214 nodal_soln[10] = .5*(elem_soln[1] + elem_soln[4]); 00215 nodal_soln[11] = .5*(elem_soln[2] + elem_soln[5]); 00216 nodal_soln[12] = .5*(elem_soln[3] + elem_soln[4]); 00217 nodal_soln[13] = .5*(elem_soln[4] + elem_soln[5]); 00218 nodal_soln[14] = .5*(elem_soln[3] + elem_soln[5]); 00219 00220 if (type == PRISM18) 00221 { 00222 nodal_soln[15] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[4] + elem_soln[3]); 00223 nodal_soln[16] = .25*(elem_soln[1] + elem_soln[2] + elem_soln[5] + elem_soln[4]); 00224 nodal_soln[17] = .25*(elem_soln[2] + elem_soln[0] + elem_soln[3] + elem_soln[5]); 00225 } 00226 00227 return; 00228 } 00229 00230 00231 00232 default: 00233 { 00234 // By default the element solution _is_ nodal, 00235 // so just copy it. 00236 nodal_soln = elem_soln; 00237 00238 return; 00239 } 00240 } 00241 } 00242 00243 case SECOND: 00244 { 00245 switch (type) 00246 { 00247 case EDGE4: 00248 { 00249 libmesh_assert_equal_to (elem_soln.size(), 3); 00250 libmesh_assert_equal_to (nodal_soln.size(), 4); 00251 00252 // Project quadratic solution onto cubic element nodes 00253 nodal_soln[0] = elem_soln[0]; 00254 nodal_soln[1] = elem_soln[1]; 00255 nodal_soln[2] = (2.*elem_soln[0] - elem_soln[1] + 00256 8.*elem_soln[2])/9.; 00257 nodal_soln[3] = (-elem_soln[0] + 2.*elem_soln[1] + 00258 8.*elem_soln[2])/9.; 00259 return; 00260 } 00261 00262 default: 00263 { 00264 // By default the element solution _is_ nodal, 00265 // so just copy it. 00266 nodal_soln = elem_soln; 00267 00268 return; 00269 } 00270 } 00271 } 00272 00273 00274 00275 00276 default: 00277 { 00278 // By default the element solution _is_ nodal, 00279 // so just copy it. 00280 nodal_soln = elem_soln; 00281 00282 return; 00283 } 00284 } 00285 } 00286 00287 00288 00289 unsigned int lagrange_n_dofs(const ElemType t, const Order o) 00290 { 00291 switch (o) 00292 { 00293 00294 // linear Lagrange shape functions 00295 case FIRST: 00296 { 00297 switch (t) 00298 { 00299 case NODEELEM: 00300 return 1; 00301 00302 case EDGE2: 00303 case EDGE3: 00304 case EDGE4: 00305 return 2; 00306 00307 case TRI3: 00308 case TRI6: 00309 return 3; 00310 00311 case QUAD4: 00312 case QUAD8: 00313 case QUAD9: 00314 return 4; 00315 00316 case TET4: 00317 case TET10: 00318 return 4; 00319 00320 case HEX8: 00321 case HEX20: 00322 case HEX27: 00323 return 8; 00324 00325 case PRISM6: 00326 case PRISM15: 00327 case PRISM18: 00328 return 6; 00329 00330 case PYRAMID5: 00331 return 5; 00332 00333 default: 00334 { 00335 #ifdef DEBUG 00336 libMesh::err << "ERROR: Bad ElemType = " << t 00337 << " for FIRST order approximation!" 00338 << std::endl; 00339 #endif 00340 libmesh_error(); 00341 } 00342 } 00343 } 00344 00345 00346 // quadratic Lagrange shape functions 00347 case SECOND: 00348 { 00349 switch (t) 00350 { 00351 case NODEELEM: 00352 return 1; 00353 00354 case EDGE3: 00355 return 3; 00356 00357 case TRI6: 00358 return 6; 00359 00360 case QUAD8: 00361 return 8; 00362 00363 case QUAD9: 00364 return 9; 00365 00366 case TET10: 00367 return 10; 00368 00369 case HEX20: 00370 return 20; 00371 00372 case HEX27: 00373 return 27; 00374 00375 case PRISM15: 00376 return 15; 00377 00378 case PRISM18: 00379 return 18; 00380 00381 default: 00382 { 00383 #ifdef DEBUG 00384 libMesh::err << "ERROR: Bad ElemType = " << t 00385 << " for SECOND order approximation!" 00386 << std::endl; 00387 #endif 00388 libmesh_error(); 00389 } 00390 } 00391 } 00392 00393 case THIRD: 00394 { 00395 switch (t) 00396 { 00397 case NODEELEM: 00398 return 1; 00399 00400 case EDGE4: 00401 return 4; 00402 00403 default: 00404 { 00405 #ifdef DEBUG 00406 libMesh::err << "ERROR: Bad ElemType = " << t 00407 << " for THIRD order approximation!" 00408 << std::endl; 00409 #endif 00410 libmesh_error(); 00411 } 00412 } 00413 } 00414 00415 default: 00416 libmesh_error(); 00417 } 00418 00419 libmesh_error(); 00420 return 0; 00421 } 00422 00423 00424 00425 00426 unsigned int lagrange_n_dofs_at_node(const ElemType t, 00427 const Order o, 00428 const unsigned int n) 00429 { 00430 switch (o) 00431 { 00432 00433 // linear Lagrange shape functions 00434 case FIRST: 00435 { 00436 switch (t) 00437 { 00438 case NODEELEM: 00439 return 1; 00440 00441 case EDGE2: 00442 case EDGE3: 00443 case EDGE4: 00444 { 00445 switch (n) 00446 { 00447 case 0: 00448 case 1: 00449 return 1; 00450 00451 default: 00452 return 0; 00453 } 00454 } 00455 00456 case TRI3: 00457 case TRI6: 00458 { 00459 switch (n) 00460 { 00461 case 0: 00462 case 1: 00463 case 2: 00464 return 1; 00465 00466 default: 00467 return 0; 00468 } 00469 } 00470 00471 case QUAD4: 00472 case QUAD8: 00473 case QUAD9: 00474 { 00475 switch (n) 00476 { 00477 case 0: 00478 case 1: 00479 case 2: 00480 case 3: 00481 return 1; 00482 00483 default: 00484 return 0; 00485 } 00486 } 00487 00488 00489 case TET4: 00490 case TET10: 00491 { 00492 switch (n) 00493 { 00494 case 0: 00495 case 1: 00496 case 2: 00497 case 3: 00498 return 1; 00499 00500 default: 00501 return 0; 00502 } 00503 } 00504 00505 case HEX8: 00506 case HEX20: 00507 case HEX27: 00508 { 00509 switch (n) 00510 { 00511 case 0: 00512 case 1: 00513 case 2: 00514 case 3: 00515 case 4: 00516 case 5: 00517 case 6: 00518 case 7: 00519 return 1; 00520 00521 default: 00522 return 0; 00523 } 00524 } 00525 00526 case PRISM6: 00527 case PRISM15: 00528 case PRISM18: 00529 { 00530 switch (n) 00531 { 00532 case 0: 00533 case 1: 00534 case 2: 00535 case 3: 00536 case 4: 00537 case 5: 00538 return 1; 00539 00540 default: 00541 return 0; 00542 } 00543 } 00544 00545 case PYRAMID5: 00546 { 00547 switch (n) 00548 { 00549 case 0: 00550 case 1: 00551 case 2: 00552 case 3: 00553 case 4: 00554 return 1; 00555 00556 default: 00557 return 0; 00558 } 00559 } 00560 00561 default: 00562 { 00563 #ifdef DEBUG 00564 libMesh::err << "ERROR: Bad ElemType = " << t 00565 << " for FIRST order approximation!" 00566 << std::endl; 00567 #endif 00568 libmesh_error(); 00569 } 00570 } 00571 } 00572 00573 // quadratic Lagrange shape functions 00574 case SECOND: 00575 { 00576 switch (t) 00577 { 00578 // quadratic lagrange has one dof at each node 00579 case NODEELEM: 00580 case EDGE3: 00581 case TRI6: 00582 case QUAD8: 00583 case QUAD9: 00584 case TET10: 00585 case HEX20: 00586 case HEX27: 00587 case PRISM15: 00588 case PRISM18: 00589 return 1; 00590 00591 default: 00592 { 00593 #ifdef DEBUG 00594 libMesh::err << "ERROR: Bad ElemType = " << t 00595 << " for SECOND order approximation!" 00596 << std::endl; 00597 #endif 00598 libmesh_error(); 00599 } 00600 } 00601 } 00602 00603 case THIRD: 00604 { 00605 switch (t) 00606 { 00607 case NODEELEM: 00608 case EDGE4: 00609 return 1; 00610 00611 default: 00612 { 00613 #ifdef DEBUG 00614 libMesh::err << "ERROR: Bad ElemType = " << t 00615 << " for THIRD order approximation!" 00616 << std::endl; 00617 #endif 00618 libmesh_error(); 00619 } 00620 } 00621 } 00622 00623 00624 00625 default: 00626 libmesh_error(); 00627 } 00628 00629 libmesh_error(); 00630 return 0; 00631 00632 } 00633 00634 00635 00636 #ifdef LIBMESH_ENABLE_AMR 00637 void lagrange_compute_constraints (DofConstraints &constraints, 00638 DofMap &dof_map, 00639 const unsigned int variable_number, 00640 const Elem* elem, 00641 const unsigned Dim) 00642 { 00643 // Only constrain elements in 2,3D. 00644 if (Dim == 1) 00645 return; 00646 00647 libmesh_assert(elem); 00648 00649 // Only constrain active and ancestor elements 00650 if (elem->subactive()) 00651 return; 00652 00653 FEType fe_type = dof_map.variable_type(variable_number); 00654 fe_type.order = static_cast<Order>(fe_type.order + elem->p_level()); 00655 00656 std::vector<dof_id_type> my_dof_indices, parent_dof_indices; 00657 00658 // Look at the element faces. Check to see if we need to 00659 // build constraints. 00660 for (unsigned int s=0; s<elem->n_sides(); s++) 00661 if (elem->neighbor(s) != NULL) 00662 if (elem->neighbor(s)->level() < elem->level()) // constrain dofs shared between 00663 { // this element and ones coarser 00664 // than this element. 00665 // Get pointers to the elements of interest and its parent. 00666 const Elem* parent = elem->parent(); 00667 00668 // This can't happen... Only level-0 elements have NULL 00669 // parents, and no level-0 elements can be at a higher 00670 // level than their neighbors! 00671 libmesh_assert(parent); 00672 00673 const AutoPtr<Elem> my_side (elem->build_side(s)); 00674 const AutoPtr<Elem> parent_side (parent->build_side(s)); 00675 00676 // This function gets called element-by-element, so there 00677 // will be a lot of memory allocation going on. We can 00678 // at least minimize this for the case of the dof indices 00679 // by efficiently preallocating the requisite storage. 00680 my_dof_indices.reserve (my_side->n_nodes()); 00681 parent_dof_indices.reserve (parent_side->n_nodes()); 00682 00683 dof_map.dof_indices (my_side.get(), my_dof_indices, 00684 variable_number); 00685 dof_map.dof_indices (parent_side.get(), parent_dof_indices, 00686 variable_number); 00687 00688 for (unsigned int my_dof=0; 00689 my_dof<FEInterface::n_dofs(Dim-1, fe_type, my_side->type()); 00690 my_dof++) 00691 { 00692 libmesh_assert_less (my_dof, my_side->n_nodes()); 00693 00694 // My global dof index. 00695 const dof_id_type my_dof_g = my_dof_indices[my_dof]; 00696 00697 // Hunt for "constraining against myself" cases before 00698 // we bother creating a constraint row 00699 bool self_constraint = false; 00700 for (unsigned int their_dof=0; 00701 their_dof<FEInterface::n_dofs(Dim-1, fe_type, parent_side->type()); 00702 their_dof++) 00703 { 00704 libmesh_assert_less (their_dof, parent_side->n_nodes()); 00705 00706 // Their global dof index. 00707 const dof_id_type their_dof_g = 00708 parent_dof_indices[their_dof]; 00709 00710 if (their_dof_g == my_dof_g) 00711 { 00712 self_constraint = true; 00713 break; 00714 } 00715 } 00716 00717 if (self_constraint) 00718 continue; 00719 00720 DofConstraintRow* constraint_row; 00721 00722 // we may be running constraint methods concurretly 00723 // on multiple threads, so we need a lock to 00724 // ensure that this constraint is "ours" 00725 { 00726 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 00727 00728 if (dof_map.is_constrained_dof(my_dof_g)) 00729 continue; 00730 00731 constraint_row = &(constraints[my_dof_g].first); 00732 libmesh_assert(constraint_row->empty()); 00733 constraints[my_dof_g].second = 0; 00734 } 00735 00736 // The support point of the DOF 00737 const Point& support_point = my_side->point(my_dof); 00738 00739 // Figure out where my node lies on their reference element. 00740 const Point mapped_point = FEInterface::inverse_map(Dim-1, fe_type, 00741 parent_side.get(), 00742 support_point); 00743 00744 // Compute the parent's side shape function values. 00745 for (unsigned int their_dof=0; 00746 their_dof<FEInterface::n_dofs(Dim-1, fe_type, parent_side->type()); 00747 their_dof++) 00748 { 00749 libmesh_assert_less (their_dof, parent_side->n_nodes()); 00750 00751 // Their global dof index. 00752 const dof_id_type their_dof_g = 00753 parent_dof_indices[their_dof]; 00754 00755 const Real their_dof_value = FEInterface::shape(Dim-1, 00756 fe_type, 00757 parent_side->type(), 00758 their_dof, 00759 mapped_point); 00760 00761 // Only add non-zero and non-identity values 00762 // for Lagrange basis functions. 00763 if ((std::abs(their_dof_value) > 1.e-5) && 00764 (std::abs(their_dof_value) < .999)) 00765 { 00766 constraint_row->insert(std::make_pair (their_dof_g, 00767 their_dof_value)); 00768 } 00769 #ifdef DEBUG 00770 // Protect for the case u_i = 0.999 u_j, 00771 // in which case i better equal j. 00772 else if (their_dof_value >= .999) 00773 libmesh_assert_equal_to (my_dof_g, their_dof_g); 00774 #endif 00775 } 00776 } 00777 } 00778 } // lagrange_compute_constrants() 00779 #endif // #ifdef LIBMESH_ENABLE_AMR 00780 00781 } // anonymous namespace 00782 00783 00784 // Do full-specialization for every dimension, instead 00785 // of explicit instantiation at the end of this file. 00786 // This could be macro-ified so that it fits on one line... 00787 template <> 00788 void FE<0,LAGRANGE>::nodal_soln(const Elem* elem, 00789 const Order order, 00790 const std::vector<Number>& elem_soln, 00791 std::vector<Number>& nodal_soln) 00792 { lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); } 00793 00794 template <> 00795 void FE<1,LAGRANGE>::nodal_soln(const Elem* elem, 00796 const Order order, 00797 const std::vector<Number>& elem_soln, 00798 std::vector<Number>& nodal_soln) 00799 { lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); } 00800 00801 template <> 00802 void FE<2,LAGRANGE>::nodal_soln(const Elem* elem, 00803 const Order order, 00804 const std::vector<Number>& elem_soln, 00805 std::vector<Number>& nodal_soln) 00806 { lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); } 00807 00808 template <> 00809 void FE<3,LAGRANGE>::nodal_soln(const Elem* elem, 00810 const Order order, 00811 const std::vector<Number>& elem_soln, 00812 std::vector<Number>& nodal_soln) 00813 { lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); } 00814 00815 00816 // Do full-specialization for every dimension, instead 00817 // of explicit instantiation at the end of this function. 00818 // This could be macro-ified. 00819 template <> unsigned int FE<0,LAGRANGE>::n_dofs(const ElemType t, const Order o) { return lagrange_n_dofs(t, o); } 00820 template <> unsigned int FE<1,LAGRANGE>::n_dofs(const ElemType t, const Order o) { return lagrange_n_dofs(t, o); } 00821 template <> unsigned int FE<2,LAGRANGE>::n_dofs(const ElemType t, const Order o) { return lagrange_n_dofs(t, o); } 00822 template <> unsigned int FE<3,LAGRANGE>::n_dofs(const ElemType t, const Order o) { return lagrange_n_dofs(t, o); } 00823 00824 00825 // Do full-specialization for every dimension, instead 00826 // of explicit instantiation at the end of this function. 00827 template <> unsigned int FE<0,LAGRANGE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(t, o, n); } 00828 template <> unsigned int FE<1,LAGRANGE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(t, o, n); } 00829 template <> unsigned int FE<2,LAGRANGE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(t, o, n); } 00830 template <> unsigned int FE<3,LAGRANGE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(t, o, n); } 00831 00832 00833 // Lagrange elements have no dofs per element 00834 // (just at the nodes) 00835 template <> unsigned int FE<0,LAGRANGE>::n_dofs_per_elem(const ElemType, const Order) { return 0; } 00836 template <> unsigned int FE<1,LAGRANGE>::n_dofs_per_elem(const ElemType, const Order) { return 0; } 00837 template <> unsigned int FE<2,LAGRANGE>::n_dofs_per_elem(const ElemType, const Order) { return 0; } 00838 template <> unsigned int FE<3,LAGRANGE>::n_dofs_per_elem(const ElemType, const Order) { return 0; } 00839 00840 // Lagrange FEMs are always C^0 continuous 00841 template <> FEContinuity FE<0,LAGRANGE>::get_continuity() const { return C_ZERO; } 00842 template <> FEContinuity FE<1,LAGRANGE>::get_continuity() const { return C_ZERO; } 00843 template <> FEContinuity FE<2,LAGRANGE>::get_continuity() const { return C_ZERO; } 00844 template <> FEContinuity FE<3,LAGRANGE>::get_continuity() const { return C_ZERO; } 00845 00846 // Lagrange FEMs are not hierarchic 00847 template <> bool FE<0,LAGRANGE>::is_hierarchic() const { return false; } 00848 template <> bool FE<1,LAGRANGE>::is_hierarchic() const { return false; } 00849 template <> bool FE<2,LAGRANGE>::is_hierarchic() const { return false; } 00850 template <> bool FE<3,LAGRANGE>::is_hierarchic() const { return false; } 00851 00852 // Lagrange FEM shapes do not need reinit (is this always true?) 00853 template <> bool FE<0,LAGRANGE>::shapes_need_reinit() const { return false; } 00854 template <> bool FE<1,LAGRANGE>::shapes_need_reinit() const { return false; } 00855 template <> bool FE<2,LAGRANGE>::shapes_need_reinit() const { return false; } 00856 template <> bool FE<3,LAGRANGE>::shapes_need_reinit() const { return false; } 00857 00858 // Methods for computing Lagrange constraints. Note: we pass the 00859 // dimension as the last argument to the anonymous helper function. 00860 // Also note: we only need instantiations of this function for 00861 // Dim==2 and 3. 00862 #ifdef LIBMESH_ENABLE_AMR 00863 template <> 00864 void FE<2,LAGRANGE>::compute_constraints (DofConstraints &constraints, 00865 DofMap &dof_map, 00866 const unsigned int variable_number, 00867 const Elem* elem) 00868 { lagrange_compute_constraints(constraints, dof_map, variable_number, elem, /*Dim=*/2); } 00869 00870 template <> 00871 void FE<3,LAGRANGE>::compute_constraints (DofConstraints &constraints, 00872 DofMap &dof_map, 00873 const unsigned int variable_number, 00874 const Elem* elem) 00875 { lagrange_compute_constraints(constraints, dof_map, variable_number, elem, /*Dim=*/3); } 00876 #endif // LIBMESH_ENABLE_AMR 00877 00878 } // namespace libMesh
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:46 UTC
Hosted By: