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