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