SundanceCellJacobianBatch.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 "SundanceCellJacobianBatch.hpp"
00043 #include "PlayaExceptions.hpp"
00044 #include "SundanceOut.hpp"
00045 #include "PlayaTabs.hpp"
00046 #include "Teuchos_Time.hpp"
00047 #include "Teuchos_TimeMonitor.hpp"
00048 
00049 using namespace Sundance;
00050 using namespace Sundance;
00051 using namespace Teuchos;
00052 using namespace Sundance;
00053 
00054 
00055 /* declare LAPACK subroutines */
00056 extern "C"
00057 {
00058   /* LAPACK backsolve on a factored system */
00059   void dgetrs_(const char* trans, const int* N, const int* NRHS, 
00060                const double* A, const int* lda, 
00061                const int* iPiv, double* B, const int* ldb, int* info);
00062 
00063   /* LAPACK factorization */
00064   void dgetrf_(const int* M, const int* N, double* A, const int* lda, 
00065                const int* iPiv, int* info);
00066 }
00067 
00068 static Time& jacobianInversionTimer() 
00069 {
00070   static RCP<Time> rtn 
00071     = TimeMonitor::getNewTimer("jacobian inversion"); 
00072   return *rtn;
00073 }
00074 
00075 static Time& jacobianFactoringTimer() 
00076 {
00077   static RCP<Time> rtn 
00078     = TimeMonitor::getNewTimer("jacobian factoring"); 
00079   return *rtn;
00080 }
00081 
00082 
00083 CellJacobianBatch::CellJacobianBatch()
00084   : spatialDim_(0), cellDim_(0), 
00085     jSize_(0), numCells_(0), numQuad_(0), iPiv_(), J_(), detJ_(), invJ_(),
00086     isFactored_(false), hasInverses_(false)
00087 {}
00088 
00089 void CellJacobianBatch::resize(int numCells, int numQuad, 
00090                                int spatialDim, int cellDim)
00091 {
00092   spatialDim_ = spatialDim;
00093   cellDim_ = cellDim;
00094   if (spatialDim_ == cellDim_)
00095     {
00096       jSize_ = spatialDim_*spatialDim_;
00097      }
00098   
00099   numCells_ = numCells;
00100   numQuad_ = numQuad;
00101   iPiv_.resize(spatialDim_*numCells_*numQuad_);
00102   J_.resize(spatialDim_*spatialDim_*numCells_*numQuad_);
00103   detJ_.resize(numCells_*numQuad_);
00104   isFactored_ = false;
00105   hasInverses_ = false;
00106 }
00107 
00108 void CellJacobianBatch::resize(int numCells, int spatialDim, int cellDim)
00109 {
00110   spatialDim_ = spatialDim;
00111   cellDim_ = cellDim;
00112   if (spatialDim_ == cellDim_)
00113     {
00114       jSize_ = spatialDim_*spatialDim_;
00115     }
00116 
00117   numCells_ = numCells;
00118   numQuad_ = 1;
00119   iPiv_.resize(spatialDim_*numCells_);
00120   J_.resize(spatialDim_*spatialDim_*numCells_);
00121   detJ_.resize(numCells_);
00122   isFactored_ = false;
00123   hasInverses_ = false;
00124 }
00125 
00126 void CellJacobianBatch::factor() const 
00127 {
00128   TimeMonitor timer(jacobianFactoringTimer());
00129   if (isFactored_) return;
00130   /* We're given the Jacobian, and we want to factor it and compute its determinant. 
00131    * We factor it using the LAPACK routine dgetrf(), after which J is replaced
00132    * by its LU factorization. The determinant of J is obtained by taking the
00133    * project of the diagonal elements of U. 
00134    */
00135 
00136   TEUCHOS_TEST_FOR_EXCEPTION(spatialDim_ != cellDim_, std::logic_error,
00137                      "Attempting to factor the Jacobian of a cell "
00138                      "that is not of maximal dimension");
00139   Tabs tabs;
00140   SUNDANCE_OUT(this->verb() > 2,
00141                tabs << "factoring Jacobians");
00142   
00143   for (int cell=0; cell<numCells_; cell++)
00144     {
00145       for (int q=0; q<numQuad_; q++)
00146         {
00147           int start = (cell*numQuad_ + q)*jSize_;
00148 
00149           /* pointer to start of J for this cell */
00150           double* jFactPtr = &(J_[start]);
00151           int* iPiv = &(iPiv_[(q + cell*numQuad_)*spatialDim_]);
00152   
00153           /* fortran junk */
00154           int lda = spatialDim_; // leading dimension of J
00155           
00156           int info = 0; // error return flag, will be zero if successful. 
00157           
00158           /* Factor J */
00159           ::dgetrf_( &spatialDim_,  &spatialDim_, jFactPtr, &lda, iPiv, &info);
00160           
00161           TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
00162                              "CellJacobianBatch::setJacobian(): factoring failed");
00163 
00164           /* the determinant is the product of the diagonal elements 
00165            * the upper triangular factor of the factored Jacobian */
00166           double detJ = 1.0;
00167           for (int i=0; i<spatialDim_; i++)
00168             {
00169               detJ *= jFactPtr[i + spatialDim_*i];
00170             }
00171           detJ_[cell*numQuad_ + q] = detJ;
00172         }
00173     }
00174 
00175   addFlops(numCells_ * spatialDim_ * (1.0 + spatialDim_ * spatialDim_));
00176   isFactored_ = true;
00177 }
00178 
00179 void CellJacobianBatch::computeInverses() const 
00180 {
00181   TimeMonitor timer(jacobianInversionTimer());
00182   if (hasInverses_) return;
00183 
00184   Tabs tabs;
00185   SUNDANCE_OUT(this->verb() > 2,
00186                tabs << "inverting Jacobians");
00187 
00188   invJ_.resize(spatialDim_*spatialDim_*numQuad_*numCells_);
00189 
00190   if (!isFactored_) factor();
00191   
00192   for (int cell=0; cell<numCells_; cell++)
00193     {
00194       for (int q=0; q<numQuad_; q++)
00195         {
00196           int start = (cell*numQuad_ + q)*jSize_;
00197 
00198           /* pointer to start of J for this cell */
00199           double* jFactPtr = &(J_[start]);
00200           double* invJPtr = &(invJ_[start]);
00201           int* iPiv = &(iPiv_[(q + cell*numQuad_)*spatialDim_]);
00202   
00203           int info = 0; // error return flag, will be zero if successful. 
00204           
00205           /* fill the inverse of J with the identity */
00206           for (int i=0; i<spatialDim_; i++)
00207             {
00208               for (int j=0; j<spatialDim_; j++)
00209                 {
00210                   if (i==j) invJPtr[i*spatialDim_+j] = 1.0;
00211                   else invJPtr[i*spatialDim_+j] = 0.0;
00212                 }
00213             }
00214 
00215           ::dgetrs_("N",  &spatialDim_,  &spatialDim_, jFactPtr, 
00216                      &spatialDim_, iPiv, invJPtr,  &spatialDim_, &info);
00217           
00218           TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
00219                              "CellJacobianBatch::setJacobian(): inversion failed");
00220         }
00221     }
00222   addFlops(numCells_ * spatialDim_ * spatialDim_);
00223   hasInverses_ = true;
00224 }
00225 
00226 void CellJacobianBatch::applyInvJ(int cell, int q, 
00227                                   double* rhs, int nRhs, bool trans) const 
00228 {
00229   if (!isFactored_) factor();
00230 
00231   double* jFactPtr = &(J_[(cell*numQuad_ + q)*spatialDim_*spatialDim_]);
00232   int* iPiv = &(iPiv_[(q + cell*numQuad_)*spatialDim_]);
00233 
00234   int info = 0; // error return flag, will be zero if successful. 
00235   
00236   if (trans)
00237     {
00238       ::dgetrs_("T",  &spatialDim_, &nRhs, jFactPtr,  &spatialDim_, 
00239                 iPiv, rhs,  &spatialDim_, &info);
00240     }
00241   else
00242     {
00243       ::dgetrs_("N",  &spatialDim_, &nRhs, jFactPtr,  &spatialDim_, 
00244                 iPiv, rhs,  &spatialDim_, &info);
00245     }
00246 
00247   addFlops(numCells_ * spatialDim_ * spatialDim_ * nRhs);          
00248   TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
00249                      "CellJacobianBatch::applyInvJ(): backsolve failed");
00250 }
00251 
00252 void CellJacobianBatch::getInvJ(int cell, int quad, Array<double>& invJ) const 
00253 {
00254   if (!hasInverses_) computeInverses();
00255   
00256   int start = (cell*numQuad_ + quad)*jSize_;
00257   
00258   invJ.resize(spatialDim_*spatialDim_);
00259 
00260   for (int col=0; col<spatialDim_; col++)
00261     {
00262       for (int row=0; row<spatialDim_; row++) 
00263         {
00264           invJ[col + spatialDim_*row] = invJ_[start + col + spatialDim_*row];
00265         }
00266     }
00267 }
00268 
00269 void CellJacobianBatch::print(std::ostream& os) const
00270 {
00271   if (!hasInverses_) computeInverses();
00272 
00273   for (int c=0; c<numCells_; c++)
00274     {
00275       os << "cell " << c << std::endl;
00276       for (int q=0; q<numQuad_; q++)
00277         {
00278           int start = (c*numQuad_ + q)*jSize_;
00279           if (numQuad_ > 1) os << "q=" << q << " ";
00280           os << "{";
00281           for (int i=0; i<spatialDim_; i++)
00282             {
00283               if (i != 0) os << ", ";
00284               os << "{";
00285               for (int j=0; j<spatialDim_; j++)
00286                 {
00287                   if (j != 0) os << ", ";
00288                   os << invJ_[start + i*spatialDim_ + j];
00289                 }
00290               os << "}";
00291             }
00292           os << "}" << std::endl;
00293         }
00294       
00295     }
00296 }
00297 
00298 

Site Contact