MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BelosXpetraStatusTestGenResSubNorm.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // MueLu: A package for multigrid based preconditioning
4 //
5 // Copyright 2012 NTESS and the MueLu contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef BELOS_XPETRA_STATUS_TEST_GEN_RES_SUB_NORM_HPP
11 #define BELOS_XPETRA_STATUS_TEST_GEN_RES_SUB_NORM_HPP
12 
13 #include "Xpetra_ConfigDefs.hpp"
14 
16 
17 #include "MueLu_Exceptions.hpp"
18 
19 #include <BelosConfigDefs.hpp>
20 #include <BelosTypes.hpp>
21 #include <BelosOperatorT.hpp>
22 #include <BelosXpetraAdapterOperator.hpp>
23 #include <BelosStatusTestGenResSubNorm.hpp>
24 
25 namespace Belos {
26 
30 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
31 class StatusTestGenResSubNorm<Scalar, Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>, Belos::OperatorT<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node> > >
32  : public StatusTestResNorm<Scalar, Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>, Belos::OperatorT<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node> > > {
33  public:
34  // Convenience typedefs
38  typedef Belos::OperatorT<MV> OP;
39 
42  typedef MultiVecTraits<Scalar, MV> MVT;
43  typedef OperatorTraits<Scalar, MV, OP> OT;
44 
46 
47 
60  StatusTestGenResSubNorm(MagnitudeType Tolerance, size_t subIdx, int quorum = -1, bool showMaxResNormOnly = false)
61  : tolerance_(Tolerance)
62  , subIdx_(subIdx)
63  , quorum_(quorum)
64  , showMaxResNormOnly_(showMaxResNormOnly)
65  , resnormtype_(TwoNorm)
66  , scaletype_(NormOfInitRes)
67  , scalenormtype_(TwoNorm)
68  , scalevalue_(Teuchos::ScalarTraits<MagnitudeType>::one())
69  , status_(Undefined)
70  , curBlksz_(0)
71  , curNumRHS_(0)
72  , curLSNum_(0)
73  , numrhs_(0)
74  , firstcallCheckStatus_(true)
75  , firstcallDefineResForm_(true)
76  , firstcallDefineScaleForm_(true)
77  , mapExtractor_(Teuchos::null) {}
78 
80  virtual ~StatusTestGenResSubNorm(){};
82 
84 
85 
87 
93  int defineResForm(NormType TypeOfNorm) {
94  TEUCHOS_TEST_FOR_EXCEPTION(firstcallDefineResForm_ == false, StatusTestError,
95  "StatusTestGenResSubNorm::defineResForm(): The residual form has already been defined.");
96  firstcallDefineResForm_ = false;
97 
98  resnormtype_ = TypeOfNorm;
99 
100  return (0);
101  }
102 
104 
124  int defineScaleForm(ScaleType TypeOfScaling, NormType TypeOfNorm, MagnitudeType ScaleValue = Teuchos::ScalarTraits<MagnitudeType>::one()) {
125  TEUCHOS_TEST_FOR_EXCEPTION(firstcallDefineScaleForm_ == false, StatusTestError,
126  "StatusTestGenResSubNorm::defineScaleForm(): The scaling type has already been defined.");
127  firstcallDefineScaleForm_ = false;
128 
129  scaletype_ = TypeOfScaling;
130  scalenormtype_ = TypeOfNorm;
131  scalevalue_ = ScaleValue;
132 
133  return (0);
134  }
135 
137 
140  int setTolerance(MagnitudeType tolerance) {
141  tolerance_ = tolerance;
142  return (0);
143  }
144 
146 
148  int setSubIdx(size_t subIdx) {
149  subIdx_ = subIdx;
150  return (0);
151  }
152 
155  int setQuorum(int quorum) {
156  quorum_ = quorum;
157  return (0);
158  }
159 
161  int setShowMaxResNormOnly(bool showMaxResNormOnly) {
162  showMaxResNormOnly_ = showMaxResNormOnly;
163  return (0);
164  }
165 
167 
169 
170 
177  StatusType checkStatus(Iteration<Scalar, MV, OP>* iSolver) {
178  MagnitudeType zero = Teuchos::ScalarTraits<MagnitudeType>::zero();
179  const LinearProblem<Scalar, MV, OP>& lp = iSolver->getProblem();
180  // Compute scaling term (done once for each block that's being solved)
181  if (firstcallCheckStatus_) {
182  StatusType status = firstCallCheckStatusSetup(iSolver);
183  if (status == Failed) {
184  status_ = Failed;
185  return (status_);
186  }
187  }
188 
189  //
190  // This section computes the norm of the residual std::vector
191  //
192  if (curLSNum_ != lp.getLSNumber()) {
193  //
194  // We have moved on to the next rhs block
195  //
196  curLSNum_ = lp.getLSNumber();
197  curLSIdx_ = lp.getLSIndex();
198  curBlksz_ = (int)curLSIdx_.size();
199  int validLS = 0;
200  for (int i = 0; i < curBlksz_; ++i) {
201  if (curLSIdx_[i] > -1 && curLSIdx_[i] < numrhs_)
202  validLS++;
203  }
204  curNumRHS_ = validLS;
205  curSoln_ = Teuchos::null;
206  //
207  } else {
208  //
209  // We are in the same rhs block, return if we are converged
210  //
211  if (status_ == Passed) {
212  return status_;
213  }
214  }
215 
216  //
217  // Request the true residual for this block of right-hand sides.
218  //
219  Teuchos::RCP<MV> cur_update = iSolver->getCurrentUpdate();
220  curSoln_ = lp.updateSolution(cur_update);
221  Teuchos::RCP<MV> cur_res = MVT::Clone(*curSoln_, MVT::GetNumberVecs(*curSoln_));
222  lp.computeCurrResVec(&*cur_res, &*curSoln_);
223  std::vector<MagnitudeType> tmp_resvector(MVT::GetNumberVecs(*cur_res));
224  MvSubNorm(*cur_res, subIdx_, tmp_resvector, resnormtype_);
225 
226  typename std::vector<int>::iterator p = curLSIdx_.begin();
227  for (int i = 0; p < curLSIdx_.end(); ++p, ++i) {
228  // Check if this index is valid
229  if (*p != -1)
230  resvector_[*p] = tmp_resvector[i];
231  }
232 
233  //
234  // Compute the new linear system residuals for testing.
235  // (if any of them don't meet the tolerance or are NaN, then we exit with that status)
236  //
237  if (scalevector_.size() > 0) {
238  typename std::vector<int>::iterator pp = curLSIdx_.begin();
239  for (; pp < curLSIdx_.end(); ++pp) {
240  // Check if this index is valid
241  if (*pp != -1) {
242  // Scale the std::vector accordingly
243  if (scalevector_[*pp] != zero) {
244  // Don't intentionally divide by zero.
245  testvector_[*pp] = resvector_[*pp] / scalevector_[*pp] / scalevalue_;
246  } else {
247  testvector_[*pp] = resvector_[*pp] / scalevalue_;
248  }
249  }
250  }
251  } else {
252  typename std::vector<int>::iterator pp = curLSIdx_.begin();
253  for (; pp < curLSIdx_.end(); ++pp) {
254  // Check if this index is valid
255  if (*pp != -1)
256  testvector_[*pp] = resvector_[*pp] / scalevalue_;
257  }
258  }
259  // Check status of new linear system residuals and see if we have the quorum.
260  int have = 0;
261  ind_.resize(curLSIdx_.size());
262  typename std::vector<int>::iterator p2 = curLSIdx_.begin();
263  for (; p2 < curLSIdx_.end(); ++p2) {
264  // Check if this index is valid
265  if (*p2 != -1) {
266  // Check if any of the residuals are larger than the tolerance.
267  if (testvector_[*p2] > tolerance_) {
268  // do nothing.
270  reset();
271  } else if (testvector_[*p2] <= tolerance_) {
272  ind_[have] = *p2;
273  have++;
274  } else {
275  // Throw an std::exception if a NaN is found.
276  status_ = Failed;
277  TEUCHOS_TEST_FOR_EXCEPTION(true, StatusTestError, "StatusTestGenResSubNorm::checkStatus(): NaN has been detected.");
278  }
279  }
280  }
281  ind_.resize(have);
282  int need = (quorum_ == -1) ? curNumRHS_ : quorum_;
283  status_ = (have >= need) ? Passed : Failed;
284  // Return the current status
285  return status_;
286  }
287 
289  StatusType getStatus() const { return (status_); };
291 
293 
294 
296  void reset() {
297  status_ = Undefined;
298  curBlksz_ = 0;
299  curLSNum_ = 0;
300  curLSIdx_.resize(0);
301  numrhs_ = 0;
302  ind_.resize(0);
303  firstcallCheckStatus_ = true;
304  curSoln_ = Teuchos::null;
305  }
306 
308 
310 
311 
313  void print(std::ostream& os, int indent = 0) const {
314  os.setf(std::ios_base::scientific);
315  for (int j = 0; j < indent; j++)
316  os << ' ';
317  printStatus(os, status_);
318  os << resFormStr();
319  if (status_ == Undefined)
320  os << ", tol = " << tolerance_ << std::endl;
321  else {
322  os << std::endl;
323  if (showMaxResNormOnly_ && curBlksz_ > 1) {
324  const MagnitudeType maxRelRes = *std::max_element(
325  testvector_.begin() + curLSIdx_[0], testvector_.begin() + curLSIdx_[curBlksz_ - 1]);
326  for (int j = 0; j < indent + 13; j++)
327  os << ' ';
328  os << "max{residual[" << curLSIdx_[0] << "..." << curLSIdx_[curBlksz_ - 1] << "]} = " << maxRelRes
329  << (maxRelRes <= tolerance_ ? " <= " : " > ") << tolerance_ << std::endl;
330  } else {
331  for (int i = 0; i < numrhs_; i++) {
332  for (int j = 0; j < indent + 13; j++)
333  os << ' ';
334  os << "residual [ " << i << " ] = " << testvector_[i];
335  os << ((testvector_[i] < tolerance_) ? " < " : (testvector_[i] == tolerance_) ? " == "
336  : (testvector_[i] > tolerance_) ? " > "
337  : " ")
338  << tolerance_ << std::endl;
339  }
340  }
341  }
342  os << std::endl;
343  }
344 
346  void printStatus(std::ostream& os, StatusType type) const {
347  os << std::left << std::setw(13) << std::setfill('.');
348  switch (type) {
349  case Passed:
350  os << "Converged";
351  break;
352  case Failed:
353  os << "Unconverged";
354  break;
355  case Undefined:
356  default:
357  os << "**";
358  break;
359  }
360  os << std::left << std::setfill(' ');
361  return;
362  }
364 
366 
367 
369  Teuchos::RCP<MV> getSolution() { return curSoln_; }
370 
373  int getQuorum() const { return quorum_; }
374 
376  size_t getSubIdx() const { return subIdx_; }
377 
379  bool getShowMaxResNormOnly() { return showMaxResNormOnly_; }
380 
382  std::vector<int> convIndices() { return ind_; }
383 
385  MagnitudeType getTolerance() const { return (tolerance_); };
386 
388  const std::vector<MagnitudeType>* getTestValue() const { return (&testvector_); };
389 
391  const std::vector<MagnitudeType>* getResNormValue() const { return (&resvector_); };
392 
394  const std::vector<MagnitudeType>* getScaledNormValue() const { return (&scalevector_); };
395 
398  bool getLOADetected() const { return false; }
399 
401 
404 
410  StatusType firstCallCheckStatusSetup(Iteration<Scalar, MV, OP>* iSolver) {
411  int i;
412  MagnitudeType zero = Teuchos::ScalarTraits<MagnitudeType>::zero();
413  MagnitudeType one = Teuchos::ScalarTraits<MagnitudeType>::one();
414  const LinearProblem<Scalar, MV, OP>& lp = iSolver->getProblem();
415  // Compute scaling term (done once for each block that's being solved)
416  if (firstcallCheckStatus_) {
417  //
418  // Get some current solver information.
419  //
420  firstcallCheckStatus_ = false;
421 
422  // try to access the underlying blocked operator
423  Teuchos::RCP<const OP> Op = lp.getOperator();
425  Teuchos::rcp_dynamic_cast<const Belos::XpetraOp<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(Op);
426  TEUCHOS_TEST_FOR_EXCEPTION(xOp.is_null(), MueLu::Exceptions::BadCast, "Bad cast from \'const Belos::OperatorT\' to \'const Belos::XpetraOp\'. The origin type is " << typeid(const OP).name() << ".");
428  xOp->getOperator();
429  TEUCHOS_TEST_FOR_EXCEPTION(xIntOp.is_null(), MueLu::Exceptions::BadCast, "Cannot access Xpetra::Operator stored in Belos::XpetraOperator.");
431  Teuchos::rcp_dynamic_cast<const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(xIntOp);
432  TEUCHOS_TEST_FOR_EXCEPTION(xMat.is_null(), MueLu::Exceptions::RuntimeError, "Cannot access Xpetra::Matrix stored in Belos::XpetraOp. Error.");
434  TEUCHOS_TEST_FOR_EXCEPTION(bMat.is_null(), MueLu::Exceptions::BadCast, "Bad cast from \'const Xpetra::Matrix\' to \'const Xpetra::BlockedCrsMatrix\'. The origin type is " << typeid(const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>).name() << ". Note: you need a BlockedCrsMatrix object for the StatusTestGenResSubNorm to work!");
435  mapExtractor_ = bMat->getRangeMapExtractor();
436  TEUCHOS_TEST_FOR_EXCEPTION(mapExtractor_.is_null(), MueLu::Exceptions::RuntimeError, "Could not extract map extractor from BlockedCrsMatrix. Error.");
437  TEUCHOS_TEST_FOR_EXCEPTION(mapExtractor_->NumMaps() <= subIdx_, MueLu::Exceptions::RuntimeError, "The multivector is only split into " << mapExtractor_->NumMaps() << " sub parts. Cannot access sub-block " << subIdx_ << ".");
438 
439  // calculate initial norms
440  if (scaletype_ == NormOfRHS) {
441  Teuchos::RCP<const MV> rhs = lp.getRHS();
442  numrhs_ = MVT::GetNumberVecs(*rhs);
443  scalevector_.resize(numrhs_);
444  MvSubNorm(*rhs, subIdx_, scalevector_, scalenormtype_);
445  } else if (scaletype_ == NormOfInitRes) {
446  Teuchos::RCP<const MV> init_res = lp.getInitResVec();
447  numrhs_ = MVT::GetNumberVecs(*init_res);
448  scalevector_.resize(numrhs_);
449  MvSubNorm(*init_res, subIdx_, scalevector_, scalenormtype_);
450  } else if (scaletype_ == NormOfPrecInitRes) {
451  Teuchos::RCP<const MV> init_res = lp.getInitPrecResVec();
452  numrhs_ = MVT::GetNumberVecs(*init_res);
453  scalevector_.resize(numrhs_);
454  MvSubNorm(*init_res, subIdx_, scalevector_, scalenormtype_);
455  } else if (scaletype_ == NormOfFullInitRes) {
456  Teuchos::RCP<const MV> init_res = lp.getInitResVec();
457  numrhs_ = MVT::GetNumberVecs(*init_res);
458  scalevector_.resize(numrhs_);
459  MVT::MvNorm(*init_res, scalevector_, scalenormtype_);
460  scalevalue_ = one;
461  } else if (scaletype_ == NormOfFullPrecInitRes) {
462  Teuchos::RCP<const MV> init_res = lp.getInitPrecResVec();
463  numrhs_ = MVT::GetNumberVecs(*init_res);
464  scalevector_.resize(numrhs_);
465  MVT::MvNorm(*init_res, scalevector_, scalenormtype_);
466  scalevalue_ = one;
467  } else if (scaletype_ == NormOfFullScaledInitRes) {
468  Teuchos::RCP<const MV> init_res = lp.getInitResVec();
469  numrhs_ = MVT::GetNumberVecs(*init_res);
470  scalevector_.resize(numrhs_);
471  MVT::MvNorm(*init_res, scalevector_, scalenormtype_);
472  MvScalingRatio(*init_res, subIdx_, scalevalue_);
473  } else if (scaletype_ == NormOfFullScaledPrecInitRes) {
474  Teuchos::RCP<const MV> init_res = lp.getInitPrecResVec();
475  numrhs_ = MVT::GetNumberVecs(*init_res);
476  scalevector_.resize(numrhs_);
477  MVT::MvNorm(*init_res, scalevector_, scalenormtype_);
478  MvScalingRatio(*init_res, subIdx_, scalevalue_);
479  } else {
480  numrhs_ = MVT::GetNumberVecs(*(lp.getRHS()));
481  }
482 
483  resvector_.resize(numrhs_);
484  testvector_.resize(numrhs_);
485 
486  curLSNum_ = lp.getLSNumber();
487  curLSIdx_ = lp.getLSIndex();
488  curBlksz_ = (int)curLSIdx_.size();
489  int validLS = 0;
490  for (i = 0; i < curBlksz_; ++i) {
491  if (curLSIdx_[i] > -1 && curLSIdx_[i] < numrhs_)
492  validLS++;
493  }
494  curNumRHS_ = validLS;
495  //
496  // Initialize the testvector.
497  for (i = 0; i < numrhs_; i++) {
498  testvector_[i] = one;
499  }
500 
501  // Return an error if the scaling is zero.
502  if (scalevalue_ == zero) {
503  return Failed;
504  }
505  }
506  return Undefined;
507  }
509 
512 
514  std::string description() const {
515  std::ostringstream oss;
516  oss << "Belos::StatusTestGenResSubNorm<>: " << resFormStr();
517  oss << ", tol = " << tolerance_;
518  return oss.str();
519  }
521 
522  protected:
523  private:
525 
526 
527  std::string resFormStr() const {
528  std::ostringstream oss;
529  oss << "(";
530  oss << ((resnormtype_ == OneNorm) ? "1-Norm" : (resnormtype_ == TwoNorm) ? "2-Norm"
531  : "Inf-Norm");
532  oss << " Exp";
533  oss << " Res Vec [" << subIdx_ << "]) ";
534 
535  // If there is no residual scaling, return current string.
536  if (scaletype_ != None) {
537  // Insert division sign.
538  oss << "/ ";
539 
540  // Determine output string for scaling, if there is any.
541  if (scaletype_ == UserProvided)
542  oss << " (User Scale)";
543  else {
544  oss << "(";
545  oss << ((scalenormtype_ == OneNorm) ? "1-Norm" : (resnormtype_ == TwoNorm) ? "2-Norm"
546  : "Inf-Norm");
547  if (scaletype_ == NormOfInitRes)
548  oss << " Res0 [" << subIdx_ << "]";
549  else if (scaletype_ == NormOfPrecInitRes)
550  oss << " Prec Res0 [" << subIdx_ << "]";
551  else if (scaletype_ == NormOfFullInitRes)
552  oss << " Full Res0 [" << subIdx_ << "]";
553  else if (scaletype_ == NormOfFullPrecInitRes)
554  oss << " Full Prec Res0 [" << subIdx_ << "]";
555  else if (scaletype_ == NormOfFullScaledInitRes)
556  oss << " scaled Full Res0 [" << subIdx_ << "]";
557  else if (scaletype_ == NormOfFullScaledPrecInitRes)
558  oss << " scaled Full Prec Res0 [" << subIdx_ << "]";
559  else
560  oss << " RHS [" << subIdx_ << "]";
561  oss << ")";
562  }
563  }
564 
565  // TODO add a tagging name
566 
567  return oss.str();
568  }
569 
571 
573 
574 
575  // calculate norm of partial multivector
576  void MvSubNorm(const MV& mv, size_t block, std::vector<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>& normVec, NormType type = TwoNorm) {
577  Teuchos::RCP<const MV> input = Teuchos::rcpFromRef(mv);
578 
579  Teuchos::RCP<const MV> SubVec = mapExtractor_->ExtractVector(input, block);
580  MVT::MvNorm(*SubVec, normVec, type);
581  }
582 
583  // calculate ration of sub-vector length to full vector length (for scalevalue_)
584  void MvScalingRatio(const MV& mv, size_t block, MagnitudeType& lengthRatio) {
585  Teuchos::RCP<const MV> input = Teuchos::rcpFromRef(mv);
586 
587  Teuchos::RCP<const MV> SubVec = mapExtractor_->ExtractVector(input, block);
588 
589  lengthRatio = Teuchos::as<MagnitudeType>(SubVec->getGlobalLength()) / Teuchos::as<MagnitudeType>(input->getGlobalLength());
590  }
592 
594 
595 
597  MagnitudeType tolerance_;
598 
600  size_t subIdx_;
601 
603  int quorum_;
604 
606  bool showMaxResNormOnly_;
607 
609  NormType resnormtype_;
610 
612  ScaleType scaletype_;
613 
615  NormType scalenormtype_;
616 
618  MagnitudeType scalevalue_;
619 
621  std::vector<MagnitudeType> scalevector_;
622 
624  std::vector<MagnitudeType> resvector_;
625 
627  std::vector<MagnitudeType> testvector_;
628 
630  std::vector<int> ind_;
631 
633  Teuchos::RCP<MV> curSoln_;
634 
636  StatusType status_;
637 
639  int curBlksz_;
640 
642  int curNumRHS_;
643 
645  std::vector<int> curLSIdx_;
646 
648  int curLSNum_;
649 
651  int numrhs_;
652 
654  bool firstcallCheckStatus_;
655 
657  bool firstcallDefineResForm_;
658 
660  bool firstcallDefineScaleForm_;
661 
663  Teuchos::RCP<const ME> mapExtractor_;
665 };
666 
667 } // namespace Belos
668 
669 #endif /* BELOS_XPETRA_STATUS_TEST_GEN_RES_SUB_NORM_HPP */
Exception indicating invalid cast attempted.
void reset()
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
MueLu::DefaultScalar Scalar
Exception throws to report errors in the internal logical of the program.
bool is_null() const