36#include "LinearSystem.hpp"
41#include <boost/scoped_array.hpp>
43#include "PetscException.hpp"
44#include "OutputFileHandler.hpp"
46#include "HeartEventHandler.hpp"
48#include "Warnings.hpp"
55 :mPrecondMatrix(nullptr),
57 mMatNullSpace(nullptr),
58 mDestroyMatAndVec(true),
61 mMatrixIsConstant(false),
63 mUseAbsoluteTolerance(false),
64 mDirichletBoundaryConditionsVector(nullptr),
65 mpBlockDiagonalPC(nullptr),
66 mpLDUFactorisationPC(nullptr),
67 mpTwoLevelsBlockDiagonalPC(nullptr),
68 mpBathNodes( boost::shared_ptr<std::vector<
PetscInt> >() ),
69 mPrecondMatrixIsNotLhs(false),
70 mRowPreallocation(rowPreallocation),
71 mUseFixedNumberIterations(false),
72 mEvaluateNumItsEveryNSolves(UINT_MAX),
73 mpConvergenceTestContext(nullptr),
76 mForceSpectrumReevaluation(false)
78 assert(lhsVectorSize > 0);
88 EXCEPTION(
"You must provide a rowPreallocation argument for a large sparse system");
104 mTotalNumIterations = 0;
105 mMaxNumIterations = 0;
110 :mPrecondMatrix(nullptr),
111 mSize(lhsVectorSize),
112 mMatNullSpace(nullptr),
113 mDestroyMatAndVec(true),
116 mMatrixIsConstant(false),
118 mUseAbsoluteTolerance(false),
119 mDirichletBoundaryConditionsVector(nullptr),
120 mpBlockDiagonalPC(nullptr),
121 mpLDUFactorisationPC(nullptr),
122 mpTwoLevelsBlockDiagonalPC(nullptr),
123 mpBathNodes( boost::shared_ptr<std::vector<
PetscInt> >() ),
124 mPrecondMatrixIsNotLhs(false),
125 mUseFixedNumberIterations(false),
126 mEvaluateNumItsEveryNSolves(UINT_MAX),
127 mpConvergenceTestContext(nullptr),
130 mForceSpectrumReevaluation(false)
132 assert(lhsVectorSize > 0);
141 mTotalNumIterations = 0;
142 mMaxNumIterations = 0;
147 :mPrecondMatrix(nullptr),
148 mMatNullSpace(nullptr),
149 mDestroyMatAndVec(true),
151 mMatrixIsConstant(false),
153 mUseAbsoluteTolerance(false),
154 mDirichletBoundaryConditionsVector(nullptr),
155 mpBlockDiagonalPC(nullptr),
156 mpLDUFactorisationPC(nullptr),
157 mpTwoLevelsBlockDiagonalPC(nullptr),
158 mpBathNodes( boost::shared_ptr<std::vector<
PetscInt> >() ),
159 mPrecondMatrixIsNotLhs(false),
160 mRowPreallocation(rowPreallocation),
161 mUseFixedNumberIterations(false),
162 mEvaluateNumItsEveryNSolves(UINT_MAX),
163 mpConvergenceTestContext(nullptr),
166 mForceSpectrumReevaluation(false)
182 mTotalNumIterations = 0;
183 mMaxNumIterations = 0;
188 :mPrecondMatrix(nullptr),
189 mMatNullSpace(nullptr),
190 mDestroyMatAndVec(false),
192 mMatrixIsConstant(false),
194 mUseAbsoluteTolerance(false),
195 mDirichletBoundaryConditionsVector(nullptr),
196 mpBlockDiagonalPC(nullptr),
197 mpLDUFactorisationPC(nullptr),
198 mpTwoLevelsBlockDiagonalPC(nullptr),
199 mpBathNodes( boost::shared_ptr<std::vector<
PetscInt> >() ),
200 mPrecondMatrixIsNotLhs(false),
201 mRowPreallocation(UINT_MAX),
202 mUseFixedNumberIterations(false),
203 mEvaluateNumItsEveryNSolves(UINT_MAX),
204 mpConvergenceTestContext(nullptr),
207 mForceSpectrumReevaluation(false)
209 assert(residualVector || jacobianMatrix);
224 assert(mat_size == mat_cols);
229 MatGetInfo(
mLhsMatrix, MAT_GLOBAL_MAX, &matrix_info);
246 mTotalNumIterations = 0;
247 mMaxNumIterations = 0;
284#if (PETSC_VERSION_MAJOR == 3)
287#if (PETSC_VERSION_MINOR >= 24)
289#elif (PETSC_VERSION_MINOR >= 5)
305 std::cout << std::endl <<
"KSP iterations report:" << std::endl;
306 std::cout <<
"mNumSolves" <<
"\t" <<
"mTotalNumIterations" <<
"\t" <<
"mMaxNumIterations" <<
"\t" <<
"mAveNumIterations" << std::endl;
307 std::cout <<
mNumSolves <<
"\t" << mTotalNumIterations <<
"\t" << mMaxNumIterations <<
"\t" << ave_num_iterations << std::endl;
418 return (
unsigned)
mSize;
425 for (
unsigned vec_index=0; vec_index<numberOfBases; vec_index++)
428 VecNorm(nullBasis[vec_index], NORM_2, &l2_norm);
429 if (fabs(l2_norm-1.0) > 1e-08)
431 EXCEPTION(
"One of the vectors in the null space is not normalised");
436 for (
unsigned vec_index=1; vec_index<numberOfBases; vec_index++)
439 unsigned num_vectors_ahead = numberOfBases-vec_index;
440 boost::scoped_array<PetscScalar> dot_products(
new PetscScalar[num_vectors_ahead]);
441#if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2)
442 VecMDot(num_vectors_ahead, nullBasis[vec_index-1], &nullBasis[vec_index], dot_products.get());
444 VecMDot(nullBasis[vec_index-1], num_vectors_ahead, &nullBasis[vec_index], dot_products.get());
446 for (
unsigned index=0; index<num_vectors_ahead; index++)
448 if (fabs(dot_products[index]) > 1e-08 )
450 EXCEPTION(
"The null space is not orthogonal.");
457 PETSCEXCEPT( MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_FALSE, numberOfBases, nullBasis, &
mMatNullSpace) );
466 PETSCEXCEPT( MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_FALSE, 0,
nullptr, &
mMatNullSpace) );
467#if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 3)
507 KSPGetIterationNumber(this->
mKspSolver, &num_its);
509 return (
unsigned) num_its;
536 EXCEPTION(
"LHS matrix used for preconditioner construction");
559#if (PETSC_VERSION_MAJOR == 3)
560 MatSetOption(
mLhsMatrix, MAT_SYMMETRIC, PETSC_FALSE);
561 MatSetOption(
mLhsMatrix, MAT_STRUCTURALLY_SYMMETRIC, PETSC_FALSE);
562 MatSetOption(
mLhsMatrix, MAT_SYMMETRY_ETERNAL, PETSC_FALSE);
565 MatSetOption(
mLhsMatrix, MAT_NOT_STRUCTURALLY_SYMMETRIC);
566 MatSetOption(
mLhsMatrix, MAT_NOT_SYMMETRY_ETERNAL);
573 PetscBool symmetry_flag_is_set;
574 PetscBool symmetry_flag;
576 MatIsSymmetricKnown(
mLhsMatrix, &symmetry_flag_is_set, &symmetry_flag);
579 return symmetry_flag_is_set && symmetry_flag;
624 if (
mPcType ==
"blockdiagonal")
637 else if (
mPcType ==
"ldufactorisation")
650 else if (
mPcType ==
"twolevelsblockdiagonal")
663 TERMINATE(
"You must provide a list of bath nodes when using TwoLevelsBlockDiagonalPC");
671 PCSetType(prec, pcType);
687 MatGetInfo(
mLhsMatrix, MAT_GLOBAL_SUM, &mat_info);
692 Vec chebyshev_lhs_vector =
nullptr;
703#if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 3)
712#if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 5)
720 MatStructure preconditioner_over_successive_calls;
724 preconditioner_over_successive_calls = SAME_PRECONDITIONER;
728 preconditioner_over_successive_calls = SAME_NONZERO_PATTERN;
734#if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 5)
742#if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 5)
748#if (PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR >= 5)
752 KSPSetReusePreconditioner(
mKspSolver, PETSC_TRUE);
768#if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 3)
783 const bool is_small = (
mSize <= 6);
786 PCSetType(prec, PCNONE);
793 if (
mPcType ==
"blockdiagonal")
803 else if (
mPcType ==
"ldufactorisation")
813 else if (
mPcType ==
"twolevelsblockdiagonal")
817 TERMINATE(
"You must provide a list of bath nodes when using TwoLevelsBlockDiagonalPC");
830 PCSetType(prec,
mPcType.c_str());
839 KSPSetInitialGuessNonzero(
mKspSolver,PETSC_TRUE);
852 KSPSetComputeEigenvalues(
mKspSolver, PETSC_TRUE);
855 VecDuplicate(
mRhsVector, &chebyshev_lhs_vector);
858 VecCopy(lhsGuess, chebyshev_lhs_vector);
864 PetscReal *r_eig =
new PetscReal[
mSize];
865 PetscReal *c_eig =
new PetscReal[
mSize];
867 KSPComputeEigenvalues(
mKspSolver,
mSize, r_eig, c_eig, &eigs_computed);
872 KSPSetTolerances(
mKspSolver, DBL_EPSILON, DBL_EPSILON, PETSC_DEFAULT, PETSC_DEFAULT);
876 VecCopy(lhsGuess, chebyshev_lhs_vector);
880 KSPComputeEigenvalues(
mKspSolver,
mSize, r_eig, c_eig, &eigs_computed);
882 mEigMax = r_eig[eigs_computed-1];
892 std::cout <<
"EIGS: ";
893 for (
int index=0; index<eigs_computed; index++)
895 std::cout << r_eig[index] <<
", ";
897 std::cout << std::endl;
902 double sigma_one = 1 - alpha*
mEigMin;
903 if (
PetscTools::AmMaster()) std::cout <<
"sigma_1 = 1 - alpha*mEigMin = "<< sigma_one <<std::endl;
908#if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 3)
915 KSPSetComputeEigenvalues(
mKspSolver, PETSC_FALSE);
942 if (chebyshev_lhs_vector)
950 Timer::Print(
"KSPSetUP (contains preconditioner creation for PETSc preconditioners)");
962 WARNING(
"LinearSystem doesn't like the non-zero pattern of a matrix to change. (I think you changed it).");
980 VecCopy(lhsGuess, lhs_vector);
990 double rhs_zero_tol = 1e-15;
992 if (rhs_norm < rhs_zero_tol && rhs_norm > 0.0)
994 WARNING(
"Using zero initial guess due to small right hand side vector");
1050#if ((PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR <= 2))
1051 KSPSetNormType(
mKspSolver, KSP_PRECONDITIONED_NORM);
1053 KSPSetNormType(
mKspSolver, KSP_NORM_PRECONDITIONED);
1056#if (PETSC_VERSION_MAJOR == 3)
1059 #if (PETSC_VERSION_MINOR >= 5)
1065 #if (PETSC_VERSION_MINOR >= 5)
1086 std::stringstream num_it_str;
1095 KSPSetComputeEigenvalues(
mKspSolver, PETSC_TRUE);
1110 std::cout <<
"++ Solve: " <<
mNumSolves <<
" NumIterations: " << num_it <<
" ";
1114 mTotalNumIterations += num_it;
1115 if ((
unsigned) num_it > mMaxNumIterations)
1117 mMaxNumIterations = num_it;
1122 KSPConvergedReason reason;
1127 WARNING(
"Not explicitly checking convergence reason when using fixed number of iterations and PETSc 2");
1139 PetscReal *r_eig =
new PetscReal[
mSize];
1140 PetscReal *c_eig =
new PetscReal[
mSize];
1142 KSPComputeEigenvalues(
mKspSolver,
mSize, r_eig, c_eig, &eigs_computed);
1156#if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 3)
1163 KSPSetComputeEigenvalues(
mKspSolver, PETSC_FALSE);
1166#if ((PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR <= 2))
1170 EXCEPTION(
"Chebyshev with fixed number of iterations is known to be broken in PETSc <= 2.3.2");
1174#elif (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 2)
1176 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 7)
1191#if (PETSC_VERSION_MAJOR == 2)
1197 std::stringstream num_it_str;
1198 num_it_str << num_it;
1268 std::stringstream num_it_str;
#define TERMINATE(message)
#define EXCEPTION(message)
#define CHASTE_CLASS_EXPORT(T)
static void BeginEvent(unsigned event)
static void EndEvent(unsigned event)
Vec & rGetDirichletBoundaryConditionsVector()
void SetNullBasis(Vec nullbasis[], unsigned numberOfBases)
void SetPrecondMatrixIsDifferentFromLhs(bool precondIsDifferent=true)
boost::shared_ptr< std::vector< PetscInt > > mpBathNodes
Vec Solve(Vec lhsGuess=nullptr)
Vec mDirichletBoundaryConditionsVector
void SetMatrixIsSymmetric(bool isSymmetric=true)
void AssembleFinalLinearSystem()
bool mUseAbsoluteTolerance
void ZeroMatrixColumn(PetscInt col)
bool mForceSpectrumReevaluation
void SetMatrixIsConstant(bool matrixIsConstant)
unsigned mRowPreallocation
void FinalisePrecondMatrix()
void GetOwnershipRange(PetscInt &lo, PetscInt &hi)
PCLDUFactorisation * mpLDUFactorisationPC
void SwitchWriteModeLhsMatrix()
void AddToMatrixElement(PetscInt row, PetscInt col, double value)
double GetMatrixElement(PetscInt row, PetscInt col)
PetscInt mOwnershipRangeLo
void SetKspType(const char *kspType)
void SetMatrixElement(PetscInt row, PetscInt col, double value)
unsigned GetNumIterations() const
PetscInt mOwnershipRangeHi
void SetUseFixedNumberIterations(bool useFixedNumberIterations=true, unsigned evaluateNumItsEveryNSolves=UINT_MAX)
MatNullSpace mMatNullSpace
void ZeroMatrixRowsWithValueOnDiagonal(std::vector< unsigned > &rRows, double diagonalValue)
void ZeroMatrixRowsAndColumnsWithValueOnDiagonal(std::vector< unsigned > &rRowColIndices, double diagonalValue)
void SetAbsoluteTolerance(double absoluteTolerance)
void AssembleIntermediateLinearSystem()
void SetRhsVectorElement(PetscInt row, double value)
void SetMatrixRow(PetscInt row, double value)
void * mpConvergenceTestContext
PCTwoLevelsBlockDiagonal * mpTwoLevelsBlockDiagonalPC
Mat & rGetPrecondMatrix()
Vec GetMatrixRowDistributed(unsigned rowIndex)
PCBlockDiagonal * mpBlockDiagonalPC
void AddToRhsVectorElement(PetscInt row, double value)
unsigned mEvaluateNumItsEveryNSolves
bool mPrecondMatrixIsNotLhs
void SetRelativeTolerance(double relativeTolerance)
bool mUseFixedNumberIterations
double GetRhsVectorElement(PetscInt row)
void SetPcType(const char *pcType, boost::shared_ptr< std::vector< PetscInt > > pBathNodes=boost::shared_ptr< std::vector< PetscInt > >())
LinearSystem(PetscInt lhsVectorSize, unsigned rowPreallocation=UINT_MAX)
static void Print(std::string message)