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 #include "TSFEpetraVector.hpp"
00028 #include "TSFEpetraVectorSpace.hpp"
00029 #include "Teuchos_TestForException.hpp"
00030 #include "Teuchos_dyn_cast.hpp"
00031 #include "Teuchos_Workspace.hpp"
00032 #include "Thyra_DefaultSpmdVector.hpp"
00033 #ifdef HAVE_MPI
00034 #include "Teuchos_DefaultMpiComm.hpp"
00035 #endif
00036 #include "Teuchos_DefaultSerialComm.hpp"
00037
00038 #include "Thyra_apply_op_helper.hpp"
00039 #include "RTOpPack_SPMD_apply_op.hpp"
00040 #include "RTOp_parallel_helpers.h"
00041
00042
00043 #ifndef HAVE_TEUCHOS_EXPLICIT_INSTANTIATION
00044 #include "TSFVectorImpl.hpp"
00045 #include "TSFLinearOperatorImpl.hpp"
00046 #endif
00047
00048 using namespace Teuchos;
00049 using namespace TSFExtended;
00050 using namespace Thyra;
00051
00052 using Teuchos::Range1D;
00053
00054
00055 EpetraVector::EpetraVector(
00056 const RCP<const VectorSpaceBase<double> >& vs)
00057 : VectorDefaultBase<double>(),
00058 epetraVec_(),
00059 vecSpace_(vs),
00060 epetraVecSpace_(),
00061 epetraMap_(),
00062 localOffset_(),
00063 localSubDim_(),
00064 globalDim_(vs->dim()),
00065 in_applyOpImpl_(false)
00066 {
00067 const EpetraVectorSpace* epvs
00068 = dynamic_cast<const EpetraVectorSpace*>(vs.get());
00069 TEST_FOR_EXCEPTION(epvs==0, std::runtime_error,
00070 "could not cast vector space to EpetraVectorSpace in "
00071 "EpetraVector ctor");
00072
00073 epetraVecSpace_ = rcp_dynamic_cast<const EpetraVectorSpace>(vs);
00074 epetraMap_ = epvs->epetraMap();
00075 epetraVec_ = rcp(new Epetra_Vector(*epetraMap_, true));
00076
00077 localOffset_ = epetraMap_->MinMyGID();
00078 localSubDim_ = epetraMap_->NumMyElements();
00079 }
00080
00081
00082
00083 EpetraVector
00084 ::EpetraVector(const RCP<const VectorSpaceBase<double> >& vs,
00085 const RCP<Epetra_Vector>& vec)
00086 : VectorDefaultBase<double>(),
00087 epetraVec_(vec),
00088 vecSpace_(vs),
00089 epetraVecSpace_(),
00090 epetraMap_(),
00091 localOffset_(),
00092 localSubDim_(),
00093 globalDim_(vs->dim()),
00094 in_applyOpImpl_(false)
00095 {
00096 const EpetraVectorSpace* epvs
00097 = dynamic_cast<const EpetraVectorSpace*>(vs.get());
00098 TEST_FOR_EXCEPTION(epvs==0, std::runtime_error,
00099 "could not cast vector space to EpetraVectorSpace in "
00100 "EpetraVector ctor");
00101
00102
00103 epetraVecSpace_ = rcp_dynamic_cast<const EpetraVectorSpace>(vs);
00104 epetraMap_ = epvs->epetraMap();
00105 if (vec.get() == 0) epetraVec_ = rcp(new Epetra_Vector(*epetraMap_, true));
00106
00107 localOffset_ = epetraMap_->MinMyGID();
00108 localSubDim_ = epetraMap_->NumMyElements();
00109 }
00110
00111
00112
00113
00114
00115 #ifndef TRILINOS_8
00116
00117 void EpetraVector::applyOpImpl(const RTOpPack::RTOpT< double >& op,
00118 const ArrayView< const Ptr< const VectorBase< double > > > & vecs,
00119 const ArrayView< const Ptr< VectorBase< double > > > & targ_vecs,
00120 const Ptr< RTOpPack::ReductTarget > & reduct_obj,
00121 const OrdType global_offset_in
00122 ) const
00123 {
00124
00125
00126 const OrdType first_ele_offset_in = 0;
00127 const OrdType sub_dim_in = -1;
00128
00129 using Teuchos::null;
00130 using Teuchos::dyn_cast;
00131 using Teuchos::Workspace;
00132
00133 const int num_vecs = vecs.size();
00134 const int num_targ_vecs = targ_vecs.size();
00135
00136 #ifdef THYRA_SPMD_VECTOR_BASE_DUMP
00137 Teuchos::RCP<Teuchos::FancyOStream>
00138 out = Teuchos::VerboseObjectBase::getDefaultOStream();
00139 Teuchos::OSTab tab(out);
00140 if(show_dump) {
00141 *out << "\nEntering SpmdVectorBase<double>::applyOp(...) ...\n";
00142 *out
00143 << "\nop = " << typeName(op)
00144 << "\nnum_vecs = " << num_vecs
00145 << "\nnum_targ_vecs = " << num_targ_vecs
00146 << "\nreduct_obj = " << reduct_obj
00147 << "\nfirst_ele_offset_in = " << first_ele_offset_in
00148 << "\nsub_dim_in = " << sub_dim_in
00149 << "\nglobal_offset_in = " << global_offset_in
00150 << "\n"
00151 ;
00152 }
00153 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00154
00155 Ptr<Teuchos::WorkspaceStore> wss = Teuchos::get_default_workspace_store().ptr();
00156
00157 #ifdef TEUCHOS_DEBUG
00158
00159 TEST_FOR_EXCEPTION(
00160 in_applyOpImpl_, std::invalid_argument
00161 ,"SpmdVectorBase<>::applyOp(...): Error, this method is being entered recursively which is a "
00162 "clear sign that one of the methods acquireDetachedView(...), releaseDetachedView(...) or commitDetachedView(...) "
00163 "was not implemented properly!"
00164 );
00165 Thyra::apply_op_validate_input(
00166 "SpmdVectorBase<>::applyOp(...)",*space(),
00167 op, vecs, targ_vecs, reduct_obj,
00168 global_offset_in
00169 );
00170 #endif
00171
00172 const Teuchos::RCP<const Teuchos::Comm<OrdType> >& comm
00173 = epetraVecSpace_->getComm();
00174
00175 const SerialComm<OrdType>* serialComm =
00176 dynamic_cast<const SerialComm<OrdType>* >(comm.get());
00177
00178
00179
00180 in_applyOpImpl_ = true;
00181
00182
00183
00184 const bool locallyReplicated = ( serialComm != 0 && localSubDim_ == globalDim_ );
00185
00186
00187
00188 OrdType overlap_first_local_ele_off = 0;
00189 OrdType overlap_local_sub_dim = 0;
00190 OrdType overlap_global_off = 0;
00191 if(localSubDim_) {
00192 RTOp_parallel_calc_overlap(
00193 globalDim_, localSubDim_, localOffset_,
00194 first_ele_offset_in, sub_dim_in, global_offset_in,
00195 &overlap_first_local_ele_off, &overlap_local_sub_dim, &overlap_global_off
00196 );
00197 }
00198 const Range1D local_rng = (
00199 overlap_first_local_ele_off>=0
00200 ? Range1D( localOffset_ + overlap_first_local_ele_off, localOffset_
00201 + overlap_first_local_ele_off + overlap_local_sub_dim - 1 )
00202 : Range1D::Invalid
00203 );
00204
00205 #ifdef THYRA_SPMD_VECTOR_BASE_DUMP
00206 if(show_dump) {
00207 *out
00208 << "\noverlap_first_local_ele_off = " << overlap_first_local_ele_off
00209 << "\noverlap_local_sub_dim = " << overlap_local_sub_dim
00210 << "\noverlap_global_off = " << overlap_global_off
00211 << "\nlocal_rng = ["<<local_rng.lbound()<<","<<local_rng.ubound()<<"]"
00212 << "\n"
00213 ;
00214 }
00215 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00216
00217
00218 Workspace<RTOpPack::ConstSubVectorView<double> > sub_vecs(wss.get(),num_vecs);
00219 Workspace<RTOpPack::SubVectorView<double> > sub_targ_vecs(wss.get(),num_targ_vecs);
00220 if( overlap_first_local_ele_off >= 0 ) {
00221 {for(int k = 0; k < num_vecs; ++k ) {
00222 vecs[k]->acquireDetachedView( local_rng, &sub_vecs[k] );
00223 sub_vecs[k].setGlobalOffset( overlap_global_off );
00224 }}
00225 {for(int k = 0; k < num_targ_vecs; ++k ) {
00226 targ_vecs[k]->acquireDetachedView( local_rng, &sub_targ_vecs[k] );
00227 sub_targ_vecs[k].setGlobalOffset( overlap_global_off );
00228 }}
00229 }
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<double>::applyOp(...) ...\n";
00262 }
00263 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00264
00265 }
00266
00267 #else
00268
00269 void EpetraVector::applyOp(
00270 const RTOpPack::RTOpT<double> &op,
00271 const int num_vecs,
00272 const VectorBase<double>*const vecs[],
00273 const int num_targ_vecs,
00274 VectorBase<double>*const targ_vecs[],
00275 RTOpPack::ReductTarget *reduct_obj,
00276 const OrdType first_ele_offset_in,
00277 const OrdType sub_dim_in,
00278 const OrdType global_offset_in
00279 ) const
00280 {
00281 #ifdef THYRA_SPMD_VECTOR_BASE_DUMP
00282 Teuchos::RCP<Teuchos::FancyOStream>
00283 out = Teuchos::VerboseObjectBase::getDefaultOStream();
00284 Teuchos::OSTab tab(out);
00285 if(show_dump) {
00286 *out << "\nEntering SpmdVectorBase<double>::applyOp(...) ...\n";
00287 *out
00288 << "\nop = " << typeName(op)
00289 << "\nnum_vecs = " << num_vecs
00290 << "\nnum_targ_vecs = " << num_targ_vecs
00291 << "\nreduct_obj = " << reduct_obj
00292 << "\nfirst_ele_offset_in = " << first_ele_offset_in
00293 << "\nsub_dim_in = " << sub_dim_in
00294 << "\nglobal_offset_in = " << global_offset_in
00295 << "\n"
00296 ;
00297 }
00298 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00299 using Teuchos::dyn_cast;
00300 using Teuchos::Workspace;
00301 Teuchos::WorkspaceStore* wss = Teuchos::get_default_workspace_store().get();
00302
00303 #ifdef TEUCHOS_DEBUG
00304
00305 TEST_FOR_EXCEPTION(
00306 in_applyOpImpl_, std::invalid_argument
00307 ,"SpmdVectorBase<>::applyOp(...): Error, this method is being entered recursively which is a "
00308 "clear sign that one of the methods acquireDetachedView(...), releaseDetachedView(...) or commitDetachedView(...) "
00309 "was not implemented properly!"
00310 );
00311 Thyra::apply_op_validate_input(
00312 "SpmdVectorBase<>::applyOp(...)",*space()
00313 ,op,num_vecs,vecs,num_targ_vecs,targ_vecs,reduct_obj,first_ele_offset_in,sub_dim_in,global_offset_in
00314 );
00315 #endif
00316
00317 const Teuchos::RCP<const Teuchos::Comm<OrdType> >& comm
00318 = epetraVecSpace_->getComm();
00319
00320 const SerialComm<OrdType>* serialComm =
00321 dynamic_cast<const SerialComm<OrdType>* >(comm.get());
00322
00323
00324
00325 in_applyOpImpl_ = true;
00326
00327
00328
00329 const bool locallyReplicated = ( serialComm != 0 && localSubDim_ == globalDim_ );
00330
00331
00332
00333 OrdType overlap_first_local_ele_off = 0;
00334 OrdType overlap_local_sub_dim = 0;
00335 OrdType overlap_global_off = 0;
00336 if(localSubDim_) {
00337 RTOp_parallel_calc_overlap(
00338 globalDim_, localSubDim_, localOffset_, first_ele_offset_in, sub_dim_in, global_offset_in
00339 ,&overlap_first_local_ele_off, &overlap_local_sub_dim, &overlap_global_off
00340 );
00341 }
00342 const Range1D local_rng = (
00343 overlap_first_local_ele_off>=0
00344 ? Range1D( localOffset_ + overlap_first_local_ele_off, localOffset_ + overlap_first_local_ele_off + overlap_local_sub_dim - 1 )
00345 : Range1D::Invalid
00346 );
00347 #ifdef THYRA_SPMD_VECTOR_BASE_DUMP
00348 if(show_dump) {
00349 *out
00350 << "\noverlap_first_local_ele_off = " << overlap_first_local_ele_off
00351 << "\noverlap_local_sub_dim = " << overlap_local_sub_dim
00352 << "\noverlap_global_off = " << overlap_global_off
00353 << "\nlocal_rng = ["<<local_rng.lbound()<<","<<local_rng.ubound()<<"]"
00354 << "\n"
00355 ;
00356 }
00357 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00358
00359 Workspace<RTOpPack::ConstSubVectorView<double> > sub_vecs(wss,num_vecs);
00360 Workspace<RTOpPack::SubVectorView<double> > sub_targ_vecs(wss,num_targ_vecs);
00361 if( overlap_first_local_ele_off >= 0 ) {
00362 {for(int k = 0; k < num_vecs; ++k ) {
00363 vecs[k]->acquireDetachedView( local_rng, &sub_vecs[k] );
00364 sub_vecs[k].setGlobalOffset( overlap_global_off );
00365 }}
00366 {for(int k = 0; k < num_targ_vecs; ++k ) {
00367 targ_vecs[k]->acquireDetachedView( local_rng, &sub_targ_vecs[k] );
00368 sub_targ_vecs[k].setGlobalOffset( overlap_global_off );
00369 }}
00370 }
00371
00372 const bool validSubVecs = ( localSubDim_ > 0 && overlap_first_local_ele_off >= 0 );
00373 RTOpPack::SPMD_apply_op(
00374 locallyReplicated ? NULL : comm.get()
00375 ,op
00376 ,num_vecs
00377 ,num_vecs && validSubVecs ? &sub_vecs[0] : NULL
00378 ,num_targ_vecs
00379 ,num_targ_vecs && validSubVecs ? &sub_targ_vecs[0] : NULL
00380 ,reduct_obj
00381 );
00382
00383 if( overlap_first_local_ele_off >= 0 ) {
00384 {for(int k = 0; k < num_vecs; ++k ) {
00385 sub_vecs[k].setGlobalOffset(local_rng.lbound());
00386 vecs[k]->releaseDetachedView( &sub_vecs[k] );
00387 }}
00388 {for(int k = 0; k < num_targ_vecs; ++k ) {
00389 sub_targ_vecs[k].setGlobalOffset(local_rng.lbound());
00390 targ_vecs[k]->commitDetachedView( &sub_targ_vecs[k] );
00391 }}
00392 }
00393
00394 in_applyOpImpl_ = false;
00395 #ifdef THYRA_SPMD_VECTOR_BASE_DUMP
00396 if(show_dump) {
00397 *out << "\nLeaving SpmdVectorBase<double>::applyOp(...) ...\n";
00398 }
00399 #endif // THYRA_SPMD_VECTOR_BASE_DUMP
00400 }
00401
00402
00403
00404 #endif
00405
00406
00407
00408
00409 void EpetraVector::acquireDetachedVectorViewImpl(
00410 const Teuchos::Range1D& rng_in,
00411 RTOpPack::ConstSubVectorView<double>* sub_vec) const
00412 {
00413
00414 if (rng_in == Range1D::Invalid)
00415 {
00416 sub_vec->initialize(rng_in.lbound(), 0, Teuchos::ArrayRCP<double>(), 1);
00417 return ;
00418 }
00419
00420
00421 const Range1D rng = validateRange(rng_in);
00422
00423
00424
00425 if (
00426 rng.lbound() < localOffset_
00427 || localOffset_ + localSubDim_ - 1 < rng.ubound())
00428 {
00429 VectorDefaultBase<double>::acquireDetachedVectorViewImpl(rng_in,sub_vec);
00430 return ;
00431 }
00432
00433
00434 const double* localValues = &(epetraVec_->operator[](0));
00435 Teuchos::ArrayRCP<const double> locVals(localValues, rng.lbound()-localOffset_,
00436 rng.size(), false);
00437
00438
00439 OrdType stride = 1;
00440
00441 sub_vec->initialize(rng.lbound(), rng.size(),
00442 locVals, stride);
00443
00444 }
00445
00446
00447
00448
00449 void EpetraVector::releaseDetachedVectorViewImpl(
00450 RTOpPack::ConstSubVectorView<double>* sub_vec) const
00451 {
00452 if(
00453 sub_vec->globalOffset() < localOffset_
00454 || localOffset_+localSubDim_ < sub_vec->globalOffset()+sub_vec->subDim()
00455 )
00456 {
00457
00458 VectorDefaultBase<double>::releaseDetachedVectorViewImpl(sub_vec);
00459 return;
00460 }
00461
00462 sub_vec->uninitialize();
00463 }
00464
00465
00466
00467
00468 void EpetraVector::acquireNonconstDetachedVectorViewImpl(
00469 const Teuchos::Range1D& rng_in,
00470 RTOpPack::SubVectorView<double>* sub_vec)
00471 {
00472 if( rng_in == Range1D::Invalid ) {
00473
00474 sub_vec->initialize(rng_in.lbound(), 0, Teuchos::ArrayRCP<double>(), 1);
00475 return;
00476 }
00477
00478 const Range1D rng = validateRange(rng_in);
00479 if(
00480 rng.lbound() < localOffset_
00481 ||
00482 localOffset_+localSubDim_-1 < rng.ubound()
00483 )
00484 {
00485
00486
00487 VectorDefaultBase<double>::acquireNonconstDetachedVectorViewImpl(rng_in,
00488 sub_vec);
00489 return;
00490 }
00491
00492
00493 double* localValues = &(epetraVec_->operator[](0));
00494 Teuchos::ArrayRCP<double> locVals(localValues, rng.lbound()-localOffset_,
00495
00496 rng.size(), false);
00497 OrdType stride = 1;
00498
00499 sub_vec->initialize(rng.lbound(), rng.size(),
00500 locVals, stride);
00501
00502 }
00503
00504
00505
00506 void EpetraVector::commitNonconstDetachedVectorViewImpl(
00507 RTOpPack::SubVectorView<double>* sub_vec
00508 )
00509 {
00510 if(
00511 sub_vec->globalOffset() < localOffset_
00512 ||
00513 localOffset_+localSubDim_ < sub_vec->globalOffset()+sub_vec->subDim()
00514 )
00515 {
00516
00517 VectorDefaultBase<double>::commitNonconstDetachedVectorViewImpl(sub_vec);
00518 return;
00519 }
00520 sub_vec->uninitialize();
00521 }
00522
00523
00524
00525
00526 Teuchos::Range1D EpetraVector::validateRange(const Teuchos::Range1D& rng_in) const
00527 {
00528 const Range1D rng = Teuchos::full_range(rng_in,0,globalDim_-1);
00529 TEST_FOR_EXCEPTION(
00530 !( 0 <= rng.lbound() && rng.ubound() < globalDim_ ), std::invalid_argument
00531 ,"EpetraVector::validateRange(rowRng): Error, the range rng = ["
00532 <<rng.lbound()<<","<<rng.ubound()<<"] is not "
00533 "in the range [0,"<<(globalDim_-1)<<"]!"
00534 );
00535 return rng;
00536 }
00537
00538
00539
00540
00541
00542 double& EpetraVector::operator[](OrdType globalIndex)
00543 {
00544 const Epetra_BlockMap& myMap = epetraVec()->Map();
00545 return (*epetraVec())[myMap.LID(globalIndex)];
00546 }
00547
00548 void EpetraVector::setElement(OrdType index, const double& value)
00549 {
00550 int loc_index[1] = { index };
00551 epetraVec()->ReplaceGlobalValues(1, const_cast<double*>(&value),
00552 loc_index);
00553 }
00554
00555 void EpetraVector::addToElement(OrdType index, const double& value)
00556 {
00557
00558 int loc_index[1] = { index };
00559 epetraVec()->SumIntoGlobalValues(1, const_cast<double*>(&value),
00560 loc_index);
00561 }
00562
00563 const double& EpetraVector::getElement(OrdType index) const
00564 {
00565 const Epetra_BlockMap& myMap = epetraVec()->Map();
00566 return (*epetraVec())[myMap.LID(index)];
00567 }
00568
00569 void EpetraVector::getElements(const OrdType* globalIndices, int numElems,
00570 Teuchos::Array<double>& elems) const
00571 {
00572 elems.resize(numElems);
00573 const Epetra_BlockMap& myMap = epetraVec()->Map();
00574 RCP<const Epetra_Vector> epv = epetraVec();
00575
00576 for (int i=0; i<numElems; i++)
00577 {
00578 elems[i] = (*epv)[myMap.LID(globalIndices[i])];
00579 }
00580 }
00581
00582 void EpetraVector::setElements(int numElems, const int* globalIndices,
00583 const double* values)
00584 {
00585 Epetra_FEVector* vec = dynamic_cast<Epetra_FEVector*>(epetraVec().get());
00586 int ierr = vec->ReplaceGlobalValues(numElems, globalIndices, values);
00587 TEST_FOR_EXCEPTION(ierr < 0, std::runtime_error, "ReplaceGlobalValues returned "
00588 "ierr=" << ierr << " in EpetraVector::setElements()");
00589 }
00590
00591 void EpetraVector::addToElements(int numElems, const int* globalIndices,
00592 const double* values)
00593 {
00594 Epetra_FEVector* vec = dynamic_cast<Epetra_FEVector*>(epetraVec().get());
00595 int ierr = vec->SumIntoGlobalValues(numElems, globalIndices, values);
00596 TEST_FOR_EXCEPTION(ierr < 0, std::runtime_error, "SumIntoGlobalValues returned "
00597 "ierr=" << ierr << " in EpetraVector::addToElements()");
00598 }
00599
00600 void EpetraVector::finalizeAssembly()
00601 {
00602 Epetra_FEVector* vec = dynamic_cast<Epetra_FEVector*>(epetraVec().get());
00603 vec->GlobalAssemble();
00604 }
00605
00606
00607 void EpetraVector::print(std::ostream& os) const
00608 {
00609 epetraVec()->Print(os);
00610 }
00611
00612
00613 const Epetra_Vector& EpetraVector::getConcrete(const TSFExtended::Vector<double>& tsfVec)
00614 {
00615 const EpetraVector* epv
00616 = dynamic_cast<const EpetraVector*>(tsfVec.ptr().get());
00617 TEST_FOR_EXCEPTION(epv==0, std::runtime_error,
00618 "EpetraVector::getConcrete called on a vector that "
00619 "could not be cast to an EpetraVector");
00620 return *(epv->epetraVec());
00621 }
00622
00623 Epetra_Vector& EpetraVector::getConcrete(TSFExtended::Vector<double>& tsfVec)
00624 {
00625 EpetraVector* epv
00626 = dynamic_cast<EpetraVector*>(tsfVec.ptr().get());
00627 TEST_FOR_EXCEPTION(epv==0, std::runtime_error,
00628 "EpetraVector::getConcrete called on a vector that "
00629 "could not be cast to an EpetraVector");
00630 return *(epv->epetraVec());
00631 }
00632
00633
00634 Epetra_Vector* EpetraVector::getConcretePtr(TSFExtended::Vector<double>& tsfVec)
00635 {
00636 EpetraVector* epv
00637 = dynamic_cast<EpetraVector*>(tsfVec.ptr().get());
00638 TEST_FOR_EXCEPTION(epv==0, std::runtime_error,
00639 "EpetraVector::getConcrete called on a vector that "
00640 "could not be cast to an EpetraVector");
00641 return epv->epetraVec().get();
00642 }
00643
00644
00645
00646