Thyra_SpmdVectorBase.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_SPMD_VECTOR_BASE_HPP
00030 #define THYRA_SPMD_VECTOR_BASE_HPP
00031 
00032 
00033 #include "Thyra_SpmdVectorBaseDecl.hpp"
00034 #include "Thyra_VectorDefaultBase.hpp"
00035 #include "Thyra_SpmdVectorSpaceDefaultBase.hpp"
00036 #include "Thyra_apply_op_helper.hpp"
00037 #include "RTOp_parallel_helpers.h"
00038 #include "RTOpPack_SPMD_apply_op.hpp"
00039 #include "Teuchos_Workspace.hpp"
00040 #include "Teuchos_TestForException.hpp"
00041 #include "Teuchos_dyn_cast.hpp"
00042 
00043 
00044 #ifdef THYRA_SPMD_VECTOR_BASE_DUMP
00045 #  include "Teuchos_VerboseObject.hpp"
00046 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00047 
00048 
00049 namespace Thyra {
00050 
00051 
00052 template<class Scalar>
00053 SpmdVectorBase<Scalar>::SpmdVectorBase()
00054   :in_applyOp_(false)
00055   ,globalDim_(0)
00056   ,localOffset_(-1)
00057   ,localSubDim_(0)
00058 {}
00059 
00060 
00061 // Virtual methods with default implementations
00062 
00063 
00064 template<class Scalar>
00065 void SpmdVectorBase<Scalar>::getLocalData( const Scalar** values, Index* stride ) const
00066 {
00067   const_cast<SpmdVectorBase<Scalar>*>(this)->getLocalData(const_cast<Scalar**>(values),stride);
00068 }
00069 
00070 
00071 template<class Scalar>
00072 void SpmdVectorBase<Scalar>::freeLocalData( const Scalar* values ) const
00073 {
00074   const_cast<SpmdVectorBase<Scalar>*>(this)->commitLocalData(const_cast<Scalar*>(values));
00075 }
00076 
00077 
00078 template<class Scalar>
00079 void SpmdVectorBase<Scalar>::applyOp(
00080   const Teuchos::Comm<Index>      *comm_in
00081   ,const RTOpPack::RTOpT<Scalar>  &op
00082   ,const int                      num_vecs
00083   ,const VectorBase<Scalar>*const vecs[]
00084   ,const int                      num_targ_vecs
00085   ,VectorBase<Scalar>*const       targ_vecs[]
00086   ,RTOpPack::ReductTarget         *reduct_obj
00087   ,const Index                    first_ele_offset_in
00088   ,const Index                    sub_dim_in
00089   ,const Index                    global_offset_in
00090   ) const
00091 {
00092 #ifdef THYRA_SPMD_VECTOR_BASE_DUMP
00093   Teuchos::RCP<Teuchos::FancyOStream>
00094     out = Teuchos::VerboseObjectBase::getDefaultOStream();
00095   Teuchos::OSTab tab(out);
00096   if(show_dump) {
00097     *out << "\nEntering SpmdVectorBase<Scalar>::applyOp(...) ...\n";
00098     *out
00099       << "\nop = " << typeName(op)
00100       << "\nnum_vecs = " << num_vecs
00101       << "\nnum_targ_vecs = " << num_targ_vecs
00102       << "\nreduct_obj = " << reduct_obj
00103       << "\nfirst_ele_offset_in = " << first_ele_offset_in
00104       << "\nsub_dim_in = " << sub_dim_in
00105       << "\nglobal_offset_in = " << global_offset_in
00106       << "\n"
00107       ;
00108   }
00109 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00110   using Teuchos::dyn_cast;
00111   using Teuchos::Workspace;
00112   Teuchos::WorkspaceStore* wss = Teuchos::get_default_workspace_store().get();
00113   const SpmdVectorSpaceBase<Scalar> &spmdSpc = *spmdSpace();
00114 #ifdef TEUCHOS_DEBUG
00115   // ToDo: Validate input!
00116   TEST_FOR_EXCEPTION(
00117     in_applyOp_, std::invalid_argument
00118     ,"SpmdVectorBase<>::applyOp(...): Error, this method is being entered recursively which is a "
00119     "clear sign that one of the methods acquireDetachedView(...), releaseDetachedView(...) or commitDetachedView(...) "
00120     "was not implemented properly!"
00121     );
00122   Thyra::apply_op_validate_input(
00123     "SpmdVectorBase<>::applyOp(...)",*space()
00124     ,op,num_vecs,vecs,num_targ_vecs,targ_vecs,reduct_obj,first_ele_offset_in,sub_dim_in,global_offset_in
00125     );
00126 #endif
00127   Teuchos::RCP<const Teuchos::Comm<Index> > comm;
00128   if( comm_in != NULL )
00129     comm = Teuchos::rcp(comm_in,false);
00130   else
00131     comm = spmdSpc.getComm();
00132   // Flag that we are in applyOp()
00133   in_applyOp_ = true;
00134   // First see if this is a locally replicated vector in which case
00135   // we treat this as a local operation only.
00136   const bool locallyReplicated = ( comm_in == NULL && localSubDim_ == globalDim_ );
00137   // Get the overlap in the current process with the input logical sub-vector
00138   // from (first_ele_offset_in,sub_dim_in,global_offset_in)
00139   Index  overlap_first_local_ele_off  = 0;
00140   Index  overlap_local_sub_dim        = 0;
00141   Index  overlap_global_off           = 0;
00142   if(localSubDim_) {
00143     RTOp_parallel_calc_overlap(
00144       globalDim_, localSubDim_, localOffset_, first_ele_offset_in, sub_dim_in, global_offset_in
00145       ,&overlap_first_local_ele_off, &overlap_local_sub_dim, &overlap_global_off
00146       );
00147   }
00148   const Range1D local_rng = (
00149     overlap_first_local_ele_off>=0
00150     ? Range1D( localOffset_ + overlap_first_local_ele_off, localOffset_ + overlap_first_local_ele_off + overlap_local_sub_dim - 1 )
00151     : Range1D::Invalid
00152     );
00153 #ifdef THYRA_SPMD_VECTOR_BASE_DUMP
00154   if(show_dump) {
00155     *out
00156       << "\noverlap_first_local_ele_off = " << overlap_first_local_ele_off
00157       << "\noverlap_local_sub_dim = " << overlap_local_sub_dim
00158       << "\noverlap_global_off = " << overlap_global_off
00159       << "\nlocal_rng = ["<<local_rng.lbound()<<","<<local_rng.ubound()<<"]"
00160       << "\n"
00161       ;
00162   }
00163 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00164   // Create sub-vector views of all of the *participating* local data
00165   Workspace<RTOpPack::ConstSubVectorView<Scalar> > sub_vecs(wss,num_vecs);
00166   Workspace<RTOpPack::SubVectorView<Scalar> > sub_targ_vecs(wss,num_targ_vecs);
00167   if( overlap_first_local_ele_off >= 0 ) {
00168     {for(int k = 0; k < num_vecs; ++k ) {
00169       vecs[k]->acquireDetachedView( local_rng, &sub_vecs[k] );
00170       sub_vecs[k].setGlobalOffset( overlap_global_off );
00171     }}
00172     {for(int k = 0; k < num_targ_vecs; ++k ) {
00173       targ_vecs[k]->acquireDetachedView( local_rng, &sub_targ_vecs[k] );
00174       sub_targ_vecs[k].setGlobalOffset( overlap_global_off );
00175     }}
00176   }
00177   // Apply the RTOp operator object (all processors must participate)
00178   const bool validSubVecs = ( localSubDim_ > 0 && overlap_first_local_ele_off >= 0 );
00179   RTOpPack::SPMD_apply_op(
00180     locallyReplicated ? NULL : comm.get()                       // comm
00181     ,op                                                         // op
00182     ,num_vecs                                                   // num_vecs
00183     ,num_vecs && validSubVecs ? &sub_vecs[0] : NULL             // sub_vecs
00184     ,num_targ_vecs                                              // num_targ_vecs
00185     ,num_targ_vecs && validSubVecs ? &sub_targ_vecs[0] : NULL   // targ_sub_vecs
00186     ,reduct_obj                                                 // reduct_obj
00187     );
00188   // Free and commit the local data
00189   if( overlap_first_local_ele_off >= 0 ) {
00190     {for(int k = 0; k < num_vecs; ++k ) {
00191       sub_vecs[k].setGlobalOffset(local_rng.lbound());
00192       vecs[k]->releaseDetachedView( &sub_vecs[k] );
00193     }}
00194     {for(int k = 0; k < num_targ_vecs; ++k ) {
00195       sub_targ_vecs[k].setGlobalOffset(local_rng.lbound());
00196       targ_vecs[k]->commitDetachedView( &sub_targ_vecs[k] );
00197     }}
00198   }
00199   // Flag that we are leaving applyOp()
00200   in_applyOp_ = false;
00201 #ifdef THYRA_SPMD_VECTOR_BASE_DUMP
00202   if(show_dump) {
00203     *out << "\nLeaving SpmdVectorBase<Scalar>::applyOp(...) ...\n";
00204   }
00205 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00206 }
00207 
00208 
00209 // Overridden from Teuchos::Describable
00210 
00211 
00212 template<class Scalar>
00213 std::string SpmdVectorBase<Scalar>::description() const
00214 {
00215   using Teuchos::RCP; using Teuchos::Comm; using Teuchos::null;
00216   using Teuchos::typeName;
00217   std::ostringstream ostr;
00218   ostr<<typeName(*this)<<"{spmdSpace="<<spmdSpace()->description()<<"}";
00219   return ostr.str();
00220 }
00221 
00222 
00223 // Overridden from VectorBase
00224 
00225 template<class Scalar>
00226 Teuchos::RCP<const VectorSpaceBase<Scalar> >
00227 SpmdVectorBase<Scalar>::space() const
00228 {
00229   return spmdSpace();
00230 }
00231 
00232 
00233 template<class Scalar>
00234 void SpmdVectorBase<Scalar>::applyOp(
00235   const RTOpPack::RTOpT<Scalar>   &op
00236   ,const int                      num_vecs
00237   ,const VectorBase<Scalar>*const vecs[]
00238   ,const int                      num_targ_vecs
00239   ,VectorBase<Scalar>*const       targ_vecs[]
00240   ,RTOpPack::ReductTarget         *reduct_obj
00241   ,const Index                    first_ele_offset
00242   ,const Index                    sub_dim
00243   ,const Index                    global_offset
00244   ) const
00245 {
00246   applyOp(
00247     NULL
00248     ,op,num_vecs,vecs,num_targ_vecs,targ_vecs,reduct_obj
00249     ,first_ele_offset,sub_dim,global_offset
00250     );
00251 }
00252 
00253 
00254 template<class Scalar>
00255 void SpmdVectorBase<Scalar>::acquireDetachedVectorViewImpl(
00256   const Range1D& rng_in, RTOpPack::ConstSubVectorView<Scalar>* sub_vec
00257   ) const
00258 {
00259   if( rng_in == Range1D::Invalid ) {
00260     // Just return an null view
00261     sub_vec->initialize(
00262       rng_in.lbound()    // globalOffset
00263       ,0                 // subDim
00264       ,0                 // values
00265       ,1                 // stride
00266       );
00267     return;
00268   }
00269   const Range1D rng = validateRange(rng_in);
00270   if(
00271     rng.lbound() < localOffset_ 
00272     ||
00273     localOffset_+localSubDim_-1 < rng.ubound()
00274     )
00275   {
00276     // rng consists of off-processor elements so use the default implementation!
00277     VectorDefaultBase<Scalar>::acquireDetachedVectorViewImpl(rng_in,sub_vec);
00278     return;
00279   }
00280   // rng consists of all local data so get it!
00281   const Scalar *localValues = NULL;
00282   Index stride = 0;
00283   this->getLocalData(&localValues,&stride);
00284   sub_vec->initialize(
00285     rng.lbound()                               // globalOffset
00286     ,rng.size()                                // subDim
00287     ,localValues+(rng.lbound()-localOffset_)   // values
00288     ,stride                                    // stride
00289     );
00290 }
00291 
00292 
00293 template<class Scalar>
00294 void SpmdVectorBase<Scalar>::releaseDetachedVectorViewImpl(
00295   RTOpPack::ConstSubVectorView<Scalar>* sub_vec
00296   ) const
00297 {
00298 #ifdef TEUCHOS_DEBUG
00299   TEST_FOR_EXCEPTION(
00300     sub_vec==NULL || sub_vec->globalOffset() < 0 || sub_vec->globalOffset() + sub_vec->subDim() > globalDim_
00301     ,std::logic_error
00302     ,"SpmdVectorBase<Scalar>::releaseDetachedVectorViewImpl(...) : Error, this sub vector was not gotten from acquireDetachedView(...)!"
00303     );
00304 #endif
00305   if(
00306     sub_vec->globalOffset() < localOffset_ 
00307     || localOffset_+localSubDim_ < sub_vec->globalOffset()+sub_vec->subDim()
00308     )
00309   {
00310     // Let the default implementation handle it!
00311     VectorDefaultBase<Scalar>::releaseDetachedVectorViewImpl(sub_vec);
00312     return;
00313   }
00314   // Nothing to deallocate!
00315   sub_vec->set_uninitialized();
00316 }
00317 
00318 
00319 template<class Scalar>
00320 void SpmdVectorBase<Scalar>::acquireNonconstDetachedVectorViewImpl(
00321   const Range1D& rng_in, RTOpPack::SubVectorView<Scalar>* sub_vec
00322   )
00323 {
00324   if( rng_in == Range1D::Invalid ) {
00325     // Just return an null view
00326     sub_vec->initialize(
00327       rng_in.lbound()    // globalOffset
00328       ,0                 // subDim
00329       ,0                 // values
00330       ,1                 // stride
00331       );
00332     return;
00333   }
00334   const Range1D rng = validateRange(rng_in);
00335   if(
00336     rng.lbound() < localOffset_ 
00337     ||
00338     localOffset_+localSubDim_-1 < rng.ubound()
00339     )
00340   {
00341     // rng consists of off-processor elements so use the default implementation!
00342     VectorDefaultBase<Scalar>::acquireNonconstDetachedVectorViewImpl(rng_in,sub_vec);
00343     return;
00344   }
00345   // rng consists of all local data so get it!
00346   Scalar *localValues = NULL;
00347   Index stride = 0;
00348   this->getLocalData(&localValues,&stride);
00349   sub_vec->initialize(
00350     rng.lbound()                               // globalOffset
00351     ,rng.size()                                // subDim
00352     ,localValues+(rng.lbound()-localOffset_)   // values
00353     ,stride                                    // stride
00354     );
00355 }
00356 
00357 
00358 template<class Scalar>
00359 void SpmdVectorBase<Scalar>::commitNonconstDetachedVectorViewImpl(
00360   RTOpPack::SubVectorView<Scalar>* sub_vec
00361   )
00362 {
00363 #ifdef TEUCHOS_DEBUG
00364   TEST_FOR_EXCEPTION(
00365     sub_vec==NULL || sub_vec->globalOffset() < 0 || sub_vec->globalOffset() + sub_vec->subDim() > globalDim_
00366     ,std::logic_error
00367     ,"SpmdVectorBase<Scalar>::commitDetachedView(...) : Error, this sub vector was not gotten from acquireDetachedView(...)!"
00368     );
00369 #endif
00370   if(
00371     sub_vec->globalOffset() < localOffset_
00372     ||
00373     localOffset_+localSubDim_ < sub_vec->globalOffset()+sub_vec->subDim()
00374     )
00375   {
00376     // Let the default implementation handle it!
00377     VectorDefaultBase<Scalar>::commitNonconstDetachedVectorViewImpl(sub_vec);
00378     return;
00379   }
00380   sub_vec->set_uninitialized();  // Nothing to deallocate!
00381 }
00382 
00383 
00384 // protected
00385 
00386 
00387 template<class Scalar>
00388 void SpmdVectorBase<Scalar>::updateSpmdSpace()
00389 {
00390   if(globalDim_ == 0) {
00391     const SpmdVectorSpaceBase<Scalar> *spmdSpace = this->spmdSpace().get();
00392     if(spmdSpace) {
00393       globalDim_    = spmdSpace->dim();
00394       localOffset_  = spmdSpace->localOffset();
00395       localSubDim_  = spmdSpace->localSubDim();
00396     }
00397     else {
00398       globalDim_    = 0;
00399       localOffset_  = -1;
00400       localSubDim_  = 0;
00401     }
00402   }
00403 }
00404 
00405 
00406 // private
00407 
00408 
00409 template<class Scalar>
00410 Range1D SpmdVectorBase<Scalar>::validateRange( const Range1D &rng_in ) const
00411 {
00412   const Range1D rng = Teuchos::full_range(rng_in,0,globalDim_-1);
00413 #ifdef TEUCHOS_DEBUG
00414   TEST_FOR_EXCEPTION(
00415     !(0 <= rng.lbound() && rng.ubound() < globalDim_), std::invalid_argument
00416     ,"SpmdVectorBase<Scalar>::validateRange(...): Error, the range ["
00417     <<rng.lbound()<<","<<rng.ubound()<<"] is not "
00418     "in the range [0,"<<(globalDim_-1)<<"]!"
00419     );
00420 #endif
00421   return rng;
00422 }
00423 
00424 
00425 #ifdef THYRA_SPMD_VECTOR_BASE_DUMP
00426 template<class Scalar>
00427 bool SpmdVectorBase<Scalar>::show_dump = false;
00428 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00429 
00430 
00431 } // end namespace Thyra
00432 
00433 
00434 #endif // THYRA_SPMD_VECTOR_BASE_HPP

Generated on Tue Oct 20 12:46:59 2009 for Thyra Operator/Vector Support by doxygen 1.4.7