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