SundanceBernstein.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                             Sundance
00005 //                 Copyright 2011 Sandia Corporation
00006 // 
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Kevin Long (kevin.long@ttu.edu)
00038 // 
00039 
00040 /* @HEADER@ */
00041 
00042 #include "SundanceBernstein.hpp"
00043 #include "SundanceADReal.hpp"
00044 #include "PlayaExceptions.hpp"
00045 #include "SundanceSpatialDerivSpecifier.hpp"
00046 #include "SundancePoint.hpp"
00047 #include "SundanceObjectWithVerbosity.hpp"
00048 #include "SundanceOut.hpp"
00049 
00050 using namespace Sundance;
00051 using namespace Teuchos;
00052 
00053 
00054 Bernstein::Bernstein(int order)
00055   : order_(order)
00056 {
00057   TEUCHOS_TEST_FOR_EXCEPTION(order < 0, std::runtime_error,
00058     "invalid polynomial order=" << order
00059     << " in Bernstein ctor");
00060 }
00061 
00062 bool Bernstein::supportsCellTypePair(
00063   const CellType& maximalCellType,
00064   const CellType& cellType
00065   ) const
00066 {
00067   switch(maximalCellType)
00068   {
00069     case LineCell:
00070       switch(cellType)
00071       {
00072         case LineCell:
00073         case PointCell:
00074           return true;
00075         default:
00076           return false;
00077       }
00078     case TriangleCell:
00079       switch(cellType)
00080       {
00081         case TriangleCell:
00082         case LineCell:
00083         case PointCell:
00084           return true;
00085         default:
00086           return false;
00087       }
00088     case TetCell:
00089       switch(cellType)
00090       {
00091         case TetCell:
00092         case TriangleCell:
00093         case LineCell:
00094         case PointCell:
00095           return true;
00096         default:
00097           return false;
00098       }
00099     default:
00100       return false;
00101   }
00102 }
00103 
00104 void Bernstein::print(std::ostream& os) const 
00105 {
00106   os << "Bernstein(" << order_ << ")";
00107 }
00108 
00109 int Bernstein::nReferenceDOFsWithoutFacets(
00110   const CellType& maximalCellType,
00111   const CellType& cellType
00112   ) const
00113 {
00114   if (order_==0)
00115   {
00116     if (maximalCellType != cellType) return 0;
00117     return 1;
00118   }
00119 
00120   switch(cellType)
00121   {
00122     case PointCell:
00123       return 1;
00124     case LineCell:
00125       return order_-1;
00126     case TriangleCell:
00127       if (order_ < 3) return 0;
00128       if (order_ >= 3) return (order_-1)*(order_-2)/2;
00129       break;
00130     case QuadCell:
00131       if (order_==1) return 0;
00132       if (order_==2) return 1;
00133       TEUCHOS_TEST_FOR_EXCEPTION(order_>2, std::runtime_error, 
00134         "Bernstein order > 2 not implemented "
00135         "for quad cells");
00136     case TetCell:
00137       if (order_<=2) return 0;
00138       TEUCHOS_TEST_FOR_EXCEPTION(order_>2, std::runtime_error, 
00139         "Bernstein order > 2 not implemented "
00140         "for tet cells");
00141     case BrickCell:
00142       if (order_<=1) return 0;
00143       if (order_==2) return 1;
00144       TEUCHOS_TEST_FOR_EXCEPTION(order_>2, std::runtime_error, 
00145         "Bernstein order > 2 not implemented "
00146         "for brick cells");
00147     default:
00148       TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "Cell type "
00149         << cellType << " not implemented in Bernstein basis");
00150       return -1; // -Wall
00151   }
00152   return -1; // -Wall
00153 }
00154 
00155 void Bernstein::getReferenceDOFs(
00156   const CellType& maximalCellType,
00157   const CellType& cellType,
00158   Array<Array<Array<int> > >& dofs) const 
00159 {
00160   const int N=(order()+1)*(order()+2)/2;
00161   typedef Array<int> Aint;
00162   switch(cellType)
00163   {
00164     case PointCell:
00165       dofs.resize(1);
00166       dofs[0] = tuple<Aint>(tuple(0));
00167       return;
00168     case LineCell:
00169       dofs.resize(2);
00170       dofs[0] = tuple<Aint>(tuple(0), tuple(order()));
00171       dofs[1] = tuple<Aint>(makeRange(1, order()-1));
00172       return;
00173     case TriangleCell:
00174     {
00175       dofs.resize(3);
00176       dofs[0] = tuple<Aint>(tuple(0),tuple(N-order()-1),tuple(N-1));
00177       if (order()>1)
00178       {
00179         // order() - 1 dof per edge
00180         Aint dof0(order()-1);
00181         Aint dof1; // will fill in with range
00182         Aint dof2(order()-1);
00183 
00184         // first edge (from vertex 0 to 1
00185         int inc = 2;
00186         dof0[0] = 1;
00187         for (int i=1;i<order()-1;i++) 
00188         {
00189           dof0[i] = dof0[i-1]+inc;
00190           inc++;
00191         }
00192 
00193         // second edge runs from vertex 1 to 2
00194         dof1 = makeRange(N-order(),N-2);
00195 
00196         // third edge runs from vertex 2 to vertex 0
00197         inc = 3;
00198         dof2[order()-2] = 2;
00199         for (int i=order()-3;i>=0;i--)
00200         {
00201           dof2[i] = dof2[i+1]+inc;
00202           inc++;
00203         }
00204         /** permuted from (0,1,2) to (1,2,0) for UFC ordering */
00205         dofs[1] = tuple<Aint>(dof1,dof2,dof0);
00206       }
00207       else
00208       {
00209         dofs[1] = tuple(Array<int>());
00210       }
00211       if (order()>2)
00212       {
00213         Array<int> internaldofs;
00214         int bfcur = 0;
00215         //int internalbfcur=0; // Commented out unused variable -- KL
00216         for (int alpha1=order();alpha1>=0;alpha1--)
00217         {
00218           for (int alpha2=order()-alpha1;alpha2>=0;alpha2--)
00219           {
00220             int alpha3 = order()-alpha1-alpha2;
00221             if (alpha1*alpha2*alpha3>0) {
00222               internaldofs.append(bfcur);
00223             }
00224             bfcur++;
00225           }
00226         }
00227         dofs[2] = tuple(internaldofs);
00228       }
00229       else
00230       {
00231         dofs[2] = tuple(Array<int>());
00232       }
00233       return;
00234     }
00235     case TetCell:
00236     {
00237     }
00238     default:
00239       TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "Cell type "
00240         << cellType << " not implemented in Bernstein basis");
00241   }
00242 }
00243 
00244 
00245 
00246 Array<int> Bernstein::makeRange(int low, int high)
00247 {
00248   if (high < low) return Array<int>();
00249 
00250   Array<int> rtn(high-low+1);
00251   for (int i=0; i<rtn.length(); i++) rtn[i] = low+i;
00252   return rtn;
00253 }
00254 
00255 void Bernstein::refEval(
00256   const CellType& cellType,
00257   const Array<Point>& pts,
00258   const SpatialDerivSpecifier& sds,
00259   Array<Array<Array<double> > >& result,
00260   int verbosity) const
00261 {
00262   TEUCHOS_TEST_FOR_EXCEPTION(!(sds.isPartial() || sds.isIdentity()), 
00263     std::runtime_error,
00264     "cannot evaluate spatial derivative " << sds << " on Bernstein basis");
00265   const MultiIndex& deriv = sds.mi();
00266   typedef Array<double> Adouble;
00267   result.resize(1);
00268   result[0].resize(pts.length());
00269 
00270   switch(cellType)
00271   {
00272     case PointCell:
00273       result[0] = tuple<Adouble>(tuple(1.0));
00274       return;
00275     case LineCell:
00276       for (int i=0; i<pts.length(); i++)
00277       {
00278         evalOnLine(pts[i], deriv, result[0][i]);
00279       }
00280       return;
00281     case TriangleCell:
00282       for (int i=0; i<pts.length(); i++)
00283       {
00284         evalOnTriangle(pts[i], deriv, result[0][i]);
00285       }
00286       return;
00287     case TetCell:
00288       for (int i=0; i<pts.length(); i++)
00289       {
00290         evalOnTet(pts[i], deriv, result[0][i]);
00291       }
00292       return;
00293     default:
00294       TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
00295         "Bernstein::refEval() unimplemented for cell type "
00296         << cellType);
00297 
00298   }
00299 }
00300 
00301 /* ---------- evaluation on different cell types -------------- */
00302 
00303 void Bernstein::evalOnLine(const Point& pt, 
00304   const MultiIndex& deriv,
00305   Array<double>& result) const
00306 {
00307   ADReal x = ADReal(pt[0], 0, 1);
00308   ADReal one(1.0, 1);
00309   
00310   result.resize(order()+1);
00311   Array<ADReal> tmp(result.length());
00312   Array<double> x0(order()+1);
00313   
00314   if (order_ == 0)
00315   {
00316     tmp[0] = one;
00317   }
00318   else
00319   {
00320     double binom_cur = 1.0;
00321     for (int i=0; i<=order_; i++)
00322     {
00323       tmp[i] = one;
00324 
00325       for (int j=0;j<order_-i;j++) 
00326       {
00327         tmp[i] *= (1-x);
00328       }
00329       for (int j=0;j<i;j++) 
00330       {
00331         tmp[i] *= x;
00332       }
00333       tmp[i] *= binom_cur;
00334       binom_cur *= double(order()-i) / double(i+1);
00335     }
00336   }
00337   
00338   for (int i=0; i<tmp.length(); i++)
00339   {
00340     if (deriv.order()==0) result[i] = tmp[i].value();
00341     else result[i] = tmp[i].gradient()[0];
00342   }
00343 }
00344 
00345 void Bernstein::evalOnTriangle(const Point& pt, 
00346   const MultiIndex& deriv,
00347   Array<double>& result) const
00348 
00349 {
00350   ADReal x = ADReal(pt[0], 0, 2);
00351   ADReal y = ADReal(pt[1], 1, 2);
00352   ADReal one(1.0, 2);
00353   
00354   Array<ADReal> tmp;
00355 
00356   SUNDANCE_OUT(this->verb() > 3, "x=" << x.value() << " y="
00357     << y.value());
00358  
00359   if(order_==0) {
00360     result.resize(1);
00361     tmp.resize(1);
00362     tmp[0] = one;
00363   }
00364   else {
00365     int N = (order()+1)*(order()+2)/2;
00366     result.resize(N);
00367     tmp.resize(N);
00368     // these are the barycentric coordinates
00369     ADReal b1 = 1.0 - x - y;
00370     ADReal b2 = x;
00371     ADReal b3 = y;
00372 
00373     // will hold \binom{n}{\alpha_1}
00374     int bfcur = 0;
00375 
00376     for (int alpha1=order();alpha1>=0;alpha1--) 
00377     {
00378       for (int alpha2 = order()-alpha1;alpha2>=0;alpha2--)
00379       {
00380         int alpha3 = order() - alpha1 - alpha2;
00381         tmp[bfcur] = one;
00382         for (int i=0;i<alpha1;i++)
00383         {
00384           tmp[bfcur] *= b1;
00385         }
00386         for (int i=0;i<alpha2;i++) 
00387         {
00388           tmp[bfcur] *= b2;
00389         }
00390         for (int i=0;i<alpha3;i++)
00391         {
00392           tmp[bfcur] *= b3;
00393         }
00394         for (int i=2;i<=order();i++)
00395         {
00396           tmp[bfcur] *= (double) i;
00397         }
00398         for (int i=2;i<=alpha1;i++) 
00399         {
00400           tmp[bfcur] /= (double) i;
00401         }
00402         for (int i=2;i<=alpha2;i++) 
00403         {
00404           tmp[bfcur] /= (double) i;
00405         }
00406         for (int i=2;i<=alpha3;i++) 
00407         {
00408           tmp[bfcur] /= (double) i;
00409         }
00410         bfcur++;
00411       }
00412     }
00413   }
00414 
00415   for (int i=0; i<tmp.length(); i++)
00416   {
00417     if (deriv.order()==0) result[i] = tmp[i].value();
00418     else 
00419       result[i] = tmp[i].gradient()[deriv.firstOrderDirection()];
00420   }
00421 }
00422 
00423 void Bernstein::evalOnTet(const Point& pt, 
00424   const MultiIndex& deriv,
00425   Array<double>& result) const
00426 {
00427   ADReal x = ADReal(pt[0], 0, 3);
00428   ADReal y = ADReal(pt[1], 1, 3);
00429   ADReal z = ADReal(pt[2], 2, 3);
00430   ADReal one(1.0, 3);
00431   
00432   Array<ADReal> tmp(result.length());
00433 
00434   if(order_==0)
00435   {
00436     tmp.resize(1);
00437     result.resize(1);
00438     tmp[0] = one;
00439   }
00440   else
00441   {
00442   }
00443 
00444   for (int i=0; i<tmp.length(); i++)
00445   {
00446     if (deriv.order()==0) result[i] = tmp[i].value();
00447     else 
00448       result[i] = tmp[i].gradient()[deriv.firstOrderDirection()];
00449   }
00450 }
00451 
00452 
00453 
00454 

Site Contact