Thyra_MPIVectorBase.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_MPI_VECTOR_BASE_HPP
00030 #define THYRA_MPI_VECTOR_BASE_HPP
00031 
00032 #include "Thyra_MPIVectorBaseDecl.hpp"
00033 #include "Thyra_MPIVectorSpaceBase.hpp"
00034 #include "RTOp_parallel_helpers.h"
00035 #include "RTOpPack_MPI_apply_op.hpp"
00036 #include "Teuchos_Workspace.hpp"
00037 #include "Teuchos_TestForException.hpp"
00038 #include "Teuchos_dyn_cast.hpp"
00039 
00040 namespace Thyra {
00041 
00042 template<class Scalar>
00043 MPIVectorBase<Scalar>::MPIVectorBase()
00044   :in_applyOp_(false)
00045   ,globalDim_(0)
00046   ,localOffset_(-1)
00047   ,localSubDim_(0)
00048 {}
00049 
00050 // Virtual methods with default implementations
00051 
00052 template<class Scalar>
00053 void MPIVectorBase<Scalar>::getLocalData( const Scalar** values, Index* stride ) const
00054 {
00055   const_cast<MPIVectorBase<Scalar>*>(this)->getLocalData(const_cast<Scalar**>(values),stride);
00056 }
00057 
00058 template<class Scalar>
00059 void MPIVectorBase<Scalar>::freeLocalData( const Scalar* values ) const
00060 {
00061   const_cast<MPIVectorBase<Scalar>*>(this)->commitLocalData(const_cast<Scalar*>(values));
00062 }
00063 
00064 // Overridden from VectorBase
00065 
00066 template<class Scalar>
00067 Teuchos::RefCountPtr<const VectorSpaceBase<Scalar> >
00068 MPIVectorBase<Scalar>::space() const
00069 {
00070   return mpiSpace();
00071 }
00072 
00073 template<class Scalar>
00074 void MPIVectorBase<Scalar>::applyOp(
00075   const RTOpPack::RTOpT<Scalar>   &op
00076   ,const int                      num_vecs
00077   ,const VectorBase<Scalar>*      vecs[]
00078   ,const int                      num_targ_vecs
00079   ,VectorBase<Scalar>*            targ_vecs[]
00080   ,RTOpPack::ReductTarget         *reduct_obj
00081   ,const Index                    first_ele_in
00082   ,const Index                    sub_dim_in
00083   ,const Index                    global_offset_in
00084   ) const
00085 {
00086   using Teuchos::dyn_cast;
00087   using Teuchos::Workspace;
00088   Teuchos::WorkspaceStore* wss = Teuchos::get_default_workspace_store().get();
00089   const MPIVectorSpaceBase<Scalar> &mpiSpc = *mpiSpace();
00090 #ifdef _DEBUG
00091   // ToDo: Validate input!
00092   TEST_FOR_EXCEPTION(
00093     in_applyOp_, std::invalid_argument
00094     ,"MPIVectorBase<>::applyOp(...): Error, this method is being entered recursively which is a "
00095     "clear sign that one of the methods getSubVector(...), freeSubVector(...) or commitSubVector(...) "
00096     "was not implemented properly!"
00097     );
00098   Thyra::apply_op_validate_input(
00099     "MPIVectorBase<>::applyOp(...)",*space()
00100     ,op,num_vecs,vecs,num_targ_vecs,targ_vecs,reduct_obj,first_ele_in,sub_dim_in,global_offset_in
00101     );
00102 #endif
00103   // Flag that we are in applyOp()
00104   in_applyOp_ = true;
00105   // First see if this is a locally replicated vector in which case
00106   // we treat this as a local operation only.
00107   const bool locallyReplicated = (localSubDim_ == globalDim_);
00108   // Get the overlap in the current process with the input logical sub-vector
00109   // from (first_ele_in,sub_dim_in,global_offset_in)
00110   RTOp_index_type  overlap_first_local_ele  = 0;
00111   RTOp_index_type  overalap_local_sub_dim   = 0;
00112   RTOp_index_type  overlap_global_offset    = 0;
00113   RTOp_parallel_calc_overlap(
00114     globalDim_, localSubDim_, localOffset_, first_ele_in, sub_dim_in, global_offset_in
00115     ,&overlap_first_local_ele, &overalap_local_sub_dim, &overlap_global_offset
00116     );
00117   const Range1D local_rng = (
00118     overlap_first_local_ele!=0
00119     ? Range1D( localOffset_ + overlap_first_local_ele, localOffset_ + overlap_first_local_ele + overalap_local_sub_dim - 1 )
00120     : Range1D::Invalid
00121     );
00122   // Create sub-vector views of all of the *participating* local data
00123   Workspace<RTOpPack::SubVectorT<Scalar> > sub_vecs(wss,num_vecs);
00124   Workspace<RTOpPack::MutableSubVectorT<Scalar> > sub_targ_vecs(wss,num_targ_vecs);
00125   if( overlap_first_local_ele != 0 ) {
00126     if(1){for(int k = 0; k < num_vecs; ++k ) {
00127       vecs[k]->getSubVector( local_rng, &sub_vecs[k] );
00128       sub_vecs[k].setGlobalOffset( overlap_global_offset );
00129     }}
00130     if(1){for(int k = 0; k < num_targ_vecs; ++k ) {
00131       targ_vecs[k]->getSubVector( local_rng, &sub_targ_vecs[k] );
00132       sub_targ_vecs[k].setGlobalOffset( overlap_global_offset );
00133     }}
00134   }
00135   // Apply the RTOp operator object (all processors must participate)
00136   RTOpPack::MPI_apply_op(
00137     locallyReplicated ? MPI_COMM_NULL : mpiSpc.mpiComm()                   // comm
00138     ,op                                                                    // op
00139     ,-1                                                                    // root_rank (perform an all-reduce)
00140     ,num_vecs                                                              // num_vecs
00141     ,num_vecs && overlap_first_local_ele ? &sub_vecs[0] : NULL             // sub_vecs
00142     ,num_targ_vecs                                                         // num_targ_vecs
00143     ,num_targ_vecs && overlap_first_local_ele ? &sub_targ_vecs[0] : NULL   // targ_sub_vecs
00144     ,reduct_obj                                                            // reduct_obj
00145     );
00146   // Free and commit the local data
00147   if( overlap_first_local_ele != 0 ) {
00148     if(1){for(int k = 0; k < num_vecs; ++k ) {
00149       sub_vecs[k].setGlobalOffset(local_rng.lbound()-1);
00150       vecs[k]->freeSubVector( &sub_vecs[k] );
00151     }}
00152     if(1){for(int k = 0; k < num_targ_vecs; ++k ) {
00153       sub_targ_vecs[k].setGlobalOffset(local_rng.lbound()-1);
00154       targ_vecs[k]->commitSubVector( &sub_targ_vecs[k] );
00155     }}
00156   }
00157   // Flag that we are leaving applyOp()
00158   in_applyOp_ = false;
00159 }
00160 
00161 template<class Scalar>
00162 void MPIVectorBase<Scalar>::getSubVector( const Range1D& rng_in, RTOpPack::SubVectorT<Scalar>* sub_vec ) const
00163 {
00164   const Range1D rng = validateRange(rng_in);
00165   if( rng.lbound() < localOffset_+1 || localOffset_+localSubDim_ < rng.ubound() ) {
00166     // rng consists of off-processor elements so use the default implementation!
00167     VectorBase<Scalar>::getSubVector(rng_in,sub_vec);
00168     return;
00169   }
00170   // rng consists of all local data so get it!
00171   const Scalar *localValues = NULL;
00172   Index stride = 0;
00173   this->getLocalData(&localValues,&stride);
00174   sub_vec->initialize(
00175     rng.lbound()-1                             // globalOffset
00176     ,rng.size()                                // subDim
00177     ,localValues+(rng.lbound()-localOffset_-1) // values
00178     ,stride                                    // stride
00179     );
00180 }
00181 
00182 template<class Scalar>
00183 void MPIVectorBase<Scalar>::freeSubVector( RTOpPack::SubVectorT<Scalar>* sub_vec ) const
00184 {
00185 #ifdef _DEBUG
00186   TEST_FOR_EXCEPTION(
00187     sub_vec==NULL || sub_vec->globalOffset() < 0 || sub_vec->globalOffset() + sub_vec->subDim() > globalDim_
00188     ,std::logic_error
00189     ,"MPIVectorBase<Scalar>::freeSubVector(...) : Error, this sub vector was not gotten from getSubVector(...)!"
00190     );
00191 #endif
00192   if( sub_vec->globalOffset() < localOffset_ || localOffset_+localSubDim_ < sub_vec->globalOffset()+sub_vec->subDim() ) {
00193     // Let the default implementation handle it!
00194     VectorBase<Scalar>::freeSubVector(sub_vec);
00195     return;
00196   }
00197   // Nothing to deallocate!
00198   sub_vec->set_uninitialized();
00199 }
00200 
00201 template<class Scalar>
00202 void MPIVectorBase<Scalar>::getSubVector( const Range1D& rng_in, RTOpPack::MutableSubVectorT<Scalar>* sub_vec )
00203 {
00204   const Range1D rng = validateRange(rng_in);
00205   if( rng.lbound() < localOffset_+1 || localOffset_+localSubDim_ < rng.ubound() ) {
00206     // rng consists of off-processor elements so use the default implementation!
00207     VectorBase<Scalar>::getSubVector(rng_in,sub_vec);
00208     return;
00209   }
00210   // rng consists of all local data so get it!
00211   Scalar *localValues = NULL;
00212   Index stride = 0;
00213   this->getLocalData(&localValues,&stride);
00214   sub_vec->initialize(
00215     rng.lbound()-1                             // globalOffset
00216     ,rng.size()                                // subDim
00217     ,localValues+(rng.lbound()-localOffset_-1) // values
00218     ,stride                                    // stride
00219     );
00220 }
00221 
00222 template<class Scalar>
00223 void MPIVectorBase<Scalar>::commitSubVector( RTOpPack::MutableSubVectorT<Scalar>* sub_vec )
00224 {
00225 #ifdef _DEBUG
00226   TEST_FOR_EXCEPTION(
00227     sub_vec==NULL || sub_vec->globalOffset() < 0 || sub_vec->globalOffset() + sub_vec->subDim() > globalDim_
00228     ,std::logic_error
00229     ,"MPIVectorBase<Scalar>::commitSubVector(...) : Error, this sub vector was not gotten from getSubVector(...)!"
00230     );
00231 #endif
00232   if( sub_vec->globalOffset() < localOffset_ || localOffset_+localSubDim_ < sub_vec->globalOffset()+sub_vec->subDim() ) {
00233     // Let the default implementation handle it!
00234     VectorBase<Scalar>::commitSubVector(sub_vec);
00235     return;
00236   }
00237   sub_vec->set_uninitialized();  // Nothing to deallocate!
00238 }
00239 
00240 // protected
00241 
00242 template<class Scalar>
00243 void MPIVectorBase<Scalar>::updateMpiSpace()
00244 {
00245   if(globalDim_ == 0) {
00246     const MPIVectorSpaceBase<Scalar> *mpiSpace = this->mpiSpace().get();
00247     if(mpiSpace) {
00248       globalDim_    = mpiSpace->dim();
00249       localOffset_  = mpiSpace->localOffset();
00250       localSubDim_  = mpiSpace->localSubDim();
00251     }
00252     else {
00253       globalDim_    = 0;
00254       localOffset_  = -1;
00255       localSubDim_  = 0;
00256     }
00257   }
00258 }
00259 
00260 // private
00261 
00262 template<class Scalar>
00263 Range1D MPIVectorBase<Scalar>::validateRange( const Range1D &rng_in ) const
00264 {
00265   const Range1D rng = RangePack::full_range(rng_in,1,globalDim_);
00266 #ifdef _DEBUG
00267   TEST_FOR_EXCEPTION(
00268     rng.lbound() < 1 || globalDim_ < rng.ubound(), std::invalid_argument
00269     ,"MPIVectorBase<Scalar>::validateRange(...): Error, the range ["
00270     <<rng.lbound()<<","<<rng.ubound()<<"] is not "
00271     "in the range [1,"<<globalDim_<<"]!"
00272     );
00273 #endif
00274   return rng;
00275 }
00276 
00277 } // end namespace Thyra
00278 
00279 #endif // THYRA_MPI_VECTOR_BASE_HPP

Generated on Thu Sep 18 12:39:52 2008 for Thyra ANA Operator/VectorBase Interfaces and Related Software by doxygen 1.3.9.1