Stratimikos  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
BelosThyraAdapter.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Stratimikos: Thyra-based strategies for linear solvers
4 //
5 // Copyright 2006 NTESS and the Stratimikos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
20 #ifndef BELOS_THYRA_ADAPTER_HPP
21 #define BELOS_THYRA_ADAPTER_HPP
22 
23 #include "Stratimikos_Config.h"
24 #include "BelosConfigDefs.hpp"
25 #include "BelosMultiVecTraits.hpp"
26 #include "BelosOperatorTraits.hpp"
27 
28 #include <Thyra_DetachedMultiVectorView.hpp>
29 #include <Thyra_MultiVectorBase.hpp>
30 #include <Thyra_MultiVectorStdOps.hpp>
31 #ifdef HAVE_BELOS_TSQR
32 # include <Thyra_TsqrAdaptor.hpp>
33 #endif // HAVE_BELOS_TSQR
34 
35 #ifdef HAVE_STRATIMIKOS_BELOS_TIMERS
36 # include <Teuchos_TimeMonitor.hpp>
37 
38 # define STRATIMIKOS_TIME_MONITOR(NAME) \
39  Teuchos::TimeMonitor tM(*Teuchos::TimeMonitor::getNewTimer(std::string(NAME)))
40 
41 #else
42 
43 # define STRATIMIKOS_TIME_MONITOR(NAME)
44 
45 #endif
46 
47 namespace Belos {
48 
50  //
51  // Implementation of the Belos::MultiVecTraits for Thyra::MultiVectorBase
52  //
54 
61  template<class ScalarType>
62  class MultiVecTraits< ScalarType, Thyra::MultiVectorBase<ScalarType> >
63  {
64  private:
67  typedef typename ST::magnitudeType magType;
68 
69  public:
70 
73 
78  static Teuchos::RCP<TMVB> Clone( const TMVB& mv, const int numvecs )
79  {
80  Teuchos::RCP<TMVB> c = Thyra::createMembers( mv.range(), numvecs );
81  return c;
82  }
83 
88  static Teuchos::RCP<TMVB> CloneCopy( const TMVB& mv )
89  {
90  int numvecs = mv.domain()->dim();
91  // create the new multivector
92  Teuchos::RCP< TMVB > cc = Thyra::createMembers( mv.range(), numvecs );
93  // copy the data from the source multivector to the new multivector
94  Thyra::assign(cc.ptr(), mv);
95  return cc;
96  }
97 
103  static Teuchos::RCP<TMVB> CloneCopy( const TMVB& mv, const std::vector<int>& index )
104  {
105  int numvecs = index.size();
106  // create the new multivector
107  Teuchos::RCP<TMVB> cc = Thyra::createMembers( mv.range(), numvecs );
108  // create a view to the relevant part of the source multivector
109  Teuchos::RCP<const TMVB> view = mv.subView(index);
110  // copy the data from the relevant view to the new multivector
111  Thyra::assign(cc.ptr(), *view);
112  return cc;
113  }
114 
115  static Teuchos::RCP<TMVB>
116  CloneCopy (const TMVB& mv, const Teuchos::Range1D& index)
117  {
118  const int numVecs = index.size();
119  // Create the new multivector
120  Teuchos::RCP<TMVB> cc = Thyra::createMembers (mv.range(), numVecs);
121  // Create a view to the relevant part of the source multivector
122  Teuchos::RCP<const TMVB> view = mv.subView (index);
123  // Copy the data from the view to the new multivector.
124  Thyra::assign (cc.ptr(), *view);
125  return cc;
126  }
127 
133  static Teuchos::RCP<TMVB> CloneViewNonConst( TMVB& mv, const std::vector<int>& index )
134  {
135  int numvecs = index.size();
136 
137  // We do not assume that the indices are sorted, nor do we check that
138  // index.size() > 0. This code is fail-safe, in the sense that a zero
139  // length index std::vector will pass the error on the Thyra.
140 
141  // Thyra has two ways to create an indexed View:
142  // * contiguous (via a range of columns)
143  // * indexed (via a std::vector of column indices)
144  // The former is significantly more efficient than the latter, in terms of
145  // computations performed with/against the created view.
146  // We will therefore check to see if the given indices are contiguous, and
147  // if so, we will use the contiguous view creation method.
148 
149  int lb = index[0];
150  bool contig = true;
151  for (int i=0; i<numvecs; i++) {
152  if (lb+i != index[i]) contig = false;
153  }
154 
156  if (contig) {
157  const Thyra::Range1D rng(lb,lb+numvecs-1);
158  // create a contiguous view to the relevant part of the source multivector
159  cc = mv.subView(rng);
160  }
161  else {
162  // create an indexed view to the relevant part of the source multivector
163  cc = mv.subView(index);
164  }
165  return cc;
166  }
167 
168  static Teuchos::RCP<TMVB>
169  CloneViewNonConst (TMVB& mv, const Teuchos::Range1D& index)
170  {
171  // We let Thyra be responsible for checking that the index range
172  // is nonempty.
173  //
174  // Create and return a contiguous view to the relevant part of
175  // the source multivector.
176  return mv.subView (index);
177  }
178 
179 
185  static Teuchos::RCP<const TMVB> CloneView( const TMVB& mv, const std::vector<int>& index )
186  {
187  int numvecs = index.size();
188 
189  // We do not assume that the indices are sorted, nor do we check that
190  // index.size() > 0. This code is fail-safe, in the sense that a zero
191  // length index std::vector will pass the error on the Thyra.
192 
193  // Thyra has two ways to create an indexed View:
194  // * contiguous (via a range of columns)
195  // * indexed (via a std::vector of column indices)
196  // The former is significantly more efficient than the latter, in terms of
197  // computations performed with/against the created view.
198  // We will therefore check to see if the given indices are contiguous, and
199  // if so, we will use the contiguous view creation method.
200 
201  int lb = index[0];
202  bool contig = true;
203  for (int i=0; i<numvecs; i++) {
204  if (lb+i != index[i]) contig = false;
205  }
206 
208  if (contig) {
209  const Thyra::Range1D rng(lb,lb+numvecs-1);
210  // create a contiguous view to the relevant part of the source multivector
211  cc = mv.subView(rng);
212  }
213  else {
214  // create an indexed view to the relevant part of the source multivector
215  cc = mv.subView(index);
216  }
217  return cc;
218  }
219 
221  CloneView (const TMVB& mv, const Teuchos::Range1D& index)
222  {
223  // We let Thyra be responsible for checking that the index range
224  // is nonempty.
225  //
226  // Create and return a contiguous view to the relevant part of
227  // the source multivector.
228  return mv.subView (index);
229  }
230 
232 
235 
237  static ptrdiff_t GetGlobalLength( const TMVB& mv ) {
238  return Teuchos::as<ptrdiff_t>(mv.range()->dim());
239  }
240 
242  static int GetNumberVecs( const TMVB& mv )
243  { return mv.domain()->dim(); }
244 
246 
249 
252  static void MvTimesMatAddMv( const ScalarType alpha, const TMVB& A,
254  const ScalarType beta, TMVB& mv )
255  {
256  using Teuchos::arrayView; using Teuchos::arcpFromArrayView;
257  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvTimesMatAddMv");
258 
259  const int m = B.numRows();
260  const int n = B.numCols();
261  // Check if B is 1-by-1, in which case we can just call MvAddMv()
262  if ((m == 1) && (n == 1)) {
263  using Teuchos::tuple; using Teuchos::ptrInArg; using Teuchos::inoutArg;
264  const ScalarType alphaNew = alpha * B(0, 0);
265  Thyra::linear_combination<ScalarType>(tuple(alphaNew)(), tuple(ptrInArg(A))(), beta, inoutArg(mv));
266  } else {
267  // perform the operation via A: mv <- alpha*A*B_thyra + beta*mv
268  auto vs = A.domain();
269  // Create a view of the B object!
271  B_thyra = vs->createCachedMembersView(
273  0, m, 0, n,
274  arcpFromArrayView(arrayView(&B(0,0), B.stride()*B.numCols())), B.stride()
275  )
276  );
277  Thyra::apply<ScalarType>(A, Thyra::NOTRANS, *B_thyra, Teuchos::outArg(mv), alpha, beta);
278  }
279  }
280 
283  static void MvAddMv( const ScalarType alpha, const TMVB& A,
284  const ScalarType beta, const TMVB& B, TMVB& mv )
285  {
286  using Teuchos::tuple; using Teuchos::ptrInArg; using Teuchos::inoutArg;
287  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvAddMv");
288 
289  Thyra::linear_combination<ScalarType>(
290  tuple(alpha, beta)(), tuple(ptrInArg(A), ptrInArg(B))(), Teuchos::ScalarTraits<ScalarType>::zero(), inoutArg(mv));
291  }
292 
295  static void MvScale ( TMVB& mv, const ScalarType alpha )
296  {
297  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvScale");
298 
299  Thyra::scale(alpha, Teuchos::inoutArg(mv));
300  }
301 
304  static void MvScale (TMVB& mv, const std::vector<ScalarType>& alpha)
305  {
306  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvScale");
307 
308  for (unsigned int i=0; i<alpha.size(); i++) {
309  Thyra::scale<ScalarType> (alpha[i], mv.col(i).ptr());
310  }
311  }
312 
315  static void MvTransMv( const ScalarType alpha, const TMVB& A, const TMVB& mv,
317  {
318  using Teuchos::arrayView; using Teuchos::arcpFromArrayView;
319  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvTransMv");
320 
321  // Create a multivector to hold the result (m by n)
322  int m = A.domain()->dim();
323  int n = mv.domain()->dim();
324  auto vs = A.domain();
325  // Create a view of the B object!
327  B_thyra = vs->createCachedMembersView(
329  0, m, 0, n,
330  arcpFromArrayView(arrayView(&B(0,0), B.stride()*B.numCols())), B.stride()
331  ),
332  false
333  );
334  Thyra::apply<ScalarType>(A, Thyra::CONJTRANS, mv, B_thyra.ptr(), alpha);
335  }
336 
340  static void MvDot( const TMVB& mv, const TMVB& A, std::vector<ScalarType>& b )
341  {
342  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvDot");
343 
344  Thyra::dots(mv, A, Teuchos::arrayViewFromVector(b));
345  }
346 
348 
351 
355  static void MvNorm( const TMVB& mv, std::vector<magType>& normvec,
356  NormType type = TwoNorm ) {
357  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvNorm");
358 
359  if(type == TwoNorm)
360  Thyra::norms_2(mv, Teuchos::arrayViewFromVector(normvec));
361  else if(type == OneNorm)
362  Thyra::norms_1(mv, Teuchos::arrayViewFromVector(normvec));
363  else if(type == InfNorm)
364  Thyra::norms_inf(mv, Teuchos::arrayViewFromVector(normvec));
365  else
366  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
367  "Belos::MultiVecTraits::MvNorm (Thyra specialization): "
368  "invalid norm type. Must be either TwoNorm, OneNorm or InfNorm");
369  }
370 
372 
375 
378  static void SetBlock( const TMVB& A, const std::vector<int>& index, TMVB& mv )
379  {
380  // Extract the "numvecs" columns of mv indicated by the index std::vector.
381  int numvecs = index.size();
382  std::vector<int> indexA(numvecs);
383  int numAcols = A.domain()->dim();
384  for (int i=0; i<numvecs; i++) {
385  indexA[i] = i;
386  }
387  // Thyra::assign requires that both arguments have the same number of
388  // vectors. Enforce this, by shrinking one to match the other.
389  if ( numAcols < numvecs ) {
390  // A does not have enough columns to satisfy index_plus. Shrink
391  // index_plus.
392  numvecs = numAcols;
393  }
394  else if ( numAcols > numvecs ) {
395  numAcols = numvecs;
396  indexA.resize( numAcols );
397  }
398  // create a view to the relevant part of the source multivector
399  Teuchos::RCP< const TMVB > relsource = A.subView(indexA);
400  // create a view to the relevant part of the destination multivector
401  Teuchos::RCP< TMVB > reldest = mv.subView(index);
402  // copy the data to the destination multivector subview
403  Thyra::assign(reldest.ptr(), *relsource);
404  }
405 
406  static void
407  SetBlock (const TMVB& A, const Teuchos::Range1D& index, TMVB& mv)
408  {
409  const int numColsA = A.domain()->dim();
410  const int numColsMv = mv.domain()->dim();
411  // 'index' indexes into mv; it's the index set of the target.
412  const bool validIndex = index.lbound() >= 0 && index.ubound() < numColsMv;
413  // We can't take more columns out of A than A has.
414  const bool validSource = index.size() <= numColsA;
415 
416  if (! validIndex || ! validSource)
417  {
418  std::ostringstream os;
419  os << "Belos::MultiVecTraits<Scalar, Thyra::MultiVectorBase<Scalar> "
420  ">::SetBlock(A, [" << index.lbound() << ", " << index.ubound()
421  << "], mv): ";
422  TEUCHOS_TEST_FOR_EXCEPTION(index.lbound() < 0, std::invalid_argument,
423  os.str() << "Range lower bound must be nonnegative.");
424  TEUCHOS_TEST_FOR_EXCEPTION(index.ubound() >= numColsMv, std::invalid_argument,
425  os.str() << "Range upper bound must be less than "
426  "the number of columns " << numColsA << " in the "
427  "'mv' output argument.");
428  TEUCHOS_TEST_FOR_EXCEPTION(index.size() > numColsA, std::invalid_argument,
429  os.str() << "Range must have no more elements than"
430  " the number of columns " << numColsA << " in the "
431  "'A' input argument.");
432  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Should never get here!");
433  }
434 
435  // View of the relevant column(s) of the target multivector mv.
436  // We avoid view creation overhead by only creating a view if
437  // the index range is different than [0, (# columns in mv) - 1].
438  Teuchos::RCP<TMVB> mv_view;
439  if (index.lbound() == 0 && index.ubound()+1 == numColsMv)
440  mv_view = Teuchos::rcpFromRef (mv); // Non-const, non-owning RCP
441  else
442  mv_view = mv.subView (index);
443 
444  // View of the relevant column(s) of the source multivector A.
445  // If A has fewer columns than mv_view, then create a view of
446  // the first index.size() columns of A.
448  if (index.size() == numColsA)
449  A_view = Teuchos::rcpFromRef (A); // Const, non-owning RCP
450  else
451  A_view = A.subView (Teuchos::Range1D(0, index.size()-1));
452 
453  // Copy the data to the destination multivector.
454  Thyra::assign(mv_view.ptr(), *A_view);
455  }
456 
457  static void
458  Assign (const TMVB& A, TMVB& mv)
459  {
460  STRATIMIKOS_TIME_MONITOR("Belos::MVT::Assign");
461 
462  const int numColsA = A.domain()->dim();
463  const int numColsMv = mv.domain()->dim();
464  if (numColsA > numColsMv)
465  {
466  std::ostringstream os;
467  os << "Belos::MultiVecTraits<Scalar, Thyra::MultiVectorBase<Scalar>"
468  " >::Assign(A, mv): ";
469  TEUCHOS_TEST_FOR_EXCEPTION(numColsA > numColsMv, std::invalid_argument,
470  os.str() << "Input multivector 'A' has "
471  << numColsA << " columns, but output multivector "
472  "'mv' has only " << numColsMv << " columns.");
473  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Should never get here!");
474  }
475  // Copy the data to the destination multivector.
476  if (numColsA == numColsMv) {
477  Thyra::assign (Teuchos::outArg (mv), A);
478  } else {
479  Teuchos::RCP<TMVB> mv_view =
480  CloneViewNonConst (mv, Teuchos::Range1D(0, numColsA-1));
481  Thyra::assign (mv_view.ptr(), A);
482  }
483  }
484 
487  static void MvRandom( TMVB& mv )
488  {
489  // Thyra::randomize generates via a uniform distribution on [l,u]
490  // We will use this to generate on [-1,1]
491  Thyra::randomize<ScalarType>(
494  Teuchos::outArg(mv));
495  }
496 
498  static void
499  MvInit (TMVB& mv, ScalarType alpha = Teuchos::ScalarTraits<ScalarType>::zero())
500  {
501  Thyra::assign (Teuchos::outArg (mv), alpha);
502  }
503 
505 
508 
511  static void MvPrint( const TMVB& mv, std::ostream& os )
512  { os << describe(mv,Teuchos::VERB_EXTREME); }
513 
515 
516 #ifdef HAVE_BELOS_TSQR
517  typedef Thyra::TsqrAdaptor< ScalarType > tsqr_adaptor_type;
523 #endif // HAVE_BELOS_TSQR
524  };
525 
527  //
528  // Implementation of the Belos::OperatorTraits for Thyra::LinearOpBase
529  //
531 
539  template<class ScalarType>
540  class OperatorTraits <ScalarType,
541  Thyra::MultiVectorBase<ScalarType>,
542  Thyra::LinearOpBase<ScalarType> >
543  {
544  private:
547 
548  public:
564  static void
565  Apply (const TLOB& Op,
566  const TMVB& x,
567  TMVB& y,
568  ETrans trans = NOTRANS)
569  {
570  Thyra::EOpTransp whichOp;
571 
572  // We don't check here whether the operator implements the
573  // requested operation. Call HasApplyTranspose() to check.
574  // Thyra::LinearOpBase implementations are not required to
575  // implement NOTRANS. However, Belos needs NOTRANS
576  // (obviously!), so we assume that Op implements NOTRANS.
577  if (trans == NOTRANS)
578  whichOp = Thyra::NOTRANS;
579  else if (trans == TRANS)
580  whichOp = Thyra::TRANS;
581  else if (trans == CONJTRANS)
582  whichOp = Thyra::CONJTRANS;
583  else
584  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
585  "Belos::OperatorTraits::Apply (Thyra specialization): "
586  "'trans' argument must be neither NOTRANS=" << NOTRANS
587  << ", TRANS=" << TRANS << ", or CONJTRANS=" << CONJTRANS
588  << ", but instead has an invalid value of " << trans << ".");
589  Thyra::apply<ScalarType>(Op, whichOp, x, Teuchos::outArg(y));
590  }
591 
593  static bool HasApplyTranspose (const TLOB& Op)
594  {
596 
597  // Thyra::LinearOpBase's interface lets you check whether the
598  // operator implements any of all four possible combinations of
599  // conjugation and transpose. Belos only needs transpose
600  // (TRANS) if the operator is real; in that case, Apply() does
601  // the same thing with trans = CONJTRANS or TRANS. If the
602  // operator is complex, Belos needs both transpose and conjugate
603  // transpose (CONJTRANS) if the operator is complex.
604  return Op.opSupported (Thyra::TRANS) &&
605  (! STS::isComplex || Op.opSupported (Thyra::CONJTRANS));
606  }
607  };
608 
609 } // end of Belos namespace
610 
611 #endif
612 // end of file BELOS_THYRA_ADAPTER_HPP
static int GetNumberVecs(const TMVB &mv)
Obtain the number of vectors in mv.
virtual RCP< const VectorSpaceBase< Scalar > > range() const =0
EOpTransp
static ptrdiff_t GetGlobalLength(const TMVB &mv)
Obtain the std::vector length of mv.
static void MvPrint(const TMVB &mv, std::ostream &os)
Print the mv multi-std::vector to the os output stream.
Stub adaptor from Thyra::MultiVectorBase to TSQR.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
static Teuchos::RCP< const MV > CloneView(const MV &mv, const std::vector< int > &index)
static Teuchos::RCP< TMVB > CloneCopy(const TMVB &mv, const std::vector< int > &index)
Creates a new MultiVectorBase and copies the selected contents of mv into the new std::vector (deep c...
static void MvTransMv(const ScalarType alpha, const TMVB &A, const TMVB &mv, Teuchos::SerialDenseMatrix< int, ScalarType > &B)
Compute a dense matrix B through the matrix-matrix multiply .
static void MvInit(MV &mv, const ScalarType alpha=Teuchos::ScalarTraits< ScalarType >::zero())
static void MvScale(TMVB &mv, const std::vector< ScalarType > &alpha)
Scale each element of the i-th vector in *this with alpha[i].
static void MvDot(const TMVB &mv, const TMVB &A, std::vector< ScalarType > &b)
Compute a std::vector b where the components are the individual dot-products of the i-th columns of A...
Ordinal ubound() const
static void Assign(const MV &A, MV &mv)
static Teuchos::RCP< TMVB > CloneCopy(const TMVB &mv)
Creates a new MultiVectorBase and copies contents of mv into the new std::vector (deep copy)...
static void MvScale(TMVB &mv, const ScalarType alpha)
Scale each element of the vectors in *this with alpha.
static void SetBlock(const MV &A, const std::vector< int > &index, MV &mv)
RCP< const MultiVectorBase< Scalar > > subView(const Range1D &colRng) const
static Teuchos::RCP< MV > CloneViewNonConst(MV &mv, const std::vector< int > &index)
static void MvTimesMatAddMv(const ScalarType alpha, const TMVB &A, const Teuchos::SerialDenseMatrix< int, ScalarType > &B, const ScalarType beta, TMVB &mv)
Update mv with .
Ptr< T > ptr() const
RCP< const VectorBase< Scalar > > col(Ordinal j) const
static Teuchos::RCP< const TMVB > CloneView(const TMVB &mv, const std::vector< int > &index)
Creates a new const MultiVectorBase that shares the selected contents of mv (shallow copy)...
static void Apply(const TLOB &Op, const TMVB &x, TMVB &y, ETrans trans=NOTRANS)
Apply Op to x, storing the result in y.
static void MvRandom(TMVB &mv)
Replace the vectors in mv with random vectors.
static Teuchos::RCP< MV > CloneCopy(const MV &mv)
Ordinal lbound() const
OrdinalType numCols() const
virtual RCP< const VectorSpaceBase< Scalar > > domain() const =0
static void SetBlock(const TMVB &A, const std::vector< int > &index, TMVB &mv)
Copy the vectors in A to a set of vectors in mv indicated by the indices given in index...
Ordinal size() const
static void MvNorm(const TMVB &mv, std::vector< magType > &normvec, NormType type=TwoNorm)
Compute the 2-norm of each individual std::vector of mv. Upon return, normvec[i] holds the value of ...
static bool HasApplyTranspose(const TLOB &Op)
Whether the operator implements applying the transpose.
static Teuchos::RCP< TMVB > CloneViewNonConst(TMVB &mv, const std::vector< int > &index)
Creates a new MultiVectorBase that shares the selected contents of mv (shallow copy).
OrdinalType stride() const
static Teuchos::RCP< TMVB > Clone(const TMVB &mv, const int numvecs)
Creates a new empty MultiVectorBase containing numvecs columns.
static void MvAddMv(const ScalarType alpha, const TMVB &A, const ScalarType beta, const TMVB &B, TMVB &mv)
Replace mv with .
OrdinalType numRows() const
Teuchos::Range1D Range1D

Generated on Fri Dec 20 2024 09:21:59 for Stratimikos by doxygen 1.8.5