Thyra Version of the Day
Loading...
Searching...
No Matches
Thyra_DefaultBlockedTriangularLinearOpWithSolve_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_BLOCKED_TRIANGULAR_LINEAR_OP_WITH_SOLVE_DEF_HPP
11#define THYRA_DEFAULT_BLOCKED_TRIANGULAR_LINEAR_OP_WITH_SOLVE_DEF_HPP
12
13
14#include "Thyra_DefaultBlockedTriangularLinearOpWithSolve_decl.hpp"
15#include "Thyra_ProductMultiVectorBase.hpp"
16#include "Thyra_DefaultProductVectorSpace.hpp"
17#include "Thyra_AssertOp.hpp"
18
19
20namespace Thyra {
21
22
23// public
24
25
26// Constructors/Initializers/Accessors
27
28
29template<class Scalar>
33
34
35template<class Scalar>
38 )
39{
40 assertAndSetBlockStructure(*blocks);
41 blocks_.initialize(blocks);
42}
43
44
45template<class Scalar>
47 const RCP<const PhysicallyBlockedLinearOpBase<Scalar> > &blocks
48 )
49{
50 assertAndSetBlockStructure(*blocks);
51 blocks_.initialize(blocks);
52}
53
54
55template<class Scalar>
61
62
63template<class Scalar>
66{
67 return blocks_.getConstObj();
68}
69
70
71// Overridden from PhysicallyBlockedLinearOpWithSolveBase
72
73
74template<class Scalar>
76 const int i, const int j
77 ) const
78{
79 assertBlockFillIsActive(true);
80 assertBlockRowCol(i,j);
81 return i==j; // Only accept LOWS blocks along the diagonal!
82}
83
84template<class Scalar>
86 const int i, const int j,
88 )
89{
90 setLOWSBlockImpl(i,j,block);
91}
92
93
94template<class Scalar>
96 const int i, const int j,
98 )
99{
100 setLOWSBlockImpl(i,j,block);
101}
102
103
104// Overridden from PhysicallyBlockedLinearOpBase
105
106
107template<class Scalar>
109{
110 assertBlockFillIsActive(false);
111 TEUCHOS_TEST_FOR_EXCEPT("ToDo: Have not implemented flexible block fill yet!");
112}
113
114
115template<class Scalar>
117 const int numRowBlocks, const int numColBlocks
118 )
119{
120 using Teuchos::null;
121#ifdef THYRA_DEBUG
122 TEUCHOS_ASSERT_EQUALITY(numRowBlocks, numColBlocks);
123#else
124 (void)numColBlocks;
125#endif
126 assertBlockFillIsActive(false);
127 numDiagBlocks_ = numRowBlocks;
128 diagonalBlocks_.resize(numDiagBlocks_);
129 productRange_ = null;
130 productDomain_ = null;
131 blockFillIsActive_ = true;
132}
133
134
135template<class Scalar>
137 const Teuchos::RCP<const ProductVectorSpaceBase<Scalar> > &productRange_in,
138 const Teuchos::RCP<const ProductVectorSpaceBase<Scalar> > &productDomain_in
139 )
140{
141#ifdef THYRA_DEBUG
142 TEUCHOS_TEST_FOR_EXCEPT( is_null(productRange_in) );
143 TEUCHOS_TEST_FOR_EXCEPT( is_null(productDomain_in) );
144 TEUCHOS_TEST_FOR_EXCEPT( productRange_in->numBlocks() != productDomain_in->numBlocks() );
145#endif
146 assertBlockFillIsActive(false);
147 productRange_ = productRange_in;
148 productDomain_ = productDomain_in;
149 numDiagBlocks_ = productRange_in->numBlocks();
150 diagonalBlocks_.resize(numDiagBlocks_);
151 blockFillIsActive_ = true;
152}
153
154
155template<class Scalar>
157{
158 return blockFillIsActive_;
159}
160
161
162template<class Scalar>
164 const int i, const int j
165 ) const
166{
167 assertBlockFillIsActive(true);
168 assertBlockRowCol(i,j);
169 return false; // ToDo: Change this once we accept off-diagonal blocks
170}
171
172
173template<class Scalar>
175 const int /* i */, const int /* j */,
176 const Teuchos::RCP<LinearOpBase<Scalar> > &/* block */
177 )
178{
179 assertBlockFillIsActive(true);
180 TEUCHOS_TEST_FOR_EXCEPT("Error, we don't support off-diagonal LOB objects yet!");
181}
182
183
184template<class Scalar>
186 const int /* i */, const int /* j */,
187 const Teuchos::RCP<const LinearOpBase<Scalar> > &/* block */
188 )
189{
190 assertBlockFillIsActive(true);
191 TEUCHOS_TEST_FOR_EXCEPT("Error, we don't support off-diagonal LOB objects yet!");
192}
193
194
195template<class Scalar>
197{
198 assertBlockFillIsActive(true);
201 for ( int k = 0; k < numDiagBlocks_; ++k ) {
203 diagonalBlocks_[k].getConstObj();
204 TEUCHOS_TEST_FOR_EXCEPTION(is_null(lows_k), std::logic_error,
205 "Error, the block diagonal k="<<k<<" can not be null when ending block fill!"
206 );
207 if (is_null(productRange_)) {
208 rangeSpaces.push_back(lows_k->range());
209 domainSpaces.push_back(lows_k->domain());
210 }
211 }
212 if (is_null(productRange_)) {
213 productRange_ = productVectorSpace<Scalar>(rangeSpaces());
214 productDomain_ = productVectorSpace<Scalar>(domainSpaces());
215 }
216 blockFillIsActive_ = false;
217}
218
219
220template<class Scalar>
222{
223 assertBlockFillIsActive(false);
224 productRange_ = Teuchos::null;
225 productDomain_ = Teuchos::null;
226 numDiagBlocks_ = 0;
227 diagonalBlocks_.resize(0);
228}
229
230
231// Overridden from BlockedLinearOpWithSolveBase
232
233
234template<class Scalar>
237 const int i, const int j
238 )
239{
240 assertBlockFillIsActive(false);
241 assertBlockRowCol(i,j);
242 if (i!=j)
243 return Teuchos::null;
244 return diagonalBlocks_[i].getNonconstObj();
245}
246
247
248template<class Scalar>
251 const int i, const int j
252 ) const
253{
254 assertBlockFillIsActive(false);
255 assertBlockRowCol(i, j);
256 if (i != j)
257 return Teuchos::null;
258 return diagonalBlocks_[i].getConstObj();
259}
260
261
262// Overridden from BlockedLinearOpBase
263
264
265template<class Scalar>
268{
269 return productRange_;
270}
271
272
273template<class Scalar>
276{
277 return productDomain_;
278}
279
280
281template<class Scalar>
283 const int i, const int j
284 ) const
285{
286 assertBlockFillIsActive(false);
287 assertBlockRowCol(i,j);
288 if (i!=j)
289 return false; // ToDo: Update this when off-diagonals are supported!
290 return !is_null(diagonalBlocks_[i].getConstObj());
291}
292
293
294template<class Scalar>
296 const int i, const int j
297 ) const
298{
299 assertBlockFillIsActive(true);
300 assertBlockRowCol(i,j);
301 return diagonalBlocks_[i].isConst();
302}
303
304
305template<class Scalar>
308 const int i, const int j
309 )
310{
311 assertBlockFillIsActive(true);
312 assertBlockRowCol(i,j);
313 if (i!=j)
314 return Teuchos::null; // ToDo: Update when off-diagonals are supported!
315 return this->getNonconstLOWSBlock(i,j);
316}
317
318
319template<class Scalar>
322 const int i, const int j
323 ) const
324{
325 assertBlockFillIsActive(true);
326 assertBlockRowCol(i,j);
327 if (i!=j)
328 return Teuchos::null; // ToDo: Update when off-diagonals are supported!
329 return this->getLOWSBlock(i,j);
330}
331
332
333// Overridden from LinearOpBase
334
335
336template<class Scalar>
339{
340 return this->productRange();
341}
342
343
344template<class Scalar>
347{
348 return this->productDomain();
349}
350
351
352template<class Scalar>
355{
356 return Teuchos::null; // ToDo: Implement clone when needed!
357}
358
359
360// Overridden from Teuchos::Describable
361
362
363template<class Scalar>
364std::string
366{
367 assertBlockFillIsActive(false);
368 std::ostringstream oss;
369 oss
371 << "numDiagBlocks="<<numDiagBlocks_
372 << "}";
373 return oss.str();
374}
375
376
377template<class Scalar>
380 const Teuchos::EVerbosityLevel verbLevel
381 ) const
382{
383 assertBlockFillIsActive(false);
384 Teuchos::Describable::describe(out, verbLevel);
385 // ToDo: Fill in a better version of this!
386}
387
388
389// protected
390
391
392// Overridden from LinearOpBase
393
394
395template<class Scalar>
397 EOpTransp M_trans
398 ) const
399{
400 using Thyra::opSupported;
401 assertBlockFillIsActive(false);
402 for ( int k = 0; k < numDiagBlocks_; ++k ) {
403 if ( !opSupported(*diagonalBlocks_[k].getConstObj(),M_trans) )
404 return false;
405 }
406 return true;
407 // ToDo: To be safe we really should do a collective reduction of all
408 // clusters of processes. However, for the typical use case, every block
409 // will return the same info and we should be safe!
410}
411
412
413template<class Scalar>
415 const EOpTransp M_trans,
416 const MultiVectorBase<Scalar> &X_in,
417 const Ptr<MultiVectorBase<Scalar> > &Y_inout,
418 const Scalar alpha,
419 const Scalar beta
420 ) const
421{
422
423 using Teuchos::RCP;
424 using Teuchos::dyn_cast;
425 using Thyra::apply;
426
427#ifdef THYRA_DEBUG
429 "DefaultBlockedTriangularLinearOpWithSolve<Scalar>::apply(...)",
430 *this, M_trans, X_in, &*Y_inout
431 );
432#endif // THYRA_DEBUG
433
434 //
435 // Y = alpha * op(M) * X + beta*Y
436 //
437 // =>
438 //
439 // Y[i] = beta+Y[i] + alpha*op(Op)[i]*X[i], for i=0...numDiagBlocks-1
440 //
441 // ToDo: Update to handle off diagonal blocks when needed!
442 //
443
445 &X = dyn_cast<const ProductMultiVectorBase<Scalar> >(X_in);
447 &Y = dyn_cast<ProductMultiVectorBase<Scalar> >(*Y_inout);
448
449 for ( int i = 0; i < numDiagBlocks_; ++ i ) {
450 Thyra::apply( *diagonalBlocks_[i].getConstObj(), M_trans,
451 *X.getMultiVectorBlock(i), Y.getNonconstMultiVectorBlock(i).ptr(),
452 alpha, beta
453 );
454 }
455
456}
457
458
459// Overridden from LinearOpWithSolveBase
460
461
462template<class Scalar>
463bool
465 EOpTransp M_trans
466 ) const
467{
468 assertBlockFillIsActive(false);
469 for ( int k = 0; k < numDiagBlocks_; ++k ) {
470 if ( !Thyra::solveSupports( *diagonalBlocks_[k].getConstObj(), M_trans ) )
471 return false;
472 }
473 return true;
474 // ToDo: To be safe we really should do a collective reduction of all
475 // clusters of processes. However, for the typical use case, every block
476 // will return the same info and we should be safe!
477}
478
479
480template<class Scalar>
481bool
483 EOpTransp M_trans, const SolveMeasureType& solveMeasureType
484 ) const
485{
486 using Thyra::solveSupportsSolveMeasureType;
487 assertBlockFillIsActive(false);
488 for ( int k = 0; k < numDiagBlocks_; ++k ) {
489 if (
490 !solveSupportsSolveMeasureType(
491 *diagonalBlocks_[k].getConstObj(),
492 M_trans, solveMeasureType
493 )
494 )
495 {
496 return false;
497 }
498 }
499 return true;
500}
501
502
503template<class Scalar>
506 const EOpTransp M_trans,
507 const MultiVectorBase<Scalar> &B_in,
508 const Ptr<MultiVectorBase<Scalar> > &X_inout,
509 const Ptr<const SolveCriteria<Scalar> > solveCriteria
510 ) const
511{
512
513 using Teuchos::RCP;
514 using Teuchos::dyn_cast;
515 using Thyra::solve;
516
517#ifdef THYRA_DEBUG
519 "DefaultBlockedTriangularLinearOpWithSolve<Scalar>::apply(...)",
520 *this, M_trans, *X_inout, &B_in
521 );
522 TEUCHOS_TEST_FOR_EXCEPT(!this->solveSupportsImpl(M_trans));
523 // TEUCHOS_TEST_FOR_EXCEPTION(
524 // nonnull(solveCriteria) && !solveCriteria->solveMeasureType.useDefault(),
525 // std::logic_error,
526 // "Error, we can't handle any non-default solve criteria yet!"
527 // );
528 // ToDo: If solve criteria is to be handled, then we will have to be very
529 // carefull how it it interpreted in terms of the individual period solves!
530#endif // THYRA_DEBUG
531
532 //
533 // Y = alpha * inv(op(M)) * X + beta*Y
534 //
535 // =>
536 //
537 // X[i] = inv(op(Op[i]))*B[i], for i=0...numDiagBlocks-1
538 //
539 // ToDo: Update to handle off diagonal blocks when needed!
540 //
541
543 &B = dyn_cast<const ProductMultiVectorBase<Scalar> >(B_in);
545 &X = dyn_cast<ProductMultiVectorBase<Scalar> >(*X_inout);
546
547 bool converged = true;
548 for ( int i = 0; i < numDiagBlocks_; ++ i ) {
550 Op_k = diagonalBlocks_[i].getConstObj();
551 Op_k->setOStream(this->getOStream());
552 Op_k->setVerbLevel(this->getVerbLevel());
553 SolveStatus<Scalar> status =
554 Thyra::solve( *Op_k, M_trans, *B.getMultiVectorBlock(i),
555 X.getNonconstMultiVectorBlock(i).ptr(), solveCriteria );
557 converged = false;
558 // ToDo: Pass in solve criteria when needed!
559 }
560
561 SolveStatus<Scalar> solveStatus;
562 solveStatus.solveStatus =
564
565 return solveStatus;
566
567}
568
569
570
571// private
572
573
574template<class Scalar>
576 bool blockFillIsActive_in
577 ) const
578{
579#ifdef THYRA_DEBUG
580 TEUCHOS_TEST_FOR_EXCEPT(!(blockFillIsActive_==blockFillIsActive_in));
581#else
582 (void)blockFillIsActive_in;
583#endif
584}
585
586
587template<class Scalar>
588void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::assertBlockRowCol(
589 const int i, const int j
590 ) const
591{
592#ifdef THYRA_DEBUG
594 !( 0 <= i && i < numDiagBlocks_ ), std::logic_error,
595 "Error, i="<<i<<" does not fall in the range [0,"<<numDiagBlocks_-1<<"]!"
596 );
598 !( 0 <= j && j < numDiagBlocks_ ), std::logic_error,
599 "Error, j="<<j<<" does not fall in the range [0,"<<numDiagBlocks_-1<<"]!"
600 );
601#else
602 (void)i;
603 (void)j;
604#endif
605}
606
607
608template<class Scalar>
609template<class LinearOpWithSolveType>
610void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::setLOWSBlockImpl(
611 const int i, const int j,
613 )
614{
615 assertBlockFillIsActive(true);
616#ifdef THYRA_DEBUG
617 TEUCHOS_ASSERT_INEQUALITY( i, >=, 0 );
618 TEUCHOS_ASSERT_INEQUALITY( j, >=, 0 );
619 TEUCHOS_ASSERT_INEQUALITY( i, <, numDiagBlocks_ );
620 TEUCHOS_ASSERT_INEQUALITY( j, <, numDiagBlocks_ );
622 !this->acceptsLOWSBlock(i,j), std::logic_error,
623 "Error, this DefaultBlockedTriangularLinearOpWithSolve does not accept\n"
624 "LOWSB objects for the block i="<<i<<", j="<<j<<"!"
625 );
626#else
627 (void)j;
628#endif
629 diagonalBlocks_[i] = block;
630}
631
632
633template<class Scalar>
634void DefaultBlockedTriangularLinearOpWithSolve<Scalar>::assertAndSetBlockStructure(
635 const PhysicallyBlockedLinearOpBase<Scalar>& blocks
636 )
637{
638#ifdef THYRA_DEBUG
640 "DefaultBlockedTriangularLinearOpWithSolve<Scalar>::assertAndSetBlockStructure(blocks)",
641 *blocks.range(), *this->range()
642 );
644 "DefaultBlockedTriangularLinearOpWithSolve<Scalar>::assertAndSetBlockStructure(blocks)",
645 *blocks.domain(), *this->domain()
646 );
647 // ToDo: Make sure that all of the blocks are above or below the diagonal
648 // but not both!
649#else
650 (void)blocks;
651#endif
652 // ToDo: Set if this is an upper or lower triangular block operator.
653}
654
655
656} // namespace Thyra
657
658
659#endif // THYRA_DEFAULT_BLOCKED_TRIANGULAR_LINEAR_OP_WITH_SOLVE_DEF_HPP
void push_back(const value_type &x)
virtual void describe(FancyOStream &out, const EVerbosityLevel verbLevel=verbLevel_default) const
virtual std::string description() const
Concrete composite LinearOpWithSolveBase subclass that creates single upper or lower block triangular...
void setNonconstBlocks(const RCP< PhysicallyBlockedLinearOpBase< Scalar > > &blocks)
SolveStatus< Scalar > solveImpl(const EOpTransp transp, const MultiVectorBase< Scalar > &B, const Ptr< MultiVectorBase< Scalar > > &X, const Ptr< const SolveCriteria< Scalar > > solveCriteria) const
void setLOWSBlock(const int i, const int j, const RCP< const LinearOpWithSolveBase< Scalar > > &block)
RCP< const LinearOpWithSolveBase< Scalar > > getLOWSBlock(const int i, const int j) const
RCP< const LinearOpBase< Scalar > > getBlock(const int i, const int j) const
void setNonconstBlock(const int i, const int j, const RCP< LinearOpBase< Scalar > > &block)
void setBlocks(const RCP< const PhysicallyBlockedLinearOpBase< Scalar > > &blocks)
bool solveSupportsSolveMeasureTypeImpl(EOpTransp M_trans, const SolveMeasureType &solveMeasureType) const
std::string description() const
Prints just the name DefaultBlockedTriangularLinearOpWithSolve along with the overall dimensions and ...
void setNonconstLOWSBlock(const int i, const int j, const RCP< LinearOpWithSolveBase< Scalar > > &block)
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
Prints the details about the constituent linear operators.
void setBlock(const int i, const int j, const RCP< const LinearOpBase< Scalar > > &block)
void applyImpl(const EOpTransp M_trans, const MultiVectorBase< Scalar > &X, const Ptr< MultiVectorBase< Scalar > > &Y, const Scalar alpha, const Scalar beta) const
RCP< LinearOpWithSolveBase< Scalar > > getNonconstLOWSBlock(const int i, const int j)
Base class for all linear operators.
Base class for all linear operators that can support a high-level solve operation.
Interface for a collection of column vectors called a multi-vector.
Base interface for physically blocked linear operators.
Base interface for product multi-vectors.
virtual Teuchos::RCP< const MultiVectorBase< Scalar > > getMultiVectorBlock(const int k) const =0
Returns a non-persisting const view of the (zero-based) kth block multi-vector.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
#define TEUCHOS_ASSERT_INEQUALITY(val1, comp, val2)
#define TEUCHOS_ASSERT_EQUALITY(val1, val2)
@ SOLVE_STATUS_UNCONVERGED
The requested solution criteria has likely not been achieved.
@ SOLVE_STATUS_CONVERGED
The requested solution criteria has likely been achieved.
#define THYRA_ASSERT_VEC_SPACES(FUNC_NAME, VS1, VS2)
This is a very useful macro that should be used to validate that two vector spaces are compatible.
#define THYRA_ASSERT_LINEAR_OP_MULTIVEC_APPLY_SPACES(FUNC_NAME, M, M_T, X, Y)
This is a very useful macro that should be used to validate that the spaces for the multi-vector vers...
EOpTransp
Enumeration for determining how a linear operator is applied. `*.
T_To & dyn_cast(T_From &from)
Simple struct that defines the requested solution criteria for a solve.
Simple struct for the return status from a solve.
ESolveStatus solveStatus
The return status of the solve.