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

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