ExampleTridiagSpmdLinearOp.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_EXAMPLE_TRIDIAG_SPMD_LINEAR_OP_HPP
00030 #define THYRA_EXAMPLE_TRIDIAG_SPMD_LINEAR_OP_HPP
00031 
00032 #include "Thyra_SpmdLinearOpBase.hpp"
00033 #include "Teuchos_DefaultComm.hpp"
00034 #include "Teuchos_CommHelpers.hpp"
00035 
00133 template<class Scalar>
00134 class ExampleTridiagSpmdLinearOp : public Thyra::SpmdLinearOpBase<Scalar> {
00135 private:
00136 
00137   Teuchos::RCP<const Teuchos::Comm<Thyra::Index> >  comm_;
00138   int                  procRank_;
00139   int                  numProcs_;
00140   Thyra::Index         localDim_;
00141   std::vector<Scalar>  lower_;   // size = ( procRank == 0         ? localDim - 1 : localDim )    
00142   std::vector<Scalar>  diag_;    // size = localDim
00143   std::vector<Scalar>  upper_;   // size = ( procRank == numProc-1 ? localDim - 1 : localDim )
00144 
00145   void communicate( const bool first, const bool last, const Scalar x[], Scalar *x_km1, Scalar *x_kp1 ) const;
00146 
00147 public:
00148 
00150   using Thyra::SpmdLinearOpBase<Scalar>::euclideanApply;
00151 
00153   ExampleTridiagSpmdLinearOp() : procRank_(0), numProcs_(0) {}
00154 
00156   ExampleTridiagSpmdLinearOp(
00157     const Teuchos::RCP<const Teuchos::Comm<Thyra::Index> > &comm
00158     ,const Thyra::Index localDim, const Scalar lower[], const Scalar diag[], const Scalar upper[] )
00159     { this->initialize(comm,localDim,lower,diag,upper); }
00160   
00180   void initialize(
00181     const Teuchos::RCP<const Teuchos::Comm<Thyra::Index> > &comm
00182     ,const Thyra::Index             localDim // >= 2
00183     ,const Scalar                   lower[]  // size == ( procRank == 0         ? localDim - 1 : localDim )
00184     ,const Scalar                   diag[]   // size == localDim
00185     ,const Scalar                   upper[]  // size == ( procRank == numProc-1 ? localDim - 1 : localDim )
00186     )
00187     {
00188       TEST_FOR_EXCEPT( localDim < 2 );
00189       this->setLocalDimensions(comm,localDim,localDim); // Needed to set up range() and domain()
00190       comm_  = Teuchos::DefaultComm<Thyra::Index>::getDefaultSerialComm(comm);
00191       localDim_ = localDim;
00192       numProcs_ = comm->getSize();
00193       procRank_ = comm->getRank();
00194       const Thyra::Index
00195         lowerDim = ( procRank_ == 0           ? localDim - 1 : localDim ),
00196         upperDim = ( procRank_ == numProcs_-1 ? localDim - 1 : localDim );
00197       lower_.resize(lowerDim);  for( int k = 0; k < lowerDim; ++k ) lower_[k] = lower[k];
00198       diag_.resize(localDim);   for( int k = 0; k < localDim; ++k ) diag_[k]  = diag[k];
00199       upper_.resize(upperDim);  for( int k = 0; k < upperDim; ++k ) upper_[k] = upper[k];
00200     }
00201 
00202   // Overridden form Teuchos::Describable */
00203 
00204   std::string description() const
00205     {
00206       return (std::string("ExampleTridiagSpmdLinearOp<") + Teuchos::ScalarTraits<Scalar>::name() + std::string(">"));
00207     }
00208 
00209 protected:
00210 
00211 
00212   // Overridden from SingleScalarEuclideanLinearOpBase
00213 
00214   bool opSupported( Thyra::EOpTransp M_trans ) const
00215     {
00216       typedef Teuchos::ScalarTraits<Scalar> ST;
00217       return (M_trans == Thyra::NOTRANS || (!ST::isComplex && M_trans == Thyra::CONJ) );
00218     }
00219 
00220   // Overridden from SerialLinearOpBase
00221 
00222   void euclideanApply(
00223     const Thyra::EOpTransp                         M_trans
00224     ,const RTOpPack::ConstSubVectorView<Scalar>  &local_x_in
00225     ,const RTOpPack::SubVectorView<Scalar>       *local_y_out
00226     ,const Scalar                                alpha
00227     ,const Scalar                                beta
00228     ) const
00229     {
00230       typedef Teuchos::ScalarTraits<Scalar> ST;
00231       TEST_FOR_EXCEPTION( M_trans != Thyra::NOTRANS, std::logic_error, "Error, can not handle transpose!" );
00232       // Get constants
00233       const Scalar zero = ST::zero();
00234       // Get raw pointers to vector data to make me feel better!
00235       const Scalar *x = local_x_in.values().get();
00236       Scalar       *y = local_y_out->values().get();
00237       // Determine what process we are
00238       const bool first = ( procRank_ == 0 ), last = ( procRank_ == numProcs_-1 );
00239       // Communicate ghost elements
00240       Scalar x_km1, x_kp1;
00241       communicate( first, last, x, &x_km1, &x_kp1 );
00242       // Perform operation (if beta==0 then we must be careful since y could be uninitialized on input!)
00243       Thyra::Index k = 0, lk = 0;
00244       if( beta == zero ) {
00245         y[k] = alpha * ( (first?zero:lower_[lk]*x_km1) + diag_[k]*x[k] + upper_[k]*x[k+1] ); if(!first) ++lk;             // First local row
00246         for( k = 1; k < localDim_ - 1; ++lk, ++k )
00247           y[k] = alpha * ( lower_[lk]*x[k-1] + diag_[k]*x[k] + upper_[k]*x[k+1] );                                        // Middle local rows
00248         y[k] = alpha * ( lower_[lk]*x[k-1] + diag_[k]*x[k] + (last?zero:upper_[k]*x_kp1) );                               // Last local row
00249       }
00250       else {
00251         y[k] = alpha * ( (first?zero:lower_[lk]*x_km1) + diag_[k]*x[k] + upper_[k]*x[k+1] ) + beta*y[k]; if(!first) ++lk; // First local row
00252         for( k = 1; k < localDim_ - 1; ++lk, ++k )
00253           y[k] = alpha * ( lower_[lk]*x[k-1] + diag_[k]*x[k] + upper_[k]*x[k+1] ) + beta*y[k];                            // Middle local rows
00254         y[k] = alpha * ( lower_[lk]*x[k-1] + diag_[k]*x[k] + (last?zero:upper_[k]*x_kp1) ) + beta*y[k];                   // Last local row
00255       }
00256       //std::cout << "\ny = ["; for(k=0;k<localDim_;++k) { std::cout << y[k]; if(k<localDim_-1) std::cout << ","; } std::cout << "]\n";
00257     }
00258 
00259 };  // end class ExampleTridiagSpmdLinearOp
00260 
00261 // private
00262 
00263 template<class Scalar>
00264 void ExampleTridiagSpmdLinearOp<Scalar>::communicate(
00265   const bool first, const bool last, const Scalar x[], Scalar *x_km1, Scalar *x_kp1
00266   ) const
00267 {
00268   const bool isEven = (procRank_ % 2 == 0);
00269   const bool isOdd = !isEven;
00270   // 1) Send x[localDim_-1] from each even process forward to the next odd
00271   // process where it is received in x_km1.
00272   if( isEven && procRank_+1 < numProcs_ ) send(*comm_,x[localDim_-1],procRank_+1);
00273   if( isOdd && procRank_-1 >= 0 )         receive(*comm_,procRank_-1,x_km1);
00274   // 2) Send x[0] from each odd process backward to the previous even
00275   // process where it is received in x_kp1.
00276   if( isOdd && procRank_-1 >= 0 )         send(*comm_,x[0],procRank_-1);
00277   if( isEven && procRank_+1 < numProcs_ ) receive(*comm_,procRank_+1,x_kp1);
00278   // 3) Send x[localDim_-1] from each odd process forward to the next even
00279   // process where it is received in x_km1.
00280   if( isOdd && procRank_+1 < numProcs_ )  send(*comm_,x[localDim_-1],procRank_+1);
00281   if( isEven && procRank_-1 >= 0 )        receive(*comm_,procRank_-1,x_km1);
00282   // 4) Send x[0] from each even process backward to the previous odd
00283   // process where it is received in x_kp1.
00284   if(isEven && procRank_-1 >= 0 )         send(*comm_,x[0],procRank_-1);
00285   if(isOdd && procRank_+1 < numProcs_ )   receive(*comm_,procRank_+1,x_kp1);
00286 }
00287 
00288 #endif  // THYRA_EXAMPLE_TRIDIAG_SPMD_LINEAR_OP_HPP

Generated on Wed May 12 21:26:53 2010 for Thyra Operator/Vector Support by  doxygen 1.4.7