Stratimikos Version of the Day
Loading...
Searching...
No Matches
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"
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
47namespace 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:
65 typedef Thyra::MultiVectorBase<ScalarType> TMVB;
66 typedef Teuchos::ScalarTraits<ScalarType> ST;
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
155 Teuchos::RCP< TMVB > cc;
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
207 Teuchos::RCP< const TMVB > cc;
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
220 static Teuchos::RCP<const TMVB>
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,
253 const Teuchos::SerialDenseMatrix<int,ScalarType>& B,
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!
270 Teuchos::RCP< const TMVB >
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,
316 Teuchos::SerialDenseMatrix<int,ScalarType>& B )
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!
326 Teuchos::RCP< TMVB >
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.
447 Teuchos::RCP<const TMVB> A_view;
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>(
492 -Teuchos::ScalarTraits<ScalarType>::one(),
493 Teuchos::ScalarTraits<ScalarType>::one(),
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
522 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:
545 typedef Thyra::MultiVectorBase<ScalarType> TMVB;
546 typedef Thyra::LinearOpBase<ScalarType> TLOB;
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 {
595 typedef Teuchos::ScalarTraits<ScalarType> STS;
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 void MvPrint(const TMVB &mv, std::ostream &os)
Print the mv multi-std::vector to the os output stream.
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.
static void MvAddMv(const ScalarType alpha, const TMVB &A, const ScalarType beta, const TMVB &B, TMVB &mv)
Replace mv with .
static int GetNumberVecs(const TMVB &mv)
Obtain the number of vectors in 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 ptrdiff_t GetGlobalLength(const TMVB &mv)
Obtain the std::vector length of mv.
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...
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 Teuchos::RCP< TMVB > CloneViewNonConst(TMVB &mv, const std::vector< int > &index)
Creates a new MultiVectorBase that shares the selected contents of mv (shallow copy).
static Teuchos::RCP< TMVB > Clone(const TMVB &mv, const int numvecs)
Creates a new empty MultiVectorBase containing numvecs columns.
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 MvScale(TMVB &mv, const ScalarType alpha)
Scale each element of the vectors in *this with alpha.
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 MvScale(TMVB &mv, const std::vector< ScalarType > &alpha)
Scale each element of the i-th vector in *this with alpha[i].
static void MvTimesMatAddMv(const ScalarType alpha, const TMVB &A, const Teuchos::SerialDenseMatrix< int, ScalarType > &B, const ScalarType beta, TMVB &mv)
Update mv with .
static void MvRandom(TMVB &mv)
Replace the vectors in mv with random vectors.
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 void MvInit(TMVB &mv, ScalarType alpha=Teuchos::ScalarTraits< ScalarType >::zero())
Replace each element of the vectors in mv with alpha.
static Teuchos::RCP< MV > CloneCopy(const MV &mv)
static Teuchos::RCP< const MV > CloneView(const MV &mv, const std::vector< int > &index)
static Teuchos::RCP< MV > CloneViewNonConst(MV &mv, const std::vector< int > &index)
static void SetBlock(const MV &A, const std::vector< int > &index, MV &mv)
static void Assign(const MV &A, MV &mv)
static bool HasApplyTranspose(const TLOB &Op)
Whether the operator implements applying the transpose.
static void Apply(const TLOB &Op, const TMVB &x, TMVB &y, ETrans trans=NOTRANS)
Apply Op to x, storing the result in y.
Stub adaptor from Thyra::MultiVectorBase to TSQR.

Generated for Stratimikos by doxygen 1.9.8