$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 // Local includes 00020 #include "libmesh/fe.h" 00021 #include "libmesh/libmesh_logging.h" 00022 #include "libmesh/fe_type.h" 00023 #include "libmesh/quadrature.h" 00024 #include "libmesh/face_tri3_subdivision.h" 00025 #include "libmesh/fe_macro.h" 00026 #include "libmesh/dense_matrix.h" 00027 #include "libmesh/utility.h" 00028 00029 00030 namespace libMesh 00031 { 00032 00033 FESubdivision::FESubdivision(const FEType& fet) : 00034 FE<2,SUBDIVISION>(fet) 00035 { 00036 // Only 2D meshes in 3D space are supported 00037 libmesh_assert_equal_to(LIBMESH_DIM, 3); 00038 } 00039 00040 00041 00042 void FESubdivision::init_subdivision_matrix(DenseMatrix<Real> &A, 00043 unsigned int valence) 00044 { 00045 A.resize(valence + 12, valence + 12); 00046 00047 // A = (S11 0; S21 S22), see Cirak et al., 00048 // Int. J. Numer. Meth. Engng. 2000; 47:2039-2072, Appendix A.2. 00049 00050 // First, set the static S21 part 00051 A(valence+ 1,0 ) = 0.125; 00052 A(valence+ 1,1 ) = 0.375; 00053 A(valence+ 1,valence ) = 0.375; 00054 A(valence+ 2,0 ) = 0.0625; 00055 A(valence+ 2,1 ) = 0.625; 00056 A(valence+ 2,2 ) = 0.0625; 00057 A(valence+ 2,valence ) = 0.0625; 00058 A(valence+ 3,0 ) = 0.125; 00059 A(valence+ 3,1 ) = 0.375; 00060 A(valence+ 3,2 ) = 0.375; 00061 A(valence+ 4,0 ) = 0.0625; 00062 A(valence+ 4,1 ) = 0.0625; 00063 A(valence+ 4,valence-1) = 0.0625; 00064 A(valence+ 4,valence ) = 0.625; 00065 A(valence+ 5,0 ) = 0.125; 00066 A(valence+ 5,valence-1) = 0.375; 00067 A(valence+ 5,valence ) = 0.375; 00068 A(valence+ 6,1 ) = 0.375; 00069 A(valence+ 6,valence ) = 0.125; 00070 A(valence+ 7,1 ) = 0.375; 00071 A(valence+ 8,1 ) = 0.375; 00072 A(valence+ 8,2 ) = 0.125; 00073 A(valence+ 9,1 ) = 0.125; 00074 A(valence+ 9,valence ) = 0.375; 00075 A(valence+10,valence ) = 0.375; 00076 A(valence+11,valence-1) = 0.125; 00077 A(valence+11,valence ) = 0.375; 00078 00079 // Next, set the static S22 part 00080 A(valence+ 1,valence+1) = 0.125; 00081 A(valence+ 2,valence+1) = 0.0625; 00082 A(valence+ 2,valence+2) = 0.0625; 00083 A(valence+ 2,valence+3) = 0.0625; 00084 A(valence+ 3,valence+3) = 0.125; 00085 A(valence+ 4,valence+1) = 0.0625; 00086 A(valence+ 4,valence+4) = 0.0625; 00087 A(valence+ 4,valence+5) = 0.0625; 00088 A(valence+ 5,valence+5) = 0.125; 00089 A(valence+ 6,valence+1) = 0.375; 00090 A(valence+ 6,valence+2) = 0.125; 00091 A(valence+ 7,valence+1) = 0.125; 00092 A(valence+ 7,valence+2) = 0.375; 00093 A(valence+ 7,valence+3) = 0.125; 00094 A(valence+ 8,valence+2) = 0.125; 00095 A(valence+ 8,valence+3) = 0.375; 00096 A(valence+ 9,valence+1) = 0.375; 00097 A(valence+ 9,valence+4) = 0.125; 00098 A(valence+10,valence+1) = 0.125; 00099 A(valence+10,valence+4) = 0.375; 00100 A(valence+10,valence+5) = 0.125; 00101 A(valence+11,valence+4) = 0.125; 00102 A(valence+11,valence+5) = 0.375; 00103 00104 // Last, set the S11 part: first row 00105 std::vector<Real> weights; 00106 loop_subdivision_mask(weights, valence); 00107 for (unsigned int i = 0; i <= valence; ++i) 00108 A(0,i) = weights[i]; 00109 00110 // second row 00111 A(1,0) = 0.375; 00112 A(1,1) = 0.375; 00113 A(1,2) = 0.125; 00114 A(1,valence) = 0.125; 00115 00116 // third to second-to-last rows 00117 for (unsigned int i = 2; i < valence; ++i) 00118 { 00119 A(i,0 ) = 0.375; 00120 A(i,i-1) = 0.125; 00121 A(i,i ) = 0.375; 00122 A(i,i+1) = 0.125; 00123 } 00124 00125 // last row 00126 A(valence,0) = 0.375; 00127 A(valence,1) = 0.125; 00128 A(valence,valence-1) = 0.125; 00129 A(valence,valence ) = 0.375; 00130 } 00131 00132 00133 00134 Real FESubdivision::regular_shape(const unsigned int i, 00135 const Real v, 00136 const Real w) 00137 { 00138 // These are the 12 quartic box splines, see Cirak et al., 00139 // Int. J. Numer. Meth. Engng. 2000; 47:2039-2072, Appendix A.1. 00140 00141 const Real u = 1 - v - w; 00142 libmesh_assert_less_equal(0, v); 00143 libmesh_assert_less_equal(0, w); 00144 libmesh_assert_less_equal(0, u); 00145 00146 using Utility::pow; 00147 const Real factor = 1. / 12; 00148 00149 switch (i) 00150 { 00151 case 0: 00152 return factor*(pow<4>(u) + 2*u*u*u*v); 00153 case 1: 00154 return factor*(pow<4>(u) + 2*u*u*u*w); 00155 case 2: 00156 return factor*(pow<4>(u) + 2*u*u*u*w + 6*u*u*u*v + 6*u*u*v*w + 12*u*u*v*v + 6*u*v*v*w + 6*u*v*v*v + 00157 2*v*v*v*w + pow<4>(v)); 00158 case 3: 00159 return factor*(6*pow<4>(u) + 24*u*u*u*w + 24*u*u*w*w + 8*u*w*w*w + pow<4>(w) + 24*u*u*u*v + 00160 60*u*u*v*w + 36*u*v*w*w + 6*v*w*w*w + 24*u*u*v*v + 36*u*v*v*w + 12*v*v*w*w + 8*u*v*v*v + 00161 6*v*v*v*w + pow<4>(v)); 00162 case 4: 00163 return factor*(pow<4>(u) + 6*u*u*u*w + 12*u*u*w*w + 6*u*w*w*w + pow<4>(w) + 2*u*u*u*v + 6*u*u*v*w + 00164 6*u*v*w*w + 2*v*w*w*w); 00165 case 5: 00166 return factor*(2*u*v*v*v + pow<4>(v)); 00167 case 6: 00168 return factor*(pow<4>(u) + 6*u*u*u*w + 12*u*u*w*w + 6*u*w*w*w + pow<4>(w) + 8*u*u*u*v + 36*u*u*v*w + 00169 36*u*v*w*w + 8*v*w*w*w + 24*u*u*v*v + 60*u*v*v*w + 24*v*v*w*w + 24*u*v*v*v + 24*v*v*v*w + 6*pow<4>(v)); 00170 case 7: 00171 return factor*(pow<4>(u) + 8*u*u*u*w + 24*u*u*w*w + 24*u*w*w*w + 6*pow<4>(w) + 6*u*u*u*v + 36*u*u*v*w + 00172 60*u*v*w*w + 24*v*w*w*w + 12*u*u*v*v + 36*u*v*v*w + 24*v*v*w*w + 6*u*v*v*v + 8*v*v*v*w + pow<4>(v)); 00173 case 8: 00174 return factor*(2*u*w*w*w + pow<4>(w)); 00175 case 9: 00176 return factor*(2*v*v*v*w + pow<4>(v)); 00177 case 10: 00178 return factor*(2*u*w*w*w + pow<4>(w) + 6*u*v*w*w + 6*v*w*w*w + 6*u*v*v*w + 12*v*v*w*w + 2*u*v*v*v + 00179 6*v*v*v*w + pow<4>(v)); 00180 case 11: 00181 return factor*(pow<4>(w) + 2*v*w*w*w); 00182 00183 default: 00184 libmesh_error_msg("Invalid i = " << i); 00185 } 00186 00187 libmesh_error_msg("We'll never get here!"); 00188 return 0.; 00189 } 00190 00191 00192 00193 Real FESubdivision::regular_shape_deriv(const unsigned int i, 00194 const unsigned int j, 00195 const Real v, 00196 const Real w) 00197 { 00198 const Real u = 1 - v - w; 00199 const Real factor = 1. / 12; 00200 00201 switch (j) // j=0: xi-directional derivative, j=1: eta-directional derivative 00202 { 00203 case 0: // xi derivatives 00204 { 00205 switch (i) // shape function number 00206 { 00207 case 0: 00208 return factor*(-6*v*u*u - 2*u*u*u); 00209 case 1: 00210 return factor*(-4*u*u*u - 6*u*u*w); 00211 case 2: 00212 return factor*(-2*v*v*v - 6*v*v*u + 6*v*u*u + 2*u*u*u); 00213 case 3: 00214 return factor*(-4*v*v*v - 24*v*v*u - 24*v*u*u - 18*v*v*w - 48*v*u*w - 12*u*u*w - 00215 12*v*w*w - 12*u*w*w - 2*w*w*w); 00216 case 4: 00217 return factor*(-6*v*u*u - 2*u*u*u - 12*v*u*w-12*u*u*w - 6*v*w*w - 18*u*w*w - 4*w*w*w); 00218 case 5: 00219 return factor*(2*v*v*v + 6*v*v*u); 00220 case 6: 00221 return factor*(24*v*v*u + 24*v*u*u + 4*u*u*u + 12*v*v*w + 48*v*u*w + 18*u*u*w + 00222 12*v*w*w + 12*u*w*w + 2*w*w*w); 00223 case 7: 00224 return factor*(-2*v*v*v - 6*v*v*u + 6*v*u*u + 2*u*u*u - 12*v*v*w + 12*u*u*w - 00225 12*v*w*w + 12*u*w*w); 00226 case 8: 00227 return -w*w*w/6; 00228 case 9: 00229 return factor*(4*v*v*v + 6*v*v*w); 00230 case 10: 00231 return factor*(2*v*v*v + 6*v*v*u + 12*v*v*w + 12*v*u*w + 18*v*w*w + 6*u*w*w + 4*w*w*w); 00232 case 11: 00233 return w*w*w/6; 00234 default: 00235 libmesh_error_msg("Invalid i = " << i); 00236 } 00237 } 00238 case 1: // eta derivatives 00239 { 00240 switch (i) // shape function number 00241 { 00242 case 0: 00243 return factor*(-6*v*u*u - 4*u*u*u); 00244 case 1: 00245 return factor*(-2*u*u*u - 6*u*u*w); 00246 case 2: 00247 return factor*(-4*v*v*v - 18*v*v*u - 12*v*u*u - 2*u*u*u - 6*v*v*w - 12*v*u*w - 00248 6*u*u*w); 00249 case 3: 00250 return factor*(-2*v*v*v-12*v*v*u - 12*v*u*u - 12*v*v*w - 48*v*u*w - 24*u*u*w - 00251 18*v*w*w - 24*u*w*w - 4*w*w*w); 00252 case 4: 00253 return factor*(2*u*u*u + 6*u*u*w - 6*u*w*w - 2*w*w*w); 00254 case 5: 00255 return -v*v*v/6; 00256 case 6: 00257 return factor*(12*v*v*u + 12*v*u*u + 2*u*u*u - 12*v*v*w + 6*u*u*w - 12*v*w*w - 00258 6*u*w*w - 2*w*w*w); 00259 case 7: 00260 return factor*(2*v*v*v + 12*v*v*u + 18*v*u*u + 4*u*u*u + 12*v*v*w + 48*v*u*w + 00261 24*u*u*w + 12*v*w*w + 24*u*w*w); 00262 case 8: 00263 return factor*(6*u*w*w + 2*w*w*w); 00264 case 9: 00265 return v*v*v/6; 00266 case 10: 00267 return factor*(4*v*v*v + 6*v*v*u + 18*v*v*w + 12*v*u*w + 12*v*w*w + 6*u*w*w + 00268 2*w*w*w); 00269 case 11: 00270 return factor*(6*v*w*w + 4*w*w*w); 00271 default: 00272 libmesh_error_msg("Invalid i = " << i); 00273 } 00274 } 00275 default: 00276 libmesh_error_msg("Invalid j = " << j); 00277 } 00278 00279 libmesh_error_msg("We'll never get here!"); 00280 return 0.; 00281 } 00282 00283 00284 00285 Real FESubdivision::regular_shape_second_deriv(const unsigned int i, 00286 const unsigned int j, 00287 const Real v, 00288 const Real w) 00289 { 00290 const Real u = 1 - v - w; 00291 const Real factor = 1. / 12; 00292 00293 switch (j) 00294 { 00295 case 0: // xi-xi derivative 00296 { 00297 switch (i) // shape function number 00298 { 00299 case 0: 00300 return v*u; 00301 case 1: 00302 return u*u + u*w; 00303 case 2: 00304 return -2*v*u; 00305 case 3: 00306 return v*v - 2*u*u + v*w - 2*u*w; 00307 case 4: 00308 return v*u + v*w + u*w + w*w; 00309 case 5: 00310 return v*u; 00311 case 6: 00312 return factor*(-24*v*v + 12*u*u - 24*v*w + 12*u*w); 00313 case 7: 00314 return -2*v*u - 2*v*w - 2*u*w - 2*w*w; 00315 case 8: 00316 return 0.; 00317 case 9: 00318 return v*v + v*w; 00319 case 10: 00320 return v*u + v*w + u*w + w*w; 00321 case 11: 00322 return 0.; 00323 default: 00324 libmesh_error_msg("Invalid i = " << i); 00325 } 00326 } 00327 case 1: //eta-xi derivative 00328 { 00329 switch (i) 00330 { 00331 case 0: 00332 return factor*(12*v*u + 6*u*u); 00333 case 1: 00334 return factor*(6*u*u + 12*u*w); 00335 case 2: 00336 return factor*(6*v*v - 12*v*u - 6*u*u); 00337 case 3: 00338 return factor*(6*v*v - 12*u*u + 24*v*w + 6*w*w); 00339 case 4: 00340 return factor*(-6*u*u - 12*u*w + 6*w*w); 00341 case 5: 00342 return -v*v/2.; 00343 case 6: 00344 return factor*(-12*v*v + 6*u*u - 24*v*w - 12*u*w - 6*w*w); 00345 case 7: 00346 return factor*(-6*v*v - 12*v*u + 6*u*u - 24*v*w - 12*w*w); 00347 case 8: 00348 return -w*w/2.; 00349 case 9: 00350 return v*v/2.; 00351 case 10: 00352 return factor*(6*v*v + 12*v*u + 24*v*w + 12*u*w + 6*w*w); 00353 case 11: 00354 return w*w/2.; 00355 default: 00356 libmesh_error_msg("Invalid i = " << i); 00357 } 00358 } 00359 case 2: // eta-eta derivative 00360 { 00361 switch (i) 00362 { 00363 case 0: 00364 return v*u + u*u; 00365 case 1: 00366 return u*w; 00367 case 2: 00368 return v*v + v*u + v*w + u*w; 00369 case 3: 00370 return -2*v*u - 2*u*u + v*w + w*w; 00371 case 4: 00372 return -2*u*w; 00373 case 5: 00374 return 0.; 00375 case 6: 00376 return -2*v*v - 2*v*u - 2*v*w - 2*u*w; 00377 case 7: 00378 return v*u + u*u - 2*v*w - 2*w*w; 00379 case 8: 00380 return u*w; 00381 case 9: 00382 return 0.; 00383 case 10: 00384 return v*v + v*u + v*w + u*w; 00385 case 11: 00386 return v*w + w*w; 00387 default: 00388 libmesh_error_msg("Invalid i = " << i); 00389 } 00390 } 00391 default: 00392 libmesh_error_msg("Invalid j = " << j); 00393 } 00394 00395 libmesh_error_msg("We'll never get here!"); 00396 return 0.; 00397 } 00398 00399 00400 00401 void FESubdivision::loop_subdivision_mask(std::vector<Real> & weights, 00402 const unsigned int valence) 00403 { 00404 libmesh_assert_greater(valence, 0); 00405 const Real cs = std::cos(2 * libMesh::pi / valence); 00406 const Real nb_weight = (0.625 - Utility::pow<2>(0.375 + 0.25 * cs)) / valence; 00407 weights.resize(1 + valence, nb_weight); 00408 weights[0] = 1.0 - valence * nb_weight; 00409 } 00410 00411 00412 00413 void FESubdivision::init_shape_functions(const std::vector<Point> &qp, 00414 const Elem *elem) 00415 { 00416 libmesh_assert(elem); 00417 libmesh_assert_equal_to(elem->type(), TRI3SUBDIVISION); 00418 const Tri3Subdivision* sd_elem = static_cast<const Tri3Subdivision*>(elem); 00419 00420 START_LOG("init_shape_functions()", "FESubdivision"); 00421 00422 calculations_started = true; 00423 00424 // If the user forgot to request anything, we'll be safe and calculate everything: 00425 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00426 if (!calculate_phi && !calculate_dphi && !calculate_d2phi) 00427 calculate_phi = calculate_dphi = calculate_d2phi = true; 00428 #else 00429 if (!calculate_phi && !calculate_dphi) 00430 calculate_phi = calculate_dphi = true; 00431 #endif 00432 00433 const unsigned int valence = sd_elem->get_ordered_valence(0); 00434 const unsigned int n_qp = cast_int<unsigned int>(qp.size()); 00435 const unsigned int n_approx_shape_functions = valence + 6; 00436 00437 // resize the vectors to hold current data 00438 phi.resize (n_approx_shape_functions); 00439 dphi.resize (n_approx_shape_functions); 00440 dphidxi.resize (n_approx_shape_functions); 00441 dphideta.resize (n_approx_shape_functions); 00442 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00443 d2phi.resize (n_approx_shape_functions); 00444 d2phidxi2.resize (n_approx_shape_functions); 00445 d2phidxideta.resize(n_approx_shape_functions); 00446 d2phideta2.resize (n_approx_shape_functions); 00447 #endif 00448 00449 for (unsigned int i = 0; i < n_approx_shape_functions; ++i) 00450 { 00451 phi[i].resize (n_qp); 00452 dphi[i].resize (n_qp); 00453 dphidxi[i].resize (n_qp); 00454 dphideta[i].resize (n_qp); 00455 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00456 d2phi[i].resize (n_qp); 00457 d2phidxi2[i].resize (n_qp); 00458 d2phidxideta[i].resize(n_qp); 00459 d2phideta2[i].resize (n_qp); 00460 #endif 00461 } 00462 00463 // Renumbering of the shape functions 00464 static const unsigned int cvi[12] = {3,6,2,0,1,4,7,10,9,5,11,8}; 00465 00466 if (valence == 6) // This means that all vertices are regular, i.e. we have 12 shape functions 00467 { 00468 for (unsigned int i = 0; i < n_approx_shape_functions; ++i) 00469 { 00470 for (unsigned int p = 0; p < n_qp; ++p) 00471 { 00472 phi[i][p] = FE<2,SUBDIVISION>::shape (elem, fe_type.order, cvi[i], qp[p]); 00473 dphidxi[i][p] = FE<2,SUBDIVISION>::shape_deriv (elem, fe_type.order, cvi[i], 0, qp[p]); 00474 dphideta[i][p] = FE<2,SUBDIVISION>::shape_deriv (elem, fe_type.order, cvi[i], 1, qp[p]); 00475 dphi[i][p](0) = dphidxi[i][p]; 00476 dphi[i][p](1) = dphideta[i][p]; 00477 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00478 d2phidxi2[i][p] = FE<2,SUBDIVISION>::shape_second_deriv(elem, fe_type.order, cvi[i], 0, qp[p]); 00479 d2phidxideta[i][p] = FE<2,SUBDIVISION>::shape_second_deriv(elem, fe_type.order, cvi[i], 1, qp[p]); 00480 d2phideta2[i][p] = FE<2,SUBDIVISION>::shape_second_deriv(elem, fe_type.order, cvi[i], 2, qp[p]); 00481 d2phi[i][p](0,0) = d2phidxi2[i][p]; 00482 d2phi[i][p](0,1) = d2phi[i][p](1,0) = d2phidxideta[i][p]; 00483 d2phi[i][p](1,1) = d2phideta2[i][p]; 00484 #endif 00485 } 00486 } 00487 } 00488 else // vertex 0 is irregular by construction of the mesh 00489 { 00490 static const Real eps = 1e-10; 00491 00492 // temporary values 00493 std::vector<Real> tphi(12); 00494 std::vector<Real> tdphidxi(12); 00495 std::vector<Real> tdphideta(12); 00496 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00497 std::vector<Real> td2phidxi2(12); 00498 std::vector<Real> td2phidxideta(12); 00499 std::vector<Real> td2phideta2(12); 00500 #endif 00501 00502 for (unsigned int p = 0; p < n_qp; ++p) 00503 { 00504 // evaluate the number of the required subdivisions 00505 Real v = qp[p](0); 00506 Real w = qp[p](1); 00507 Real u = 1 - v - w; 00508 Real min = 0, max = 0.5; 00509 int n = 0; 00510 while (!(u > min-eps && u < max+eps)) 00511 { 00512 ++n; 00513 min = max; 00514 max += std::pow((Real)(2), -n-1); 00515 } 00516 00517 // transform u, v and w according to the number of subdivisions required. 00518 const Real pow2 = std::pow((Real)(2), n); 00519 v *= pow2; 00520 w *= pow2; 00521 u = 1 - v - w; 00522 libmesh_assert_less(u, 0.5 + eps); 00523 libmesh_assert_greater(u, -eps); 00524 00525 // find out in which subdivided patch we are and setup the "selection matrix" P and the transformation Jacobian 00526 // (see Int. J. Numer. Meth. Engng. 2000; 47:2039-2072, Appendix A.2.) 00527 const int k = n+1; 00528 Real jfac; // the additional factor per derivative order 00529 DenseMatrix<Real> P(12, valence+12); 00530 if (v > 0.5 - eps) 00531 { 00532 v = 2*v - 1; 00533 w = 2*w; 00534 jfac = std::pow((Real)(2), k); 00535 P( 0,2 ) = 1; 00536 P( 1,0 ) = 1; 00537 P( 2,valence+3) = 1; 00538 P( 3,1 ) = 1; 00539 P( 4,valence ) = 1; 00540 P( 5,valence+8) = 1; 00541 P( 6,valence+2) = 1; 00542 P( 7,valence+1) = 1; 00543 P( 8,valence+4) = 1; 00544 P( 9,valence+7) = 1; 00545 P(10,valence+6) = 1; 00546 P(11,valence+9) = 1; 00547 } 00548 else if (w > 0.5 - eps) 00549 { 00550 v = 2*v; 00551 w = 2*w - 1; 00552 jfac = std::pow((Real)(2), k); 00553 P( 0,0 ) = 1; 00554 P( 1,valence- 1) = 1; 00555 P( 2,1 ) = 1; 00556 P( 3,valence ) = 1; 00557 P( 4,valence+ 5) = 1; 00558 P( 5,valence+ 2) = 1; 00559 P( 6,valence+ 1) = 1; 00560 P( 7,valence+ 4) = 1; 00561 P( 8,valence+11) = 1; 00562 P( 9,valence+ 6) = 1; 00563 P(10,valence+ 9) = 1; 00564 P(11,valence+10) = 1; 00565 } 00566 else 00567 { 00568 v = 1 - 2*v; 00569 w = 1 - 2*w; 00570 jfac = std::pow((Real)(-2), k); 00571 P( 0,valence+9) = 1; 00572 P( 1,valence+6) = 1; 00573 P( 2,valence+4) = 1; 00574 P( 3,valence+1) = 1; 00575 P( 4,valence+2) = 1; 00576 P( 5,valence+5) = 1; 00577 P( 6,valence ) = 1; 00578 P( 7,1 ) = 1; 00579 P( 8,valence+3) = 1; 00580 P( 9,valence-1) = 1; 00581 P(10,0 ) = 1; 00582 P(11,2 ) = 1; 00583 } 00584 00585 u = 1 - v - w; 00586 if ((u > 1 + eps) || (u < -eps)) 00587 libmesh_error_msg("SUBDIVISION irregular patch: u is outside valid range!"); 00588 00589 DenseMatrix<Real> A; 00590 init_subdivision_matrix(A, valence); 00591 00592 // compute P*A^k 00593 if (k > 1) 00594 { 00595 DenseMatrix<Real> Acopy(A); 00596 for (int e = 1; e < k; ++e) 00597 A.right_multiply(Acopy); 00598 } 00599 P.right_multiply(A); 00600 00601 const Point transformed_p(v,w); 00602 00603 for (unsigned int i = 0; i < 12; ++i) 00604 { 00605 tphi[i] = FE<2,SUBDIVISION>::shape (elem, fe_type.order, i, transformed_p); 00606 tdphidxi[i] = FE<2,SUBDIVISION>::shape_deriv (elem, fe_type.order, i, 0, transformed_p); 00607 tdphideta[i] = FE<2,SUBDIVISION>::shape_deriv (elem, fe_type.order, i, 1, transformed_p); 00608 00609 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00610 td2phidxi2[i] = FE<2,SUBDIVISION>::shape_second_deriv(elem, fe_type.order, i, 0, transformed_p); 00611 td2phidxideta[i] = FE<2,SUBDIVISION>::shape_second_deriv(elem, fe_type.order, i, 1, transformed_p); 00612 td2phideta2[i] = FE<2,SUBDIVISION>::shape_second_deriv(elem, fe_type.order, i, 2, transformed_p); 00613 #endif 00614 } 00615 00616 // Finally, we can compute the irregular shape functions as the product of P 00617 // and the regular shape functions: 00618 Real sum1, sum2, sum3, sum4, sum5, sum6; 00619 for (unsigned int j = 0; j < n_approx_shape_functions; ++j) 00620 { 00621 sum1 = sum2 = sum3 = sum4 = sum5 = sum6 = 0; 00622 for (unsigned int i = 0; i < 12; ++i) 00623 { 00624 sum1 += P(i,j) * tphi[i]; 00625 sum2 += P(i,j) * tdphidxi[i]; 00626 sum3 += P(i,j) * tdphideta[i]; 00627 00628 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00629 sum4 += P(i,j) * td2phidxi2[i]; 00630 sum5 += P(i,j) * td2phidxideta[i]; 00631 sum6 += P(i,j) * td2phideta2[i]; 00632 #endif 00633 } 00634 phi[j][p] = sum1; 00635 dphidxi[j][p] = sum2 * jfac; 00636 dphideta[j][p] = sum3 * jfac; 00637 dphi[j][p](0) = dphidxi[j][p]; 00638 dphi[j][p](1) = dphideta[j][p]; 00639 00640 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00641 d2phidxi2[j][p] = sum4 * jfac * jfac; 00642 d2phidxideta[j][p] = sum5 * jfac * jfac; 00643 d2phideta2[j][p] = sum6 * jfac * jfac; 00644 d2phi[j][p](0,0) = d2phidxi2[j][p]; 00645 d2phi[j][p](0,1) = d2phi[j][p](1,0) = d2phidxideta[j][p]; 00646 d2phi[j][p](1,1) = d2phideta2[j][p]; 00647 #endif 00648 } 00649 } // end quadrature loop 00650 } // end irregular vertex 00651 00652 // Let the FEMap use the same initialized shape functions 00653 this->_fe_map->get_phi_map() = phi; 00654 this->_fe_map->get_dphidxi_map() = dphidxi; 00655 this->_fe_map->get_dphideta_map() = dphideta; 00656 00657 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 00658 this->_fe_map->get_d2phidxi2_map() = d2phidxi2; 00659 this->_fe_map->get_d2phideta2_map() = d2phideta2; 00660 this->_fe_map->get_d2phidxideta_map() = d2phidxideta; 00661 #endif 00662 00663 STOP_LOG("init_shape_functions()", "FESubdivision"); 00664 } 00665 00666 00667 00668 void FESubdivision::attach_quadrature_rule(QBase *q) 00669 { 00670 libmesh_assert(q); 00671 00672 qrule = q; 00673 // make sure we don't cache results from a previous quadrature rule 00674 elem_type = INVALID_ELEM; 00675 return; 00676 } 00677 00678 00679 00680 void FESubdivision::reinit(const Elem* elem, 00681 const std::vector<Point>* const libmesh_dbg_var(pts), 00682 const std::vector<Real>* const) 00683 { 00684 libmesh_assert(elem); 00685 libmesh_assert_equal_to(elem->type(), TRI3SUBDIVISION); 00686 #ifndef NDEBUG 00687 const Tri3Subdivision* sd_elem = static_cast<const Tri3Subdivision*>(elem); 00688 #endif 00689 00690 START_LOG("reinit()", "FESubdivision"); 00691 00692 libmesh_assert(!sd_elem->is_ghost()); 00693 libmesh_assert(sd_elem->is_subdivision_updated()); 00694 00695 // check if vertices 1 and 2 are regular 00696 libmesh_assert_equal_to(sd_elem->get_ordered_valence(1), 6); 00697 libmesh_assert_equal_to(sd_elem->get_ordered_valence(2), 6); 00698 00699 // no custom quadrature support 00700 libmesh_assert(pts == NULL); 00701 libmesh_assert(qrule); 00702 qrule->init(elem->type()); 00703 00704 // Initialize the shape functions 00705 this->init_shape_functions(this->qrule->get_points(), elem); 00706 00707 // The shape functions correspond to the qrule 00708 shapes_on_quadrature = true; 00709 00710 // Compute the map for this element. 00711 this->_fe_map->compute_map (this->dim, this->qrule->get_weights(), elem); 00712 00713 STOP_LOG("reinit()", "FESubdivision"); 00714 } 00715 00716 00717 00718 template <> 00719 Real FE<2,SUBDIVISION>::shape(const ElemType type, 00720 const Order order, 00721 const unsigned int i, 00722 const Point& p) 00723 { 00724 switch (order) 00725 { 00726 case FOURTH: 00727 { 00728 switch (type) 00729 { 00730 case TRI3SUBDIVISION: 00731 libmesh_assert_less(i, 12); 00732 return FESubdivision::regular_shape(i,p(0),p(1)); 00733 default: 00734 libmesh_error_msg("ERROR: Unsupported element type!"); 00735 } 00736 } 00737 default: 00738 libmesh_error_msg("ERROR: Unsupported polynomial order!"); 00739 } 00740 00741 libmesh_error_msg("We'll never get here!"); 00742 return 0.; 00743 } 00744 00745 00746 00747 template <> 00748 Real FE<2,SUBDIVISION>::shape(const Elem* elem, 00749 const Order order, 00750 const unsigned int i, 00751 const Point& p) 00752 { 00753 libmesh_assert(elem); 00754 return FE<2,SUBDIVISION>::shape(elem->type(), order, i, p); 00755 } 00756 00757 00758 00759 template <> 00760 Real FE<2,SUBDIVISION>::shape_deriv(const ElemType type, 00761 const Order order, 00762 const unsigned int i, 00763 const unsigned int j, 00764 const Point& p) 00765 { 00766 switch (order) 00767 { 00768 case FOURTH: 00769 { 00770 switch (type) 00771 { 00772 case TRI3SUBDIVISION: 00773 libmesh_assert_less(i, 12); 00774 return FESubdivision::regular_shape_deriv(i,j,p(0),p(1)); 00775 default: 00776 libmesh_error_msg("ERROR: Unsupported element type!"); 00777 } 00778 } 00779 default: 00780 libmesh_error_msg("ERROR: Unsupported polynomial order!"); 00781 } 00782 00783 libmesh_error_msg("We'll never get here!"); 00784 return 0.; 00785 } 00786 00787 00788 00789 template <> 00790 Real FE<2,SUBDIVISION>::shape_deriv(const Elem* elem, 00791 const Order order, 00792 const unsigned int i, 00793 const unsigned int j, 00794 const Point& p) 00795 { 00796 libmesh_assert(elem); 00797 return FE<2,SUBDIVISION>::shape_deriv(elem->type(), order, i, j, p); 00798 } 00799 00800 00801 00802 template <> 00803 Real FE<2,SUBDIVISION>::shape_second_deriv(const ElemType type, 00804 const Order order, 00805 const unsigned int i, 00806 const unsigned int j, 00807 const Point& p) 00808 { 00809 switch (order) 00810 { 00811 case FOURTH: 00812 { 00813 switch (type) 00814 { 00815 case TRI3SUBDIVISION: 00816 libmesh_assert_less(i, 12); 00817 return FESubdivision::regular_shape_second_deriv(i,j,p(0),p(1)); 00818 default: 00819 libmesh_error_msg("ERROR: Unsupported element type!"); 00820 } 00821 } 00822 default: 00823 libmesh_error_msg("ERROR: Unsupported polynomial order!"); 00824 } 00825 00826 libmesh_error_msg("We'll never get here!"); 00827 return 0.; 00828 } 00829 00830 00831 00832 template <> 00833 Real FE<2,SUBDIVISION>::shape_second_deriv(const Elem* elem, 00834 const Order order, 00835 const unsigned int i, 00836 const unsigned int j, 00837 const Point& p) 00838 { 00839 libmesh_assert(elem); 00840 return FE<2,SUBDIVISION>::shape_second_deriv(elem->type(), order, i, j, p); 00841 } 00842 00843 00844 00845 template <> 00846 void FE<2,SUBDIVISION>::nodal_soln(const Elem* elem, 00847 const Order, 00848 const std::vector<Number>& elem_soln, 00849 std::vector<Number>& nodal_soln) 00850 { 00851 libmesh_assert(elem); 00852 libmesh_assert_equal_to(elem->type(), TRI3SUBDIVISION); 00853 const Tri3Subdivision* sd_elem = static_cast<const Tri3Subdivision*>(elem); 00854 00855 nodal_soln.resize(3); // three nodes per element 00856 00857 // Ghost nodes are auxiliary. 00858 if (sd_elem->is_ghost()) 00859 { 00860 nodal_soln[0] = 0; 00861 nodal_soln[1] = 0; 00862 nodal_soln[2] = 0; 00863 return; 00864 } 00865 00866 // First node (node 0 in the element patch): 00867 unsigned int j = sd_elem->local_node_number(sd_elem->get_ordered_node(0)->id()); 00868 nodal_soln[j] = elem_soln[0]; 00869 00870 // Second node (node 1 in the element patch): 00871 j = sd_elem->local_node_number(sd_elem->get_ordered_node(1)->id()); 00872 nodal_soln[j] = elem_soln[1]; 00873 00874 // Third node (node 'valence' in the element patch): 00875 j = sd_elem->local_node_number(sd_elem->get_ordered_node(2)->id()); 00876 nodal_soln[j] = elem_soln[sd_elem->get_ordered_valence(0)]; 00877 } 00878 00879 00880 00881 // the empty template specializations below are needed to avoid 00882 // linker reference errors, but should never get called 00883 template <> 00884 void FE<2,SUBDIVISION>::side_map(const Elem*, 00885 const Elem*, 00886 const unsigned int, 00887 const std::vector<Point>&, 00888 std::vector<Point>&) 00889 { 00890 libmesh_not_implemented(); 00891 } 00892 00893 template <> 00894 void FE<2,SUBDIVISION>::edge_reinit(Elem const*, 00895 unsigned int, 00896 Real, 00897 const std::vector<Point>* const, 00898 const std::vector<Real>* const) 00899 { 00900 libmesh_not_implemented(); 00901 } 00902 00903 template <> 00904 Point FE<2,SUBDIVISION>::inverse_map(const Elem*, 00905 const Point&, 00906 const Real, 00907 const bool) 00908 { 00909 libmesh_not_implemented(); 00910 } 00911 00912 template <> 00913 void FE<2,SUBDIVISION>::inverse_map(const Elem*, 00914 const std::vector<Point>&, 00915 std::vector<Point>&, 00916 Real, 00917 bool) 00918 { 00919 libmesh_not_implemented(); 00920 } 00921 00922 00923 00924 // The number of dofs per subdivision element depends on the valence of its nodes, so it is non-static 00925 template <> unsigned int FE<2,SUBDIVISION>::n_dofs(const ElemType, const Order) { libmesh_not_implemented(); return 0; } 00926 00927 // Loop subdivision elements have only a single dof per node 00928 template <> unsigned int FE<2,SUBDIVISION>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 1; } 00929 00930 // Subdivision FEMs have dofs only at the nodes 00931 template <> unsigned int FE<2,SUBDIVISION>::n_dofs_per_elem(const ElemType, const Order) { return 0; } 00932 00933 // Subdivision FEMs have dofs only at the nodes 00934 template <> void FE<2,SUBDIVISION>::dofs_on_side(const Elem *const, const Order, unsigned int, std::vector<unsigned int> &di) { di.resize(0); } 00935 template <> void FE<2,SUBDIVISION>::dofs_on_edge(const Elem *const, const Order, unsigned int, std::vector<unsigned int> &di) { di.resize(0); } 00936 00937 // Subdivision FEMs are C^1 continuous 00938 template <> FEContinuity FE<2,SUBDIVISION>::get_continuity() const { return C_ONE; } 00939 00940 // Subdivision FEMs are not hierarchic 00941 template <> bool FE<2,SUBDIVISION>::is_hierarchic() const { return false; } 00942 00943 // Subdivision FEM shapes need reinit 00944 template <> bool FE<2,SUBDIVISION>::shapes_need_reinit() const { return true; } 00945 00946 } // namespace libMesh