Thyra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Thyra_DefaultClusteredSpmdProductVector_def.hpp
1 // @HEADER
2 // *****************************************************************************
3 // Thyra: Interfaces and Support for Abstract Numerical Algorithms
4 //
5 // Copyright 2004 NTESS and the Thyra contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef THYRA_DEFAULT_CLUSTERED_SPMD_PRODUCT_VECTOR_HPP
11 #define THYRA_DEFAULT_CLUSTERED_SPMD_PRODUCT_VECTOR_HPP
12 
13 #include "Thyra_DefaultClusteredSpmdProductVector_decl.hpp"
14 #include "Thyra_DefaultClusteredSpmdProductVectorSpace.hpp"
15 #include "Thyra_SpmdVectorBase.hpp"
16 #include "RTOp_parallel_helpers.h"
17 #include "RTOpPack_SPMD_apply_op.hpp"
18 #include "Teuchos_Workspace.hpp"
19 #include "Teuchos_dyn_cast.hpp"
20 #include "Teuchos_implicit_cast.hpp"
21 
22 
23 namespace Thyra {
24 
25 
26 // Constructors/initializers/accessors
27 
28 
29 template <class Scalar>
31 {
32  uninitialize();
33 }
34 
35 
36 template <class Scalar>
39  ,const Teuchos::RCP<VectorBase<Scalar> > vecs[]
40  )
41 {
42  initialize(productSpace_in,vecs);
43 }
44 
45 
46 template <class Scalar>
49  ,const Teuchos::RCP<VectorBase<Scalar> > vecs[]
50  )
51 {
52  // ToDo: Validate input!
53  productSpace_ = productSpace_in;
54  const int numBlocks = productSpace_->numBlocks();
55  vecs_.resize(numBlocks);
56  if(vecs) {
57  std::copy( vecs, vecs + numBlocks, &vecs_[0] );
58  }
59  else {
60  for( int k = 0; k < numBlocks; ++k )
61  vecs_[k] = createMember(productSpace_->getBlock(k));
62  }
63 }
64 
65 
66 template <class Scalar>
70  )
71 {
72  const int numBlocks = vecs_.size();
73  if(productSpace_in) *productSpace_in = productSpace_;
74  if(vecs) std::copy( &vecs_[0], &vecs_[0]+numBlocks, vecs );
75  productSpace_ = Teuchos::null;
76  vecs_.resize(0);
77 }
78 
79 
80 // Overridden from ProductVectorBase
81 
82 
83 template <class Scalar>
86 {
88  TEUCHOS_TEST_FOR_EXCEPT( ! ( 0 <= k && k < implicit_cast<int>(vecs_.size()) ) );
89  return vecs_[k];
90 }
91 
92 
93 template <class Scalar>
96 {
98  TEUCHOS_TEST_FOR_EXCEPT( ! ( 0 <= k && k < implicit_cast<int>(vecs_.size()) ) );
99  return vecs_[k];
100 }
101 
102 
103 // Overridden from ProductVectorBase
104 
105 
106 template <class Scalar>
109 {
110  return productSpace_;
111 }
112 
113 
114 template <class Scalar>
116 {
118  TEUCHOS_TEST_FOR_EXCEPT( ! ( 0 <= k && k < implicit_cast<int>(vecs_.size()) ) );
119  return false;
120 }
121 
122 
123 template <class Scalar>
126 {
127  return getNonconstVectorBlock(k);
128 }
129 
130 
131 template <class Scalar>
134 {
135  return getVectorBlock(k);
136 }
137 
138 
139 // Overridden from VectorBase
140 
141 
142 template <class Scalar>
145 {
146  return productSpace_;
147 }
148 
149 
150 // Overridden protected members from VectorBase
151 
152 
153 template <class Scalar>
155  const RTOpPack::RTOpT<Scalar> &op,
156  const ArrayView<const Ptr<const VectorBase<Scalar> > > &vecs,
157  const ArrayView<const Ptr<VectorBase<Scalar> > > &targ_vecs,
158  const Ptr<RTOpPack::ReductTarget> &reduct_obj,
159  const Ordinal global_offset_in
160  ) const
161 {
162 
163  const Ordinal first_ele_offset_in = 0;
164  const Ordinal sub_dim_in = -1;
165 
166  using Teuchos::null;
167  using Teuchos::ptr_dynamic_cast;
168  using Teuchos::tuple;
169 
170  const int num_vecs = vecs.size();
171  const int num_targ_vecs = targ_vecs.size();
172 
173  // Validate input
174 #ifdef TEUCHOS_DEBUG
176  global_offset_in < 0, std::invalid_argument,
177  "DefaultClusteredSpmdProductVector::applyOp(...): Error, "
178  "global_offset_in = " << global_offset_in << " is not acceptable" );
179  bool test_failed;
180  for (int k = 0; k < num_vecs; ++k) {
181  test_failed = !this->space()->isCompatible(*vecs[k]->space());
184  "DefaultClusteredSpmdProductVector::applyOp(...): Error vecs["<<k<<"]->space() "
185  <<"of type \'"<<typeName(*vecs[k]->space())<<"\' is not compatible with this "
186  <<"\'VectorSpaceBlocked\' vector space!"
187  );
188  }
189  for (int k = 0; k < num_targ_vecs; ++k) {
190  test_failed = !this->space()->isCompatible(*targ_vecs[k]->space());
193  ,"DefaultClusteredSpmdProductVector::applyOp(...): Error targ_vecs["<<k<<"]->space() "
194  <<"of type \'"<<typeName(*vecs[k]->space())<<"\' is not compatible with this "
195  <<"\'VectorSpaceBlocked\' vector space!"
196  );
197  }
198 #endif
199 
200  //
201  // Cast all of the vector arguments to DefaultClusteredSpmdProductVector and
202  // make sure that they are all compatible!
203  //
205  for ( int k = 0; k < num_vecs; ++k ) {
206 #ifdef TEUCHOS_DEBUG
207  TEUCHOS_TEST_FOR_EXCEPT(vecs[k]==null);
208 #endif
209  cl_vecs[k] = ptr_dynamic_cast<const DefaultClusteredSpmdProductVector<Scalar> >(vecs[k],true);
210  }
211  Array<Ptr<DefaultClusteredSpmdProductVector<Scalar> > > cl_targ_vecs(num_targ_vecs);
212  for ( int k = 0; k < num_targ_vecs; ++k ) {
213 #ifdef TEUCHOS_DEBUG
214  TEUCHOS_TEST_FOR_EXCEPT(targ_vecs[k]==null);
215 #endif
216  cl_targ_vecs[k] = ptr_dynamic_cast<DefaultClusteredSpmdProductVector<Scalar> >(targ_vecs[k],true);
217  }
218 
219  //
220  // Get the overlap of the element for this cluster that will participate in
221  // the RTOp operation.
222  //
224  intraClusterComm = productSpace_->intraClusterComm(),
225  interClusterComm = productSpace_->interClusterComm();
226  const Ordinal
227  clusterSubDim = productSpace_->clusterSubDim(),
228  clusterOffset = productSpace_->clusterOffset(),
229  globalDim = productSpace_->dim();
230  Ordinal overlap_first_cluster_ele_off = 0;
231  Ordinal overlap_cluster_sub_dim = 0;
232  Ordinal overlap_global_off = 0;
233  if (clusterSubDim) {
234  RTOp_parallel_calc_overlap(
235  globalDim,clusterSubDim,clusterOffset,first_ele_offset_in,sub_dim_in
236  ,global_offset_in
237  ,&overlap_first_cluster_ele_off,&overlap_cluster_sub_dim,&overlap_global_off
238  );
239  }
240 
241  //
242  // Perform the RTOp for each set of block vectors just within this cluster
243  // of processes.
244  //
246  if (!is_null(reduct_obj))
247  i_reduct_obj = op.reduct_obj_create();
248  // Note: i_reduct_obj will accumulate the reduction within this cluster of
249  // processes.
250  const int numBlocks = vecs_.size();
251  if (overlap_first_cluster_ele_off >=0) {
252 
253  //
254  // There is overlap with at least one element in one block
255  // vector for this cluster
256  //
257  Array<Ptr<const VectorBase<Scalar> > > v_vecs(num_vecs);
258  Array<Ptr<VectorBase<Scalar> > > v_targ_vecs(num_targ_vecs);
259  Ordinal overall_global_offset = overlap_global_off;
260  for( int j = 0; j < numBlocks; ++j ) {
261  const VectorBase<Scalar>
262  &v = *vecs_[j];
264  &v_space = *v.space();
265  // Load up the constutuent block SPMD vectors
266  for( int k = 0; k < num_vecs ; ++k )
267  v_vecs[k] = cl_vecs[k]->vecs_[j].ptr();
268  for( int k = 0; k < num_targ_vecs ; ++k )
269  v_targ_vecs[k] = cl_targ_vecs[k]->vecs_[j].ptr();
271  numBlocks > 1, std::logic_error
272  ,"Error, Have not implemented general support for numBlocks > 1!"
273  ); // ToDo: Fix the below code for numBlocks_ > 1!
274  Ordinal v_global_offset = overall_global_offset;
275  // Apply RTOp on just this cluster
276  Thyra::applyOp<Scalar>(
277  op, v_vecs(), v_targ_vecs(), i_reduct_obj.ptr(),
278  v_global_offset);
279  //
280  overall_global_offset += v_space.dim();
281  }
282 
283  }
284 
285  //
286  // Perform the global reduction across all of the root processes in each of
287  // the clusters and then move the global reduction out to each of the
288  // processes within the cluster.
289  //
290  if (!is_null(reduct_obj)) {
292  icl_reduct_obj = op.reduct_obj_create();
293  // First, accumulate the global reduction across all of the elements by
294  // just performing the global reduction involving the root processes of
295  // each cluster.
296  if (interClusterComm.get()) {
297  RTOpPack::SPMD_all_reduce(
298  &*interClusterComm,
299  op,
300  1,
301  tuple<const RTOpPack::ReductTarget*>(&*i_reduct_obj).getRawPtr(),
302  tuple<RTOpPack::ReductTarget*>(&*icl_reduct_obj).getRawPtr()
303  );
304  }
305  // Now the root processes in each cluster have the full global reduction
306  // across all elements stored in *icl_reduct_obj and the other processes
307  // in each cluster have empty reductions in *icl_reduct_obj. The last
308  // thing to do is to just perform the reduction within each cluster of
309  // processes and to add into the in/out *reduct_obj.
310  RTOpPack::SPMD_all_reduce(
311  &*intraClusterComm,
312  op,
313  1,
314  tuple<const RTOpPack::ReductTarget*>(&*icl_reduct_obj).getRawPtr(),
315  tuple<RTOpPack::ReductTarget*>(&*reduct_obj).getRawPtr()
316  );
317  // ToDo: Replace the above operation with a reduction across clustere into
318  // reduct_obj in the root processes and then broadcast the result to all
319  // of the slave processes.
320  }
321 
322 }
323 
324 
325 } // namespace Thyra
326 
327 
328 #endif // THYRA_DEFAULT_CLUSTERED_SPMD_PRODUCT_VECTOR_HPP
virtual RCP< const VectorSpaceBase< Scalar > > space() const =0
Return a smart pointer to the vector space that this vector belongs to.
void initialize(int *argc, char ***argv)
void uninitialize(Teuchos::RCP< const DefaultClusteredSpmdProductVectorSpace< Scalar > > *productSpace=NULL, Teuchos::RCP< VectorBase< Scalar > > vecs[]=NULL)
Uninitialize.
Teuchos::RCP< const ProductVectorSpaceBase< Scalar > > productSpace() const
bool is_null(const boost::shared_ptr< T > &p)
Thrown if vector spaces are incompatible.
void applyOpImpl(const RTOpPack::RTOpT< Scalar > &op, const ArrayView< const Ptr< const VectorBase< Scalar > > > &vecs, const ArrayView< const Ptr< VectorBase< Scalar > > > &targ_vecs, const Ptr< RTOpPack::ReductTarget > &reduct_obj, const Ordinal global_offset) const
Teuchos::RCP< const VectorBase< Scalar > > getVectorBlock(const int k) const
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Abstract interface for objects that represent a space for vectors.
Teuchos::RCP< const MultiVectorBase< Scalar > > getMultiVectorBlock(const int k) const
Teuchos::Ordinal Ordinal
Type for the dimension of a vector space. `*.
void initialize(const Teuchos::RCP< const DefaultClusteredSpmdProductVectorSpace< Scalar > > &productSpace, const Teuchos::RCP< VectorBase< Scalar > > vecs[])
Initialize.
Ptr< T > ptr() const
Teuchos::RCP< MultiVectorBase< Scalar > > getNonconstMultiVectorBlock(const int k)
Concrete implementation of a clustered Spmd-based product vector.
TypeTo implicit_cast(const TypeFrom &t)
Abstract interface for finite-dimensional dense vectors.
Teuchos::RCP< const VectorSpaceBase< Scalar > > space() const
Teuchos::RCP< ReductTarget > reduct_obj_create() const
Teuchos::RCP< VectorBase< Scalar > > getNonconstVectorBlock(const int k)
virtual Ordinal dim() const =0
Return the dimension of the vector space.
DefaultClusteredSpmdProductVector()
Constructs to uninitialized (see postconditions for uninitialize()).
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
std::string typeName(const T &t)