Thyra_DefaultBlockedTriangularLinearOpWithSolve.hpp

00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //    Thyra: Interfaces and Support for Abstract Numerical Algorithms
00005 //                 Copyright (2004) 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 Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 #ifndef THYRA_DEFAULT_BLOCKED_TRIANGULAR_LINEAR_OP_WITH_SOLVE_HPP
00030 #define THYRA_DEFAULT_BLOCKED_TRIANGULAR_LINEAR_OP_WITH_SOLVE_HPP
00031 
00032 
00033 #include "Thyra_DefaultBlockedTriangularLinearOpWithSolveDecl.hpp"
00034 
00035 
00036 namespace Thyra {
00037 
00038 
00039 // public
00040 
00041 
00042 // Constructors
00043 
00044 
00045 template<class Scalar>
00046 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::DefaultBlockedTriangularLinearOpWithSolve()
00047   : blockFillIsActive_(false), numDiagBlocks_(0)
00048 {}
00049 
00050 
00051 // Overridden from PhysicallyBlockedLinearOpWithSolveBase
00052 
00053 
00054 template<class Scalar>
00055 bool DefaultBlockedTriangularLinearOpWithSolve<Scalar>::acceptsLOWSBlock(
00056   const int i, const int j
00057   ) const
00058 {
00059   assertBlockFillIsActive(true);
00060   assertBlockRowCol(i,j);
00061   return i==j; // Only accept LOWS blocks along the diagonal!
00062 }
00063 
00064 template<class Scalar>
00065 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::setNonconstLOWSBlock(
00066   const int i, const int j,
00067   const Teuchos::RCP<LinearOpWithSolveBase<Scalar> > &block
00068   )
00069 {
00070   setLOWSBlockImpl(i,j,block);
00071 }
00072 
00073 
00074 template<class Scalar>
00075 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::setLOWSBlock(
00076   const int i, const int j,
00077   const Teuchos::RCP<const LinearOpWithSolveBase<Scalar> > &block
00078   )
00079 {
00080   setLOWSBlockImpl(i,j,block);
00081 }
00082 
00083 
00084 // Overridden from PhysicallyBlockedLinearOpBase
00085 
00086 
00087 template<class Scalar>
00088 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::beginBlockFill()
00089 {
00090  assertBlockFillIsActive(false);
00091   TEST_FOR_EXCEPT("ToDo: Have not implemented flexible block fill yet!");
00092 }
00093 
00094 
00095 template<class Scalar>
00096 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::beginBlockFill(
00097   const int numRowBlocks, const int numColBlocks
00098   )
00099 {
00100   assertBlockFillIsActive(false);
00101   TEST_FOR_EXCEPT("ToDo: Have not implemented block fill with just numBlocks yet!!");
00102 }
00103 
00104 
00105 template<class Scalar>
00106 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::beginBlockFill(
00107   const Teuchos::RCP<const ProductVectorSpaceBase<Scalar> >  &productRange,
00108   const Teuchos::RCP<const ProductVectorSpaceBase<Scalar> > &productDomain
00109   )
00110 {
00111   assertBlockFillIsActive(false);
00112   TEST_FOR_EXCEPT( is_null(productRange) );
00113   TEST_FOR_EXCEPT( is_null(productDomain) );
00114   TEST_FOR_EXCEPT( productRange->numBlocks() != productDomain->numBlocks() );
00115   productRange_ = productRange.assert_not_null();
00116   productDomain_ = productDomain.assert_not_null();
00117   numDiagBlocks_ = productRange->numBlocks();
00118   diagonalBlocks_.resize(numDiagBlocks_);
00119   blockFillIsActive_ = true;
00120 }
00121 
00122 
00123 template<class Scalar>
00124 bool DefaultBlockedTriangularLinearOpWithSolve<Scalar>::blockFillIsActive() const
00125 {
00126   return blockFillIsActive_;
00127 }
00128 
00129 
00130 template<class Scalar>
00131 bool DefaultBlockedTriangularLinearOpWithSolve<Scalar>::acceptsBlock(
00132   const int i, const int j
00133   ) const
00134 {
00135   assertBlockFillIsActive(true);
00136   assertBlockRowCol(i,j);
00137   return false; // ToDo: Change this once we accept off-diagonal blocks
00138 }
00139 
00140 
00141 template<class Scalar>
00142 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::setNonconstBlock(
00143   const int i, const int j,
00144   const Teuchos::RCP<LinearOpBase<Scalar> > &block
00145   )
00146 {
00147   assertBlockFillIsActive(true);
00148   TEST_FOR_EXCEPT("Error, we don't support off-diagonal LOB objects yet!");
00149 }
00150 
00151 
00152 template<class Scalar>
00153 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::setBlock(
00154   const int i, const int j,
00155   const Teuchos::RCP<const LinearOpBase<Scalar> > &block
00156   )
00157 {
00158   assertBlockFillIsActive(true);
00159   TEST_FOR_EXCEPT("Error, we don't support off-diagonal LOB objects yet!");
00160 }
00161 
00162 
00163 template<class Scalar>
00164 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::endBlockFill()
00165 {
00166   assertBlockFillIsActive(true);
00167   for ( int k = 0; k < numDiagBlocks_; ++k ) {
00168     TEST_FOR_EXCEPTION(
00169       is_null(diagonalBlocks_[k].getConstObj()), std::logic_error,
00170       "Error, the block diagonal k="<<k<<" can not be null when ending block fill!"
00171       );
00172   }
00173   blockFillIsActive_ = false;
00174 }
00175 
00176 
00177 template<class Scalar>
00178 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::uninitialize()
00179 {
00180   assertBlockFillIsActive(false);
00181   productRange_ = Teuchos::null;
00182   productDomain_ = Teuchos::null;
00183   numDiagBlocks_ = 0;
00184   diagonalBlocks_.resize(0);
00185 }
00186 
00187 
00188 // Overridden from BlockedLinearOpWithSolveBase
00189 
00190 
00191 template<class Scalar>
00192 Teuchos::RCP<LinearOpWithSolveBase<Scalar> >
00193 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::getNonconstLOWSBlock(
00194   const int i, const int j
00195   )
00196 {
00197   assertBlockFillIsActive(false);
00198   assertBlockRowCol(i,j);
00199   if (i!=j)
00200     return Teuchos::null;
00201   return diagonalBlocks_[i].getNonconstObj();
00202 } 
00203 
00204 
00205 template<class Scalar>
00206 Teuchos::RCP<const LinearOpWithSolveBase<Scalar> >
00207 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::getLOWSBlock(
00208   const int i, const int j
00209   ) const
00210 {
00211   assertBlockFillIsActive(false);
00212   assertBlockRowCol(i,j);
00213   if (i!=j)
00214     return Teuchos::null;
00215   return diagonalBlocks_[i].getConstObj();
00216 }
00217 
00218 
00219 // Overridden from BlockedLinearOpBase
00220 
00221 
00222 template<class Scalar>
00223 Teuchos::RCP<const ProductVectorSpaceBase<Scalar> >
00224 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::productRange() const
00225 {
00226   return productRange_;
00227 }
00228 
00229 
00230 template<class Scalar>
00231 Teuchos::RCP<const ProductVectorSpaceBase<Scalar> >
00232 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::productDomain() const
00233 {
00234   return productDomain_;
00235 }
00236 
00237 
00238 template<class Scalar>
00239 bool DefaultBlockedTriangularLinearOpWithSolve<Scalar>::blockExists(
00240   const int i, const int j
00241   ) const
00242 {
00243   assertBlockFillIsActive(false);
00244   assertBlockRowCol(i,j);
00245   if (i!=j)
00246     return false; // ToDo: Update this when off-diagonals are supported!
00247   return !is_null(diagonalBlocks_[i].getConstObj());
00248 } 
00249 
00250 
00251 template<class Scalar>
00252 bool DefaultBlockedTriangularLinearOpWithSolve<Scalar>::blockIsConst(
00253   const int i, const int j
00254   ) const
00255 {
00256   assertBlockFillIsActive(true);
00257   assertBlockRowCol(i,j);
00258   return diagonalBlocks_[i].isConst();
00259 } 
00260 
00261 
00262 template<class Scalar>
00263 Teuchos::RCP<LinearOpBase<Scalar> >
00264 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::getNonconstBlock(
00265   const int i, const int j
00266   )
00267 {
00268   assertBlockFillIsActive(true);
00269   assertBlockRowCol(i,j);
00270   if (i!=j)
00271     return Teuchos::null; // ToDo: Update when off-diagonals are supported!
00272   return this->getNonconstLOWSBlock(i,j);
00273 } 
00274 
00275 
00276 template<class Scalar>
00277 Teuchos::RCP<const LinearOpBase<Scalar> >
00278 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::getBlock(
00279   const int i, const int j
00280   ) const
00281 {
00282   assertBlockFillIsActive(true);
00283   assertBlockRowCol(i,j);
00284   if (i!=j)
00285     return Teuchos::null; // ToDo: Update when off-diagonals are supported!
00286   return this->getLOWSBlock(i,j);
00287 } 
00288 
00289 
00290 // Overridden from LinearOpBase
00291 
00292 
00293 template<class Scalar>
00294 Teuchos::RCP< const VectorSpaceBase<Scalar> >
00295 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::range() const
00296 {
00297   return this->productRange();
00298 }
00299 
00300 
00301 template<class Scalar>
00302 Teuchos::RCP< const VectorSpaceBase<Scalar> >
00303 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::domain() const
00304 {
00305   return this->productDomain();
00306 }
00307 
00308 
00309 template<class Scalar>
00310 Teuchos::RCP<const LinearOpBase<Scalar> >
00311 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::clone() const
00312 {
00313   return Teuchos::null;  // ToDo: Implement clone when needed!
00314 }
00315 
00316 
00317 // Overridden from Teuchos::Describable
00318 
00319                                                 
00320 template<class Scalar>
00321 std::string
00322 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::description() const
00323 {
00324   typedef Teuchos::ScalarTraits<Scalar>  ST;
00325   assertBlockFillIsActive(false);
00326   std::ostringstream oss;
00327   oss
00328     << Teuchos::Describable::description() << "{"
00329     << "numDiagBlocks="<<numDiagBlocks_
00330     << "}";
00331   return oss.str();
00332 }
00333 
00334 
00335 template<class Scalar>
00336 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::describe(
00337   Teuchos::FancyOStream &out,
00338   const Teuchos::EVerbosityLevel verbLevel
00339   ) const
00340 {
00341   assertBlockFillIsActive(false);
00342   Teuchos::Describable::describe(out,verbLevel);
00343   // ToDo: Fill in a better version of this!
00344 }
00345 
00346 
00347 // protected
00348 
00349 
00350 // Overridden from SingleScalarLinearOpWithSolveBase
00351 
00352 
00353 template<class Scalar>
00354 bool DefaultBlockedTriangularLinearOpWithSolve<Scalar>::solveSupportsTrans(
00355   ETransp M_trans
00356   ) const
00357 {
00358   assertBlockFillIsActive(false);
00359   for ( int k = 0; k < numDiagBlocks_; ++k ) {
00360     if ( !solveSupports( *diagonalBlocks_[k].getConstObj(), M_trans ) )
00361       return false;
00362   }
00363   return true;
00364   // ToDo: To be safe we really should do a collective reduction of all
00365   // clusters of processes.  However, for the typical use case, every block
00366   // will return the same info and we should be safe!
00367 }
00368 
00369 
00370 template<class Scalar>
00371 bool
00372 DefaultBlockedTriangularLinearOpWithSolve<Scalar>::solveSupportsSolveMeasureType(
00373   ETransp M_trans, const SolveMeasureType& solveMeasureType
00374   ) const
00375 {
00376   using Thyra::solveSupportsSolveMeasureType;
00377   assertBlockFillIsActive(false);
00378   for ( int k = 0; k < numDiagBlocks_; ++k ) {
00379     if (
00380       !solveSupportsSolveMeasureType(
00381         *diagonalBlocks_[k].getConstObj(),
00382         M_trans, solveMeasureType
00383         )
00384       )
00385     {
00386       return false;
00387     }
00388   }
00389   return true;
00390   // ToDo: To be safe we really should do a collective reduction of all
00391   // clusters of processes.  However, for the typical use case, every block
00392   // will return the same info and we should be safe!
00393 }
00394 
00395 
00396 template<class Scalar>
00397 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::solve(
00398   const ETransp M_trans,
00399   const MultiVectorBase<Scalar> &B_in,
00400   MultiVectorBase<Scalar> *X_inout,
00401   const int numBlocks,
00402   const BlockSolveCriteria<Scalar> blockSolveCriteria[],
00403   SolveStatus<Scalar> blockSolveStatus[]
00404   ) const
00405 {
00406 
00407   using Teuchos::RCP;
00408   using Teuchos::dyn_cast;
00409   typedef Teuchos::ScalarTraits<Scalar> ST;
00410   using Thyra::solve;
00411 
00412 #ifdef TEUCHOS_DEBUG
00413   TEST_FOR_EXCEPT(0==X_inout);
00414   THYRA_ASSERT_LINEAR_OP_MULTIVEC_APPLY_SPACES(
00415     "DefaultBlockedTriangularLinearOpWithSolve<Scalar>::apply(...)",*this,M_trans,*X_inout,&B_in
00416     );
00417   TEST_FOR_EXCEPT(!this->solveSupportsTrans(M_trans));
00418   TEST_FOR_EXCEPT( numBlocks > 1 );
00419   TEST_FOR_EXCEPTION(
00420     blockSolveCriteria && !blockSolveCriteria[0].solveCriteria.solveMeasureType.useDefault(),
00421     std::logic_error,
00422     "Error, we can't handle any non-default solve criteria yet!"
00423     );
00424   // ToDo: If solve criteria is to be handled, then we will have to be very
00425   // carefull how it it interpreted in terms of the individual period solves!
00426 #endif // TEUCHOS_DEBUG  
00427 
00428   //
00429   // Y = alpha * inv(op(M)) * X + beta*Y
00430   //
00431   // =>
00432   //
00433   // X[i] = inv(op(Op[i]))*B[i], for i=0...numDiagBlocks-1
00434   //
00435   // ToDo: Update to handle off diagonal blocks when needed!
00436   //
00437 
00438   const ProductMultiVectorBase<Scalar>
00439     &B = dyn_cast<const ProductMultiVectorBase<Scalar> >(B_in);
00440   ProductMultiVectorBase<Scalar>
00441     &X = dyn_cast<ProductMultiVectorBase<Scalar> >(*X_inout);
00442   
00443   for ( int i = 0; i < numDiagBlocks_; ++ i ) {
00444     Thyra::solve( *diagonalBlocks_[i].getConstObj(), M_trans,
00445       *B.getMultiVectorBlock(i),
00446       &*X.getNonconstMultiVectorBlock(i)
00447       );
00448     // ToDo: Pass in solve criteria when needed!
00449   }
00450 
00451   // ToDo: We really need to collect the SolveStatus objects across clusters
00452   // in order to really implement this interface correctly!  If a solve fails
00453   // on some cluster but not another, then different solve status information
00454   // will be returned.  This may result in different decisions being taken in
00455   // different clusters with bad consequences.  To really handle multiple
00456   // clusters correctly, we need a strategy object that knows how to do these
00457   // reductions correctly.  Actually, would could use Teuchos:Comm along with
00458   // a user-defined reduction object to do these reductions correctly!
00459 
00460 }
00461 
00462 
00463 // Overridden from SingleScalarLinearOpBase
00464 
00465 
00466 template<class Scalar>
00467 bool DefaultBlockedTriangularLinearOpWithSolve<Scalar>::opSupported(
00468   ETransp M_trans
00469   ) const
00470 {
00471   using Thyra::opSupported;
00472   assertBlockFillIsActive(false);
00473   for ( int k = 0; k < numDiagBlocks_; ++k ) {
00474     if ( !opSupported(*diagonalBlocks_[k].getConstObj(),M_trans) )
00475       return false;
00476   }
00477   return true;
00478   // ToDo: To be safe we really should do a collective reduction of all
00479   // clusters of processes.  However, for the typical use case, every block
00480   // will return the same info and we should be safe!
00481 }
00482 
00483 
00484 template<class Scalar>
00485 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::apply(
00486   const ETransp M_trans,
00487   const MultiVectorBase<Scalar> &X_in,
00488   MultiVectorBase<Scalar> *Y_inout,
00489   const Scalar alpha,
00490   const Scalar beta
00491   ) const
00492 {
00493 
00494   using Teuchos::RCP;
00495   using Teuchos::dyn_cast;
00496   typedef Teuchos::ScalarTraits<Scalar> ST;
00497   using Thyra::apply;
00498 
00499 #ifdef TEUCHOS_DEBUG
00500   THYRA_ASSERT_LINEAR_OP_MULTIVEC_APPLY_SPACES(
00501     "DefaultBlockedTriangularLinearOpWithSolve<Scalar>::apply(...)",*this,M_trans,X_in,Y_inout
00502     );
00503 #endif // TEUCHOS_DEBUG  
00504 
00505   //
00506   // Y = alpha * op(M) * X + beta*Y
00507   //
00508   // =>
00509   //
00510   // Y[i] = beta+Y[i] + alpha*op(Op)[i]*X[i], for i=0...numDiagBlocks-1
00511   //
00512   // ToDo: Update to handle off diagonal blocks when needed!
00513   //
00514 
00515   const ProductMultiVectorBase<Scalar>
00516     &X = dyn_cast<const ProductMultiVectorBase<Scalar> >(X_in);
00517   ProductMultiVectorBase<Scalar>
00518     &Y = dyn_cast<ProductMultiVectorBase<Scalar> >(*Y_inout);
00519   
00520   for ( int i = 0; i < numDiagBlocks_; ++ i ) {
00521     Thyra::apply( *diagonalBlocks_[i].getConstObj(), M_trans,
00522       *X.getMultiVectorBlock(i),
00523       &*Y.getNonconstMultiVectorBlock(i)
00524       );
00525   }
00526 
00527 }
00528 
00529 
00530 // private
00531 
00532 
00533 template<class Scalar>
00534 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::assertBlockFillIsActive(
00535   bool blockFillIsActive
00536   ) const
00537 {
00538 #ifdef TEUCHOS_DEBUG
00539   TEST_FOR_EXCEPT(!(blockFillIsActive_==blockFillIsActive));
00540 #endif
00541 }
00542 
00543 
00544 template<class Scalar>
00545 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::assertBlockRowCol(
00546   const int i, const int j
00547   ) const
00548 {
00549 #ifdef TEUCHOS_DEBUG
00550   TEST_FOR_EXCEPTION(
00551     !( 0 <= i && i < numDiagBlocks_ ), std::logic_error,
00552     "Error, i="<<i<<" does not fall in the range [0,"<<numDiagBlocks_-1<<"]!"
00553       );
00554   TEST_FOR_EXCEPTION(
00555     !( 0 <= j && j < numDiagBlocks_ ), std::logic_error,
00556     "Error, j="<<j<<" does not fall in the range [0,"<<numDiagBlocks_-1<<"]!"
00557       );
00558 #endif
00559 }
00560 
00561 
00562 template<class Scalar>
00563 template<class LinearOpWithSolveType>
00564 void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::setLOWSBlockImpl(
00565   const int i, const int j,
00566   const Teuchos::RCP<LinearOpWithSolveType> &block
00567   )
00568 {
00569   assertBlockFillIsActive(true);
00570   TEST_FOR_EXCEPTION(
00571     !this->acceptsLOWSBlock(i,j), std::logic_error,
00572     "Error, this DefaultBlockedTriangularLinearOpWithSolve does not accept\n"
00573     "LOWSB objects for the block i="<<i<<", j="<<j<<"!"
00574     );
00575   diagonalBlocks_[i] = block;
00576 }
00577 
00578 
00579 
00580 } // namespace Thyra
00581 
00582 
00583 #endif  // THYRA_DEFAULT_BLOCKED_TRIANGULAR_LINEAR_OP_WITH_SOLVE_HPP

Generated on Tue Oct 20 12:47:11 2009 for Thyra Operator Solve Support by doxygen 1.4.7