IFPACK  Development
 All Classes Namespaces Files Functions Variables Enumerations Friends Pages
Ifpack_BlockRelaxation.h
1 /*
2 //@HEADER
3 // ***********************************************************************
4 //
5 // Ifpack: Object-Oriented Algebraic Preconditioner Package
6 // Copyright (2002) Sandia Corporation
7 //
8 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
9 // license for use of this work by or on behalf of the U.S. Government.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
39 //
40 // ***********************************************************************
41 //@HEADER
42 */
43 
44 #ifndef IFPACK_BLOCKPRECONDITIONER_H
45 #define IFPACK_BLOCKPRECONDITIONER_H
46 
47 #if defined(Ifpack_SHOW_DEPRECATED_WARNINGS)
48 #ifdef __GNUC__
49 #warning "The Ifpack package is deprecated"
50 #endif
51 #endif
52 
53 #include "Ifpack_ConfigDefs.h"
54 #include "Ifpack_Preconditioner.h"
55 #include "Ifpack_Partitioner.h"
56 #include "Ifpack_LinePartitioner.h"
57 #include "Ifpack_LinearPartitioner.h"
58 #include "Ifpack_GreedyPartitioner.h"
59 #include "Ifpack_METISPartitioner.h"
60 #include "Ifpack_EquationPartitioner.h"
61 #include "Ifpack_UserPartitioner.h"
62 #include "Ifpack_Graph_Epetra_RowMatrix.h"
63 #include "Ifpack_DenseContainer.h"
64 #include "Ifpack_Utils.h"
65 #include "Teuchos_ParameterList.hpp"
66 #include "Teuchos_RefCountPtr.hpp"
67 
68 #include "Epetra_Map.h"
69 #include "Epetra_RowMatrix.h"
70 #include "Epetra_MultiVector.h"
71 #include "Epetra_Vector.h"
72 #include "Epetra_Time.h"
73 #include "Epetra_Import.h"
74 
75 static const int IFPACK_JACOBI = 0;
76 static const int IFPACK_GS = 1;
77 static const int IFPACK_SGS = 2;
78 
79 
81 
144 template<typename T>
146 
147 public:
148 
150 
157 
158  virtual ~Ifpack_BlockRelaxation();
159 
161 
163 
165 
173  virtual int Apply(const Epetra_MultiVector& X,
174  Epetra_MultiVector& Y) const;
175 
177 
186  virtual int ApplyInverse(const Epetra_MultiVector& X,
187  Epetra_MultiVector& Y) const;
188 
190  virtual double NormInf() const
191  {
192  return(-1.0);
193  }
195 
197 
198  virtual int SetUseTranspose(bool UseTranspose_in)
199  {
200  if (UseTranspose_in)
201  IFPACK_CHK_ERR(-98); // FIXME: can I work with the transpose?
202  return(0);
203  }
204 
205  virtual const char* Label() const;
206 
208  virtual bool UseTranspose() const
209  {
210  return(false);
211  }
212 
214  virtual bool HasNormInf() const
215  {
216  return(false);
217  }
218 
220  virtual const Epetra_Comm & Comm() const;
221 
223  virtual const Epetra_Map & OperatorDomainMap() const;
224 
226  virtual const Epetra_Map & OperatorRangeMap() const;
228 
230  int NumLocalBlocks() const
231  {
232  return(NumLocalBlocks_);
233  }
234 
236  virtual bool IsInitialized() const
237  {
238  return(IsInitialized_);
239  }
240 
242  virtual bool IsComputed() const
243  {
244  return(IsComputed_);
245  }
246 
248  virtual int SetParameters(Teuchos::ParameterList& List);
249 
251  virtual int Initialize();
252 
254  virtual int Compute();
255 
256  virtual const Epetra_RowMatrix& Matrix() const
257  {
258  return(*Matrix_);
259  }
260 
261  virtual double Condest(const Ifpack_CondestType /* CT */ = Ifpack_Cheap,
262  const int /* MaxIters */ = 1550,
263  const double /* Tol */ = 1e-9,
264  Epetra_RowMatrix* /* Matrix_in */ = 0)
265  {
266  return(-1.0);
267  }
268 
269  virtual double Condest() const
270  {
271  return(-1.0);
272  }
273 
274  std::ostream& Print(std::ostream& os) const;
275 
277  virtual int NumInitialize() const
278  {
279  return(NumInitialize_);
280  }
281 
283  virtual int NumCompute() const
284  {
285  return(NumCompute_);
286  }
287 
289  virtual int NumApplyInverse() const
290  {
291  return(NumApplyInverse_);
292  }
293 
295  virtual double InitializeTime() const
296  {
297  return(InitializeTime_);
298  }
299 
301  virtual double ComputeTime() const
302  {
303  return(ComputeTime_);
304  }
305 
307  virtual double ApplyInverseTime() const
308  {
309  return(ApplyInverseTime_);
310  }
311 
313  virtual double InitializeFlops() const
314  {
315 #ifdef IFPACK_FLOPCOUNTERS
316  if (Containers_.size() == 0)
317  return(0.0);
318 
319  // the total number of flops is computed each time InitializeFlops() is
320  // called. This is becase I also have to add the contribution from each
321  // container.
322  double total = InitializeFlops_;
323  for (unsigned int i = 0 ; i < Containers_.size() ; ++i)
324  if(Containers_[i]) total += Containers_[i]->InitializeFlops();
325  return(total);
326 #else
327  return(0.0);
328 #endif
329  }
330 
331  virtual double ComputeFlops() const
332  {
333 #ifdef IFPACK_FLOPCOUNTERS
334  if (Containers_.size() == 0)
335  return(0.0);
336 
337  double total = ComputeFlops_;
338  for (unsigned int i = 0 ; i < Containers_.size() ; ++i)
339  if(Containers_[i]) total += Containers_[i]->ComputeFlops();
340  return(total);
341 #else
342  return(0.0);
343 #endif
344  }
345 
346  virtual double ApplyInverseFlops() const
347  {
348 #ifdef IFPACK_FLOPCOUNTERS
349  if (Containers_.size() == 0)
350  return(0.0);
351 
352  double total = ApplyInverseFlops_;
353  for (unsigned int i = 0 ; i < Containers_.size() ; ++i) {
354  if(Containers_[i]) total += Containers_[i]->ApplyInverseFlops();
355  }
356  return(total);
357 #else
358  return(0.0);
359 #endif
360  }
361 
362 private:
363 
366 
368  Ifpack_BlockRelaxation & operator=(const Ifpack_BlockRelaxation& rhs)
369  {
370  return(*this);
371  }
372 
373  virtual int ApplyInverseJacobi(const Epetra_MultiVector& X,
374  Epetra_MultiVector& Y) const;
375 
376  virtual int DoJacobi(const Epetra_MultiVector& X,
377  Epetra_MultiVector& Y) const;
378 
379  virtual int ApplyInverseGS(const Epetra_MultiVector& X,
380  Epetra_MultiVector& Y) const;
381 
382  virtual int DoGaussSeidel(Epetra_MultiVector& X,
383  Epetra_MultiVector& Y) const;
384 
385  virtual int ApplyInverseSGS(const Epetra_MultiVector& X,
386  Epetra_MultiVector& Y) const;
387 
388  virtual int DoSGS(const Epetra_MultiVector& X,
389  Epetra_MultiVector& Xtmp,
390  Epetra_MultiVector& Y) const;
391 
392  int ExtractSubmatrices();
393 
394  // @{ Initializations, timing and flops
395 
397  bool IsInitialized_;
399  bool IsComputed_;
401  int NumInitialize_;
403  int NumCompute_;
405  mutable int NumApplyInverse_;
407  double InitializeTime_;
409  double ComputeTime_;
411  mutable double ApplyInverseTime_;
413  double InitializeFlops_;
415  double ComputeFlops_;
417  mutable double ApplyInverseFlops_;
418  // @}
419 
420  // @{ Settings
422  int NumSweeps_;
424  double DampingFactor_;
426  int NumLocalBlocks_;
428  Teuchos::ParameterList List_;
429  // @}
430 
431  // @{ Other data
434  Teuchos::RefCountPtr< const Epetra_RowMatrix > Matrix_;
435  mutable std::vector<Teuchos::RefCountPtr<T> > Containers_;
436  Epetra_Vector Diagonal_ ;
437 
439  Teuchos::RefCountPtr<Ifpack_Partitioner> Partitioner_;
440  std::string PartitionerType_;
441  int PrecType_;
443  std::string Label_;
445  bool ZeroStartingSolution_;
446  Teuchos::RefCountPtr<Ifpack_Graph> Graph_;
448  Teuchos::RefCountPtr<Epetra_Vector> W_;
449  // Level of overlap among blocks (for Jacobi only).
450  int OverlapLevel_;
451  mutable Epetra_Time Time_;
452  bool IsParallel_;
453  Teuchos::RefCountPtr<Epetra_Import> Importer_;
454  // @}
455 
456 }; // class Ifpack_BlockRelaxation
457 
458 //==============================================================================
459 template<typename T>
462  IsInitialized_(false),
463  IsComputed_(false),
464  NumInitialize_(0),
465  NumCompute_(0),
466  NumApplyInverse_(0),
467  InitializeTime_(0.0),
468  ComputeTime_(0.0),
469  ApplyInverseTime_(0.0),
470  InitializeFlops_(0.0),
471  ComputeFlops_(0.0),
472  ApplyInverseFlops_(0.0),
473  NumSweeps_(1),
474  DampingFactor_(1.0),
475  NumLocalBlocks_(1),
476  Matrix_(Teuchos::rcp(Matrix_in,false)),
477  Diagonal_( Matrix_in->Map()),
478  PartitionerType_("greedy"),
479  PrecType_(IFPACK_JACOBI),
480  ZeroStartingSolution_(true),
481  OverlapLevel_(0),
482  Time_(Comm()),
483  IsParallel_(false)
484 {
485  if (Matrix_in->Comm().NumProc() != 1)
486  IsParallel_ = true;
487 }
488 
489 //==============================================================================
490 template<typename T>
492 {
493 }
494 
495 //==============================================================================
496 template<typename T>
497 const char* Ifpack_BlockRelaxation<T>::Label() const
498 {
499  return(Label_.c_str());
500 }
501 
502 //==============================================================================
503 template<typename T>
506 {
507  int ierr = Matrix().Apply(X,Y);
508  IFPACK_RETURN(ierr);
509 }
510 
511 //==============================================================================
512 template<typename T>
514 Comm() const
515 {
516  return(Matrix().Comm());
517 }
518 
519 //==============================================================================
520 template<typename T>
523 {
524  return(Matrix().OperatorDomainMap());
525 }
526 
527 //==============================================================================
528 template<typename T>
531 {
532  return(Matrix().OperatorRangeMap());
533 }
534 
535 //==============================================================================
536 template<typename T>
538 {
539 
540  if (Partitioner_ == Teuchos::null)
541  IFPACK_CHK_ERR(-3);
542 
543  NumLocalBlocks_ = Partitioner_->NumLocalParts();
544 
545  Containers_.resize(NumLocalBlocks());
546 
547  Diagonal_ = Epetra_Vector(Matrix_->Map());
548  Matrix_->ExtractDiagonalCopy(Diagonal_);
549 
550  for (int i = 0 ; i < NumLocalBlocks() ; ++i) {
551 
552  int rows = Partitioner_->NumRowsInPart(i);
553  // if rows == 1, then this is a singleton block, and should not be
554  // created. For now, allow creation, and just force the compute step below.
555 
556  if( rows != 1 ) {
557  Containers_[i] = Teuchos::rcp( new T(rows) );
558 
559  IFPACK_CHK_ERR(Containers_[i]->SetParameters(List_));
560  IFPACK_CHK_ERR(Containers_[i]->Initialize());
561  // flops in Initialize() will be computed on-the-fly in method InitializeFlops().
562 
563  // set "global" ID of each partitioner row
564  for (int j = 0 ; j < rows ; ++j) {
565  int LRID = (*Partitioner_)(i,j);
566  Containers_[i]->ID(j) = LRID;
567  }
568 
569  IFPACK_CHK_ERR(Containers_[i]->Compute(*Matrix_));
570  }
571  // otherwise leave Containers_[i] as null
572  }
573 
574 #ifdef SINGLETON_DEBUG
575  int issing = 0;
576 
577  for (int i = 0 ; i < NumLocalBlocks() ; ++i)
578  issing += (int) ( Partitioner_->NumRowsInPart(i) == 1);
579  printf( " %d of %d containers are singleton \n",issing,NumLocalBlocks());
580 #endif
581 
582  return(0);
583 }
584 
585 //==============================================================================
586 template<typename T>
588 {
589 
590  if (!IsInitialized())
591  IFPACK_CHK_ERR(Initialize());
592 
593  Time_.ResetStartTime();
594 
595  IsComputed_ = false;
596 
597  if (Matrix().NumGlobalRows64() != Matrix().NumGlobalCols64())
598  IFPACK_CHK_ERR(-2); // only square matrices
599 
600  IFPACK_CHK_ERR(ExtractSubmatrices());
601 
602  if (IsParallel_ && PrecType_ != IFPACK_JACOBI) {
603  // not needed by Jacobi (done by matvec)
604  Importer_ = Teuchos::rcp( new Epetra_Import(Matrix().RowMatrixColMap(),
605  Matrix().RowMatrixRowMap()) );
606 
607  if (Importer_ == Teuchos::null) IFPACK_CHK_ERR(-5);
608  }
609  IsComputed_ = true;
610  ComputeTime_ += Time_.ElapsedTime();
611  ++NumCompute_;
612 
613  return(0);
614 
615 }
616 
617 //==============================================================================
618 template<typename T>
621 {
622  if (!IsComputed())
623  IFPACK_CHK_ERR(-3);
624 
625  if (X.NumVectors() != Y.NumVectors())
626  IFPACK_CHK_ERR(-2);
627 
628  Time_.ResetStartTime();
629 
630  // AztecOO gives X and Y pointing to the same memory location,
631  // need to create an auxiliary vector, Xcopy
632  Teuchos::RefCountPtr< const Epetra_MultiVector > Xcopy;
633  if (X.Pointers()[0] == Y.Pointers()[0])
634  Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) );
635  else
636  Xcopy = Teuchos::rcp( &X, false );
637 
638  switch (PrecType_) {
639  case IFPACK_JACOBI:
640  IFPACK_CHK_ERR(ApplyInverseJacobi(*Xcopy,Y));
641  break;
642  case IFPACK_GS:
643  IFPACK_CHK_ERR(ApplyInverseGS(*Xcopy,Y));
644  break;
645  case IFPACK_SGS:
646  IFPACK_CHK_ERR(ApplyInverseSGS(*Xcopy,Y));
647  break;
648  }
649 
650  ApplyInverseTime_ += Time_.ElapsedTime();
651  ++NumApplyInverse_;
652 
653  return(0);
654 }
655 
656 //==============================================================================
657 // This method in general will not work with AztecOO if used
658 // outside Ifpack_AdditiveSchwarz and OverlapLevel_ != 0
659 //
660 template<typename T>
663  Epetra_MultiVector& Y) const
664 {
665 
666  if (ZeroStartingSolution_)
667  Y.PutScalar(0.0);
668 
669  // do not compute the residual in this case
670  if (NumSweeps_ == 1 && ZeroStartingSolution_) {
671  int ierr = DoJacobi(X,Y);
672  IFPACK_RETURN(ierr);
673  }
674 
675  Epetra_MultiVector AX(Y);
676 
677  for (int j = 0; j < NumSweeps_ ; j++) {
678  IFPACK_CHK_ERR(Apply(Y,AX));
679  ApplyInverseFlops_ += X.NumVectors() * 2 * Matrix_->NumGlobalNonzeros64();
680  IFPACK_CHK_ERR(AX.Update(1.0,X,-1.0));
681  ApplyInverseFlops_ += X.NumVectors() * 2 * Matrix_->NumGlobalRows64();
682  IFPACK_CHK_ERR(DoJacobi(AX,Y));
683  // flops counted in DoJacobi()
684  }
685 
686 
687  return(0);
688 }
689 
690 //==============================================================================
691 template<typename T>
694 {
695  int NumVectors = X.NumVectors();
696 
697  if (OverlapLevel_ == 0) {
698 
699  for (int i = 0 ; i < NumLocalBlocks() ; ++i) {
700 
701  int rows = Partitioner_->NumRowsInPart(i);
702  // may happen that a partition is empty
703  if (rows == 0)
704  continue;
705 
706  if(rows != 1) {
707  int LID;
708 
709  // extract RHS from X
710  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
711  LID = Containers_[i]->ID(j);
712  for (int k = 0 ; k < NumVectors ; ++k) {
713  Containers_[i]->RHS(j,k) = X[k][LID];
714  }
715  }
716 
717  // apply the inverse of each block. NOTE: flops occurred
718  // in ApplyInverse() of each block are summed up in method
719  // ApplyInverseFlops().
720 
721  IFPACK_CHK_ERR(Containers_[i]->ApplyInverse());
722 
723  // copy back into solution vector Y
724  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
725  LID = Containers_[i]->ID(j);
726  for (int k = 0 ; k < NumVectors ; ++k) {
727  Y[k][LID] += DampingFactor_ * Containers_[i]->LHS(j,k);
728  }
729  }
730  } //end if(rows !=1)
731  else {
732  // rows == 1, this is a singleton. compute directly.
733  int LRID = (*Partitioner_)(i,0);
734  double b = X[0][LRID];
735  double a = Diagonal_[LRID];
736  Y[0][LRID] += DampingFactor_* b/a;
737  }
738  // NOTE: flops for ApplyInverse() of each block are summed up
739  // in method ApplyInverseFlops()
740 #ifdef IFPACK_FLOPCOUNTERS
741  ApplyInverseFlops_ += NumVectors * 2 * Matrix_->NumGlobalRows();
742 #endif
743 
744  }
745  }
746  else { // overlap test
747 
748  for (int i = 0 ; i < NumLocalBlocks() ; ++i) {
749 
750  int rows = Partitioner_->NumRowsInPart(i);
751 
752  // may happen that a partition is empty
753  if (rows == 0)
754  continue;
755  if(rows != 1) {
756  int LID;
757 
758  // extract RHS from X
759  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
760  LID = Containers_[i]->ID(j);
761  for (int k = 0 ; k < NumVectors ; ++k) {
762  Containers_[i]->RHS(j,k) = (*W_)[LID] * X[k][LID];
763  }
764  }
765 
766  // apply the inverse of each block
767  // if(rows != 1)
768  IFPACK_CHK_ERR(Containers_[i]->ApplyInverse());
769 
770  // copy back into solution vector Y
771  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
772  LID = Containers_[i]->ID(j);
773  for (int k = 0 ; k < NumVectors ; ++k) {
774  Y[k][LID] += DampingFactor_ * (*W_)[LID] * Containers_[i]->LHS(j,k);
775  }
776  }
777  } // end if(rows != 1)
778  else { // rows == 1, this is a singleton. compute directly.
779  int LRID = (*Partitioner_)(i,0);
780  double w = (*W_)[LRID];
781  double b = w * X[0][LRID];
782  double a = Diagonal_[LRID];
783 
784  Y[0][LRID] += DampingFactor_ * w * b / a;
785  }
786  }
787  // NOTE: flops for ApplyInverse() of each block are summed up
788  // in method ApplyInverseFlops()
789  // NOTE: do not count for simplicity the flops due to overlapping rows
790 #ifdef IFPACK_FLOPCOUNTERS
791  ApplyInverseFlops_ += NumVectors * 4 * Matrix_->NumGlobalRows();
792 #endif
793  }
794 
795  return(0);
796 }
797 
798 //==============================================================================
799 template<typename T>
802  Epetra_MultiVector& Y) const
803 {
804 
805  if (ZeroStartingSolution_)
806  Y.PutScalar(0.0);
807 
808  Epetra_MultiVector Xcopy(X);
809  for (int j = 0; j < NumSweeps_ ; j++) {
810  IFPACK_CHK_ERR(DoGaussSeidel(Xcopy,Y));
811  if (j != NumSweeps_ - 1)
812  Xcopy = X;
813  }
814 
815  return(0);
816 
817 }
818 
819 //==============================================================================
820 template<typename T>
823 {
824 
825  // cycle over all local subdomains
826 
827  int Length = Matrix().MaxNumEntries();
828  std::vector<int> Indices(Length);
829  std::vector<double> Values(Length);
830 
831  int NumMyRows = Matrix().NumMyRows();
832  int NumVectors = X.NumVectors();
833 
834  // an additonal vector is needed by parallel computations
835  // (note that applications through Ifpack_AdditiveSchwarz
836  // are always seen are serial)
837  Teuchos::RefCountPtr< Epetra_MultiVector > Y2;
838  if (IsParallel_)
839  Y2 = Teuchos::rcp( new Epetra_MultiVector(Importer_->TargetMap(), NumVectors) );
840  else
841  Y2 = Teuchos::rcp( &Y, false );
842 
843  double** y_ptr;
844  double** y2_ptr;
845  Y.ExtractView(&y_ptr);
846  Y2->ExtractView(&y2_ptr);
847 
848  // data exchange is here, once per sweep
849  if (IsParallel_)
850  IFPACK_CHK_ERR(Y2->Import(Y,*Importer_,Insert));
851 
852  for (int i = 0 ; i < NumLocalBlocks() ; ++i) {
853  int rows = Partitioner_->NumRowsInPart(i);
854 
855  // may happen that a partition is empty, but if rows == 1, the container is null
856  if (rows!=1 && Containers_[i]->NumRows() == 0)
857  continue;
858 
859  int LID;
860 
861  // update from previous block
862 
863  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
864  LID = (*Partitioner_)(i,j);
865 
866  int NumEntries;
867  IFPACK_CHK_ERR(Matrix().ExtractMyRowCopy(LID, Length,NumEntries,
868  &Values[0], &Indices[0]));
869 
870  for (int k = 0 ; k < NumEntries ; ++k) {
871  int col = Indices[k];
872 
873  for (int kk = 0 ; kk < NumVectors ; ++kk) {
874  X[kk][LID] -= Values[k] * y2_ptr[kk][col];
875  }
876  }
877  }
878 
879  if(rows != 1) {
880  // solve with this block
881 
882  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
883  LID = Containers_[i]->ID(j);
884  for (int k = 0 ; k < NumVectors ; ++k) {
885  Containers_[i]->RHS(j,k) = X[k][LID];
886  }
887  }
888 
889  IFPACK_CHK_ERR(Containers_[i]->ApplyInverse());
890 #ifdef IFPACK_FLOPCOUNTERS
891  ApplyInverseFlops_ += Containers_[i]->ApplyInverseFlops();
892 #endif
893 
894  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
895  LID = Containers_[i]->ID(j);
896  for (int k = 0 ; k < NumVectors ; ++k) {
897  double temp = DampingFactor_ * Containers_[i]->LHS(j,k);
898  y2_ptr[k][LID] += temp;
899  }
900  }
901  } // end if(rows != 1)
902  else {
903  int LRID = (*Partitioner_)(i,0);
904  double b = X[0][LRID];
905  double a = Diagonal_[LRID];
906  y2_ptr[0][LRID]+= DampingFactor_* b/a;
907  }
908  }
909  // operations for all getrow()'s
910  // NOTE: flops for ApplyInverse() of each block are summed up
911  // in method ApplyInverseFlops()
912 #ifdef IFPACK_FLOPCOUNTERS
913  ApplyInverseFlops_ += NumVectors * 2 * Matrix_->NumGlobalNonzeros();
914  ApplyInverseFlops_ += NumVectors * 2 * Matrix_->NumGlobalRows();
915 #endif
916 
917  // Attention: this is delicate... Not all combinations
918  // of Y2 and Y will always work (tough for ML it should be ok)
919  if (IsParallel_)
920  for (int m = 0 ; m < NumVectors ; ++m)
921  for (int i = 0 ; i < NumMyRows ; ++i)
922  y_ptr[m][i] = y2_ptr[m][i];
923 
924  return(0);
925  }
926 
927 //==============================================================================
928 template<typename T>
931 {
932 
933  if (ZeroStartingSolution_)
934  Y.PutScalar(0.0);
935 
936  Epetra_MultiVector Xcopy(X);
937  for (int j = 0; j < NumSweeps_ ; j++) {
938  IFPACK_CHK_ERR(DoSGS(X,Xcopy,Y));
939  if (j != NumSweeps_ - 1)
940  Xcopy = X;
941  }
942  return(0);
943 }
944 
945 //==============================================================================
946 template<typename T>
949  Epetra_MultiVector& Y) const
950 {
951 
952  int NumMyRows = Matrix().NumMyRows();
953  int NumVectors = X.NumVectors();
954 
955  int Length = Matrix().MaxNumEntries();
956  std::vector<int> Indices;
957  std::vector<double> Values;
958  Indices.resize(Length);
959  Values.resize(Length);
960 
961  // an additonal vector is needed by parallel computations
962  // (note that applications through Ifpack_AdditiveSchwarz
963  // are always seen are serial)
964  Teuchos::RefCountPtr< Epetra_MultiVector > Y2;
965  if (IsParallel_)
966  Y2 = Teuchos::rcp( new Epetra_MultiVector(Importer_->TargetMap(), NumVectors) );
967  else
968  Y2 = Teuchos::rcp( &Y, false );
969 
970  double** y_ptr;
971  double** y2_ptr;
972  Y.ExtractView(&y_ptr);
973  Y2->ExtractView(&y2_ptr);
974 
975  // data exchange is here, once per sweep
976  if (IsParallel_)
977  IFPACK_CHK_ERR(Y2->Import(Y,*Importer_,Insert));
978 
979  for (int i = 0 ; i < NumLocalBlocks() ; ++i) {
980  int rows = Partitioner_->NumRowsInPart(i);
981  // may happen that a partition is empty
982  if (rows !=1 && Containers_[i]->NumRows() == 0)
983  continue;
984 
985  int LID;
986 
987  // update from previous block
988 
989  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
990  LID = (*Partitioner_)(i,j);
991  int NumEntries;
992  IFPACK_CHK_ERR(Matrix().ExtractMyRowCopy(LID, Length,NumEntries,
993  &Values[0], &Indices[0]));
994 
995  for (int k = 0 ; k < NumEntries ; ++k) {
996  int col = Indices[k];
997 
998  for (int kk = 0 ; kk < NumVectors ; ++kk) {
999  Xcopy[kk][LID] -= Values[k] * y2_ptr[kk][col];
1000  }
1001  }
1002  }
1003 
1004  // solve with this block
1005 
1006  if(rows != 1) {
1007  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
1008  LID = Containers_[i]->ID(j);
1009  for (int k = 0 ; k < NumVectors ; ++k) {
1010  Containers_[i]->RHS(j,k) = Xcopy[k][LID];
1011  }
1012  }
1013 
1014  IFPACK_CHK_ERR(Containers_[i]->ApplyInverse());
1015 #ifdef IFPACK_FLOPCOUNTERS
1016  ApplyInverseFlops_ += Containers_[i]->ApplyInverseFlops();
1017 #endif
1018 
1019  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
1020  LID = Containers_[i]->ID(j);
1021  for (int k = 0 ; k < NumVectors ; ++k) {
1022  y2_ptr[k][LID] += DampingFactor_ * Containers_[i]->LHS(j,k);
1023  }
1024  }
1025  }
1026  else {
1027  int LRID = (*Partitioner_)(i,0);
1028  double b = Xcopy[0][LRID];
1029  double a = Diagonal_[LRID];
1030  y2_ptr[0][LRID]+= DampingFactor_* b/a;
1031  }
1032  }
1033 
1034 #ifdef IFPACK_FLOPCOUNTERS
1035  // operations for all getrow()'s
1036  ApplyInverseFlops_ += NumVectors * 2 * Matrix_->NumGlobalNonzeros();
1037  ApplyInverseFlops_ += NumVectors * 2 * Matrix_->NumGlobalRows();
1038 #endif
1039 
1040  Xcopy = X;
1041 
1042  for (int i = NumLocalBlocks() - 1; i >=0 ; --i) {
1043  int rows = Partitioner_->NumRowsInPart(i);
1044  if (rows != 1 &&Containers_[i]->NumRows() == 0)
1045  continue;
1046 
1047  int LID;
1048 
1049  // update from previous block
1050 
1051  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
1052  LID = (*Partitioner_)(i,j);
1053 
1054  int NumEntries;
1055  IFPACK_CHK_ERR(Matrix().ExtractMyRowCopy(LID, Length,NumEntries,
1056  &Values[0], &Indices[0]));
1057 
1058  for (int k = 0 ; k < NumEntries ; ++k) {
1059  int col = Indices[k];
1060 
1061  for (int kk = 0 ; kk < NumVectors ; ++kk) {
1062  Xcopy[kk][LID] -= Values[k] * y2_ptr[kk][col];
1063  }
1064  }
1065  }
1066 
1067  // solve with this block
1068  if(rows != 1) {
1069  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
1070  LID = Containers_[i]->ID(j);
1071  for (int k = 0 ; k < NumVectors ; ++k) {
1072  Containers_[i]->RHS(j,k) = Xcopy[k][LID];
1073  }
1074  }
1075 
1076  IFPACK_CHK_ERR(Containers_[i]->ApplyInverse());
1077 #ifdef IFPACK_FLOPCOUNTERS
1078  ApplyInverseFlops_ += Containers_[i]->ApplyInverseFlops();
1079 #endif
1080 
1081  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
1082  LID = Containers_[i]->ID(j);
1083  for (int k = 0 ; k < NumVectors ; ++k) {
1084  y2_ptr[k][LID] += DampingFactor_ * Containers_[i]->LHS(j,k);
1085  }
1086  }
1087  }
1088  else {
1089  int LRID = (*Partitioner_)(i,0);
1090  double b = Xcopy[0][LRID];
1091  double a = Diagonal_[LRID];
1092  y2_ptr[0][LRID]+= DampingFactor_* b/a;
1093  }
1094  }
1095 
1096 #ifdef IFPACK_FLOPCOUNTERS
1097  // operations for all getrow()'s
1098  ApplyInverseFlops_ += NumVectors * 2 * Matrix_->NumGlobalNonzeros();
1099  ApplyInverseFlops_ += NumVectors * 2 * Matrix_->NumGlobalRows();
1100 #endif
1101 
1102  // Attention: this is delicate... Not all combinations
1103  // of Y2 and Y will always work (tough for ML it should be ok)
1104  if (IsParallel_)
1105  for (int m = 0 ; m < NumVectors ; ++m)
1106  for (int i = 0 ; i < NumMyRows ; ++i)
1107  y_ptr[m][i] = y2_ptr[m][i];
1108 
1109  return(0);
1110 }
1111 
1112 //==============================================================================
1113 template<typename T>
1114 std::ostream& Ifpack_BlockRelaxation<T>::Print(std::ostream & os) const
1115 {
1116  using std::endl;
1117 
1118  std::string PT;
1119  if (PrecType_ == IFPACK_JACOBI)
1120  PT = "Jacobi";
1121  else if (PrecType_ == IFPACK_GS)
1122  PT = "Gauss-Seidel";
1123  else if (PrecType_ == IFPACK_SGS)
1124  PT = "symmetric Gauss-Seidel";
1125 
1126  if (!Comm().MyPID()) {
1127  os << endl;
1128  os << "================================================================================" << endl;
1129  os << "Ifpack_BlockRelaxation, " << PT << endl;
1130  os << "Sweeps = " << NumSweeps_ << endl;
1131  os << "Damping factor = " << DampingFactor_;
1132  if (ZeroStartingSolution_)
1133  os << ", using zero starting solution" << endl;
1134  else
1135  os << ", using input starting solution" << endl;
1136  os << "Number of local blocks = " << Partitioner_->NumLocalParts() << endl;
1137  //os << "Condition number estimate = " << Condest_ << endl;
1138  os << "Global number of rows = " << Matrix_->NumGlobalRows64() << endl;
1139  os << endl;
1140  os << "Phase # calls Total Time (s) Total MFlops MFlops/s" << endl;
1141  os << "----- ------- -------------- ------------ --------" << endl;
1142  os << "Initialize() " << std::setw(5) << NumInitialize()
1143  << " " << std::setw(15) << InitializeTime()
1144  << " " << std::setw(15) << 1.0e-6 * InitializeFlops();
1145  if (InitializeTime() != 0.0)
1146  os << " " << std::setw(15) << 1.0e-6 * InitializeFlops() / InitializeTime() << endl;
1147  else
1148  os << " " << std::setw(15) << 0.0 << endl;
1149  os << "Compute() " << std::setw(5) << NumCompute()
1150  << " " << std::setw(15) << ComputeTime()
1151  << " " << std::setw(15) << 1.0e-6 * ComputeFlops();
1152  if (ComputeTime() != 0.0)
1153  os << " " << std::setw(15) << 1.0e-6 * ComputeFlops() / ComputeTime() << endl;
1154  else
1155  os << " " << std::setw(15) << 0.0 << endl;
1156  os << "ApplyInverse() " << std::setw(5) << NumApplyInverse()
1157  << " " << std::setw(15) << ApplyInverseTime()
1158  << " " << std::setw(15) << 1.0e-6 * ApplyInverseFlops();
1159  if (ApplyInverseTime() != 0.0)
1160  os << " " << std::setw(15) << 1.0e-6 * ApplyInverseFlops() / ApplyInverseTime() << endl;
1161  else
1162  os << " " << std::setw(15) << 0.0 << endl;
1163  os << "================================================================================" << endl;
1164  os << endl;
1165  }
1166 
1167  return(os);
1168 }
1169 
1170 //==============================================================================
1171 template<typename T>
1172 int Ifpack_BlockRelaxation<T>::SetParameters(Teuchos::ParameterList& List)
1173 {
1174  using std::cerr;
1175  using std::endl;
1176 
1177  std::string PT;
1178  if (PrecType_ == IFPACK_JACOBI)
1179  PT = "Jacobi";
1180  else if (PrecType_ == IFPACK_GS)
1181  PT = "Gauss-Seidel";
1182  else if (PrecType_ == IFPACK_SGS)
1183  PT = "symmetric Gauss-Seidel";
1184 
1185  PT = List.get("relaxation: type", PT);
1186 
1187  if (PT == "Jacobi") {
1188  PrecType_ = IFPACK_JACOBI;
1189  }
1190  else if (PT == "Gauss-Seidel") {
1191  PrecType_ = IFPACK_GS;
1192  }
1193  else if (PT == "symmetric Gauss-Seidel") {
1194  PrecType_ = IFPACK_SGS;
1195  } else {
1196  cerr << "Option `relaxation: type' has an incorrect value ("
1197  << PT << ")'" << endl;
1198  cerr << "(file " << __FILE__ << ", line " << __LINE__ << ")" << endl;
1199  exit(EXIT_FAILURE);
1200  }
1201 
1202  NumSweeps_ = List.get("relaxation: sweeps", NumSweeps_);
1203  DampingFactor_ = List.get("relaxation: damping factor",
1204  DampingFactor_);
1205  ZeroStartingSolution_ = List.get("relaxation: zero starting solution",
1206  ZeroStartingSolution_);
1207  PartitionerType_ = List.get("partitioner: type",
1208  PartitionerType_);
1209  NumLocalBlocks_ = List.get("partitioner: local parts",
1210  NumLocalBlocks_);
1211  // only Jacobi can work with overlap among local domains,
1212  OverlapLevel_ = List.get("partitioner: overlap",
1213  OverlapLevel_);
1214 
1215  // check parameters
1216  if (PrecType_ != IFPACK_JACOBI)
1217  OverlapLevel_ = 0;
1218  if (NumLocalBlocks_ < 0)
1219  NumLocalBlocks_ = Matrix().NumMyRows() / (-NumLocalBlocks_);
1220  // other checks are performed in Partitioner_
1221 
1222  // copy the list as each subblock's constructor will
1223  // require it later
1224  List_ = List;
1225 
1226  // set the label
1227  std::string PT2;
1228  if (PrecType_ == IFPACK_JACOBI)
1229  PT2 = "BJ";
1230  else if (PrecType_ == IFPACK_GS)
1231  PT2 = "BGS";
1232  else if (PrecType_ == IFPACK_SGS)
1233  PT2 = "BSGS";
1234  Label_ = "IFPACK (" + PT2 + ", sweeps="
1235  + Ifpack_toString(NumSweeps_) + ", damping="
1236  + Ifpack_toString(DampingFactor_) + ", blocks="
1237  + Ifpack_toString(NumLocalBlocks()) + ")";
1238 
1239  return(0);
1240 }
1241 
1242 //==============================================================================
1243 template<typename T>
1245 {
1246  IsInitialized_ = false;
1247  Time_.ResetStartTime();
1248 
1249  Graph_ = Teuchos::rcp( new Ifpack_Graph_Epetra_RowMatrix(Teuchos::rcp(&Matrix(),false)) );
1250  if (Graph_ == Teuchos::null) IFPACK_CHK_ERR(-5);
1251 
1252  if (PartitionerType_ == "linear")
1253  Partitioner_ = Teuchos::rcp( new Ifpack_LinearPartitioner(&*Graph_) );
1254  else if (PartitionerType_ == "greedy")
1255  Partitioner_ = Teuchos::rcp( new Ifpack_GreedyPartitioner(&*Graph_) );
1256  else if (PartitionerType_ == "metis")
1257  Partitioner_ = Teuchos::rcp( new Ifpack_METISPartitioner(&*Graph_) );
1258  else if (PartitionerType_ == "equation")
1259  Partitioner_ = Teuchos::rcp( new Ifpack_EquationPartitioner(&*Graph_) );
1260  else if (PartitionerType_ == "user")
1261  Partitioner_ = Teuchos::rcp( new Ifpack_UserPartitioner(&*Graph_) );
1262  else if (PartitionerType_ == "line")
1263  Partitioner_ = Teuchos::rcp( new Ifpack_LinePartitioner(&Matrix()) );
1264  else
1265  IFPACK_CHK_ERR(-2);
1266 
1267  if (Partitioner_ == Teuchos::null) IFPACK_CHK_ERR(-5);
1268 
1269  // need to partition the graph of A
1270  IFPACK_CHK_ERR(Partitioner_->SetParameters(List_));
1271  IFPACK_CHK_ERR(Partitioner_->Compute());
1272 
1273  // get actual number of partitions
1274  NumLocalBlocks_ = Partitioner_->NumLocalParts();
1275 
1276  // weight of each vertex
1277  W_ = Teuchos::rcp( new Epetra_Vector(Matrix().RowMatrixRowMap()) );
1278  W_->PutScalar(0.0);
1279 
1280  for (int i = 0 ; i < NumLocalBlocks() ; ++i) {
1281 
1282  for (int j = 0 ; j < Partitioner_->NumRowsInPart(i) ; ++j) {
1283  int LID = (*Partitioner_)(i,j);
1284  (*W_)[LID]++;
1285  }
1286  }
1287  W_->Reciprocal(*W_);
1288 
1289  // Update Label_ if line smoothing
1290  if (PartitionerType_ == "line") {
1291  // set the label
1292  std::string PT2;
1293  if (PrecType_ == IFPACK_JACOBI)
1294  PT2 = "BJ";
1295  else if (PrecType_ == IFPACK_GS)
1296  PT2 = "BGS";
1297  else if (PrecType_ == IFPACK_SGS)
1298  PT2 = "BSGS";
1299  Label_ = "IFPACK (" + PT2 + ", auto-line, sweeps="
1300  + Ifpack_toString(NumSweeps_) + ", damping="
1301  + Ifpack_toString(DampingFactor_) + ", blocks="
1302  + Ifpack_toString(NumLocalBlocks()) + ")";
1303  }
1304 
1305  InitializeTime_ += Time_.ElapsedTime();
1306  IsInitialized_ = true;
1307  ++NumInitialize_;
1308 
1309  return(0);
1310 }
1311 
1312 //==============================================================================
1313 #endif // IFPACK_BLOCKPRECONDITIONER_H
virtual const Epetra_Comm & Comm() const
Returns a pointer to the Epetra_Comm communicator associated with this operator.
Ifpack_BlockRelaxation: a class to define block relaxation preconditioners of Epetra_RowMatrix&#39;s.
Ifpack_UserPartitioner: A class to define linear partitions.
virtual const Epetra_Map & OperatorDomainMap() const
Returns the Epetra_Map object associated with the domain of this operator.
virtual double ApplyInverseFlops() const
Returns the number of flops in the application of the preconditioner.
virtual bool UseTranspose() const
Returns the current UseTranspose setting.
virtual int NumInitialize() const
Returns the number of calls to Initialize().
virtual double ApplyInverseTime() const
Returns the time spent in ApplyInverse().
virtual int ApplyInverse(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const
Applies the block Jacobi preconditioner to X, returns the result in Y.
int NumLocalBlocks() const
Returns the number local blocks.
virtual bool IsComputed() const
Returns true if the preconditioner has been successfully computed.
virtual double ComputeTime() const
Returns the time spent in Compute().
virtual bool HasNormInf() const
Returns true if the this object can provide an approximate Inf-norm, false otherwise.
virtual bool IsInitialized() const
Returns true if the preconditioner has been successfully computed.
Ifpack_EquationPartitioner: A class to decompose an Ifpack_Graph so that each block will contain all ...
virtual double ComputeFlops() const
Returns the number of flops in the computation phase.
virtual const Epetra_RowMatrix & Matrix() const
Returns a pointer to the matrix to be preconditioned.
virtual int Apply(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const
Applies the matrix to an Epetra_MultiVector.
virtual int Apply(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const =0
virtual int MaxNumEntries() const =0
virtual const Epetra_Comm & Comm() const =0
virtual int Compute()
Computes the preconditioner.
Ifpack_METISPartitioner: A class to decompose Ifpack_Graph&#39;s using METIS.
Ifpack_Preconditioner: basic class for preconditioning in Ifpack.
Ifpack_BlockRelaxation(const Epetra_RowMatrix *Matrix)
Ifpack_BlockRelaxation constructor with given Epetra_RowMatrix.
virtual int SetParameters(Teuchos::ParameterList &List)
Sets all the parameters for the preconditioner.
virtual int NumMyRows() const =0
Ifpack_Graph_Epetra_RowMatrix: a class to define Ifpack_Graph as a light-weight conversion of Epetra_...
std::ostream & Print(std::ostream &os) const
Prints basic information on iostream. This function is used by operator&lt;&lt;.
virtual int NumCompute() const
Returns the number of calls to Compute().
virtual const Epetra_Map & OperatorRangeMap() const
Returns the Epetra_Map object associated with the range of this operator.
virtual double InitializeTime() const
Returns the time spent in Initialize().
virtual int NumProc() const =0
virtual double Condest() const
Returns the computed condition number estimate, or -1.0 if not computed.
virtual int Initialize()
Initializes the preconditioner.
Ifpack_LinearPartitioner: A class to define linear partitions.
virtual double InitializeFlops() const
Returns the number of flops in the initialization phase.
virtual int NumApplyInverse() const
Returns the number of calls to ApplyInverse().
virtual double Condest(const Ifpack_CondestType=Ifpack_Cheap, const int=1550, const double=1e-9, Epetra_RowMatrix *=0)
Computes the condition number estimate, returns its value.
virtual double NormInf() const
Returns the infinity norm of the global matrix (not implemented)
std::string Ifpack_toString(const int &x)
Converts an integer to std::string.
Ifpack_GreedyPartitioner: A class to decompose Ifpack_Graph&#39;s using a simple greedy algorithm...