IFPACK Development
Loading...
Searching...
No Matches
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
75static const int IFPACK_JACOBI = 0;
76static const int IFPACK_GS = 1;
77static const int IFPACK_SGS = 2;
78
79
81
144template<typename T>
146
147public:
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
362private:
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//==============================================================================
459template<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//==============================================================================
490template<typename T>
492{
493}
494
495//==============================================================================
496template<typename T>
497const char* Ifpack_BlockRelaxation<T>::Label() const
498{
499 return(Label_.c_str());
500}
501
502//==============================================================================
503template<typename T>
506{
507 int ierr = Matrix().Apply(X,Y);
508 IFPACK_RETURN(ierr);
509}
510
511//==============================================================================
512template<typename T>
514Comm() const
515{
516 return(Matrix().Comm());
517}
518
519//==============================================================================
520template<typename T>
522OperatorDomainMap() const
523{
524 return(Matrix().OperatorDomainMap());
525}
526
527//==============================================================================
528template<typename T>
530OperatorRangeMap() const
531{
532 return(Matrix().OperatorRangeMap());
533}
534
535//==============================================================================
536template<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//==============================================================================
586template<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//==============================================================================
618template<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//
660template<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//==============================================================================
691template<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//==============================================================================
799template<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//==============================================================================
820template<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//==============================================================================
928template<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//==============================================================================
946template<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//==============================================================================
1113template<typename T>
1114std::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//==============================================================================
1171template<typename T>
1172int 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//==============================================================================
1243template<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 int NumProc() const=0
int NumVectors() const
int ExtractView(double **A, int *MyLDA) const
double ** Pointers() const
int PutScalar(double ScalarConstant)
virtual int Apply(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const=0
virtual const Epetra_Comm & Comm() const=0
virtual int NumMyRows() const=0
virtual int MaxNumEntries() const=0
Ifpack_BlockRelaxation: a class to define block relaxation preconditioners of Epetra_RowMatrix's.
virtual int Apply(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const
Applies the matrix to an Epetra_MultiVector.
virtual bool HasNormInf() const
Returns true if the this object can provide an approximate Inf-norm, false otherwise.
Ifpack_BlockRelaxation(const Epetra_RowMatrix *Matrix)
Ifpack_BlockRelaxation constructor with given Epetra_RowMatrix.
virtual int NumCompute() const
Returns the number of calls to Compute().
virtual double InitializeFlops() const
Returns the number of flops in the initialization phase.
virtual const Epetra_RowMatrix & Matrix() const
Returns a pointer to the matrix to be preconditioned.
virtual int SetParameters(Teuchos::ParameterList &List)
Sets all the parameters for the preconditioner.
virtual bool UseTranspose() const
Returns the current UseTranspose setting.
virtual const Epetra_Map & OperatorDomainMap() const
Returns the Epetra_Map object associated with the domain of this operator.
virtual double ComputeFlops() const
Returns the number of flops in the computation phase.
virtual const Epetra_Comm & Comm() const
Returns a pointer to the Epetra_Comm communicator associated with this operator.
virtual double ComputeTime() const
Returns the time spent in Compute().
std::ostream & Print(std::ostream &os) const
Prints basic information on iostream. This function is used by operator<<.
virtual double ApplyInverseFlops() const
Returns the number of flops in the application of the preconditioner.
virtual double NormInf() const
Returns the infinity norm of the global matrix (not implemented)
virtual int Initialize()
Initializes the preconditioner.
virtual double Condest() const
Returns the computed condition number estimate, or -1.0 if not computed.
virtual int NumInitialize() const
Returns the number of calls to Initialize().
virtual int ApplyInverse(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const
Applies the block Jacobi preconditioner to X, returns the result in Y.
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.
int NumLocalBlocks() const
Returns the number local blocks.
virtual bool IsInitialized() const
Returns true if the preconditioner has been successfully computed.
virtual bool IsComputed() const
Returns true if the preconditioner has been successfully computed.
virtual int NumApplyInverse() const
Returns the number of calls to ApplyInverse().
virtual double InitializeTime() const
Returns the time spent in Initialize().
virtual double ApplyInverseTime() const
Returns the time spent in ApplyInverse().
virtual const Epetra_Map & OperatorRangeMap() const
Returns the Epetra_Map object associated with the range of this operator.
virtual int Compute()
Computes the preconditioner.
Ifpack_EquationPartitioner: A class to decompose an Ifpack_Graph so that each block will contain all ...
Ifpack_Graph_Epetra_RowMatrix: a class to define Ifpack_Graph as a light-weight conversion of Epetra_...
Ifpack_GreedyPartitioner: A class to decompose Ifpack_Graph's using a simple greedy algorithm.
Ifpack_LinearPartitioner: A class to define linear partitions.
Ifpack_METISPartitioner: A class to decompose Ifpack_Graph's using METIS.
Ifpack_Preconditioner: basic class for preconditioning in Ifpack.
Ifpack_UserPartitioner: A class to define linear partitions.