Thyra_ProductVector.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_PRODUCT_VECTOR_HPP
00030 #define THYRA_PRODUCT_VECTOR_HPP
00031 
00032 #include "Thyra_ProductVectorDecl.hpp"
00033 #include "Thyra_ProductVectorSpace.hpp"
00034 #include "Teuchos_Workspace.hpp"
00035 
00036 namespace Thyra {
00037 
00038 // Constructors/initializers/accessors
00039 
00040 template <class Scalar>
00041 ProductVector<Scalar>::ProductVector()
00042 {
00043   uninitialize();
00044 }
00045 
00046 template <class Scalar>
00047 ProductVector<Scalar>::ProductVector(
00048   const Teuchos::RefCountPtr<const ProductVectorSpace<Scalar> >  &productSpace
00049   ,const Teuchos::RefCountPtr<VectorBase<Scalar> >               vecs[]
00050   )
00051 {
00052   initialize(productSpace,vecs);
00053 }
00054 
00055 template <class Scalar>
00056 void ProductVector<Scalar>::initialize(
00057   const Teuchos::RefCountPtr<const ProductVectorSpace<Scalar> >  &productSpace
00058   ,const Teuchos::RefCountPtr<VectorBase<Scalar> >               vecs[]
00059   )
00060 {
00061   // ToDo: Validate input!
00062   numBlocks_ = productSpace->numBlocks();
00063   productSpace_ = productSpace;
00064   vecs_.resize(numBlocks_);
00065   if(vecs) {
00066     std::copy( vecs, vecs + numBlocks_, &vecs_[0] );
00067   }
00068   else {
00069     for( int k = 0; k < numBlocks_; ++k )
00070       vecs_[k] = createMember(productSpace->getBlock(k));
00071   }
00072 }
00073 
00074 template <class Scalar>
00075 void ProductVector<Scalar>::uninitialize(
00076   Teuchos::RefCountPtr<const ProductVectorSpace<Scalar> >  *productSpace
00077   ,Teuchos::RefCountPtr<VectorBase<Scalar> >               vecs[]
00078   )
00079 {
00080   if(productSpace) *productSpace = productSpace_;
00081   if(vecs) std::copy( &vecs_[0], &vecs_[0]+numBlocks_, vecs );
00082   productSpace_ = Teuchos::null;
00083   vecs_.resize(0);
00084   numBlocks_ = 0;
00085 }
00086 
00087 // Overridden from ProductVectorBase
00088 
00089 template <class Scalar>
00090 Teuchos::RefCountPtr<const ProductVectorSpaceBase<Scalar> >
00091 ProductVector<Scalar>::productSpace() const
00092 {
00093   return productSpace_;
00094 }
00095 
00096 template <class Scalar>
00097 Teuchos::RefCountPtr<VectorBase<Scalar> >
00098 ProductVector<Scalar>::getBlock(const int k)
00099 {
00100   TEST_FOR_EXCEPT( k < 0 || numBlocks_-1 < k);
00101   return vecs_[k];
00102 }
00103 
00104 template <class Scalar>
00105 Teuchos::RefCountPtr<const VectorBase<Scalar> >
00106 ProductVector<Scalar>::getBlock(const int k) const
00107 {
00108   TEST_FOR_EXCEPT( k < 0 || numBlocks_-1 < k);
00109   return vecs_[k];
00110 }
00111 
00112 // Overridden from VectorBase
00113 
00114 template <class Scalar>
00115 Teuchos::RefCountPtr< const VectorSpaceBase<Scalar> >
00116 ProductVector<Scalar>::space() const
00117 {
00118   return productSpace_;
00119 }
00120 
00121 template <class Scalar>
00122 void ProductVector<Scalar>::applyOp(
00123   const RTOpPack::RTOpT<Scalar>    &op
00124   ,const int                       num_vecs
00125   ,const VectorBase<Scalar>*       vecs[]
00126   ,const int                       num_targ_vecs
00127   ,VectorBase<Scalar>*             targ_vecs[]
00128   ,RTOpPack::ReductTarget          *reduct_obj
00129   ,const Index                     first_ele_in
00130   ,const Index                     sub_dim_in
00131   ,const Index                     global_offset_in
00132   ) const
00133 {
00134   using Teuchos::Workspace;
00135   Teuchos::WorkspaceStore* wss = Teuchos::get_default_workspace_store().get();
00136   //
00137   const Index n = productSpace_->dim();
00138   // Validate the compatibility of the vectors!
00139 #ifdef _DEBUG
00140   TEST_FOR_EXCEPTION(
00141     !(1 <= first_ele_in && first_ele_in <= n), std::out_of_range
00142     ,"ProductVector::applyOp(...): Error, "
00143     "first_ele_in = " << first_ele_in << " is not in range [1,"<<n<<"]" );
00144   TEST_FOR_EXCEPTION(
00145     sub_dim_in < 0, std::invalid_argument
00146     ,"ProductVector::applyOp(...): Error, "
00147     "sub_dim_in = " << sub_dim_in << " is not acceptable" );
00148   TEST_FOR_EXCEPTION(
00149     global_offset_in < 0, std::invalid_argument
00150     ,"ProductVector::applyOp(...): Error, "
00151     "global_offset_in = " << global_offset_in << " is not acceptable" );
00152   TEST_FOR_EXCEPTION(
00153     sub_dim_in > 0 && sub_dim_in - (first_ele_in - 1) > n, std::length_error
00154     ,"ProductVector::applyOp(...): Error, "
00155     "global_offset_in = " << global_offset_in << ", sub_dim_in = " << sub_dim_in
00156     << "first_ele_in = " << first_ele_in << " and n = " << n
00157     << " are not compatible" );
00158   bool test_failed;
00159   for(int k = 0; k < num_vecs; ++k) {
00160     test_failed = !this->space()->isCompatible(*vecs[k]->space());
00161     TEST_FOR_EXCEPTION(
00162       test_failed, Exceptions::IncompatibleVectorSpaces
00163       ,"ProductVector::applyOp(...): Error vecs["<<k<<"]->space() "
00164       <<"of type \'"<<typeid(*vecs[k]->space()).name()<<"\' is not compatible with this "
00165       <<"\'VectorSpaceBlocked\' vector space!"
00166       );
00167   }
00168   for(int k = 0; k < num_targ_vecs; ++k) {
00169     test_failed = !this->space()->isCompatible(*targ_vecs[k]->space());
00170     TEST_FOR_EXCEPTION(
00171       test_failed, Exceptions::IncompatibleVectorSpaces
00172       ,"ProductVector::applyOp(...): Error targ_vecs["<<k<<"]->space() "
00173       <<"of type \'"<<typeid(*vecs[k]->space()).name()<<"\' is not compatible with this "
00174       <<"\'VectorSpaceBlocked\' vector space!"
00175       );
00176   }
00177 #endif
00178   // Get the index of an incore-only input vector and input/output vector?
00179   const bool this_isInCore = productSpace_->isInCore();
00180   int incore_vec_k = -1, incore_targ_vec_k = -1;
00181   // Dynamic cast the pointers for the vector arguments
00182   Workspace<const ProductVector<Scalar>*>
00183     vecs_args(wss,num_vecs,false);
00184   for(int k = 0; k < num_vecs; ++k) {
00185     vecs_args[k] = dynamic_cast<const ProductVector<Scalar>*>(vecs[k]);
00186     if( vecs_args[k] == NULL ) {
00187       const bool isInCore_k = vecs[k]->space()->isInCore();
00188       if( this_isInCore && isInCore_k ) {
00189         incore_vec_k = k;
00190         break;
00191       }
00192       TEST_FOR_EXCEPTION(
00193         !this_isInCore || (this_isInCore && !isInCore_k), Exceptions::IncompatibleVectorSpaces
00194         ,"ProductVector::applyOp(...): Error vecs["<<k<<"] "
00195         <<"of type \'"<<typeid(*vecs[k]).name()<<"\' does not support the "
00196         <<"\'ProductVector<Scalar>\' interface and is not an incore vector or this is not an incore vector!"
00197         );
00198     }
00199   }
00200   Workspace<ProductVector<Scalar>*>
00201     targ_vecs_args(wss,num_targ_vecs,false);
00202   for(int k = 0; k < num_targ_vecs; ++k) {
00203     targ_vecs_args[k] = dynamic_cast<ProductVector<Scalar>*>(targ_vecs[k]);
00204     if( targ_vecs_args[k] == NULL ) {
00205       const bool isInCore_k = targ_vecs[k]->space()->isInCore();
00206       if( this_isInCore && isInCore_k ) {
00207         incore_targ_vec_k = k;
00208         break;
00209       }
00210       TEST_FOR_EXCEPTION(
00211         !this_isInCore || (this_isInCore && !isInCore_k), Exceptions::IncompatibleVectorSpaces
00212         ,"ProductVector::applyOp(...): Error targ_vecs["<<k<<"] "
00213         <<"of type \'"<<typeid(*targ_vecs[k]).name()<<"\' does not support the "
00214         <<"\'ProductVector<Scalar>\' interface and is not an incore vector or this is not an incore vector!"
00215         );
00216     }
00217   }
00218   // Let a incore-only vector handle this through explicit vector access
00219   // if all else fails?
00220   if( incore_vec_k >= 0 ) {
00221     vecs[incore_vec_k]->applyOp(
00222       op,num_vecs,vecs,num_targ_vecs,targ_vecs,reduct_obj
00223       ,first_ele_in,sub_dim_in,global_offset_in
00224       );
00225     return;
00226   }
00227   else if ( incore_targ_vec_k >= 0 ) {
00228     targ_vecs[incore_targ_vec_k]->applyOp(
00229       op,num_vecs,vecs,num_targ_vecs,targ_vecs,reduct_obj
00230       ,first_ele_in,sub_dim_in,global_offset_in
00231       );
00232     return;
00233   }
00234   // Perform the reduction on each vector segment at a time.
00235   const Index this_dim = n;
00236   const Index sub_dim  = ( sub_dim_in == 0
00237                            ? this_dim - (first_ele_in - 1)
00238                            : sub_dim_in );
00239   Index num_elements_remaining = sub_dim;
00240   const int  numBlocks = productSpace_->numBlocks();
00241   Workspace<const VectorBase<Scalar>*>
00242     sub_vecs(wss,num_vecs,false);
00243   Workspace<VectorBase<Scalar>*>
00244     sub_targ_vecs(wss,num_targ_vecs,false);
00245   Index g_off = -first_ele_in + 1;
00246   for(int k = 0; k < numBlocks; ++k) {
00247     const Index local_dim = productSpace_->getBlock(k)->dim();
00248     if( g_off < 0 && -g_off > local_dim ) {
00249       g_off += local_dim;
00250       continue;
00251     }
00252     const Index
00253       local_sub_dim = ( g_off >= 0
00254                         ? std::min( local_dim, num_elements_remaining )
00255                         : std::min( local_dim + g_off, num_elements_remaining ) );
00256     if( local_sub_dim <= 0 )
00257       break;
00258     for( int i = 0; i < num_vecs; ++i )       // Fill constituent vectors for block k
00259       sub_vecs[i] = &*vecs_args[i]->vecs_[k];
00260     for( int j = 0; j < num_targ_vecs; ++j )  // Fill constituent target vectors for block k
00261       sub_targ_vecs[j] = &*targ_vecs_args[j]->vecs_[k];
00262     Thyra::applyOp( 
00263       op
00264       ,num_vecs,num_vecs?&sub_vecs[0]:NULL
00265       ,num_targ_vecs,num_targ_vecs?&sub_targ_vecs[0]:NULL
00266       ,reduct_obj
00267       ,g_off < 0 ? -g_off + 1 : 1                                // first_ele
00268       ,local_sub_dim                                             // sub_dim
00269       ,g_off < 0 ? global_offset_in : global_offset_in + g_off   // global_offset
00270       );
00271     g_off += local_dim;
00272     num_elements_remaining -= local_sub_dim;
00273   }
00274   TEST_FOR_EXCEPT(!(num_elements_remaining==0));
00275 }
00276 
00277 template <class Scalar>
00278 void ProductVector<Scalar>::getSubVector(
00279   const Range1D& rng_in, RTOpPack::SubVectorT<Scalar>* sub_vec
00280   ) const
00281 {
00282   const Range1D
00283     rng = rng_in.full_range() ? Range1D( 1, productSpace_->dim()) : rng_in;
00284   int    kth_vector_space  = -1;
00285   Index  kth_global_offset = 0;
00286   productSpace_->getVecSpcPoss(rng.lbound(),&kth_vector_space,&kth_global_offset);
00287 #ifdef _DEBUG
00288   TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= numBlocks_ ) );
00289 #endif
00290   if( rng.lbound() + rng.size() <= kth_global_offset + 1 + vecs_[kth_vector_space]->space()->dim() ) {
00291     // This involves only one sub-vector so just return it.
00292     const_cast<const VectorBase<Scalar>*>(&*vecs_[kth_vector_space])->getSubVector(
00293       rng - kth_global_offset, sub_vec );
00294     sub_vec->setGlobalOffset( sub_vec->globalOffset() + kth_global_offset );
00295   }
00296   else {
00297     // Just let the default implementation handle this.  ToDo: In the future
00298     // we could manually construct an explicit sub-vector that spanned
00299     // two or more constituent vectors but this would be a lot of work.
00300     // However, this would require the use of temporary memory but
00301     // so what.
00302     VectorBase<Scalar>::getSubVector(rng_in,sub_vec);
00303   }
00304 }
00305 
00306 template <class Scalar>
00307 void ProductVector<Scalar>::freeSubVector(
00308   RTOpPack::SubVectorT<Scalar>* sub_vec
00309   ) const
00310 {
00311   if( sub_vec->values() == NULL ) return;
00312   int    kth_vector_space  = -1;
00313   Index  kth_global_offset = 0;
00314   productSpace_->getVecSpcPoss(sub_vec->globalOffset()+1,&kth_vector_space,&kth_global_offset);
00315 #ifdef _DEBUG
00316   TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= numBlocks_ ) );
00317 #endif
00318   if( sub_vec->globalOffset() + sub_vec->subDim() <= kth_global_offset +  vecs_[kth_vector_space]->space()->dim() ) {
00319     // This sub_vec was extracted from a single constituent vector
00320     sub_vec->setGlobalOffset( sub_vec->globalOffset() - kth_global_offset );
00321     vecs_[kth_vector_space]->freeSubVector(sub_vec);
00322   }
00323   else {
00324     // This sub_vec was created by the default implementation!
00325     VectorBase<Scalar>::freeSubVector(sub_vec);
00326   }
00327 }
00328 
00329 template <class Scalar>
00330 void ProductVector<Scalar>::getSubVector(
00331   const Range1D& rng_in, RTOpPack::MutableSubVectorT<Scalar>* sub_vec
00332   )
00333 {
00334   const Range1D
00335     rng = rng_in.full_range() ? Range1D( 1, productSpace_->dim()) : rng_in;
00336   int    kth_vector_space  = -1;
00337   Index  kth_global_offset = 0;
00338   productSpace_->getVecSpcPoss(rng.lbound(),&kth_vector_space,&kth_global_offset);
00339 #ifdef _DEBUG
00340   TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= numBlocks_ ) );
00341 #endif
00342   if( rng.lbound() + rng.size() <= kth_global_offset + 1 + vecs_[kth_vector_space]->space()->dim() ) {
00343     // This involves only one sub-vector so just return it.
00344     vecs_[kth_vector_space]->getSubVector(
00345       rng - kth_global_offset, sub_vec );
00346     sub_vec->setGlobalOffset( sub_vec->globalOffset() + kth_global_offset );
00347   }
00348   else {
00349     // Just let the default implementation handle this.  ToDo: In the future
00350     // we could manually construct an explicit sub-vector that spanned
00351     // two or more constituent vectors but this would be a lot of work.
00352     // However, this would require the use of temporary memory but
00353     // so what.
00354     VectorBase<Scalar>::getSubVector(rng_in,sub_vec);
00355   }
00356 }
00357 
00358 template <class Scalar>
00359 void ProductVector<Scalar>::commitSubVector(
00360   RTOpPack::MutableSubVectorT<Scalar>* sub_vec
00361   )
00362 {
00363   if( sub_vec->values() == NULL ) return;
00364   int    kth_vector_space  = -1;
00365   Index  kth_global_offset = 0;
00366   productSpace_->getVecSpcPoss(sub_vec->globalOffset()+1,&kth_vector_space,&kth_global_offset);
00367 #ifdef _DEBUG
00368   TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= numBlocks_ ) );
00369 #endif
00370   if( sub_vec->globalOffset() + sub_vec->subDim() <= kth_global_offset +  vecs_[kth_vector_space]->space()->dim() ) {
00371     // This sub_vec was extracted from a single constituent vector
00372     sub_vec->setGlobalOffset( sub_vec->globalOffset() - kth_global_offset );
00373     vecs_[kth_vector_space]->commitSubVector(sub_vec);
00374   }
00375   else {
00376     // This sub_vec was created by the default implementation!
00377     VectorBase<Scalar>::commitSubVector(sub_vec);
00378   }
00379 }
00380 
00381 template <class Scalar>
00382 void ProductVector<Scalar>::setSubVector(
00383   const RTOpPack::SparseSubVectorT<Scalar>& sub_vec
00384   )
00385 {
00386   int    kth_vector_space  = -1;
00387   Index  kth_global_offset = 0;
00388   productSpace_->getVecSpcPoss(sub_vec.globalOffset()+1,&kth_vector_space,&kth_global_offset);
00389 #ifdef _DEBUG
00390   TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= numBlocks_ ) );
00391 #endif
00392   if( sub_vec.globalOffset() + sub_vec.subDim() <= kth_global_offset + vecs_[kth_vector_space]->space()->dim() ) {
00393     // This sub-vector fits into a single constituent vector
00394     RTOpPack::SparseSubVectorT<Scalar> sub_vec_g = sub_vec;
00395     sub_vec_g.setGlobalOffset( sub_vec_g.globalOffset() - kth_global_offset );
00396     vecs_[kth_vector_space]->setSubVector(sub_vec_g);
00397   }
00398   else {
00399     // Let the default implementation take care of this.  ToDo: In the future
00400     // it would be possible to manually set the relevant constituent
00401     // vectors with no temp memory allocations.
00402     VectorBase<Scalar>::setSubVector(sub_vec);
00403   }
00404 }
00405 
00406 } // namespace Thyra
00407 
00408 #endif // THYRA_PRODUCT_VECTOR_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