fe_abstract.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/fe.h" 00022 #include "libmesh/libmesh_logging.h" 00023 00024 // For projection code: 00025 #include "libmesh/boundary_info.h" 00026 #include "libmesh/mesh_base.h" 00027 #include "libmesh/dense_matrix.h" 00028 #include "libmesh/dense_vector.h" 00029 #include "libmesh/dof_map.h" 00030 #include "libmesh/elem.h" 00031 #include "libmesh/fe_interface.h" 00032 #include "libmesh/numeric_vector.h" 00033 #include "libmesh/periodic_boundaries.h" 00034 #include "libmesh/periodic_boundary.h" 00035 #include "libmesh/quadrature.h" 00036 #include "libmesh/quadrature_gauss.h" 00037 #include "libmesh/remote_elem.h" 00038 #include "libmesh/tensor_value.h" 00039 #include "libmesh/threads.h" 00040 00041 namespace libMesh 00042 { 00043 00044 AutoPtr<FEAbstract> FEAbstract::build( const unsigned int dim, 00045 const FEType& fet) 00046 { 00047 // The stupid AutoPtr<FEAbstract> ap(); return ap; 00048 // construct is required to satisfy IBM's xlC 00049 00050 switch (dim) 00051 { 00052 // 0D 00053 case 0: 00054 { 00055 switch (fet.family) 00056 { 00057 case CLOUGH: 00058 { 00059 AutoPtr<FEAbstract> ap(new FE<0,CLOUGH>(fet)); 00060 return ap; 00061 } 00062 00063 case HERMITE: 00064 { 00065 AutoPtr<FEAbstract> ap(new FE<0,HERMITE>(fet)); 00066 return ap; 00067 } 00068 00069 case LAGRANGE: 00070 { 00071 AutoPtr<FEAbstract> ap(new FE<0,LAGRANGE>(fet)); 00072 return ap; 00073 } 00074 00075 case LAGRANGE_VEC: 00076 { 00077 AutoPtr<FEAbstract> ap(new FE<0,LAGRANGE_VEC>(fet)); 00078 return ap; 00079 } 00080 00081 case L2_LAGRANGE: 00082 { 00083 AutoPtr<FEAbstract> ap(new FE<0,L2_LAGRANGE>(fet)); 00084 return ap; 00085 } 00086 00087 case HIERARCHIC: 00088 { 00089 AutoPtr<FEAbstract> ap(new FE<0,HIERARCHIC>(fet)); 00090 return ap; 00091 } 00092 00093 case L2_HIERARCHIC: 00094 { 00095 AutoPtr<FEAbstract> ap(new FE<0,L2_HIERARCHIC>(fet)); 00096 return ap; 00097 } 00098 00099 case MONOMIAL: 00100 { 00101 AutoPtr<FEAbstract> ap(new FE<0,MONOMIAL>(fet)); 00102 return ap; 00103 } 00104 00105 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES 00106 case SZABAB: 00107 { 00108 AutoPtr<FEAbstract> ap(new FE<0,SZABAB>(fet)); 00109 return ap; 00110 } 00111 00112 case BERNSTEIN: 00113 { 00114 AutoPtr<FEAbstract> ap(new FE<0,BERNSTEIN>(fet)); 00115 return ap; 00116 } 00117 #endif 00118 00119 case XYZ: 00120 { 00121 AutoPtr<FEAbstract> ap(new FEXYZ<0>(fet)); 00122 return ap; 00123 } 00124 00125 case SCALAR: 00126 { 00127 AutoPtr<FEAbstract> ap(new FEScalar<0>(fet)); 00128 return ap; 00129 } 00130 00131 default: 00132 libMesh::out << "ERROR: Bad FEType.family= " << fet.family << std::endl; 00133 libmesh_error(); 00134 } 00135 } 00136 // 1D 00137 case 1: 00138 { 00139 switch (fet.family) 00140 { 00141 case CLOUGH: 00142 { 00143 AutoPtr<FEAbstract> ap(new FE<1,CLOUGH>(fet)); 00144 return ap; 00145 } 00146 00147 case HERMITE: 00148 { 00149 AutoPtr<FEAbstract> ap(new FE<1,HERMITE>(fet)); 00150 return ap; 00151 } 00152 00153 case LAGRANGE: 00154 { 00155 AutoPtr<FEAbstract> ap(new FE<1,LAGRANGE>(fet)); 00156 return ap; 00157 } 00158 00159 case LAGRANGE_VEC: 00160 { 00161 AutoPtr<FEAbstract> ap(new FE<1,LAGRANGE_VEC>(fet)); 00162 return ap; 00163 } 00164 00165 case L2_LAGRANGE: 00166 { 00167 AutoPtr<FEAbstract> ap(new FE<1,L2_LAGRANGE>(fet)); 00168 return ap; 00169 } 00170 00171 case HIERARCHIC: 00172 { 00173 AutoPtr<FEAbstract> ap(new FE<1,HIERARCHIC>(fet)); 00174 return ap; 00175 } 00176 00177 case L2_HIERARCHIC: 00178 { 00179 AutoPtr<FEAbstract> ap(new FE<1,L2_HIERARCHIC>(fet)); 00180 return ap; 00181 } 00182 00183 case MONOMIAL: 00184 { 00185 AutoPtr<FEAbstract> ap(new FE<1,MONOMIAL>(fet)); 00186 return ap; 00187 } 00188 00189 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES 00190 case SZABAB: 00191 { 00192 AutoPtr<FEAbstract> ap(new FE<1,SZABAB>(fet)); 00193 return ap; 00194 } 00195 00196 case BERNSTEIN: 00197 { 00198 AutoPtr<FEAbstract> ap(new FE<1,BERNSTEIN>(fet)); 00199 return ap; 00200 } 00201 #endif 00202 00203 case XYZ: 00204 { 00205 AutoPtr<FEAbstract> ap(new FEXYZ<1>(fet)); 00206 return ap; 00207 } 00208 00209 case SCALAR: 00210 { 00211 AutoPtr<FEAbstract> ap(new FEScalar<1>(fet)); 00212 return ap; 00213 } 00214 00215 default: 00216 libMesh::out << "ERROR: Bad FEType.family= " << fet.family << std::endl; 00217 libmesh_error(); 00218 } 00219 } 00220 00221 00222 // 2D 00223 case 2: 00224 { 00225 switch (fet.family) 00226 { 00227 case CLOUGH: 00228 { 00229 AutoPtr<FEAbstract> ap(new FE<2,CLOUGH>(fet)); 00230 return ap; 00231 } 00232 00233 case HERMITE: 00234 { 00235 AutoPtr<FEAbstract> ap(new FE<2,HERMITE>(fet)); 00236 return ap; 00237 } 00238 00239 case LAGRANGE: 00240 { 00241 AutoPtr<FEAbstract> ap(new FE<2,LAGRANGE>(fet)); 00242 return ap; 00243 } 00244 00245 case LAGRANGE_VEC: 00246 { 00247 AutoPtr<FEAbstract> ap(new FE<2,LAGRANGE_VEC>(fet)); 00248 return ap; 00249 } 00250 00251 case L2_LAGRANGE: 00252 { 00253 AutoPtr<FEAbstract> ap(new FE<2,L2_LAGRANGE>(fet)); 00254 return ap; 00255 } 00256 00257 case HIERARCHIC: 00258 { 00259 AutoPtr<FEAbstract> ap(new FE<2,HIERARCHIC>(fet)); 00260 return ap; 00261 } 00262 00263 case L2_HIERARCHIC: 00264 { 00265 AutoPtr<FEAbstract> ap(new FE<2,L2_HIERARCHIC>(fet)); 00266 return ap; 00267 } 00268 00269 case MONOMIAL: 00270 { 00271 AutoPtr<FEAbstract> ap(new FE<2,MONOMIAL>(fet)); 00272 return ap; 00273 } 00274 00275 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES 00276 case SZABAB: 00277 { 00278 AutoPtr<FEAbstract> ap(new FE<2,SZABAB>(fet)); 00279 return ap; 00280 } 00281 00282 case BERNSTEIN: 00283 { 00284 AutoPtr<FEAbstract> ap(new FE<2,BERNSTEIN>(fet)); 00285 return ap; 00286 } 00287 #endif 00288 00289 case XYZ: 00290 { 00291 AutoPtr<FEAbstract> ap(new FEXYZ<2>(fet)); 00292 return ap; 00293 } 00294 00295 case SCALAR: 00296 { 00297 AutoPtr<FEAbstract> ap(new FEScalar<2>(fet)); 00298 return ap; 00299 } 00300 00301 case NEDELEC_ONE: 00302 { 00303 AutoPtr<FEAbstract> ap(new FENedelecOne<2>(fet)); 00304 return ap; 00305 } 00306 00307 default: 00308 libMesh::out << "ERROR: Bad FEType.family= " << fet.family << std::endl; 00309 libmesh_error(); 00310 } 00311 } 00312 00313 00314 // 3D 00315 case 3: 00316 { 00317 switch (fet.family) 00318 { 00319 case CLOUGH: 00320 { 00321 libMesh::out << "ERROR: Clough-Tocher elements currently only support 1D and 2D" 00322 << std::endl; 00323 libmesh_error(); 00324 } 00325 00326 case HERMITE: 00327 { 00328 AutoPtr<FEAbstract> ap(new FE<3,HERMITE>(fet)); 00329 return ap; 00330 } 00331 00332 case LAGRANGE: 00333 { 00334 AutoPtr<FEAbstract> ap(new FE<3,LAGRANGE>(fet)); 00335 return ap; 00336 } 00337 00338 case LAGRANGE_VEC: 00339 { 00340 AutoPtr<FEAbstract> ap(new FE<3,LAGRANGE_VEC>(fet)); 00341 return ap; 00342 } 00343 00344 case L2_LAGRANGE: 00345 { 00346 AutoPtr<FEAbstract> ap(new FE<3,L2_LAGRANGE>(fet)); 00347 return ap; 00348 } 00349 00350 case HIERARCHIC: 00351 { 00352 AutoPtr<FEAbstract> ap(new FE<3,HIERARCHIC>(fet)); 00353 return ap; 00354 } 00355 00356 case L2_HIERARCHIC: 00357 { 00358 AutoPtr<FEAbstract> ap(new FE<3,L2_HIERARCHIC>(fet)); 00359 return ap; 00360 } 00361 00362 case MONOMIAL: 00363 { 00364 AutoPtr<FEAbstract> ap(new FE<3,MONOMIAL>(fet)); 00365 return ap; 00366 } 00367 00368 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES 00369 case SZABAB: 00370 { 00371 AutoPtr<FEAbstract> ap(new FE<3,SZABAB>(fet)); 00372 return ap; 00373 } 00374 00375 case BERNSTEIN: 00376 { 00377 AutoPtr<FEAbstract> ap(new FE<3,BERNSTEIN>(fet)); 00378 return ap; 00379 } 00380 #endif 00381 00382 case XYZ: 00383 { 00384 AutoPtr<FEAbstract> ap(new FEXYZ<3>(fet)); 00385 return ap; 00386 } 00387 00388 case SCALAR: 00389 { 00390 AutoPtr<FEAbstract> ap(new FEScalar<3>(fet)); 00391 return ap; 00392 } 00393 00394 case NEDELEC_ONE: 00395 { 00396 AutoPtr<FEAbstract> ap(new FENedelecOne<3>(fet)); 00397 return ap; 00398 } 00399 00400 default: 00401 libMesh::out << "ERROR: Bad FEType.family= " << fet.family << std::endl; 00402 libmesh_error(); 00403 } 00404 } 00405 00406 default: 00407 libmesh_error(); 00408 } 00409 00410 libmesh_error(); 00411 AutoPtr<FEAbstract> ap(NULL); 00412 return ap; 00413 } 00414 00415 void FEAbstract::get_refspace_nodes(const ElemType itemType, std::vector<Point>& nodes) 00416 { 00417 switch(itemType) 00418 { 00419 case EDGE2: 00420 { 00421 nodes.resize(2); 00422 nodes[0] = Point (-1.,0.,0.); 00423 nodes[1] = Point (1.,0.,0.); 00424 return; 00425 } 00426 case EDGE3: 00427 { 00428 nodes.resize(3); 00429 nodes[0] = Point (-1.,0.,0.); 00430 nodes[1] = Point (1.,0.,0.); 00431 nodes[2] = Point (0.,0.,0.); 00432 return; 00433 } 00434 case TRI3: 00435 { 00436 nodes.resize(3); 00437 nodes[0] = Point (0.,0.,0.); 00438 nodes[1] = Point (1.,0.,0.); 00439 nodes[2] = Point (0.,1.,0.); 00440 return; 00441 } 00442 case TRI6: 00443 { 00444 nodes.resize(6); 00445 nodes[0] = Point (0.,0.,0.); 00446 nodes[1] = Point (1.,0.,0.); 00447 nodes[2] = Point (0.,1.,0.); 00448 nodes[3] = Point (.5,0.,0.); 00449 nodes[4] = Point (.5,.5,0.); 00450 nodes[5] = Point (0.,.5,0.); 00451 return; 00452 } 00453 case QUAD4: 00454 { 00455 nodes.resize(4); 00456 nodes[0] = Point (-1.,-1.,0.); 00457 nodes[1] = Point (1.,-1.,0.); 00458 nodes[2] = Point (1.,1.,0.); 00459 nodes[3] = Point (-1.,1.,0.); 00460 return; 00461 } 00462 case QUAD8: 00463 { 00464 nodes.resize(8); 00465 nodes[0] = Point (-1.,-1.,0.); 00466 nodes[1] = Point (1.,-1.,0.); 00467 nodes[2] = Point (1.,1.,0.); 00468 nodes[3] = Point (-1.,1.,0.); 00469 nodes[4] = Point (0.,-1.,0.); 00470 nodes[5] = Point (1.,0.,0.); 00471 nodes[6] = Point (0.,1.,0.); 00472 nodes[7] = Point (-1.,0.,0.); 00473 return; 00474 } 00475 case QUAD9: 00476 { 00477 nodes.resize(9); 00478 nodes[0] = Point (-1.,-1.,0.); 00479 nodes[1] = Point (1.,-1.,0.); 00480 nodes[2] = Point (1.,1.,0.); 00481 nodes[3] = Point (-1.,1.,0.); 00482 nodes[4] = Point (0.,-1.,0.); 00483 nodes[5] = Point (1.,0.,0.); 00484 nodes[6] = Point (0.,1.,0.); 00485 nodes[7] = Point (-1.,0.,0.); 00486 nodes[8] = Point (0.,0.,0.); 00487 return; 00488 } 00489 case TET4: 00490 { 00491 nodes.resize(4); 00492 nodes[0] = Point (0.,0.,0.); 00493 nodes[1] = Point (1.,0.,0.); 00494 nodes[2] = Point (0.,1.,0.); 00495 nodes[3] = Point (0.,0.,1.); 00496 return; 00497 } 00498 case TET10: 00499 { 00500 nodes.resize(10); 00501 nodes[0] = Point (0.,0.,0.); 00502 nodes[1] = Point (1.,0.,0.); 00503 nodes[2] = Point (0.,1.,0.); 00504 nodes[3] = Point (0.,0.,1.); 00505 nodes[4] = Point (.5,0.,0.); 00506 nodes[5] = Point (.5,.5,0.); 00507 nodes[6] = Point (0.,.5,0.); 00508 nodes[7] = Point (0.,0.,.5); 00509 nodes[8] = Point (.5,0.,.5); 00510 nodes[9] = Point (0.,.5,.5); 00511 return; 00512 } 00513 case HEX8: 00514 { 00515 nodes.resize(8); 00516 nodes[0] = Point (-1.,-1.,-1.); 00517 nodes[1] = Point (1.,-1.,-1.); 00518 nodes[2] = Point (1.,1.,-1.); 00519 nodes[3] = Point (-1.,1.,-1.); 00520 nodes[4] = Point (-1.,-1.,1.); 00521 nodes[5] = Point (1.,-1.,1.); 00522 nodes[6] = Point (1.,1.,1.); 00523 nodes[7] = Point (-1.,1.,1.); 00524 return; 00525 } 00526 case HEX20: 00527 { 00528 nodes.resize(20); 00529 nodes[0] = Point (-1.,-1.,-1.); 00530 nodes[1] = Point (1.,-1.,-1.); 00531 nodes[2] = Point (1.,1.,-1.); 00532 nodes[3] = Point (-1.,1.,-1.); 00533 nodes[4] = Point (-1.,-1.,1.); 00534 nodes[5] = Point (1.,-1.,1.); 00535 nodes[6] = Point (1.,1.,1.); 00536 nodes[7] = Point (-1.,1.,1.); 00537 nodes[8] = Point (0.,-1.,-1.); 00538 nodes[9] = Point (1.,0.,-1.); 00539 nodes[10] = Point (0.,1.,-1.); 00540 nodes[11] = Point (-1.,0.,-1.); 00541 nodes[12] = Point (-1.,-1.,0.); 00542 nodes[13] = Point (1.,-1.,0.); 00543 nodes[14] = Point (1.,1.,0.); 00544 nodes[15] = Point (-1.,1.,0.); 00545 nodes[16] = Point (0.,-1.,1.); 00546 nodes[17] = Point (1.,0.,1.); 00547 nodes[18] = Point (0.,1.,1.); 00548 nodes[19] = Point (-1.,0.,1.); 00549 return; 00550 } 00551 case HEX27: 00552 { 00553 nodes.resize(27); 00554 nodes[0] = Point (-1.,-1.,-1.); 00555 nodes[1] = Point (1.,-1.,-1.); 00556 nodes[2] = Point (1.,1.,-1.); 00557 nodes[3] = Point (-1.,1.,-1.); 00558 nodes[4] = Point (-1.,-1.,1.); 00559 nodes[5] = Point (1.,-1.,1.); 00560 nodes[6] = Point (1.,1.,1.); 00561 nodes[7] = Point (-1.,1.,1.); 00562 nodes[8] = Point (0.,-1.,-1.); 00563 nodes[9] = Point (1.,0.,-1.); 00564 nodes[10] = Point (0.,1.,-1.); 00565 nodes[11] = Point (-1.,0.,-1.); 00566 nodes[12] = Point (-1.,-1.,0.); 00567 nodes[13] = Point (1.,-1.,0.); 00568 nodes[14] = Point (1.,1.,0.); 00569 nodes[15] = Point (-1.,1.,0.); 00570 nodes[16] = Point (0.,-1.,1.); 00571 nodes[17] = Point (1.,0.,1.); 00572 nodes[18] = Point (0.,1.,1.); 00573 nodes[19] = Point (-1.,0.,1.); 00574 nodes[20] = Point (0.,0.,-1.); 00575 nodes[21] = Point (0.,-1.,0.); 00576 nodes[22] = Point (1.,0.,0.); 00577 nodes[23] = Point (0.,1.,0.); 00578 nodes[24] = Point (-1.,0.,0.); 00579 nodes[25] = Point (0.,0.,1.); 00580 nodes[26] = Point (0.,0.,0.); 00581 return; 00582 } 00583 case PRISM6: 00584 { 00585 nodes.resize(6); 00586 nodes[0] = Point (0.,0.,-1.); 00587 nodes[1] = Point (1.,0.,-1.); 00588 nodes[2] = Point (0.,1.,-1.); 00589 nodes[3] = Point (0.,0.,1.); 00590 nodes[4] = Point (1.,0.,1.); 00591 nodes[5] = Point (0.,1.,1.); 00592 return; 00593 } 00594 case PRISM15: 00595 { 00596 nodes.resize(15); 00597 nodes[0] = Point (0.,0.,-1.); 00598 nodes[1] = Point (1.,0.,-1.); 00599 nodes[2] = Point (0.,1.,-1.); 00600 nodes[3] = Point (0.,0.,1.); 00601 nodes[4] = Point (1.,0.,1.); 00602 nodes[5] = Point (0.,1.,1.); 00603 nodes[6] = Point (.5,0.,-1.); 00604 nodes[7] = Point (.5,.5,-1.); 00605 nodes[8] = Point (0.,.5,-1.); 00606 nodes[9] = Point (0.,0.,0.); 00607 nodes[10] = Point (1.,0.,0.); 00608 nodes[11] = Point (0.,1.,0.); 00609 nodes[12] = Point (.5,0.,1.); 00610 nodes[13] = Point (.5,.5,1.); 00611 nodes[14] = Point (0.,.5,1.); 00612 return; 00613 } 00614 case PRISM18: 00615 { 00616 nodes.resize(18); 00617 nodes[0] = Point (0.,0.,-1.); 00618 nodes[1] = Point (1.,0.,-1.); 00619 nodes[2] = Point (0.,1.,-1.); 00620 nodes[3] = Point (0.,0.,1.); 00621 nodes[4] = Point (1.,0.,1.); 00622 nodes[5] = Point (0.,1.,1.); 00623 nodes[6] = Point (.5,0.,-1.); 00624 nodes[7] = Point (.5,.5,-1.); 00625 nodes[8] = Point (0.,.5,-1.); 00626 nodes[9] = Point (0.,0.,0.); 00627 nodes[10] = Point (1.,0.,0.); 00628 nodes[11] = Point (0.,1.,0.); 00629 nodes[12] = Point (.5,0.,1.); 00630 nodes[13] = Point (.5,.5,1.); 00631 nodes[14] = Point (0.,.5,1.); 00632 nodes[15] = Point (.5,0.,0.); 00633 nodes[16] = Point (.5,.5,0.); 00634 nodes[17] = Point (0.,.5,0.); 00635 return; 00636 } 00637 case PYRAMID5: 00638 { 00639 nodes.resize(5); 00640 nodes[0] = Point (-1.,-1.,0.); 00641 nodes[1] = Point (1.,-1.,0.); 00642 nodes[2] = Point (1.,1.,0.); 00643 nodes[3] = Point (-1.,1.,0.); 00644 nodes[4] = Point (-1.,-1.,1.); 00645 return; 00646 } 00647 default: 00648 { 00649 libMesh::err << "ERROR: Unknown element type " << itemType << std::endl; 00650 libmesh_error(); 00651 } 00652 } 00653 return; 00654 } 00655 00656 bool FEAbstract::on_reference_element(const Point& p, const ElemType t, const Real eps) 00657 { 00658 libmesh_assert_greater_equal (eps, 0.); 00659 00660 const Real xi = p(0); 00661 #if LIBMESH_DIM > 1 00662 const Real eta = p(1); 00663 #else 00664 const Real eta = 0.; 00665 #endif 00666 #if LIBMESH_DIM > 2 00667 const Real zeta = p(2); 00668 #else 00669 const Real zeta = 0.; 00670 #endif 00671 00672 switch (t) 00673 { 00674 case NODEELEM: 00675 { 00676 return (!xi && !eta && !zeta); 00677 } 00678 case EDGE2: 00679 case EDGE3: 00680 case EDGE4: 00681 { 00682 // The reference 1D element is [-1,1]. 00683 if ((xi >= -1.-eps) && 00684 (xi <= 1.+eps)) 00685 return true; 00686 00687 return false; 00688 } 00689 00690 00691 case TRI3: 00692 case TRI6: 00693 { 00694 // The reference triangle is isocoles 00695 // and is bound by xi=0, eta=0, and xi+eta=1. 00696 if ((xi >= 0.-eps) && 00697 (eta >= 0.-eps) && 00698 ((xi + eta) <= 1.+eps)) 00699 return true; 00700 00701 return false; 00702 } 00703 00704 00705 case QUAD4: 00706 case QUAD8: 00707 case QUAD9: 00708 { 00709 // The reference quadrilateral element is [-1,1]^2. 00710 if ((xi >= -1.-eps) && 00711 (xi <= 1.+eps) && 00712 (eta >= -1.-eps) && 00713 (eta <= 1.+eps)) 00714 return true; 00715 00716 return false; 00717 } 00718 00719 00720 case TET4: 00721 case TET10: 00722 { 00723 // The reference tetrahedral is isocoles 00724 // and is bound by xi=0, eta=0, zeta=0, 00725 // and xi+eta+zeta=1. 00726 if ((xi >= 0.-eps) && 00727 (eta >= 0.-eps) && 00728 (zeta >= 0.-eps) && 00729 ((xi + eta + zeta) <= 1.+eps)) 00730 return true; 00731 00732 return false; 00733 } 00734 00735 00736 case HEX8: 00737 case HEX20: 00738 case HEX27: 00739 { 00740 /* 00741 if ((xi >= -1.) && 00742 (xi <= 1.) && 00743 (eta >= -1.) && 00744 (eta <= 1.) && 00745 (zeta >= -1.) && 00746 (zeta <= 1.)) 00747 return true; 00748 */ 00749 00750 // The reference hexahedral element is [-1,1]^3. 00751 if ((xi >= -1.-eps) && 00752 (xi <= 1.+eps) && 00753 (eta >= -1.-eps) && 00754 (eta <= 1.+eps) && 00755 (zeta >= -1.-eps) && 00756 (zeta <= 1.+eps)) 00757 { 00758 // libMesh::out << "Strange Point:\n"; 00759 // p.print(); 00760 return true; 00761 } 00762 00763 return false; 00764 } 00765 00766 case PRISM6: 00767 case PRISM15: 00768 case PRISM18: 00769 { 00770 // Figure this one out... 00771 // inside the reference triange with zeta in [-1,1] 00772 if ((xi >= 0.-eps) && 00773 (eta >= 0.-eps) && 00774 (zeta >= -1.-eps) && 00775 (zeta <= 1.+eps) && 00776 ((xi + eta) <= 1.+eps)) 00777 return true; 00778 00779 return false; 00780 } 00781 00782 00783 case PYRAMID5: 00784 { 00785 libMesh::err << "BEN: Implement this you lazy bastard!" 00786 << std::endl; 00787 libmesh_error(); 00788 00789 return false; 00790 } 00791 00792 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00793 case INFHEX8: 00794 { 00795 // The reference infhex8 is a [-1,1]^3. 00796 if ((xi >= -1.-eps) && 00797 (xi <= 1.+eps) && 00798 (eta >= -1.-eps) && 00799 (eta <= 1.+eps) && 00800 (zeta >= -1.-eps) && 00801 (zeta <= 1.+eps)) 00802 { 00803 return true; 00804 } 00805 return false; 00806 } 00807 00808 case INFPRISM6: 00809 { 00810 // inside the reference triange with zeta in [-1,1] 00811 if ((xi >= 0.-eps) && 00812 (eta >= 0.-eps) && 00813 (zeta >= -1.-eps) && 00814 (zeta <= 1.+eps) && 00815 ((xi + eta) <= 1.+eps)) 00816 { 00817 return true; 00818 } 00819 00820 return false; 00821 } 00822 #endif 00823 00824 default: 00825 libMesh::err << "ERROR: Unknown element type " << t << std::endl; 00826 libmesh_error(); 00827 } 00828 00829 // If we get here then the point is _not_ in the 00830 // reference element. Better return false. 00831 00832 return false; 00833 } 00834 00835 00836 00837 00838 void FEAbstract::print_JxW(std::ostream& os) const 00839 { 00840 this->_fe_map->print_JxW(os); 00841 } 00842 00843 00844 00845 void FEAbstract::print_xyz(std::ostream& os) const 00846 { 00847 this->_fe_map->print_xyz(os); 00848 } 00849 00850 00851 void FEAbstract::print_info(std::ostream& os) const 00852 { 00853 os << "phi[i][j]: Shape function i at quadrature pt. j" << std::endl; 00854 this->print_phi(os); 00855 00856 os << "dphi[i][j]: Shape function i's gradient at quadrature pt. j" << std::endl; 00857 this->print_dphi(os); 00858 00859 os << "XYZ locations of the quadrature pts." << std::endl; 00860 this->print_xyz(os); 00861 00862 os << "Values of JxW at the quadrature pts." << std::endl; 00863 this->print_JxW(os); 00864 } 00865 00866 00867 std::ostream& operator << (std::ostream& os, const FEAbstract& fe) 00868 { 00869 fe.print_info(os); 00870 return os; 00871 } 00872 00873 00874 00875 #ifdef LIBMESH_ENABLE_AMR 00876 00877 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS 00878 void FEAbstract::compute_node_constraints (NodeConstraints &constraints, 00879 const Elem* elem) 00880 { 00881 libmesh_assert(elem); 00882 00883 const unsigned int Dim = elem->dim(); 00884 00885 // Only constrain elements in 2,3D. 00886 if (Dim == 1) 00887 return; 00888 00889 // Only constrain active and ancestor elements 00890 if (elem->subactive()) 00891 return; 00892 00893 // We currently always use LAGRANGE mappings for geometry 00894 const FEType fe_type(elem->default_order(), LAGRANGE); 00895 00896 std::vector<const Node*> my_nodes, parent_nodes; 00897 00898 // Look at the element faces. Check to see if we need to 00899 // build constraints. 00900 for (unsigned int s=0; s<elem->n_sides(); s++) 00901 if (elem->neighbor(s) != NULL && 00902 elem->neighbor(s) != remote_elem) 00903 if (elem->neighbor(s)->level() < elem->level()) // constrain dofs shared between 00904 { // this element and ones coarser 00905 // than this element. 00906 // Get pointers to the elements of interest and its parent. 00907 const Elem* parent = elem->parent(); 00908 00909 // This can't happen... Only level-0 elements have NULL 00910 // parents, and no level-0 elements can be at a higher 00911 // level than their neighbors! 00912 libmesh_assert(parent); 00913 00914 const AutoPtr<Elem> my_side (elem->build_side(s)); 00915 const AutoPtr<Elem> parent_side (parent->build_side(s)); 00916 00917 const unsigned int n_side_nodes = my_side->n_nodes(); 00918 00919 my_nodes.clear(); 00920 my_nodes.reserve (n_side_nodes); 00921 parent_nodes.clear(); 00922 parent_nodes.reserve (n_side_nodes); 00923 00924 for (unsigned int n=0; n != n_side_nodes; ++n) 00925 my_nodes.push_back(my_side->get_node(n)); 00926 00927 for (unsigned int n=0; n != n_side_nodes; ++n) 00928 parent_nodes.push_back(parent_side->get_node(n)); 00929 00930 for (unsigned int my_side_n=0; 00931 my_side_n < n_side_nodes; 00932 my_side_n++) 00933 { 00934 libmesh_assert_less (my_side_n, FEInterface::n_dofs(Dim-1, fe_type, my_side->type())); 00935 00936 const Node* my_node = my_nodes[my_side_n]; 00937 00938 // The support point of the DOF 00939 const Point& support_point = *my_node; 00940 00941 // Figure out where my node lies on their reference element. 00942 const Point mapped_point = FEInterface::inverse_map(Dim-1, fe_type, 00943 parent_side.get(), 00944 support_point); 00945 00946 // Compute the parent's side shape function values. 00947 for (unsigned int their_side_n=0; 00948 their_side_n < n_side_nodes; 00949 their_side_n++) 00950 { 00951 libmesh_assert_less (their_side_n, FEInterface::n_dofs(Dim-1, fe_type, parent_side->type())); 00952 00953 const Node* their_node = parent_nodes[their_side_n]; 00954 libmesh_assert(their_node); 00955 00956 const Real their_value = FEInterface::shape(Dim-1, 00957 fe_type, 00958 parent_side->type(), 00959 their_side_n, 00960 mapped_point); 00961 00962 const Real their_mag = std::abs(their_value); 00963 #ifdef DEBUG 00964 // Protect for the case u_i ~= u_j, 00965 // in which case i better equal j. 00966 if (their_mag > 0.999) 00967 { 00968 libmesh_assert_equal_to (my_node, their_node); 00969 libmesh_assert_less (std::abs(their_value - 1.), 0.001); 00970 } 00971 else 00972 #endif 00973 // To make nodal constraints useful for constructing 00974 // sparsity patterns faster, we need to get EVERY 00975 // POSSIBLE constraint coupling identified, even if 00976 // there is no coupling in the isoparametric 00977 // Lagrange case. 00978 if (their_mag < 1.e-5) 00979 { 00980 // since we may be running this method concurretly 00981 // on multiple threads we need to acquire a lock 00982 // before modifying the shared constraint_row object. 00983 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 00984 00985 // A reference to the constraint row. 00986 NodeConstraintRow& constraint_row = constraints[my_node].first; 00987 00988 constraint_row.insert(std::make_pair (their_node, 00989 0.)); 00990 } 00991 // To get nodal coordinate constraints right, only 00992 // add non-zero and non-identity values for Lagrange 00993 // basis functions. 00994 else // (1.e-5 <= their_mag <= .999) 00995 { 00996 // since we may be running this method concurretly 00997 // on multiple threads we need to acquire a lock 00998 // before modifying the shared constraint_row object. 00999 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 01000 01001 // A reference to the constraint row. 01002 NodeConstraintRow& constraint_row = constraints[my_node].first; 01003 01004 constraint_row.insert(std::make_pair (their_node, 01005 their_value)); 01006 } 01007 } 01008 } 01009 } 01010 } 01011 01012 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS 01013 01014 #endif // #ifdef LIBMESH_ENABLE_AMR 01015 01016 01017 01018 #ifdef LIBMESH_ENABLE_PERIODIC 01019 01020 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS 01021 void FEAbstract::compute_periodic_node_constraints (NodeConstraints &constraints, 01022 const PeriodicBoundaries &boundaries, 01023 const MeshBase &mesh, 01024 const PointLocatorBase *point_locator, 01025 const Elem* elem) 01026 { 01027 // Only bother if we truly have periodic boundaries 01028 if (boundaries.empty()) 01029 return; 01030 01031 libmesh_assert(elem); 01032 01033 // Only constrain active elements with this method 01034 if (!elem->active()) 01035 return; 01036 01037 const unsigned int Dim = elem->dim(); 01038 01039 // We currently always use LAGRANGE mappings for geometry 01040 const FEType fe_type(elem->default_order(), LAGRANGE); 01041 01042 std::vector<const Node*> my_nodes, neigh_nodes; 01043 01044 // Look at the element faces. Check to see if we need to 01045 // build constraints. 01046 for (unsigned int s=0; s<elem->n_sides(); s++) 01047 { 01048 if (elem->neighbor(s)) 01049 continue; 01050 01051 const std::vector<boundary_id_type>& bc_ids = mesh.boundary_info->boundary_ids (elem, s); 01052 for (std::vector<boundary_id_type>::const_iterator id_it=bc_ids.begin(); id_it!=bc_ids.end(); ++id_it) 01053 { 01054 const boundary_id_type boundary_id = *id_it; 01055 const PeriodicBoundaryBase *periodic = boundaries.boundary(boundary_id); 01056 if (periodic) 01057 { 01058 libmesh_assert(point_locator); 01059 01060 // Get pointers to the element's neighbor. 01061 const Elem* neigh = boundaries.neighbor(boundary_id, *point_locator, elem, s); 01062 01063 // h refinement constraints: 01064 // constrain dofs shared between 01065 // this element and ones as coarse 01066 // as or coarser than this element. 01067 if (neigh->level() <= elem->level()) 01068 { 01069 unsigned int s_neigh = 01070 mesh.boundary_info->side_with_boundary_id (neigh, periodic->pairedboundary); 01071 libmesh_assert_not_equal_to (s_neigh, libMesh::invalid_uint); 01072 01073 #ifdef LIBMESH_ENABLE_AMR 01074 libmesh_assert(neigh->active()); 01075 #endif // #ifdef LIBMESH_ENABLE_AMR 01076 01077 const AutoPtr<Elem> my_side (elem->build_side(s)); 01078 const AutoPtr<Elem> neigh_side (neigh->build_side(s_neigh)); 01079 01080 const unsigned int n_side_nodes = my_side->n_nodes(); 01081 01082 my_nodes.clear(); 01083 my_nodes.reserve (n_side_nodes); 01084 neigh_nodes.clear(); 01085 neigh_nodes.reserve (n_side_nodes); 01086 01087 for (unsigned int n=0; n != n_side_nodes; ++n) 01088 my_nodes.push_back(my_side->get_node(n)); 01089 01090 for (unsigned int n=0; n != n_side_nodes; ++n) 01091 neigh_nodes.push_back(neigh_side->get_node(n)); 01092 01093 // Make sure we're not adding recursive constraints 01094 // due to the redundancy in the way we add periodic 01095 // boundary constraints, or adding constraints to 01096 // nodes that already have AMR constraints 01097 std::vector<bool> skip_constraint(n_side_nodes, false); 01098 01099 for (unsigned int my_side_n=0; 01100 my_side_n < n_side_nodes; 01101 my_side_n++) 01102 { 01103 libmesh_assert_less (my_side_n, FEInterface::n_dofs(Dim-1, fe_type, my_side->type())); 01104 01105 const Node* my_node = my_nodes[my_side_n]; 01106 01107 // Figure out where my node lies on their reference element. 01108 const Point neigh_point = periodic->get_corresponding_pos(*my_node); 01109 01110 const Point mapped_point = FEInterface::inverse_map(Dim-1, fe_type, 01111 neigh_side.get(), 01112 neigh_point); 01113 01114 // If we've already got a constraint on this 01115 // node, then the periodic constraint is 01116 // redundant 01117 { 01118 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 01119 01120 if (constraints.count(my_node)) 01121 { 01122 skip_constraint[my_side_n] = true; 01123 continue; 01124 } 01125 } 01126 01127 // Compute the neighbors's side shape function values. 01128 for (unsigned int their_side_n=0; 01129 their_side_n < n_side_nodes; 01130 their_side_n++) 01131 { 01132 libmesh_assert_less (their_side_n, FEInterface::n_dofs(Dim-1, fe_type, neigh_side->type())); 01133 01134 const Node* their_node = neigh_nodes[their_side_n]; 01135 01136 // If there's a constraint on an opposing node, 01137 // we need to see if it's constrained by 01138 // *our side* making any periodic constraint 01139 // on us recursive 01140 { 01141 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 01142 01143 if (!constraints.count(their_node)) 01144 continue; 01145 01146 const NodeConstraintRow& their_constraint_row = 01147 constraints[their_node].first; 01148 01149 for (unsigned int orig_side_n=0; 01150 orig_side_n < n_side_nodes; 01151 orig_side_n++) 01152 { 01153 libmesh_assert_less (orig_side_n, FEInterface::n_dofs(Dim-1, fe_type, my_side->type())); 01154 01155 const Node* orig_node = my_nodes[orig_side_n]; 01156 01157 if (their_constraint_row.count(orig_node)) 01158 skip_constraint[orig_side_n] = true; 01159 } 01160 } 01161 } 01162 } 01163 for (unsigned int my_side_n=0; 01164 my_side_n < n_side_nodes; 01165 my_side_n++) 01166 { 01167 libmesh_assert_less (my_side_n, FEInterface::n_dofs(Dim-1, fe_type, my_side->type())); 01168 01169 if (skip_constraint[my_side_n]) 01170 continue; 01171 01172 const Node* my_node = my_nodes[my_side_n]; 01173 01174 // Figure out where my node lies on their reference element. 01175 const Point neigh_point = periodic->get_corresponding_pos(*my_node); 01176 01177 // Figure out where my node lies on their reference element. 01178 const Point mapped_point = FEInterface::inverse_map(Dim-1, fe_type, 01179 neigh_side.get(), 01180 neigh_point); 01181 01182 for (unsigned int their_side_n=0; 01183 their_side_n < n_side_nodes; 01184 their_side_n++) 01185 { 01186 libmesh_assert_less (their_side_n, FEInterface::n_dofs(Dim-1, fe_type, neigh_side->type())); 01187 01188 const Node* their_node = neigh_nodes[their_side_n]; 01189 libmesh_assert(their_node); 01190 01191 const Real their_value = FEInterface::shape(Dim-1, 01192 fe_type, 01193 neigh_side->type(), 01194 their_side_n, 01195 mapped_point); 01196 01197 // since we may be running this method concurretly 01198 // on multiple threads we need to acquire a lock 01199 // before modifying the shared constraint_row object. 01200 { 01201 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 01202 01203 NodeConstraintRow& constraint_row = 01204 constraints[my_node].first; 01205 01206 constraint_row.insert(std::make_pair(their_node, 01207 their_value)); 01208 } 01209 } 01210 } 01211 } 01212 } 01213 } 01214 } 01215 } 01216 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS 01217 01218 #endif // LIBMESH_ENABLE_PERIODIC 01219 01220 01221 } // namespace libMesh
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:46 UTC
Hosted By: