MueLu Version of the Day
Loading...
Searching...
No Matches
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
15#include "Xpetra_BlockedCrsMatrix.hpp"
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
25namespace Belos {
26
30template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
31class 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
35 typedef Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node> MV;
36 typedef Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> BCRS;
37 typedef Xpetra::MapExtractor<Scalar, LocalOrdinal, GlobalOrdinal, Node> ME;
38 typedef Belos::OperatorT<MV> OP;
39
40 typedef Teuchos::ScalarTraits<Scalar> SCT;
41 typedef typename SCT::magnitudeType MagnitudeType;
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.
269 } else if (testvector_[*p2] == Teuchos::ScalarTraits<Scalar>::magnitude(Teuchos::ScalarTraits<Scalar>::zero())) {
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();
424 Teuchos::RCP<const Belos::XpetraOp<Scalar, LocalOrdinal, GlobalOrdinal, Node> > xOp =
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() << ".");
427 Teuchos::RCP<const Xpetra::Operator<Scalar, LocalOrdinal, GlobalOrdinal, Node> > xIntOp =
428 xOp->getOperator();
429 TEUCHOS_TEST_FOR_EXCEPTION(xIntOp.is_null(), MueLu::Exceptions::BadCast, "Cannot access Xpetra::Operator stored in Belos::XpetraOperator.");
430 Teuchos::RCP<const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> > xMat =
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.");
433 Teuchos::RCP<const Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> > bMat = Teuchos::rcp_dynamic_cast<const Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(xMat);
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 */
MueLu::DefaultScalar Scalar
Exception indicating invalid cast attempted.
Exception throws to report errors in the internal logical of the program.
magnitude_type tolerance