Loading...
Searching...
No Matches
system_solvers_large.cpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6 *
7 * -------------------------------------------------------------------------
8 * License
9 * This file is part of bitpit.
10 *
11 * bitpit is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License v3 (LGPL)
13 * as published by the Free Software Foundation.
14 *
15 * bitpit is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 * License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with bitpit. If not, see <http://www.gnu.org/licenses/>.
22 *
23\*---------------------------------------------------------------------------*/
24
25#include "system_solvers_large.hpp"
26
27#include "bitpit_common.hpp"
28#include "bitpit_containers.hpp"
29#include "bitpit_IO.hpp"
30#include "bitpit_operators.hpp"
31
32#include "petscksp.h"
33#include "petscmat.h"
34#include "petscsystypes.h"
35#include "petscvec.h"
36
37#include <fstream>
38#include <stdexcept>
39#include <string>
40#include <numeric>
41#include <unordered_set>
42
43#ifndef PETSC_NULLPTR
44#define PETSC_NULLPTR PETSC_NULL
45#endif
46
47namespace bitpit {
48
59
67
79{
80 return row;
81}
82
94{
95 return col;
96}
97
105
113
120 : SystemMatrixAssembler(), m_matrix(matrix)
121{
122}
123
124#if BITPIT_ENABLE_MPI==1
131{
132 return m_matrix->isPartitioned();
133}
134
141{
142 return m_matrix->getCommunicator();
143}
144#endif
145
152{
153 AssemblyOptions options;
154 options.full = true;
155 options.sorted = false;
156
157 return options;
158}
159
166{
167 return m_transpose;
168}
169
181void SystemSolver::setTranspose(bool transpose)
182{
183 // Early return if the transpose flag is already correctly set.
184 if (m_transpose == transpose) {
185 return;
186 }
187
188 // Clear the workspace
190
191 // Re-create the vectors
192 if (isAssembled()) {
193 VecDestroy(&m_rhs);
194 VecDestroy(&m_solution);
195
197 }
198
199 // Set the flag
200 m_transpose = transpose;
201}
202
209{
210 return m_matrix->getBlockSize();
211}
212
223{
224 return m_matrix->getRowCount();
225}
226
237{
238 return m_matrix->getColCount();
239}
240
250{
251 long nRowElements = getBlockSize() * getRowCount();
252
253 return nRowElements;
254}
255
265{
266 long nColElements = getBlockSize() * getColCount();
267
268 return nColElements;
271#if BITPIT_ENABLE_MPI==1
272/**
273 * Get number of global (block) rows handled by the assembler.
275 * If the matrix is a block matrix (i.e., the block size is greater than one),
276 * this function will return the global number of block rows, where a block row
277 * is defined as a group of block-size matrix rows.
278 *
279 * \result The number of global rows handled by the assembler.
280 */
282{
283 return m_matrix->getRowGlobalCount();
286/**
287 * Get number of global (block) columns handled by the assembler.
288 *
289 * If the matrix is a block matrix (i.e., the block size is greater than one),
290 * this function will return the global number of block columns, where a block
291 * column is defined as a group of block-size matrix columns.
292 *
293 * \result The number of global (block) columns handled by the assembler.
294 */
296{
297 return m_matrix->getColGlobalCount();
298}
299
309{
310 long nElements = getBlockSize() * getRowGlobalCount();
311
312 return nElements;
313}
314
324{
325 long nElements = getBlockSize() * getColGlobalCount();
326
327 return nElements;
328}
329
336{
337 return m_matrix->getRowGlobalOffset();
338}
339
346{
347 return m_matrix->getColGlobalOffset();
348}
349
359{
360 long offset = getBlockSize() * getRowGlobalOffset();
361
362 return offset;
363}
364
374{
375 long offset = getBlockSize() * getColGlobalOffset();
376
377 return offset;
378}
379#endif
380
388{
389 return m_matrix->getRowNZCount(rowIndex);
390}
391
398{
399 return m_matrix->getMaxRowNZCount();
400}
401
411 */
412void SystemSparseMatrixAssembler::getRowPattern(long rowIndex, ConstProxyVector<long> *pattern) const
413{
414 m_matrix->getRowPattern(rowIndex, pattern);
415}
426 * \param rowIndex is the index of the row in the assembler
427 * \param values on output will contain the values of the specified (block) row.
428 * If the block size is greater than one, values will be stored in a logically
429 * two-dimensional array that uses a col-major order
430 */
431void SystemSparseMatrixAssembler::getRowValues(long rowIndex, ConstProxyVector<double> *values) const
433 m_matrix->getRowValues(rowIndex, values);
434}
435
448 * \param rowIndex is the index of the row in the assembler
449 * \param pattern on output will contain the pattern of the specified (block) row
450 * \param values on output will contain the values of the specified (block) row.
451 * If the block size is greater than one, values will be stored in a logically
452 * two-dimensional array that uses a col-major order
453 */
454void SystemSparseMatrixAssembler::getRowData(long rowIndex, ConstProxyVector<long> *pattern, ConstProxyVector<double> *values) const
455{
456 m_matrix->getRowPattern(rowIndex, pattern);
457 m_matrix->getRowValues(rowIndex, values);
458}
459
466
472PetscErrorCode PetscManager::displayLogView()
473{
474 return PetscLogView(PETSC_VIEWER_STDOUT_WORLD);
475}
476
482void PetscManager::addInitOption(const std::string &option)
483{
484 if (!areOptionsEditable()) {
485 throw std::runtime_error("Initialization options can be set only before initializing the solver.");
486 }
487
488 m_options.push_back(option);
489}
490
505void PetscManager::addInitOptions(int argc, char **argv)
506{
507 if (!areOptionsEditable()) {
508 throw std::runtime_error("Initialization options can be set only before initializing the solver.");
509 }
510
511 for (int i = 1; i < argc; ++i) {
512 m_options.push_back(argv[i]);
513 }
514}
515
521void PetscManager::addInitOptions(const std::vector<std::string> &options)
522{
523 if (!areOptionsEditable()) {
524 throw std::runtime_error("Initialization options can be set only before initializing the solver.");
525 }
526
527 for (const std::string &option : options) {
528 m_options.push_back(option);
529 }
530}
531
536{
537 m_options.clear();
538}
539
545void PetscManager::enableLogView()
546{
547 if (m_logViewEnabled) {
548 return;
549 }
550
551#if (PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 7)
552 PetscLogDefaultBegin();
553#else
554 PetscLogBegin();
555#endif
556 PetscRegisterFinalize(&(PetscManager::displayLogView));
557 m_logViewEnabled = true;
558}
559
564 : m_externalMPIInitialization(true), m_externalPETScInitialization(true),
565 m_options(std::vector<std::string>(1, "bitpit")), m_logViewEnabled(false)
566{
567}
568
576
583{
584 PetscBool isPetscInitialized;
585 PetscInitialized(&isPetscInitialized);
586
587 return (!isPetscInitialized);
588}
589
595#if BITPIT_ENABLE_MPI==1
600#endif
610{
611 // Early return if PETSc is already initialized
612 PetscBool isPetscInitialized;
613 PetscInitialized(&isPetscInitialized);
614 if (isPetscInitialized) {
615 return false;
616 }
617
618#if BITPIT_ENABLE_MPI==1
619 // Early return if MPI is already finalized
620 int isMPIFinalized;
621 MPI_Finalized(&isMPIFinalized);
622 if (isMPIFinalized) {
623 throw std::runtime_error("PETSc finalization cannot be called after MPI finaliation.");
624 }
625#endif
626
627 // Generate command line arguments
628 //
629 // The first argument is the executable name and it is set to a
630 // dummy value.
631 std::string help = "None";
632 std::string programName = "bitpit_petsc_manager";
633
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());
639 }
640 argv[argc] = nullptr;
641
642#if BITPIT_ENABLE_MPI==1
643 // Initialize MPI
644 int isMPIInitialized;
645 MPI_Initialized(&isMPIInitialized);
646 if (!isMPIInitialized) {
647 MPI_Init(&argc, &argv);
648 m_externalMPIInitialization = false;
649 }
650#endif
651
652 // Initialize PETSc
653 PetscInitialize(&argc, &argv, 0, help.data());
654 m_externalPETScInitialization = false;
655
656 // Enable log view
657 if (debug) {
658 enableLogView();
659 }
660
661 // Clean-up command line arguments
662 for (int i = 0; i < argc; ++i) {
663 free(argv[i]);
664 }
665
666 delete[] argv;
667
668 // Initialization completed
669 return true;
670}
671
677#if BITPIT_ENABLE_MPI==1
683#else
688#endif
694{
695#if BITPIT_ENABLE_MPI==1
696 // Early return if MPI is already finalized
697 int isMPIFinalized;
698 MPI_Finalized(&isMPIFinalized);
699 if (isMPIFinalized) {
700 return false;
701 }
702#endif
703
704 // Early return if PETSc was initialized externally
705 if (m_externalPETScInitialization) {
706 return false;
707 }
708
709 // Finalize PETSc
710 PetscBool isPetscFinalized;
711 PetscFinalized(&isPetscFinalized);
712 if (!isPetscFinalized) {
713 PetscFinalize();
714 }
715
716#if BITPIT_ENABLE_MPI==1
717 // Finalize MPI
718 if (!m_externalMPIInitialization) {
719 MPI_Finalize();
720 }
721#endif
722
723 return (!isPetscFinalized);
724}
725
745#if BITPIT_ENABLE_MPI==1
754#else
759#endif
760
761PetscManager SystemSolver::m_petscManager = PetscManager();
762
763int SystemSolver::m_nInstances = 0;
764
771 : SystemSolver("", false, false, debug)
772{
773}
774
781SystemSolver::SystemSolver(bool transpose, bool debug)
782 : SystemSolver("", false, transpose, debug)
783{
784}
785
786
799SystemSolver::SystemSolver(bool flatten, bool transpose, bool debug)
800 : SystemSolver("", flatten, transpose, debug)
801{
802}
803
810SystemSolver::SystemSolver(const std::string &prefix, bool debug)
811 : SystemSolver(prefix, false, debug)
812{
813}
814
821SystemSolver::SystemSolver(const std::string &prefix, bool transpose, bool debug)
822 : SystemSolver(prefix, false, transpose, debug)
823{
824}
825
839SystemSolver::SystemSolver(const std::string &prefix, bool flatten, bool transpose, bool debug)
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),
848#endif
849 m_forceConsistency(false)
850{
851 // Initialize PETSc
852 if (m_nInstances == 0) {
853 m_petscManager.initialize(debug);
854 }
855
856 // Increase the number of instances
857 ++m_nInstances;
858}
859
864{
865 // Clear the solver
866 clear();
867
868 // Decrease the number of instances
869 --m_nInstances;
870}
871
876{
878
881
884
886
887#if BITPIT_ENABLE_MPI==1
888 freeCommunicator();
889#endif
890
891 m_assembled = false;
892}
893
900{
901 // Early return if the KSP has not been created
902 if (!m_KSP) {
903 return;
904 }
905
906 // Destroy the KSP
907 destroyKSP();
908}
909
918{
920}
921
930void SystemSolver::assembly(const SparseMatrix &matrix, const SystemMatrixOrdering &reordering)
931{
932 // Check if the matrix is assembled
933 if (!matrix.isAssembled()) {
934 throw std::runtime_error("Unable to assembly the system. The matrix is not yet assembled.");
935 }
936
937 // Assembly the system matrix
938 SystemSparseMatrixAssembler assembler(&matrix);
939 assembly<SystemSolver>(static_cast<const Assembler &>(assembler), reordering);
940}
941
949void SystemSolver::assembly(const Assembler &assembler)
950{
952}
953
962void SystemSolver::assembly(const Assembler &assembler, const SystemMatrixOrdering &reordering)
963{
964 assembly<SystemSolver>(assembler, reordering);
965}
966
977void SystemSolver::update(long nRows, const long *rows, const SparseMatrix &elements)
978{
979 // Check if the element storage is assembled
980 if (!elements.isAssembled()) {
981 throw std::runtime_error("Unable to update the system. The element storage is not yet assembled.");
982 }
983
984 // Update matrix
985 SystemSparseMatrixAssembler assembler(&elements);
986 update<SystemSolver>(nRows, rows, static_cast<const Assembler &>(assembler));
987}
988
997void SystemSolver::update(const Assembler &assembler)
998{
999 update(getRowCount(), nullptr, assembler);
1000}
1001
1012void SystemSolver::update(long nRows, const long *rows, const Assembler &assembler)
1013{
1014 update<SystemSolver>(nRows, rows, assembler);
1015}
1016
1023{
1024 if (m_A == PETSC_NULLPTR) {
1025 return 0;
1026 }
1027
1028 PetscInt blockSize;
1029 MatGetBlockSize(m_A, &blockSize);
1030
1031 return blockSize;
1032}
1033
1044{
1045 if (m_A == PETSC_NULLPTR) {
1046 return 0;
1047 }
1048
1049 PetscInt nRows;
1050 MatGetLocalSize(m_A, &nRows, NULL);
1051 nRows /= getBlockSize();
1052
1053 return nRows;
1054}
1055
1066{
1067 if (m_A == PETSC_NULLPTR) {
1068 return 0;
1069 }
1070
1071 PetscInt nCols;
1072 MatGetLocalSize(m_A, NULL, &nCols);
1073 nCols /= getBlockSize();
1074
1075 return nCols;
1076}
1077
1088{
1089 if (m_A == PETSC_NULLPTR) {
1090 return 0;
1091 }
1092
1093 PetscInt nRows;
1094 MatGetLocalSize(m_A, &nRows, NULL);
1095
1096 return nRows;
1097}
1098
1109{
1110 if (m_A == PETSC_NULLPTR) {
1111 return 0;
1112 }
1113
1114 PetscInt nCols;
1115 MatGetLocalSize(m_A, NULL, &nCols);
1116
1117 return nCols;
1118}
1119
1120#if BITPIT_ENABLE_MPI==1
1131{
1132 if (m_A == PETSC_NULLPTR) {
1133 return 0;
1134 }
1135
1136 PetscInt nRows;
1137 MatGetSize(m_A, &nRows, NULL);
1138 nRows /= getBlockSize();
1139
1140 return nRows;
1141}
1142
1153{
1154 if (m_A == PETSC_NULLPTR) {
1155 return 0;
1156 }
1157
1158 PetscInt nCols;
1159 MatGetSize(m_A, NULL, &nCols);
1160 nCols /= getBlockSize();
1161
1162 return nCols;
1163}
1164
1174{
1175 if (m_A == PETSC_NULLPTR) {
1176 return 0;
1177 }
1178
1179 PetscInt nRows;
1180 MatGetSize(m_A, &nRows, NULL);
1181
1182 return nRows;
1183}
1184
1194{
1195 if (m_A == PETSC_NULLPTR) {
1196 return 0;
1197 }
1198
1199 PetscInt nCols;
1200 MatGetSize(m_A, NULL, &nCols);
1201
1202 return nCols;
1203}
1204
1211{
1212 return m_partitioned;
1213}
1214#endif
1215
1222{
1223 return m_assembled;
1224}
1225
1230{
1231 // Check if the system is assembled
1232 if (!isAssembled()) {
1233 throw std::runtime_error("Unable to solve the system. The system is not yet assembled.");
1234 }
1235
1236 // Perform actions before KSP solution
1238
1239 // Solve KSP
1240 solveKSP();
1241
1242 // Perform actions after KSP solution
1244}
1245
1253void SystemSolver::solve(const std::vector<double> &rhs, std::vector<double> *solution)
1254{
1255 // Fills the vectors
1256 vectorsFill(rhs, *solution);
1257
1258 // Solve the system
1259 solve();
1260
1261 // Export the solution
1262 exportVector(m_solution, solution);
1263}
1264
1269{
1270 PetscErrorCode solverError;
1271 if (!m_transpose) {
1272 solverError = KSPSolve(m_KSP, m_rhs, m_solution);
1273 } else {
1274 solverError = KSPSolveTranspose(m_KSP, m_rhs, m_solution);
1275 }
1276
1277 if (solverError) {
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);
1282 }
1283}
1284
1289{
1290 // Prepare KSP
1291 prepareKSP();
1292
1293 // Reorder vectors
1294 vectorsReorder(true);
1295
1296 // Force consistency
1297 if (m_forceConsistency) {
1298 removeNullSpaceFromRHS();
1299 }
1300}
1301
1306{
1307 // Fill status of KSP
1308 fillKSPStatus();
1309
1310 // Reorder vectors
1311 vectorsReorder(false);
1312
1313 // Finalize KSP
1314 finalizeKSP();
1315}
1316
1323{
1324 const int DUMP_VERSION = 1;
1325
1326 return DUMP_VERSION;
1327}
1328
1334void SystemSolver::matrixAssembly(const Assembler &assembler)
1335{
1336 const PetscInt *rowReordering = PETSC_NULLPTR;
1337 if (m_rowReordering) {
1338 ISGetIndices(m_rowReordering, &rowReordering);
1339 }
1340
1341 // Create the matrix
1342 int blockSize = assembler.getBlockSize();
1343 createMatrix(blockSize, blockSize, &m_A);
1344
1345 MatType matrixType;
1346 MatGetType(m_A, &matrixType);
1347
1348 // Get sizes
1349 long nAssemblerRows = assembler.getRowCount();
1350
1351 long nRowsElements = assembler.getRowElementCount();
1352 long nColsElements = assembler.getColElementCount();
1353
1354 long nGlobalRowsElements;
1355 long nGlobalColsElements;
1356#if BITPIT_ENABLE_MPI == 1
1357 nGlobalRowsElements = assembler.getRowGlobalElementCount();
1358 nGlobalColsElements = assembler.getColGlobalElementCount();
1359#else
1360 nGlobalRowsElements = nRowsElements;
1361 nGlobalColsElements = nColsElements;
1362#endif
1363
1364 MatSetSizes(m_A, nRowsElements, nColsElements, nGlobalRowsElements, nGlobalColsElements);
1365
1366 // Allocate storage
1367 //
1368 // When the internal storage of the system matrix was created without taking into account
1369 // block information, preallocation information should be provided for each row of each
1370 // block.
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;
1377#endif
1378 } else {
1379 allocationExpansion = 1;
1380 }
1381
1382 long nAllocatedRows = allocationExpansion * nAssemblerRows;
1383
1384 std::vector<int> d_nnz(nAllocatedRows, 0);
1385 for (long n = 0; n < nAssemblerRows; ++n) {
1386 long matrixRow = n;
1387 if (rowReordering) {
1388 matrixRow = rowReordering[matrixRow];
1389 }
1390
1391 int nAssemblerRowNZ = assembler.getRowNZCount(n);
1392
1393 long matrixRowOffset = matrixRow * allocationExpansion;
1394 for (int i = 0; i < allocationExpansion; ++i) {
1395 d_nnz[matrixRowOffset + i] = allocationExpansion * nAssemblerRowNZ;
1396 }
1397 }
1398
1399#if BITPIT_ENABLE_MPI == 1
1400 std::vector<int> o_nnz(nAllocatedRows, 0);
1401 if (m_partitioned) {
1402 long nAssemblerCols = assembler.getColCount();
1403
1404 long assemblerDiagonalBegin = assembler.getColGlobalOffset();
1405 long assemblerDiagonalEnd = assemblerDiagonalBegin + nAssemblerCols;
1406
1407 ConstProxyVector<long> assemblerRowPattern(static_cast<std::size_t>(0), assembler.getMaxRowNZCount());
1408 for (long n = 0; n < nAssemblerRows; ++n) {
1409 long matrixRow = n;
1410 if (rowReordering) {
1411 matrixRow = rowReordering[matrixRow];
1412 }
1413
1414 assembler.getRowPattern(n, &assemblerRowPattern);
1415 int nAssemblerRowNZ = assemblerRowPattern.size();
1416
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;
1424 }
1425 }
1426 }
1427 }
1428 }
1429#endif
1430
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());
1440#endif
1441 } else {
1442 throw std::runtime_error("Matrix format not supported.");
1443 }
1444
1445 // Each process will only set values for its own rows
1446 MatSetOption(m_A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE);
1447
1448#if PETSC_VERSION_GE(3, 12, 0)
1449 // The first assembly will set a superset of the off-process entries
1450 // required for all subsequent assemblies. This avoids a rendezvous
1451 // step in the MatAssembly functions.
1452 MatSetOption(m_A, MAT_SUBSET_OFF_PROC_ENTRIES, PETSC_TRUE);
1453#endif
1454
1455 // Cleanup
1456 if (m_rowReordering) {
1457 ISRestoreIndices(m_rowReordering, &rowReordering);
1458 }
1459
1460 // Fill matrix
1461 matrixUpdate(assembler.getRowCount(), nullptr, assembler);
1462
1463 // No new allocations are now allowed
1464 //
1465 // When updating the matrix it will not be possible to alter the pattern,
1466 // it will be possible to change only the values.
1467 MatSetOption(m_A, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE);
1468}
1469
1479void SystemSolver::matrixFill(const std::string &filePath)
1480{
1481 // Check if the matrix exists
1482 if (!m_A) {
1483 throw std::runtime_error("Matrix should be created before filling it.");
1484 }
1485
1486 // Fill the matrix
1487 fillMatrix(m_A, filePath);
1488}
1489
1506void SystemSolver::matrixUpdate(long nRows, const long *rows, const Assembler &assembler)
1507{
1508 // Updating the matrix invalidates the KSP
1509 m_KSPDirty = true;
1510
1511 // Get block size
1512 const int blockSize = getBlockSize();
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);
1517 }
1518
1519 // Initialize reordering
1520 const PetscInt *rowReordering = PETSC_NULLPTR;
1521 if (m_rowReordering) {
1522 ISGetIndices(m_rowReordering, &rowReordering);
1523 }
1524
1525 const PetscInt *colReordering = PETSC_NULLPTR;
1526 if (m_colReordering) {
1527 ISGetIndices(m_colReordering, &colReordering);
1528 }
1529
1530 // Global information
1531 PetscInt colGlobalBegin;
1532 PetscInt colGlobalEnd;
1533 MatGetOwnershipRangeColumn(m_A, &colGlobalBegin, &colGlobalEnd);
1534 colGlobalBegin /= blockSize;
1535 colGlobalEnd /= blockSize;
1536
1537 PetscInt rowGlobalOffset;
1538 MatGetOwnershipRange(m_A, &rowGlobalOffset, PETSC_NULLPTR);
1539 rowGlobalOffset /= blockSize;
1540
1541 // Get the options for assembling the matrix
1542 SystemMatrixAssembler::AssemblyOptions assemblyOptions = assembler.getOptions();
1543
1544#if PETSC_VERSION_GE(3, 12, 0)
1545 // Check if it is possible to speedup insertion of values
1546 //
1547 // The option MAT_SORTED_FULL means that each process provides exactly its
1548 // local rows; all column indices for a given row are passed in a single call
1549 // to MatSetValues(), preallocation is perfect, row oriented, INSERT_VALUES
1550 // is used. If this options is set to PETSC_TRUE, the function MatSetValues
1551 // will be faster.
1552 //
1553 // This options needs at least PETSc 3.12.
1554 PetscBool matrixSortedFull = (assemblyOptions.full && assemblyOptions.sorted) ? PETSC_TRUE : PETSC_FALSE;
1555 MatSetOption(m_A, MAT_SORTED_FULL, matrixSortedFull);
1556#endif
1557
1558 // Check if it possible to perform a fast update
1559 //
1560 // A fast update allows to set all the values of a row at once (without
1561 // the need to get the row pattern), it can be performed if:
1562 // - the system matrix has already been assembled;
1563 // - the system matrix has a unitary block size;
1564 // - the assembler is providing all the values of the row;
1565 // - values provided by the assembler are sorted by ascending column.
1566 //
1567 // If fast update is used, row values will be set using a special PETSc
1568 // function (MatSetValuesRow) that allows to set all the values of a
1569 // row at once, without requiring the pattern of the row.
1570 //
1571 // Fast update is not related to the option MAT_SORTED_FULL, that option
1572 // is used to speedup the standard function MatSetValues (which still
1573 // requires the pattern of the row).
1574 bool fastUpdate = isAssembled() && (blockSize == 1) && assemblyOptions.full && assemblyOptions.sorted;
1575
1576 // Update element values
1577 //
1578 // If the sizes of PETSc data types match the sizes of data types expected by
1579 // bitpit a direct update can be performed, otherwise the matrix is updated
1580 // using intermediate data storages.
1581 const long assemblerMaxRowNZ = std::max(assembler.getMaxRowNZCount(), 0L);
1582
1583 bool patternDirectUpdate = !colReordering && (sizeof(long) == sizeof(PetscInt));
1584 bool valuesDirectUpdate = (sizeof(double) == sizeof(PetscScalar));
1585
1586 ConstProxyVector<long> rowPattern;
1587 std::vector<PetscInt> petscRowPatternStorage;
1588 const PetscInt *petscRowPattern;
1589 if (!patternDirectUpdate) {
1590 rowPattern.set(ConstProxyVector<long>::INTERNAL_STORAGE, 0, assemblerMaxRowNZ);
1591 petscRowPatternStorage.resize(assemblerMaxRowNZ);
1592 petscRowPattern = petscRowPatternStorage.data();
1593 }
1594
1595 ConstProxyVector<double> rowValues;
1596 std::vector<PetscScalar> petscRowValuesStorage;
1597 const PetscScalar *petscRowValues;
1598 if (!valuesDirectUpdate) {
1599 long assemblerMaxRowNZElements = blockSize * blockSize * assemblerMaxRowNZ;
1600 rowValues.set(ConstProxyVector<double>::INTERNAL_STORAGE, 0, assemblerMaxRowNZElements);
1601 petscRowValuesStorage.resize(assemblerMaxRowNZElements);
1602 petscRowValues = petscRowValuesStorage.data();
1603 }
1604
1605 for (long n = 0; n < nRows; ++n) {
1606 // Get row information
1607 long row;
1608 if (rows) {
1609 row = rows[n];
1610 } else {
1611 row = n;
1612 }
1613
1614 if (rowReordering) {
1615 row = rowReordering[row];
1616 }
1617
1618 const PetscInt globalRow = rowGlobalOffset + row;
1619
1620 // Get row data
1621 if (fastUpdate) {
1622 assembler.getRowValues(n, &rowValues);
1623 } else {
1624 assembler.getRowData(n, &rowPattern, &rowValues);
1625 }
1626
1627 if (rowValues.size() == 0) {
1628 continue;
1629 }
1630
1631 // Get values in PETSc format
1632 const std::size_t rowPatternSize = rowPattern.size();
1633
1634 if (valuesDirectUpdate) {
1635 petscRowValues = reinterpret_cast<const PetscScalar *>(rowValues.data());
1636 } else {
1637 std::copy(rowValues.cbegin(), rowValues.cend(), petscRowValuesStorage.begin());
1638 }
1639
1640 if (fastUpdate) {
1641 MatSetValuesRow(m_A, globalRow, petscRowValues);
1642 } else {
1643 // Get pattern in PETSc format
1644 if (patternDirectUpdate) {
1645 petscRowPattern = reinterpret_cast<const PetscInt *>(rowPattern.data());
1646 } else {
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;
1654 }
1655 }
1656
1657 petscRowPatternStorage[k] = globalCol;
1658 }
1659 }
1660
1661 // Set data
1662 if (blockSize > 1) {
1663 MatSetValuesBlocked(m_A, 1, &globalRow, rowPatternSize, petscRowPattern, petscRowValues, INSERT_VALUES);
1664 } else {
1665 MatSetValues(m_A, 1, &globalRow, rowPatternSize, petscRowPattern, petscRowValues, INSERT_VALUES);
1666 }
1667 }
1668 }
1669
1670 // Let petsc assembly the matrix after the update
1671 MatAssemblyBegin(m_A, MAT_FINAL_ASSEMBLY);
1672 MatAssemblyEnd(m_A, MAT_FINAL_ASSEMBLY);
1673
1674 // Cleanup
1675 if (rowReordering) {
1676 ISRestoreIndices(m_rowReordering, &rowReordering);
1677 }
1678
1679 if (colReordering) {
1680 ISRestoreIndices(m_colReordering, &colReordering);
1681 }
1682}
1683
1691void SystemSolver::matrixDump(std::ostream &systemStream, const std::string &directory,
1692 const std::string &prefix) const
1693{
1694 BITPIT_UNUSED(systemStream);
1695
1696 dumpMatrix(m_A, directory, prefix + "A");
1697}
1698
1706#if BITPIT_ENABLE_MPI==1
1712void SystemSolver::matrixRestore(std::istream &systemStream, const std::string &directory,
1713 const std::string &prefix, bool redistribute)
1714#else
1715void SystemSolver::matrixRestore(std::istream &systemStream, const std::string &directory,
1716 const std::string &prefix)
1717#endif
1718{
1719 BITPIT_UNUSED(systemStream);
1720
1721#if BITPIT_ENABLE_MPI==1
1722 restoreMatrix(directory, prefix + "A", redistribute, &m_A);
1723#else
1724 restoreMatrix(directory, prefix + "A", &m_A);
1725#endif
1726}
1727
1732{
1733 destroyMatrix(&m_A);
1734}
1735
1742{
1743 if (!m_transpose) {
1744 MatCreateVecs(m_A, &m_solution, &m_rhs);
1745 } else {
1746 MatCreateVecs(m_A, &m_rhs, &m_solution);
1747 }
1748}
1749
1758void SystemSolver::vectorsFill(const std::vector<double> &rhs, const std::vector<double> &solution)
1759{
1760 if (!rhs.empty()) {
1761 fillVector(m_rhs, rhs);
1762 }
1763
1764 if (!solution.empty()) {
1765 fillVector(m_solution, solution);
1766 }
1767}
1768
1777void SystemSolver::vectorsFill(const std::string &rhsFilePath, const std::string &solutionFilePath)
1778{
1779 if (!rhsFilePath.empty()) {
1780 fillVector(m_rhs, rhsFilePath);
1781 }
1782
1783 if (!solutionFilePath.empty()) {
1784 fillVector(m_solution, solutionFilePath);
1785 }
1786}
1787
1794{
1795 if (!m_transpose) {
1796 reorderVector(m_rhs, m_colReordering, invert);
1797 reorderVector(m_solution, m_rowReordering, invert);
1798 } else {
1799 reorderVector(m_rhs, m_rowReordering, invert);
1800 reorderVector(m_solution, m_colReordering, invert);
1801 }
1802}
1803
1811void SystemSolver::vectorsDump(std::ostream &systemStream, const std::string &directory,
1812 const std::string &prefix) const
1813{
1814 BITPIT_UNUSED(systemStream);
1815
1816 dumpVector(m_rhs, directory, prefix + "rhs");
1817 dumpVector(m_solution, directory, prefix + "solution");
1818}
1819
1827void SystemSolver::vectorsRestore(std::istream &systemStream, const std::string &directory,
1828 const std::string &prefix)
1829{
1830 BITPIT_UNUSED(systemStream);
1831
1832 restoreVector(directory, prefix + "rhs", m_A, VECTOR_SIDE_RIGHT, &m_rhs);
1833 restoreVector(directory, prefix + "solution", m_A, VECTOR_SIDE_LEFT, &m_solution);
1834}
1835
1840{
1841 destroyVector(&m_rhs);
1842 destroyVector(&m_solution);
1843}
1844
1851{
1852 PetscScalar *raw_rhs;
1853 VecGetArray(m_rhs, &raw_rhs);
1854
1855 return raw_rhs;
1856}
1857
1863const double * SystemSolver::getRHSRawPtr() const
1864{
1865 return getRHSRawReadPtr();
1866}
1867
1874{
1875 const PetscScalar *raw_rhs;
1876 VecGetArrayRead(m_rhs, &raw_rhs);
1877
1878 return raw_rhs;
1879}
1880
1888{
1889 VecRestoreArray(m_rhs, &raw_rhs);
1890}
1891
1898void SystemSolver::restoreRHSRawReadPtr(const double *raw_rhs) const
1899{
1900 VecRestoreArrayRead(m_rhs, &raw_rhs);
1901}
1902
1909{
1910 PetscScalar *raw_solution;
1911 VecGetArray(m_solution, &raw_solution);
1912
1913 return raw_solution;
1914}
1915
1922{
1923 return getSolutionRawReadPtr();
1924}
1925
1932{
1933 const PetscScalar *raw_solution;
1934 VecGetArrayRead(m_solution, &raw_solution);
1935
1936 return raw_solution;
1937}
1938
1945void SystemSolver::restoreSolutionRawPtr(double *raw_solution)
1946{
1947 VecRestoreArray(m_solution, &raw_solution);
1948}
1949
1956void SystemSolver::restoreSolutionRawReadPtr(const double *raw_solution) const
1957{
1958 VecRestoreArrayRead(m_solution, &raw_solution);
1959}
1960
1968void SystemSolver::exportMatrix(const std::string &filePath, FileFormat fileFormat) const
1969{
1970 exportMatrix(m_A, filePath, fileFormat);
1971}
1972
1982void SystemSolver::importMatrix(const std::string &filePath)
1983{
1984 // Check if the matrix exists
1985 if (!m_A) {
1986 throw std::runtime_error("Matrix should be created before filling it.");
1987 }
1988
1989 // Clear workspace
1991
1992 // Clear reordering
1994
1995 // Fill the matrix
1996 matrixFill(filePath);
1997
1998 // Re-create vectors
2000 vectorsCreate();
2001}
2002
2010void SystemSolver::exportRHS(const std::string &filePath, FileFormat fileFormat) const
2011{
2012 exportVector(m_rhs, filePath, fileFormat);
2013}
2014
2026void SystemSolver::importRHS(const std::string &filePath)
2027{
2028 // Check if the system is assembled
2029 if (!m_assembled) {
2030 throw std::runtime_error("The RHS vector can be loaded only after assembling the system.");
2031 }
2032
2033 // Fill the RHS vector
2034 vectorsFill(filePath, "");
2035
2036 // Check if the imported RHS is compatible with the matrix
2037 PetscInt size;
2038 VecGetLocalSize(m_rhs, &size);
2039
2040 PetscInt expectedSize;
2041 if (!m_transpose) {
2042 expectedSize = getColCount();
2043 } else {
2044 expectedSize = getRowCount();
2045 }
2046 expectedSize *= getBlockSize();
2047
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");
2053 }
2054}
2055
2063void SystemSolver::exportSolution(const std::string &filePath, FileFormat fileFormat) const
2064{
2065 exportVector(m_solution, filePath, fileFormat);
2066}
2067
2079void SystemSolver::importSolution(const std::string &filePath)
2080{
2081 // Check if the system is assembled
2082 if (!m_assembled) {
2083 throw std::runtime_error("The solution vector can be loaded only after assembling the system.");
2084 }
2085
2086 // Fill the solution vector
2087 vectorsFill("", filePath);
2088
2089 // Check if the imported solution is compatible with the matrix
2090 PetscInt size;
2091 VecGetLocalSize(m_solution, &size);
2092
2093 PetscInt expectedSize;
2094 if (!m_transpose) {
2095 expectedSize = getRowCount();
2096 } else {
2097 expectedSize = getColCount();
2098 }
2099 expectedSize *= getBlockSize();
2100
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");
2106 }
2107}
2108
2120void SystemSolver::dumpSystem(const std::string &header, const std::string &directory,
2121 const std::string &prefix) const
2122{
2123 int partitioningBlock = getBinaryArchiveBlock();
2124
2125 // Open stream that will contain system information
2126 OBinaryArchive systemArchive;
2127 if (partitioningBlock <= 0) {
2128 openBinaryArchive(header, directory, prefix + "info", -1, &systemArchive);
2129 }
2130 std::ostream &systemStream = systemArchive.getStream();
2131
2132 // Dump system information
2133 dumpInfo(systemStream);
2134
2135 // Dump matrix
2136 matrixDump(systemStream, directory, prefix);
2137
2138 // Dump vectors
2139 vectorsDump(systemStream, directory, prefix);
2140
2141 // Open stream with system information
2142 closeBinaryArchive(&systemArchive);
2143}
2144
2155#if BITPIT_ENABLE_MPI==1
2162#endif
2167#if BITPIT_ENABLE_MPI==1
2168void SystemSolver::restoreSystem(MPI_Comm communicator, bool redistribute,
2169 const std::string &directory, const std::string &prefix)
2170#else
2171void SystemSolver::restoreSystem(const std::string &directory, const std::string &prefix)
2172#endif
2173{
2174 // Clear the system
2175 clear();
2176
2177#if BITPIT_ENABLE_MPI == 1
2178 // Set the communicator
2179 setCommunicator(communicator);
2180#endif
2181
2182 // Open stream with system information
2183 IBinaryArchive systemArchive;
2184 openBinaryArchive(directory, prefix + "info", -1, &systemArchive);
2185 std::istream &systemStream = systemArchive.getStream();
2186
2187 // Dump system information
2188 restoreInfo(systemStream);
2189
2190 // Restore the matrix
2191#if BITPIT_ENABLE_MPI==1
2192 matrixRestore(systemStream, directory, prefix, redistribute);
2193#else
2194 matrixRestore(systemStream, directory, prefix);
2195#endif
2196
2197 // Restore RHS and solution vectors
2198 vectorsRestore(systemStream, directory, prefix);
2199
2200 // Close stream with system information
2201 closeBinaryArchive(&systemArchive);
2202
2203 // The system is now assembled
2204 m_assembled = true;
2205
2206 // Initialize KSP options
2208
2209 // Initialize KSP statuses
2211}
2212
2218void SystemSolver::dumpInfo(std::ostream &systemStream) const
2219{
2220 if (systemStream.good()) {
2221#if BITPIT_ENABLE_MPI==1
2222 utils::binary::write(systemStream, m_partitioned);
2223#endif
2224 utils::binary::write(systemStream, m_transpose);
2225 }
2226}
2227
2233void SystemSolver::restoreInfo(std::istream &systemStream)
2234{
2235#if BITPIT_ENABLE_MPI == 1
2236 // Detect if the system is partitioned
2237 utils::binary::read(systemStream, m_partitioned);
2238#endif
2239
2240 // Set transpose flag
2241 bool transpose;
2242 utils::binary::read(systemStream, transpose);
2243 setTranspose(transpose);
2244
2245}
2246
2254void SystemSolver::createMatrix(int rowBlockSize, int colBlockSize, Mat *matrix) const
2255{
2256 // Create the matrix
2257#if BITPIT_ENABLE_MPI == 1
2258 MatCreate(m_communicator, matrix);
2259#else
2260 MatCreate(PETSC_COMM_SELF, matrix);
2261#endif
2262
2263 // Set matrix type
2264 bool creatBlockMatrix = false;
2265 if (m_flatten) {
2266 creatBlockMatrix = false;
2267 } else {
2268 creatBlockMatrix = (rowBlockSize == colBlockSize) && (rowBlockSize != 1);
2269 }
2270
2271#if BITPIT_ENABLE_MPI == 1
2272 if (m_partitioned) {
2273 if (creatBlockMatrix) {
2274 MatSetType(*matrix, MATMPIBAIJ);
2275 } else {
2276 MatSetType(*matrix, MATMPIAIJ);
2277 }
2278 } else
2279#endif
2280 {
2281 if (creatBlockMatrix) {
2282 MatSetType(*matrix, MATSEQBAIJ);
2283 } else {
2284 MatSetType(*matrix, MATSEQAIJ);
2285 }
2286 }
2287
2288 // Set block size
2289 if (rowBlockSize == colBlockSize) {
2290 MatSetBlockSize(*matrix, rowBlockSize);
2291 } else if (rowBlockSize != 1 || colBlockSize != 1) {
2292 MatSetBlockSizes(*matrix, rowBlockSize, colBlockSize);
2293 }
2294}
2295
2309void SystemSolver::createMatrix(int rowBlockSize, int colBlockSize, int nNestRows, int nNestCols,
2310 Mat *subMatrices, Mat *matrix) const
2311{
2312 // Create the matrix
2313#if BITPIT_ENABLE_MPI == 1
2314 MatCreateNest(getCommunicator(), nNestRows, PETSC_NULLPTR, nNestCols, PETSC_NULLPTR, subMatrices, matrix);
2315#else
2316 MatCreateNest(PETSC_COMM_SELF, nNestRows, PETSC_NULLPTR, nNestCols, PETSC_NULLPTR, subMatrices, matrix);
2317#endif
2318
2319 // Set block size
2320 if (rowBlockSize == colBlockSize) {
2321 MatSetBlockSize(*matrix, rowBlockSize);
2322 } else if (rowBlockSize != 1 || colBlockSize != 1) {
2323 MatSetBlockSizes(*matrix, rowBlockSize, colBlockSize);
2324 }
2325}
2326
2336void SystemSolver::fillMatrix(Mat matrix, const std::string &filePath) const
2337{
2338 // Check if the file exists
2339 std::ifstream fileStream(filePath.c_str());
2340 if (!fileStream.good()) {
2341 throw std::runtime_error("The PETSc matrix file \"" + filePath + "\" doesn't exists.");
2342 }
2343 fileStream.close();
2344
2345 // Fill matrix content
2346 PetscViewer viewer;
2347#if BITPIT_ENABLE_MPI==1
2348 PetscViewerCreate(m_communicator, &viewer);
2349#else
2350 PetscViewerCreate(PETSC_COMM_SELF, &viewer);
2351#endif
2352 PetscViewerSetType(viewer, PETSCVIEWERBINARY);
2353 PetscViewerFileSetMode(viewer, FILE_MODE_READ);
2354 PetscViewerFileSetName(viewer, filePath.c_str());
2355 MatLoad(matrix, viewer);
2356 PetscViewerDestroy(&viewer);
2357}
2358
2366#if BITPIT_ENABLE_MPI==1
2371#endif
2378void SystemSolver::dumpMatrix(Mat matrix, const std::string &directory, const std::string &name) const
2379{
2380 int partitioningBlock = getBinaryArchiveBlock();
2381
2382 // Store information needed to create the matrix
2383 OBinaryArchive infoArchive;
2384 if (partitioningBlock <= 0) {
2385 openBinaryArchive("", directory, name + ".info", -1, &infoArchive);
2386 std::ostream &infoStream = infoArchive.getStream();
2387
2388 bool matrixExists = matrix;
2389 utils::binary::write(infoStream, matrixExists);
2390 if (!matrixExists) {
2391 closeBinaryArchive(&infoArchive);
2392 return;
2393 }
2394
2395 PetscInt rowBlockSize;
2396 PetscInt colBlockSize;
2397 MatGetBlockSizes(matrix, &rowBlockSize, &colBlockSize);
2398 utils::binary::write(infoStream, static_cast<int>(rowBlockSize));
2399 utils::binary::write(infoStream, static_cast<int>(colBlockSize));
2400
2401 closeBinaryArchive(&infoArchive);
2402 }
2403
2404 if (!matrix) {
2405 return;
2406 }
2407
2408#if BITPIT_ENABLE_MPI==1
2409 // Store partitioning information
2410 if (isPartitioned()) {
2411 OBinaryArchive partitioningArchive;
2412 openBinaryArchive("", directory, name + ".partitioning", partitioningBlock, &partitioningArchive);
2413 std::ostream &partitioningStream = partitioningArchive.getStream();
2414
2415 PetscInt nLocalRows;
2416 PetscInt nLocalCols;
2417 MatGetLocalSize(matrix, &nLocalRows, &nLocalCols);
2418 utils::binary::write(partitioningStream, static_cast<std::size_t>(nLocalRows));
2419 utils::binary::write(partitioningStream, static_cast<std::size_t>(nLocalCols));
2420
2421 PetscInt nGlobalRows;
2422 PetscInt nGlobalCols;
2423 MatGetSize(matrix, &nGlobalRows, &nGlobalCols);
2424 utils::binary::write(partitioningStream, static_cast<std::size_t>(nGlobalRows));
2425 utils::binary::write(partitioningStream, static_cast<std::size_t>(nGlobalCols));
2426
2427 closeBinaryArchive(&partitioningArchive);
2428 }
2429#endif
2430
2431 // Store matrix data
2432 std::string filePath = getDataFilePath(directory, name);
2433 exportMatrix(matrix, filePath, FILE_BINARY);
2434}
2435
2442#if BITPIT_ENABLE_MPI==1
2448#endif
2452#if BITPIT_ENABLE_MPI==1
2453void SystemSolver::restoreMatrix(const std::string &directory, const std::string &name,
2454 bool redistribute, Mat *matrix) const
2455{
2456#else
2457void SystemSolver::restoreMatrix(const std::string &directory, const std::string &name,
2458 Mat *matrix) const
2459{
2460#endif
2461
2462 // Create matrix
2463 IBinaryArchive infoArchive;
2464 openBinaryArchive(directory, name + ".info", -1, &infoArchive);
2465 std::istream &infoStream = infoArchive.getStream();
2466
2467 bool matrixExists;
2468 utils::binary::read(infoStream, matrixExists);
2469 if (!matrixExists) {
2470 *matrix = PETSC_NULLPTR;
2471 closeBinaryArchive(&infoArchive);
2472 return;
2473 }
2474
2475 int rowBlockSize;
2476 int colBlockSize;
2477 utils::binary::read(infoStream, rowBlockSize);
2478 utils::binary::read(infoStream, colBlockSize);
2479 createMatrix(rowBlockSize, colBlockSize, matrix);
2480
2481 closeBinaryArchive(&infoArchive);
2482
2483#if BITPIT_ENABLE_MPI==1
2484 // Set partitioning information
2485 if (isPartitioned() && !redistribute) {
2486 int partitioningBlock = getBinaryArchiveBlock();
2487
2488 IBinaryArchive partitioningArchive;
2489 openBinaryArchive(directory, name + ".partitioning", partitioningBlock, &partitioningArchive);
2490 std::istream &partitioningStream = partitioningArchive.getStream();
2491
2492 std::size_t nLocalRows;
2493 std::size_t nLocalCols;
2494 utils::binary::read(partitioningStream, nLocalRows);
2495 utils::binary::read(partitioningStream, nLocalCols);
2496 std::size_t nGlobalRows;
2497 std::size_t nGlobalCols;
2498 utils::binary::read(partitioningStream, nGlobalRows);
2499 utils::binary::read(partitioningStream, nGlobalCols);
2500 MatSetSizes(*matrix, nLocalRows, nLocalCols, nGlobalRows, nGlobalCols);
2501
2502 closeBinaryArchive(&partitioningArchive);
2503 }
2504#endif
2505
2506 // Fill matrix
2507 std::string filePath = getDataFilePath(directory, name);
2508 fillMatrix(*matrix, filePath);
2509}
2510
2519void SystemSolver::exportMatrix(Mat matrix, const std::string &filePath, FileFormat fileFormat) const
2520{
2521 // Early return if the matrix doesn't exist
2522 bool matrixExists = matrix;
2523 if (!matrixExists) {
2524 std::ofstream dataFile(filePath);
2525 dataFile.close();
2526
2527 std::ofstream infoFile(filePath + ".info");
2528 infoFile.close();
2529
2530 return;
2531 }
2532
2533 // Create the viewer
2534 PetscViewerType viewerType;
2535 PetscViewerFormat viewerFormat;
2536 if (fileFormat == FILE_BINARY) {
2537 viewerType = PETSCVIEWERBINARY;
2538 viewerFormat = PETSC_VIEWER_DEFAULT;
2539 } else {
2540 viewerType = PETSCVIEWERASCII;
2541 viewerFormat = PETSC_VIEWER_ASCII_MATLAB;
2542 }
2543
2544 PetscViewer matViewer;
2545#if BITPIT_ENABLE_MPI==1
2546 PetscViewerCreate(m_communicator, &matViewer);
2547#else
2548 PetscViewerCreate(PETSC_COMM_SELF, &matViewer);
2549#endif
2550 PetscViewerSetType(matViewer, viewerType);
2551 PetscViewerFileSetMode(matViewer, FILE_MODE_WRITE);
2552 PetscViewerPushFormat(matViewer, viewerFormat);
2553 PetscViewerFileSetName(matViewer, filePath.c_str());
2554
2555 // Export the matrix
2556 MatView(matrix, matViewer);
2557
2558 // Destroy the viewer
2559 PetscViewerDestroy(&matViewer);
2560}
2561
2567void SystemSolver::destroyMatrix(Mat *matrix) const
2568{
2569 if (matrix) {
2570 MatDestroy(matrix);
2571 *matrix = PETSC_NULLPTR;
2572 }
2573}
2574
2581void SystemSolver::createVector(int blockSize, Vec *vector) const
2582{
2583 // Create the vector
2584#if BITPIT_ENABLE_MPI == 1
2585 VecCreate(m_communicator, vector);
2586#else
2587 VecCreate(PETSC_COMM_SELF, vector);
2588#endif
2589
2590 // Set vector type
2591#if BITPIT_ENABLE_MPI == 1
2592 if (m_partitioned) {
2593 VecSetType(*vector, VECMPI);
2594 } else
2595#endif
2596 {
2597 VecSetType(*vector, VECSEQ);
2598 }
2599
2600 // Set block size
2601 if (blockSize != 1) {
2602 VecSetBlockSize(*vector, blockSize);
2603 }
2604}
2605
2614void SystemSolver::createVector(int blockSize, int nestSize, Vec *subVectors, Vec *vector) const
2615{
2616 // Create the vector
2617#if BITPIT_ENABLE_MPI == 1
2618 VecCreateNest(getCommunicator(), nestSize, PETSC_NULLPTR, subVectors, vector);
2619#else
2620 VecCreateNest(PETSC_COMM_SELF, nestSize, PETSC_NULLPTR, subVectors, vector);
2621#endif
2622
2623 // Set block size
2624 if (blockSize != 1) {
2625 VecSetBlockSize(*vector, blockSize);
2626 }
2627}
2628
2638void SystemSolver::fillVector(Vec vector, const std::string &filePath) const
2639{
2640 // Check if the file exists
2641 std::ifstream fileStream(filePath);
2642 if (!fileStream.good()) {
2643 throw std::runtime_error("The file \"" + filePath + "\" cannot be read.");
2644 }
2645 fileStream.close();
2646
2647 // Fill the vector
2648 PetscViewer viewer;
2649#if BITPIT_ENABLE_MPI==1
2650 PetscViewerCreate(m_communicator, &viewer);
2651#else
2652 PetscViewerCreate(PETSC_COMM_SELF, &viewer);
2653#endif
2654 PetscViewerSetType(viewer, PETSCVIEWERBINARY);
2655 PetscViewerFileSetMode(viewer, FILE_MODE_READ);
2656 PetscViewerFileSetName(viewer, filePath.c_str());
2657 VecLoad(vector, viewer);
2658 PetscViewerDestroy(&viewer);
2659}
2660
2667void SystemSolver::fillVector(Vec vector, const std::vector<double> &data) const
2668{
2669 int size;
2670 VecGetLocalSize(vector, &size);
2671
2672 PetscScalar *petscData;
2673 VecGetArray(vector, &petscData);
2674 for (int i = 0; i < size; ++i) {
2675 petscData[i] = data[i];
2676 }
2677 VecRestoreArray(vector, &petscData);
2678}
2679
2687#if BITPIT_ENABLE_MPI==1
2692#endif
2699void SystemSolver::dumpVector(Vec vector, const std::string &directory, const std::string &name) const
2700{
2701 int partitioningBlock = getBinaryArchiveBlock();
2702
2703 // Store information needed to create the matrix
2704 if (partitioningBlock <= 0) {
2705 OBinaryArchive infoArchive;
2706 openBinaryArchive("", directory, name + ".info", -1, &infoArchive);
2707 std::ostream &infoStream = infoArchive.getStream();
2708
2709 bool vectorExists = vector;
2710 utils::binary::write(infoStream, vectorExists);
2711 if (!vectorExists) {
2712 closeBinaryArchive(&infoArchive);
2713 return;
2714 }
2715
2716 PetscInt blockSize;
2717 VecGetBlockSize(vector, &blockSize);
2718 utils::binary::write(infoStream, static_cast<int>(blockSize));
2719
2720 closeBinaryArchive(&infoArchive);
2721 }
2722
2723 if (!vector) {
2724 return;
2725 }
2726
2727#if BITPIT_ENABLE_MPI==1
2728 // Store partitioning information
2729 if (isPartitioned()) {
2730 int partitioningBlock = getBinaryArchiveBlock();
2731
2732 OBinaryArchive partitioningArchive;
2733 openBinaryArchive("", directory, name + ".partitioning", partitioningBlock, &partitioningArchive);
2734 std::ostream &partitioningStream = partitioningArchive.getStream();
2735
2736 PetscInt localSize;
2737 VecGetLocalSize(vector, &localSize);
2738 utils::binary::write(partitioningStream, static_cast<std::size_t>(localSize));
2739
2740 PetscInt globalSize;
2741 VecGetSize(vector, &globalSize);
2742 utils::binary::write(partitioningStream, static_cast<std::size_t>(globalSize));
2743
2744 closeBinaryArchive(&partitioningArchive);
2745 }
2746#endif
2747
2748 // Store vector data
2749 std::string filePath = getDataFilePath(directory, name);
2750 exportVector(vector, filePath, FILE_BINARY);
2751}
2752
2763void SystemSolver::restoreVector(const std::string &directory, const std::string &name,
2764 Mat matrix, VectorSide side, Vec *vector) const
2765{
2766 // Get size information
2767 PetscInt nLocalRows;
2768 PetscInt nLocalCols;
2769 MatGetLocalSize(matrix, &nLocalRows, &nLocalCols);
2770
2771 PetscInt nGlobalRows;
2772 PetscInt nGlobalCols;
2773 MatGetSize(matrix, &nGlobalRows, &nGlobalCols);
2774
2775 std::size_t localSize = std::numeric_limits<std::size_t>::max();
2776 std::size_t globalSize = std::numeric_limits<std::size_t>::max();
2777 if (!m_transpose) {
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;
2784 }
2785 } else {
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;
2792 }
2793 }
2794
2795 // Restore the vector
2796 restoreVector(directory, name, localSize, globalSize, vector);
2797}
2798
2805#if BITPIT_ENABLE_MPI==1
2811#endif
2815#if BITPIT_ENABLE_MPI==1
2816void SystemSolver::restoreVector(const std::string &directory, const std::string &name,
2817 bool redistribute, Vec *vector) const
2818#else
2819void SystemSolver::restoreVector(const std::string &directory, const std::string &name,
2820 Vec *vector) const
2821#endif
2822{
2823
2824 // Get size information
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
2828 if (isPartitioned()) {
2829 if (!redistribute) {
2830 int partitioningBlock = getBinaryArchiveBlock();
2831
2832 IBinaryArchive partitioningArchive;
2833 openBinaryArchive(directory, name + ".partitioning", partitioningBlock, &partitioningArchive);
2834 std::istream &partitioningStream = partitioningArchive.getStream();
2835
2836 utils::binary::read(partitioningStream, localSize);
2837 utils::binary::read(partitioningStream, globalSize);
2838
2839 closeBinaryArchive(&partitioningArchive);
2840 }
2841 }
2842#endif
2843
2844 restoreVector(directory, name, localSize, globalSize, vector);
2845}
2846
2856void SystemSolver::restoreVector(const std::string &directory, const std::string &name,
2857 std::size_t localSize, std::size_t globalSize, Vec *vector) const
2858{
2859 // Create vector
2860 IBinaryArchive infoArchive;
2861 openBinaryArchive(directory, name + ".info", -1, &infoArchive);
2862 std::istream &infoStream = infoArchive.getStream();
2863
2864 bool vectorExists;;
2865 utils::binary::read(infoStream, vectorExists);
2866 if (!vectorExists) {
2867 *vector = PETSC_NULLPTR;
2868 closeBinaryArchive(&infoArchive);
2869 return;
2870 }
2871
2872 int blockSize;
2873 utils::binary::read(infoStream, blockSize);
2874 createVector(blockSize, vector);
2875
2876 closeBinaryArchive(&infoArchive);
2877
2878 // Set size information
2879 PetscInt petscLocalSize;
2880 if (localSize != std::numeric_limits<std::size_t>::max()) {
2881 petscLocalSize = static_cast<PetscInt>(localSize);
2882 } else {
2883 petscLocalSize = PETSC_DECIDE;
2884 }
2885
2886 PetscInt petscGlobalSize;
2887 if (globalSize != std::numeric_limits<std::size_t>::max()) {
2888 petscGlobalSize = static_cast<PetscInt>(globalSize);
2889 } else {
2890 petscGlobalSize = PETSC_DETERMINE;
2891 }
2892
2893 if (petscLocalSize != PETSC_DECIDE || petscGlobalSize != PETSC_DETERMINE) {
2894 VecSetSizes(*vector, petscLocalSize, petscGlobalSize);
2895 }
2896
2897 // Fill vector data
2898 std::string filePath = getDataFilePath(directory, name);
2899 fillVector(*vector, filePath);
2900}
2901
2907void SystemSolver::reorderVector(Vec vector, IS permutations, bool invert) const
2908{
2909 if (!permutations) {
2910 return;
2911 }
2912
2913 PetscBool petscInvert;
2914 if (invert) {
2915 petscInvert = PETSC_TRUE;
2916 } else {
2917 petscInvert = PETSC_FALSE;
2918 }
2919
2920 VecPermute(vector, permutations, petscInvert);
2921}
2922
2931void SystemSolver::exportVector(Vec vector, const std::string &filePath, FileFormat fileFormat) const
2932{
2933 // Early return if the matrix doesn't exist
2934 bool vectorExists = vector;
2935 if (!vectorExists) {
2936 std::ofstream dataFile(filePath);
2937 dataFile.close();
2938
2939 std::ofstream infoFile(filePath + ".info");
2940 infoFile.close();
2941
2942 return;
2943 }
2944
2945 // Create the viewer
2946 PetscViewerType viewerType;
2947 PetscViewerFormat viewerFormat;
2948 if (fileFormat == FILE_BINARY) {
2949 viewerType = PETSCVIEWERBINARY;
2950 viewerFormat = PETSC_VIEWER_DEFAULT;
2951 } else {
2952 viewerType = PETSCVIEWERASCII;
2953 viewerFormat = PETSC_VIEWER_ASCII_MATLAB;
2954 }
2955
2956 PetscViewer viewer;
2957#if BITPIT_ENABLE_MPI==1
2958 PetscViewerCreate(m_communicator, &viewer);
2959#else
2960 PetscViewerCreate(PETSC_COMM_SELF, &viewer);
2961#endif
2962 PetscViewerSetType(viewer, viewerType);
2963 PetscViewerFileSetMode(viewer, FILE_MODE_WRITE);
2964 PetscViewerPushFormat(viewer, viewerFormat);
2965 PetscViewerFileSetName(viewer, filePath.c_str());
2966
2967 // Export the vector
2968 VecView(vector, viewer);
2969
2970 // Destroy the viewer
2971 PetscViewerDestroy(&viewer);
2972}
2973
2980void SystemSolver::exportVector(Vec vector, std::vector<double> *data) const
2981{
2982 int size;
2983 VecGetLocalSize(m_solution, &size);
2984
2985 const PetscScalar *vectorData;
2986 VecGetArrayRead(m_solution, &vectorData);
2987 for (int i = 0; i < size; ++i) {
2988 (*data)[i] = vectorData[i];
2989 }
2990 VecRestoreArrayRead(vector, &vectorData);
2991}
2992
2998void SystemSolver::destroyVector(Vec *vector) const
2999{
3000 if (vector) {
3001 VecDestroy(vector);
3002 *vector = PETSC_NULLPTR;
3003 }
3004}
3005
3013std::string SystemSolver::getInfoFilePath(const std::string &directory, const std::string &name) const
3014{
3015 return getFilePath(directory, name + ".info");
3016}
3017
3025std::string SystemSolver::getDataFilePath(const std::string &directory, const std::string &name) const
3026{
3027 return getFilePath(directory, name + ".dat");
3028}
3029
3037std::string SystemSolver::getFilePath(const std::string &directory, const std::string &name) const
3038{
3039 std::string path = directory + "/" + name;
3040
3041 return path;
3042}
3043
3048{
3049 MatNullSpace nullspace;
3050#if BITPIT_ENABLE_MPI==1
3051 MatNullSpaceCreate(m_communicator, PETSC_TRUE, 0, NULL, &nullspace);
3052#else
3053 MatNullSpaceCreate(PETSC_COMM_SELF, PETSC_TRUE, 0, NULL, &nullspace);
3054#endif
3055 MatSetNullSpace(m_A, nullspace);
3056 MatNullSpaceDestroy(&nullspace);
3057}
3058
3063{
3064 MatSetNullSpace(m_A, NULL);
3065}
3066
3084void SystemSolver::setReordering(long nRows, long nCols, const SystemMatrixOrdering &reordering)
3085{
3086 // Clear existing reordering
3088
3089 // Early return if natural ordering is used
3090 try {
3091 dynamic_cast<const NaturalSystemMatrixOrdering &>(reordering);
3092 return;
3093 } catch(const std::bad_cast &exception) {
3094 BITPIT_UNUSED(exception);
3095
3096 // A reordering other than the natural one has been passed
3097 }
3098
3099 // Set row reordering
3100 PetscInt *rowReorderingStorage;
3101 PetscMalloc(nRows * sizeof(PetscInt), &rowReorderingStorage);
3102 for (long i = 0; i < nRows; ++i) {
3103 rowReorderingStorage[reordering.getRowPermutationRank(i)] = i;
3104 }
3105
3106#if BITPIT_ENABLE_MPI == 1
3107 ISCreateGeneral(m_communicator, nRows, rowReorderingStorage, PETSC_OWN_POINTER, &m_rowReordering);
3108#else
3109 ISCreateGeneral(PETSC_COMM_SELF, nRows, rowReorderingStorage, PETSC_OWN_POINTER, &m_rowReordering);
3110#endif
3111 ISSetPermutation(m_rowReordering);
3112
3113 // Create new permutations
3114 PetscInt *colReorderingStorage;
3115 PetscMalloc(nCols * sizeof(PetscInt), &colReorderingStorage);
3116 for (long j = 0; j < nCols; ++j) {
3117 colReorderingStorage[reordering.getColPermutationRank(j)] = j;
3118 }
3119
3120#if BITPIT_ENABLE_MPI == 1
3121 ISCreateGeneral(m_communicator, nCols, colReorderingStorage, PETSC_OWN_POINTER, &m_colReordering);
3122#else
3123 ISCreateGeneral(PETSC_COMM_SELF, nCols, colReorderingStorage, PETSC_OWN_POINTER, &m_colReordering);
3124#endif
3125 ISSetPermutation(m_colReordering);
3126}
3127
3135{
3136 if (m_rowReordering) {
3137 ISDestroy(&m_rowReordering);
3138 }
3139
3140 if (m_colReordering) {
3141 ISDestroy(&m_colReordering);
3142 }
3143}
3144
3149{
3150 // Check if the system is assembled
3151 if (!isAssembled()) {
3152 throw std::runtime_error("Unable to solve the system. The system is not yet assembled.");
3153 }
3154
3155 // Early return if the KSP can be reused
3156 if (!m_KSPDirty) {
3157 return;
3158 }
3159
3160 // Create KSP
3161 bool setupNeeded = false;
3162 if (!m_KSP) {
3163 createKSP();
3164 setupNeeded = true;
3165 }
3166
3167 // Set the matrix associated with the linear system
3168 KSPSetOperators(m_KSP, m_A, m_A);
3169
3170 // Set up
3171 if (setupNeeded) {
3172 // Perform actions before preconditioner set up
3174
3175 // Initialize preconditioner from options
3176 PC pc;
3177 KSPGetPC(m_KSP, &pc);
3178 PCSetFromOptions(pc);
3179
3180 // Set up preconditioner
3182
3183 // Perform actions after preconditioner set up
3185
3186 // Perform actions before Krylov subspace method set up set up
3188
3189 // Initialize Krylov subspace from options
3190 KSPSetFromOptions(m_KSP);
3191
3192 // Set up the Krylov subspace method
3193 setupKrylov();
3194
3195 // Perform actions after Krylov subspace method set up
3197 }
3198
3199 // KSP is now ready
3200 m_KSPDirty = false;
3201
3202 // Reset KSP status
3204}
3205
3210{
3211 // Nothing to do
3212}
3213
3218{
3219 // Create KSP object
3220#if BITPIT_ENABLE_MPI==1
3221 KSPCreate(m_communicator, &m_KSP);
3222#else
3223 KSPCreate(PETSC_COMM_SELF, &m_KSP);
3224#endif
3225
3226 // Set options prefix
3227 if (!m_prefix.empty()) {
3228 KSPSetOptionsPrefix(m_KSP, m_prefix.c_str());
3229 }
3230}
3231
3236{
3237 m_KSPDirty = true;
3238 KSPDestroy(&m_KSP);
3239 m_KSP = PETSC_NULLPTR;
3240}
3241
3246{
3247 PC pc;
3248 KSPGetPC(m_KSP, &pc);
3250}
3251
3258void SystemSolver::setupPreconditioner(PC pc, const KSPOptions &options) const
3259{
3260 // Set preconditioner type
3261 PCType pcType;
3262#if BITPIT_ENABLE_MPI == 1
3263 if (isPartitioned()) {
3264 pcType = PCASM;
3265 } else {
3266 pcType = PCILU;
3267 }
3268#else
3269 pcType = PCILU;
3270#endif
3271
3272 PCSetType(pc, pcType);
3273
3274 // Configure preconditioner
3275 if (strcmp(pcType, PCASM) == 0) {
3276 if (options.overlap != PETSC_DEFAULT) {
3277 PCASMSetOverlap(pc, options.overlap);
3278 }
3279 } else if (strcmp(pcType, PCILU) == 0) {
3280 if (options.levels != PETSC_DEFAULT) {
3281 PCFactorSetLevels(pc, options.levels);
3282 }
3283 }
3284
3285 PCSetUp(pc);
3286
3287 if (strcmp(pcType, PCASM) == 0) {
3288 KSP *subKSPs;
3289 PetscInt nSubKSPs;
3290 PCASMGetSubKSP(pc, &nSubKSPs, PETSC_NULLPTR, &subKSPs);
3291
3292 for (PetscInt i = 0; i < nSubKSPs; ++i) {
3293 KSP subKSP = subKSPs[i];
3294 KSPSetType(subKSP, KSPPREONLY);
3295
3296 PC subPC;
3297 KSPGetPC(subKSP, &subPC);
3298 PCSetType(subPC, PCILU);
3299 if (options.levels != PETSC_DEFAULT) {
3300 PCFactorSetLevels(subPC, options.levels);
3301 }
3302 }
3303 }
3304}
3305
3310{
3311 // Nothing to do
3312}
3313
3318{
3319 // Nothing to do
3320}
3321
3326{
3327 setupKrylov(m_KSP, getKSPOptions());
3328}
3329
3340void SystemSolver::setupKrylov(KSP ksp, const KSPOptions &options) const
3341{
3342 KSPSetType(ksp, KSPFGMRES);
3343 if (options.restart != PETSC_DEFAULT) {
3344 KSPGMRESSetRestart(ksp, options.restart);
3345 }
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);
3348 }
3349 KSPSetInitialGuessNonzero(ksp, options.initial_non_zero);
3350}
3351
3356{
3357 // Enable convergence monitor
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(), "");
3363#else
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(), "");
3367#endif
3368 }
3369}
3370
3377
3386{
3387 if (!isAssembled()) {
3388 throw std::runtime_error("The options associated with the Krylov solver can only be accessed after assembling the system.");
3389 }
3390
3391 return m_KSPOptions;
3392}
3393
3402{
3403 if (!isAssembled()) {
3404 throw std::runtime_error("The options associated with the Krylov solver can only be accessed after assembling the system.");
3405 }
3406
3407 return m_KSPOptions;
3408}
3409
3414{
3415 resetKSPOptions(&m_KSPOptions);
3416}
3417
3424{
3425 *options = KSPOptions();
3426}
3427
3432{
3433 resetKSPOptions(&m_KSPOptions);
3434}
3435
3444{
3445 if (!isAssembled()) {
3446 throw std::runtime_error("The status of the Krylov solver can only be accessed after assembling the system.");
3447 }
3448
3449 return m_KSPStatus;
3450}
3451
3459
3464{
3465 fillKSPStatus(m_KSP, &m_KSPStatus);
3466}
3467
3474void SystemSolver::fillKSPStatus(KSP ksp, KSPStatus *status) const
3475{
3476 status->error = 0;
3477 KSPGetIterationNumber(ksp, &(status->its));
3478 KSPGetConvergedReason(ksp, &(status->convergence));
3479}
3480
3485{
3486 resetKSPStatus(&m_KSPStatus);
3487}
3488
3495{
3496 status->error = 0;
3497 status->its = -1;
3498 status->convergence = KSP_CONVERGED_ITERATING;
3499}
3500
3508
3509#if BITPIT_ENABLE_MPI==1
3515const MPI_Comm & SystemSolver::getCommunicator() const
3516{
3517 return m_communicator;
3518}
3519
3526void SystemSolver::setCommunicator(MPI_Comm communicator)
3527{
3528 if ((communicator != MPI_COMM_NULL) && (communicator != MPI_COMM_SELF)) {
3529 MPI_Comm_dup(communicator, &m_communicator);
3530 } else {
3531 m_communicator = MPI_COMM_SELF;
3532 }
3533}
3534
3538void SystemSolver::freeCommunicator()
3539{
3540 if (m_communicator != MPI_COMM_SELF) {
3541 int finalizedCalled;
3542 MPI_Finalized(&finalizedCalled);
3543 if (!finalizedCalled) {
3544 MPI_Comm_free(&m_communicator);
3545 }
3546 }
3547}
3548#endif
3549
3556void SystemSolver::removeNullSpaceFromRHS()
3557{
3558 // Get the null space from the matrix
3559 MatNullSpace nullspace;
3560 MatGetNullSpace(m_A, &nullspace);
3561
3562 // Remove null space components from right hand side
3563 MatNullSpaceRemove(nullspace, m_rhs);
3564}
3565
3573{
3574 return m_forceConsistency;
3575}
3576
3584{
3585 m_forceConsistency = enable;
3586}
3587
3600void SystemSolver::openBinaryArchive(const std::string &directory, const std::string &prefix,
3601 int block, IBinaryArchive *archive) const
3602{
3603 int expectedVersion = getDumpVersion();
3604
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) + ".";
3611
3612 throw std::runtime_error(message);
3613 }
3614}
3615
3629void SystemSolver::openBinaryArchive(const std::string &header, const std::string &directory,
3630 const std::string &prefix, int block, OBinaryArchive *archive) const
3631{
3632 int version = getDumpVersion();
3633 std::string path = getFilePath(directory, prefix);
3634 archive->open(path, "dat", version, header, block);
3635}
3636
3642void SystemSolver::closeBinaryArchive(BinaryArchive *archive) const
3643{
3644 archive->close();
3645}
3646
3652int SystemSolver::getBinaryArchiveBlock() const
3653{
3654#if BITPIT_ENABLE_MPI == 1
3655 if (isPartitioned()) {
3656 int nProcesses;
3657 MPI_Comm_size(getCommunicator(), &nProcesses);
3658 if (nProcesses <= 1) {
3659 return -1;
3660 }
3661
3662 int archiveBlock;
3663 MPI_Comm_rank(getCommunicator(), &archiveBlock);
3664
3665 return archiveBlock;
3666 } else {
3667 return -1;
3668 }
3669#else
3670 return -1;
3671#endif
3672}
3673
3674}
Input binary archive.
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
Output binary archive.
std::ostream & getStream()
The PetscManager class handles the interaction with PETSc library.
void addInitOptions(int argc, char **args)
void addInitOption(const std::string &option)
static constexpr __PXV_POINTER__ INTERNAL_STORAGE
__PXV_CONST_ITERATOR__ cend()
std::size_t size() const
__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
void matrixUpdate(long nRows, const long *rows, const Assembler &assembler)
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 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)
void reorderVector(Vec vector, IS permutations, bool invert) const
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
void setReordering(long nRows, long nCols, const SystemMatrixOrdering &reordering)
virtual void restoreInfo(std::istream &stream)
void restoreSystem(MPI_Comm communicator, bool redistribute, const std::string &directory, const std::string &prefix="")
const double * getSolutionRawReadPtr() 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
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)
const MPI_Comm & getCommunicator() const
std::string getDataFilePath(const std::string &directory, const std::string &name) const
const double * getRHSRawReadPtr() const
virtual void importSolution(const std::string &filePath)
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 vectorsFill(const std::vector< double > &rhs, const std::vector< double > &solution)
void enableForceConsistency(bool enable)
void restoreSolutionRawReadPtr(const double *raw_solution) const
virtual void vectorsReorder(bool invert)
virtual void vectorsRestore(std::istream &systemStream, const std::string &directory, const std::string &prefix)
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...
void getRowValues(long rowIndex, ConstProxyVector< double > *values) const override
const MPI_Comm & getCommunicator() const override
void getRowData(long rowIndex, ConstProxyVector< long > *pattern, ConstProxyVector< double > *values) const override
long getRowNZCount(long rowIndex) const override
AssemblyOptions getOptions() const override
void getRowPattern(long rowIndex, ConstProxyVector< long > *pattern) 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)
Definition compiler.hpp:63
Logger & cout(log::Level defaultSeverity, log::Visibility defaultVisibility)
Definition logger.cpp:1714
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.