Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Belos_IMGS_OrthoManager_MP_Vector.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Belos: Block Linear Solvers Package
4 //
5 // Copyright 2004 NTESS and the Belos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
18 #ifndef BELOS_IMGS_ORTHOMANAGER_MP_VECTOR_HPP
19 #define BELOS_IMGS_ORTHOMANAGER_MP_VECTOR_HPP
20 
22 #include "BelosIMGSOrthoManager.hpp"
23 
24 namespace Belos {
25 
26  template<class Storage, class MV, class OP>
27  class IMGSOrthoManager<Sacado::MP::Vector<Storage>,MV,OP> :
28  public MatOrthoManager<Sacado::MP::Vector<Storage>,MV,OP>
29  {
30  private:
35  typedef MultiVecTraits<ScalarType,MV> MVT;
36  typedef OperatorTraits<ScalarType,MV,OP> OPT;
37 
38  public:
40 
41 
43  IMGSOrthoManager( const std::string& label = "Belos",
45  const int max_ortho_steps = max_ortho_steps_default_,
46  const MagnitudeType blk_tol = blk_tol_default_,
47  const MagnitudeType sing_tol = sing_tol_default_ )
48  : MatOrthoManager<ScalarType,MV,OP>(Op),
49  max_ortho_steps_( max_ortho_steps ),
50  blk_tol_( blk_tol ),
51  sing_tol_( sing_tol ),
52  label_( label )
53  {
54 #ifdef BELOS_TEUCHOS_TIME_MONITOR
55  std::stringstream ss;
56  ss << label_ + ": IMGS[" << max_ortho_steps_ << "]";
57 
58  std::string orthoLabel = ss.str() + ": Orthogonalization";
59  timerOrtho_ = Teuchos::TimeMonitor::getNewCounter(orthoLabel);
60 
61  std::string updateLabel = ss.str() + ": Ortho (Update)";
62  timerUpdate_ = Teuchos::TimeMonitor::getNewCounter(updateLabel);
63 
64  std::string normLabel = ss.str() + ": Ortho (Norm)";
65  timerNorm_ = Teuchos::TimeMonitor::getNewCounter(normLabel);
66 
67  std::string ipLabel = ss.str() + ": Ortho (Inner Product)";
68  timerInnerProd_ = Teuchos::TimeMonitor::getNewCounter(ipLabel);
69 #endif
70  }
71 
74  const std::string& label = "Belos",
76  MatOrthoManager<ScalarType,MV,OP>(Op),
77  max_ortho_steps_ (max_ortho_steps_default_),
78  blk_tol_ (blk_tol_default_),
79  sing_tol_ (sing_tol_default_),
80  label_ (label)
81  {
82  setParameterList (plist);
83 
84 #ifdef BELOS_TEUCHOS_TIME_MONITOR
85  std::stringstream ss;
86  ss << label_ + ": IMGS[" << max_ortho_steps_ << "]";
87 
88  std::string orthoLabel = ss.str() + ": Orthogonalization";
89  timerOrtho_ = Teuchos::TimeMonitor::getNewCounter(orthoLabel);
90 
91  std::string updateLabel = ss.str() + ": Ortho (Update)";
92  timerUpdate_ = Teuchos::TimeMonitor::getNewCounter(updateLabel);
93 
94  std::string normLabel = ss.str() + ": Ortho (Norm)";
95  timerNorm_ = Teuchos::TimeMonitor::getNewCounter(normLabel);
96 
97  std::string ipLabel = ss.str() + ": Ortho (Inner Product)";
98  timerInnerProd_ = Teuchos::TimeMonitor::getNewCounter(ipLabel);
99 #endif
100  }
101 
105 
107 
108  void
110  {
113  using Teuchos::parameterList;
114  using Teuchos::RCP;
115 
116  RCP<const ParameterList> defaultParams = getValidParameters();
117  RCP<ParameterList> params;
118  if (plist.is_null()) {
119  params = parameterList (*defaultParams);
120  } else {
121  params = plist;
122  // Some users might want to specify "blkTol" as "depTol". Due
123  // to this case, we don't invoke
124  // validateParametersAndSetDefaults on params. Instead, we go
125  // through the parameter list one parameter at a time and look
126  // for alternatives.
127  }
128 
129  // Using temporary variables and fetching all values before
130  // setting the output arguments ensures the strong exception
131  // guarantee for this function: if an exception is thrown, no
132  // externally visible side effects (in this case, setting the
133  // output arguments) have taken place.
134  int maxNumOrthogPasses;
135  MagnitudeType blkTol;
136  MagnitudeType singTol;
137 
138  try {
139  maxNumOrthogPasses = params->get<int> ("maxNumOrthogPasses");
140  } catch (InvalidParameterName&) {
141  maxNumOrthogPasses = defaultParams->get<int> ("maxNumOrthogPasses");
142  params->set ("maxNumOrthogPasses", maxNumOrthogPasses);
143  }
144 
145  // Handling of the "blkTol" parameter is a special case. This
146  // is because some users may prefer to call this parameter
147  // "depTol" for consistency with DGKS. However, our default
148  // parameter list calls this "blkTol", and we don't want the
149  // default list's value to override the user's value. Thus, we
150  // first check the user's parameter list for both names, and
151  // only then access the default parameter list.
152  try {
153  blkTol = params->get<MagnitudeType> ("blkTol");
154  } catch (InvalidParameterName&) {
155  try {
156  blkTol = params->get<MagnitudeType> ("depTol");
157  // "depTol" is the wrong name, so remove it and replace with
158  // "blkTol". We'll set "blkTol" below.
159  params->remove ("depTol");
160  } catch (InvalidParameterName&) {
161  blkTol = defaultParams->get<MagnitudeType> ("blkTol");
162  }
163  params->set ("blkTol", blkTol);
164  }
165 
166  try {
167  singTol = params->get<MagnitudeType> ("singTol");
168  } catch (InvalidParameterName&) {
169  singTol = defaultParams->get<MagnitudeType> ("singTol");
170  params->set ("singTol", singTol);
171  }
172 
173  max_ortho_steps_ = maxNumOrthogPasses;
174  blk_tol_ = blkTol;
175  sing_tol_ = singTol;
176 
177  this->setMyParamList (params);
178  }
179 
182  {
183  if (defaultParams_.is_null()) {
184  defaultParams_ = Belos::getIMGSDefaultParameters<ScalarType, MV, OP>();
185  }
186 
187  return defaultParams_;
188  }
189 
191 
193 
194 
196  void setBlkTol( const MagnitudeType blk_tol ) { blk_tol_ = blk_tol; }
197 
199  void setSingTol( const MagnitudeType sing_tol ) { sing_tol_ = sing_tol; }
200 
202  MagnitudeType getBlkTol() const { return blk_tol_; }
203 
205  MagnitudeType getSingTol() const { return sing_tol_; }
206 
208 
209 
211 
212 
240  void project ( MV &X, Teuchos::RCP<MV> MX,
243 
244 
247  void project ( MV &X,
250  project(X,Teuchos::null,C,Q);
251  }
252 
253 
254 
279  int normalize ( MV &X, Teuchos::RCP<MV> MX,
281 
282 
286  return normalize(X,Teuchos::null,B);
287  }
288 
289  protected:
331  virtual int
332  projectAndNormalizeWithMxImpl (MV &X,
333  Teuchos::RCP<MV> MX,
337 
338  public:
340 
342 
347  orthonormError(const MV &X) const {
348  return orthonormError(X,Teuchos::null);
349  }
350 
356  orthonormError(const MV &X, Teuchos::RCP<const MV> MX) const;
357 
362  orthogError(const MV &X1, const MV &X2) const {
363  return orthogError(X1,Teuchos::null,X2);
364  }
365 
371  orthogError(const MV &X1, Teuchos::RCP<const MV> MX1, const MV &X2) const;
372 
374 
376 
377 
380  void setLabel(const std::string& label);
381 
384  const std::string& getLabel() const { return label_; }
385 
387 
389 
390 
392  static const int max_ortho_steps_default_;
397 
399  static const int max_ortho_steps_fast_;
404 
406 
407  private:
408 
415 
417  std::string label_;
418 #ifdef BELOS_TEUCHOS_TIME_MONITOR
419  Teuchos::RCP<Teuchos::Time> timerOrtho_, timerUpdate_, timerNorm_, timerInnerProd_;
420 #endif // BELOS_TEUCHOS_TIME_MONITOR
421 
424 
426  int findBasis(MV &X, Teuchos::RCP<MV> MX,
428  bool completeBasis, int howMany = -1 ) const;
429 
431  bool blkOrtho1 ( MV &X, Teuchos::RCP<MV> MX,
434 
436  bool blkOrtho ( MV &X, Teuchos::RCP<MV> MX,
439 
453  int blkOrthoSing ( MV &X, Teuchos::RCP<MV> MX,
457  };
458 
459  // Set static variables.
460  template<class StorageType, class MV, class OP>
461  const int IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::max_ortho_steps_default_ = 1;
462 
463  template<class StorageType, class MV, class OP>
464  const typename IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::MagnitudeType
465  IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::blk_tol_default_
467  Teuchos::ScalarTraits<typename IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::MagnitudeType>::eps() );
468 
469  template<class StorageType, class MV, class OP>
470  const typename IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::MagnitudeType
471  IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::sing_tol_default_
473 
474  template<class StorageType, class MV, class OP>
475  const int IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::max_ortho_steps_fast_ = 1;
476 
477  template<class StorageType, class MV, class OP>
478  const typename IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::MagnitudeType
479  IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::blk_tol_fast_
481 
482  template<class StorageType, class MV, class OP>
483  const typename IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::MagnitudeType
484  IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::sing_tol_fast_
486 
488  // Set the label for this orthogonalization manager and create new timers if it's changed
489  template<class StorageType, class MV, class OP>
490  void IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::setLabel(const std::string& label)
491  {
492  if (label != label_) {
493  label_ = label;
494 #ifdef BELOS_TEUCHOS_TIME_MONITOR
495  std::stringstream ss;
496  ss << label_ + ": IMGS[" << max_ortho_steps_ << "]";
497 
498  std::string orthoLabel = ss.str() + ": Orthogonalization";
499  timerOrtho_ = Teuchos::TimeMonitor::getNewCounter(orthoLabel);
500 
501  std::string updateLabel = ss.str() + ": Ortho (Update)";
502  timerUpdate_ = Teuchos::TimeMonitor::getNewCounter(updateLabel);
503 
504  std::string normLabel = ss.str() + ": Ortho (Norm)";
505  timerNorm_ = Teuchos::TimeMonitor::getNewCounter(normLabel);
506 
507  std::string ipLabel = ss.str() + ": Ortho (Inner Product)";
508  timerInnerProd_ = Teuchos::TimeMonitor::getNewCounter(ipLabel);
509 #endif
510  }
511  }
512 
514  // Compute the distance from orthonormality
515  template<class StorageType, class MV, class OP>
517  IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::orthonormError(const MV &X, Teuchos::RCP<const MV> MX) const {
518  const ScalarType ONE = SCT::one();
519  int rank = MVT::GetNumberVecs(X);
521  MatOrthoManager<ScalarType,MV,OP>::innerProd(X,X,MX,xTx);
522  for (int i=0; i<rank; i++) {
523  xTx(i,i) -= ONE;
524  }
525  return xTx.normFrobenius();
526  }
527 
529  // Compute the distance from orthogonality
530  template<class StorageType, class MV, class OP>
532  IMGSOrthoManager<Sacado::MP::Vector<StorageType>,MV,OP>::orthogError(const MV &X1, Teuchos::RCP<const MV> MX1, const MV &X2) const {
533  int r1 = MVT::GetNumberVecs(X1);
534  int r2 = MVT::GetNumberVecs(X2);
536  MatOrthoManager<ScalarType,MV,OP>::innerProd(X2,X1,MX1,xTx);
537  return xTx.normFrobenius();
538  }
539 
541  // Find an Op-orthonormal basis for span(X) - span(W)
542  template<class StorageType, class MV, class OP>
543  int
544  IMGSOrthoManager<Sacado::MP::Vector<StorageType>, MV, OP>::
545  projectAndNormalizeWithMxImpl(MV &X,
546  Teuchos::RCP<MV> MX,
550  {
551  using Teuchos::Array;
552  using Teuchos::null;
553  using Teuchos::is_null;
554  using Teuchos::RCP;
555  using Teuchos::rcp;
557  typedef SerialDenseMatrix< int, ScalarType > serial_dense_matrix_type;
558  typedef typename Array< RCP< const MV > >::size_type size_type;
559 
560 #ifdef BELOS_TEUCHOS_TIME_MONITOR
561  Teuchos::TimeMonitor orthotimer(*timerOrtho_);
562 #endif
563 
564  ScalarType ONE = SCT::one();
565  const MagnitudeType ZERO = MGT::zero();
566 
567  int nq = Q.size();
568  int xc = MVT::GetNumberVecs( X );
569  ptrdiff_t xr = MVT::GetGlobalLength( X );
570  int rank = xc;
571 
572  // If the user doesn't want to store the normalization
573  // coefficients, allocate some local memory for them. This will
574  // go away at the end of this method.
575  if (is_null (B)) {
576  B = rcp (new serial_dense_matrix_type (xc, xc));
577  }
578  // Likewise, if the user doesn't want to store the projection
579  // coefficients, allocate some local memory for them. Also make
580  // sure that all the entries of C are the right size. We're going
581  // to overwrite them anyway, so we don't have to worry about the
582  // contents (other than to resize them if they are the wrong
583  // size).
584  if (C.size() < nq)
585  C.resize (nq);
586  for (size_type k = 0; k < nq; ++k)
587  {
588  const int numRows = MVT::GetNumberVecs (*Q[k]);
589  const int numCols = xc; // Number of vectors in X
590 
591  if (is_null (C[k]))
592  C[k] = rcp (new serial_dense_matrix_type (numRows, numCols));
593  else if (C[k]->numRows() != numRows || C[k]->numCols() != numCols)
594  {
595  int err = C[k]->reshape (numRows, numCols);
596  TEUCHOS_TEST_FOR_EXCEPTION(err != 0, std::runtime_error,
597  "IMGS orthogonalization: failed to reshape "
598  "C[" << k << "] (the array of block "
599  "coefficients resulting from projecting X "
600  "against Q[1:" << nq << "]).");
601  }
602  }
603 
604  /****** DO NOT MODIFY *MX IF _hasOp == false ******/
605  if (this->_hasOp) {
606  if (MX == Teuchos::null) {
607  // we need to allocate space for MX
608  MX = MVT::Clone(X,MVT::GetNumberVecs(X));
609  OPT::Apply(*(this->_Op),X,*MX);
610  }
611  }
612  else {
613  // Op == I --> MX = X (ignore it if the user passed it in)
614  MX = Teuchos::rcp( &X, false );
615  }
616 
617  int mxc = MVT::GetNumberVecs( *MX );
618  ptrdiff_t mxr = MVT::GetGlobalLength( *MX );
619 
620  // short-circuit
621  TEUCHOS_TEST_FOR_EXCEPTION( xc == 0 || xr == 0, std::invalid_argument, "Belos::IMGSOrthoManager::projectAndNormalize(): X must be non-empty" );
622 
623  int numbas = 0;
624  for (int i=0; i<nq; i++) {
625  numbas += MVT::GetNumberVecs( *Q[i] );
626  }
627 
628  // check size of B
629  TEUCHOS_TEST_FOR_EXCEPTION( B->numRows() != xc || B->numCols() != xc, std::invalid_argument,
630  "Belos::IMGSOrthoManager::projectAndNormalize(): Size of X must be consistant with size of B" );
631  // check size of X and MX
632  TEUCHOS_TEST_FOR_EXCEPTION( xc<0 || xr<0 || mxc<0 || mxr<0, std::invalid_argument,
633  "Belos::IMGSOrthoManager::projectAndNormalize(): MVT returned negative dimensions for X,MX" );
634  // check size of X w.r.t. MX
635  TEUCHOS_TEST_FOR_EXCEPTION( xc!=mxc || xr!=mxr, std::invalid_argument,
636  "Belos::IMGSOrthoManager::projectAndNormalize(): Size of X must be consistant with size of MX" );
637  // check feasibility
638  //TEUCHOS_TEST_FOR_EXCEPTION( numbas+xc > xr, std::invalid_argument,
639  // "Belos::IMGSOrthoManager::projectAndNormalize(): Orthogonality constraints not feasible" );
640 
641  // Some flags for checking dependency returns from the internal orthogonalization methods
642  bool dep_flg = false;
643 
644  // Make a temporary copy of X and MX, just in case a block dependency is detected.
645  Teuchos::RCP<MV> tmpX, tmpMX;
646  tmpX = MVT::CloneCopy(X);
647  if (this->_hasOp) {
648  tmpMX = MVT::CloneCopy(*MX);
649  }
650 
651  if (xc == 1) {
652 
653  // Use the cheaper block orthogonalization.
654  // NOTE: Don't check for dependencies because the update has one vector.
655  dep_flg = blkOrtho1( X, MX, C, Q );
656 
657  // Normalize the new block X
658  if ( B == Teuchos::null ) {
660  }
661  std::vector<ScalarType> diag(xc);
662  {
663 #ifdef BELOS_TEUCHOS_TIME_MONITOR
664  Teuchos::TimeMonitor normTimer( *timerNorm_ );
665 #endif
666  MVT::MvDot( X, *MX, diag );
667  }
668  (*B)(0,0) = SCT::squareroot(SCT::magnitude(diag[0]));
669 
670  ScalarType scale = ONE;
671  mask_assign((*B)(0,0)!= ZERO, scale) /= (*B)(0,0);
672 
673  if(MaskLogic::OR((*B)(0,0)!= ZERO) )
674  rank = 1;
675  MVT::MvScale( X, scale );
676  if (this->_hasOp) {
677  // Update MXj.
678  MVT::MvScale( *MX, scale );
679  }
680  }
681  else {
682 
683  // Use the cheaper block orthogonalization.
684  dep_flg = blkOrtho( X, MX, C, Q );
685 
686  // If a dependency has been detected in this block, then perform
687  // the more expensive nonblock (single vector at a time)
688  // orthogonalization.
689  if (dep_flg) {
690  rank = blkOrthoSing( *tmpX, tmpMX, C, B, Q );
691 
692  // Copy tmpX back into X.
693  MVT::Assign( *tmpX, X );
694  if (this->_hasOp) {
695  MVT::Assign( *tmpMX, *MX );
696  }
697  }
698  else {
699  // There is no dependency, so orthonormalize new block X
700  rank = findBasis( X, MX, B, false );
701  if (rank < xc) {
702  // A dependency was found during orthonormalization of X,
703  // rerun orthogonalization using more expensive single-
704  // vector orthogonalization.
705  rank = blkOrthoSing( *tmpX, tmpMX, C, B, Q );
706 
707  // Copy tmpX back into X.
708  MVT::Assign( *tmpX, X );
709  if (this->_hasOp) {
710  MVT::Assign( *tmpMX, *MX );
711  }
712  }
713  }
714  } // if (xc == 1) {
715 
716  // this should not raise an std::exception; but our post-conditions oblige us to check
717  TEUCHOS_TEST_FOR_EXCEPTION( rank > xc || rank < 0, std::logic_error,
718  "Belos::IMGSOrthoManager::projectAndNormalize(): Debug error in rank variable." );
719 
720  // Return the rank of X.
721  return rank;
722  }
723 
724 
725 
727  // Find an Op-orthonormal basis for span(X), with rank numvectors(X)
728  template<class StorageType, class MV, class OP>
729  int IMGSOrthoManager<Sacado::MP::Vector<StorageType>, MV, OP>::normalize(
730  MV &X, Teuchos::RCP<MV> MX,
732 
733 #ifdef BELOS_TEUCHOS_TIME_MONITOR
734  Teuchos::TimeMonitor orthotimer(*timerOrtho_);
735 #endif
736 
737  // call findBasis, with the instruction to try to generate a basis of rank numvecs(X)
738  return findBasis(X, MX, B, true);
739  }
740 
741 
742 
744  template<class StorageType, class MV, class OP>
745  void IMGSOrthoManager<Sacado::MP::Vector<StorageType>, MV, OP>::project(
746  MV &X, Teuchos::RCP<MV> MX,
749  // For the inner product defined by the operator Op or the identity (Op == 0)
750  // -> Orthogonalize X against each Q[i]
751  // Modify MX accordingly
752  //
753  // Note that when Op is 0, MX is not referenced
754  //
755  // Parameter variables
756  //
757  // X : Vectors to be transformed
758  //
759  // MX : Image of the block of vectors X by the mass matrix
760  //
761  // Q : Bases to orthogonalize against. These are assumed orthonormal, mutually and independently.
762  //
763 
764 #ifdef BELOS_TEUCHOS_TIME_MONITOR
765  Teuchos::TimeMonitor orthotimer(*timerOrtho_);
766 #endif
767 
768  int xc = MVT::GetNumberVecs( X );
769  ptrdiff_t xr = MVT::GetGlobalLength( X );
770  int nq = Q.size();
771  std::vector<int> qcs(nq);
772  // short-circuit
773  if (nq == 0 || xc == 0 || xr == 0) {
774  return;
775  }
776  ptrdiff_t qr = MVT::GetGlobalLength ( *Q[0] );
777  // if we don't have enough C, expand it with null references
778  // if we have too many, resize to throw away the latter ones
779  // if we have exactly as many as we have Q, this call has no effect
780  C.resize(nq);
781 
782 
783  /****** DO NOT MODIFY *MX IF _hasOp == false ******/
784  if (this->_hasOp) {
785  if (MX == Teuchos::null) {
786  // we need to allocate space for MX
787  MX = MVT::Clone(X,MVT::GetNumberVecs(X));
788  OPT::Apply(*(this->_Op),X,*MX);
789  }
790  }
791  else {
792  // Op == I --> MX = X (ignore it if the user passed it in)
793  MX = Teuchos::rcp( &X, false );
794  }
795  int mxc = MVT::GetNumberVecs( *MX );
796  ptrdiff_t mxr = MVT::GetGlobalLength( *MX );
797 
798  // check size of X and Q w.r.t. common sense
799  TEUCHOS_TEST_FOR_EXCEPTION( xc<0 || xr<0 || mxc<0 || mxr<0, std::invalid_argument,
800  "Belos::IMGSOrthoManager::project(): MVT returned negative dimensions for X,MX" );
801  // check size of X w.r.t. MX and Q
802  TEUCHOS_TEST_FOR_EXCEPTION( xc!=mxc || xr!=mxr || xr!=qr, std::invalid_argument,
803  "Belos::IMGSOrthoManager::project(): Size of X not consistant with MX,Q" );
804 
805  // tally up size of all Q and check/allocate C
806  int baslen = 0;
807  for (int i=0; i<nq; i++) {
808  TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetGlobalLength( *Q[i] ) != qr, std::invalid_argument,
809  "Belos::IMGSOrthoManager::project(): Q lengths not mutually consistant" );
810  qcs[i] = MVT::GetNumberVecs( *Q[i] );
811  TEUCHOS_TEST_FOR_EXCEPTION( qr < qcs[i], std::invalid_argument,
812  "Belos::IMGSOrthoManager::project(): Q has less rows than columns" );
813  baslen += qcs[i];
814 
815  // check size of C[i]
816  if ( C[i] == Teuchos::null ) {
818  }
819  else {
820  TEUCHOS_TEST_FOR_EXCEPTION( C[i]->numRows() != qcs[i] || C[i]->numCols() != xc , std::invalid_argument,
821  "Belos::IMGSOrthoManager::project(): Size of Q not consistant with size of C" );
822  }
823  }
824 
825  // Use the cheaper block orthogonalization, don't check for rank deficiency.
826  blkOrtho( X, MX, C, Q );
827 
828  }
829 
831  // Find an Op-orthonormal basis for span(X), with the option of extending the subspace so that
832  // the rank is numvectors(X)
833  template<class StorageType, class MV, class OP>
834  int IMGSOrthoManager<Sacado::MP::Vector<StorageType>, MV, OP>::findBasis(
835  MV &X, Teuchos::RCP<MV> MX,
837  bool completeBasis, int howMany ) const {
838  // For the inner product defined by the operator Op or the identity (Op == 0)
839  // -> Orthonormalize X
840  // Modify MX accordingly
841  //
842  // Note that when Op is 0, MX is not referenced
843  //
844  // Parameter variables
845  //
846  // X : Vectors to be orthonormalized
847  //
848  // MX : Image of the multivector X under the operator Op
849  //
850  // Op : Pointer to the operator for the inner product
851  //
852  //
853 
854  const ScalarType ONE = SCT::one();
855  const MagnitudeType ZERO = SCT::magnitude(SCT::zero());
856 
857  int xc = MVT::GetNumberVecs( X );
858  ptrdiff_t xr = MVT::GetGlobalLength( X );
859 
860  if (howMany == -1) {
861  howMany = xc;
862  }
863 
864  /*******************************************************
865  * If _hasOp == false, we will not reference MX below *
866  *******************************************************/
867 
868  // if Op==null, MX == X (via pointer)
869  // Otherwise, either the user passed in MX or we will allocated and compute it
870  if (this->_hasOp) {
871  if (MX == Teuchos::null) {
872  // we need to allocate space for MX
873  MX = MVT::Clone(X,xc);
874  OPT::Apply(*(this->_Op),X,*MX);
875  }
876  }
877 
878  /* if the user doesn't want to store the coefficienets,
879  * allocate some local memory for them
880  */
881  if ( B == Teuchos::null ) {
883  }
884 
885  int mxc = (this->_hasOp) ? MVT::GetNumberVecs( *MX ) : xc;
886  ptrdiff_t mxr = (this->_hasOp) ? MVT::GetGlobalLength( *MX ) : xr;
887 
888  // check size of C, B
889  TEUCHOS_TEST_FOR_EXCEPTION( xc == 0 || xr == 0, std::invalid_argument,
890  "Belos::IMGSOrthoManager::findBasis(): X must be non-empty" );
891  TEUCHOS_TEST_FOR_EXCEPTION( B->numRows() != xc || B->numCols() != xc, std::invalid_argument,
892  "Belos::IMGSOrthoManager::findBasis(): Size of X not consistant with size of B" );
893  TEUCHOS_TEST_FOR_EXCEPTION( xc != mxc || xr != mxr, std::invalid_argument,
894  "Belos::IMGSOrthoManager::findBasis(): Size of X not consistant with size of MX" );
895  TEUCHOS_TEST_FOR_EXCEPTION( xc > xr, std::invalid_argument,
896  "Belos::IMGSOrthoManager::findBasis(): Size of X not feasible for normalization" );
897  TEUCHOS_TEST_FOR_EXCEPTION( howMany < 0 || howMany > xc, std::invalid_argument,
898  "Belos::IMGSOrthoManager::findBasis(): Invalid howMany parameter" );
899 
900  /* xstart is which column we are starting the process with, based on howMany
901  * columns before xstart are assumed to be Op-orthonormal already
902  */
903  int xstart = xc - howMany;
904 
905  for (int j = xstart; j < xc; j++) {
906 
907  // numX is
908  // * number of currently orthonormal columns of X
909  // * the index of the current column of X
910  int numX = j;
911  bool addVec = false;
912 
913  // Get a view of the vector currently being worked on.
914  std::vector<int> index(1);
915  index[0] = numX;
916  Teuchos::RCP<MV> Xj = MVT::CloneViewNonConst( X, index );
917  Teuchos::RCP<MV> MXj;
918  if ((this->_hasOp)) {
919  // MXj is a view of the current vector in MX
920  MXj = MVT::CloneViewNonConst( *MX, index );
921  }
922  else {
923  // MXj is a pointer to Xj, and MUST NOT be modified
924  MXj = Xj;
925  }
926 
927  Teuchos::RCP<MV> oldMXj;
928  if (numX > 0) {
929  oldMXj = MVT::CloneCopy( *MXj );
930  }
931 
932  // Make storage for these Gram-Schmidt iterations.
935  Teuchos::RCP<const MV> prevX, prevMX;
936 
937  std::vector<ScalarType> oldDot( 1 ), newDot( 1 );
938  //
939  // Save old MXj vector and compute Op-norm
940  //
941  {
942 #ifdef BELOS_TEUCHOS_TIME_MONITOR
943  Teuchos::TimeMonitor normTimer( *timerNorm_ );
944 #endif
945  MVT::MvDot( *Xj, *MXj, oldDot );
946  }
947  // Xj^H Op Xj should be real and positive, by the hermitian positive definiteness of Op
948  TEUCHOS_TEST_FOR_EXCEPTION( SCT::real(oldDot[0]) < ZERO, OrthoError,
949  "Belos::IMGSOrthoManager::findBasis(): Negative definiteness discovered in inner product" );
950 
951  // Perform MGS one vector at a time
952  for (int ii=0; ii<numX; ii++) {
953 
954  index[0] = ii;
955  prevX = MVT::CloneView( X, index );
956  if (this->_hasOp) {
957  prevMX = MVT::CloneView( *MX, index );
958  }
959 
960  for (int i=0; i<max_ortho_steps_; ++i) {
961 
962  // product <- prevX^T MXj
963  {
964 #ifdef BELOS_TEUCHOS_TIME_MONITOR
965  Teuchos::TimeMonitor innerProdTimer( *timerInnerProd_ );
966 #endif
967  MatOrthoManager<ScalarType,MV,OP>::innerProd(*prevX,*Xj,MXj,P2);
968  }
969 
970  // Xj <- Xj - prevX prevX^T MXj
971  // = Xj - prevX product
972  {
973 #ifdef BELOS_TEUCHOS_TIME_MONITOR
974  Teuchos::TimeMonitor updateTimer( *timerUpdate_ );
975 #endif
976  MVT::MvTimesMatAddMv( -ONE, *prevX, P2, ONE, *Xj );
977  }
978 
979  // Update MXj
980  if (this->_hasOp) {
981  // MXj <- Op*Xj_new
982  // = Op*(Xj_old - prevX prevX^T MXj)
983  // = MXj - prevMX product
984 #ifdef BELOS_TEUCHOS_TIME_MONITOR
985  Teuchos::TimeMonitor updateTimer( *timerUpdate_ );
986 #endif
987  MVT::MvTimesMatAddMv( -ONE, *prevMX, P2, ONE, *MXj );
988  }
989 
990  // Set coefficients
991  if ( i==0 )
992  product[ii] = P2[0];
993  else
994  product[ii] += P2[0];
995 
996  } // for (int i=0; i<max_ortho_steps_; ++i)
997 
998  } // for (int ii=0; ii<numX; ++ii)
999 
1000  // Compute Op-norm with old MXj
1001  if (numX > 0) {
1002 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1003  Teuchos::TimeMonitor normTimer( *timerNorm_ );
1004 #endif
1005  MVT::MvDot( *Xj, *oldMXj, newDot );
1006  }
1007  else {
1008  newDot[0] = oldDot[0];
1009  }
1010 
1011  // Check to see if the new vector is dependent.
1012  if (completeBasis) {
1013  //
1014  // We need a complete basis, so add random vectors if necessary
1015  //
1016  if ( SCT::magnitude(newDot[0]) < SCT::magnitude(sing_tol_*oldDot[0]) ) {
1017 
1018  // Add a random vector and orthogonalize it against previous vectors in block.
1019  addVec = true;
1020 #ifdef ORTHO_DEBUG
1021  std::cout << "Belos::IMGSOrthoManager::findBasis() --> Random for column " << numX << std::endl;
1022 #endif
1023  //
1024  Teuchos::RCP<MV> tempXj = MVT::Clone( X, 1 );
1025  Teuchos::RCP<MV> tempMXj;
1026  MVT::MvRandom( *tempXj );
1027  if (this->_hasOp) {
1028  tempMXj = MVT::Clone( X, 1 );
1029  OPT::Apply( *(this->_Op), *tempXj, *tempMXj );
1030  }
1031  else {
1032  tempMXj = tempXj;
1033  }
1034  {
1035 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1036  Teuchos::TimeMonitor normTimer( *timerNorm_ );
1037 #endif
1038  MVT::MvDot( *tempXj, *tempMXj, oldDot );
1039  }
1040  //
1041  // Perform MGS one vector at a time
1042  for (int ii=0; ii<numX; ii++) {
1043 
1044  index[0] = ii;
1045  prevX = MVT::CloneView( X, index );
1046  if (this->_hasOp) {
1047  prevMX = MVT::CloneView( *MX, index );
1048  }
1049 
1050  for (int num_orth=0; num_orth<max_ortho_steps_; num_orth++){
1051  {
1052 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1053  Teuchos::TimeMonitor innerProdTimer( *timerInnerProd_ );
1054 #endif
1055  MatOrthoManager<ScalarType,MV,OP>::innerProd(*prevX,*tempXj,tempMXj,P2);
1056  }
1057  {
1058 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1059  Teuchos::TimeMonitor updateTimer( *timerUpdate_ );
1060 #endif
1061  MVT::MvTimesMatAddMv( -ONE, *prevX, P2, ONE, *tempXj );
1062  }
1063  if (this->_hasOp) {
1064 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1065  Teuchos::TimeMonitor updateTimer( *timerUpdate_ );
1066 #endif
1067  MVT::MvTimesMatAddMv( -ONE, *prevMX, P2, ONE, *tempMXj );
1068  }
1069 
1070  // Set coefficients
1071  if ( num_orth==0 )
1072  product[ii] = P2[0];
1073  else
1074  product[ii] += P2[0];
1075  }
1076  }
1077 
1078  // Compute new Op-norm
1079  {
1080 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1081  Teuchos::TimeMonitor normTimer( *timerNorm_ );
1082 #endif
1083  MVT::MvDot( *tempXj, *tempMXj, newDot );
1084  }
1085  //
1086  if ( SCT::magnitude(newDot[0]) >= SCT::magnitude(oldDot[0]*sing_tol_) ) {
1087  // Copy vector into current column of _basisvecs
1088  MVT::Assign( *tempXj, *Xj );
1089  if (this->_hasOp) {
1090  MVT::Assign( *tempMXj, *MXj );
1091  }
1092  }
1093  else {
1094  return numX;
1095  }
1096  }
1097  }
1098  else {
1099  //
1100  // We only need to detect dependencies.
1101  //
1102  if ( SCT::magnitude(newDot[0]) < SCT::magnitude(oldDot[0]*blk_tol_) ) {
1103  return numX;
1104  }
1105  }
1106 
1107 
1108  // If we haven't left this method yet, then we can normalize the new vector Xj.
1109  // Normalize Xj.
1110  // Xj <- Xj / std::sqrt(newDot)
1111  ScalarType diag = SCT::squareroot(SCT::magnitude(newDot[0]));
1112  ScalarType scale = ONE;
1113  mask_assign(SCT::magnitude(diag) > ZERO, scale) /= diag;
1114  MVT::MvScale( *Xj, scale );
1115  if (this->_hasOp) {
1116  // Update MXj.
1117  MVT::MvScale( *MXj, scale );
1118  }
1119 
1120  // If we've added a random vector, enter a zero in the j'th diagonal element.
1121  if (addVec) {
1122  (*B)(j,j) = ZERO;
1123  }
1124  else {
1125  (*B)(j,j) = diag;
1126  }
1127 
1128  // Save the coefficients, if we are working on the original vector and not a randomly generated one
1129  if (!addVec) {
1130  for (int i=0; i<numX; i++) {
1131  (*B)(i,j) = product(i);
1132  }
1133  }
1134 
1135  } // for (j = 0; j < xc; ++j)
1136 
1137  return xc;
1138  }
1139 
1141  // Routine to compute the block orthogonalization
1142  template<class StorageType, class MV, class OP>
1143  bool
1144  IMGSOrthoManager<Sacado::MP::Vector<StorageType>, MV, OP>::blkOrtho1 ( MV &X, Teuchos::RCP<MV> MX,
1147  {
1148  int nq = Q.size();
1149  int xc = MVT::GetNumberVecs( X );
1150  const ScalarType ONE = SCT::one();
1151 
1152  std::vector<int> qcs( nq );
1153  for (int i=0; i<nq; i++) {
1154  qcs[i] = MVT::GetNumberVecs( *Q[i] );
1155  }
1156 
1157  // Perform the Gram-Schmidt transformation for a block of vectors
1158  std::vector<int> index(1);
1159  Teuchos::RCP<const MV> tempQ;
1160 
1162  // Define the product Q^T * (Op*X)
1163  for (int i=0; i<nq; i++) {
1164 
1165  // Perform MGS one vector at a time
1166  for (int ii=0; ii<qcs[i]; ii++) {
1167 
1168  index[0] = ii;
1169  tempQ = MVT::CloneView( *Q[i], index );
1170  Teuchos::SerialDenseMatrix<int,ScalarType> tempC( Teuchos::View, *C[i], 1, 1, ii, 0 );
1171 
1172  // Multiply Q' with MX
1173  {
1174 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1175  Teuchos::TimeMonitor innerProdTimer( *timerInnerProd_ );
1176 #endif
1177  MatOrthoManager<ScalarType,MV,OP>::innerProd(*tempQ,X,MX,tempC);
1178  }
1179  // Multiply by Q and subtract the result in X
1180  {
1181 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1182  Teuchos::TimeMonitor updateTimer( *timerUpdate_ );
1183 #endif
1184  MVT::MvTimesMatAddMv( -ONE, *tempQ, tempC, ONE, X );
1185  }
1186  }
1187 
1188  // Update MX, with the least number of applications of Op as possible
1189  if (this->_hasOp) {
1190  if (xc <= qcs[i]) {
1191  OPT::Apply( *(this->_Op), X, *MX);
1192  }
1193  else {
1194  // this will possibly be used again below; don't delete it
1195  MQ[i] = MVT::Clone( *Q[i], qcs[i] );
1196  OPT::Apply( *(this->_Op), *Q[i], *MQ[i] );
1197  MVT::MvTimesMatAddMv( -ONE, *MQ[i], *C[i], ONE, *MX );
1198  }
1199  }
1200  }
1201 
1202  // Do as many steps of modified Gram-Schmidt as required by max_ortho_steps_
1203  for (int j = 1; j < max_ortho_steps_; ++j) {
1204 
1205  for (int i=0; i<nq; i++) {
1206 
1208 
1209  // Perform MGS one vector at a time
1210  for (int ii=0; ii<qcs[i]; ii++) {
1211 
1212  index[0] = ii;
1213  tempQ = MVT::CloneView( *Q[i], index );
1214  Teuchos::SerialDenseMatrix<int,ScalarType> tempC( Teuchos::View, *C[i], 1, 1, ii, 0 );
1215  Teuchos::SerialDenseMatrix<int,ScalarType> tempC2( Teuchos::View, C2, 1, 1, ii, 0 );
1216 
1217  // Apply another step of modified Gram-Schmidt
1218  {
1219 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1220  Teuchos::TimeMonitor innerProdTimer( *timerInnerProd_ );
1221 #endif
1222  MatOrthoManager<ScalarType,MV,OP>::innerProd( *tempQ, X, MX, tempC2 );
1223  }
1224  tempC += tempC2;
1225  {
1226 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1227  Teuchos::TimeMonitor updateTimer( *timerUpdate_ );
1228 #endif
1229  MVT::MvTimesMatAddMv( -ONE, *tempQ, tempC2, ONE, X );
1230  }
1231 
1232  }
1233 
1234  // Update MX, with the least number of applications of Op as possible
1235  if (this->_hasOp) {
1236  if (MQ[i].get()) {
1237  // MQ was allocated and computed above; use it
1238  MVT::MvTimesMatAddMv( -ONE, *MQ[i], C2, ONE, *MX );
1239  }
1240  else if (xc <= qcs[i]) {
1241  // MQ was not allocated and computed above; it was cheaper to use X before and it still is
1242  OPT::Apply( *(this->_Op), X, *MX);
1243  }
1244  }
1245  } // for (int i=0; i<nq; i++)
1246  } // for (int j = 0; j < max_ortho_steps; ++j)
1247 
1248  return false;
1249  }
1250 
1252  // Routine to compute the block orthogonalization
1253  template<class StorageType, class MV, class OP>
1254  bool
1255  IMGSOrthoManager<Sacado::MP::Vector<StorageType>, MV, OP>::blkOrtho ( MV &X, Teuchos::RCP<MV> MX,
1258  {
1259  int nq = Q.size();
1260  int xc = MVT::GetNumberVecs( X );
1261  bool dep_flg = false;
1262  const ScalarType ONE = SCT::one();
1263 
1264  std::vector<int> qcs( nq );
1265  for (int i=0; i<nq; i++) {
1266  qcs[i] = MVT::GetNumberVecs( *Q[i] );
1267  }
1268 
1269  // Perform the Gram-Schmidt transformation for a block of vectors
1270 
1271  // Compute the initial Op-norms
1272  std::vector<ScalarType> oldDot( xc );
1273  {
1274 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1275  Teuchos::TimeMonitor normTimer( *timerNorm_ );
1276 #endif
1277  MVT::MvDot( X, *MX, oldDot );
1278  }
1279 
1280  std::vector<int> index(1);
1282  Teuchos::RCP<const MV> tempQ;
1283 
1284  // Define the product Q^T * (Op*X)
1285  for (int i=0; i<nq; i++) {
1286 
1287  // Perform MGS one vector at a time
1288  for (int ii=0; ii<qcs[i]; ii++) {
1289 
1290  index[0] = ii;
1291  tempQ = MVT::CloneView( *Q[i], index );
1292  Teuchos::SerialDenseMatrix<int,ScalarType> tempC( Teuchos::View, *C[i], 1, xc, ii, 0 );
1293 
1294  // Multiply Q' with MX
1295  {
1296 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1297  Teuchos::TimeMonitor innerProdTimer( *timerInnerProd_ );
1298 #endif
1299  MatOrthoManager<ScalarType,MV,OP>::innerProd( *tempQ, X, MX, tempC);
1300  }
1301  // Multiply by Q and subtract the result in X
1302  {
1303 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1304  Teuchos::TimeMonitor updateTimer( *timerUpdate_ );
1305 #endif
1306  MVT::MvTimesMatAddMv( -ONE, *tempQ, tempC, ONE, X );
1307  }
1308  }
1309 
1310  // Update MX, with the least number of applications of Op as possible
1311  if (this->_hasOp) {
1312  if (xc <= qcs[i]) {
1313  OPT::Apply( *(this->_Op), X, *MX);
1314  }
1315  else {
1316  // this will possibly be used again below; don't delete it
1317  MQ[i] = MVT::Clone( *Q[i], qcs[i] );
1318  OPT::Apply( *(this->_Op), *Q[i], *MQ[i] );
1319  MVT::MvTimesMatAddMv( -ONE, *MQ[i], *C[i], ONE, *MX );
1320  }
1321  }
1322  }
1323 
1324  // Do as many steps of modified Gram-Schmidt as required by max_ortho_steps_
1325  for (int j = 1; j < max_ortho_steps_; ++j) {
1326 
1327  for (int i=0; i<nq; i++) {
1329 
1330  // Perform MGS one vector at a time
1331  for (int ii=0; ii<qcs[i]; ii++) {
1332 
1333  index[0] = ii;
1334  tempQ = MVT::CloneView( *Q[i], index );
1335  Teuchos::SerialDenseMatrix<int,ScalarType> tempC( Teuchos::View, *C[i], 1, xc, ii, 0 );
1336  Teuchos::SerialDenseMatrix<int,ScalarType> tempC2( Teuchos::View, C2, 1, xc, ii, 0 );
1337 
1338  // Apply another step of modified Gram-Schmidt
1339  {
1340 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1341  Teuchos::TimeMonitor innerProdTimer( *timerInnerProd_ );
1342 #endif
1343  MatOrthoManager<ScalarType,MV,OP>::innerProd( *tempQ, X, MX, tempC2 );
1344  }
1345  tempC += tempC2;
1346  {
1347 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1348  Teuchos::TimeMonitor updateTimer( *timerUpdate_ );
1349 #endif
1350  MVT::MvTimesMatAddMv( -ONE, *tempQ, tempC2, ONE, X );
1351  }
1352  }
1353 
1354  // Update MX, with the least number of applications of Op as possible
1355  if (this->_hasOp) {
1356  if (MQ[i].get()) {
1357  // MQ was allocated and computed above; use it
1358  MVT::MvTimesMatAddMv( -ONE, *MQ[i], C2, ONE, *MX );
1359  }
1360  else if (xc <= qcs[i]) {
1361  // MQ was not allocated and computed above; it was cheaper to use X before and it still is
1362  OPT::Apply( *(this->_Op), X, *MX);
1363  }
1364  }
1365  } // for (int i=0; i<nq; i++)
1366  } // for (int j = 0; j < max_ortho_steps; ++j)
1367 
1368  // Compute new Op-norms
1369  std::vector<ScalarType> newDot(xc);
1370  {
1371 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1372  Teuchos::TimeMonitor normTimer( *timerNorm_ );
1373 #endif
1374  MVT::MvDot( X, *MX, newDot );
1375  }
1376 
1377  // Check to make sure the new block of vectors are not dependent on previous vectors
1378  for (int i=0; i<xc; i++){
1379  if (SCT::magnitude(newDot[i]) < SCT::magnitude(oldDot[i] * blk_tol_)) {
1380  dep_flg = true;
1381  break;
1382  }
1383  } // end for (i=0;...)
1384 
1385  return dep_flg;
1386  }
1387 
1388  template<class StorageType, class MV, class OP>
1389  int
1390  IMGSOrthoManager<Sacado::MP::Vector<StorageType>, MV, OP>::blkOrthoSing ( MV &X, Teuchos::RCP<MV> MX,
1394  {
1396 
1397  const ScalarType ONE = SCT::one();
1398  const ScalarType ZERO = SCT::zero();
1399 
1400  int nq = Q.size();
1401  int xc = MVT::GetNumberVecs( X );
1402  std::vector<int> indX( 1 );
1403  std::vector<ScalarType> oldDot( 1 ), newDot( 1 );
1404 
1405  std::vector<int> qcs( nq );
1406  for (int i=0; i<nq; i++) {
1407  qcs[i] = MVT::GetNumberVecs( *Q[i] );
1408  }
1409 
1410  // Create pointers for the previous vectors of X that have already been orthonormalized.
1411  Teuchos::RCP<const MV> lastQ;
1412  Teuchos::RCP<MV> Xj, MXj;
1414 
1415  // Perform the Gram-Schmidt transformation for each vector in the block of vectors.
1416  for (int j=0; j<xc; j++) {
1417 
1418  bool dep_flg = false;
1419 
1420  // Get a view of the previously orthogonalized vectors and B, add it to the arrays.
1421  if (j > 0) {
1422  std::vector<int> index( j );
1423  for (int ind=0; ind<j; ind++) {
1424  index[ind] = ind;
1425  }
1426  lastQ = MVT::CloneView( X, index );
1427 
1428  // Add these views to the Q and C arrays.
1429  Q.push_back( lastQ );
1430  C.push_back( B );
1431  qcs.push_back( MVT::GetNumberVecs( *lastQ ) );
1432  }
1433 
1434  // Get a view of the current vector in X to orthogonalize.
1435  indX[0] = j;
1436  Xj = MVT::CloneViewNonConst( X, indX );
1437  if (this->_hasOp) {
1438  MXj = MVT::CloneViewNonConst( *MX, indX );
1439  }
1440  else {
1441  MXj = Xj;
1442  }
1443 
1444  // Compute the initial Op-norms
1445  {
1446 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1447  Teuchos::TimeMonitor normTimer( *timerNorm_ );
1448 #endif
1449  MVT::MvDot( *Xj, *MXj, oldDot );
1450  }
1451 
1452  Teuchos::Array<Teuchos::RCP<MV> > MQ(Q.size());
1453  Teuchos::RCP<const MV> tempQ;
1454 
1455  // Define the product Q^T * (Op*X)
1456  for (int i=0; i<Q.size(); i++) {
1457 
1458  // Perform MGS one vector at a time
1459  for (int ii=0; ii<qcs[i]; ii++) {
1460 
1461  indX[0] = ii;
1462  tempQ = MVT::CloneView( *Q[i], indX );
1463  // Get a view of the current serial dense matrix
1464  Teuchos::SerialDenseMatrix<int,ScalarType> tempC( Teuchos::View, *C[i], 1, 1, ii, j );
1465 
1466  // Multiply Q' with MX
1467  MatOrthoManager<ScalarType,MV,OP>::innerProd(*tempQ,*Xj,MXj,tempC);
1468 
1469  // Multiply by Q and subtract the result in Xj
1470  MVT::MvTimesMatAddMv( -ONE, *tempQ, tempC, ONE, *Xj );
1471  }
1472 
1473  // Update MXj, with the least number of applications of Op as possible
1474  if (this->_hasOp) {
1475  if (xc <= qcs[i]) {
1476  OPT::Apply( *(this->_Op), *Xj, *MXj);
1477  }
1478  else {
1479  // this will possibly be used again below; don't delete it
1480  MQ[i] = MVT::Clone( *Q[i], qcs[i] );
1481  OPT::Apply( *(this->_Op), *Q[i], *MQ[i] );
1482  Teuchos::SerialDenseMatrix<int,ScalarType> tempC( Teuchos::View, *C[i], qcs[i], 1, 0, j );
1483  MVT::MvTimesMatAddMv( -ONE, *MQ[i], tempC, ONE, *MXj );
1484  }
1485  }
1486  }
1487 
1488  // Do any additional steps of modified Gram-Schmidt orthogonalization
1489  for (int num_ortho_steps=1; num_ortho_steps < max_ortho_steps_; ++num_ortho_steps) {
1490 
1491  for (int i=0; i<Q.size(); i++) {
1493 
1494  // Perform MGS one vector at a time
1495  for (int ii=0; ii<qcs[i]; ii++) {
1496 
1497  indX[0] = ii;
1498  tempQ = MVT::CloneView( *Q[i], indX );
1499  // Get a view of the current serial dense matrix
1501 
1502  // Apply another step of modified Gram-Schmidt
1503  MatOrthoManager<ScalarType,MV,OP>::innerProd( *tempQ, *Xj, MXj, tempC2);
1504  MVT::MvTimesMatAddMv( -ONE, *tempQ, tempC2, ONE, *Xj );
1505  }
1506 
1507  // Add the coefficients into C[i]
1508  Teuchos::SerialDenseMatrix<int,ScalarType> tempC( Teuchos::View, *C[i], qcs[i], 1, 0, j );
1509  tempC += C2;
1510 
1511  // Update MXj, with the least number of applications of Op as possible
1512  if (this->_hasOp) {
1513  if (MQ[i].get()) {
1514  // MQ was allocated and computed above; use it
1515  MVT::MvTimesMatAddMv( -ONE, *MQ[i], C2, ONE, *MXj );
1516  }
1517  else if (xc <= qcs[i]) {
1518  // MQ was not allocated and computed above; it was cheaper to use X before and it still is
1519  OPT::Apply( *(this->_Op), *Xj, *MXj);
1520  }
1521  }
1522  } // for (int i=0; i<Q.size(); i++)
1523 
1524  } // for (int num_ortho_steps=1; num_ortho_steps < max_ortho_steps_; ++num_ortho_steps)
1525 
1526  // Check for linear dependence.
1527  if (SCT::magnitude(newDot[0]) < SCT::magnitude(oldDot[0]*sing_tol_)) {
1528  dep_flg = true;
1529  }
1530 
1531  // Normalize the new vector if it's not dependent
1532  if (!dep_flg) {
1533  ScalarType diag = SCT::squareroot(SCT::magnitude(newDot[0]));
1534 
1535  MVT::MvScale( *Xj, ONE/diag );
1536  if (this->_hasOp) {
1537  // Update MXj.
1538  MVT::MvScale( *MXj, ONE/diag );
1539  }
1540 
1541  // Enter value on diagonal of B.
1542  (*B)(j,j) = diag;
1543  }
1544  else {
1545  // Create a random vector and orthogonalize it against all previous columns of Q.
1546  Teuchos::RCP<MV> tempXj = MVT::Clone( X, 1 );
1547  Teuchos::RCP<MV> tempMXj;
1548  MVT::MvRandom( *tempXj );
1549  if (this->_hasOp) {
1550  tempMXj = MVT::Clone( X, 1 );
1551  OPT::Apply( *(this->_Op), *tempXj, *tempMXj );
1552  }
1553  else {
1554  tempMXj = tempXj;
1555  }
1556  {
1557 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1558  Teuchos::TimeMonitor normTimer( *timerNorm_ );
1559 #endif
1560  MVT::MvDot( *tempXj, *tempMXj, oldDot );
1561  }
1562  //
1563  for (int num_orth=0; num_orth<max_ortho_steps_; num_orth++) {
1564 
1565  for (int i=0; i<Q.size(); i++) {
1566  Teuchos::SerialDenseMatrix<int,ScalarType> product( qcs[i], 1 );
1567 
1568  // Perform MGS one vector at a time
1569  for (int ii=0; ii<qcs[i]; ii++) {
1570 
1571  indX[0] = ii;
1572  tempQ = MVT::CloneView( *Q[i], indX );
1573  Teuchos::SerialDenseMatrix<int,ScalarType> tempC( Teuchos::View, product, 1, 1, ii );
1574 
1575  // Apply another step of modified Gram-Schmidt
1576  MatOrthoManager<ScalarType,MV,OP>::innerProd( *tempQ, *tempXj, tempMXj, tempC );
1577  MVT::MvTimesMatAddMv( -ONE, *tempQ, tempC, ONE, *tempXj );
1578 
1579  }
1580 
1581  // Update MXj, with the least number of applications of Op as possible
1582  if (this->_hasOp) {
1583  if (MQ[i].get()) {
1584  // MQ was allocated and computed above; use it
1585  MVT::MvTimesMatAddMv( -ONE, *MQ[i], product, ONE, *tempMXj );
1586  }
1587  else if (xc <= qcs[i]) {
1588  // MQ was not allocated and computed above; it was cheaper to use X before and it still is
1589  OPT::Apply( *(this->_Op), *tempXj, *tempMXj);
1590  }
1591  }
1592  } // for (int i=0; i<nq; i++)
1593  } // for (int num_orth=0; num_orth<max_orth_steps_; num_orth++)
1594 
1595  // Compute the Op-norms after the correction step.
1596  {
1597 #ifdef BELOS_TEUCHOS_TIME_MONITOR
1598  Teuchos::TimeMonitor normTimer( *timerNorm_ );
1599 #endif
1600  MVT::MvDot( *tempXj, *tempMXj, newDot );
1601  }
1602 
1603  // Copy vector into current column of Xj
1604  if ( SCT::magnitude(newDot[0]) >= SCT::magnitude(oldDot[0]*sing_tol_) ) {
1605  ScalarType diag = SCT::squareroot(SCT::magnitude(newDot[0]));
1606 
1607  // Enter value on diagonal of B.
1608  (*B)(j,j) = ZERO;
1609 
1610  // Copy vector into current column of _basisvecs
1611  MVT::MvAddMv( ONE/diag, *tempXj, ZERO, *tempXj, *Xj );
1612  if (this->_hasOp) {
1613  MVT::MvAddMv( ONE/diag, *tempMXj, ZERO, *tempMXj, *MXj );
1614  }
1615  }
1616  else {
1617  return j;
1618  }
1619  } // if (!dep_flg)
1620 
1621  // Remove the vectors from array
1622  if (j > 0) {
1623  Q.resize( nq );
1624  C.resize( nq );
1625  qcs.resize( nq );
1626  }
1627 
1628  } // for (int j=0; j<xc; j++)
1629 
1630  return xc;
1631  }
1632 
1633 } // namespace Belos
1634 
1635 #endif // BELOS_IMGS_ORTHOMANAGER_HPP
1636 
void project(MV &X, Teuchos::Array< Teuchos::RCP< Teuchos::SerialDenseMatrix< int, ScalarType > > > C, Teuchos::ArrayView< Teuchos::RCP< const MV > > Q) const
This method calls project(X,Teuchos::null,C,Q); see documentation for that function.
bool is_null(const boost::shared_ptr< T > &p)
Teuchos::ScalarTraits< ScalarType >::magnitudeType orthogError(const MV &X1, const MV &X2) const
This method computes the error in orthogonality of two multivectors, measured as the Frobenius norm o...
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &plist)
T & get(ParameterList &l, const std::string &name)
static RCP< Time > getNewCounter(const std::string &name)
bool is_null(const std::shared_ptr< T > &p)
const std::string & getLabel() const
This method returns the label being used by the timers in the orthogonalization manager.
static const int max_ortho_steps_fast_
Max number of (re)orthogonalization steps, including the first (fast).
void setSingTol(const MagnitudeType sing_tol)
Set parameter for singular block detection.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Teuchos::ScalarTraits< ScalarType >::magnitudeType orthonormError(const MV &X) const
This method computes the error in orthonormality of a multivector, measured as the Frobenius norm of ...
static const MagnitudeType sing_tol_fast_
Singular block detection threshold (fast).
int normalize(MV &X, Teuchos::RCP< Teuchos::SerialDenseMatrix< int, ScalarType > > B) const
This method calls normalize(X,Teuchos::null,B); see documentation for that function.
IMGSOrthoManager(const Teuchos::RCP< Teuchos::ParameterList > &plist, const std::string &label="Belos", Teuchos::RCP< const OP > Op=Teuchos::null)
Constructor that takes a list of parameters.
KOKKOS_INLINE_FUNCTION bool OR(Mask< T > m)
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
KOKKOS_INLINE_FUNCTION MaskedAssign< scalar > mask_assign(bool b, scalar *s)
int max_ortho_steps_
Max number of (re)orthogonalization steps, including the first.
IMGSOrthoManager(const std::string &label="Belos", Teuchos::RCP< const OP > Op=Teuchos::null, const int max_ortho_steps=max_ortho_steps_default_, const MagnitudeType blk_tol=blk_tol_default_, const MagnitudeType sing_tol=sing_tol_default_)
Constructor specifying re-orthogonalization tolerance.
static const MagnitudeType blk_tol_fast_
Block reorthogonalization threshold (fast).
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void setBlkTol(const MagnitudeType blk_tol)
Set parameter for block re-orthogonalization threshhold.
bool is_null(const RCP< T > &p)
static const MagnitudeType sing_tol_default_
Singular block detection threshold (default).
Teuchos::RCP< Teuchos::ParameterList > defaultParams_
Default parameter list.
static const int max_ortho_steps_default_
Max number of (re)orthogonalization steps, including the first (default).
MagnitudeType getSingTol() const
Return parameter for singular block detection.
static const MagnitudeType blk_tol_default_
Block reorthogonalization threshold (default).
MagnitudeType getBlkTol() const
Return parameter for block re-orthogonalization threshhold.