Intrepid
/usr/src/RPM/BUILD/trilinos10-10.6.4/packages/intrepid/src/Shared/Intrepid_PointToolsDef.hpp
Go to the documentation of this file.
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