$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,L2_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,L2_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,L2_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,L2_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,L2_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,L2_HIERARCHIC>::shape(EDGE3, totalorder, i0, xi)* 00214 FE<1,L2_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,L2_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,L2_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,L2_HIERARCHIC>::shape(elem, order, i, pp) - 00273 FE<2,L2_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,L2_HIERARCHIC>::shape(elem, order, i, pp) - 00283 FE<2,L2_HIERARCHIC>::shape(elem, order, i, pm))/2./eps; 00284 } 00285 00286 00287 default: 00288 libmesh_error_msg("Invalid derivative index j = " << j); 00289 } 00290 } 00291 00292 case QUAD4: 00293 libmesh_assert_less (totalorder, 2); 00294 case QUAD8: 00295 case QUAD9: 00296 { 00297 // Compute quad shape functions as a tensor-product 00298 const Real xi = p(0); 00299 const Real eta = p(1); 00300 00301 libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)); 00302 00303 // Example i, i0, i1 values for totalorder = 5: 00304 // 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 00305 // 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}; 00306 // 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}; 00307 00308 unsigned int i0, i1; 00309 00310 // Vertex DoFs 00311 if (i == 0) 00312 { i0 = 0; i1 = 0; } 00313 else if (i == 1) 00314 { i0 = 1; i1 = 0; } 00315 else if (i == 2) 00316 { i0 = 1; i1 = 1; } 00317 else if (i == 3) 00318 { i0 = 0; i1 = 1; } 00319 // Edge DoFs 00320 else if (i < totalorder + 3u) 00321 { i0 = i - 2; i1 = 0; } 00322 else if (i < 2u*totalorder + 2) 00323 { i0 = 1; i1 = i - totalorder - 1; } 00324 else if (i < 3u*totalorder + 1u) 00325 { i0 = i - 2u*totalorder; i1 = 1; } 00326 else if (i < 4u*totalorder) 00327 { i0 = 0; i1 = i - 3u*totalorder + 1; } 00328 // Interior DoFs 00329 else 00330 { 00331 unsigned int basisnum = i - 4*totalorder; 00332 i0 = square_number_column[basisnum] + 2; 00333 i1 = square_number_row[basisnum] + 2; 00334 } 00335 00336 // Flip odd degree of freedom values if necessary 00337 // to keep continuity on sides 00338 Real f = 1.; 00339 00340 if ((i0%2) && (i0 > 2) && (i1 == 0)) 00341 f = (elem->point(0) > elem->point(1))?-1.:1.; 00342 else if ((i0%2) && (i0>2) && (i1 == 1)) 00343 f = (elem->point(3) > elem->point(2))?-1.:1.; 00344 else if ((i0 == 0) && (i1%2) && (i1>2)) 00345 f = (elem->point(0) > elem->point(3))?-1.:1.; 00346 else if ((i0 == 1) && (i1%2) && (i1>2)) 00347 f = (elem->point(1) > elem->point(2))?-1.:1.; 00348 00349 switch (j) 00350 { 00351 // d()/dxi 00352 case 0: 00353 return f*(FE<1,L2_HIERARCHIC>::shape_deriv(EDGE3, totalorder, i0, 0, xi)* 00354 FE<1,L2_HIERARCHIC>::shape (EDGE3, totalorder, i1, eta)); 00355 00356 // d()/deta 00357 case 1: 00358 return f*(FE<1,L2_HIERARCHIC>::shape (EDGE3, totalorder, i0, xi)* 00359 FE<1,L2_HIERARCHIC>::shape_deriv(EDGE3, totalorder, i1, 0, eta)); 00360 00361 default: 00362 libmesh_error_msg("Invalid derivative index j = " << j); 00363 } 00364 } 00365 00366 default: 00367 libmesh_error_msg("ERROR: Unsupported element type = " << type); 00368 } 00369 00370 return 0.; 00371 } 00372 00373 00374 00375 template <> 00376 Real FE<2,L2_HIERARCHIC>::shape_second_deriv(const ElemType, 00377 const Order, 00378 const unsigned int, 00379 const unsigned int, 00380 const Point&) 00381 { 00382 libmesh_error_msg("Hierarchic polynomials require the element type \nbecause edge orientation is needed."); 00383 return 0.; 00384 } 00385 00386 00387 00388 template <> 00389 Real FE<2,L2_HIERARCHIC>::shape_second_deriv(const Elem* elem, 00390 const Order order, 00391 const unsigned int i, 00392 const unsigned int j, 00393 const Point& p) 00394 { 00395 libmesh_assert(elem); 00396 00397 // I have been lazy here and am using finite differences 00398 // to compute the derivatives! 00399 const Real eps = 1.e-6; 00400 Point pp, pm; 00401 unsigned int prevj = libMesh::invalid_uint; 00402 00403 switch (j) 00404 { 00405 // d^2()/dxi^2 00406 case 0: 00407 { 00408 pp = Point(p(0)+eps, p(1)); 00409 pm = Point(p(0)-eps, p(1)); 00410 prevj = 0; 00411 break; 00412 } 00413 00414 // d^2()/dxideta 00415 case 1: 00416 { 00417 pp = Point(p(0), p(1)+eps); 00418 pm = Point(p(0), p(1)-eps); 00419 prevj = 0; 00420 break; 00421 } 00422 00423 // d^2()/deta^2 00424 case 2: 00425 { 00426 pp = Point(p(0), p(1)+eps); 00427 pm = Point(p(0), p(1)-eps); 00428 prevj = 1; 00429 break; 00430 } 00431 default: 00432 libmesh_error_msg("Invalid derivative index j = " << j); 00433 } 00434 return (FE<2,L2_HIERARCHIC>::shape_deriv(elem, order, i, prevj, pp) - 00435 FE<2,L2_HIERARCHIC>::shape_deriv(elem, order, i, prevj, pm) 00436 )/2./eps; 00437 } 00438 00439 } // namespace libMesh