00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
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
00079 );
00080
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_,
00096 localSubDim_,
00097 Teuchos::arcp(localValues, 0, localSubDim_, false),
00098 1
00099 );
00100
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
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
00182 in_applyOpImpl_ = true;
00183
00184
00185
00186 const bool locallyReplicated = ( comm_in == null && localSubDim_ == globalDim_ );
00187
00188
00189
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
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
00234 RTOpPack::SPMD_apply_op(
00235 locallyReplicated ? NULL : &*comm,
00236 op,
00237 num_vecs,
00238 sub_vecs.getRawPtr(),
00239 num_targ_vecs,
00240 sub_targ_vecs.getRawPtr(),
00241 reduct_obj.get()
00242 );
00243
00244
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
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
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
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
00294
00295
00296
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
00322 sub_vec->initialize(
00323 rng_in.lbound()
00324 ,0
00325 ,0
00326 ,1
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
00338 VectorDefaultBase<Scalar>::acquireDetachedVectorViewImpl(rng_in,sub_vec);
00339 return;
00340 }
00341
00342 const Scalar *localValues = NULL;
00343 Index stride = 0;
00344 this->getLocalData(&localValues,&stride);
00345 sub_vec->initialize(
00346 rng.lbound()
00347 ,rng.size()
00348 ,localValues+(rng.lbound()-localOffset_)
00349 ,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
00372 VectorDefaultBase<Scalar>::releaseDetachedVectorViewImpl(sub_vec);
00373 return;
00374 }
00375
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
00387 sub_vec->initialize(
00388 rng_in.lbound()
00389 ,0
00390 ,0
00391 ,1
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
00403 VectorDefaultBase<Scalar>::acquireNonconstDetachedVectorViewImpl(rng_in,sub_vec);
00404 return;
00405 }
00406
00407 Scalar *localValues = NULL;
00408 Index stride = 0;
00409 this->getLocalData(&localValues,&stride);
00410 sub_vec->initialize(
00411 rng.lbound()
00412 ,rng.size()
00413 ,localValues+(rng.lbound()-localOffset_)
00414 ,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
00438 VectorDefaultBase<Scalar>::commitNonconstDetachedVectorViewImpl(sub_vec);
00439 return;
00440 }
00441 sub_vec->set_uninitialized();
00442 }
00443
00444
00445
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
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 }
00493
00494
00495 #endif // THYRA_SPMD_VECTOR_BASE_HPP