Thyra_DefaultClusteredSpmdProductVector.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_DEFAULT_CLUSTERED_SPMD_PRODUCT_VECTOR_HPP
00030 #define THYRA_DEFAULT_CLUSTERED_SPMD_PRODUCT_VECTOR_HPP
00031 
00032 #include "Thyra_DefaultClusteredSpmdProductVectorDecl.hpp"
00033 #include "Thyra_DefaultClusteredSpmdProductVectorSpace.hpp"
00034 #include "Thyra_SpmdVectorBase.hpp"
00035 #include "RTOp_parallel_helpers.h"
00036 #include "RTOpPack_SPMD_apply_op.hpp"
00037 #include "Teuchos_Workspace.hpp"
00038 #include "Teuchos_dyn_cast.hpp"
00039 #include "Teuchos_arrayArg.hpp"
00040 #include "Teuchos_implicit_cast.hpp"
00041 
00042 namespace Thyra {
00043 
00044 // Constructors/initializers/accessors
00045 
00046 template <class Scalar>
00047 DefaultClusteredSpmdProductVector<Scalar>::DefaultClusteredSpmdProductVector()
00048 {
00049   uninitialize();
00050 }
00051 
00052 template <class Scalar>
00053 DefaultClusteredSpmdProductVector<Scalar>::DefaultClusteredSpmdProductVector(
00054   const Teuchos::RCP<const DefaultClusteredSpmdProductVectorSpace<Scalar> >  &productSpace
00055   ,const Teuchos::RCP<VectorBase<Scalar> >                                   vecs[]
00056   )
00057 {
00058   initialize(productSpace,vecs);
00059 }
00060 
00061 template <class Scalar>
00062 void DefaultClusteredSpmdProductVector<Scalar>::initialize(
00063   const Teuchos::RCP<const DefaultClusteredSpmdProductVectorSpace<Scalar> >  &productSpace
00064   ,const Teuchos::RCP<VectorBase<Scalar> >                                   vecs[]
00065   )
00066 {
00067   // ToDo: Validate input!
00068   productSpace_ = productSpace;
00069   const int numBlocks = productSpace_->numBlocks();
00070   vecs_.resize(numBlocks);
00071   if(vecs) {
00072     std::copy( vecs, vecs + numBlocks, &vecs_[0] );
00073   }
00074   else {
00075     for( int k = 0; k < numBlocks; ++k )
00076       vecs_[k] = createMember(productSpace->getBlock(k));
00077   }
00078 }
00079 
00080 template <class Scalar>
00081 void DefaultClusteredSpmdProductVector<Scalar>::uninitialize(
00082   Teuchos::RCP<const DefaultClusteredSpmdProductVectorSpace<Scalar> >  *productSpace
00083   ,Teuchos::RCP<VectorBase<Scalar> >                                   vecs[]
00084   )
00085 {
00086   const int numBlocks = vecs_.size();
00087   if(productSpace) *productSpace = productSpace_;
00088   if(vecs) std::copy( &vecs_[0], &vecs_[0]+numBlocks, vecs );
00089   productSpace_ = Teuchos::null;
00090   vecs_.resize(0);
00091 }
00092 
00093 // Overridden from ProductVectorBase
00094 
00095 template <class Scalar>
00096 Teuchos::RCP<VectorBase<Scalar> >
00097 DefaultClusteredSpmdProductVector<Scalar>::getNonconstVectorBlock(const int k)
00098 {
00099   using Teuchos::implicit_cast;
00100   TEST_FOR_EXCEPT( ! ( 0 <= k && k < implicit_cast<int>(vecs_.size()) ) );
00101   return vecs_[k];
00102 }
00103 
00104 template <class Scalar>
00105 Teuchos::RCP<const VectorBase<Scalar> >
00106 DefaultClusteredSpmdProductVector<Scalar>::getVectorBlock(const int k) const
00107 {
00108   using Teuchos::implicit_cast;
00109   TEST_FOR_EXCEPT( ! ( 0 <= k && k < implicit_cast<int>(vecs_.size()) ) );
00110   return vecs_[k];
00111 }
00112 
00113 // Overridden from ProductVectorBase
00114 
00115 template <class Scalar>
00116 Teuchos::RCP<const ProductVectorSpaceBase<Scalar> >
00117 DefaultClusteredSpmdProductVector<Scalar>::productSpace() const
00118 {
00119   return productSpace_;
00120 }
00121 
00122 template <class Scalar>
00123 bool DefaultClusteredSpmdProductVector<Scalar>::blockIsConst(const int k) const
00124 {
00125   using Teuchos::implicit_cast;
00126   TEST_FOR_EXCEPT( ! ( 0 <= k && k < implicit_cast<int>(vecs_.size()) ) );
00127   return false;
00128 }
00129 
00130 template <class Scalar>
00131 Teuchos::RCP<MultiVectorBase<Scalar> >
00132 DefaultClusteredSpmdProductVector<Scalar>::getNonconstMultiVectorBlock(const int k)
00133 {
00134   return getNonconstVectorBlock(k);
00135 }
00136 
00137 template <class Scalar>
00138 Teuchos::RCP<const MultiVectorBase<Scalar> >
00139 DefaultClusteredSpmdProductVector<Scalar>::getMultiVectorBlock(const int k) const
00140 {
00141   return getVectorBlock(k);
00142 }
00143 
00144 // Overridden from VectorBase
00145 
00146 template <class Scalar>
00147 Teuchos::RCP< const VectorSpaceBase<Scalar> >
00148 DefaultClusteredSpmdProductVector<Scalar>::space() const
00149 {
00150   return productSpace_;
00151 }
00152 
00153 template <class Scalar>
00154 void DefaultClusteredSpmdProductVector<Scalar>::applyOp(
00155   const RTOpPack::RTOpT<Scalar>    &op
00156   ,const int                       num_vecs
00157   ,const VectorBase<Scalar>*const  vecs[]
00158   ,const int                       num_targ_vecs
00159   ,VectorBase<Scalar>*const        targ_vecs[]
00160   ,RTOpPack::ReductTarget          *reduct_obj
00161   ,const Index                     first_ele_offset_in
00162   ,const Index                     sub_dim_in
00163   ,const Index                     global_offset_in
00164   ) const
00165 {
00166   using Teuchos::dyn_cast;
00167   using Teuchos::Workspace;
00168   Teuchos::WorkspaceStore* wss = Teuchos::get_default_workspace_store().get();
00169   //
00170   const Index n = productSpace_->dim();
00171   // Validate input
00172 #ifdef TEUCHOS_DEBUG
00173   TEST_FOR_EXCEPTION(
00174     !(0 <= first_ele_offset_in && first_ele_offset_in < n), std::out_of_range
00175     ,"DefaultClusteredSpmdProductVector::applyOp(...): Error, "
00176     "first_ele_offset_in = " << first_ele_offset_in << " is not in range [0,"<<(n-1)<<"]" );
00177   TEST_FOR_EXCEPTION(
00178     global_offset_in < 0, std::invalid_argument
00179     ,"DefaultClusteredSpmdProductVector::applyOp(...): Error, "
00180     "global_offset_in = " << global_offset_in << " is not acceptable" );
00181   TEST_FOR_EXCEPTION(
00182     sub_dim_in > 0 && sub_dim_in - first_ele_offset_in > n, std::length_error
00183     ,"DefaultClusteredSpmdProductVector::applyOp(...): Error, "
00184     "global_offset_in = " << global_offset_in << ", sub_dim_in = " << sub_dim_in
00185     << "first_ele_offset_in = " << first_ele_offset_in << " and n = " << n
00186     << " are not compatible" );
00187   bool test_failed;
00188   for(int k = 0; k < num_vecs; ++k) {
00189     test_failed = !this->space()->isCompatible(*vecs[k]->space());
00190     TEST_FOR_EXCEPTION(
00191       test_failed, Exceptions::IncompatibleVectorSpaces
00192       ,"DefaultClusteredSpmdProductVector::applyOp(...): Error vecs["<<k<<"]->space() "
00193       <<"of type \'"<<typeName(*vecs[k]->space())<<"\' is not compatible with this "
00194       <<"\'VectorSpaceBlocked\' vector space!"
00195       );
00196   }
00197   for(int k = 0; k < num_targ_vecs; ++k) {
00198     test_failed = !this->space()->isCompatible(*targ_vecs[k]->space());
00199     TEST_FOR_EXCEPTION(
00200       test_failed, Exceptions::IncompatibleVectorSpaces
00201       ,"DefaultClusteredSpmdProductVector::applyOp(...): Error targ_vecs["<<k<<"]->space() "
00202       <<"of type \'"<<typeName(*vecs[k]->space())<<"\' is not compatible with this "
00203       <<"\'VectorSpaceBlocked\' vector space!"
00204       );
00205   }
00206 #endif
00207   //
00208   // Cast all of the vector arguments to DefaultClusteredSpmdProductVector and
00209   // make sure that they are all compatible!
00210   //
00211   Workspace<const DefaultClusteredSpmdProductVector<Scalar>*> cl_vecs(wss,num_vecs);
00212   for( int k = 0; k < num_vecs; ++k ) {
00213 #ifdef TEUCHOS_DEBUG
00214     TEST_FOR_EXCEPT(vecs[k]==NULL);
00215 #endif
00216     cl_vecs[k] = &dyn_cast<const DefaultClusteredSpmdProductVector<Scalar> >(*vecs[k]);
00217   }
00218   Workspace<DefaultClusteredSpmdProductVector<Scalar>*> cl_targ_vecs(wss,num_targ_vecs);
00219   for( int k = 0; k < num_targ_vecs; ++k ) {
00220 #ifdef TEUCHOS_DEBUG
00221     TEST_FOR_EXCEPT(targ_vecs[k]==NULL);
00222 #endif
00223     cl_targ_vecs[k] = &dyn_cast<DefaultClusteredSpmdProductVector<Scalar> >(*targ_vecs[k]);
00224   }
00225   //
00226   // Get the overlap of the element for this cluster that will participate in
00227   // the RTOp operation.
00228   //
00229   const Teuchos::RCP<const Teuchos::Comm<Index> >
00230     intraClusterComm = productSpace_->intraClusterComm(),
00231     interClusterComm = productSpace_->interClusterComm();
00232   const Index
00233     clusterSubDim = productSpace_->clusterSubDim(),
00234     clusterOffset = productSpace_->clusterOffset(),
00235     globalDim = productSpace_->dim();
00236   Index  overlap_first_cluster_ele_off  = 0;
00237   Index  overlap_cluster_sub_dim        = 0;
00238   Index  overlap_global_off             = 0;
00239   if(clusterSubDim) {
00240     RTOp_parallel_calc_overlap(
00241       globalDim,clusterSubDim,clusterOffset,first_ele_offset_in,sub_dim_in
00242       ,global_offset_in
00243       ,&overlap_first_cluster_ele_off,&overlap_cluster_sub_dim,&overlap_global_off
00244       );
00245   }
00246   //
00247   // Perform the RTOp for each set of block vectors just within this cluster
00248   // of processes.
00249   //
00250   Teuchos::RCP<RTOpPack::ReductTarget> i_reduct_obj;
00251   if(reduct_obj) i_reduct_obj = op.reduct_obj_create();
00252   // Note: i_reduct_obj will accumulate the reduction within this cluster of
00253   // processes.
00254   const int numBlocks = vecs_.size();
00255   if( overlap_first_cluster_ele_off >=0 ) {
00256     //
00257     // There is overlap with at least one element in one block
00258     // vector for this cluster
00259     //
00260     Workspace<const VectorBase<Scalar>*>  v_vecs(wss,num_vecs);
00261     Workspace<VectorBase<Scalar>*>        v_targ_vecs(wss,num_targ_vecs);
00262     Index overall_global_offset = overlap_global_off;
00263     for( int j = 0; j < numBlocks; ++j ) {
00264       const VectorBase<Scalar>
00265         &v = *vecs_[j];
00266       const VectorSpaceBase<Scalar>
00267         &v_space = *v.space();
00268       // Load up the constutuent block SPMD vectors
00269       for( int k = 0; k < num_vecs ; ++k )
00270         v_vecs[k] = &*cl_vecs[k]->vecs_[j];
00271       for( int k = 0; k < num_targ_vecs ; ++k )
00272         v_targ_vecs[k] = &*cl_targ_vecs[k]->vecs_[j];
00273       TEST_FOR_EXCEPTION(
00274         numBlocks > 1, std::logic_error
00275         ,"Error, Have not implemented general support for numBlocks > 1!"
00276         ); // ToDo: Fix the below code for numBlocks_ > 1!
00277       Index
00278         v_global_offset     = overall_global_offset,
00279         v_first_ele_offset  = overlap_first_cluster_ele_off,
00280         v_sub_dim           = overlap_cluster_sub_dim;
00281       // Apply RTOp on just this cluster
00282       Thyra::applyOp(
00283         op
00284         ,num_vecs, num_vecs ? &v_vecs[0] : NULL
00285         ,num_targ_vecs, num_targ_vecs ? &v_targ_vecs[0] : NULL
00286         ,i_reduct_obj.get() ? &*i_reduct_obj : NULL
00287         ,v_first_ele_offset,v_sub_dim,v_global_offset
00288         );
00289       //
00290       overall_global_offset += v_space.dim();
00291     }
00292   }
00293   //
00294   // Perform the global reduction across all of the root processes in each of
00295   // the clusters and then move the global reduction out to each of the
00296   // processes within the cluster.
00297   //
00298   if( reduct_obj ) {
00299     Teuchos::RCP<RTOpPack::ReductTarget>
00300       icl_reduct_obj = op.reduct_obj_create();
00301     // First, accumulate the global reduction across all of the elements by
00302     // just performing the global reduction involving the root processes of
00303     // each cluster.
00304     if(interClusterComm.get()) {
00305       RTOpPack::SPMD_all_reduce(
00306         &*interClusterComm
00307         ,op
00308         ,1
00309         ,Teuchos::arrayArg<const RTOpPack::ReductTarget*>(&*i_reduct_obj)()
00310         ,Teuchos::arrayArg<RTOpPack::ReductTarget*>(&*icl_reduct_obj)()
00311         );
00312     }
00313     // Now the root processes in each cluster have the full global reduction
00314     // across all elements stored in *icl_reduct_obj and the other processes
00315     // in each cluster have empty reductions in *icl_reduct_obj.  The last
00316     // thing to do is to just perform the reduction within each cluster of
00317     // processes and to add into the in/out *reduct_obj.
00318     RTOpPack::SPMD_all_reduce(
00319       &*intraClusterComm
00320       ,op
00321       ,1
00322       ,Teuchos::arrayArg<const RTOpPack::ReductTarget*>(&*icl_reduct_obj)()
00323       ,Teuchos::arrayArg<RTOpPack::ReductTarget*>(reduct_obj)()
00324       );
00325     // ToDo: Replace the above operation with a reduction across clustes into
00326     // reduct_obj in the root processes and then broadcast the result to all
00327     // of the slave processes.
00328   }
00329 }
00330 
00331 } // namespace Thyra
00332 
00333 #endif // THYRA_DEFAULT_CLUSTERED_SPMD_PRODUCT_VECTOR_HPP

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