Thyra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
20 namespace Thyra {
21 
22 
23 // public
24 
25 
26 // Constructors/Initializers/Accessors
27 
28 
29 template<class Scalar>
31  : blockFillIsActive_(false), numDiagBlocks_(0)
32 {}
33 
34 
35 template<class Scalar>
38  )
39 {
40  assertAndSetBlockStructure(*blocks);
41  blocks_.initialize(blocks);
42 }
43 
44 
45 template<class Scalar>
47  const RCP<const PhysicallyBlockedLinearOpBase<Scalar> > &blocks
48  )
49 {
50  assertAndSetBlockStructure(*blocks);
51  blocks_.initialize(blocks);
52 }
53 
54 
55 template<class Scalar>
58 {
59  return blocks_.getNonconstObj();
60 }
61 
62 
63 template<class Scalar>
66 {
67  return blocks_.getConstObj();
68 }
69 
70 
71 // Overridden from PhysicallyBlockedLinearOpWithSolveBase
72 
73 
74 template<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 
84 template<class Scalar>
86  const int i, const int j,
88  )
89 {
90  setLOWSBlockImpl(i,j,block);
91 }
92 
93 
94 template<class Scalar>
96  const int i, const int j,
97  const Teuchos::RCP<const LinearOpWithSolveBase<Scalar> > &block
98  )
99 {
100  setLOWSBlockImpl(i,j,block);
101 }
102 
103 
104 // Overridden from PhysicallyBlockedLinearOpBase
105 
106 
107 template<class Scalar>
109 {
110  assertBlockFillIsActive(false);
111  TEUCHOS_TEST_FOR_EXCEPT("ToDo: Have not implemented flexible block fill yet!");
112 }
113 
114 
115 template<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 
135 template<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 
155 template<class Scalar>
157 {
158  return blockFillIsActive_;
159 }
160 
161 
162 template<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 
173 template<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 
184 template<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 
195 template<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 
220 template<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 
234 template<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 
248 template<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 
265 template<class Scalar>
268 {
269  return productRange_;
270 }
271 
272 
273 template<class Scalar>
276 {
277  return productDomain_;
278 }
279 
280 
281 template<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 
294 template<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 
305 template<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 
319 template<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 
336 template<class Scalar>
339 {
340  return this->productRange();
341 }
342 
343 
344 template<class Scalar>
347 {
348  return this->productDomain();
349 }
350 
351 
352 template<class Scalar>
355 {
356  return Teuchos::null; // ToDo: Implement clone when needed!
357 }
358 
359 
360 // Overridden from Teuchos::Describable
361 
362 
363 template<class Scalar>
364 std::string
366 {
367  assertBlockFillIsActive(false);
368  std::ostringstream oss;
369  oss
371  << "numDiagBlocks="<<numDiagBlocks_
372  << "}";
373  return oss.str();
374 }
375 
376 
377 template<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 
395 template<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 
413 template<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 
462 template<class Scalar>
463 bool
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 
480 template<class Scalar>
481 bool
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 
503 template<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 );
556  if (status.solveStatus != SOLVE_STATUS_CONVERGED)
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 
574 template<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 
587 template<class Scalar>
588 void 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 
608 template<class Scalar>
609 template<class LinearOpWithSolveType>
610 void 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 
633 template<class Scalar>
634 void 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
bool solveSupportsSolveMeasureTypeImpl(EOpTransp M_trans, const SolveMeasureType &solveMeasureType) const
Base interface for product multi-vectors.
RCP< LinearOpWithSolveBase< Scalar > > getNonconstLOWSBlock(const int i, const int j)
#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...
SolveStatus< Scalar > solveImpl(const EOpTransp transp, const MultiVectorBase< Scalar > &B, const Ptr< MultiVectorBase< Scalar > > &X, const Ptr< const SolveCriteria< Scalar > > solveCriteria) const
void setBlocks(const RCP< const PhysicallyBlockedLinearOpBase< Scalar > > &blocks)
Base class for all linear operators that can support a high-level solve operation.
bool is_null(const boost::shared_ptr< T > &p)
EOpTransp
Enumeration for determining how a linear operator is applied. `*.
void setNonconstBlock(const int i, const int j, const RCP< LinearOpBase< Scalar > > &block)
RCP< const LinearOpBase< Scalar > > getBlock(const int i, const int j) const
Concrete composite LinearOpWithSolveBase subclass that creates single upper or lower block triangular...
#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...
void applyImpl(const EOpTransp M_trans, const MultiVectorBase< Scalar > &X, const Ptr< MultiVectorBase< Scalar > > &Y, const Scalar alpha, const Scalar beta) const
void setBlock(const int i, const int j, const RCP< const LinearOpBase< Scalar > > &block)
#define TEUCHOS_ASSERT_INEQUALITY(val1, comp, val2)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
T_To & dyn_cast(T_From &from)
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.
RCP< LinearOpBase< Scalar > > getNonconstBlock(const int i, const int j)
Interface for a collection of column vectors called a multi-vector.
void setLOWSBlock(const int i, const int j, const RCP< const LinearOpWithSolveBase< Scalar > > &block)
Base interface for physically blocked linear operators.
virtual std::string description() const
Simple struct for the return status from a solve.
std::string description() const
Prints just the name DefaultBlockedTriangularLinearOpWithSolve along with the overall dimensions and ...
Base class for all linear operators.
ESolveStatus solveStatus
The return status of the solve.
RCP< const LinearOpWithSolveBase< Scalar > > getLOWSBlock(const int i, const int j) const
void push_back(const value_type &x)
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.
The requested solution criteria has likely been achieved.
#define TEUCHOS_ASSERT_EQUALITY(val1, val2)
The requested solution criteria has likely not been achieved.
Simple struct that defines the requested solution criteria for a solve.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
virtual void describe(FancyOStream &out, const EVerbosityLevel verbLevel=verbLevel_default) const
void setNonconstBlocks(const RCP< PhysicallyBlockedLinearOpBase< Scalar > > &blocks)