$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++ inlcludes 00020 00021 // Local includes 00022 #include "libmesh/fe.h" 00023 #include "libmesh/elem.h" 00024 00025 namespace libMesh 00026 { 00027 00028 template <> 00029 RealGradient FE<2,NEDELEC_ONE>::shape(const ElemType, 00030 const Order, 00031 const unsigned int, 00032 const Point&) 00033 { 00034 libmesh_error_msg("Nedelec elements require the element type \nbecause edge orientation is needed."); 00035 return RealGradient(); 00036 } 00037 00038 00039 // An excellent discussion of Nedelec shape functions is given in 00040 // http://www.dealii.org/developer/reports/nedelec/nedelec.pdf 00041 template <> 00042 RealGradient FE<2,NEDELEC_ONE>::shape(const Elem* elem, 00043 const Order order, 00044 const unsigned int i, 00045 const Point& p) 00046 { 00047 #if LIBMESH_DIM > 1 00048 libmesh_assert(elem); 00049 00050 const Order total_order = static_cast<Order>(order + elem->p_level()); 00051 00052 switch (total_order) 00053 { 00054 case FIRST: 00055 { 00056 switch (elem->type()) 00057 { 00058 case QUAD8: 00059 case QUAD9: 00060 { 00061 libmesh_assert_less (i, 4); 00062 00063 const Real xi = p(0); 00064 const Real eta = p(1); 00065 00066 // Even with a loose inverse_map tolerance we ought to 00067 // be nearly on the element interior in master 00068 // coordinates 00069 libmesh_assert_less_equal ( std::fabs(xi), 1.0+10*TOLERANCE ); 00070 libmesh_assert_less_equal ( std::fabs(eta), 1.0+10*TOLERANCE ); 00071 00072 switch(i) 00073 { 00074 case 0: 00075 { 00076 if( elem->point(0) > elem->point(1) ) 00077 return RealGradient( -0.25*(1.0-eta), 0.0 ); 00078 else 00079 return RealGradient( 0.25*(1.0-eta), 0.0 ); 00080 } 00081 case 1: 00082 { 00083 if( elem->point(1) > elem->point(2) ) 00084 return RealGradient( 0.0, -0.25*(1.0+xi) ); 00085 else 00086 return RealGradient( 0.0, 0.25*(1.0+xi) ); 00087 } 00088 00089 case 2: 00090 { 00091 if( elem->point(2) > elem->point(3) ) 00092 return RealGradient( 0.25*(1.0+eta), 0.0 ); 00093 else 00094 return RealGradient( -0.25*(1.0+eta), 0.0 ); 00095 } 00096 case 3: 00097 { 00098 if( elem->point(3) > elem->point(0) ) 00099 return RealGradient( 0.0, -0.25*(xi-1.0) ); 00100 else 00101 return RealGradient( 0.0, 0.25*(xi-1.0) ); 00102 } 00103 00104 default: 00105 libmesh_error_msg("Invalid i = " << i); 00106 } 00107 00108 return RealGradient(); 00109 } 00110 00111 case TRI6: 00112 { 00113 const Real xi = p(0); 00114 const Real eta = p(1); 00115 00116 libmesh_assert_less (i, 3); 00117 00118 switch(i) 00119 { 00120 case 0: 00121 { 00122 if( elem->point(0) > elem->point(1) ) 00123 return RealGradient( -1.0+eta, -xi ); 00124 else 00125 return RealGradient( 1.0-eta, xi ); 00126 } 00127 case 1: 00128 { 00129 if( elem->point(1) > elem->point(2) ) 00130 return RealGradient( eta, -xi ); 00131 else 00132 return RealGradient( -eta, xi ); 00133 } 00134 00135 case 2: 00136 { 00137 if( elem->point(2) > elem->point(0) ) 00138 return RealGradient( eta, -xi+1.0 ); 00139 else 00140 return RealGradient( -eta, xi-1.0 ); 00141 } 00142 00143 default: 00144 libmesh_error_msg("Invalid i = " << i); 00145 } 00146 } 00147 00148 default: 00149 libmesh_error_msg("ERROR: Unsupported 2D element type!: " << elem->type()); 00150 } 00151 } 00152 00153 // unsupported order 00154 default: 00155 libmesh_error_msg("ERROR: Unsupported 2D FE order!: " << total_order); 00156 } 00157 #endif // LIBMESH_DIM > 1 00158 00159 libmesh_error_msg("We'll never get here!"); 00160 return RealGradient(); 00161 } 00162 00163 00164 00165 template <> 00166 RealGradient FE<2,NEDELEC_ONE>::shape_deriv(const ElemType, 00167 const Order, 00168 const unsigned int, 00169 const unsigned int, 00170 const Point&) 00171 { 00172 libmesh_error_msg("Nedelec elements require the element type \nbecause edge orientation is needed."); 00173 return RealGradient(); 00174 } 00175 00176 00177 00178 template <> 00179 RealGradient FE<2,NEDELEC_ONE>::shape_deriv(const Elem* elem, 00180 const Order order, 00181 const unsigned int i, 00182 const unsigned int j, 00183 const Point&) 00184 { 00185 #if LIBMESH_DIM > 1 00186 libmesh_assert(elem); 00187 libmesh_assert_less (j, 2); 00188 00189 const Order total_order = static_cast<Order>(order + elem->p_level()); 00190 00191 switch (total_order) 00192 { 00193 // linear Lagrange shape functions 00194 case FIRST: 00195 { 00196 switch (elem->type()) 00197 { 00198 case QUAD8: 00199 case QUAD9: 00200 { 00201 libmesh_assert_less (i, 4); 00202 00203 switch (j) 00204 { 00205 // d()/dxi 00206 case 0: 00207 { 00208 switch(i) 00209 { 00210 case 0: 00211 case 2: 00212 return RealGradient(); 00213 case 1: 00214 { 00215 if( elem->point(1) > elem->point(2) ) 00216 return RealGradient( 0.0, -0.25 ); 00217 else 00218 return RealGradient( 0.0, 0.25 ); 00219 } 00220 case 3: 00221 { 00222 if( elem->point(3) > elem->point(0) ) 00223 return RealGradient( 0.0, -0.25 ); 00224 else 00225 return RealGradient( 0.0, 0.25 ); 00226 } 00227 default: 00228 libmesh_error_msg("Invalid i = " << i); 00229 } 00230 } // j=0 00231 00232 // d()/deta 00233 case 1: 00234 { 00235 switch(i) 00236 { 00237 case 1: 00238 case 3: 00239 return RealGradient(); 00240 case 0: 00241 { 00242 if( elem->point(0) > elem->point(1) ) 00243 return RealGradient( 0.25 ); 00244 else 00245 return RealGradient( -0.25 ); 00246 } 00247 case 2: 00248 { 00249 if( elem->point(2) > elem->point(3) ) 00250 return RealGradient( 0.25 ); 00251 else 00252 return RealGradient( -0.25 ); 00253 } 00254 default: 00255 libmesh_error_msg("Invalid i = " << i); 00256 } 00257 } // j=1 00258 00259 default: 00260 libmesh_error_msg("Invalid j = " << j); 00261 } 00262 00263 return RealGradient(); 00264 } 00265 00266 case TRI6: 00267 { 00268 libmesh_assert_less (i, 3); 00269 00270 // Account for edge flipping 00271 Real f = 1.0; 00272 00273 switch(i) 00274 { 00275 case 0: 00276 { 00277 if( elem->point(0) > elem->point(1) ) 00278 f = -1.0; 00279 break; 00280 } 00281 case 1: 00282 { 00283 if( elem->point(1) > elem->point(2) ) 00284 f = -1.0; 00285 break; 00286 } 00287 case 2: 00288 { 00289 if( elem->point(2) > elem->point(0) ) 00290 f = -1.0; 00291 break; 00292 } 00293 default: 00294 libmesh_error_msg("Invalid i = " << i); 00295 } 00296 00297 switch (j) 00298 { 00299 // d()/dxi 00300 case 0: 00301 { 00302 return RealGradient( 0.0, f*1.0); 00303 } 00304 // d()/deta 00305 case 1: 00306 { 00307 return RealGradient( f*(-1.0) ); 00308 } 00309 default: 00310 libmesh_error_msg("Invalid j = " << j); 00311 } 00312 } 00313 00314 default: 00315 libmesh_error_msg("ERROR: Unsupported 2D element type!: " << elem->type()); 00316 } 00317 } 00318 // unsupported order 00319 default: 00320 libmesh_error_msg("ERROR: Unsupported 2D FE order!: " << total_order); 00321 } 00322 #endif // LIBMESH_DIM > 1 00323 00324 libmesh_error_msg("We'll never get here!"); 00325 return RealGradient(); 00326 } 00327 00328 00329 00330 00331 template <> 00332 RealGradient FE<2,NEDELEC_ONE>::shape_second_deriv(const ElemType, 00333 const Order, 00334 const unsigned int, 00335 const unsigned int, 00336 const Point&) 00337 { 00338 libmesh_error_msg("Nedelec elements require the element type \nbecause edge orientation is needed."); 00339 return RealGradient(); 00340 } 00341 00342 00343 00344 template <> 00345 RealGradient FE<2,NEDELEC_ONE>::shape_second_deriv(const Elem* elem, 00346 const Order order, 00347 const unsigned int libmesh_dbg_var(i), 00348 const unsigned int libmesh_dbg_var(j), 00349 const Point&) 00350 { 00351 #if LIBMESH_DIM > 1 00352 libmesh_assert(elem); 00353 00354 // j = 0 ==> d^2 phi / dxi^2 00355 // j = 1 ==> d^2 phi / dxi deta 00356 // j = 2 ==> d^2 phi / deta^2 00357 libmesh_assert_less (j, 3); 00358 00359 const Order total_order = static_cast<Order>(order + elem->p_level()); 00360 00361 switch (total_order) 00362 { 00363 // linear Lagrange shape functions 00364 case FIRST: 00365 { 00366 switch (elem->type()) 00367 { 00368 case QUAD8: 00369 case QUAD9: 00370 { 00371 libmesh_assert_less (i, 4); 00372 // All second derivatives for linear quads are zero. 00373 return RealGradient(); 00374 } 00375 00376 case TRI6: 00377 { 00378 libmesh_assert_less (i, 3); 00379 // All second derivatives for linear triangles are zero. 00380 return RealGradient(); 00381 } 00382 00383 default: 00384 libmesh_error_msg("ERROR: Unsupported 2D element type!: " << elem->type()); 00385 00386 } // end switch (type) 00387 } // end case FIRST 00388 00389 // unsupported order 00390 default: 00391 libmesh_error_msg("ERROR: Unsupported 2D FE order!: " << total_order); 00392 00393 } // end switch (order) 00394 00395 #endif // LIBMESH_DIM > 1 00396 00397 libmesh_error_msg("We'll never get here!"); 00398 return RealGradient(); 00399 } 00400 00401 } // namespace libMesh