$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 // C++ includes 00020 00021 // Local includes 00022 #include "libmesh/fe.h" 00023 #include "libmesh/elem.h" 00024 #include "libmesh/number_lookups.h" 00025 #include "libmesh/utility.h" 00026 00027 00028 namespace libMesh 00029 { 00030 00031 template <> 00032 Real FE<2,HIERARCHIC>::shape(const ElemType, 00033 const Order, 00034 const unsigned int, 00035 const Point&) 00036 { 00037 libmesh_error_msg("Hierarchic polynomials require the element type \nbecause edge orientation is needed."); 00038 return 0.; 00039 } 00040 00041 00042 00043 template <> 00044 Real FE<2,HIERARCHIC>::shape(const Elem* elem, 00045 const Order order, 00046 const unsigned int i, 00047 const Point& p) 00048 { 00049 libmesh_assert(elem); 00050 00051 const Order totalorder = static_cast<Order>(order+elem->p_level()); 00052 libmesh_assert_greater (totalorder, 0); 00053 00054 switch (elem->type()) 00055 { 00056 case TRI3: 00057 case TRI6: 00058 { 00059 const Real zeta1 = p(0); 00060 const Real zeta2 = p(1); 00061 const Real zeta0 = 1. - zeta1 - zeta2; 00062 00063 libmesh_assert_less (i, (totalorder+1u)*(totalorder+2u)/2); 00064 libmesh_assert (elem->type() == TRI6 || totalorder < 2); 00065 00066 // Vertex DoFs 00067 if (i == 0) 00068 return zeta0; 00069 else if (i == 1) 00070 return zeta1; 00071 else if (i == 2) 00072 return zeta2; 00073 // Edge DoFs 00074 else if (i < totalorder + 2u) 00075 { 00076 // Avoid returning NaN on vertices! 00077 if (zeta0 + zeta1 == 0.) 00078 return 0.; 00079 00080 const unsigned int basisorder = i - 1; 00081 // Get factors to account for edge-flipping 00082 Real f0 = 1; 00083 if (basisorder%2 && (elem->point(0) > elem->point(1))) 00084 f0 = -1.; 00085 00086 Real edgeval = (zeta1 - zeta0) / (zeta1 + zeta0); 00087 Real crossfunc = zeta0 + zeta1; 00088 for (unsigned int n=1; n != basisorder; ++n) 00089 crossfunc *= (zeta0 + zeta1); 00090 00091 return f0 * crossfunc * 00092 FE<1,HIERARCHIC>::shape(EDGE3, totalorder, 00093 basisorder, edgeval); 00094 } 00095 else if (i < 2u*totalorder + 1) 00096 { 00097 // Avoid returning NaN on vertices! 00098 if (zeta1 + zeta2 == 0.) 00099 return 0.; 00100 00101 const unsigned int basisorder = i - totalorder; 00102 // Get factors to account for edge-flipping 00103 Real f1 = 1; 00104 if (basisorder%2 && (elem->point(1) > elem->point(2))) 00105 f1 = -1.; 00106 00107 Real edgeval = (zeta2 - zeta1) / (zeta2 + zeta1); 00108 Real crossfunc = zeta2 + zeta1; 00109 for (unsigned int n=1; n != basisorder; ++n) 00110 crossfunc *= (zeta2 + zeta1); 00111 00112 return f1 * crossfunc * 00113 FE<1,HIERARCHIC>::shape(EDGE3, totalorder, 00114 basisorder, edgeval); 00115 } 00116 else if (i < 3u*totalorder) 00117 { 00118 // Avoid returning NaN on vertices! 00119 if (zeta0 + zeta2 == 0.) 00120 return 0.; 00121 00122 const unsigned int basisorder = i - (2u*totalorder) + 1; 00123 // Get factors to account for edge-flipping 00124 Real f2 = 1; 00125 if (basisorder%2 && (elem->point(2) > elem->point(0))) 00126 f2 = -1.; 00127 00128 Real edgeval = (zeta0 - zeta2) / (zeta0 + zeta2); 00129 Real crossfunc = zeta0 + zeta2; 00130 for (unsigned int n=1; n != basisorder; ++n) 00131 crossfunc *= (zeta0 + zeta2); 00132 00133 return f2 * crossfunc * 00134 FE<1,HIERARCHIC>::shape(EDGE3, totalorder, 00135 basisorder, edgeval); 00136 } 00137 // Interior DoFs 00138 else 00139 { 00140 const unsigned int basisnum = i - (3u*totalorder); 00141 unsigned int exp0 = triangular_number_column[basisnum] + 1; 00142 unsigned int exp1 = triangular_number_row[basisnum] + 1 - 00143 triangular_number_column[basisnum]; 00144 00145 Real returnval = 1; 00146 for (unsigned int n = 0; n != exp0; ++n) 00147 returnval *= zeta0; 00148 for (unsigned int n = 0; n != exp1; ++n) 00149 returnval *= zeta1; 00150 returnval *= zeta2; 00151 return returnval; 00152 } 00153 } 00154 00155 // Hierarchic shape functions on the quadrilateral. 00156 case QUAD4: 00157 libmesh_assert_less (totalorder, 2); 00158 case QUAD8: 00159 case QUAD9: 00160 { 00161 // Compute quad shape functions as a tensor-product 00162 const Real xi = p(0); 00163 const Real eta = p(1); 00164 00165 libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)); 00166 00167 // Example i, i0, i1 values for totalorder = 5: 00168 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 00169 // static const unsigned int i0[] = {0, 1, 1, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 2, 3, 3, 2, 4, 4, 4, 3, 2, 5, 5, 5, 5, 4, 3, 2}; 00170 // static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 0, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 2, 2, 3, 3, 2, 3, 4, 4, 4, 2, 3, 4, 5, 5, 5, 5}; 00171 00172 unsigned int i0, i1; 00173 00174 // Vertex DoFs 00175 if (i == 0) 00176 { i0 = 0; i1 = 0; } 00177 else if (i == 1) 00178 { i0 = 1; i1 = 0; } 00179 else if (i == 2) 00180 { i0 = 1; i1 = 1; } 00181 else if (i == 3) 00182 { i0 = 0; i1 = 1; } 00183 // Edge DoFs 00184 else if (i < totalorder + 3u) 00185 { i0 = i - 2; i1 = 0; } 00186 else if (i < 2u*totalorder + 2) 00187 { i0 = 1; i1 = i - totalorder - 1; } 00188 else if (i < 3u*totalorder + 1) 00189 { i0 = i - 2u*totalorder; i1 = 1; } 00190 else if (i < 4u*totalorder) 00191 { i0 = 0; i1 = i - 3u*totalorder + 1; } 00192 // Interior DoFs 00193 else 00194 { 00195 unsigned int basisnum = i - 4*totalorder; 00196 i0 = square_number_column[basisnum] + 2; 00197 i1 = square_number_row[basisnum] + 2; 00198 } 00199 00200 // Flip odd degree of freedom values if necessary 00201 // to keep continuity on sides 00202 Real f = 1.; 00203 00204 if ((i0%2) && (i0 > 2) && (i1 == 0)) 00205 f = (elem->point(0) > elem->point(1))?-1.:1.; 00206 else if ((i0%2) && (i0>2) && (i1 == 1)) 00207 f = (elem->point(3) > elem->point(2))?-1.:1.; 00208 else if ((i0 == 0) && (i1%2) && (i1>2)) 00209 f = (elem->point(0) > elem->point(3))?-1.:1.; 00210 else if ((i0 == 1) && (i1%2) && (i1>2)) 00211 f = (elem->point(1) > elem->point(2))?-1.:1.; 00212 00213 return f*(FE<1,HIERARCHIC>::shape(EDGE3, totalorder, i0, xi)* 00214 FE<1,HIERARCHIC>::shape(EDGE3, totalorder, i1, eta)); 00215 } 00216 00217 default: 00218 libmesh_error_msg("ERROR: Unsupported element type = " << elem->type()); 00219 } 00220 00221 return 0.; 00222 } 00223 00224 00225 00226 template <> 00227 Real FE<2,HIERARCHIC>::shape_deriv(const ElemType, 00228 const Order, 00229 const unsigned int, 00230 const unsigned int, 00231 const Point&) 00232 { 00233 libmesh_error_msg("Hierarchic polynomials require the element type \nbecause edge orientation is needed."); 00234 return 0.; 00235 } 00236 00237 00238 00239 template <> 00240 Real FE<2,HIERARCHIC>::shape_deriv(const Elem* elem, 00241 const Order order, 00242 const unsigned int i, 00243 const unsigned int j, 00244 const Point& p) 00245 { 00246 libmesh_assert(elem); 00247 00248 const ElemType type = elem->type(); 00249 00250 const Order totalorder = static_cast<Order>(order+elem->p_level()); 00251 00252 libmesh_assert_greater (totalorder, 0); 00253 00254 switch (type) 00255 { 00256 // 1st & 2nd-order Hierarchics. 00257 case TRI3: 00258 case TRI6: 00259 { 00260 const Real eps = 1.e-6; 00261 00262 libmesh_assert_less (j, 2); 00263 00264 switch (j) 00265 { 00266 // d()/dxi 00267 case 0: 00268 { 00269 const Point pp(p(0)+eps, p(1)); 00270 const Point pm(p(0)-eps, p(1)); 00271 00272 return (FE<2,HIERARCHIC>::shape(elem, order, i, pp) - 00273 FE<2,HIERARCHIC>::shape(elem, order, i, pm))/2./eps; 00274 } 00275 00276 // d()/deta 00277 case 1: 00278 { 00279 const Point pp(p(0), p(1)+eps); 00280 const Point pm(p(0), p(1)-eps); 00281 00282 return (FE<2,HIERARCHIC>::shape(elem, order, i, pp) - 00283 FE<2,HIERARCHIC>::shape(elem, order, i, pm))/2./eps; 00284 } 00285 00286 default: 00287 libmesh_error_msg("Invalid derivative index j = " << j); 00288 } 00289 } 00290 00291 case QUAD4: 00292 libmesh_assert_less (totalorder, 2); 00293 case QUAD8: 00294 case QUAD9: 00295 { 00296 // Compute quad shape functions as a tensor-product 00297 const Real xi = p(0); 00298 const Real eta = p(1); 00299 00300 libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)); 00301 00302 // Example i, i0, i1 values for totalorder = 5: 00303 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 00304 // static const unsigned int i0[] = {0, 1, 1, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5}; 00305 // static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 0, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}; 00306 00307 unsigned int i0, i1; 00308 00309 // Vertex DoFs 00310 if (i == 0) 00311 { i0 = 0; i1 = 0; } 00312 else if (i == 1) 00313 { i0 = 1; i1 = 0; } 00314 else if (i == 2) 00315 { i0 = 1; i1 = 1; } 00316 else if (i == 3) 00317 { i0 = 0; i1 = 1; } 00318 // Edge DoFs 00319 else if (i < totalorder + 3u) 00320 { i0 = i - 2; i1 = 0; } 00321 else if (i < 2u*totalorder + 2) 00322 { i0 = 1; i1 = i - totalorder - 1; } 00323 else if (i < 3u*totalorder + 1u) 00324 { i0 = i - 2u*totalorder; i1 = 1; } 00325 else if (i < 4u*totalorder) 00326 { i0 = 0; i1 = i - 3u*totalorder + 1; } 00327 // Interior DoFs 00328 else 00329 { 00330 unsigned int basisnum = i - 4*totalorder; 00331 i0 = square_number_column[basisnum] + 2; 00332 i1 = square_number_row[basisnum] + 2; 00333 } 00334 00335 // Flip odd degree of freedom values if necessary 00336 // to keep continuity on sides 00337 Real f = 1.; 00338 00339 if ((i0%2) && (i0 > 2) && (i1 == 0)) 00340 f = (elem->point(0) > elem->point(1))?-1.:1.; 00341 else if ((i0%2) && (i0>2) && (i1 == 1)) 00342 f = (elem->point(3) > elem->point(2))?-1.:1.; 00343 else if ((i0 == 0) && (i1%2) && (i1>2)) 00344 f = (elem->point(0) > elem->point(3))?-1.:1.; 00345 else if ((i0 == 1) && (i1%2) && (i1>2)) 00346 f = (elem->point(1) > elem->point(2))?-1.:1.; 00347 00348 switch (j) 00349 { 00350 // d()/dxi 00351 case 0: 00352 return f*(FE<1,HIERARCHIC>::shape_deriv(EDGE3, totalorder, i0, 0, xi)* 00353 FE<1,HIERARCHIC>::shape (EDGE3, totalorder, i1, eta)); 00354 00355 // d()/deta 00356 case 1: 00357 return f*(FE<1,HIERARCHIC>::shape (EDGE3, totalorder, i0, xi)* 00358 FE<1,HIERARCHIC>::shape_deriv(EDGE3, totalorder, i1, 0, eta)); 00359 00360 default: 00361 libmesh_error_msg("Invalid derivative index j = " << j); 00362 } 00363 } 00364 00365 default: 00366 libmesh_error_msg("ERROR: Unsupported element type = " << type); 00367 } 00368 00369 return 0.; 00370 } 00371 00372 00373 00374 template <> 00375 Real FE<2,HIERARCHIC>::shape_second_deriv(const ElemType, 00376 const Order, 00377 const unsigned int, 00378 const unsigned int, 00379 const Point&) 00380 { 00381 libmesh_error_msg("Hierarchic polynomials require the element type \nbecause edge orientation is needed."); 00382 return 0.; 00383 } 00384 00385 00386 00387 template <> 00388 Real FE<2,HIERARCHIC>::shape_second_deriv(const Elem* elem, 00389 const Order order, 00390 const unsigned int i, 00391 const unsigned int j, 00392 const Point& p) 00393 { 00394 libmesh_assert(elem); 00395 00396 // I have been lazy here and am using finite differences 00397 // to compute the derivatives! 00398 const Real eps = 1.e-6; 00399 Point pp, pm; 00400 unsigned int prevj = libMesh::invalid_uint; 00401 00402 switch (j) 00403 { 00404 // d^2()/dxi^2 00405 case 0: 00406 { 00407 pp = Point(p(0)+eps, p(1)); 00408 pm = Point(p(0)-eps, p(1)); 00409 prevj = 0; 00410 break; 00411 } 00412 00413 // d^2()/dxideta 00414 case 1: 00415 { 00416 pp = Point(p(0), p(1)+eps); 00417 pm = Point(p(0), p(1)-eps); 00418 prevj = 0; 00419 break; 00420 } 00421 00422 // d^2()/deta^2 00423 case 2: 00424 { 00425 pp = Point(p(0), p(1)+eps); 00426 pm = Point(p(0), p(1)-eps); 00427 prevj = 1; 00428 break; 00429 } 00430 default: 00431 libmesh_error_msg("Invalid derivative index j = " << j); 00432 } 00433 00434 return (FE<2,HIERARCHIC>::shape_deriv(elem, order, i, prevj, pp) - 00435 FE<2,HIERARCHIC>::shape_deriv(elem, order, i, prevj, pm) 00436 )/2./eps; 00437 } 00438 00439 } // namespace libMesh