00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "LinearSystem.hpp"
00030 #include "PetscException.hpp"
00031 #include <iostream>
00032 #include "OutputFileHandler.hpp"
00033 #include "PetscTools.hpp"
00034 #include <cassert>
00035 #include "HeartEventHandler.hpp"
00036 #include "Timer.hpp"
00037 #include "Warnings.hpp"
00038 #include <algorithm>
00039
00041
00043
00044 LinearSystem::LinearSystem(PetscInt lhsVectorSize, unsigned rowPreallocation)
00045 :mPrecondMatrix(NULL),
00046 mSize(lhsVectorSize),
00047 mMatNullSpace(NULL),
00048 mDestroyMatAndVec(true),
00049 mKspIsSetup(false),
00050 mNonZerosUsed(0.0),
00051 mMatrixIsConstant(false),
00052 mTolerance(1e-6),
00053 mUseAbsoluteTolerance(false),
00054 mDirichletBoundaryConditionsVector(NULL),
00055 mpBlockDiagonalPC(NULL),
00056 mpLDUFactorisationPC(NULL),
00057 mpTwoLevelsBlockDiagonalPC(NULL),
00058 mpBathNodes( boost::shared_ptr<std::vector<PetscInt> >() ),
00059 mPrecondMatrixIsNotLhs(false),
00060 mRowPreallocation(rowPreallocation),
00061 mUseFixedNumberIterations(false),
00062 mEvaluateNumItsEveryNSolves(UINT_MAX),
00063 mpConvergenceTestContext(NULL),
00064 mEigMin(DBL_MAX),
00065 mEigMax(DBL_MIN),
00066 mForceSpectrumReevaluation(false)
00067 {
00068 assert(lhsVectorSize > 0);
00069 if (mRowPreallocation == UINT_MAX)
00070 {
00071
00072 if (lhsVectorSize<15)
00073 {
00074 mRowPreallocation=lhsVectorSize;
00075 }
00076 else
00077 {
00078 EXCEPTION("You must provide a rowPreallocation argument for a large sparse system");
00079 }
00080 }
00081
00082 mRhsVector = PetscTools::CreateVec(mSize);
00083 PetscTools::SetupMat(mLhsMatrix, mSize, mSize, mRowPreallocation, PETSC_DECIDE, PETSC_DECIDE);
00084
00085 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00086
00089 mKspType = "gmres";
00090 mPcType = "jacobi";
00091
00092 mNumSolves = 0;
00093 #ifdef TRACE_KSP
00094 mTotalNumIterations = 0;
00095 mMaxNumIterations = 0;
00096 #endif
00097 }
00098
00099 LinearSystem::LinearSystem(PetscInt lhsVectorSize, Mat lhsMatrix, Vec rhsVector)
00100 :mPrecondMatrix(NULL),
00101 mSize(lhsVectorSize),
00102 mMatNullSpace(NULL),
00103 mDestroyMatAndVec(true),
00104 mKspIsSetup(false),
00105 mNonZerosUsed(0.0),
00106 mMatrixIsConstant(false),
00107 mTolerance(1e-6),
00108 mUseAbsoluteTolerance(false),
00109 mDirichletBoundaryConditionsVector(NULL),
00110 mpBlockDiagonalPC(NULL),
00111 mpLDUFactorisationPC(NULL),
00112 mpTwoLevelsBlockDiagonalPC(NULL),
00113 mpBathNodes( boost::shared_ptr<std::vector<PetscInt> >() ),
00114 mPrecondMatrixIsNotLhs(false),
00115 mUseFixedNumberIterations(false),
00116 mEvaluateNumItsEveryNSolves(UINT_MAX),
00117 mpConvergenceTestContext(NULL),
00118 mEigMin(DBL_MAX),
00119 mEigMax(DBL_MIN),
00120 mForceSpectrumReevaluation(false)
00121 {
00122 assert(lhsVectorSize > 0);
00123
00124 mLhsMatrix = lhsMatrix;
00125 mRhsVector = rhsVector;
00126
00127 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00128
00129 mNumSolves = 0;
00130 #ifdef TRACE_KSP
00131 mTotalNumIterations = 0;
00132 mMaxNumIterations = 0;
00133 #endif
00134 }
00135
00136 LinearSystem::LinearSystem(Vec templateVector, unsigned rowPreallocation)
00137 :mPrecondMatrix(NULL),
00138 mMatNullSpace(NULL),
00139 mDestroyMatAndVec(true),
00140 mKspIsSetup(false),
00141 mMatrixIsConstant(false),
00142 mTolerance(1e-6),
00143 mUseAbsoluteTolerance(false),
00144 mDirichletBoundaryConditionsVector(NULL),
00145 mpBlockDiagonalPC(NULL),
00146 mpLDUFactorisationPC(NULL),
00147 mpTwoLevelsBlockDiagonalPC(NULL),
00148 mpBathNodes( boost::shared_ptr<std::vector<PetscInt> >() ),
00149 mPrecondMatrixIsNotLhs(false),
00150 mRowPreallocation(rowPreallocation),
00151 mUseFixedNumberIterations(false),
00152 mEvaluateNumItsEveryNSolves(UINT_MAX),
00153 mpConvergenceTestContext(NULL),
00154 mEigMin(DBL_MAX),
00155 mEigMax(DBL_MIN),
00156 mForceSpectrumReevaluation(false)
00157 {
00158 VecDuplicate(templateVector, &mRhsVector);
00159 VecGetSize(mRhsVector, &mSize);
00160 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00161 PetscInt local_size = mOwnershipRangeHi - mOwnershipRangeLo;
00162
00163 PetscTools::SetupMat(mLhsMatrix, mSize, mSize, mRowPreallocation, local_size, local_size);
00164
00167 mKspType = "gmres";
00168 mPcType = "jacobi";
00169
00170 mNumSolves = 0;
00171 #ifdef TRACE_KSP
00172 mTotalNumIterations = 0;
00173 mMaxNumIterations = 0;
00174 #endif
00175 }
00176
00177 LinearSystem::LinearSystem(Vec residualVector, Mat jacobianMatrix)
00178 :mPrecondMatrix(NULL),
00179 mMatNullSpace(NULL),
00180 mDestroyMatAndVec(false),
00181 mKspIsSetup(false),
00182 mMatrixIsConstant(false),
00183 mTolerance(1e-6),
00184 mUseAbsoluteTolerance(false),
00185 mDirichletBoundaryConditionsVector(NULL),
00186 mpBlockDiagonalPC(NULL),
00187 mpLDUFactorisationPC(NULL),
00188 mpTwoLevelsBlockDiagonalPC(NULL),
00189 mpBathNodes( boost::shared_ptr<std::vector<PetscInt> >() ),
00190 mPrecondMatrixIsNotLhs(false),
00191 mRowPreallocation(UINT_MAX),
00192 mUseFixedNumberIterations(false),
00193 mEvaluateNumItsEveryNSolves(UINT_MAX),
00194 mpConvergenceTestContext(NULL),
00195 mEigMin(DBL_MAX),
00196 mEigMax(DBL_MIN),
00197 mForceSpectrumReevaluation(false)
00198 {
00199 assert(residualVector || jacobianMatrix);
00200 mRhsVector = residualVector;
00201 mLhsMatrix = jacobianMatrix;
00202
00203 PetscInt mat_size=0, vec_size=0;
00204 if (mRhsVector)
00205 {
00206 VecGetSize(mRhsVector, &vec_size);
00207 mSize = (unsigned)vec_size;
00208 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00209 }
00210 if (mLhsMatrix)
00211 {
00212 PetscInt mat_cols;
00213 MatGetSize(mLhsMatrix, &mat_size, &mat_cols);
00214 assert(mat_size == mat_cols);
00215 mSize = (unsigned)mat_size;
00216 MatGetOwnershipRange(mLhsMatrix, &mOwnershipRangeLo, &mOwnershipRangeHi);
00217
00218 MatInfo matrix_info;
00219 MatGetInfo(mLhsMatrix, MAT_GLOBAL_MAX, &matrix_info);
00220
00221
00222
00223
00224
00225 mRowPreallocation = (unsigned) matrix_info.nz_allocated / mSize;
00226 }
00227 assert(!mRhsVector || !mLhsMatrix || vec_size == mat_size);
00228
00231 mKspType = "gmres";
00232 mPcType = "jacobi";
00233
00234 mNumSolves = 0;
00235 #ifdef TRACE_KSP
00236 mTotalNumIterations = 0;
00237 mMaxNumIterations = 0;
00238 #endif
00239 }
00240
00241 LinearSystem::~LinearSystem()
00242 {
00243 delete mpBlockDiagonalPC;
00244 delete mpLDUFactorisationPC;
00245 delete mpTwoLevelsBlockDiagonalPC;
00246
00247 if (mDestroyMatAndVec)
00248 {
00249 VecDestroy(mRhsVector);
00250 MatDestroy(mLhsMatrix);
00251 }
00252
00253 if (mPrecondMatrixIsNotLhs)
00254 {
00255 MatDestroy(mPrecondMatrix);
00256 }
00257
00258 if (mMatNullSpace)
00259 {
00260 MatNullSpaceDestroy(mMatNullSpace);
00261 }
00262
00263 if (mKspIsSetup)
00264 {
00265 KSPDestroy(mKspSolver);
00266 }
00267
00268 if (mDirichletBoundaryConditionsVector)
00269 {
00271 VecDestroy(mDirichletBoundaryConditionsVector);
00272 }
00273
00274 #if (PETSC_VERSION_MAJOR == 3)
00275 if (mpConvergenceTestContext)
00276 {
00277 KSPDefaultConvergedDestroy(mpConvergenceTestContext);
00278 }
00279 #endif
00280
00281 #ifdef TRACE_KSP
00282 if (PetscTools::AmMaster())
00283 {
00284 if (mNumSolves > 0)
00285 {
00286 double ave_num_iterations = mTotalNumIterations/(double)mNumSolves;
00287
00288 std::cout << std::endl << "KSP iterations report:" << std::endl;
00289 std::cout << "mNumSolves" << "\t" << "mTotalNumIterations" << "\t" << "mMaxNumIterations" << "\t" << "mAveNumIterations" << std::endl;
00290 std::cout << mNumSolves << "\t" << mTotalNumIterations << "\t" << mMaxNumIterations << "\t" << ave_num_iterations << std::endl;
00291 }
00292 }
00293 #endif
00294 }
00295
00296 void LinearSystem::SetMatrixElement(PetscInt row, PetscInt col, double value)
00297 {
00298 PetscMatTools::SetElement(mLhsMatrix, row, col, value);
00299 }
00300
00301 void LinearSystem::AddToMatrixElement(PetscInt row, PetscInt col, double value)
00302 {
00303 PetscMatTools::AddToElement(mLhsMatrix, row, col, value);
00304 }
00305
00306 void LinearSystem::AssembleFinalLinearSystem()
00307 {
00308 FinaliseLhsMatrix();
00309 FinaliseRhsVector();
00310 }
00311
00312 void LinearSystem::AssembleIntermediateLinearSystem()
00313 {
00314 SwitchWriteModeLhsMatrix();
00315 FinaliseRhsVector();
00316 }
00317
00318 void LinearSystem::FinaliseLhsMatrix()
00319 {
00320 PetscMatTools::Finalise(mLhsMatrix);
00321 }
00322
00323 void LinearSystem::SwitchWriteModeLhsMatrix()
00324 {
00325 PetscMatTools::SwitchWriteMode(mLhsMatrix);
00326 }
00327
00328 void LinearSystem::FinalisePrecondMatrix()
00329 {
00330 PetscMatTools::Finalise(mPrecondMatrix);
00331 }
00332
00333 void LinearSystem::FinaliseRhsVector()
00334 {
00335 PetscVecTools::Finalise(mRhsVector);
00336 }
00337
00338 void LinearSystem::SetRhsVectorElement(PetscInt row, double value)
00339 {
00340 PetscVecTools::SetElement(mRhsVector, row, value);
00341 }
00342
00343 void LinearSystem::AddToRhsVectorElement(PetscInt row, double value)
00344 {
00345 PetscVecTools::AddToElement(mRhsVector, row, value);
00346 }
00347
00348 void LinearSystem::DisplayMatrix()
00349 {
00350 PetscMatTools::Display(mLhsMatrix);
00351 }
00352
00353 void LinearSystem::DisplayRhs()
00354 {
00355 PetscVecTools::Display(mRhsVector);
00356 }
00357
00358 void LinearSystem::SetMatrixRow(PetscInt row, double value)
00359 {
00360 PetscMatTools::SetRow(mLhsMatrix, row, value);
00361 }
00362
00363 Vec LinearSystem::GetMatrixRowDistributed(unsigned rowIndex)
00364 {
00365 return PetscMatTools::GetMatrixRowDistributed(mLhsMatrix, rowIndex);
00366 }
00367
00368 void LinearSystem::ZeroMatrixRowsWithValueOnDiagonal(std::vector<unsigned>& rRows, double diagonalValue)
00369 {
00370 PetscMatTools::ZeroRowsWithValueOnDiagonal(mLhsMatrix, rRows, diagonalValue);
00371 }
00372
00373 void LinearSystem::ZeroMatrixRowsAndColumnsWithValueOnDiagonal(std::vector<unsigned>& rRowColIndices, double diagonalValue)
00374 {
00375 PetscMatTools::ZeroRowsAndColumnsWithValueOnDiagonal(mLhsMatrix, rRowColIndices, diagonalValue);
00376 }
00377
00378 void LinearSystem::ZeroMatrixColumn(PetscInt col)
00379 {
00380 PetscMatTools::ZeroColumn(mLhsMatrix, col);
00381 }
00382
00383 void LinearSystem::ZeroRhsVector()
00384 {
00385 PetscVecTools::Zero(mRhsVector);
00386 }
00387
00388 void LinearSystem::ZeroLhsMatrix()
00389 {
00390 PetscMatTools::Zero(mLhsMatrix);
00391 }
00392
00393 void LinearSystem::ZeroLinearSystem()
00394 {
00395 ZeroRhsVector();
00396 ZeroLhsMatrix();
00397 }
00398
00399 unsigned LinearSystem::GetSize() const
00400 {
00401 return (unsigned) mSize;
00402 }
00403
00404 void LinearSystem::SetNullBasis(Vec nullBasis[], unsigned numberOfBases)
00405 {
00406 #ifndef NDEBUG
00407
00408 for (unsigned vec_index=0; vec_index<numberOfBases; vec_index++)
00409 {
00410 PetscReal l2_norm;
00411 VecNorm(nullBasis[vec_index], NORM_2, &l2_norm);
00412 if (fabs(l2_norm-1.0) > 1e-08)
00413 {
00414 EXCEPTION("One of the vectors in the null space is not normalised");
00415 }
00416 }
00417
00418
00419 for (unsigned vec_index=1; vec_index<numberOfBases; vec_index++)
00420 {
00421
00422 unsigned num_vectors_ahead = numberOfBases-vec_index;
00423 PetscScalar dot_products[num_vectors_ahead];
00424 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00425 VecMDot(num_vectors_ahead, nullBasis[vec_index-1], &nullBasis[vec_index], dot_products);
00426 #else
00427 VecMDot(nullBasis[vec_index-1], num_vectors_ahead, &nullBasis[vec_index], dot_products);
00428 #endif
00429 for (unsigned index=0; index<num_vectors_ahead; index++)
00430 {
00431 if (fabs(dot_products[index]) > 1e-08 )
00432 {
00433 EXCEPTION("The null space is not orthogonal.");
00434 }
00435 }
00436 }
00437
00438 #endif
00439
00440 PETSCEXCEPT( MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_FALSE, numberOfBases, nullBasis, &mMatNullSpace) );
00441 }
00442
00443 void LinearSystem::RemoveNullSpace()
00444 {
00445
00446 if (mMatNullSpace)
00447 {
00448 PETSCEXCEPT( MatNullSpaceDestroy(mMatNullSpace) );
00449 PETSCEXCEPT( MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_FALSE, 0, NULL, &mMatNullSpace) );
00450 if (mKspIsSetup)
00451 {
00452 PETSCEXCEPT( KSPSetNullSpace(mKspSolver, mMatNullSpace) );
00453 }
00454
00455 }
00456 }
00457
00458 void LinearSystem::GetOwnershipRange(PetscInt& lo, PetscInt& hi)
00459 {
00460 lo = mOwnershipRangeLo;
00461 hi = mOwnershipRangeHi;
00462 }
00463
00464 double LinearSystem::GetMatrixElement(PetscInt row, PetscInt col)
00465 {
00466 return PetscMatTools::GetElement(mLhsMatrix, row, col);
00467 }
00468
00469 double LinearSystem::GetRhsVectorElement(PetscInt row)
00470 {
00471 return PetscVecTools::GetElement(mRhsVector, row);
00472 }
00473
00474 unsigned LinearSystem::GetNumIterations() const
00475 {
00476 assert(this->mKspIsSetup);
00477
00478 PetscInt num_its;
00479 KSPGetIterationNumber(this->mKspSolver, &num_its);
00480
00481 return (unsigned) num_its;
00482 }
00483
00484 Vec& LinearSystem::rGetRhsVector()
00485 {
00486 return mRhsVector;
00487 }
00488
00489 Vec LinearSystem::GetRhsVector() const
00490 {
00491 return mRhsVector;
00492 }
00493
00494 Mat& LinearSystem::rGetLhsMatrix()
00495 {
00496 return mLhsMatrix;
00497 }
00498
00499 Mat LinearSystem::GetLhsMatrix() const
00500 {
00501 return mLhsMatrix;
00502 }
00503
00504 Mat& LinearSystem::rGetPrecondMatrix()
00505 {
00506 if (!mPrecondMatrixIsNotLhs)
00507 {
00508 EXCEPTION("LHS matrix used for preconditioner construction");
00509 }
00510
00511 return mPrecondMatrix;
00512 }
00513
00514 Vec& LinearSystem::rGetDirichletBoundaryConditionsVector()
00515 {
00516 return mDirichletBoundaryConditionsVector;
00517 }
00518
00519 void LinearSystem::SetMatrixIsSymmetric(bool isSymmetric)
00520 {
00522
00523 if (isSymmetric)
00524 {
00525 PetscMatTools::SetOption(mLhsMatrix, MAT_SYMMETRIC);
00526 PetscMatTools::SetOption(mLhsMatrix, MAT_SYMMETRY_ETERNAL);
00527 }
00528 else
00529 {
00530
00531 #if (PETSC_VERSION_MAJOR == 3) //PETSc 3.x.x
00532 MatSetOption(mLhsMatrix, MAT_SYMMETRIC, PETSC_FALSE);
00533 MatSetOption(mLhsMatrix, MAT_STRUCTURALLY_SYMMETRIC, PETSC_FALSE);
00534 MatSetOption(mLhsMatrix, MAT_SYMMETRY_ETERNAL, PETSC_FALSE);
00535 #else
00536 MatSetOption(mLhsMatrix, MAT_NOT_SYMMETRIC);
00537 MatSetOption(mLhsMatrix, MAT_NOT_STRUCTURALLY_SYMMETRIC);
00538 MatSetOption(mLhsMatrix, MAT_NOT_SYMMETRY_ETERNAL);
00539 #endif
00540 }
00541 }
00542
00543 bool LinearSystem::IsMatrixSymmetric()
00544 {
00545 PetscTruth symmetry_flag_is_set;
00546 PetscTruth symmetry_flag;
00547
00548 MatIsSymmetricKnown(mLhsMatrix, &symmetry_flag_is_set, &symmetry_flag);
00549
00550
00551 return symmetry_flag_is_set && symmetry_flag;
00552 }
00553
00554 void LinearSystem::SetMatrixIsConstant(bool matrixIsConstant)
00555 {
00556 mMatrixIsConstant = matrixIsConstant;
00557 }
00558
00559 void LinearSystem::SetRelativeTolerance(double relativeTolerance)
00560 {
00561 mTolerance = relativeTolerance;
00562 mUseAbsoluteTolerance = false;
00563 if (mKspIsSetup)
00564 {
00565 KSPSetTolerances(mKspSolver, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
00566 }
00567 }
00568
00569 void LinearSystem::SetAbsoluteTolerance(double absoluteTolerance)
00570 {
00571 mTolerance = absoluteTolerance;
00572 mUseAbsoluteTolerance = true;
00573 if (mKspIsSetup)
00574 {
00575 KSPSetTolerances(mKspSolver, DBL_EPSILON, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT);
00576 }
00577 }
00578
00579 void LinearSystem::SetKspType(const char *kspType)
00580 {
00581 mKspType = kspType;
00582 if (mKspIsSetup)
00583 {
00584 KSPSetType(mKspSolver, kspType);
00585 KSPSetFromOptions(mKspSolver);
00586 }
00587 }
00588
00589 void LinearSystem::SetPcType(const char* pcType, boost::shared_ptr<std::vector<PetscInt> > pBathNodes)
00590 {
00591 mPcType = pcType;
00592 mpBathNodes = pBathNodes;
00593
00594 if (mKspIsSetup)
00595 {
00596 if (mPcType == "blockdiagonal")
00597 {
00598
00600 delete mpBlockDiagonalPC;
00601 mpBlockDiagonalPC = NULL;
00602 delete mpLDUFactorisationPC;
00603 mpLDUFactorisationPC = NULL;
00604 delete mpTwoLevelsBlockDiagonalPC;
00605 mpTwoLevelsBlockDiagonalPC = NULL;
00606
00607 mpBlockDiagonalPC = new PCBlockDiagonal(mKspSolver);
00608 }
00609 else if (mPcType == "ldufactorisation")
00610 {
00611
00613 delete mpBlockDiagonalPC;
00614 mpBlockDiagonalPC = NULL;
00615 delete mpLDUFactorisationPC;
00616 mpLDUFactorisationPC = NULL;
00617 delete mpTwoLevelsBlockDiagonalPC;
00618 mpTwoLevelsBlockDiagonalPC = NULL;
00619
00620 mpLDUFactorisationPC = new PCLDUFactorisation(mKspSolver);
00621 }
00622 else if (mPcType == "twolevelsblockdiagonal")
00623 {
00624
00626 delete mpBlockDiagonalPC;
00627 mpBlockDiagonalPC = NULL;
00628 delete mpLDUFactorisationPC;
00629 mpLDUFactorisationPC = NULL;
00630 delete mpTwoLevelsBlockDiagonalPC;
00631 mpTwoLevelsBlockDiagonalPC = NULL;
00632
00633 if (!mpBathNodes)
00634 {
00635 TERMINATE("You must provide a list of bath nodes when using TwoLevelsBlockDiagonalPC");
00636 }
00637 mpTwoLevelsBlockDiagonalPC = new PCTwoLevelsBlockDiagonal(mKspSolver, *mpBathNodes);
00638 }
00639 else
00640 {
00641 PC prec;
00642 KSPGetPC(mKspSolver, &prec);
00643 PCSetType(prec, pcType);
00644 }
00645 KSPSetFromOptions(mKspSolver);
00646 }
00647 }
00648
00649 Vec LinearSystem::Solve(Vec lhsGuess)
00650 {
00651
00652
00653
00654
00655
00656
00657
00658 MatInfo mat_info;
00659 MatGetInfo(mLhsMatrix, MAT_GLOBAL_SUM, &mat_info);
00660
00661 if (!mKspIsSetup)
00662 {
00663
00664 Vec chebyshev_lhs_vector = NULL;
00665
00666 HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00667 mNonZerosUsed=mat_info.nz_used;
00668
00669 PC prec;
00670
00671 KSPCreate(PETSC_COMM_WORLD, &mKspSolver);
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682 MatStructure preconditioner_over_successive_calls;
00683
00684 if (mMatrixIsConstant)
00685 {
00686 preconditioner_over_successive_calls = SAME_PRECONDITIONER;
00687 }
00688 else
00689 {
00690 preconditioner_over_successive_calls = SAME_NONZERO_PATTERN;
00691 }
00692
00693 if (mPrecondMatrixIsNotLhs)
00694 {
00695 KSPSetOperators(mKspSolver, mLhsMatrix, mPrecondMatrix, preconditioner_over_successive_calls);
00696 }
00697 else
00698 {
00699 KSPSetOperators(mKspSolver, mLhsMatrix, mLhsMatrix, preconditioner_over_successive_calls);
00700 }
00701
00702
00703
00704 if (mUseAbsoluteTolerance)
00705 {
00706 KSPSetTolerances(mKspSolver, DBL_EPSILON, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT);
00707 }
00708 else
00709 {
00710 KSPSetTolerances(mKspSolver, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
00711 }
00712
00713
00714 KSPSetType(mKspSolver, mKspType.c_str());
00715 KSPGetPC(mKspSolver, &prec);
00716
00717
00718 if (mSize <= 4)
00719 {
00720 PCSetType(prec, PCNONE);
00721 }
00722 else
00723 {
00724 #ifdef TRACE_KSP
00725 Timer::Reset();
00726 #endif
00727 if (mPcType == "blockdiagonal")
00728 {
00729 mpBlockDiagonalPC = new PCBlockDiagonal(mKspSolver);
00730 #ifdef TRACE_KSP
00731 if (PetscTools::AmMaster())
00732 {
00733 Timer::Print("Purpose-build preconditioner creation");
00734 }
00735 #endif
00736 }
00737 else if (mPcType == "ldufactorisation")
00738 {
00739 mpLDUFactorisationPC = new PCLDUFactorisation(mKspSolver);
00740 #ifdef TRACE_KSP
00741 if (PetscTools::AmMaster())
00742 {
00743 Timer::Print("Purpose-build preconditioner creation");
00744 }
00745 #endif
00746 }
00747 else if (mPcType == "twolevelsblockdiagonal")
00748 {
00749 if (!mpBathNodes)
00750 {
00751 TERMINATE("You must provide a list of bath nodes when using TwoLevelsBlockDiagonalPC");
00752 }
00753 mpTwoLevelsBlockDiagonalPC = new PCTwoLevelsBlockDiagonal(mKspSolver, *mpBathNodes);
00754 #ifdef TRACE_KSP
00755 if (PetscTools::AmMaster())
00756 {
00757 Timer::Print("Purpose-build preconditioner creation");
00758 }
00759 #endif
00760
00761 }
00762 else
00763 {
00764 PCSetType(prec, mPcType.c_str());
00765 }
00766 }
00767
00768 if (mMatNullSpace)
00769 {
00771 PETSCEXCEPT( KSPSetNullSpace(mKspSolver, mMatNullSpace) );
00772 }
00773
00774 if (lhsGuess)
00775 {
00776
00777 KSPSetInitialGuessNonzero(mKspSolver,PETSC_TRUE);
00778 }
00779
00780 KSPSetFromOptions(mKspSolver);
00781
00782
00783
00784
00785
00786 if (mKspType == "chebychev" && !mUseFixedNumberIterations)
00787 {
00788 #ifdef TRACE_KSP
00789 Timer::Reset();
00790 #endif
00791
00792 KSPSetType(mKspSolver,"cg");
00793 KSPSetComputeEigenvalues(mKspSolver, PETSC_TRUE);
00794 KSPSetUp(mKspSolver);
00795
00796 VecDuplicate(mRhsVector, &chebyshev_lhs_vector);
00797 if (lhsGuess)
00798 {
00799 VecCopy(lhsGuess, chebyshev_lhs_vector);
00800 }
00801
00802
00803 KSPSolve(mKspSolver, mRhsVector, chebyshev_lhs_vector);
00804
00805 PetscReal *r_eig = new PetscReal[mSize];
00806 PetscReal *c_eig = new PetscReal[mSize];
00807 PetscInt eigs_computed;
00808 KSPComputeEigenvalues(mKspSolver, mSize, r_eig, c_eig, &eigs_computed);
00809
00810 mEigMin = r_eig[0];
00811
00812
00813 KSPSetTolerances(mKspSolver, DBL_EPSILON, DBL_EPSILON, PETSC_DEFAULT, PETSC_DEFAULT);
00814 KSPSetUp(mKspSolver);
00815 if (lhsGuess)
00816 {
00817 VecCopy(lhsGuess, chebyshev_lhs_vector);
00818 }
00819
00820 KSPSolve(mKspSolver, mRhsVector, chebyshev_lhs_vector);
00821 KSPComputeEigenvalues(mKspSolver, mSize, r_eig, c_eig, &eigs_computed);
00822
00823 mEigMax = r_eig[eigs_computed-1];
00824
00825 #ifdef TRACE_KSP
00826
00827
00828
00829
00830
00831 if (PetscTools::AmMaster())
00832 {
00833 std::cout << "EIGS: ";
00834 for (int index=0; index<eigs_computed; index++)
00835 {
00836 std::cout << r_eig[index] << ", ";
00837 }
00838 std::cout << std::endl;
00839 }
00840
00841 if (PetscTools::AmMaster()) std::cout << "EIGS "<< mEigMax << " " << mEigMin <<std::endl;
00842 double alpha = 2/(mEigMax+mEigMin);
00843 double sigma_one = 1 - alpha*mEigMin;
00844 if (PetscTools::AmMaster()) std::cout << "sigma_1 = 1 - alpha*mEigMin = "<< sigma_one <<std::endl;
00845 #endif
00846
00847
00848 assert(mKspType == "chebychev");
00849 KSPSetType(mKspSolver, mKspType.c_str());
00850 KSPChebychevSetEigenvalues(mKspSolver, mEigMax, mEigMin);
00851 KSPSetComputeEigenvalues(mKspSolver, PETSC_FALSE);
00852 if (mUseAbsoluteTolerance)
00853 {
00854 KSPSetTolerances(mKspSolver, DBL_EPSILON, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT);
00855 }
00856 else
00857 {
00858 KSPSetTolerances(mKspSolver, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
00859 }
00860
00861 delete[] r_eig;
00862 delete[] c_eig;
00863
00864 #ifdef TRACE_KSP
00865 if (PetscTools::AmMaster())
00866 {
00867 Timer::Print("Computing extremal eigenvalues");
00868 }
00869 #endif
00870 }
00871
00872 #ifdef TRACE_KSP
00873 Timer::Reset();
00874 #endif
00875
00876 KSPSetUp(mKspSolver);
00877
00878 if (chebyshev_lhs_vector)
00879 {
00880 VecDestroy(chebyshev_lhs_vector);
00881 }
00882
00883 #ifdef TRACE_KSP
00884 if (PetscTools::AmMaster())
00885 {
00886 Timer::Print("KSPSetUP (contains preconditioner creation for PETSc preconditioners)");
00887 }
00888 #endif
00889
00890 mKspIsSetup = true;
00891
00892 HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00893 }
00894 else
00895 {
00896 #define COVERAGE_IGNORE
00897 if (mNonZerosUsed!=mat_info.nz_used)
00898 {
00899 EXCEPTION("LinearSystem doesn't allow the non-zero pattern of a matrix to change. (I think you changed it).");
00900 }
00901
00902
00903
00904
00905
00906
00907 #undef COVERAGE_IGNORE
00908 }
00909
00910 HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00911
00913 Vec lhs_vector;
00914 VecDuplicate(mRhsVector, &lhs_vector);
00915 if (lhsGuess)
00916 {
00917 VecCopy(lhsGuess, lhs_vector);
00918 }
00919
00920
00921
00922 PetscReal rhs_norm;
00923 VecNorm(mRhsVector, NORM_1, &rhs_norm);
00924 double rhs_zero_tol = 1e-15;
00925
00926 if (rhs_norm < rhs_zero_tol && rhs_norm > 0.0)
00927 {
00928 WARNING("Using zero initial guess due to small right hand side vector");
00929 PetscVecTools::Zero(lhs_vector);
00930 }
00931
00932 HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973 try
00974 {
00975 HeartEventHandler::BeginEvent(HeartEventHandler::SOLVE_LINEAR_SYSTEM);
00976
00977 #ifdef TRACE_KSP
00978 Timer::Reset();
00979 #endif
00980
00981
00982 if (mUseFixedNumberIterations && (mNumSolves%mEvaluateNumItsEveryNSolves==0 || mForceSpectrumReevaluation))
00983 {
00984 #if ((PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR <= 2))
00985 KSPSetNormType(mKspSolver, KSP_PRECONDITIONED_NORM);
00986 #else
00987 KSPSetNormType(mKspSolver, KSP_NORM_PRECONDITIONED);
00988 #endif
00989
00990 #if (PETSC_VERSION_MAJOR == 3)
00991 if (!mpConvergenceTestContext)
00992 {
00993 KSPDefaultConvergedCreate(&mpConvergenceTestContext);
00994 }
00995 KSPSetConvergenceTest(mKspSolver, KSPDefaultConverged, &mpConvergenceTestContext, PETSC_NULL);
00996 #else
00997 KSPSetConvergenceTest(mKspSolver, KSPDefaultConverged, PETSC_NULL);
00998 #endif
00999
01000 if (mUseAbsoluteTolerance)
01001 {
01002 KSPSetTolerances(mKspSolver, DBL_EPSILON, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT);
01003 }
01004 else
01005 {
01006 KSPSetTolerances(mKspSolver, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
01007 }
01008
01010 std::stringstream num_it_str;
01011 num_it_str << 1000;
01012 PetscOptionsSetValue("-ksp_max_it", num_it_str.str().c_str());
01013
01014
01015 if (mKspType == "chebychev")
01016 {
01017
01018 KSPSetType(mKspSolver,"cg");
01019 KSPSetComputeEigenvalues(mKspSolver, PETSC_TRUE);
01020 }
01021
01022 KSPSetFromOptions(mKspSolver);
01023 KSPSetUp(mKspSolver);
01024 }
01025
01026 PETSCEXCEPT(KSPSolve(mKspSolver, mRhsVector, lhs_vector));
01027 HeartEventHandler::EndEvent(HeartEventHandler::SOLVE_LINEAR_SYSTEM);
01028
01029 #ifdef TRACE_KSP
01030 PetscInt num_it;
01031 KSPGetIterationNumber(mKspSolver, &num_it);
01032 if (PetscTools::AmMaster())
01033 {
01034 std::cout << "++ Solve: " << mNumSolves << " NumIterations: " << num_it << " ";
01035 Timer::Print("Solve");
01036 }
01037
01038 mTotalNumIterations += num_it;
01039 if ((unsigned) num_it > mMaxNumIterations)
01040 {
01041 mMaxNumIterations = num_it;
01042 }
01043 #endif
01044
01045
01046 KSPConvergedReason reason;
01047 KSPGetConvergedReason(mKspSolver, &reason);
01048
01049 if (mUseFixedNumberIterations && PETSC_VERSION_MAJOR < 3)
01050 {
01051 WARNING("Not explicitly checking convergence reason when using fixed number of iterations and PETSc 2");
01052 }
01053 else
01054 {
01055 KSPEXCEPT(reason);
01056 }
01057
01058 if (mUseFixedNumberIterations && (mNumSolves%mEvaluateNumItsEveryNSolves==0 || mForceSpectrumReevaluation))
01059 {
01060
01061 if (mKspType == "chebychev")
01062 {
01063 PetscReal *r_eig = new PetscReal[mSize];
01064 PetscReal *c_eig = new PetscReal[mSize];
01065 PetscInt eigs_computed;
01066 KSPComputeEigenvalues(mKspSolver, mSize, r_eig, c_eig, &eigs_computed);
01067
01068 mEigMin = r_eig[0];
01069
01070
01071
01072
01073
01074 mEigMax = std::max(mEigMax,r_eig[eigs_computed-1]);
01075
01076 delete[] r_eig;
01077 delete[] c_eig;
01078
01079 assert(mKspType == "chebychev");
01080 KSPSetType(mKspSolver, mKspType.c_str());
01081 KSPChebychevSetEigenvalues(mKspSolver, mEigMax, mEigMin);
01082 KSPSetComputeEigenvalues(mKspSolver, PETSC_FALSE);
01083 }
01084
01085 #if ((PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR <= 2))
01086 if (mKspType == "chebychev")
01087 {
01088
01089 EXCEPTION("Chebyshev with fixed number of iterations is known to be broken in PETSc <= 2.3.2");
01090 }
01091
01092 KSPSetNormType(mKspSolver, KSP_NO_NORM);
01093 #else
01094 KSPSetNormType(mKspSolver, KSP_NORM_NO);
01095 #endif
01096
01097 #if (PETSC_VERSION_MAJOR != 3)
01098 KSPSetConvergenceTest(mKspSolver, KSPSkipConverged, PETSC_NULL);
01099 #endif
01100
01101 PetscInt num_it;
01102 KSPGetIterationNumber(mKspSolver, &num_it);
01103 std::stringstream num_it_str;
01104 num_it_str << num_it;
01105 PetscOptionsSetValue("-ksp_max_it", num_it_str.str().c_str());
01106
01107 KSPSetFromOptions(mKspSolver);
01108 KSPSetUp(mKspSolver);
01109
01110 mForceSpectrumReevaluation=false;
01111 }
01112
01113 mNumSolves++;
01114
01115 }
01116 catch (const Exception& e)
01117 {
01118
01119 VecDestroy(lhs_vector);
01120 throw e;
01121 }
01122
01123 return lhs_vector;
01124 }
01125
01126 void LinearSystem::SetPrecondMatrixIsDifferentFromLhs(bool precondIsDifferent)
01127 {
01128 mPrecondMatrixIsNotLhs = precondIsDifferent;
01129
01130 if (mPrecondMatrixIsNotLhs)
01131 {
01132 if (mRowPreallocation == UINT_MAX)
01133 {
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143 NEVER_REACHED;
01144 }
01145
01146 PetscInt local_size = mOwnershipRangeHi - mOwnershipRangeLo;
01147 PetscTools::SetupMat(mPrecondMatrix, mSize, mSize, mRowPreallocation, local_size, local_size);
01148 }
01149 }
01150
01151 void LinearSystem::SetUseFixedNumberIterations(bool useFixedNumberIterations, unsigned evaluateNumItsEveryNSolves)
01152 {
01153
01154 mUseFixedNumberIterations = useFixedNumberIterations;
01155 mEvaluateNumItsEveryNSolves = evaluateNumItsEveryNSolves;
01156 }
01157
01158 void LinearSystem::ResetKspSolver()
01159 {
01160 if (mKspIsSetup)
01161 {
01162 KSPDestroy(mKspSolver);
01163 }
01164
01165 mKspIsSetup = false;
01166 mForceSpectrumReevaluation = true;
01167
01168
01169
01170
01171
01172
01174 std::stringstream num_it_str;
01175 num_it_str << 1000;
01176 PetscOptionsSetValue("-ksp_max_it", num_it_str.str().c_str());
01177 }
01178
01179
01180 #include "SerializationExportWrapperForCpp.hpp"
01181 CHASTE_CLASS_EXPORT(LinearSystem)