|
Intrepid
|
00001 // @HEADER 00002 // ************************************************************************ 00003 // 00004 // Intrepid Package 00005 // Copyright (2007) Sandia Corporation 00006 // 00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00008 // license for use of this work by or on behalf of the U.S. Government. 00009 // 00010 // This library is free software; you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as 00012 // published by the Free Software Foundation; either version 2.1 of the 00013 // License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, but 00016 // WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00023 // USA 00024 // Questions? Contact Pavel Bochev (pbboche@sandia.gov) or 00025 // Denis Ridzal (dridzal@sandia.gov). 00026 // 00027 // ************************************************************************ 00028 // @HEADER 00029 00034 #ifdef _MSC_VER 00035 #include "winmath.h" 00036 #endif 00037 00038 00039 namespace Intrepid { 00040 00041 int PointTools::getLatticeSize( const shards::CellTopology& cellType , 00042 const int order , 00043 const int offset ) 00044 { 00045 switch( cellType.getKey() ) { 00046 case shards::Tetrahedron<4>::key: 00047 case shards::Tetrahedron<8>::key: 00048 case shards::Tetrahedron<10>::key: 00049 { 00050 const int effectiveOrder = order - 4 * offset; 00051 if (effectiveOrder < 0) return 0; 00052 else return (effectiveOrder+1)*(effectiveOrder+2)*(effectiveOrder+3)/6; 00053 } 00054 break; 00055 case shards::Triangle<3>::key: 00056 case shards::Triangle<4>::key: 00057 case shards::Triangle<6>::key: 00058 { 00059 const int effectiveOrder = order - 3 * offset; 00060 if (effectiveOrder < 0) return 0; 00061 else return (effectiveOrder+1)*(effectiveOrder+2)/2; 00062 } 00063 break; 00064 case shards::Line<2>::key: 00065 case shards::Line<3>::key: 00066 { 00067 const int effectiveOrder = order - 2 * offset; 00068 if (effectiveOrder < 0) return 0; 00069 else return (effectiveOrder+1); 00070 } 00071 break; 00072 default: 00073 TEST_FOR_EXCEPTION( true , std::invalid_argument , 00074 ">>> ERROR (Intrepid::PointTools::getLatticeSize): Illegal cell type" ); 00075 00076 } 00077 } 00078 00079 template<class Scalar, class ArrayType> 00080 void PointTools::getLattice(ArrayType &pts , 00081 const shards::CellTopology& cellType , 00082 const int order , 00083 const int offset , 00084 const EPointType pointType ) 00085 { 00086 switch (pointType) { 00087 case POINTTYPE_EQUISPACED: 00088 getEquispacedLattice<Scalar,ArrayType>( cellType , pts , order , offset ); 00089 break; 00090 case POINTTYPE_WARPBLEND: 00091 getWarpBlendLattice<Scalar,ArrayType>( cellType , pts , order , offset ); 00092 break; 00093 default: 00094 TEST_FOR_EXCEPTION( true , 00095 std::invalid_argument , 00096 "PointTools::getLattice: invalid EPointType" ); 00097 } 00098 return; 00099 } 00100 00101 template<class Scalar, class ArrayType> 00102 void PointTools::getGaussPoints( ArrayType &pts , 00103 const int order ) 00104 { 00105 00106 Scalar *z = new Scalar[order+1]; 00107 Scalar *w = new Scalar[order+1]; 00108 00109 IntrepidPolylib::zwgj( z , w , order + 1 , 0.0 , 0.0 ); 00110 for (int i=0;i<order+1;i++) { 00111 pts(i,0) = z[i]; 00112 } 00113 00114 delete []z; 00115 delete []w; 00116 } 00117 00118 00119 template<class Scalar, class ArrayType> 00120 void PointTools::getEquispacedLattice(const shards::CellTopology& cellType , 00121 ArrayType &points , 00122 const int order , 00123 const int offset ) 00124 00125 { 00126 switch (cellType.getKey()) { 00127 case shards::Tetrahedron<4>::key: 00128 case shards::Tetrahedron<8>::key: 00129 case shards::Tetrahedron<10>::key: 00130 TEST_FOR_EXCEPTION( ( points.dimension(0) != getLatticeSize( cellType , order , offset ) ) 00131 || points.dimension(1) != 3 , 00132 std::invalid_argument , 00133 ">>> ERROR(PointTools::getEquispacedLattice): points argument is ill-sized." ); 00134 getEquispacedLatticeTetrahedron<Scalar,ArrayType>( points , order , offset ); 00135 break; 00136 case shards::Triangle<3>::key: 00137 case shards::Triangle<4>::key: 00138 case shards::Triangle<6>::key: 00139 TEST_FOR_EXCEPTION( ( points.dimension(0) != getLatticeSize( cellType , order , offset ) ) 00140 || points.dimension(1) != 2 , 00141 std::invalid_argument , 00142 ">>> ERROR(PointTools::getEquispacedLattice): points argument is ill-sized." ); 00143 getEquispacedLatticeTriangle<Scalar,ArrayType>( points , order , offset ); 00144 break; 00145 case shards::Line<2>::key: 00146 case shards::Line<3>::key: 00147 TEST_FOR_EXCEPTION( ( points.dimension(0) != getLatticeSize( cellType , order , offset ) ) 00148 || points.dimension(1) != 1 , 00149 std::invalid_argument , 00150 ">>> ERROR(PointTools::getEquispacedLattice): points argument is ill-sized." ); 00151 getEquispacedLatticeLine<Scalar,ArrayType>( points , order , offset ); 00152 break; 00153 default: 00154 TEST_FOR_EXCEPTION( true , std::invalid_argument , 00155 ">>> ERROR (Intrepid::PointTools::getEquispacedLattice): Illegal cell type" ); 00156 } 00157 00158 } 00159 00160 template<class Scalar, class ArrayType> 00161 void PointTools::getWarpBlendLattice( const shards::CellTopology& cellType , 00162 ArrayType &points , 00163 const int order , 00164 const int offset ) 00165 00166 { 00167 switch (cellType.getKey()) { 00168 case shards::Tetrahedron<4>::key: 00169 case shards::Tetrahedron<8>::key: 00170 case shards::Tetrahedron<10>::key: 00171 TEST_FOR_EXCEPTION( ( points.dimension(0) != getLatticeSize( cellType , order , offset ) ) 00172 || points.dimension(1) != 3 , 00173 std::invalid_argument , 00174 ">>> ERROR(PointTools::getWarpBlendLattice): points argument is ill-sized." ); 00175 getWarpBlendLatticeTetrahedron<Scalar,ArrayType>( points , order , offset ); 00176 break; 00177 case shards::Triangle<3>::key: 00178 case shards::Triangle<4>::key: 00179 case shards::Triangle<6>::key: 00180 TEST_FOR_EXCEPTION( ( points.dimension(0) != getLatticeSize( cellType , order , offset ) ) 00181 || points.dimension(1) != 2 , 00182 std::invalid_argument , 00183 ">>> ERROR(PointTools::getWarpBlendLattice): points argument is ill-sized." ); 00184 getWarpBlendLatticeTriangle<Scalar,ArrayType>( points , order , offset ); 00185 break; 00186 case shards::Line<2>::key: 00187 case shards::Line<3>::key: 00188 TEST_FOR_EXCEPTION( ( points.dimension(0) != getLatticeSize( cellType , order , offset ) ) 00189 || points.dimension(1) != 1 , 00190 std::invalid_argument , 00191 ">>> ERROR(PointTools::getWarpBlendLattice): points argument is ill-sized." ); 00192 getWarpBlendLatticeLine<Scalar,ArrayType>( points , order , offset ); 00193 break; 00194 default: 00195 TEST_FOR_EXCEPTION( true , std::invalid_argument , 00196 ">>> ERROR (Intrepid::PointTools::getWarpBlendLattice): Illegal cell type" ); 00197 } 00198 00199 } 00200 00201 template<class Scalar, class ArrayType> 00202 void PointTools::getEquispacedLatticeLine( ArrayType &points , 00203 const int order , 00204 const int offset ) 00205 { 00206 TEST_FOR_EXCEPTION( order < 0 , 00207 std::invalid_argument , 00208 ">>> ERROR (Intrepid::PointTools::getEquispacedLatticeLine): order must be positive" ); 00209 if (order == 0) { 00210 points(0,0) = 0.0; 00211 } 00212 else { 00213 const Scalar h = 2.0 / order; 00214 00215 for (int i=offset;i<=order-offset;i++) { 00216 points(i-offset,0) = -1.0 + h * (Scalar) i; 00217 } 00218 } 00219 00220 return; 00221 } 00222 00223 template<class Scalar, class ArrayType> 00224 void PointTools::getEquispacedLatticeTriangle( ArrayType &points , 00225 const int order , 00226 const int offset ) 00227 { 00228 TEST_FOR_EXCEPTION( order <= 0 , 00229 std::invalid_argument , 00230 ">>> ERROR (Intrepid::PointTools::getEquispacedLatticeLine): order must be positive" ); 00231 00232 const Scalar h = 1.0 / order; 00233 int cur = 0; 00234 00235 for (int i=offset;i<=order-offset;i++) { 00236 for (int j=offset;j<=order-i-offset;j++) { 00237 points(cur,0) = (Scalar)0.0 + (Scalar) j * h ; 00238 points(cur,1) = (Scalar)0.0 + (Scalar) i * h; 00239 cur++; 00240 } 00241 } 00242 00243 return; 00244 } 00245 00246 template<class Scalar, class ArrayType> 00247 void PointTools::getEquispacedLatticeTetrahedron( ArrayType &points , 00248 const int order , 00249 const int offset ) 00250 { 00251 TEST_FOR_EXCEPTION( (order <= 0) , 00252 std::invalid_argument , 00253 ">>> ERROR (Intrepid::PointTools::getEquispacedLatticeTetrahedron): order must be positive" ); 00254 00255 const Scalar h = 1.0 / order; 00256 int cur = 0; 00257 00258 for (int i=offset;i<=order-offset;i++) { 00259 for (int j=offset;j<=order-i-offset;j++) { 00260 for (int k=offset;k<=order-i-j-offset;k++) { 00261 points(cur,0) = (Scalar) k * h; 00262 points(cur,1) = (Scalar) j * h; 00263 points(cur,2) = (Scalar) i * h; 00264 cur++; 00265 } 00266 } 00267 } 00268 00269 return; 00270 } 00271 00272 template<class Scalar, class ArrayType> 00273 void PointTools::getWarpBlendLatticeLine( ArrayType &points , 00274 const int order , 00275 const int offset ) 00276 { 00277 Scalar *z = new Scalar[order+1]; 00278 Scalar *w = new Scalar[order+1]; 00279 00280 // order is order of polynomial degree. The Gauss-Lobatto points are accurate 00281 // up to degree 2*i-1 00282 IntrepidPolylib::zwglj( z , w , order+1 , 0.0 , 0.0 ); 00283 00284 for (int i=offset;i<=order-offset;i++) { 00285 points(i-offset,0) = z[i]; 00286 } 00287 00288 delete []z; 00289 delete []w; 00290 00291 return; 00292 } 00293 00294 template<class Scalar, class ArrayType> 00295 void PointTools::warpFactor( const int order , 00296 const ArrayType &xnodes , 00297 const ArrayType &xout , 00298 ArrayType &warp) 00299 { 00300 TEST_FOR_EXCEPTION( ( warp.dimension(0) != xout.dimension(0) ) , 00301 std::invalid_argument , 00302 ">>> ERROR (PointTools::warpFactor): xout and warp must be same size." ); 00303 00304 warp.initialize(); 00305 00306 FieldContainer<Scalar> d( xout.dimension(0) ); 00307 d.initialize(); 00308 00309 FieldContainer<Scalar> xeq( order + 1 ,1); 00310 PointTools::getEquispacedLatticeLine<Scalar,ArrayType>( xeq , order , 0 ); 00311 xeq.resize( order + 1 ); 00312 00313 TEST_FOR_EXCEPTION( ( xeq.dimension(0) != xnodes.dimension(0) ) , 00314 std::invalid_argument , 00315 ">>> ERROR (PointTools::warpFactor): xeq and xnodes must be same size." ); 00316 00317 for (int i=0;i<=order;i++) { 00318 00319 for (int k=0;k<d.dimension(0);k++) { 00320 d(k) = xnodes(i) - xeq(i); 00321 } 00322 00323 for (int j=1;j<order;j++) { 00324 if (i != j) { 00325 for (int k=0;k<d.dimension(0);k++) { 00326 d(k) = d(k) * ( (xout(k)-xeq(j)) / (xeq(i)-xeq(j)) ); 00327 } 00328 } 00329 } 00330 00331 // deflate end roots 00332 if ( i != 0 ) { 00333 for (int k=0;k<d.dimension(0);k++) { 00334 d(k) = -d(k) / (xeq(i) - xeq(0)); 00335 } 00336 } 00337 00338 if (i != order ) { 00339 for (int k=0;k<d.dimension(0);k++) { 00340 d(k) = d(k) / (xeq(i) - xeq(order)); 00341 } 00342 } 00343 00344 for (int k=0;k<d.dimension(0);k++) { 00345 warp(k) += d(k); 00346 } 00347 00348 } 00349 00350 00351 return; 00352 } 00353 00354 template<class Scalar, class ArrayType> 00355 void PointTools::getWarpBlendLatticeTriangle( ArrayType &points , 00356 const int order , 00357 const int offset ) 00358 { 00359 /* get Gauss-Lobatto points */ 00360 Intrepid::FieldContainer<Scalar> gaussX( order + 1 , 1 ); 00361 00362 PointTools::getWarpBlendLatticeLine<Scalar,FieldContainer<Scalar> >( gaussX , order , 0 ); 00363 00364 gaussX.resize(gaussX.dimension(0)); 00365 00366 Scalar alpopt[] = {0.0000,0.0000,1.4152,0.1001,0.2751,0.9800,1.0999, 00367 1.2832,1.3648, 1.4773, 1.4959, 1.5743, 1.5770, 1.6223, 1.6258}; 00368 00369 Scalar alpha; 00370 00371 if (order >= 1 && order < 16) { 00372 alpha = alpopt[order-1]; 00373 } 00374 else { 00375 alpha = 5.0 / 3.0; 00376 } 00377 00378 const int p = order; /* switch to Warburton's notation */ 00379 int N = (p+1)*(p+2)/2; 00380 00381 /* equidistributed nodes on equilateral triangle */ 00382 Intrepid::FieldContainer<Scalar> L1( N ); 00383 Intrepid::FieldContainer<Scalar> L2( N ); 00384 Intrepid::FieldContainer<Scalar> L3( N ); 00385 Intrepid::FieldContainer<Scalar> X(N); 00386 Intrepid::FieldContainer<Scalar> Y(N); 00387 00388 int sk = 0; 00389 for (int n=1;n<=p+1;n++) { 00390 for (int m=1;m<=p+2-n;m++) { 00391 L1(sk) = (n-1) / (Scalar)p; 00392 L3(sk) = (m-1) / (Scalar)p; 00393 L2(sk) = 1.0 - L1(sk) - L3(sk); 00394 sk++; 00395 } 00396 } 00397 00398 for (int n=0;n<N;n++) { 00399 X(n) = -L2(n) + L3(n); 00400 Y(n) = (-L2(n) - L3(n) + 2*L1(n))/1.7320508075688772; 00401 } 00402 00403 /* get blending function for each node at each edge */ 00404 Intrepid::FieldContainer<Scalar> blend1(N); 00405 Intrepid::FieldContainer<Scalar> blend2(N); 00406 Intrepid::FieldContainer<Scalar> blend3(N); 00407 00408 for (int n=0;n<N;n++) { 00409 blend1(n) = 4.0 * L2(n) * L3(n); 00410 blend2(n) = 4.0 * L1(n) * L3(n); 00411 blend3(n) = 4.0 * L1(n) * L2(n); 00412 } 00413 00414 /* get difference of each barycentric coordinate */ 00415 Intrepid::FieldContainer<Scalar> L3mL2(N); 00416 Intrepid::FieldContainer<Scalar> L1mL3(N); 00417 Intrepid::FieldContainer<Scalar> L2mL1(N); 00418 00419 for (int k=0;k<N;k++) { 00420 L3mL2(k) = L3(k)-L2(k); 00421 L1mL3(k) = L1(k)-L3(k); 00422 L2mL1(k) = L2(k)-L1(k); 00423 } 00424 00425 FieldContainer<Scalar> warpfactor1(N); 00426 FieldContainer<Scalar> warpfactor2(N); 00427 FieldContainer<Scalar> warpfactor3(N); 00428 00429 warpFactor<Scalar,FieldContainer<Scalar> >( order , gaussX , L3mL2 , warpfactor1 ); 00430 warpFactor<Scalar,FieldContainer<Scalar> >( order , gaussX , L1mL3 , warpfactor2 ); 00431 warpFactor<Scalar,FieldContainer<Scalar> >( order , gaussX , L2mL1 , warpfactor3 ); 00432 00433 FieldContainer<Scalar> warp1(N); 00434 FieldContainer<Scalar> warp2(N); 00435 FieldContainer<Scalar> warp3(N); 00436 00437 for (int k=0;k<N;k++) { 00438 warp1(k) = blend1(k) * warpfactor1(k) * 00439 ( 1.0 + alpha * alpha * L1(k) * L1(k) ); 00440 warp2(k) = blend2(k) * warpfactor2(k) * 00441 ( 1.0 + alpha * alpha * L2(k) * L2(k) ); 00442 warp3(k) = blend3(k) * warpfactor3(k) * 00443 ( 1.0 + alpha * alpha * L3(k) * L3(k) ); 00444 } 00445 00446 for (int k=0;k<N;k++) { 00447 X(k) += 1.0 * warp1(k) + cos( 2.0 * M_PI / 3.0 ) * warp2(k) + cos(4*M_PI/3.0) * warp3(k); 00448 Y(k) += 0.0 * warp1(k) + sin( 2.0 * M_PI / 3.0 ) * warp2(k) + sin( 4*M_PI/3.0) * warp3(k); 00449 } 00450 00451 FieldContainer<Scalar> warXY(N,2); 00452 00453 for (int k=0;k<N;k++) { 00454 warXY(k,0) = X(k); 00455 warXY(k,1) = Y(k); 00456 } 00457 00458 00459 // finally, convert the warp-blend points to the correct triangle 00460 FieldContainer<Scalar> warburtonVerts(1,3,2); 00461 warburtonVerts(0,0,0) = -1.0; 00462 warburtonVerts(0,0,1) = -1.0/sqrt(3.0); 00463 warburtonVerts(0,1,0) = 1.0; 00464 warburtonVerts(0,1,1) = -1.0/sqrt(3.0); 00465 warburtonVerts(0,2,0) = 0.0; 00466 warburtonVerts(0,2,1) = 2.0/sqrt(3.0); 00467 00468 FieldContainer<Scalar> refPts(N,2); 00469 00470 Intrepid::CellTools<Scalar>::mapToReferenceFrame( refPts , 00471 warXY , 00472 warburtonVerts , 00473 shards::getCellTopologyData< shards::Triangle<3> >(), 00474 0 ); 00475 00476 // now write from refPts into points, taking care of offset 00477 int noffcur = 0; // index into refPts 00478 int offcur = 0; // index int points 00479 for (int i=0;i<=order;i++) { 00480 for (int j=0;j<=order-i;j++) { 00481 if ( (i >= offset) && (i <= order-offset) && 00482 (j >= offset) && (j <= order-i-offset) ) { 00483 points(offcur,0) = refPts(noffcur,0); 00484 points(offcur,1) = refPts(noffcur,1); 00485 offcur++; 00486 } 00487 noffcur++; 00488 } 00489 } 00490 00491 return; 00492 } 00493 00494 00495 template<class Scalar, class ArrayType> 00496 void PointTools::warpShiftFace3D( const int order , 00497 const Scalar pval , 00498 const ArrayType &L1, 00499 const ArrayType &L2, 00500 const ArrayType &L3, 00501 const ArrayType &L4, 00502 ArrayType &dxy) 00503 { 00504 evalshift<Scalar,ArrayType>(order,pval,L2,L3,L4,dxy); 00505 return; 00506 } 00507 00508 template<class Scalar, class ArrayType> 00509 void PointTools::evalshift( const int order , 00510 const Scalar pval , 00511 const ArrayType &L1 , 00512 const ArrayType &L2 , 00513 const ArrayType &L3 , 00514 ArrayType &dxy ) 00515 { 00516 // get Gauss-Lobatto-nodes 00517 FieldContainer<Scalar> gaussX(order+1,1); 00518 PointTools::getWarpBlendLatticeLine<Scalar,FieldContainer<Scalar> >( gaussX , order , 0 ); 00519 gaussX.resize(order+1); 00520 const int N = L1.dimension(0); 00521 00522 // Warburton code reverses them 00523 for (int k=0;k<=order;k++) { 00524 gaussX(k) *= -1.0; 00525 } 00526 00527 // blending function at each node for each edge 00528 FieldContainer<Scalar> blend1(N); 00529 FieldContainer<Scalar> blend2(N); 00530 FieldContainer<Scalar> blend3(N); 00531 00532 for (int i=0;i<N;i++) { 00533 blend1(i) = L2(i) * L3(i); 00534 blend2(i) = L1(i) * L3(i); 00535 blend3(i) = L1(i) * L2(i); 00536 } 00537 00538 // amount of warp for each node for each edge 00539 FieldContainer<Scalar> warpfactor1(N); 00540 FieldContainer<Scalar> warpfactor2(N); 00541 FieldContainer<Scalar> warpfactor3(N); 00542 00543 // differences of barycentric coordinates 00544 FieldContainer<Scalar> L3mL2(N); 00545 FieldContainer<Scalar> L1mL3(N); 00546 FieldContainer<Scalar> L2mL1(N); 00547 00548 for (int k=0;k<N;k++) { 00549 L3mL2(k) = L3(k)-L2(k); 00550 L1mL3(k) = L1(k)-L3(k); 00551 L2mL1(k) = L2(k)-L1(k); 00552 } 00553 00554 evalwarp<Scalar,FieldContainer<Scalar> >( warpfactor1 , order , gaussX , L3mL2 ); 00555 evalwarp<Scalar,FieldContainer<Scalar> >( warpfactor2 , order , gaussX , L1mL3 ); 00556 evalwarp<Scalar,FieldContainer<Scalar> >( warpfactor3 , order , gaussX , L2mL1 ); 00557 00558 for (int k=0;k<N;k++) { 00559 warpfactor1(k) *= 4.0; 00560 warpfactor2(k) *= 4.0; 00561 warpfactor3(k) *= 4.0; 00562 } 00563 00564 FieldContainer<Scalar> warp1(N); 00565 FieldContainer<Scalar> warp2(N); 00566 FieldContainer<Scalar> warp3(N); 00567 00568 for (int k=0;k<N;k++) { 00569 warp1(k) = blend1(k) * warpfactor1(k) * 00570 ( 1.0 + pval * pval * L1(k) * L1(k) ); 00571 warp2(k) = blend2(k) * warpfactor2(k) * 00572 ( 1.0 + pval * pval * L2(k) * L2(k) ); 00573 warp3(k) = blend3(k) * warpfactor3(k) * 00574 ( 1.0 + pval * pval * L3(k) * L3(k) ); 00575 } 00576 00577 for (int k=0;k<N;k++) { 00578 dxy(k,0) = 1.0 * warp1(k) + cos( 2.0 * M_PI / 3.0 ) * warp2(k) + cos( 4.0*M_PI/3.0 ) * warp3(k); 00579 dxy(k,1) = 0.0 * warp1(k) + sin( 2.0 * M_PI / 3.0 ) * warp2(k) + sin( 4.0*M_PI/3.0 ) * warp3(k); 00580 } 00581 00582 return; 00583 00584 } 00585 00586 /* one-d edge warping function */ 00587 template<class Scalar, class ArrayType> 00588 void PointTools::evalwarp( ArrayType &warp , 00589 const int order , 00590 const ArrayType &xnodes , 00591 const ArrayType &xout ) 00592 { 00593 FieldContainer<Scalar> xeq(order+1); 00594 FieldContainer<Scalar> d(xout.dimension(0)); 00595 00596 d.initialize(); 00597 00598 for (int i=0;i<=order;i++) { 00599 xeq(i) = -1.0 + 2.0 * ( order - i ) / order; 00600 } 00601 00602 00603 00604 for (int i=0;i<=order;i++) { 00605 d.initialize( xnodes(i) - xeq(i) ); 00606 for (int j=1;j<order;j++) { 00607 if (i!=j) { 00608 for (int k=0;k<d.dimension(0);k++) { 00609 d(k) = d(k) * (xout(k)-xeq(j))/(xeq(i)-xeq(j)); 00610 } 00611 } 00612 } 00613 if (i!=0) { 00614 for (int k=0;k<d.dimension(0);k++) { 00615 d(k) = -d(k)/(xeq(i)-xeq(0)); 00616 } 00617 } 00618 if (i!=order) { 00619 for (int k=0;k<d.dimension(0);k++) { 00620 d(k) = d(k)/(xeq(i)-xeq(order)); 00621 } 00622 } 00623 00624 for (int k=0;k<d.dimension(0);k++) { 00625 warp(k) += d(k); 00626 } 00627 } 00628 00629 return; 00630 } 00631 00632 00633 template<class Scalar, class ArrayType> 00634 void PointTools::getWarpBlendLatticeTetrahedron(ArrayType &points , 00635 const int order , 00636 const int offset ) 00637 { 00638 Scalar alphastore[] = { 0,0,0,0.1002, 1.1332,1.5608,1.3413,1.2577,1.1603, 00639 1.10153,0.6080,0.4523,0.8856,0.8717,0.9655}; 00640 Scalar alpha; 00641 00642 if (order <= 15) { 00643 alpha = alphastore[order-1]; 00644 } 00645 else { 00646 alpha = 1.0; 00647 } 00648 00649 const int N = (order+1)*(order+2)*(order+3)/6; 00650 Scalar tol = 1.e-10; 00651 00652 FieldContainer<Scalar> shift(N,3); 00653 shift.initialize(); 00654 00655 /* create 3d equidistributed nodes on Warburton tet */ 00656 FieldContainer<Scalar> equipoints(N,3); 00657 int sk = 0; 00658 for (int n=0;n<=order;n++) { 00659 for (int m=0;m<=order-n;m++) { 00660 for (int q=0;q<=order-n-m;q++) { 00661 equipoints(sk,0) = -1.0 + (q * 2.0 ) / order; 00662 equipoints(sk,1) = -1.0 + (m * 2.0 ) / order; 00663 equipoints(sk,2) = -1.0 + (n * 2.0 ) / order; 00664 sk++; 00665 } 00666 } 00667 } 00668 00669 00670 /* construct barycentric coordinates for equispaced lattice */ 00671 FieldContainer<Scalar> L1(N); 00672 FieldContainer<Scalar> L2(N); 00673 FieldContainer<Scalar> L3(N); 00674 FieldContainer<Scalar> L4(N); 00675 for (int i=0;i<N;i++) { 00676 L1(i) = (1.0 + equipoints(i,2)) / 2.0; 00677 L2(i) = (1.0 + equipoints(i,1)) / 2.0; 00678 L3(i) = -(1.0 + equipoints(i,0) + equipoints(i,1) + equipoints(i,2)) / 2.0; 00679 L4(i) = (1.0 + equipoints(i,0)) / 2.0; 00680 } 00681 00682 00683 /* vertices of Warburton tet */ 00684 FieldContainer<Scalar> warVerts(4,3); 00685 warVerts(0,0) = -1.0; 00686 warVerts(0,1) = -1.0/sqrt(3.0); 00687 warVerts(0,2) = -1.0/sqrt(6.0); 00688 warVerts(1,0) = 1.0; 00689 warVerts(1,1) = -1.0/sqrt(3.0); 00690 warVerts(1,2) = -1.0/sqrt(6.0); 00691 warVerts(2,0) = 0.0; 00692 warVerts(2,1) = 2.0 / sqrt(3.0); 00693 warVerts(2,2) = -1.0/sqrt(6.0); 00694 warVerts(3,0) = 0.0; 00695 warVerts(3,1) = 0.0; 00696 warVerts(3,2) = 3.0 / sqrt(6.0); 00697 00698 00699 /* tangents to faces */ 00700 FieldContainer<Scalar> t1(4,3); 00701 FieldContainer<Scalar> t2(4,3); 00702 for (int i=0;i<3;i++) { 00703 t1(0,i) = warVerts(1,i) - warVerts(0,i); 00704 t1(1,i) = warVerts(1,i) - warVerts(0,i); 00705 t1(2,i) = warVerts(2,i) - warVerts(1,i); 00706 t1(3,i) = warVerts(2,i) - warVerts(0,i); 00707 t2(0,i) = warVerts(2,i) - 0.5 * ( warVerts(0,i) + warVerts(1,i) ); 00708 t2(1,i) = warVerts(3,i) - 0.5 * ( warVerts(0,i) + warVerts(1,i) ); 00709 t2(2,i) = warVerts(3,i) - 0.5 * ( warVerts(1,i) + warVerts(2,i) ); 00710 t2(3,i) = warVerts(3,i) - 0.5 * ( warVerts(0,i) + warVerts(2,i) ); 00711 } 00712 00713 /* normalize tangents */ 00714 for (int n=0;n<4;n++) { 00715 /* Compute norm of t1(n) and t2(n) */ 00716 Scalar normt1n = 0.0; 00717 Scalar normt2n = 0.0; 00718 for (int i=0;i<3;i++) { 00719 normt1n += (t1(n,i) * t1(n,i)); 00720 normt2n += (t2(n,i) * t2(n,i)); 00721 } 00722 normt1n = sqrt(normt1n); 00723 normt2n = sqrt(normt2n); 00724 /* normalize each tangent now */ 00725 for (int i=0;i<3;i++) { 00726 t1(n,i) /= normt1n; 00727 t2(n,i) /= normt2n; 00728 } 00729 } 00730 00731 /* undeformed coordinates */ 00732 FieldContainer<Scalar> XYZ(N,3); 00733 for (int i=0;i<N;i++) { 00734 for (int j=0;j<3;j++) { 00735 XYZ(i,j) = L3(i)*warVerts(0,j) + L4(i)*warVerts(1,j) + L2(i)*warVerts(2,j) + L1(i)*warVerts(3,j); 00736 } 00737 } 00738 00739 for (int face=1;face<=4;face++) { 00740 FieldContainer<Scalar> La, Lb, Lc, Ld; 00741 FieldContainer<Scalar> warp(N,2); 00742 FieldContainer<Scalar> blend(N); 00743 FieldContainer<Scalar> denom(N); 00744 switch (face) { 00745 case 1: 00746 La = L1; Lb = L2; Lc = L3; Ld = L4; break; 00747 case 2: 00748 La = L2; Lb = L1; Lc = L3; Ld = L4; break; 00749 case 3: 00750 La = L3; Lb = L1; Lc = L4; Ld = L2; break; 00751 case 4: 00752 La = L4; Lb = L1; Lc = L3; Ld = L2; break; 00753 } 00754 00755 /* get warp tangential to face */ 00756 warpShiftFace3D<Scalar,ArrayType>(order,alpha,La,Lb,Lc,Ld,warp); 00757 00758 for (int k=0;k<N;k++) { 00759 blend(k) = Lb(k) * Lc(k) * Ld(k); 00760 } 00761 00762 for (int k=0;k<N;k++) { 00763 denom(k) = (Lb(k) + 0.5 * La(k)) * (Lc(k) + 0.5*La(k)) * (Ld(k) + 0.5 * La(k)); 00764 } 00765 00766 for (int k=0;k<N;k++) { 00767 if (denom(k) > tol) { 00768 blend(k) *= ( 1.0 + alpha * alpha * La(k) * La(k) ) / denom(k); 00769 } 00770 } 00771 00772 00773 // compute warp and blend 00774 for (int k=0;k<N;k++) { 00775 for (int j=0;j<3;j++) { 00776 shift(k,j) = shift(k,j) + blend(k) * warp(k,0) * t1(face-1,j) 00777 + blend(k) * warp(k,1) * t2(face-1,j); 00778 } 00779 } 00780 00781 for (int k=0;k<N;k++) { 00782 if (La(k) < tol && ( Lb(k) < tol || Lc(k) < tol || Ld(k) < tol )) { 00783 for (int j=0;j<3;j++) { 00784 shift(k,j) = warp(k,0) * t1(face-1,j) + warp(k,1) * t2(face-1,j); 00785 } 00786 } 00787 } 00788 00789 } 00790 00791 FieldContainer<Scalar> updatedPoints(N,3); 00792 for (int k=0;k<N;k++) { 00793 for (int j=0;j<3;j++) { 00794 updatedPoints(k,j) = XYZ(k,j) + shift(k,j); 00795 } 00796 } 00797 00798 warVerts.resize( 1 , 4 , 3 ); 00799 00800 // now we convert to Pavel's reference triangle! 00801 FieldContainer<Scalar> refPts(N,3); 00802 CellTools<Scalar>::mapToReferenceFrame( refPts ,updatedPoints , 00803 warVerts , 00804 shards::getCellTopologyData<shards::Tetrahedron<4> >() , 00805 0 ); 00806 00807 // now write from refPts into points, taking offset into account 00808 int noffcur = 0; 00809 int offcur = 0; 00810 for (int i=0;i<=order;i++) { 00811 for (int j=0;j<=order-i;j++) { 00812 for (int k=0;k<=order-i-j;k++) { 00813 if ( (i >= offset) && (i <= order-offset) && 00814 (j >= offset) && (j <= order-i-offset) && 00815 (k >= offset) && (k <= order-i-j-offset) ) { 00816 points(offcur,0) = refPts(noffcur,0); 00817 points(offcur,1) = refPts(noffcur,1); 00818 points(offcur,2) = refPts(noffcur,2); 00819 offcur++; 00820 } 00821 noffcur++; 00822 } 00823 } 00824 } 00825 00826 00827 00828 } 00829 00830 00831 } // face Intrepid
1.7.4