25#include "system_solvers_large.hpp"
27#include "bitpit_common.hpp"
28#include "bitpit_containers.hpp"
29#include "bitpit_IO.hpp"
30#include "bitpit_operators.hpp"
34#include "petscsystypes.h"
41#include <unordered_set>
44#define PETSC_NULLPTR PETSC_NULL
120 : SystemMatrixAssembler(), m_matrix(matrix)
124#if BITPIT_ENABLE_MPI==1
132 return m_matrix->isPartitioned();
142 return m_matrix->getCommunicator();
155 options.sorted =
false;
184 if (m_transpose == transpose) {
194 VecDestroy(&m_solution);
200 m_transpose = transpose;
210 return m_matrix->getBlockSize();
224 return m_matrix->getRowCount();
238 return m_matrix->getColCount();
271#if BITPIT_ENABLE_MPI==1
297 return m_matrix->getColGlobalCount();
337 return m_matrix->getRowGlobalOffset();
347 return m_matrix->getColGlobalOffset();
389 return m_matrix->getRowNZCount(rowIndex);
399 return m_matrix->getMaxRowNZCount();
414 m_matrix->getRowPattern(rowIndex, pattern);
456 m_matrix->getRowPattern(rowIndex, pattern);
457 m_matrix->getRowValues(rowIndex, values);
472PetscErrorCode PetscManager::displayLogView()
474 return PetscLogView(PETSC_VIEWER_STDOUT_WORLD);
485 throw std::runtime_error(
"Initialization options can be set only before initializing the solver.");
488 m_options.push_back(option);
508 throw std::runtime_error(
"Initialization options can be set only before initializing the solver.");
511 for (
int i = 1; i < argc; ++i) {
512 m_options.push_back(argv[i]);
524 throw std::runtime_error(
"Initialization options can be set only before initializing the solver.");
527 for (
const std::string &option : options) {
528 m_options.push_back(option);
545void PetscManager::enableLogView()
547 if (m_logViewEnabled) {
551#if (PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 7)
552 PetscLogDefaultBegin();
556 PetscRegisterFinalize(&(PetscManager::displayLogView));
557 m_logViewEnabled =
true;
564 : m_externalMPIInitialization(true), m_externalPETScInitialization(true),
565 m_options(std::vector<std::string>(1,
"bitpit")), m_logViewEnabled(false)
584 PetscBool isPetscInitialized;
585 PetscInitialized(&isPetscInitialized);
587 return (!isPetscInitialized);
595#if BITPIT_ENABLE_MPI==1
612 PetscBool isPetscInitialized;
613 PetscInitialized(&isPetscInitialized);
614 if (isPetscInitialized) {
618#if BITPIT_ENABLE_MPI==1
621 MPI_Finalized(&isMPIFinalized);
622 if (isMPIFinalized) {
623 throw std::runtime_error(
"PETSc finalization cannot be called after MPI finaliation.");
631 std::string help =
"None";
632 std::string programName =
"bitpit_petsc_manager";
634 int argc = 1 + m_options.size();
635 char **argv =
new char*[argc + 1];
636 argv[0] = strdup(programName.data());
637 for (std::size_t i = 0; i < m_options.size(); i++) {
638 argv[1 + i] = strdup(m_options[i].data());
640 argv[argc] =
nullptr;
642#if BITPIT_ENABLE_MPI==1
644 int isMPIInitialized;
645 MPI_Initialized(&isMPIInitialized);
646 if (!isMPIInitialized) {
647 MPI_Init(&argc, &argv);
648 m_externalMPIInitialization =
false;
653 PetscInitialize(&argc, &argv, 0, help.data());
654 m_externalPETScInitialization =
false;
662 for (
int i = 0; i < argc; ++i) {
677#if BITPIT_ENABLE_MPI==1
695#if BITPIT_ENABLE_MPI==1
698 MPI_Finalized(&isMPIFinalized);
699 if (isMPIFinalized) {
705 if (m_externalPETScInitialization) {
710 PetscBool isPetscFinalized;
711 PetscFinalized(&isPetscFinalized);
712 if (!isPetscFinalized) {
716#if BITPIT_ENABLE_MPI==1
718 if (!m_externalMPIInitialization) {
723 return (!isPetscFinalized);
745#if BITPIT_ENABLE_MPI==1
763int SystemSolver::m_nInstances = 0;
840 : m_flatten(flatten), m_transpose(transpose),
841 m_A(PETSC_NULLPTR), m_rhs(PETSC_NULLPTR), m_solution(PETSC_NULLPTR),
842 m_rowReordering(PETSC_NULLPTR), m_colReordering(PETSC_NULLPTR),
843 m_convergenceMonitorEnabled(debug),
844 m_KSP(PETSC_NULLPTR), m_KSPDirty(true),
845 m_prefix(prefix), m_assembled(false),
846#if BITPIT_ENABLE_MPI==1
847 m_communicator(MPI_COMM_SELF), m_partitioned(false),
849 m_forceConsistency(false)
852 if (m_nInstances == 0) {
853 m_petscManager.initialize(debug);
887#if BITPIT_ENABLE_MPI==1
934 throw std::runtime_error(
"Unable to assembly the system. The matrix is not yet assembled.");
977void SystemSolver::update(
long nRows,
const long *rows,
const SparseMatrix &elements)
981 throw std::runtime_error(
"Unable to update the system. The element storage is not yet assembled.");
986 update<SystemSolver>(nRows, rows,
static_cast<const Assembler &
>(assembler));
997void SystemSolver::update(
const Assembler &assembler)
1012void SystemSolver::update(
long nRows,
const long *rows,
const Assembler &assembler)
1014 update<SystemSolver>(nRows, rows, assembler);
1024 if (m_A == PETSC_NULLPTR) {
1029 MatGetBlockSize(m_A, &blockSize);
1045 if (m_A == PETSC_NULLPTR) {
1050 MatGetLocalSize(m_A, &nRows, NULL);
1067 if (m_A == PETSC_NULLPTR) {
1072 MatGetLocalSize(m_A, NULL, &nCols);
1089 if (m_A == PETSC_NULLPTR) {
1094 MatGetLocalSize(m_A, &nRows, NULL);
1110 if (m_A == PETSC_NULLPTR) {
1115 MatGetLocalSize(m_A, NULL, &nCols);
1120#if BITPIT_ENABLE_MPI==1
1132 if (m_A == PETSC_NULLPTR) {
1137 MatGetSize(m_A, &nRows, NULL);
1154 if (m_A == PETSC_NULLPTR) {
1159 MatGetSize(m_A, NULL, &nCols);
1175 if (m_A == PETSC_NULLPTR) {
1180 MatGetSize(m_A, &nRows, NULL);
1195 if (m_A == PETSC_NULLPTR) {
1200 MatGetSize(m_A, NULL, &nCols);
1212 return m_partitioned;
1233 throw std::runtime_error(
"Unable to solve the system. The system is not yet assembled.");
1270 PetscErrorCode solverError;
1272 solverError = KSPSolve(m_KSP, m_rhs, m_solution);
1274 solverError = KSPSolveTranspose(m_KSP, m_rhs, m_solution);
1278 const char *petscMessage =
nullptr;
1279 PetscErrorMessage(solverError, &petscMessage, PETSC_NULLPTR);
1280 std::string message =
"Unable to solver the system. " + std::string(petscMessage);
1281 throw std::runtime_error(message);
1297 if (m_forceConsistency) {
1298 removeNullSpaceFromRHS();
1324 const int DUMP_VERSION = 1;
1326 return DUMP_VERSION;
1336 const PetscInt *rowReordering = PETSC_NULLPTR;
1337 if (m_rowReordering) {
1338 ISGetIndices(m_rowReordering, &rowReordering);
1342 int blockSize = assembler.getBlockSize();
1346 MatGetType(m_A, &matrixType);
1349 long nAssemblerRows = assembler.getRowCount();
1351 long nRowsElements = assembler.getRowElementCount();
1352 long nColsElements = assembler.getColElementCount();
1354 long nGlobalRowsElements;
1355 long nGlobalColsElements;
1356#if BITPIT_ENABLE_MPI == 1
1357 nGlobalRowsElements = assembler.getRowGlobalElementCount();
1358 nGlobalColsElements = assembler.getColGlobalElementCount();
1360 nGlobalRowsElements = nRowsElements;
1361 nGlobalColsElements = nColsElements;
1364 MatSetSizes(m_A, nRowsElements, nColsElements, nGlobalRowsElements, nGlobalColsElements);
1371 int allocationExpansion;
1372 if (strcmp(matrixType, MATSEQAIJ) == 0) {
1373 allocationExpansion = blockSize;
1374#if BITPIT_ENABLE_MPI == 1
1375 }
else if (strcmp(matrixType, MATMPIAIJ) == 0) {
1376 allocationExpansion = blockSize;
1379 allocationExpansion = 1;
1382 long nAllocatedRows = allocationExpansion * nAssemblerRows;
1384 std::vector<int> d_nnz(nAllocatedRows, 0);
1385 for (
long n = 0; n < nAssemblerRows; ++n) {
1387 if (rowReordering) {
1388 matrixRow = rowReordering[matrixRow];
1391 int nAssemblerRowNZ = assembler.getRowNZCount(n);
1393 long matrixRowOffset = matrixRow * allocationExpansion;
1394 for (
int i = 0; i < allocationExpansion; ++i) {
1395 d_nnz[matrixRowOffset + i] = allocationExpansion * nAssemblerRowNZ;
1399#if BITPIT_ENABLE_MPI == 1
1400 std::vector<int> o_nnz(nAllocatedRows, 0);
1401 if (m_partitioned) {
1402 long nAssemblerCols = assembler.getColCount();
1404 long assemblerDiagonalBegin = assembler.getColGlobalOffset();
1405 long assemblerDiagonalEnd = assemblerDiagonalBegin + nAssemblerCols;
1407 ConstProxyVector<long> assemblerRowPattern(
static_cast<std::size_t
>(0), assembler.getMaxRowNZCount());
1408 for (
long n = 0; n < nAssemblerRows; ++n) {
1410 if (rowReordering) {
1411 matrixRow = rowReordering[matrixRow];
1414 assembler.getRowPattern(n, &assemblerRowPattern);
1415 int nAssemblerRowNZ = assemblerRowPattern.
size();
1417 long matrixRowOffset = matrixRow * allocationExpansion;
1418 for (
int k = 0; k < nAssemblerRowNZ; ++k) {
1419 long id = assemblerRowPattern[k];
1420 if (id < assemblerDiagonalBegin || id >= assemblerDiagonalEnd) {
1421 for (
int i = 0; i < allocationExpansion; ++i) {
1422 o_nnz[matrixRowOffset + i] += allocationExpansion;
1423 d_nnz[matrixRowOffset + i] -= allocationExpansion;
1431 if (strcmp(matrixType, MATSEQAIJ) == 0) {
1432 MatSeqAIJSetPreallocation(m_A, 0, d_nnz.data());
1433 }
else if (strcmp(matrixType, MATSEQBAIJ) == 0) {
1434 MatSeqBAIJSetPreallocation(m_A, blockSize, 0, d_nnz.data());
1435#if BITPIT_ENABLE_MPI == 1
1436 }
else if (strcmp(matrixType, MATMPIAIJ) == 0) {
1437 MatMPIAIJSetPreallocation(m_A, 0, d_nnz.data(), 0, o_nnz.data());
1438 }
else if (strcmp(matrixType, MATMPIBAIJ) == 0) {
1439 MatMPIBAIJSetPreallocation(m_A, blockSize, 0, d_nnz.data(), 0, o_nnz.data());
1442 throw std::runtime_error(
"Matrix format not supported.");
1446 MatSetOption(m_A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE);
1448#if PETSC_VERSION_GE(3, 12, 0)
1452 MatSetOption(m_A, MAT_SUBSET_OFF_PROC_ENTRIES, PETSC_TRUE);
1456 if (m_rowReordering) {
1457 ISRestoreIndices(m_rowReordering, &rowReordering);
1461 matrixUpdate(assembler.getRowCount(),
nullptr, assembler);
1467 MatSetOption(m_A, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE);
1483 throw std::runtime_error(
"Matrix should be created before filling it.");
1513 if (assembler.getBlockSize() != blockSize) {
1514 std::string message =
"Unable to update the matrix.";
1515 message +=
" The block size of the assembler is not equal to the block size of the system matrix.";
1516 throw std::runtime_error(message);
1520 const PetscInt *rowReordering = PETSC_NULLPTR;
1521 if (m_rowReordering) {
1522 ISGetIndices(m_rowReordering, &rowReordering);
1525 const PetscInt *colReordering = PETSC_NULLPTR;
1526 if (m_colReordering) {
1527 ISGetIndices(m_colReordering, &colReordering);
1531 PetscInt colGlobalBegin;
1532 PetscInt colGlobalEnd;
1533 MatGetOwnershipRangeColumn(m_A, &colGlobalBegin, &colGlobalEnd);
1534 colGlobalBegin /= blockSize;
1535 colGlobalEnd /= blockSize;
1537 PetscInt rowGlobalOffset;
1538 MatGetOwnershipRange(m_A, &rowGlobalOffset, PETSC_NULLPTR);
1539 rowGlobalOffset /= blockSize;
1544#if PETSC_VERSION_GE(3, 12, 0)
1554 PetscBool matrixSortedFull = (assemblyOptions.
full && assemblyOptions.sorted) ? PETSC_TRUE : PETSC_FALSE;
1555 MatSetOption(m_A, MAT_SORTED_FULL, matrixSortedFull);
1574 bool fastUpdate =
isAssembled() && (blockSize == 1) && assemblyOptions.
full && assemblyOptions.sorted;
1581 const long assemblerMaxRowNZ = std::max(assembler.getMaxRowNZCount(), 0L);
1583 bool patternDirectUpdate = !colReordering && (
sizeof(long) ==
sizeof(PetscInt));
1584 bool valuesDirectUpdate = (
sizeof(double) ==
sizeof(PetscScalar));
1586 ConstProxyVector<long> rowPattern;
1587 std::vector<PetscInt> petscRowPatternStorage;
1588 const PetscInt *petscRowPattern;
1589 if (!patternDirectUpdate) {
1591 petscRowPatternStorage.resize(assemblerMaxRowNZ);
1592 petscRowPattern = petscRowPatternStorage.data();
1595 ConstProxyVector<double> rowValues;
1596 std::vector<PetscScalar> petscRowValuesStorage;
1597 const PetscScalar *petscRowValues;
1598 if (!valuesDirectUpdate) {
1599 long assemblerMaxRowNZElements = blockSize * blockSize * assemblerMaxRowNZ;
1601 petscRowValuesStorage.resize(assemblerMaxRowNZElements);
1602 petscRowValues = petscRowValuesStorage.data();
1605 for (
long n = 0; n < nRows; ++n) {
1614 if (rowReordering) {
1615 row = rowReordering[row];
1618 const PetscInt globalRow = rowGlobalOffset + row;
1622 assembler.getRowValues(n, &rowValues);
1624 assembler.getRowData(n, &rowPattern, &rowValues);
1627 if (rowValues.
size() == 0) {
1632 const std::size_t rowPatternSize = rowPattern.
size();
1634 if (valuesDirectUpdate) {
1635 petscRowValues =
reinterpret_cast<const PetscScalar *
>(rowValues.
data());
1637 std::copy(rowValues.
cbegin(), rowValues.
cend(), petscRowValuesStorage.begin());
1641 MatSetValuesRow(m_A, globalRow, petscRowValues);
1644 if (patternDirectUpdate) {
1645 petscRowPattern =
reinterpret_cast<const PetscInt *
>(rowPattern.
data());
1647 for (std::size_t k = 0; k < rowPatternSize; ++k) {
1648 long globalCol = rowPattern[k];
1649 if (colReordering) {
1650 if (globalCol >= colGlobalBegin && globalCol < colGlobalEnd) {
1651 long col = globalCol - colGlobalBegin;
1652 col = colReordering[col];
1653 globalCol = colGlobalBegin + col;
1657 petscRowPatternStorage[k] = globalCol;
1662 if (blockSize > 1) {
1663 MatSetValuesBlocked(m_A, 1, &globalRow, rowPatternSize, petscRowPattern, petscRowValues, INSERT_VALUES);
1665 MatSetValues(m_A, 1, &globalRow, rowPatternSize, petscRowPattern, petscRowValues, INSERT_VALUES);
1671 MatAssemblyBegin(m_A, MAT_FINAL_ASSEMBLY);
1672 MatAssemblyEnd(m_A, MAT_FINAL_ASSEMBLY);
1675 if (rowReordering) {
1676 ISRestoreIndices(m_rowReordering, &rowReordering);
1679 if (colReordering) {
1680 ISRestoreIndices(m_colReordering, &colReordering);
1692 const std::string &prefix)
const
1706#if BITPIT_ENABLE_MPI==1
1713 const std::string &prefix,
bool redistribute)
1716 const std::string &prefix)
1721#if BITPIT_ENABLE_MPI==1
1744 MatCreateVecs(m_A, &m_solution, &m_rhs);
1746 MatCreateVecs(m_A, &m_rhs, &m_solution);
1764 if (!solution.empty()) {
1779 if (!rhsFilePath.empty()) {
1783 if (!solutionFilePath.empty()) {
1812 const std::string &prefix)
const
1816 dumpVector(m_rhs, directory, prefix +
"rhs");
1817 dumpVector(m_solution, directory, prefix +
"solution");
1828 const std::string &prefix)
1832 restoreVector(directory, prefix +
"rhs", m_A, VECTOR_SIDE_RIGHT, &m_rhs);
1833 restoreVector(directory, prefix +
"solution", m_A, VECTOR_SIDE_LEFT, &m_solution);
1852 PetscScalar *raw_rhs;
1853 VecGetArray(m_rhs, &raw_rhs);
1875 const PetscScalar *raw_rhs;
1876 VecGetArrayRead(m_rhs, &raw_rhs);
1889 VecRestoreArray(m_rhs, &raw_rhs);
1900 VecRestoreArrayRead(m_rhs, &raw_rhs);
1910 PetscScalar *raw_solution;
1911 VecGetArray(m_solution, &raw_solution);
1913 return raw_solution;
1933 const PetscScalar *raw_solution;
1934 VecGetArrayRead(m_solution, &raw_solution);
1936 return raw_solution;
1947 VecRestoreArray(m_solution, &raw_solution);
1958 VecRestoreArrayRead(m_solution, &raw_solution);
1986 throw std::runtime_error(
"Matrix should be created before filling it.");
2030 throw std::runtime_error(
"The RHS vector can be loaded only after assembling the system.");
2038 VecGetLocalSize(m_rhs, &size);
2040 PetscInt expectedSize;
2048 if (size != expectedSize) {
2049 log::cout() <<
"The imported RHS vector is not compatible with the matrix" << std::endl;
2050 log::cout() <<
"The size of the imported RHS vector is " << size << std::endl;
2051 log::cout() <<
"The expected size of RHS vector is " << expectedSize << std::endl;
2052 throw std::runtime_error(
"The imported RHS vector is not compatible with the matrix");
2083 throw std::runtime_error(
"The solution vector can be loaded only after assembling the system.");
2091 VecGetLocalSize(m_solution, &size);
2093 PetscInt expectedSize;
2101 if (size != expectedSize) {
2102 log::cout() <<
"The imported solution vector is not compatible with the matrix" << std::endl;
2103 log::cout() <<
"The size of the imported solution vector is " << size << std::endl;
2104 log::cout() <<
"The expected size of solution vector is " << expectedSize << std::endl;
2105 throw std::runtime_error(
"The imported solution vector is not compatible with the matrix");
2121 const std::string &prefix)
const
2123 int partitioningBlock = getBinaryArchiveBlock();
2127 if (partitioningBlock <= 0) {
2128 openBinaryArchive(header, directory, prefix +
"info", -1, &systemArchive);
2130 std::ostream &systemStream = systemArchive.
getStream();
2142 closeBinaryArchive(&systemArchive);
2155#if BITPIT_ENABLE_MPI==1
2167#if BITPIT_ENABLE_MPI==1
2169 const std::string &directory,
const std::string &prefix)
2177#if BITPIT_ENABLE_MPI == 1
2179 setCommunicator(communicator);
2184 openBinaryArchive(directory, prefix +
"info", -1, &systemArchive);
2185 std::istream &systemStream = systemArchive.
getStream();
2191#if BITPIT_ENABLE_MPI==1
2192 matrixRestore(systemStream, directory, prefix, redistribute);
2201 closeBinaryArchive(&systemArchive);
2220 if (systemStream.good()) {
2221#if BITPIT_ENABLE_MPI==1
2235#if BITPIT_ENABLE_MPI == 1
2257#if BITPIT_ENABLE_MPI == 1
2258 MatCreate(m_communicator, matrix);
2260 MatCreate(PETSC_COMM_SELF, matrix);
2264 bool creatBlockMatrix =
false;
2266 creatBlockMatrix =
false;
2268 creatBlockMatrix = (rowBlockSize == colBlockSize) && (rowBlockSize != 1);
2271#if BITPIT_ENABLE_MPI == 1
2272 if (m_partitioned) {
2273 if (creatBlockMatrix) {
2274 MatSetType(*matrix, MATMPIBAIJ);
2276 MatSetType(*matrix, MATMPIAIJ);
2281 if (creatBlockMatrix) {
2282 MatSetType(*matrix, MATSEQBAIJ);
2284 MatSetType(*matrix, MATSEQAIJ);
2289 if (rowBlockSize == colBlockSize) {
2290 MatSetBlockSize(*matrix, rowBlockSize);
2291 }
else if (rowBlockSize != 1 || colBlockSize != 1) {
2292 MatSetBlockSizes(*matrix, rowBlockSize, colBlockSize);
2310 Mat *subMatrices, Mat *matrix)
const
2313#if BITPIT_ENABLE_MPI == 1
2314 MatCreateNest(
getCommunicator(), nNestRows, PETSC_NULLPTR, nNestCols, PETSC_NULLPTR, subMatrices, matrix);
2316 MatCreateNest(PETSC_COMM_SELF, nNestRows, PETSC_NULLPTR, nNestCols, PETSC_NULLPTR, subMatrices, matrix);
2320 if (rowBlockSize == colBlockSize) {
2321 MatSetBlockSize(*matrix, rowBlockSize);
2322 }
else if (rowBlockSize != 1 || colBlockSize != 1) {
2323 MatSetBlockSizes(*matrix, rowBlockSize, colBlockSize);
2339 std::ifstream fileStream(filePath.c_str());
2340 if (!fileStream.good()) {
2341 throw std::runtime_error(
"The PETSc matrix file \"" + filePath +
"\" doesn't exists.");
2347#if BITPIT_ENABLE_MPI==1
2348 PetscViewerCreate(m_communicator, &viewer);
2350 PetscViewerCreate(PETSC_COMM_SELF, &viewer);
2352 PetscViewerSetType(viewer, PETSCVIEWERBINARY);
2353 PetscViewerFileSetMode(viewer, FILE_MODE_READ);
2354 PetscViewerFileSetName(viewer, filePath.c_str());
2355 MatLoad(matrix, viewer);
2356 PetscViewerDestroy(&viewer);
2366#if BITPIT_ENABLE_MPI==1
2380 int partitioningBlock = getBinaryArchiveBlock();
2384 if (partitioningBlock <= 0) {
2385 openBinaryArchive(
"", directory, name +
".info", -1, &infoArchive);
2386 std::ostream &infoStream = infoArchive.
getStream();
2388 bool matrixExists = matrix;
2390 if (!matrixExists) {
2391 closeBinaryArchive(&infoArchive);
2395 PetscInt rowBlockSize;
2396 PetscInt colBlockSize;
2397 MatGetBlockSizes(matrix, &rowBlockSize, &colBlockSize);
2401 closeBinaryArchive(&infoArchive);
2408#if BITPIT_ENABLE_MPI==1
2412 openBinaryArchive(
"", directory, name +
".partitioning", partitioningBlock, &partitioningArchive);
2413 std::ostream &partitioningStream = partitioningArchive.
getStream();
2415 PetscInt nLocalRows;
2416 PetscInt nLocalCols;
2417 MatGetLocalSize(matrix, &nLocalRows, &nLocalCols);
2421 PetscInt nGlobalRows;
2422 PetscInt nGlobalCols;
2423 MatGetSize(matrix, &nGlobalRows, &nGlobalCols);
2427 closeBinaryArchive(&partitioningArchive);
2442#if BITPIT_ENABLE_MPI==1
2452#if BITPIT_ENABLE_MPI==1
2454 bool redistribute, Mat *matrix)
const
2464 openBinaryArchive(directory, name +
".info", -1, &infoArchive);
2465 std::istream &infoStream = infoArchive.
getStream();
2469 if (!matrixExists) {
2470 *matrix = PETSC_NULLPTR;
2471 closeBinaryArchive(&infoArchive);
2481 closeBinaryArchive(&infoArchive);
2483#if BITPIT_ENABLE_MPI==1
2486 int partitioningBlock = getBinaryArchiveBlock();
2489 openBinaryArchive(directory, name +
".partitioning", partitioningBlock, &partitioningArchive);
2490 std::istream &partitioningStream = partitioningArchive.
getStream();
2492 std::size_t nLocalRows;
2493 std::size_t nLocalCols;
2496 std::size_t nGlobalRows;
2497 std::size_t nGlobalCols;
2500 MatSetSizes(*matrix, nLocalRows, nLocalCols, nGlobalRows, nGlobalCols);
2502 closeBinaryArchive(&partitioningArchive);
2522 bool matrixExists = matrix;
2523 if (!matrixExists) {
2524 std::ofstream dataFile(filePath);
2527 std::ofstream infoFile(filePath +
".info");
2534 PetscViewerType viewerType;
2535 PetscViewerFormat viewerFormat;
2536 if (fileFormat == FILE_BINARY) {
2537 viewerType = PETSCVIEWERBINARY;
2538 viewerFormat = PETSC_VIEWER_DEFAULT;
2540 viewerType = PETSCVIEWERASCII;
2541 viewerFormat = PETSC_VIEWER_ASCII_MATLAB;
2544 PetscViewer matViewer;
2545#if BITPIT_ENABLE_MPI==1
2546 PetscViewerCreate(m_communicator, &matViewer);
2548 PetscViewerCreate(PETSC_COMM_SELF, &matViewer);
2550 PetscViewerSetType(matViewer, viewerType);
2551 PetscViewerFileSetMode(matViewer, FILE_MODE_WRITE);
2552 PetscViewerPushFormat(matViewer, viewerFormat);
2553 PetscViewerFileSetName(matViewer, filePath.c_str());
2556 MatView(matrix, matViewer);
2559 PetscViewerDestroy(&matViewer);
2571 *matrix = PETSC_NULLPTR;
2584#if BITPIT_ENABLE_MPI == 1
2585 VecCreate(m_communicator, vector);
2587 VecCreate(PETSC_COMM_SELF, vector);
2591#if BITPIT_ENABLE_MPI == 1
2592 if (m_partitioned) {
2593 VecSetType(*vector, VECMPI);
2597 VecSetType(*vector, VECSEQ);
2601 if (blockSize != 1) {
2602 VecSetBlockSize(*vector, blockSize);
2617#if BITPIT_ENABLE_MPI == 1
2618 VecCreateNest(
getCommunicator(), nestSize, PETSC_NULLPTR, subVectors, vector);
2620 VecCreateNest(PETSC_COMM_SELF, nestSize, PETSC_NULLPTR, subVectors, vector);
2624 if (blockSize != 1) {
2625 VecSetBlockSize(*vector, blockSize);
2641 std::ifstream fileStream(filePath);
2642 if (!fileStream.good()) {
2643 throw std::runtime_error(
"The file \"" + filePath +
"\" cannot be read.");
2649#if BITPIT_ENABLE_MPI==1
2650 PetscViewerCreate(m_communicator, &viewer);
2652 PetscViewerCreate(PETSC_COMM_SELF, &viewer);
2654 PetscViewerSetType(viewer, PETSCVIEWERBINARY);
2655 PetscViewerFileSetMode(viewer, FILE_MODE_READ);
2656 PetscViewerFileSetName(viewer, filePath.c_str());
2657 VecLoad(vector, viewer);
2658 PetscViewerDestroy(&viewer);
2670 VecGetLocalSize(vector, &size);
2672 PetscScalar *petscData;
2673 VecGetArray(vector, &petscData);
2674 for (
int i = 0; i < size; ++i) {
2675 petscData[i] = data[i];
2677 VecRestoreArray(vector, &petscData);
2687#if BITPIT_ENABLE_MPI==1
2701 int partitioningBlock = getBinaryArchiveBlock();
2704 if (partitioningBlock <= 0) {
2706 openBinaryArchive(
"", directory, name +
".info", -1, &infoArchive);
2707 std::ostream &infoStream = infoArchive.
getStream();
2709 bool vectorExists = vector;
2711 if (!vectorExists) {
2712 closeBinaryArchive(&infoArchive);
2717 VecGetBlockSize(vector, &blockSize);
2720 closeBinaryArchive(&infoArchive);
2727#if BITPIT_ENABLE_MPI==1
2730 int partitioningBlock = getBinaryArchiveBlock();
2733 openBinaryArchive(
"", directory, name +
".partitioning", partitioningBlock, &partitioningArchive);
2734 std::ostream &partitioningStream = partitioningArchive.
getStream();
2737 VecGetLocalSize(vector, &localSize);
2740 PetscInt globalSize;
2741 VecGetSize(vector, &globalSize);
2744 closeBinaryArchive(&partitioningArchive);
2764 Mat matrix, VectorSide side, Vec *vector)
const
2767 PetscInt nLocalRows;
2768 PetscInt nLocalCols;
2769 MatGetLocalSize(matrix, &nLocalRows, &nLocalCols);
2771 PetscInt nGlobalRows;
2772 PetscInt nGlobalCols;
2773 MatGetSize(matrix, &nGlobalRows, &nGlobalCols);
2775 std::size_t localSize = std::numeric_limits<std::size_t>::max();
2776 std::size_t globalSize = std::numeric_limits<std::size_t>::max();
2778 if (side == VECTOR_SIDE_RIGHT) {
2779 localSize = nLocalCols;
2780 globalSize = nGlobalCols;
2781 }
else if (side == VECTOR_SIDE_LEFT) {
2782 localSize = nLocalRows;
2783 globalSize = nGlobalRows;
2786 if (side == VECTOR_SIDE_RIGHT) {
2787 localSize = nLocalRows;
2788 globalSize = nGlobalRows;
2789 }
else if (side == VECTOR_SIDE_LEFT) {
2790 localSize = nLocalCols;
2791 globalSize = nGlobalCols;
2796 restoreVector(directory, name, localSize, globalSize, vector);
2805#if BITPIT_ENABLE_MPI==1
2815#if BITPIT_ENABLE_MPI==1
2817 bool redistribute, Vec *vector)
const
2825 std::size_t localSize = std::numeric_limits<std::size_t>::max();
2826 std::size_t globalSize = std::numeric_limits<std::size_t>::max();
2827#if BITPIT_ENABLE_MPI==1
2829 if (!redistribute) {
2830 int partitioningBlock = getBinaryArchiveBlock();
2833 openBinaryArchive(directory, name +
".partitioning", partitioningBlock, &partitioningArchive);
2834 std::istream &partitioningStream = partitioningArchive.
getStream();
2839 closeBinaryArchive(&partitioningArchive);
2844 restoreVector(directory, name, localSize, globalSize, vector);
2857 std::size_t localSize, std::size_t globalSize, Vec *vector)
const
2861 openBinaryArchive(directory, name +
".info", -1, &infoArchive);
2862 std::istream &infoStream = infoArchive.
getStream();
2866 if (!vectorExists) {
2867 *vector = PETSC_NULLPTR;
2868 closeBinaryArchive(&infoArchive);
2876 closeBinaryArchive(&infoArchive);
2879 PetscInt petscLocalSize;
2880 if (localSize != std::numeric_limits<std::size_t>::max()) {
2881 petscLocalSize =
static_cast<PetscInt
>(localSize);
2883 petscLocalSize = PETSC_DECIDE;
2886 PetscInt petscGlobalSize;
2887 if (globalSize != std::numeric_limits<std::size_t>::max()) {
2888 petscGlobalSize =
static_cast<PetscInt
>(globalSize);
2890 petscGlobalSize = PETSC_DETERMINE;
2893 if (petscLocalSize != PETSC_DECIDE || petscGlobalSize != PETSC_DETERMINE) {
2894 VecSetSizes(*vector, petscLocalSize, petscGlobalSize);
2909 if (!permutations) {
2913 PetscBool petscInvert;
2915 petscInvert = PETSC_TRUE;
2917 petscInvert = PETSC_FALSE;
2920 VecPermute(vector, permutations, petscInvert);
2934 bool vectorExists = vector;
2935 if (!vectorExists) {
2936 std::ofstream dataFile(filePath);
2939 std::ofstream infoFile(filePath +
".info");
2946 PetscViewerType viewerType;
2947 PetscViewerFormat viewerFormat;
2948 if (fileFormat == FILE_BINARY) {
2949 viewerType = PETSCVIEWERBINARY;
2950 viewerFormat = PETSC_VIEWER_DEFAULT;
2952 viewerType = PETSCVIEWERASCII;
2953 viewerFormat = PETSC_VIEWER_ASCII_MATLAB;
2957#if BITPIT_ENABLE_MPI==1
2958 PetscViewerCreate(m_communicator, &viewer);
2960 PetscViewerCreate(PETSC_COMM_SELF, &viewer);
2962 PetscViewerSetType(viewer, viewerType);
2963 PetscViewerFileSetMode(viewer, FILE_MODE_WRITE);
2964 PetscViewerPushFormat(viewer, viewerFormat);
2965 PetscViewerFileSetName(viewer, filePath.c_str());
2968 VecView(vector, viewer);
2971 PetscViewerDestroy(&viewer);
2983 VecGetLocalSize(m_solution, &size);
2985 const PetscScalar *vectorData;
2986 VecGetArrayRead(m_solution, &vectorData);
2987 for (
int i = 0; i < size; ++i) {
2988 (*data)[i] = vectorData[i];
2990 VecRestoreArrayRead(vector, &vectorData);
3002 *vector = PETSC_NULLPTR;
3039 std::string path = directory +
"/" + name;
3049 MatNullSpace nullspace;
3050#if BITPIT_ENABLE_MPI==1
3051 MatNullSpaceCreate(m_communicator, PETSC_TRUE, 0, NULL, &nullspace);
3053 MatNullSpaceCreate(PETSC_COMM_SELF, PETSC_TRUE, 0, NULL, &nullspace);
3055 MatSetNullSpace(m_A, nullspace);
3056 MatNullSpaceDestroy(&nullspace);
3064 MatSetNullSpace(m_A, NULL);
3093 }
catch(
const std::bad_cast &exception) {
3100 PetscInt *rowReorderingStorage;
3101 PetscMalloc(nRows *
sizeof(PetscInt), &rowReorderingStorage);
3102 for (
long i = 0; i < nRows; ++i) {
3106#if BITPIT_ENABLE_MPI == 1
3107 ISCreateGeneral(m_communicator, nRows, rowReorderingStorage, PETSC_OWN_POINTER, &m_rowReordering);
3109 ISCreateGeneral(PETSC_COMM_SELF, nRows, rowReorderingStorage, PETSC_OWN_POINTER, &m_rowReordering);
3111 ISSetPermutation(m_rowReordering);
3114 PetscInt *colReorderingStorage;
3115 PetscMalloc(nCols *
sizeof(PetscInt), &colReorderingStorage);
3116 for (
long j = 0; j < nCols; ++j) {
3120#if BITPIT_ENABLE_MPI == 1
3121 ISCreateGeneral(m_communicator, nCols, colReorderingStorage, PETSC_OWN_POINTER, &m_colReordering);
3123 ISCreateGeneral(PETSC_COMM_SELF, nCols, colReorderingStorage, PETSC_OWN_POINTER, &m_colReordering);
3125 ISSetPermutation(m_colReordering);
3136 if (m_rowReordering) {
3137 ISDestroy(&m_rowReordering);
3140 if (m_colReordering) {
3141 ISDestroy(&m_colReordering);
3152 throw std::runtime_error(
"Unable to solve the system. The system is not yet assembled.");
3161 bool setupNeeded =
false;
3168 KSPSetOperators(m_KSP, m_A, m_A);
3177 KSPGetPC(m_KSP, &pc);
3178 PCSetFromOptions(pc);
3190 KSPSetFromOptions(m_KSP);
3220#if BITPIT_ENABLE_MPI==1
3221 KSPCreate(m_communicator, &m_KSP);
3223 KSPCreate(PETSC_COMM_SELF, &m_KSP);
3227 if (!m_prefix.empty()) {
3228 KSPSetOptionsPrefix(m_KSP, m_prefix.c_str());
3239 m_KSP = PETSC_NULLPTR;
3248 KSPGetPC(m_KSP, &pc);
3262#if BITPIT_ENABLE_MPI == 1
3272 PCSetType(pc, pcType);
3275 if (strcmp(pcType, PCASM) == 0) {
3276 if (options.overlap != PETSC_DEFAULT) {
3277 PCASMSetOverlap(pc, options.overlap);
3279 }
else if (strcmp(pcType, PCILU) == 0) {
3280 if (options.
levels != PETSC_DEFAULT) {
3281 PCFactorSetLevels(pc, options.
levels);
3287 if (strcmp(pcType, PCASM) == 0) {
3290 PCASMGetSubKSP(pc, &nSubKSPs, PETSC_NULLPTR, &subKSPs);
3292 for (PetscInt i = 0; i < nSubKSPs; ++i) {
3293 KSP subKSP = subKSPs[i];
3294 KSPSetType(subKSP, KSPPREONLY);
3297 KSPGetPC(subKSP, &subPC);
3298 PCSetType(subPC, PCILU);
3299 if (options.
levels != PETSC_DEFAULT) {
3300 PCFactorSetLevels(subPC, options.
levels);
3342 KSPSetType(ksp, KSPFGMRES);
3343 if (options.
restart != PETSC_DEFAULT) {
3344 KSPGMRESSetRestart(ksp, options.
restart);
3346 if (options.
rtol != PETSC_DEFAULT || options.
atol != PETSC_DEFAULT || options.
maxits != PETSC_DEFAULT) {
3347 KSPSetTolerances(ksp, options.
rtol, options.
atol, PETSC_DEFAULT, options.
maxits);
3358 if (m_convergenceMonitorEnabled) {
3359#if (PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 7)
3360 PetscOptionsSetValue(PETSC_NULLPTR, (
"-" + m_prefix +
"ksp_monitor_true_residual").c_str(),
"");
3361 PetscOptionsSetValue(PETSC_NULLPTR, (
"-" + m_prefix +
"ksp_monitor_singular_value").c_str(),
"");
3362 PetscOptionsSetValue(PETSC_NULLPTR, (
"-" + m_prefix +
"ksp_converged_reason").c_str(),
"");
3364 PetscOptionsSetValue((
"-" + m_prefix +
"ksp_monitor_true_residual").c_str(),
"");
3365 PetscOptionsSetValue((
"-" + m_prefix +
"ksp_monitor_singular_value").c_str(),
"");
3366 PetscOptionsSetValue((
"-" + m_prefix +
"ksp_converged_reason").c_str(),
"");
3388 throw std::runtime_error(
"The options associated with the Krylov solver can only be accessed after assembling the system.");
3391 return m_KSPOptions;
3404 throw std::runtime_error(
"The options associated with the Krylov solver can only be accessed after assembling the system.");
3407 return m_KSPOptions;
3446 throw std::runtime_error(
"The status of the Krylov solver can only be accessed after assembling the system.");
3477 KSPGetIterationNumber(ksp, &(status->its));
3478 KSPGetConvergedReason(ksp, &(status->convergence));
3498 status->convergence = KSP_CONVERGED_ITERATING;
3509#if BITPIT_ENABLE_MPI==1
3517 return m_communicator;
3526void SystemSolver::setCommunicator(MPI_Comm communicator)
3528 if ((communicator != MPI_COMM_NULL) && (communicator != MPI_COMM_SELF)) {
3529 MPI_Comm_dup(communicator, &m_communicator);
3531 m_communicator = MPI_COMM_SELF;
3538void SystemSolver::freeCommunicator()
3540 if (m_communicator != MPI_COMM_SELF) {
3541 int finalizedCalled;
3542 MPI_Finalized(&finalizedCalled);
3543 if (!finalizedCalled) {
3544 MPI_Comm_free(&m_communicator);
3556void SystemSolver::removeNullSpaceFromRHS()
3559 MatNullSpace nullspace;
3560 MatGetNullSpace(m_A, &nullspace);
3563 MatNullSpaceRemove(nullspace, m_rhs);
3574 return m_forceConsistency;
3585 m_forceConsistency = enable;
3600void SystemSolver::openBinaryArchive(
const std::string &directory,
const std::string &prefix,
3605 std::string path =
getFilePath(directory, prefix);
3606 archive->
open(path,
"dat", block);
3607 bool versionsMatch = archive->
checkVersion(expectedVersion);
3608 if (!versionsMatch) {
3609 std::string message =
"Version stored in binary archive " + path +
" does not match";
3610 message +=
" the expected version " + std::to_string(expectedVersion) +
".";
3612 throw std::runtime_error(message);
3629void SystemSolver::openBinaryArchive(
const std::string &header,
const std::string &directory,
3630 const std::string &prefix,
int block, OBinaryArchive *archive)
const
3633 std::string path =
getFilePath(directory, prefix);
3634 archive->open(path,
"dat", version, header, block);
3642void SystemSolver::closeBinaryArchive(BinaryArchive *archive)
const
3652int SystemSolver::getBinaryArchiveBlock()
const
3654#if BITPIT_ENABLE_MPI == 1
3658 if (nProcesses <= 1) {
3665 return archiveBlock;
bool checkVersion(int version)
void open(const std::string &name, int block=-1)
std::istream & getStream()
The NaturalSystemMatrixOrdering class defines allows to use a matrix natural ordering.
long getColPermutationRank(long col) const override
long getRowPermutationRank(long row) const override
std::ostream & getStream()
The PetscManager class handles the interaction with PETSc library.
bool initialize(bool debug)
bool areOptionsEditable() const
void addInitOptions(int argc, char **args)
void addInitOption(const std::string &option)
static constexpr __PXV_POINTER__ INTERNAL_STORAGE
__PXV_CONST_ITERATOR__ cend()
__PXV_POINTER__ data() noexcept
__PXV_CONST_ITERATOR__ cbegin()
void set(__PXV_POINTER__ data, std::size_t size)
ConstProxyVector< double > getRowValues(long row) const
long getRowGlobalCount() const
The SystemMatrixOrdering class provides an interface for defining classes that allows to reorder the ...
virtual long getColPermutationRank(long col) const =0
virtual long getRowPermutationRank(long row) const =0
void dumpMatrix(Mat matrix, const std::string &directory, const std::string &name) const
virtual void vectorsCreate()
void matrixUpdate(long nRows, const long *rows, const Assembler &assembler)
double * getSolutionRawPtr()
long getRowGlobalElementCount() const
bool isPartitioned() const
virtual int getDumpVersion() const
virtual void exportMatrix(const std::string &filePath, FileFormat exportFormat=FILE_BINARY) const
virtual void matrixFill(const std::string &filePath)
virtual void initializeKSPOptions()
virtual void prePreconditionerSetupActions()
void restoreSolutionRawPtr(double *raw_solution)
virtual void matrixRestore(std::istream &systemStream, const std::string &directory, const std::string &prefix, bool redistribute)
void fillMatrix(Mat matrix, const std::string &filePath) const
void restoreRHSRawReadPtr(const double *raw_rhs) const
void dumpVector(Vec vector, const std::string &directory, const std::string &name) const
virtual void postPreconditionerSetupActions()
virtual void importMatrix(const std::string &filePath)
virtual void initializeKSPStatus()
void reorderVector(Vec vector, IS permutations, bool invert) const
virtual void finalizeKSP()
std::string getInfoFilePath(const std::string &directory, const std::string &name) const
virtual void vectorsDump(std::ostream &systemStream, const std::string &directory, const std::string &prefix) const
virtual void resetKSPOptions(KSPOptions *options) const
void exportVector(Vec vector, const std::string &filePath, FileFormat fileFormat) const
void dumpSystem(const std::string &header, const std::string &directory, const std::string &prefix="") const
virtual void destroyKSPOptions()
virtual void clearWorkspace()
void setReordering(long nRows, long nCols, const SystemMatrixOrdering &reordering)
virtual void prepareKSP()
virtual void restoreInfo(std::istream &stream)
virtual void setNullSpace()
virtual void preKSPSolveActions()
virtual void setupKrylov()
virtual void postKrylovSetupActions()
long getColGlobalCount() const
void restoreSystem(MPI_Comm communicator, bool redistribute, const std::string &directory, const std::string &prefix="")
const double * getSolutionRawReadPtr() const
bool getTranspose() const
virtual void exportRHS(const std::string &filePath, FileFormat exportFormat=FILE_BINARY) const
virtual int getBlockSize() const
void restoreRHSRawPtr(double *raw_rhs)
void setTranspose(bool transpose)
const KSPStatus & getKSPStatus() const
void restoreMatrix(const std::string &directory, const std::string &name, bool redistribute, Mat *matrix) const
void matrixAssembly(const Assembler &assembler)
void createVector(int blockSize, Vec *vector) const
void destroyMatrix(Mat *matrix) const
std::string getFilePath(const std::string &directory, const std::string &name) const
long getColElementCount() const
virtual void matrixDump(std::ostream &systemStream, const std::string &directory, const std::string &prefix) const
virtual void dumpInfo(std::ostream &stream) const
void assembly(const SparseMatrix &matrix)
virtual void destroyKSP()
virtual void postKSPSolveActions()
const MPI_Comm & getCommunicator() const
virtual void fillKSPStatus()
std::string getDataFilePath(const std::string &directory, const std::string &name) const
const double * getRHSRawReadPtr() const
virtual void preKrylovSetupActions()
virtual void importSolution(const std::string &filePath)
virtual void resetKSPStatus()
SystemSolver(bool debug=false)
virtual void importRHS(const std::string &filePath)
void destroyVector(Vec *vector) const
void createMatrix(int rowBlockSize, int colBlockSize, Mat *matrix) const
void fillVector(Vec vector, const std::string &filePath) const
virtual void matrixDestroy()
virtual void destroyKSPStatus()
virtual void vectorsFill(const std::vector< double > &rhs, const std::vector< double > &solution)
virtual void vectorsDestroy()
virtual void setupPreconditioner()
void enableForceConsistency(bool enable)
long getRowGlobalCount() const
void restoreSolutionRawReadPtr(const double *raw_solution) const
bool isForceConsistencyEnabled() const
KSPOptions & getKSPOptions()
long getRowElementCount() const
virtual void vectorsReorder(bool invert)
virtual void vectorsRestore(std::istream &systemStream, const std::string &directory, const std::string &prefix)
long getColGlobalElementCount() const
void restoreVector(const std::string &directory, const std::string &name, Mat matrix, VectorSide side, Vec *vector) const
virtual void exportSolution(const std::string &filePath, FileFormat exportFormat=FILE_BINARY) const
The SystemSparseMatrixAssembler class defines an assembler for building the system matrix form a spar...
long getColGlobalCount() const override
long getRowGlobalCount() const override
void getRowValues(long rowIndex, ConstProxyVector< double > *values) const override
const MPI_Comm & getCommunicator() const override
long getRowElementCount() const override
long getColGlobalElementCount() const override
long getMaxRowNZCount() const override
long getRowGlobalElementCount() const override
void getRowData(long rowIndex, ConstProxyVector< long > *pattern, ConstProxyVector< double > *values) const override
long getRowNZCount(long rowIndex) const override
long getRowGlobalOffset() const override
long getRowCount() const override
bool isPartitioned() const override
AssemblyOptions getOptions() const override
long getColGlobalOffset() const override
long getColGlobalElementOffset() const override
void getRowPattern(long rowIndex, ConstProxyVector< long > *pattern) const override
long getColCount() const override
long getRowGlobalElementOffset() const override
long getColElementCount() const override
int getBlockSize() const override
SystemSparseMatrixAssembler(const SparseMatrix *matrix)
void write(std::ostream &stream, const std::vector< bool > &container)
void read(std::istream &stream, std::vector< bool > &container)
#define BITPIT_UNUSED(variable)
Logger & cout(log::Level defaultSeverity, log::Visibility defaultVisibility)
PetscInt levels
Overlap between a pair of subdomains for the partitioned preconditioner.
PetscInt restart
Tells the iterative solver that the initial guess is nonzero.
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.
bool full
Controls if the assembler is providing all the non-zero values of a row.