Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Belos_TpetraAdapter_MP_Vector.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Stokhos Package
4 //
5 // Copyright 2009 NTESS and the Stokhos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef BELOS_TPETRA_ADAPTER_MP_VECTOR_HPP
11 #define BELOS_TPETRA_ADAPTER_MP_VECTOR_HPP
12 
13 #include "BelosTpetraAdapter.hpp"
16 #include "KokkosBlas.hpp"
17 
18 #ifdef HAVE_BELOS_TSQR
20 #endif // HAVE_BELOS_TSQR
21 
22 namespace Belos {
23 
25  //
26  // Implementation of Belos::MultiVecTraits for Tpetra::MultiVector.
27  //
29 
40  template<class Storage, class LO, class GO, class Node>
41  class MultiVecTraits<typename Storage::value_type,
42  Tpetra::MultiVector< Sacado::MP::Vector<Storage>,
43  LO, GO, Node > > {
44  public:
45  typedef typename Storage::ordinal_type s_ordinal;
46  typedef typename Storage::value_type BaseScalar;
48  typedef Tpetra::MultiVector<Scalar, LO, GO, Node> MV;
49  public:
50  typedef typename Tpetra::MultiVector<Scalar,LO,GO,Node>::dot_type dot_type;
51  typedef typename Tpetra::MultiVector<Scalar,LO,GO,Node>::mag_type mag_type;
52 
58  static Teuchos::RCP<MV> Clone (const MV& X, const int numVecs) {
59  Teuchos::RCP<MV> Y (new MV (X.getMap (), numVecs, false));
60  Y->setCopyOrView (Teuchos::View);
61  return Y;
62  }
63 
65  static Teuchos::RCP<MV> CloneCopy (const MV& X)
66  {
67  // Make a deep copy of X. The one-argument copy constructor
68  // does a shallow copy by default; the second argument tells it
69  // to do a deep copy.
70  Teuchos::RCP<MV> X_copy (new MV (X, Teuchos::Copy));
71  // Make Tpetra::MultiVector use the new view semantics. This is
72  // a no-op for the Kokkos refactor version of Tpetra; it only
73  // does something for the "classic" version of Tpetra. This
74  // shouldn't matter because Belos only handles MV through RCP
75  // and through this interface anyway, but it doesn't hurt to set
76  // it and make sure that it works.
77  X_copy->setCopyOrView (Teuchos::View);
78  return X_copy;
79  }
80 
92  static Teuchos::RCP<MV>
93  CloneCopy (const MV& mv, const std::vector<int>& index)
94  {
95 #ifdef HAVE_TPETRA_DEBUG
96  const char fnName[] = "Belos::MultiVecTraits::CloneCopy(mv,index)";
97  const size_t inNumVecs = mv.getNumVectors ();
99  index.size () > 0 && *std::min_element (index.begin (), index.end ()) < 0,
100  std::runtime_error, fnName << ": All indices must be nonnegative.");
102  index.size () > 0 &&
103  static_cast<size_t> (*std::max_element (index.begin (), index.end ())) >= inNumVecs,
104  std::runtime_error,
105  fnName << ": All indices must be strictly less than the number of "
106  "columns " << inNumVecs << " of the input multivector mv.");
107 #endif // HAVE_TPETRA_DEBUG
108 
109  // Tpetra wants an array of size_t, not of int.
110  Teuchos::Array<size_t> columns (index.size ());
111  for (std::vector<int>::size_type j = 0; j < index.size (); ++j) {
112  columns[j] = index[j];
113  }
114  // mfh 14 Aug 2014: Tpetra already detects and optimizes for a
115  // continuous column index range in MultiVector::subCopy, so we
116  // don't have to check here.
117  Teuchos::RCP<MV> X_copy = mv.subCopy (columns ());
118  X_copy->setCopyOrView (Teuchos::View);
119  return X_copy;
120  }
121 
128  static Teuchos::RCP<MV>
129  CloneCopy (const MV& mv, const Teuchos::Range1D& index)
130  {
131  const bool validRange = index.size() > 0 &&
132  index.lbound() >= 0 &&
133  index.ubound() < GetNumberVecs(mv);
134  if (! validRange) { // invalid range; generate error message
135  std::ostringstream os;
136  os << "Belos::MultiVecTraits::CloneCopy(mv,index=["
137  << index.lbound() << "," << index.ubound() << "]): ";
139  index.size() == 0, std::invalid_argument,
140  os.str() << "Empty index range is not allowed.");
142  index.lbound() < 0, std::invalid_argument,
143  os.str() << "Index range includes negative index/ices, which is not "
144  "allowed.");
146  index.ubound() >= GetNumberVecs(mv), std::invalid_argument,
147  os.str() << "Index range exceeds number of vectors "
148  << mv.getNumVectors() << " in the input multivector.");
149  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
150  os.str() << "Should never get here!");
151  }
152  Teuchos::RCP<MV> X_copy = mv.subCopy (index);
153  X_copy->setCopyOrView (Teuchos::View);
154  return X_copy;
155  }
156 
157 
158  static Teuchos::RCP<MV>
159  CloneViewNonConst (MV& mv, const std::vector<int>& index)
160  {
161 #ifdef HAVE_TPETRA_DEBUG
162  const char fnName[] = "Belos::MultiVecTraits::CloneViewNonConst(mv,index)";
163  const size_t numVecs = mv.getNumVectors ();
165  index.size () > 0 && *std::min_element (index.begin (), index.end ()) < 0,
166  std::invalid_argument,
167  fnName << ": All indices must be nonnegative.");
169  index.size () > 0 &&
170  static_cast<size_t> (*std::max_element (index.begin (), index.end ())) >= numVecs,
171  std::invalid_argument,
172  fnName << ": All indices must be strictly less than the number of "
173  "columns " << numVecs << " in the input MultiVector mv.");
174 #endif // HAVE_TPETRA_DEBUG
175 
176  // Tpetra wants an array of size_t, not of int.
177  Teuchos::Array<size_t> columns (index.size ());
178  for (std::vector<int>::size_type j = 0; j < index.size (); ++j) {
179  columns[j] = index[j];
180  }
181  // mfh 14 Aug 2014: Tpetra already detects and optimizes for a
182  // continuous column index range in
183  // MultiVector::subViewNonConst, so we don't have to check here.
184  Teuchos::RCP<MV> X_view = mv.subViewNonConst (columns ());
185  X_view->setCopyOrView (Teuchos::View);
186  return X_view;
187  }
188 
189  static Teuchos::RCP<MV>
191  {
192  // NOTE (mfh 11 Jan 2011) We really should check for possible
193  // overflow of int here. However, the number of columns in a
194  // multivector typically fits in an int.
195  const int numCols = static_cast<int> (mv.getNumVectors());
196  const bool validRange = index.size() > 0 &&
197  index.lbound() >= 0 && index.ubound() < numCols;
198  if (! validRange) {
199  std::ostringstream os;
200  os << "Belos::MultiVecTraits::CloneViewNonConst(mv,index=["
201  << index.lbound() << ", " << index.ubound() << "]): ";
203  index.size() == 0, std::invalid_argument,
204  os.str() << "Empty index range is not allowed.");
206  index.lbound() < 0, std::invalid_argument,
207  os.str() << "Index range includes negative inde{x,ices}, which is "
208  "not allowed.");
210  index.ubound() >= numCols, std::invalid_argument,
211  os.str() << "Index range exceeds number of vectors " << numCols
212  << " in the input multivector.");
214  true, std::logic_error,
215  os.str() << "Should never get here!");
216  }
217  Teuchos::RCP<MV> X_view = mv.subViewNonConst (index);
218  X_view->setCopyOrView (Teuchos::View);
219  return X_view;
220  }
221 
223  CloneView (const MV& mv, const std::vector<int>& index)
224  {
225 #ifdef HAVE_TPETRA_DEBUG
226  const char fnName[] = "Belos::MultiVecTraits<Scalar, "
227  "Tpetra::MultiVector<...> >::CloneView(mv,index)";
228  const size_t numVecs = mv.getNumVectors ();
230  *std::min_element (index.begin (), index.end ()) < 0,
231  std::invalid_argument,
232  fnName << ": All indices must be nonnegative.");
234  static_cast<size_t> (*std::max_element (index.begin (), index.end ())) >= numVecs,
235  std::invalid_argument,
236  fnName << ": All indices must be strictly less than the number of "
237  "columns " << numVecs << " in the input MultiVector mv.");
238 #endif // HAVE_TPETRA_DEBUG
239 
240  // Tpetra wants an array of size_t, not of int.
241  Teuchos::Array<size_t> columns (index.size ());
242  for (std::vector<int>::size_type j = 0; j < index.size (); ++j) {
243  columns[j] = index[j];
244  }
245  // mfh 14 Aug 2014: Tpetra already detects and optimizes for a
246  // continuous column index range in MultiVector::subView, so we
247  // don't have to check here.
248  Teuchos::RCP<const MV> X_view = mv.subView (columns);
249  Teuchos::rcp_const_cast<MV> (X_view)->setCopyOrView (Teuchos::View);
250  return X_view;
251  }
252 
254  CloneView (const MV& mv, const Teuchos::Range1D& index)
255  {
256  // NOTE (mfh 11 Jan 2011) We really should check for possible
257  // overflow of int here. However, the number of columns in a
258  // multivector typically fits in an int.
259  const int numCols = static_cast<int> (mv.getNumVectors());
260  const bool validRange = index.size() > 0 &&
261  index.lbound() >= 0 && index.ubound() < numCols;
262  if (! validRange) {
263  std::ostringstream os;
264  os << "Belos::MultiVecTraits::CloneView(mv, index=["
265  << index.lbound () << ", " << index.ubound() << "]): ";
266  TEUCHOS_TEST_FOR_EXCEPTION(index.size() == 0, std::invalid_argument,
267  os.str() << "Empty index range is not allowed.");
268  TEUCHOS_TEST_FOR_EXCEPTION(index.lbound() < 0, std::invalid_argument,
269  os.str() << "Index range includes negative index/ices, which is not "
270  "allowed.");
272  index.ubound() >= numCols, std::invalid_argument,
273  os.str() << "Index range exceeds number of vectors " << numCols
274  << " in the input multivector.");
275  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
276  os.str() << "Should never get here!");
277  }
278  Teuchos::RCP<const MV> X_view = mv.subView (index);
279  Teuchos::rcp_const_cast<MV> (X_view)->setCopyOrView (Teuchos::View);
280  return X_view;
281  }
282 
283  static ptrdiff_t GetGlobalLength (const MV& mv) {
284  return static_cast<ptrdiff_t> (mv.getGlobalLength ());
285  }
286 
287  static int GetNumberVecs (const MV& mv) {
288  return static_cast<int> (mv.getNumVectors ());
289  }
290 
291  static bool HasConstantStride (const MV& mv) {
292  return mv.isConstantStride ();
293  }
294 
295  template <class DstType, class SrcType>
297  const DstType& dst,
298  const SrcType& src
299  )
300  {
301  if (std::is_same<typename SrcType::memory_space, Kokkos::HostSpace>::value)
302  {
303  auto dst_i = Kokkos::create_mirror(dst);
304  for (size_t i = 0; i < src.extent(0); i++)
305  {
306  for (size_t j = 0; j < src.extent(1); j++)
307  {
308  dst_i(i, j) = src(i, j);
309  }
310  }
311  Kokkos::deep_copy(dst, dst_i);
312  }
313  else
314  {
315  auto src_i = Kokkos::create_mirror(src);
316  Kokkos::deep_copy(src_i, src);
317  for (size_t i = 0; i < src.extent(0); i++)
318  {
319  for (size_t j = 0; j < src.extent(1); j++)
320  {
321  dst(i, j) = src_i(i, j);
322  }
323  }
324  }
325  }
326 
327  static void
328  MvTimesMatAddMv (const dot_type& alpha,
329  const Tpetra::MultiVector<Scalar,LO,GO,Node>& A,
331  const dot_type& beta,
332  Tpetra::MultiVector<Scalar,LO,GO,Node>& C)
333  {
334  using Teuchos::RCP;
335  using Teuchos::rcp;
336 
337  // Check if numRowsB == numColsB == 1, in which case we can call update()
338  const int numRowsB = B.numRows ();
339  const int numColsB = B.numCols ();
340  const int strideB = B.stride ();
341  if (numRowsB == 1 && numColsB == 1) {
342  C.update (alpha*B(0,0), A, beta);
343  return;
344  }
345 
346  // Ensure A and C have constant stride
347  RCP<const MV> Atmp;
348  RCP< MV> Ctmp;
349  if (A.isConstantStride() == false) Atmp = rcp (new MV (A, Teuchos::Copy));
350  else Atmp = rcp(&A,false);
351 
352  if (C.isConstantStride() == false) Ctmp = rcp (new MV (C, Teuchos::Copy));
353  else Ctmp = rcp(&C,false);
354 
355  // Create flattened view's
356  typedef Tpetra::MultiVector<dot_type,LO,GO,Node> FMV;
357  typedef typename FMV::dual_view_type::t_dev flat_view_type;
359  typename flat_view_type::const_type flat_A_view = Atmp->getLocalViewDevice(Tpetra::Access::ReadOnly);
360  flat_view_type flat_C_view = Ctmp->getLocalViewDevice(Tpetra::Access::OverwriteAll);
361 
362  // Create a view for B on the host
363  typedef Kokkos::View<dot_type**, Kokkos::LayoutLeft, Kokkos::HostSpace> b_host_view_type;
364  b_host_view_type B_view_host_input( B.values(), strideB, numColsB);
365  auto B_view_host = Kokkos::subview(B_view_host_input,
366  Kokkos::pair<int,int>(0,numRowsB),
367  Kokkos::pair<int,int>(0,numColsB));
368 
369  // Create view for B on the device -- need to be careful to get the
370  // right stride to match B
371  typedef Kokkos::View<dot_type**, Kokkos::LayoutLeft, execution_space> b_view_type;
372  typedef Kokkos::View<dot_type*, Kokkos::LayoutLeft, execution_space> b_1d_view_type;
373  b_1d_view_type B_1d_view_dev(Kokkos::ViewAllocateWithoutInitializing("B"), numRowsB*numColsB);
374  b_view_type B_view_dev( B_1d_view_dev.data(), numRowsB, numColsB);
375 
376  if (Kokkos::SpaceAccessibility<Kokkos::HostSpace, typename execution_space::memory_space>::accessible)
377  {
378  Kokkos::deep_copy(B_view_dev, B_view_host);
379  }
380  else
381  {
382  deep_copy_2d_view_with_intercessory_space(B_view_dev, B_view_host);
383  }
384 
385  // Do local multiply
386  {
387  const char ctransA = 'N', ctransB = 'N';
389  &ctransA, &ctransB,
390  alpha, flat_A_view, B_view_dev, beta, flat_C_view);
391  }
392  // Copy back to C if we made a copy
393  if (C.isConstantStride() == false)
394  C.assign(*Ctmp);
395  }
396 
404  static void
405  MvAddMv (Scalar alpha,
406  const Tpetra::MultiVector<Scalar,LO,GO,Node>& A,
407  Scalar beta,
408  const Tpetra::MultiVector<Scalar,LO,GO,Node>& B,
409  Tpetra::MultiVector<Scalar,LO,GO,Node>& mv)
410  {
411  mv.update (alpha, A, beta, B, Teuchos::ScalarTraits<Scalar>::zero ());
412  }
413 
414  static void
415  MvScale (Tpetra::MultiVector<Scalar,LO,GO,Node>& mv,
416  const Scalar& alpha)
417  {
418  mv.scale (alpha);
419  }
420 
421  static void
422  MvScale (Tpetra::MultiVector<Scalar,LO,GO,Node>& mv,
423  const std::vector<BaseScalar>& alphas)
424  {
425  std::vector<Scalar> alphas_mp(alphas.size());
426  const size_t sz = alphas.size();
427  for (size_t i=0; i<sz; ++i)
428  alphas_mp[i] = alphas[i];
429  mv.scale (alphas_mp);
430  }
431 
432  static void
433  MvScale (Tpetra::MultiVector<Scalar,LO,GO,Node>& mv,
434  const std::vector<Scalar>& alphas)
435  {
436  mv.scale (alphas);
437  }
438 
439  static void
441  const Tpetra::MultiVector<Scalar,LO,GO,Node>& A,
442  const Tpetra::MultiVector<Scalar,LO,GO,Node>& B,
444  {
445  using Teuchos::Comm;
446  using Teuchos::RCP;
447  using Teuchos::rcp;
448  using Teuchos::REDUCE_SUM;
449  using Teuchos::reduceAll;
450 
451  // Check if numRowsC == numColsC == 1, in which case we can call dot()
452  const int numRowsC = C.numRows ();
453  const int numColsC = C.numCols ();
454  const int strideC = C.stride ();
455  if (numRowsC == 1 && numColsC == 1) {
456  if (alpha == Teuchos::ScalarTraits<Scalar>::zero ()) {
457  // Short-circuit, as required by BLAS semantics.
458  C(0,0) = alpha;
459  return;
460  }
461  A.dot (B, Teuchos::ArrayView<dot_type> (C.values (), 1));
462  if (alpha != Teuchos::ScalarTraits<Scalar>::one ()) {
463  C(0,0) *= alpha;
464  }
465  return;
466  }
467 
468  // Ensure A and B have constant stride
469  RCP<const MV> Atmp, Btmp;
470  if (A.isConstantStride() == false) Atmp = rcp (new MV (A, Teuchos::Copy));
471  else Atmp = rcp(&A,false);
472 
473  if (B.isConstantStride() == false) Btmp = rcp (new MV (B, Teuchos::Copy));
474  else Btmp = rcp(&B,false);
475 
476  // Create flattened Kokkos::MultiVector's
477  typedef Tpetra::MultiVector<dot_type,LO,GO,Node> FMV;
478  typedef typename FMV::dual_view_type::t_dev flat_view_type;
480  typename flat_view_type::const_type flat_A_view = Atmp->getLocalViewDevice(Tpetra::Access::ReadOnly);
481  typename flat_view_type::const_type flat_B_view = Btmp->getLocalViewDevice(Tpetra::Access::ReadOnly);
482 
483  // Create a view for C on the host
484  typedef Kokkos::View<dot_type**, Kokkos::LayoutLeft, Kokkos::HostSpace> c_host_view_type;
485  c_host_view_type C_view_host_input( C.values(), strideC, numColsC);
486  auto C_view_host = Kokkos::subview(C_view_host_input,
487  Kokkos::pair<int,int>(0,numRowsC),
488  Kokkos::pair<int,int>(0,numColsC));
489 
490  // Create view for C on the device -- need to be careful to get the
491  // right stride to match C (allow setting to 0 for first-touch)
492  typedef Kokkos::View<dot_type**, Kokkos::LayoutLeft, execution_space> c_view_type;
493  typedef Kokkos::View<dot_type*, Kokkos::LayoutLeft, execution_space> c_1d_view_type;
494  c_1d_view_type C_1d_view_dev("C", numRowsC*numColsC);
495  c_view_type C_view_dev( C_1d_view_dev.data(), numRowsC, numColsC);
496 
497  // Do local multiply
498  {
499  const char ctransA = 'C', ctransB = 'N';
501  &ctransA, &ctransB,
502  alpha, flat_A_view, flat_B_view,
503  Kokkos::ArithTraits<dot_type>::zero(),
504  C_view_dev);
505  }
506 
507  // reduce across processors -- could check for RDMA
508  RCP<const Comm<int> > pcomm = A.getMap()->getComm ();
509  if (pcomm->getSize () == 1)
510  {
511  if (Kokkos::SpaceAccessibility<execution_space, Kokkos::HostSpace>::accessible)
512  {
513  Kokkos::deep_copy(C_view_host, C_view_dev);
514  }
515  else
516  {
517  deep_copy_2d_view_with_intercessory_space(C_view_host, C_view_dev);
518  }
519  }
520  else
521  {
522  typedef Kokkos::View<dot_type*, Kokkos::LayoutLeft, Kokkos::HostSpace> c_1d_host_view_type;
523  c_1d_host_view_type C_1d_view_tmp(Kokkos::ViewAllocateWithoutInitializing("C_tmp"), strideC*numColsC);
524  c_host_view_type C_view_tmp_input( C_1d_view_tmp.data(), strideC, numColsC);
525  auto C_view_tmp = Kokkos::subview(C_view_tmp_input,
526  Kokkos::pair<int,int>(0,numRowsC),
527  Kokkos::pair<int,int>(0,numColsC));
528 
529  if (Kokkos::SpaceAccessibility<execution_space, Kokkos::HostSpace>::accessible)
530  {
531  Kokkos::deep_copy(C_view_tmp, C_view_dev);
532  }
533  else
534  {
535  deep_copy_2d_view_with_intercessory_space(C_view_tmp, C_view_dev);
536  }
537 
538  reduceAll<int> (*pcomm, REDUCE_SUM, strideC*numColsC,
539  C_view_tmp.data(),
540  C_view_host.data());
541  }
542  }
543 
545  static void
546  MvDot (const Tpetra::MultiVector<Scalar,LO,GO,Node>& A,
547  const Tpetra::MultiVector<Scalar,LO,GO,Node>& B,
548  std::vector<dot_type>& dots)
549  {
550  const size_t numVecs = A.getNumVectors ();
551 
553  numVecs != B.getNumVectors (), std::invalid_argument,
554  "Belos::MultiVecTraits<Scalar,Tpetra::MultiVector>::MvDot(A,B,dots): "
555  "A and B must have the same number of columns. "
556  "A has " << numVecs << " column(s), "
557  "but B has " << B.getNumVectors () << " column(s).");
558 #ifdef HAVE_TPETRA_DEBUG
560  dots.size() < numVecs, std::invalid_argument,
561  "Belos::MultiVecTraits<Scalar,Tpetra::MultiVector>::MvDot(A,B,dots): "
562  "The output array 'dots' must have room for all dot products. "
563  "A and B each have " << numVecs << " column(s), "
564  "but 'dots' only has " << dots.size() << " entry(/ies).");
565 #endif // HAVE_TPETRA_DEBUG
566 
568  A.dot (B, av (0, numVecs));
569  }
570 
572  static void
573  MvNorm (const Tpetra::MultiVector<Scalar,LO,GO,Node>& mv,
574  std::vector<mag_type> &normvec,
575  NormType type=TwoNorm)
576  {
577 
578 #ifdef HAVE_TPETRA_DEBUG
579  typedef std::vector<int>::size_type size_type;
581  normvec.size () < static_cast<size_type> (mv.getNumVectors ()),
582  std::invalid_argument,
583  "Belos::MultiVecTraits::MvNorm(mv,normvec): The normvec output "
584  "argument must have at least as many entries as the number of vectors "
585  "(columns) in the MultiVector mv. normvec.size() = " << normvec.size ()
586  << " < mv.getNumVectors() = " << mv.getNumVectors () << ".");
587 #endif
588 
589  Teuchos::ArrayView<mag_type> av(normvec);
590  switch (type) {
591  case OneNorm:
592  mv.norm1(av(0,mv.getNumVectors()));
593  break;
594  case TwoNorm:
595  mv.norm2(av(0,mv.getNumVectors()));
596  break;
597  case InfNorm:
598  mv.normInf(av(0,mv.getNumVectors()));
599  break;
600  default:
601  // Throw logic_error rather than invalid_argument, because if
602  // we get here, it's probably the fault of a Belos solver,
603  // rather than a user giving Belos an invalid input.
605  true, std::logic_error,
606  "Belos::MultiVecTraits::MvNorm: Invalid NormType value " << type
607  << ". Valid values are OneNorm=" << OneNorm << ", TwoNorm="
608  << TwoNorm <<", and InfNorm=" << InfNorm << ". If you are a Belos "
609  "user and have not modified Belos in any way, and you get this "
610  "message, then this is probably a bug in the Belos solver you were "
611  "using. Please report this to the Belos developers.");
612  }
613  }
614 
615  static void
616  SetBlock (const MV& A, const std::vector<int>& index, MV& mv)
617  {
618  using Teuchos::Range1D;
619  using Teuchos::RCP;
620  const size_t inNumVecs = A.getNumVectors ();
621 #ifdef HAVE_TPETRA_DEBUG
623  inNumVecs < static_cast<size_t> (index.size ()), std::invalid_argument,
624  "Belos::MultiVecTraits::SetBlock(A,index,mv): 'index' argument must "
625  "have no more entries as the number of columns in the input MultiVector"
626  " A. A.getNumVectors() = " << inNumVecs << " < index.size () = "
627  << index.size () << ".");
628 #endif // HAVE_TPETRA_DEBUG
629  RCP<MV> mvsub = CloneViewNonConst (mv, index);
630  if (inNumVecs > static_cast<size_t> (index.size ())) {
631  RCP<const MV> Asub = A.subView (Range1D (0, index.size () - 1));
632  ::Tpetra::deep_copy (*mvsub, *Asub);
633  } else {
634  ::Tpetra::deep_copy (*mvsub, A);
635  }
636  }
637 
638  static void
639  SetBlock (const MV& A, const Teuchos::Range1D& index, MV& mv)
640  {
641  // Range1D bounds are signed; size_t is unsigned.
642  // Assignment of Tpetra::MultiVector is a deep copy.
643 
644  // Tpetra::MultiVector::getNumVectors() returns size_t. It's
645  // fair to assume that the number of vectors won't overflow int,
646  // since the typical use case of multivectors involves few
647  // columns, but it's friendly to check just in case.
648  const size_t maxInt =
649  static_cast<size_t> (Teuchos::OrdinalTraits<int>::max ());
650  const bool overflow =
651  maxInt < A.getNumVectors () && maxInt < mv.getNumVectors ();
652  if (overflow) {
653  std::ostringstream os;
654  os << "Belos::MultiVecTraits::SetBlock(A, index=[" << index.lbound ()
655  << ", " << index.ubound () << "], mv): ";
657  maxInt < A.getNumVectors (), std::range_error, os.str () << "Number "
658  "of columns (size_t) in the input MultiVector 'A' overflows int.");
660  maxInt < mv.getNumVectors (), std::range_error, os.str () << "Number "
661  "of columns (size_t) in the output MultiVector 'mv' overflows int.");
662  }
663  // We've already validated the static casts above.
664  const int numColsA = static_cast<int> (A.getNumVectors ());
665  const int numColsMv = static_cast<int> (mv.getNumVectors ());
666  // 'index' indexes into mv; it's the index set of the target.
667  const bool validIndex =
668  index.lbound () >= 0 && index.ubound () < numColsMv;
669  // We can't take more columns out of A than A has.
670  const bool validSource = index.size () <= numColsA;
671 
672  if (! validIndex || ! validSource) {
673  std::ostringstream os;
674  os << "Belos::MultiVecTraits::SetBlock(A, index=[" << index.lbound ()
675  << ", " << index.ubound () << "], mv): ";
677  index.lbound() < 0, std::invalid_argument,
678  os.str() << "Range lower bound must be nonnegative.");
680  index.ubound() >= numColsMv, std::invalid_argument,
681  os.str() << "Range upper bound must be less than the number of "
682  "columns " << numColsA << " in the 'mv' output argument.");
684  index.size() > numColsA, std::invalid_argument,
685  os.str() << "Range must have no more elements than the number of "
686  "columns " << numColsA << " in the 'A' input argument.");
688  true, std::logic_error, "Should never get here!");
689  }
690 
691  // View of the relevant column(s) of the target multivector mv.
692  // We avoid view creation overhead by only creating a view if
693  // the index range is different than [0, (# columns in mv) - 1].
694  Teuchos::RCP<MV> mv_view;
695  if (index.lbound () == 0 && index.ubound () + 1 == numColsMv) {
696  mv_view = Teuchos::rcpFromRef (mv); // Non-const, non-owning RCP
697  } else {
698  mv_view = CloneViewNonConst (mv, index);
699  }
700 
701  // View of the relevant column(s) of the source multivector A.
702  // If A has fewer columns than mv_view, then create a view of
703  // the first index.size() columns of A.
704  Teuchos::RCP<const MV> A_view;
705  if (index.size () == numColsA) {
706  A_view = Teuchos::rcpFromRef (A); // Const, non-owning RCP
707  } else {
708  A_view = CloneView (A, Teuchos::Range1D (0, index.size () - 1));
709  }
710 
711  ::Tpetra::deep_copy (*mv_view, *A_view);
712  }
713 
714  static void Assign (const MV& A, MV& mv)
715  {
716  const char errPrefix[] = "Belos::MultiVecTraits::Assign(A, mv): ";
717 
718  // Range1D bounds are signed; size_t is unsigned.
719  // Assignment of Tpetra::MultiVector is a deep copy.
720 
721  // Tpetra::MultiVector::getNumVectors() returns size_t. It's
722  // fair to assume that the number of vectors won't overflow int,
723  // since the typical use case of multivectors involves few
724  // columns, but it's friendly to check just in case.
725  const size_t maxInt =
726  static_cast<size_t> (Teuchos::OrdinalTraits<int>::max ());
727  const bool overflow =
728  maxInt < A.getNumVectors () && maxInt < mv.getNumVectors ();
729  if (overflow) {
731  maxInt < A.getNumVectors(), std::range_error,
732  errPrefix << "Number of columns in the input multivector 'A' "
733  "(a size_t) overflows int.");
735  maxInt < mv.getNumVectors(), std::range_error,
736  errPrefix << "Number of columns in the output multivector 'mv' "
737  "(a size_t) overflows int.");
739  true, std::logic_error, "Should never get here!");
740  }
741  // We've already validated the static casts above.
742  const int numColsA = static_cast<int> (A.getNumVectors ());
743  const int numColsMv = static_cast<int> (mv.getNumVectors ());
744  if (numColsA > numColsMv) {
746  numColsA > numColsMv, std::invalid_argument,
747  errPrefix << "Input multivector 'A' has " << numColsA << " columns, "
748  "but output multivector 'mv' has only " << numColsMv << " columns.");
749  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Should never get here!");
750  }
751  if (numColsA == numColsMv) {
752  ::Tpetra::deep_copy (mv, A);
753  } else {
754  Teuchos::RCP<MV> mv_view =
755  CloneViewNonConst (mv, Teuchos::Range1D (0, numColsA - 1));
756  ::Tpetra::deep_copy (*mv_view, A);
757  }
758  }
759 
760 
761  static void MvRandom (MV& mv) {
762  mv.randomize ();
763  }
764 
765  static void
766  MvInit (MV& mv, const Scalar alpha = Teuchos::ScalarTraits<Scalar>::zero ())
767  {
768  mv.putScalar (alpha);
769  }
770 
771  static void MvPrint (const MV& mv, std::ostream& os) {
772  Teuchos::FancyOStream fos (Teuchos::rcpFromRef (os));
773  mv.describe (fos, Teuchos::VERB_EXTREME);
774  }
775 
776 #ifdef HAVE_BELOS_TSQR
777  typedef Tpetra::TsqrAdaptor< Tpetra::MultiVector< Scalar, LO, GO, Node > > tsqr_adaptor_type;
781 #endif // HAVE_BELOS_TSQR
782  };
783 
785  //
786  // Implementation of the Belos::OperatorTraits for Tpetra::Operator.
787  //
789 
791  template <class Storage, class LO, class GO, class Node>
792  class OperatorTraits <typename Storage::value_type,
793  Tpetra::MultiVector<Sacado::MP::Vector<Storage>,
794  LO,GO,Node>,
795  Tpetra::Operator<Sacado::MP::Vector<Storage>,
796  LO,GO,Node> >
797  {
798  public:
800  static void
801  Apply (const Tpetra::Operator<Scalar,LO,GO,Node>& Op,
802  const Tpetra::MultiVector<Scalar,LO,GO,Node>& X,
803  Tpetra::MultiVector<Scalar,LO,GO,Node>& Y,
804  ETrans trans=NOTRANS)
805  {
806  switch (trans) {
807  case NOTRANS:
808  Op.apply(X,Y,Teuchos::NO_TRANS);
809  break;
810  case TRANS:
811  Op.apply(X,Y,Teuchos::TRANS);
812  break;
813  case CONJTRANS:
814  Op.apply(X,Y,Teuchos::CONJ_TRANS);
815  break;
816  default:
817  const std::string scalarName = Teuchos::TypeNameTraits<Scalar>::name();
818  const std::string loName = Teuchos::TypeNameTraits<LO>::name();
819  const std::string goName = Teuchos::TypeNameTraits<GO>::name();
820  const std::string nodeName = Teuchos::TypeNameTraits<Node>::name();
821  const std::string otName = "Belos::OperatorTraits<" + scalarName
822  + "," + loName + "," + goName + "," + nodeName + ">";
823  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, otName << ": Should never "
824  "get here; fell through a switch statement. "
825  "Please report this bug to the Belos developers.");
826  }
827  }
828 
829  static bool
830  HasApplyTranspose (const Tpetra::Operator<Scalar,LO,GO,Node>& Op)
831  {
832  return Op.hasTransposeApply ();
833  }
834  };
835 
836 } // end of Belos namespace
837 
838 #endif
839 // end of file BELOS_TPETRA_ADAPTER_HPP
ScalarType * values() const
static Teuchos::RCP< MV > CloneCopy(const MV &mv, const std::vector< int > &index)
Create and return a deep copy of the given columns of mv.
static void MvScale(Tpetra::MultiVector< Scalar, LO, GO, Node > &mv, const std::vector< BaseScalar > &alphas)
Kokkos::DefaultExecutionSpace execution_space
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Ordinal ubound() const
static void MvTimesMatAddMv(const dot_type &alpha, const Tpetra::MultiVector< Scalar, LO, GO, Node > &A, const Teuchos::SerialDenseMatrix< int, dot_type > &B, const dot_type &beta, Tpetra::MultiVector< Scalar, LO, GO, Node > &C)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
static void MvScale(Tpetra::MultiVector< Scalar, LO, GO, Node > &mv, const std::vector< Scalar > &alphas)
static void MvTransMv(dot_type alpha, const Tpetra::MultiVector< Scalar, LO, GO, Node > &A, const Tpetra::MultiVector< Scalar, LO, GO, Node > &B, Teuchos::SerialDenseMatrix< int, dot_type > &C)
void deep_copy(const Stokhos::CrsMatrix< ValueType, DstDevice, Layout > &dst, const Stokhos::CrsMatrix< ValueType, SrcDevice, Layout > &src)
static void MvNorm(const Tpetra::MultiVector< Scalar, LO, GO, Node > &mv, std::vector< mag_type > &normvec, NormType type=TwoNorm)
For all columns j of mv, set normvec[j] = norm(mv[j]).
static Teuchos::RCP< MV > Clone(const MV &X, const int numVecs)
Create a new MultiVector with numVecs columns.
Ordinal lbound() const
OrdinalType numCols() const
static void Apply(const Tpetra::Operator< Scalar, LO, GO, Node > &Op, const Tpetra::MultiVector< Scalar, LO, GO, Node > &X, Tpetra::MultiVector< Scalar, LO, GO, Node > &Y, ETrans trans=NOTRANS)
static Teuchos::RCP< MV > CloneCopy(const MV &mv, const Teuchos::Range1D &index)
Create and return a deep copy of the given columns of mv.
std::enable_if< Kokkos::is_view_mp_vector< Kokkos::View< DA, PA...> >::value &&Kokkos::is_view_mp_vector< Kokkos::View< DB, PB...> >::value &&Kokkos::is_view_mp_vector< Kokkos::View< DC, PC...> >::value >::type gemm(const char transA[], const char transB[], typename Kokkos::View< DA, PA...>::const_value_type &alpha, const Kokkos::View< DA, PA...> &A, const Kokkos::View< DB, PB...> &B, typename Kokkos::View< DC, PC...>::const_value_type &beta, const Kokkos::View< DC, PC...> &C)
Ordinal size() const
Stokhos::CrsMatrix< ValueType, Device, Layout >::HostMirror create_mirror(const Stokhos::CrsMatrix< ValueType, Device, Layout > &A)
OrdinalType stride() const
static std::string name()
OrdinalType numRows() const
static void MvDot(const Tpetra::MultiVector< Scalar, LO, GO, Node > &A, const Tpetra::MultiVector< Scalar, LO, GO, Node > &B, std::vector< dot_type > &dots)
For all columns j of A, set dots[j] := A[j]^T * B[j].
static void MvAddMv(Scalar alpha, const Tpetra::MultiVector< Scalar, LO, GO, Node > &A, Scalar beta, const Tpetra::MultiVector< Scalar, LO, GO, Node > &B, Tpetra::MultiVector< Scalar, LO, GO, Node > &mv)
mv := alpha*A + beta*B