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) //PETSc 3.x.x
287 #if (PETSC_VERSION_MINOR >= 5) //PETSc 3.5 or later
302 std::cout << std::endl <<
"KSP iterations report:" << std::endl;
303 std::cout <<
"mNumSolves" <<
"\t" <<
"mTotalNumIterations" <<
"\t" <<
"mMaxNumIterations" <<
"\t" <<
"mAveNumIterations" << std::endl;
304 std::cout <<
mNumSolves <<
"\t" << mTotalNumIterations <<
"\t" << mMaxNumIterations <<
"\t" << ave_num_iterations << std::endl;
415 return (
unsigned)
mSize;
422 for (
unsigned vec_index=0; vec_index<numberOfBases; vec_index++)
425 VecNorm(nullBasis[vec_index], NORM_2, &l2_norm);
426 if (fabs(l2_norm-1.0) > 1e-08)
428 EXCEPTION(
"One of the vectors in the null space is not normalised");
433 for (
unsigned vec_index=1; vec_index<numberOfBases; vec_index++)
436 unsigned num_vectors_ahead = numberOfBases-vec_index;
437 boost::scoped_array<PetscScalar> dot_products(
new PetscScalar[num_vectors_ahead]);
438 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
439 VecMDot(num_vectors_ahead, nullBasis[vec_index-1], &nullBasis[vec_index], dot_products.get());
441 VecMDot(nullBasis[vec_index-1], num_vectors_ahead, &nullBasis[vec_index], dot_products.get());
443 for (
unsigned index=0; index<num_vectors_ahead; index++)
445 if (fabs(dot_products[index]) > 1e-08 )
447 EXCEPTION(
"The null space is not orthogonal.");
454 PETSCEXCEPT( MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_FALSE, numberOfBases, nullBasis, &
mMatNullSpace) );
463 PETSCEXCEPT( MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_FALSE, 0,
nullptr, &
mMatNullSpace) );
464 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 3) //PETSc 3.3 or later
504 KSPGetIterationNumber(this->
mKspSolver, &num_its);
506 return (
unsigned) num_its;
533 EXCEPTION(
"LHS matrix used for preconditioner construction");
556 #if (PETSC_VERSION_MAJOR == 3) //PETSc 3.x.x
557 MatSetOption(
mLhsMatrix, MAT_SYMMETRIC, PETSC_FALSE);
558 MatSetOption(
mLhsMatrix, MAT_STRUCTURALLY_SYMMETRIC, PETSC_FALSE);
559 MatSetOption(
mLhsMatrix, MAT_SYMMETRY_ETERNAL, PETSC_FALSE);
562 MatSetOption(
mLhsMatrix, MAT_NOT_STRUCTURALLY_SYMMETRIC);
563 MatSetOption(
mLhsMatrix, MAT_NOT_SYMMETRY_ETERNAL);
570 PetscBool symmetry_flag_is_set;
571 PetscBool symmetry_flag;
573 MatIsSymmetricKnown(
mLhsMatrix, &symmetry_flag_is_set, &symmetry_flag);
576 return symmetry_flag_is_set && symmetry_flag;
621 if (
mPcType ==
"blockdiagonal")
634 else if (
mPcType ==
"ldufactorisation")
647 else if (
mPcType ==
"twolevelsblockdiagonal")
660 TERMINATE(
"You must provide a list of bath nodes when using TwoLevelsBlockDiagonalPC");
668 PCSetType(prec, pcType);
684 MatGetInfo(
mLhsMatrix, MAT_GLOBAL_SUM, &mat_info);
689 Vec chebyshev_lhs_vector =
nullptr;
700 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 3) //PETSc 3.3 or later
709 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 5) //PETSc 3.5 or later
717 MatStructure preconditioner_over_successive_calls;
721 preconditioner_over_successive_calls = SAME_PRECONDITIONER;
725 preconditioner_over_successive_calls = SAME_NONZERO_PATTERN;
731 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 5) //PETSc 3.5 or later
739 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 5) //PETSc 3.5 or later
745 #if (PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR >= 5) //PETSc 3.5 or later
749 KSPSetReusePreconditioner(
mKspSolver, PETSC_TRUE);
765 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 3) //PETSc 3.3 or later
780 const bool is_small = (
mSize <= 6);
783 PCSetType(prec, PCNONE);
790 if (
mPcType ==
"blockdiagonal")
800 else if (
mPcType ==
"ldufactorisation")
810 else if (
mPcType ==
"twolevelsblockdiagonal")
814 TERMINATE(
"You must provide a list of bath nodes when using TwoLevelsBlockDiagonalPC");
827 PCSetType(prec,
mPcType.c_str());
836 KSPSetInitialGuessNonzero(
mKspSolver,PETSC_TRUE);
849 KSPSetComputeEigenvalues(
mKspSolver, PETSC_TRUE);
852 VecDuplicate(
mRhsVector, &chebyshev_lhs_vector);
855 VecCopy(lhsGuess, chebyshev_lhs_vector);
861 PetscReal *r_eig =
new PetscReal[
mSize];
862 PetscReal *c_eig =
new PetscReal[
mSize];
864 KSPComputeEigenvalues(
mKspSolver,
mSize, r_eig, c_eig, &eigs_computed);
869 KSPSetTolerances(
mKspSolver, DBL_EPSILON, DBL_EPSILON, PETSC_DEFAULT, PETSC_DEFAULT);
873 VecCopy(lhsGuess, chebyshev_lhs_vector);
877 KSPComputeEigenvalues(
mKspSolver,
mSize, r_eig, c_eig, &eigs_computed);
879 mEigMax = r_eig[eigs_computed-1];
889 std::cout <<
"EIGS: ";
890 for (
int index=0; index<eigs_computed; index++)
892 std::cout << r_eig[index] <<
", ";
894 std::cout << std::endl;
899 double sigma_one = 1 - alpha*
mEigMin;
900 if (
PetscTools::AmMaster()) std::cout <<
"sigma_1 = 1 - alpha*mEigMin = "<< sigma_one <<std::endl;
905 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 3) //PETSc 3.3 or later
912 KSPSetComputeEigenvalues(
mKspSolver, PETSC_FALSE);
939 if (chebyshev_lhs_vector)
947 Timer::Print(
"KSPSetUP (contains preconditioner creation for PETSc preconditioners)");
959 WARNING(
"LinearSystem doesn't like the non-zero pattern of a matrix to change. (I think you changed it).");
977 VecCopy(lhsGuess, lhs_vector);
987 double rhs_zero_tol = 1e-15;
989 if (rhs_norm < rhs_zero_tol && rhs_norm > 0.0)
991 WARNING(
"Using zero initial guess due to small right hand side vector");
1047 #if ((PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR <= 2))
1048 KSPSetNormType(
mKspSolver, KSP_PRECONDITIONED_NORM);
1050 KSPSetNormType(
mKspSolver, KSP_NORM_PRECONDITIONED);
1053 #if (PETSC_VERSION_MAJOR == 3) //PETSc 3.x.x
1056 #if (PETSC_VERSION_MINOR >= 5) //PETSc 3.5 or later
1062 #if (PETSC_VERSION_MINOR >= 5) //PETSc 3.5 or later
1070 KSPSetConvergenceTest(
mKspSolver, KSPDefaultConverged, PETSC_NULL);
1083 std::stringstream num_it_str;
1092 KSPSetComputeEigenvalues(
mKspSolver, PETSC_TRUE);
1107 std::cout <<
"++ Solve: " <<
mNumSolves <<
" NumIterations: " << num_it <<
" ";
1111 mTotalNumIterations += num_it;
1112 if ((
unsigned) num_it > mMaxNumIterations)
1114 mMaxNumIterations = num_it;
1119 KSPConvergedReason reason;
1124 WARNING(
"Not explicitly checking convergence reason when using fixed number of iterations and PETSc 2");
1136 PetscReal *r_eig =
new PetscReal[
mSize];
1137 PetscReal *c_eig =
new PetscReal[
mSize];
1139 KSPComputeEigenvalues(
mKspSolver,
mSize, r_eig, c_eig, &eigs_computed);
1153 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 3) //PETSc 3.3 or later
1160 KSPSetComputeEigenvalues(
mKspSolver, PETSC_FALSE);
1163 #if ((PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR <= 2))
1167 EXCEPTION(
"Chebyshev with fixed number of iterations is known to be broken in PETSc <= 2.3.2");
1171 #elif (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 2) //PETSc 3.2 or later
1173 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 7) //PETSc 3.7 or later
1182 KSPSetConvergenceTest(
mKspSolver, KSPConvergedSkip, PETSC_NULL, PETSC_NULL);
1188 #if (PETSC_VERSION_MAJOR == 2)
1189 KSPSetConvergenceTest(
mKspSolver, KSPSkipConverged, PETSC_NULL);
1194 std::stringstream num_it_str;
1195 num_it_str << num_it;
1265 std::stringstream num_it_str;
void AssembleFinalLinearSystem()
Mat & rGetPrecondMatrix()
void FinalisePrecondMatrix()
unsigned mRowPreallocation
void AddToRhsVectorElement(PetscInt row, double value)
void GetOwnershipRange(PetscInt &lo, PetscInt &hi)
bool mUseAbsoluteTolerance
void * mpConvergenceTestContext
void SetKspType(const char *kspType)
Vec Solve(Vec lhsGuess=nullptr)
void ZeroMatrixRowsWithValueOnDiagonal(std::vector< unsigned > &rRows, double diagonalValue)
unsigned mEvaluateNumItsEveryNSolves
#define EXCEPTION(message)
void SetRelativeTolerance(double relativeTolerance)
static void BeginEvent(unsigned event)
void SetMatrixElement(PetscInt row, PetscInt col, double value)
void AddToMatrixElement(PetscInt row, PetscInt col, double value)
Vec mDirichletBoundaryConditionsVector
Vec & rGetDirichletBoundaryConditionsVector()
PCTwoLevelsBlockDiagonal * mpTwoLevelsBlockDiagonalPC
#define TERMINATE(message)
void ZeroMatrixRowsAndColumnsWithValueOnDiagonal(std::vector< unsigned > &rRowColIndices, double diagonalValue)
double GetRhsVectorElement(PetscInt row)
boost::shared_ptr< std::vector< PetscInt > > mpBathNodes
double GetMatrixElement(PetscInt row, PetscInt col)
void ZeroMatrixColumn(PetscInt col)
void SetPrecondMatrixIsDifferentFromLhs(bool precondIsDifferent=true)
PetscInt mOwnershipRangeHi
static void Print(std::string message)
void SetMatrixIsSymmetric(bool isSymmetric=true)
LinearSystem(PetscInt lhsVectorSize, unsigned rowPreallocation=UINT_MAX)
PCBlockDiagonal * mpBlockDiagonalPC
void SetNullBasis(Vec nullbasis[], unsigned numberOfBases)
MatNullSpace mMatNullSpace
PCLDUFactorisation * mpLDUFactorisationPC
void SetPcType(const char *pcType, boost::shared_ptr< std::vector< PetscInt > > pBathNodes=boost::shared_ptr< std::vector< PetscInt > >())
void SetAbsoluteTolerance(double absoluteTolerance)
bool mForceSpectrumReevaluation
void SetRhsVectorElement(PetscInt row, double value)
void AssembleIntermediateLinearSystem()
#define CHASTE_CLASS_EXPORT(T)
void SwitchWriteModeLhsMatrix()
unsigned GetNumIterations() const
static void EndEvent(unsigned event)
PetscInt mOwnershipRangeLo
void SetUseFixedNumberIterations(bool useFixedNumberIterations=true, unsigned evaluateNumItsEveryNSolves=UINT_MAX)
bool mPrecondMatrixIsNotLhs
void SetMatrixRow(PetscInt row, double value)
Vec GetMatrixRowDistributed(unsigned rowIndex)
void SetMatrixIsConstant(bool matrixIsConstant)
bool mUseFixedNumberIterations