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
00037
00039
00041
00042 LinearSystem::LinearSystem(PetscInt lhsVectorSize, MatType matType)
00043 :mSize(lhsVectorSize),
00044 mMatNullSpace(NULL),
00045 mDestroyMatAndVec(true),
00046 mKspIsSetup(false),
00047 mNonZerosUsed(0.0),
00048 mMatrixIsConstant(false),
00049 mTolerance(1e-6),
00050 mUseAbsoluteTolerance(false),
00051 mDirichletBoundaryConditionsVector(NULL),
00052 mpBlockDiagonalPC(NULL)
00053 {
00054 SetupVectorAndMatrix(matType);
00055
00058 mKspType = "gmres";
00059 mPcType = "jacobi";
00060
00061 #ifdef TRACE_KSP
00062 mNumSolves = 0;
00063 mTotalNumIterations = 0;
00064 mMaxNumIterations = 0;
00065 #endif
00066 }
00067
00068 LinearSystem::LinearSystem(PetscInt lhsVectorSize, Mat lhsMatrix, Vec rhsVector, MatType matType)
00069 :mSize(lhsVectorSize),
00070 mMatNullSpace(NULL),
00071 mDestroyMatAndVec(true),
00072 mKspIsSetup(false),
00073 mNonZerosUsed(0.0),
00074 mMatrixIsConstant(false),
00075 mTolerance(1e-6),
00076 mUseAbsoluteTolerance(false),
00077 mDirichletBoundaryConditionsVector(NULL),
00078 mpBlockDiagonalPC(NULL)
00079 {
00080
00081 mLhsMatrix = lhsMatrix;
00082 mRhsVector = rhsVector;
00083
00084 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00085
00086 #ifdef TRACE_KSP
00087 mNumSolves = 0;
00088 mTotalNumIterations = 0;
00089 mMaxNumIterations = 0;
00090 #endif
00091 }
00092
00093 LinearSystem::LinearSystem(Vec templateVector)
00094 :mMatNullSpace(NULL),
00095 mDestroyMatAndVec(true),
00096 mKspIsSetup(false),
00097 mMatrixIsConstant(false),
00098 mTolerance(1e-6),
00099 mUseAbsoluteTolerance(false),
00100 mDirichletBoundaryConditionsVector(NULL),
00101 mpBlockDiagonalPC(NULL)
00102 {
00103 VecDuplicate(templateVector, &mRhsVector);
00104 VecGetSize(mRhsVector, &mSize);
00105 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00106 PetscInt local_size = mOwnershipRangeHi - mOwnershipRangeLo;
00107
00108 PetscTools::SetupMat(mLhsMatrix, mSize, mSize, (MatType) MATMPIAIJ, local_size, local_size);
00109
00112 mKspType = "gmres";
00113 mPcType = "jacobi";
00114
00115 #ifdef TRACE_KSP
00116 mNumSolves = 0;
00117 mTotalNumIterations = 0;
00118 mMaxNumIterations = 0;
00119 #endif
00120 }
00121
00122 LinearSystem::LinearSystem(Vec residualVector, Mat jacobianMatrix)
00123 :mMatNullSpace(NULL),
00124 mDestroyMatAndVec(false),
00125 mKspIsSetup(false),
00126 mMatrixIsConstant(false),
00127 mTolerance(1e-6),
00128 mUseAbsoluteTolerance(false),
00129 mDirichletBoundaryConditionsVector(NULL),
00130 mpBlockDiagonalPC(NULL)
00131 {
00132 assert(residualVector || jacobianMatrix);
00133 mRhsVector = residualVector;
00134 mLhsMatrix = jacobianMatrix;
00135
00136 PetscInt mat_size=0, vec_size=0;
00137 if (mRhsVector)
00138 {
00139 VecGetSize(mRhsVector, &vec_size);
00140 mSize = (unsigned)vec_size;
00141 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00142 }
00143 if (mLhsMatrix)
00144 {
00145 PetscInt mat_cols;
00146 MatGetSize(mLhsMatrix, &mat_size, &mat_cols);
00147 assert(mat_size == mat_cols);
00148 mSize = (unsigned)mat_size;
00149 MatGetOwnershipRange(mLhsMatrix, &mOwnershipRangeLo, &mOwnershipRangeHi);
00150 }
00151 assert(!mRhsVector || !mLhsMatrix || vec_size == mat_size);
00152
00155 mKspType = "gmres";
00156 mPcType = "jacobi";
00157
00158 #ifdef TRACE_KSP
00159 mNumSolves = 0;
00160 mTotalNumIterations = 0;
00161 mMaxNumIterations = 0;
00162 #endif
00163 }
00164
00165 LinearSystem::~LinearSystem()
00166 {
00167 if (mpBlockDiagonalPC)
00168 {
00169 delete mpBlockDiagonalPC;
00170 }
00171
00172 if (mDestroyMatAndVec)
00173 {
00174 VecDestroy(mRhsVector);
00175 MatDestroy(mLhsMatrix);
00176 }
00177
00178 if (mMatNullSpace)
00179 {
00180 MatNullSpaceDestroy(mMatNullSpace);
00181 }
00182
00183 if (mKspIsSetup)
00184 {
00185 KSPDestroy(mKspSolver);
00186 }
00187
00188 if (mDirichletBoundaryConditionsVector)
00189 {
00191 VecDestroy(mDirichletBoundaryConditionsVector);
00192 }
00193
00194 #ifdef TRACE_KSP
00195 if (mNumSolves > 0)
00196 {
00197 double ave_num_iterations = mTotalNumIterations/(double)mNumSolves;
00198
00199 std::cout << std::endl << "KSP iterations report:" << std::endl;
00200 std::cout << "mNumSolves" << "\t" << "mTotalNumIterations" << "\t" << "mMaxNumIterations" << "\t" << "mAveNumIterations" << std::endl;
00201 std::cout << mNumSolves << "\t" << mTotalNumIterations << "\t" << mMaxNumIterations << "\t" << ave_num_iterations << std::endl;
00202 }
00203 #endif
00204
00205 }
00206
00207 void LinearSystem::SetupVectorAndMatrix(MatType matType)
00208 {
00209 VecCreate(PETSC_COMM_WORLD, &mRhsVector);
00210 VecSetSizes(mRhsVector, PETSC_DECIDE, mSize);
00211 VecSetFromOptions(mRhsVector);
00212
00213 PetscTools::SetupMat(mLhsMatrix, mSize, mSize, matType);
00214
00215 VecGetOwnershipRange(mRhsVector, &mOwnershipRangeLo, &mOwnershipRangeHi);
00216 }
00217
00218 void LinearSystem::SetMatrixElement(PetscInt row, PetscInt col, double value)
00219 {
00220 if (row >= mOwnershipRangeLo && row < mOwnershipRangeHi)
00221 {
00222 MatSetValue(mLhsMatrix, row, col, value, INSERT_VALUES);
00223 }
00224 }
00225
00226 void LinearSystem::AddToMatrixElement(PetscInt row, PetscInt col, double value)
00227 {
00228 if (row >= mOwnershipRangeLo && row < mOwnershipRangeHi)
00229 {
00230 MatSetValue(mLhsMatrix, row, col, value, ADD_VALUES);
00231 }
00232 }
00233
00234 void LinearSystem::AssembleFinalLinearSystem()
00235 {
00236 AssembleFinalLhsMatrix();
00237 AssembleRhsVector();
00238 }
00239
00240 void LinearSystem::AssembleIntermediateLinearSystem()
00241 {
00242 AssembleIntermediateLhsMatrix();
00243 AssembleRhsVector();
00244 }
00245
00246 void LinearSystem::AssembleFinalLhsMatrix()
00247 {
00248 MatAssemblyBegin(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00249 MatAssemblyEnd(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00250 }
00251
00252 void LinearSystem::AssembleIntermediateLhsMatrix()
00253 {
00254 MatAssemblyBegin(mLhsMatrix, MAT_FLUSH_ASSEMBLY);
00255 MatAssemblyEnd(mLhsMatrix, MAT_FLUSH_ASSEMBLY);
00256 }
00257
00258 void LinearSystem::AssembleRhsVector()
00259 {
00260 VecAssemblyBegin(mRhsVector);
00261 VecAssemblyEnd(mRhsVector);
00262 }
00263
00264 void LinearSystem::SetRhsVectorElement(PetscInt row, double value)
00265 {
00266 if (row >= mOwnershipRangeLo && row < mOwnershipRangeHi)
00267 {
00268 VecSetValues(mRhsVector, 1, &row, &value, INSERT_VALUES);
00269 }
00270 }
00271
00272 void LinearSystem::AddToRhsVectorElement(PetscInt row, double value)
00273 {
00274 if (row >= mOwnershipRangeLo && row < mOwnershipRangeHi)
00275 {
00276 VecSetValues(mRhsVector, 1, &row, &value, ADD_VALUES);
00277 }
00278 }
00279
00280 void LinearSystem::DisplayMatrix()
00281 {
00282 MatView(mLhsMatrix,PETSC_VIEWER_STDOUT_WORLD);
00283 }
00284
00285 void LinearSystem::DisplayRhs()
00286 {
00287 VecView(mRhsVector,PETSC_VIEWER_STDOUT_WORLD);
00288 }
00289
00290 void LinearSystem::SetMatrixRow(PetscInt row, double value)
00291 {
00292 if (row >= mOwnershipRangeLo && row < mOwnershipRangeHi)
00293 {
00294 PetscInt rows, cols;
00295 MatGetSize(mLhsMatrix, &rows, &cols);
00296 for (PetscInt i=0; i<cols; i++)
00297 {
00298 this->SetMatrixElement(row, i, value);
00299 }
00300 }
00301 }
00302
00303 void LinearSystem::ZeroMatrixRow(PetscInt row)
00304 {
00305 MatAssemblyBegin(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00306 MatAssemblyEnd(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00307 double diag_zero=0.0;
00308
00309
00310
00311 #if (PETSC_VERSION_MINOR == 2) //Old API
00312 IS is;
00313 ISCreateGeneral(PETSC_COMM_WORLD,1,&row,&is);
00314 MatZeroRows(mLhsMatrix, is, &diag_zero);
00315 ISDestroy(is);
00316 #else
00317
00318 MatZeroRows(mLhsMatrix, 1, &row, diag_zero);
00319 #endif
00320
00321 }
00322
00323 void LinearSystem::ZeroMatrixColumn(PetscInt col)
00324 {
00325 MatAssemblyBegin(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00326 MatAssemblyEnd(mLhsMatrix, MAT_FINAL_ASSEMBLY);
00327
00328
00329
00330
00331
00332
00333
00334 std::vector<unsigned> nonzero_rows;
00335 for (PetscInt row = mOwnershipRangeLo; row < mOwnershipRangeHi; row++)
00336 {
00337 if (GetMatrixElement(row, col) != 0.0)
00338 {
00339 nonzero_rows.push_back(row);
00340 }
00341 }
00342
00343
00344 unsigned size = nonzero_rows.size();
00345 PetscInt* rows = new PetscInt[size];
00346 PetscInt cols[1];
00347 double* zeros = new double[size];
00348
00349 cols[0] = col;
00350
00351 for (unsigned i=0; i<size; i++)
00352 {
00353 rows[i] = nonzero_rows[i];
00354 zeros[i] = 0.0;
00355 }
00356
00357 MatSetValues(mLhsMatrix, size, rows, 1, cols, zeros, INSERT_VALUES);
00358 delete [] rows;
00359 delete [] zeros;
00360
00361 }
00362
00363 void LinearSystem::ZeroRhsVector()
00364 {
00365 double *p_rhs_vector_array;
00366 VecGetArray(mRhsVector, &p_rhs_vector_array);
00367 for (PetscInt local_index=0; local_index<mOwnershipRangeHi - mOwnershipRangeLo; local_index++)
00368 {
00369 p_rhs_vector_array[local_index]=0.0;
00370 }
00371 VecRestoreArray(mRhsVector, &p_rhs_vector_array);
00372 }
00373
00374 void LinearSystem::ZeroLhsMatrix()
00375 {
00376 MatZeroEntries(mLhsMatrix);
00377 }
00378
00379 void LinearSystem::ZeroLinearSystem()
00380 {
00381 ZeroRhsVector();
00382 ZeroLhsMatrix();
00383 }
00384
00385 unsigned LinearSystem::GetSize() const
00386 {
00387 return (unsigned) mSize;
00388 }
00389
00390 void LinearSystem::SetNullBasis(Vec nullBasis[], unsigned numberOfBases)
00391 {
00392 PETSCEXCEPT( MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_FALSE, numberOfBases, nullBasis, &mMatNullSpace) );
00393 }
00394
00395 void LinearSystem::GetOwnershipRange(PetscInt& lo, PetscInt& hi)
00396 {
00397 lo = mOwnershipRangeLo;
00398 hi = mOwnershipRangeHi;
00399 }
00400
00401 double LinearSystem::GetMatrixElement(PetscInt row, PetscInt col)
00402 {
00403 assert(mOwnershipRangeLo <= row && row < mOwnershipRangeHi);
00404 PetscInt row_as_array[1];
00405 row_as_array[0] = row;
00406 PetscInt col_as_array[1];
00407 col_as_array[0] = col;
00408
00409 double ret_array[1];
00410
00411 MatGetValues(mLhsMatrix, 1, row_as_array, 1, col_as_array, ret_array);
00412
00413 return ret_array[0];
00414 }
00415
00416 double LinearSystem::GetRhsVectorElement(PetscInt row)
00417 {
00418 assert(mOwnershipRangeLo <= row && row < mOwnershipRangeHi);
00419
00420 double *p_rhs_vector;
00421 PetscInt local_index=row-mOwnershipRangeLo;
00422 VecGetArray(mRhsVector, &p_rhs_vector);
00423 double answer=p_rhs_vector[local_index];
00424 VecRestoreArray(mRhsVector, &p_rhs_vector);
00425
00426 return answer;
00427 }
00428
00429 unsigned LinearSystem::GetNumIterations() const
00430 {
00431 assert(this->mKspIsSetup);
00432
00433 PetscInt num_its;
00434 KSPGetIterationNumber(this->mKspSolver, &num_its);
00435
00436 return (unsigned) num_its;
00437 }
00438
00439
00440 Vec& LinearSystem::rGetRhsVector()
00441 {
00442 return mRhsVector;
00443 }
00444
00445 Vec LinearSystem::GetRhsVector() const
00446 {
00447 return mRhsVector;
00448 }
00449
00450 Mat& LinearSystem::rGetLhsMatrix()
00451 {
00452 return mLhsMatrix;
00453 }
00454
00455 Mat LinearSystem::GetLhsMatrix() const
00456 {
00457 return mLhsMatrix;
00458 }
00459
00460 Vec& LinearSystem::rGetDirichletBoundaryConditionsVector()
00461 {
00462 return mDirichletBoundaryConditionsVector;
00463 }
00464
00465 void LinearSystem::SetMatrixIsSymmetric(bool isSymmetric)
00466 {
00467 if (isSymmetric)
00468 {
00469 MatSetOption(mLhsMatrix, MAT_SYMMETRIC);
00470 MatSetOption(mLhsMatrix, MAT_SYMMETRY_ETERNAL);
00471 }
00472 else
00473 {
00474 MatSetOption(mLhsMatrix, MAT_NOT_SYMMETRIC);
00475 MatSetOption(mLhsMatrix, MAT_NOT_STRUCTURALLY_SYMMETRIC);
00476 MatSetOption(mLhsMatrix, MAT_NOT_SYMMETRY_ETERNAL);
00477 }
00478 }
00479
00480 void LinearSystem::SetMatrixIsConstant(bool matrixIsConstant)
00481 {
00482 mMatrixIsConstant=matrixIsConstant;
00483 }
00484
00485 void LinearSystem::SetRelativeTolerance(double relativeTolerance)
00486 {
00487 mTolerance=relativeTolerance;
00488 mUseAbsoluteTolerance=false;
00489 if (mKspIsSetup)
00490 {
00491 KSPSetTolerances(mKspSolver, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
00492 }
00493 }
00494
00495 void LinearSystem::SetAbsoluteTolerance(double absoluteTolerance)
00496 {
00497 mTolerance=absoluteTolerance;
00498 mUseAbsoluteTolerance=true;
00499 if (mKspIsSetup)
00500 {
00501 KSPSetTolerances(mKspSolver, DBL_EPSILON, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT);
00502 }
00503 }
00504
00505 void LinearSystem::SetKspType(const char *kspType)
00506 {
00507 mKspType = kspType;
00508 if (mKspIsSetup)
00509 {
00510 KSPSetType(mKspSolver, kspType);
00511 KSPSetFromOptions(mKspSolver);
00512 }
00513 }
00514
00515 void LinearSystem::SetPcType(const char *pcType)
00516 {
00517 mPcType=pcType;
00518 if (mKspIsSetup)
00519 {
00520 if (mPcType == "blockdiagonal")
00521 {
00522 if (mpBlockDiagonalPC)
00523 {
00524
00525 delete mpBlockDiagonalPC;
00526 }
00527 mpBlockDiagonalPC = new PCBlockDiagonal(mKspSolver);
00528 }
00529 else
00530 {
00531 PC prec;
00532 KSPGetPC(mKspSolver, &prec);
00533 PCSetType(prec, pcType);
00534 }
00535 KSPSetFromOptions(mKspSolver);
00536 }
00537 }
00538
00539 Vec LinearSystem::Solve(Vec lhsGuess)
00540 {
00541
00542
00543
00544
00545
00546 MatInfo mat_info;
00547 MatGetInfo(mLhsMatrix, MAT_GLOBAL_SUM, &mat_info);
00548
00549 if (!mKspIsSetup)
00550 {
00551 HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00552 mNonZerosUsed=mat_info.nz_used;
00553
00554 PC prec;
00555
00556 KSPCreate(PETSC_COMM_WORLD, &mKspSolver);
00557
00558
00559
00560
00561 if (mMatrixIsConstant)
00562 {
00563 KSPSetOperators(mKspSolver, mLhsMatrix, mLhsMatrix, SAME_PRECONDITIONER);
00564 }
00565 else
00566 {
00567 KSPSetOperators(mKspSolver, mLhsMatrix, mLhsMatrix, SAME_NONZERO_PATTERN);
00568 }
00569
00570
00571
00572 if (mUseAbsoluteTolerance)
00573 {
00574 KSPSetTolerances(mKspSolver, DBL_EPSILON, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT);
00575 }
00576 else
00577 {
00578 KSPSetTolerances(mKspSolver, mTolerance, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
00579 }
00580
00581
00582 KSPSetType(mKspSolver, mKspType.c_str());
00583 KSPGetPC(mKspSolver, &prec);
00584
00585
00586
00587 if (mSize <= 4)
00588 {
00589 PCSetType(prec, PCNONE);
00590 }
00591 else
00592 {
00593 if (mPcType == "blockdiagonal")
00594 {
00595 mpBlockDiagonalPC = new PCBlockDiagonal(mKspSolver);
00596 }
00597 else
00598 {
00599 PCSetType(prec, mPcType.c_str());
00600 }
00601 }
00602
00603 if (mMatNullSpace)
00604 {
00606 PETSCEXCEPT( KSPSetNullSpace(mKspSolver, mMatNullSpace) );
00607 }
00608
00609 if (lhsGuess)
00610 {
00611
00612
00613 KSPSetInitialGuessNonzero(mKspSolver,PETSC_TRUE);
00614 }
00615
00616 KSPSetFromOptions(mKspSolver);
00617 KSPSetUp(mKspSolver);
00618
00619 mKspIsSetup = true;
00620
00621 HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00622 }
00623 else
00624 {
00625 #define COVERAGE_IGNORE
00626 if (mNonZerosUsed!=mat_info.nz_used)
00627 {
00628 EXCEPTION("LinearSystem doesn't allow the non-zero pattern of a matrix to change. (I think you changed it).");
00629 }
00630
00631
00632
00633
00634
00635
00636 #undef COVERAGE_IGNORE
00637 }
00638
00639
00641 HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00642 Vec lhs_vector;
00643 VecDuplicate(mRhsVector, &lhs_vector);
00644 if (lhsGuess)
00645 {
00646 VecCopy(lhsGuess, lhs_vector);
00647
00648 }
00649 HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690 try
00691 {
00692 HeartEventHandler::BeginEvent(HeartEventHandler::SOLVE_LINEAR_SYSTEM);
00693 PETSCEXCEPT(KSPSolve(mKspSolver, mRhsVector, lhs_vector));
00694 HeartEventHandler::EndEvent(HeartEventHandler::SOLVE_LINEAR_SYSTEM);
00695
00696
00697 KSPConvergedReason reason;
00698 KSPGetConvergedReason(mKspSolver, &reason);
00699 KSPEXCEPT(reason);
00700
00701 #ifdef TRACE_KSP
00702 PetscInt num_it;
00703 KSPGetIterationNumber(mKspSolver, &num_it);
00704 std::cout << "++ Solve: " << mNumSolves << " NumIterations: " << num_it << std::endl << std::flush;
00705
00706 mNumSolves++;
00707 mTotalNumIterations += num_it;
00708 if ((unsigned) num_it > mMaxNumIterations)
00709 {
00710 mMaxNumIterations = num_it;
00711 }
00712 #endif
00713
00714 }
00715 catch (const Exception& e)
00716 {
00717
00718 VecDestroy(lhs_vector);
00719 throw e;
00720 }
00721
00722 return lhs_vector;
00723 }