This example shows how to dump and restore a SystemSolver.
This example shows how to dump and restore a SystemSolver.This example builds a small linear system, it dumps it to the disk, it solves the linear system and it exports the solution to disk. Dump files will be saved in the current directory and they names are: LA_example_0001_linear_system_A.dat LA_example_0001_linear_system_A.dat.info LA_example_0001_linear_system_A.info.dat LA_example_0001_linear_system_A.partitioning.bXXXX.dat LA_example_0001_linear_system_info.dat LA_example_0001_linear_system_rhs.dat LA_example_0001_linear_system_rhs.dat.info LA_example_0001_linear_system_rhs.info.dat LA_example_0001_linear_system_rhs.partitioning.bXXXX.dat LA_example_0001_linear_system_solution.dat LA_example_0001_linear_system_solution.dat.info LA_example_0001_linear_system_solution.info.dat LA_example_0001_linear_system_solution.partitioning.bXXXX.dat
This example contains an extension of the bare SystemSolver class adding the ability to solve using algebraic multigrid (PETSc GAMG) preconditioner. Only non-block matrices can be solved using GAMG. A check disables algebraic multigrid for block matrices with a message in the logger.
#include <array>
#if BITPIT_ENABLE_MPI==1
#include <mpi.h>
#endif
#include "bitpit_common.hpp"
#include "bitpit_LA.hpp"
using namespace bitpit;
public:
m_multigrid(multigrid)
{
}
protected:
const static PetscInt GAMG_MAX_LEVELS;
const static PetscReal GAMG_THRESHOLD;
const static PetscReal GAMG_THRESHOLD_SCALE;
bool m_multigrid;
{
if (!m_multigrid) {
SystemSolver::setupPreconditioner(pc, options);
return;
}
KSPGetPC(this->m_KSP, &pc);
PCSetType(pc, PCGAMG);
std::vector<PetscReal> thresholds(GAMG_MAX_LEVELS);
for (int i = 0; i < GAMG_MAX_LEVELS; ++i) {
thresholds[i] = GAMG_THRESHOLD;
}
PCGAMGSetNSmooths(pc, 0);
#if (PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR <= 17)
#if BITPIT_ENABLE_MPI == 1
PCGAMGSetSymGraph(pc, PETSC_TRUE);
}
#endif
#endif
PCGAMGSetNlevels(pc, GAMG_MAX_LEVELS);
#if (PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 16)
PCGAMGSetThreshold(pc, thresholds.data(), GAMG_MAX_LEVELS);
PCGAMGSetThresholdScale(pc, GAMG_THRESHOLD_SCALE);
#else
PCGAMGSetThreshold(pc, GAMG_THRESHOLD);
#endif
PCSetUp(pc);
KSP coarseKSP;
PCMGGetCoarseSolve(pc, &coarseKSP);
PC coarsePreconditioner;
KSPGetPC(coarseKSP, &coarsePreconditioner);
PCSetType(coarsePreconditioner, PCSVD);
}
};
const PetscInt AMGSystemSolver::GAMG_MAX_LEVELS = 10;
const PetscReal AMGSystemSolver::GAMG_THRESHOLD = 0.02;
const PetscReal AMGSystemSolver::GAMG_THRESHOLD_SCALE = 1.0;
int run_dump(int rank, int nProcs)
{
log::cout() << std::endl;
log::cout() << "Running dump example..." << std::endl;
int nRows;
int nCols;
int nNZ;
if (nProcs == 1) {
nRows = 10;
nCols = 10;
nNZ = 10;
} else if (nProcs == 2) {
if (rank == 0) {
nRows = 6;
nCols = 6;
nNZ = 6;
} if (rank == 1) {
nRows = 4;
nCols = 4;
nNZ = 4;
}
} else {
if (rank == 0) {
nRows = 2;
nCols = 2;
nNZ = 2;
} if (rank == 1) {
nRows = 5;
nCols = 5;
nNZ = 5;
} if (rank == 2) {
nRows = 3;
nCols = 3;
nNZ = 3;
} else {
nRows = 0;
nCols = 0;
nNZ = 0;
}
}
int blockSize = 5;
log::cout() << "Building matrix..." << std::endl;
std::vector<long> rowPattern(1);
std::vector<double> rowValues(blockSize * blockSize);
#if BITPIT_ENABLE_MPI==1
SparseMatrix matrix(MPI_COMM_WORLD,
true, blockSize, nRows, nCols, nNZ);
int rowOffset = matrix.getRowGlobalOffset();
int colOffset = matrix.getColGlobalOffset();
#else
int rowOffset = 0;
int colOffset = 0;
#endif
for (int i = 0; i < nRows; ++i) {
rowPattern[0] = colOffset + i;
for (int k = 0; k < blockSize; ++k) {
int kk = linearalgebra::linearIndexRowMajor(k, k, blockSize, blockSize);
rowValues[kk] = 1. / (double) (blockSize * (rowOffset + i) + k + 1);
}
matrix.addRow(rowPattern, rowValues);
}
matrix.assembly();
log::cout() << "Building solver..." << std::endl;
bool multigrid = true;
solver.assembly(matrix);
double *rhs = solver.getRHSRawPtr();
for (int i = 0; i < blockSize * nCols; ++i) {
rhs[i] = 1.;
}
solver.restoreRHSRawPtr(rhs);
double *initialSolution = solver.getSolutionRawPtr();
for (int i = 0; i < nRows; ++i) {
initialSolution[i] = 0;
}
solver.restoreSolutionRawPtr(initialSolution);
solver.exportMatrix("LA_example_0001_matrix.txt", SystemSolver::FILE_ASCII);
solver.exportRHS("LA_example_0001_rhs.txt", SystemSolver::FILE_ASCII);
solver.exportSolution("LA_example_0001_solution.txt", SystemSolver::FILE_ASCII);
log::cout() << "Dumping initialized linear system..." << std::endl;
solver.dumpSystem("bitpit linear system", ".", "LA_example_0001_linear_system_");
log::cout() << "Solve linear system..." << std::endl;
solver.solve();
const KSPStatus &status = solver.getKSPStatus();
log::cout() <<
"Reason: " << status.
convergence <<
" in its: " << status.
its << std::endl;
log::cout() << "Linear system solved." << std::endl;
log::cout() << "Export solution..." << std::endl;
solver.exportSolution("LA_example_0001_linear_system_solution.dat", bitpit::SystemSolver::FILE_BINARY);
log::cout() << "Comparing solutions..." << std::endl;
const double TOLERANCE = options.
rtol;
log::cout() <<
" Tolerance = " << options.
rtol << std::endl;
std::size_t nRowElements = solver.getRowElementCount();
bool isSolutionCorrect = true;
const double *solution = solver.getSolutionRawReadPtr();
for (std::size_t i = 0; i < nRowElements; ++i) {
std::size_t globalDOF = rowOffset * blockSize + i;
double expectedSolution = static_cast<double>(globalDOF + 1);
std::stringstream message;
message << "Solutions do not match for global DOF #" << globalDOF << ".";
message << " Expected solution is " << expectedSolution;
message << ", current solution is " << solution[i] << ".";
log::cout() << message.str() << std::endl;
isSolutionCorrect = false;
}
}
solver.restoreSolutionRawReadPtr(solution);
if (isSolutionCorrect) {
log::cout() << "Solutions match." << std::endl;
}
return 0;
}
int run_restore(int rank, int nProcs)
{
log::cout() << std::endl;
log::cout() << "Running restore example..." << std::endl;
log::cout() << "Restoring linear system ..." << std::endl;
bool multigrid = true;
#if BITPIT_ENABLE_MPI==1
solver.restoreSystem(MPI_COMM_WORLD, false, ".", "LA_example_0001_linear_system_");
#else
solver.restoreSystem(".", "LA_example_0001_linear_system_");
#endif
log::cout() << "Linear system restored." << std::endl;
solver.exportMatrix("LA_example_0001_restored_matrix.txt", SystemSolver::FILE_ASCII);
solver.exportRHS("LA_example_0001_restored_rhs.txt", SystemSolver::FILE_ASCII);
solver.exportSolution("LA_example_0001_restored_solution.txt", SystemSolver::FILE_ASCII);
log::cout() << "Solving linear system..." << std::endl;
solver.solve();
const KSPStatus &status = solver.getKSPStatus();
log::cout() << "Reason: " << status.convergence << " in its: " << status.its << std::endl;
log::cout() << "Linear system solved." << std::endl;
bool compareSolutions = true;
if (compareSolutions) {
log::cout() << "Storing computed solution for comparison..." << std::endl;
std::size_t nRowElements = solver.getRowElementCount();
std::vector<double> expectedSolution(nRowElements, 0.0);
double *computedSolution = solver.getSolutionRawPtr();
for (std::size_t i = 0; i < nRowElements; ++i) {
expectedSolution[i] = computedSolution[i];
}
solver.restoreSolutionRawPtr(computedSolution);
log::cout() << "Restoring solution..." << std::endl;
solver.importSolution("LA_example_0001_linear_system_solution.dat");
log::cout() << "Solution restored." << std::endl;
log::cout() << "Comparing solutions..." << std::endl;
const double TOLERANCE = options.
rtol;
log::cout() <<
" Tolerance = " << options.
rtol << std::endl;
bool isSolutionCorrect = true;
const double *solution = solver.getSolutionRawReadPtr();
for (std::size_t i = 0; i < nRowElements; ++i) {
std::stringstream message;
message << "Solutions do not match for local DOF #" << i << ".";
message << " Expected solution is " << expectedSolution[i];
message << ", current solution is " << solution[i] << ".";
log::cout() << message.str() << std::endl;
isSolutionCorrect = false;
}
}
solver.restoreSolutionRawReadPtr(solution);
if (isSolutionCorrect) {
log::cout() << "Solutions match." << std::endl;
}
}
return 0;
}
int main(int argc, char *argv[])
{
#if BITPIT_ENABLE_MPI==1
MPI_Init(&argc, &argv);
#else
#endif
int nProcs;
int rank;
#if BITPIT_ENABLE_MPI==1
MPI_Comm_size(MPI_COMM_WORLD, &nProcs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
#else
rank = 0;
nProcs = 1;
#endif
log::manager().initialize(log::COMBINED, true, nProcs, rank);
log::cout().setDefaultVisibility(log::GLOBAL);
log::cout() << "Build, dump, solve and restore linear system" << std::endl;
int status;
try {
status = run_dump(rank, nProcs);
if (status != 0) {
return status;
}
status = run_restore(rank, nProcs);
if (status != 0) {
return status;
}
} catch (const std::exception &exception) {
log::cout() << exception.what();
exit(1);
}
#if BITPIT_ENABLE_MPI==1
MPI_Finalize();
#endif
}
The class AMGSystemSolver is derived form SystemSolver and it allows to solve the linear system using...
AMGSystemSolver(bool transpose, bool multigrid, bool debug)
The SystemSolver class provides methods for building and solving large linear systems.
bool isPartitioned() const
SystemSolver(bool debug=false)
virtual void setupPreconditioner()
#define BITPIT_UNUSED(variable)
void transpose(std::vector< std::vector< T > > &, std::vector< std::vector< T > > &)
Logger & debug(log::Visibility defaultVisibility)
PetscInt maxits
Number of iterations at which the GMRES method restarts.
PetscScalar atol
Relative convergence tolerance, relative decrease in the preconditioned residual norm.
PetscScalar rtol
Maximum number of iterations.
PetscBool initial_non_zero
Number of levels of fill used by the preconditioner.