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
00038
00040
00042
00043 LinearSystem::LinearSystem(PetscInt lhsVectorSize, unsigned rowPreallocation)
00044 :mSize(lhsVectorSize),
00045 mMatNullSpace(NULL),
00046 mDestroyMatAndVec(true),
00047 mKspIsSetup(false),
00048 mNonZerosUsed(0.0),
00049 mMatrixIsConstant(false),
00050 mTolerance(1e-6),
00051 mUseAbsoluteTolerance(false),
00052 mDirichletBoundaryConditionsVector(NULL),
00053 mpBlockDiagonalPC(NULL),
00054 mpLDUFactorisationPC(NULL),
00055 mpTwoLevelsBlockDiagonalPC(NULL),
00056 mpBathNodes( boost::shared_ptr<std::vector<PetscInt> >() )
00057 {
00058 assert(lhsVectorSize>0);
00059 if (rowPreallocation == UINT_MAX)
00060 {
00061
00062 if (lhsVectorSize<15)
00063 {
00064 rowPreallocation=lhsVectorSize;
00065 }
00066 else
00067 {
00068 EXCEPTION("You must provide a rowPreallocation argument for a large sparse system");
00069 }
00070 }
00071
00072 mRhsVector=PetscTools::CreateVec(mSize);
00073 PetscTools::SetupMat(mLhsMatrix, mSize, mSize, rowPreallocation, PETSC_DECIDE, PETSC_DECIDE);
00074
00075 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00076
00079 mKspType = "gmres";
00080 mPcType = "jacobi";
00081
00082 #ifdef TRACE_KSP
00083 mNumSolves = 0;
00084 mTotalNumIterations = 0;
00085 mMaxNumIterations = 0;
00086 #endif
00087 }
00088
00089 LinearSystem::LinearSystem(PetscInt lhsVectorSize, Mat lhsMatrix, Vec rhsVector)
00090 :mSize(lhsVectorSize),
00091 mMatNullSpace(NULL),
00092 mDestroyMatAndVec(true),
00093 mKspIsSetup(false),
00094 mNonZerosUsed(0.0),
00095 mMatrixIsConstant(false),
00096 mTolerance(1e-6),
00097 mUseAbsoluteTolerance(false),
00098 mDirichletBoundaryConditionsVector(NULL),
00099 mpBlockDiagonalPC(NULL),
00100 mpLDUFactorisationPC(NULL),
00101 mpTwoLevelsBlockDiagonalPC(NULL),
00102 mpBathNodes( boost::shared_ptr<std::vector<PetscInt> >() )
00103 {
00104 assert(lhsVectorSize>0);
00105
00106 mLhsMatrix = lhsMatrix;
00107 mRhsVector = rhsVector;
00108
00109 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00110
00111 #ifdef TRACE_KSP
00112 mNumSolves = 0;
00113 mTotalNumIterations = 0;
00114 mMaxNumIterations = 0;
00115 #endif
00116 }
00117
00118 LinearSystem::LinearSystem(Vec templateVector, unsigned rowPreallocation)
00119 :mMatNullSpace(NULL),
00120 mDestroyMatAndVec(true),
00121 mKspIsSetup(false),
00122 mMatrixIsConstant(false),
00123 mTolerance(1e-6),
00124 mUseAbsoluteTolerance(false),
00125 mDirichletBoundaryConditionsVector(NULL),
00126 mpBlockDiagonalPC(NULL),
00127 mpLDUFactorisationPC(NULL),
00128 mpTwoLevelsBlockDiagonalPC(NULL),
00129 mpBathNodes( boost::shared_ptr<std::vector<PetscInt> >() )
00130 {
00131 VecDuplicate(templateVector, &mRhsVector);
00132 VecGetSize(mRhsVector, &mSize);
00133 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00134 PetscInt local_size = mOwnershipRangeHi - mOwnershipRangeLo;
00135
00136 PetscTools::SetupMat(mLhsMatrix, mSize, mSize, rowPreallocation, local_size, local_size);
00137
00140 mKspType = "gmres";
00141 mPcType = "jacobi";
00142
00143 #ifdef TRACE_KSP
00144 mNumSolves = 0;
00145 mTotalNumIterations = 0;
00146 mMaxNumIterations = 0;
00147 #endif
00148 }
00149
00150 LinearSystem::LinearSystem(Vec residualVector, Mat jacobianMatrix)
00151 :mMatNullSpace(NULL),
00152 mDestroyMatAndVec(false),
00153 mKspIsSetup(false),
00154 mMatrixIsConstant(false),
00155 mTolerance(1e-6),
00156 mUseAbsoluteTolerance(false),
00157 mDirichletBoundaryConditionsVector(NULL),
00158 mpBlockDiagonalPC(NULL),
00159 mpLDUFactorisationPC(NULL),
00160 mpTwoLevelsBlockDiagonalPC(NULL),
00161 mpBathNodes( boost::shared_ptr<std::vector<PetscInt> >() )
00162 {
00163 assert(residualVector || jacobianMatrix);
00164 mRhsVector = residualVector;
00165 mLhsMatrix = jacobianMatrix;
00166
00167 PetscInt mat_size=0, vec_size=0;
00168 if (mRhsVector)
00169 {
00170 VecGetSize(mRhsVector, &vec_size);
00171 mSize = (unsigned)vec_size;
00172 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00173 }
00174 if (mLhsMatrix)
00175 {
00176 PetscInt mat_cols;
00177 MatGetSize(mLhsMatrix, &mat_size, &mat_cols);
00178 assert(mat_size == mat_cols);
00179 mSize = (unsigned)mat_size;
00180 MatGetOwnershipRange(mLhsMatrix, &mOwnershipRangeLo, &mOwnershipRangeHi);
00181 }
00182 assert(!mRhsVector || !mLhsMatrix || vec_size == mat_size);
00183
00186 mKspType = "gmres";
00187 mPcType = "jacobi";
00188
00189 #ifdef TRACE_KSP
00190 mNumSolves = 0;
00191 mTotalNumIterations = 0;
00192 mMaxNumIterations = 0;
00193 #endif
00194 }
00195
00196 LinearSystem::~LinearSystem()
00197 {
00198 delete mpBlockDiagonalPC;
00199 delete mpLDUFactorisationPC;
00200 delete mpTwoLevelsBlockDiagonalPC;
00201
00202 if (mDestroyMatAndVec)
00203 {
00204 VecDestroy(mRhsVector);
00205 MatDestroy(mLhsMatrix);
00206 }
00207
00208 if (mMatNullSpace)
00209 {
00210 MatNullSpaceDestroy(mMatNullSpace);
00211 }
00212
00213 if (mKspIsSetup)
00214 {
00215 KSPDestroy(mKspSolver);
00216 }
00217
00218 if (mDirichletBoundaryConditionsVector)
00219 {
00221 VecDestroy(mDirichletBoundaryConditionsVector);
00222 }
00223
00224 #ifdef TRACE_KSP
00225 if (PetscTools::AmMaster())
00226 {
00227 if (mNumSolves > 0)
00228 {
00229 double ave_num_iterations = mTotalNumIterations/(double)mNumSolves;
00230
00231 std::cout << std::endl << "KSP iterations report:" << std::endl;
00232 std::cout << "mNumSolves" << "\t" << "mTotalNumIterations" << "\t" << "mMaxNumIterations" << "\t" << "mAveNumIterations" << std::endl;
00233 std::cout << mNumSolves << "\t" << mTotalNumIterations << "\t" << mMaxNumIterations << "\t" << ave_num_iterations << std::endl;
00234 }
00235 }
00236 #endif
00237
00238 }
00239
00240
00241 void LinearSystem::SetMatrixElement(PetscInt row, PetscInt col, double value)
00242 {
00243 if (row >= mOwnershipRangeLo && row < mOwnershipRangeHi)
00244 {
00245 MatSetValue(mLhsMatrix, row, col, value, INSERT_VALUES);
00246 }
00247 }
00248
00249 void LinearSystem::AddToMatrixElement(PetscInt row, PetscInt col, double value)
00250 {
00251 if (row >= mOwnershipRangeLo && row < mOwnershipRangeHi)
00252 {
00253 MatSetValue(mLhsMatrix, row, col, value, ADD_VALUES);
00254 }
00255 }
00256
00257 void LinearSystem::AssembleFinalLinearSystem()
00258 {
00259 AssembleFinalLhsMatrix();
00260 AssembleRhsVector();
00261 }
00262
00263 void LinearSystem::AssembleIntermediateLinearSystem()
00264 {
00265 AssembleIntermediateLhsMatrix();
00266 AssembleRhsVector();
00267 }
00268
00269 void LinearSystem::AssembleFinalLhsMatrix()
00270 {
00271 MatAssemblyBegin(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00272 MatAssemblyEnd(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00273 }
00274
00275 void LinearSystem::AssembleIntermediateLhsMatrix()
00276 {
00277 MatAssemblyBegin(mLhsMatrix, MAT_FLUSH_ASSEMBLY);
00278 MatAssemblyEnd(mLhsMatrix, MAT_FLUSH_ASSEMBLY);
00279 }
00280
00281 void LinearSystem::AssembleRhsVector()
00282 {
00283 VecAssemblyBegin(mRhsVector);
00284 VecAssemblyEnd(mRhsVector);
00285 }
00286
00287 void LinearSystem::SetRhsVectorElement(PetscInt row, double value)
00288 {
00289 if (row >= mOwnershipRangeLo && row < mOwnershipRangeHi)
00290 {
00291 VecSetValues(mRhsVector, 1, &row, &value, INSERT_VALUES);
00292 }
00293 }
00294
00295 void LinearSystem::AddToRhsVectorElement(PetscInt row, double value)
00296 {
00297 if (row >= mOwnershipRangeLo && row < mOwnershipRangeHi)
00298 {
00299 VecSetValues(mRhsVector, 1, &row, &value, ADD_VALUES);
00300 }
00301 }
00302
00303 void LinearSystem::DisplayMatrix()
00304 {
00305 MatView(mLhsMatrix,PETSC_VIEWER_STDOUT_WORLD);
00306 }
00307
00308 void LinearSystem::DisplayRhs()
00309 {
00310 VecView(mRhsVector,PETSC_VIEWER_STDOUT_WORLD);
00311 }
00312
00313 void LinearSystem::SetMatrixRow(PetscInt row, double value)
00314 {
00315 if (row >= mOwnershipRangeLo && row < mOwnershipRangeHi)
00316 {
00317 PetscInt rows, cols;
00318 MatGetSize(mLhsMatrix, &rows, &cols);
00319 for (PetscInt i=0; i<cols; i++)
00320 {
00321 this->SetMatrixElement(row, i, value);
00322 }
00323 }
00324 }
00325
00326 Vec LinearSystem::GetMatrixRowDistributed(unsigned row_index)
00327 {
00328 Vec lhs_ith_row;
00329 VecDuplicate(mRhsVector, &lhs_ith_row);
00330
00331 PetscInt num_entries;
00332 const PetscInt *column_indices;
00333 const PetscScalar *values;
00334
00335 bool am_row_owner = (PetscInt)row_index >= mOwnershipRangeLo && (PetscInt)row_index < mOwnershipRangeHi;
00336
00337
00338
00339 if (am_row_owner)
00340 {
00341 MatGetRow(mLhsMatrix, row_index, &num_entries, &column_indices, &values);
00342 VecSetValues(lhs_ith_row, num_entries, column_indices, values, INSERT_VALUES);
00343 }
00344
00345 VecAssemblyBegin(lhs_ith_row);
00346 VecAssemblyEnd(lhs_ith_row);
00347
00348 if (am_row_owner)
00349 {
00350 MatRestoreRow(mLhsMatrix, row_index, &num_entries, &column_indices, &values);
00351 }
00352
00353 return lhs_ith_row;
00354 }
00355
00356 void LinearSystem::ZeroMatrixRowsWithValueOnDiagonal(std::vector<unsigned>& rRows, double diagonalValue)
00357 {
00358 MatAssemblyBegin(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00359 MatAssemblyEnd(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00360
00361
00362
00363
00364
00365 #if (PETSC_VERSION_MAJOR == 3) //PETSc 3.x.x
00366 #if (PETSC_VERSION_MINOR == 0)
00367 MatSetOption(mLhsMatrix, MAT_KEEP_ZEROED_ROWS, PETSC_TRUE);
00368 #else
00369 MatSetOption(mLhsMatrix, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE);
00370 #endif
00371 #else
00372 MatSetOption(mLhsMatrix, MAT_KEEP_ZEROED_ROWS);
00373 #endif
00374
00375 PetscInt* rows = new PetscInt[rRows.size()];
00376 for(unsigned i=0; i<rRows.size(); i++)
00377 {
00378 rows[i] = rRows[i];
00379 }
00380 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00381 IS is;
00382 ISCreateGeneral(PETSC_COMM_WORLD, rRows.size(), rows, &is);
00383 MatZeroRows(mLhsMatrix, is, &diagonalValue);
00384 ISDestroy(is);
00385 #else
00386 MatZeroRows(mLhsMatrix, rRows.size(), rows, diagonalValue);
00387 #endif
00388 delete [] rows;
00389 }
00390
00391
00392 void LinearSystem::ZeroMatrixRowsAndColumnsWithValueOnDiagonal(std::vector<unsigned>& rRowColIndices, double diagonalValue)
00393 {
00394 MatAssemblyBegin(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00395 MatAssemblyEnd(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00396
00397 std::vector<unsigned>* p_nonzero_rows_per_column = new std::vector<unsigned>[rRowColIndices.size()];
00398
00399
00400
00401
00402
00403 for(unsigned index=0; index<rRowColIndices.size(); index++)
00404 {
00405 unsigned column = rRowColIndices[index];
00406
00407
00408
00409 for (PetscInt row = mOwnershipRangeLo; row < mOwnershipRangeHi; row++)
00410 {
00411 if (GetMatrixElement(row, column) != 0.0)
00412 {
00413 p_nonzero_rows_per_column[index].push_back(row);
00414 }
00415 }
00416 }
00417
00418
00419 for(unsigned index=0; index<rRowColIndices.size(); index++)
00420 {
00421
00422 unsigned size = p_nonzero_rows_per_column[index].size();
00423 PetscInt* rows = new PetscInt[size];
00424 PetscInt cols[1];
00425 double* zeros = new double[size];
00426
00427 cols[0] = rRowColIndices[index];
00428
00429 for (unsigned i=0; i<size; i++)
00430 {
00431 rows[i] = p_nonzero_rows_per_column[index][i];
00432 zeros[i] = 0.0;
00433 }
00434
00435 MatSetValues(mLhsMatrix, size, rows, 1, cols, zeros, INSERT_VALUES);
00436 delete [] rows;
00437 delete [] zeros;
00438 }
00439 delete[] p_nonzero_rows_per_column;
00440
00441
00442 ZeroMatrixRowsWithValueOnDiagonal(rRowColIndices, diagonalValue);
00443 }
00444
00445
00446
00447
00448 void LinearSystem::ZeroMatrixColumn(PetscInt col)
00449 {
00450 MatAssemblyBegin(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00451 MatAssemblyEnd(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00452
00453
00454
00455 std::vector<unsigned> nonzero_rows;
00456 for (PetscInt row = mOwnershipRangeLo; row < mOwnershipRangeHi; row++)
00457 {
00458 if (GetMatrixElement(row, col) != 0.0)
00459 {
00460 nonzero_rows.push_back(row);
00461 }
00462 }
00463
00464
00465 unsigned size = nonzero_rows.size();
00466 PetscInt* rows = new PetscInt[size];
00467 PetscInt cols[1];
00468 double* zeros = new double[size];
00469
00470 cols[0] = col;
00471
00472 for (unsigned i=0; i<size; i++)
00473 {
00474 rows[i] = nonzero_rows[i];
00475 zeros[i] = 0.0;
00476 }
00477
00478 MatSetValues(mLhsMatrix, size, rows, 1, cols, zeros, INSERT_VALUES);
00479 delete [] rows;
00480 delete [] zeros;
00481 }
00482
00483 void LinearSystem::ZeroRhsVector()
00484 {
00485 double* p_rhs_vector_array;
00486 VecGetArray(mRhsVector, &p_rhs_vector_array);
00487 for (PetscInt local_index=0; local_index<mOwnershipRangeHi - mOwnershipRangeLo; local_index++)
00488 {
00489 p_rhs_vector_array[local_index]=0.0;
00490 }
00491 VecRestoreArray(mRhsVector, &p_rhs_vector_array);
00492 }
00493
00494 void LinearSystem::ZeroLhsMatrix()
00495 {
00496 MatZeroEntries(mLhsMatrix);
00497 }
00498
00499 void LinearSystem::ZeroLinearSystem()
00500 {
00501 ZeroRhsVector();
00502 ZeroLhsMatrix();
00503 }
00504
00505 unsigned LinearSystem::GetSize() const
00506 {
00507 return (unsigned) mSize;
00508 }
00509
00510 void LinearSystem::SetNullBasis(Vec nullBasis[], unsigned numberOfBases)
00511 {
00512 #ifndef NDEBUG
00513
00514 for (unsigned vec_index=0; vec_index<numberOfBases; vec_index++)
00515 {
00516 PetscReal l2_norm;
00517 VecNorm(nullBasis[vec_index], NORM_2, &l2_norm);
00518 if (fabs(l2_norm-1.0) > 1e-08)
00519 {
00520 EXCEPTION("One of the vectors in the null space is not normalised");
00521 }
00522 }
00523
00524
00525 for (unsigned vec_index=1; vec_index<numberOfBases; vec_index++)
00526 {
00527
00528 unsigned num_vectors_ahead = numberOfBases-vec_index;
00529 PetscScalar dot_products[num_vectors_ahead];
00530 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00531 VecMDot(num_vectors_ahead, nullBasis[vec_index-1], &nullBasis[vec_index], dot_products);
00532 #else
00533 VecMDot(nullBasis[vec_index-1], num_vectors_ahead, &nullBasis[vec_index], dot_products);
00534 #endif
00535 for (unsigned index=0; index<num_vectors_ahead; index++)
00536 {
00537 if (fabs(dot_products[index]) > 1e-08 )
00538 {
00539 EXCEPTION("The null space is not orthogonal.");
00540 }
00541 }
00542
00543 }
00544
00545 #endif
00546
00547 PETSCEXCEPT( MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_FALSE, numberOfBases, nullBasis, &mMatNullSpace) );
00548 }
00549
00550 void LinearSystem::RemoveNullSpace()
00551 {
00552
00553 if (mMatNullSpace)
00554 {
00555 PETSCEXCEPT( MatNullSpaceDestroy(mMatNullSpace) );
00556 PETSCEXCEPT( MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_FALSE, 0, NULL, &mMatNullSpace) );
00557 if (mKspIsSetup)
00558 {
00559 PETSCEXCEPT( KSPSetNullSpace(mKspSolver, mMatNullSpace) );
00560 }
00561
00562 }
00563 }
00564
00565
00566 void LinearSystem::GetOwnershipRange(PetscInt& lo, PetscInt& hi)
00567 {
00568 lo = mOwnershipRangeLo;
00569 hi = mOwnershipRangeHi;
00570 }
00571
00572 double LinearSystem::GetMatrixElement(PetscInt row, PetscInt col)
00573 {
00574 assert(mOwnershipRangeLo <= row && row < mOwnershipRangeHi);
00575 PetscInt row_as_array[1];
00576 row_as_array[0] = row;
00577 PetscInt col_as_array[1];
00578 col_as_array[0] = col;
00579
00580 double ret_array[1];
00581
00582 MatGetValues(mLhsMatrix, 1, row_as_array, 1, col_as_array, ret_array);
00583
00584 return ret_array[0];
00585 }
00586
00587 double LinearSystem::GetRhsVectorElement(PetscInt row)
00588 {
00589 assert(mOwnershipRangeLo <= row && row < mOwnershipRangeHi);
00590
00591 double* p_rhs_vector;
00592 PetscInt local_index=row-mOwnershipRangeLo;
00593 VecGetArray(mRhsVector, &p_rhs_vector);
00594 double answer=p_rhs_vector[local_index];
00595 VecRestoreArray(mRhsVector, &p_rhs_vector);
00596
00597 return answer;
00598 }
00599
00600 unsigned LinearSystem::GetNumIterations() const
00601 {
00602 assert(this->mKspIsSetup);
00603
00604 PetscInt num_its;
00605 KSPGetIterationNumber(this->mKspSolver, &num_its);
00606
00607 return (unsigned) num_its;
00608 }
00609
00610
00611 Vec& LinearSystem::rGetRhsVector()
00612 {
00613 return mRhsVector;
00614 }
00615
00616 Vec LinearSystem::GetRhsVector() const
00617 {
00618 return mRhsVector;
00619 }
00620
00621 Mat& LinearSystem::rGetLhsMatrix()
00622 {
00623 return mLhsMatrix;
00624 }
00625
00626 Mat LinearSystem::GetLhsMatrix() const
00627 {
00628 return mLhsMatrix;
00629 }
00630
00631 Vec& LinearSystem::rGetDirichletBoundaryConditionsVector()
00632 {
00633 return mDirichletBoundaryConditionsVector;
00634 }
00635
00636 void LinearSystem::SetMatrixIsSymmetric(bool isSymmetric)
00637 {
00639
00640 if (isSymmetric)
00641 {
00642 #if (PETSC_VERSION_MAJOR == 3) //PETSc 3.x.x
00643 MatSetOption(mLhsMatrix, MAT_SYMMETRIC, PETSC_TRUE);
00644 MatSetOption(mLhsMatrix, MAT_SYMMETRY_ETERNAL, PETSC_TRUE);
00645 #else
00646 MatSetOption(mLhsMatrix, MAT_SYMMETRIC);
00647 MatSetOption(mLhsMatrix, MAT_SYMMETRY_ETERNAL);
00648 #endif
00649 }
00650 else
00651 {
00652 #if (PETSC_VERSION_MAJOR == 3) //PETSc 3.x.x
00653 MatSetOption(mLhsMatrix, MAT_SYMMETRIC, PETSC_FALSE);
00654 MatSetOption(mLhsMatrix, MAT_STRUCTURALLY_SYMMETRIC, PETSC_FALSE);
00655 MatSetOption(mLhsMatrix, MAT_SYMMETRY_ETERNAL, PETSC_FALSE);
00656 #else
00657 MatSetOption(mLhsMatrix, MAT_NOT_SYMMETRIC);
00658 MatSetOption(mLhsMatrix, MAT_NOT_STRUCTURALLY_SYMMETRIC);
00659 MatSetOption(mLhsMatrix, MAT_NOT_SYMMETRY_ETERNAL);
00660 #endif
00661 }
00662 }
00663
00664 bool LinearSystem::IsMatrixSymmetric()
00665 {
00666 PetscTruth symmetry_flag_is_set;
00667 PetscTruth symmetry_flag;
00668
00669 MatIsSymmetricKnown(mLhsMatrix, &symmetry_flag_is_set, &symmetry_flag);
00670
00671
00672 return symmetry_flag_is_set && symmetry_flag;
00673 }
00674
00675 void LinearSystem::SetMatrixIsConstant(bool matrixIsConstant)
00676 {
00677 mMatrixIsConstant=matrixIsConstant;
00678 }
00679
00680 void LinearSystem::SetRelativeTolerance(double relativeTolerance)
00681 {
00682 mTolerance=relativeTolerance;
00683 mUseAbsoluteTolerance=false;
00684 if (mKspIsSetup)
00685 {
00686 KSPSetTolerances(mKspSolver, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
00687 }
00688 }
00689
00690 void LinearSystem::SetAbsoluteTolerance(double absoluteTolerance)
00691 {
00692 mTolerance=absoluteTolerance;
00693 mUseAbsoluteTolerance=true;
00694 if (mKspIsSetup)
00695 {
00696 KSPSetTolerances(mKspSolver, DBL_EPSILON, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT);
00697 }
00698 }
00699
00700 void LinearSystem::SetKspType(const char *kspType)
00701 {
00702 mKspType = kspType;
00703 if (mKspIsSetup)
00704 {
00705 KSPSetType(mKspSolver, kspType);
00706 KSPSetFromOptions(mKspSolver);
00707 }
00708 }
00709
00710 void LinearSystem::SetPcType(const char* pcType, boost::shared_ptr<std::vector<PetscInt> > pBathNodes)
00711 {
00712 mPcType=pcType;
00713 mpBathNodes = pBathNodes;
00714
00715 if (mKspIsSetup)
00716 {
00717 if (mPcType == "blockdiagonal")
00718 {
00719
00721 delete mpBlockDiagonalPC;
00722 mpBlockDiagonalPC = NULL;
00723 delete mpLDUFactorisationPC;
00724 mpLDUFactorisationPC = NULL;
00725 delete mpTwoLevelsBlockDiagonalPC;
00726 mpTwoLevelsBlockDiagonalPC = NULL;
00727
00728 mpBlockDiagonalPC = new PCBlockDiagonal(mKspSolver);
00729 }
00730 else if (mPcType == "ldufactorisation")
00731 {
00732
00734 delete mpBlockDiagonalPC;
00735 mpBlockDiagonalPC = NULL;
00736 delete mpLDUFactorisationPC;
00737 mpLDUFactorisationPC = NULL;
00738 delete mpTwoLevelsBlockDiagonalPC;
00739 mpTwoLevelsBlockDiagonalPC = NULL;
00740
00741 mpLDUFactorisationPC = new PCLDUFactorisation(mKspSolver);
00742 }
00743 else if (mPcType == "twolevelsblockdiagonal")
00744 {
00745
00747 delete mpBlockDiagonalPC;
00748 mpBlockDiagonalPC = NULL;
00749 delete mpLDUFactorisationPC;
00750 mpLDUFactorisationPC = NULL;
00751 delete mpTwoLevelsBlockDiagonalPC;
00752 mpTwoLevelsBlockDiagonalPC = NULL;
00753
00754 if (!mpBathNodes)
00755 {
00756 TERMINATE("You must provide a list of bath nodes when using TwoLevelsBlockDiagonalPC");
00757 }
00758 mpTwoLevelsBlockDiagonalPC = new PCTwoLevelsBlockDiagonal(mKspSolver, *mpBathNodes);
00759 }
00760 else
00761 {
00762 PC prec;
00763 KSPGetPC(mKspSolver, &prec);
00764 PCSetType(prec, pcType);
00765 }
00766 KSPSetFromOptions(mKspSolver);
00767 }
00768 }
00769
00770 Vec LinearSystem::Solve(Vec lhsGuess)
00771 {
00772
00773
00774
00775
00776
00777 MatInfo mat_info;
00778 MatGetInfo(mLhsMatrix, MAT_GLOBAL_SUM, &mat_info);
00779
00780 if (!mKspIsSetup)
00781 {
00782 HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00783 mNonZerosUsed=mat_info.nz_used;
00784
00785 PC prec;
00786
00787 KSPCreate(PETSC_COMM_WORLD, &mKspSolver);
00788
00789
00790
00791
00792 if (mMatrixIsConstant)
00793 {
00794 KSPSetOperators(mKspSolver, mLhsMatrix, mLhsMatrix, SAME_PRECONDITIONER);
00795 }
00796 else
00797 {
00798 KSPSetOperators(mKspSolver, mLhsMatrix, mLhsMatrix, SAME_NONZERO_PATTERN);
00799 }
00800
00801
00802
00803 if (mUseAbsoluteTolerance)
00804 {
00805 KSPSetTolerances(mKspSolver, DBL_EPSILON, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT);
00806 }
00807 else
00808 {
00809 KSPSetTolerances(mKspSolver, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
00810 }
00811
00812
00813 KSPSetType(mKspSolver, mKspType.c_str());
00814 KSPGetPC(mKspSolver, &prec);
00815
00816
00817
00818 if (mSize <= 4)
00819 {
00820 PCSetType(prec, PCNONE);
00821 }
00822 else
00823 {
00824 #ifdef TRACE_KSP
00825 Timer::Reset();
00826 #endif
00827 if (mPcType == "blockdiagonal")
00828 {
00829 mpBlockDiagonalPC = new PCBlockDiagonal(mKspSolver);
00830 #ifdef TRACE_KSP
00831 if (PetscTools::AmMaster())
00832 {
00833 Timer::Print("Purpose-build preconditioner creation");
00834 }
00835 #endif
00836 }
00837 else if (mPcType == "ldufactorisation")
00838 {
00839 mpLDUFactorisationPC = new PCLDUFactorisation(mKspSolver);
00840 #ifdef TRACE_KSP
00841 if (PetscTools::AmMaster())
00842 {
00843 Timer::Print("Purpose-build preconditioner creation");
00844 }
00845 #endif
00846 }
00847 else if (mPcType == "twolevelsblockdiagonal")
00848 {
00849 if (!mpBathNodes)
00850 {
00851 TERMINATE("You must provide a list of bath nodes when using TwoLevelsBlockDiagonalPC");
00852 }
00853 mpTwoLevelsBlockDiagonalPC = new PCTwoLevelsBlockDiagonal(mKspSolver, *mpBathNodes);
00854 #ifdef TRACE_KSP
00855 if (PetscTools::AmMaster())
00856 {
00857 Timer::Print("Purpose-build preconditioner creation");
00858 }
00859 #endif
00860
00861 }
00862 else
00863 {
00864 PCSetType(prec, mPcType.c_str());
00865 }
00866 }
00867
00868 if (mMatNullSpace)
00869 {
00871 PETSCEXCEPT( KSPSetNullSpace(mKspSolver, mMatNullSpace) );
00872 }
00873
00874 if (lhsGuess)
00875 {
00876
00877
00878 KSPSetInitialGuessNonzero(mKspSolver,PETSC_TRUE);
00879 }
00880
00881 KSPSetFromOptions(mKspSolver);
00882
00883 #ifdef TRACE_KSP
00884 Timer::Reset();
00885 #endif
00886 KSPSetUp(mKspSolver);
00887 #ifdef TRACE_KSP
00888 if (PetscTools::AmMaster())
00889 {
00890 Timer::Print("KSPSetUP (contains preconditioner creation for PETSc preconditioners)");
00891 }
00892 #endif
00893
00894 mKspIsSetup = true;
00895
00896 HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00897 }
00898 else
00899 {
00900 #define COVERAGE_IGNORE
00901 if (mNonZerosUsed!=mat_info.nz_used)
00902 {
00903 EXCEPTION("LinearSystem doesn't allow the non-zero pattern of a matrix to change. (I think you changed it).");
00904 }
00905
00906
00907
00908
00909
00910
00911 #undef COVERAGE_IGNORE
00912 }
00913
00914
00916 HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00917 Vec lhs_vector;
00918 VecDuplicate(mRhsVector, &lhs_vector);
00919 if (lhsGuess)
00920 {
00921 VecCopy(lhsGuess, lhs_vector);
00922 }
00923 HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00924
00925
00926
00927
00928
00929
00930
00931
00932
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 try
00965 {
00966 HeartEventHandler::BeginEvent(HeartEventHandler::SOLVE_LINEAR_SYSTEM);
00967
00968 #ifdef TRACE_KSP
00969 Timer::Reset();
00970 #endif
00971
00972 PETSCEXCEPT(KSPSolve(mKspSolver, mRhsVector, lhs_vector));
00973 HeartEventHandler::EndEvent(HeartEventHandler::SOLVE_LINEAR_SYSTEM);
00974
00975 #ifdef TRACE_KSP
00976 PetscInt num_it;
00977 KSPGetIterationNumber(mKspSolver, &num_it);
00978 if (PetscTools::AmMaster())
00979 {
00980 std::cout << "++ Solve: " << mNumSolves << " NumIterations: " << num_it << " ";
00981 Timer::Print("Solve");
00982 }
00983
00984 mNumSolves++;
00985 mTotalNumIterations += num_it;
00986 if ((unsigned) num_it > mMaxNumIterations)
00987 {
00988 mMaxNumIterations = num_it;
00989 }
00990 #endif
00991
00992
00993
00994 KSPConvergedReason reason;
00995 KSPGetConvergedReason(mKspSolver, &reason);
00996 KSPEXCEPT(reason);
00997
00998
00999 }
01000 catch (const Exception& e)
01001 {
01002
01003 VecDestroy(lhs_vector);
01004 throw e;
01005 }
01006
01007 return lhs_vector;
01008 }
01009
01010
01011
01012 #include "SerializationExportWrapperForCpp.hpp"
01013 CHASTE_CLASS_EXPORT(LinearSystem)