Loading...
Searching...
No Matches
LA_example_00002.cpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2023 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 <array>
26#if BITPIT_ENABLE_MPI==1
27#include <mpi.h>
28#endif
29
30#include "bitpit_common.hpp"
31#include "bitpit_LA.hpp"
32
33using namespace bitpit;
34
35const double SOLVER_RTOL = 1e-7;
36const double SOLVER_ATOL = 1e-50;
37const int SOLVER_MAXITS = 100;
38
78
79public:
87 AMGSplitSystemSolver(bool transpose, bool multigrid, bool debug)
88 : SplitSystemSolver(multigrid, transpose, debug),
89 m_multigrid(multigrid)
90 {
91 }
92
93protected:
94 const static PetscInt GAMG_MAX_LEVELS;
95 const static PetscReal GAMG_THRESHOLD;
96 const static PetscReal GAMG_THRESHOLD_SCALE;
97
98 bool m_multigrid;
99
106 void setupPreconditioner(PC pc, const KSPOptions &options) const override
107 {
108 // Early return for non-multigrid
109 if (!m_multigrid) {
111 return;
112 }
113
114 // Set multigrid options
115 KSPGetPC(this->m_KSP, &pc);
116 PCSetType(pc, PCGAMG);
117
118 std::vector<PetscReal> thresholds(GAMG_MAX_LEVELS);
119 for (int i = 0; i < GAMG_MAX_LEVELS; ++i) {
120 thresholds[i] = GAMG_THRESHOLD;
121 }
122
123 PCGAMGSetNSmooths(pc, 0);
124#if (PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR <= 17)
125#if BITPIT_ENABLE_MPI == 1
126 if (this->isPartitioned()) {
127 PCGAMGSetSymGraph(pc, PETSC_TRUE);
128 }
129#endif
130#endif
131
132 PCGAMGSetNlevels(pc, GAMG_MAX_LEVELS);
133#if (PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 16)
134 PCGAMGSetThreshold(pc, thresholds.data(), GAMG_MAX_LEVELS);
135 PCGAMGSetThresholdScale(pc, GAMG_THRESHOLD_SCALE);
136#else
137 PCGAMGSetThreshold(pc, GAMG_THRESHOLD);
138#endif
139
140 // Setup
141 PCSetUp(pc);
142
143 // Set options for the multigrid coarse level
144 KSP coarseKSP;
145 PCMGGetCoarseSolve(pc, &coarseKSP);
146
147 PC coarsePreconditioner;
148 KSPGetPC(coarseKSP, &coarsePreconditioner);
149 PCSetType(coarsePreconditioner, PCSVD);
150 }
151};
152
153const PetscInt AMGSplitSystemSolver::GAMG_MAX_LEVELS = 10;
154const PetscReal AMGSplitSystemSolver::GAMG_THRESHOLD = 0.02;
155const PetscReal AMGSplitSystemSolver::GAMG_THRESHOLD_SCALE = 1.0;
156
163int run_dump(int rank, int nProcs)
164{
165 log::cout() << std::endl;
166 log::cout() << "Running dump example..." << std::endl;
167
168 int nRows;
169 int nCols;
170 int nNZ;
171 if (nProcs == 1) {
172 nRows = 10;
173 nCols = 10;
174 nNZ = 10;
175 } else if (nProcs == 2) {
176 if (rank == 0) {
177 nRows = 6;
178 nCols = 6;
179 nNZ = 6;
180 } if (rank == 1) {
181 nRows = 4;
182 nCols = 4;
183 nNZ = 4;
184 }
185 } else {
186 if (rank == 0) {
187 nRows = 2;
188 nCols = 2;
189 nNZ = 2;
190 } if (rank == 1) {
191 nRows = 5;
192 nCols = 5;
193 nNZ = 5;
194 } if (rank == 2) {
195 nRows = 3;
196 nCols = 3;
197 nNZ = 3;
198 } else {
199 nRows = 0;
200 nCols = 0;
201 nNZ = 0;
202 }
203 }
204
205 int blockSize = 5;
206
207 // Build matrix
208 log::cout() << "Building matrix..." << std::endl;
209
210 std::vector<long> rowPattern(1);
211 std::vector<double> rowValues(blockSize * blockSize);
212
213#if BITPIT_ENABLE_MPI==1
214 SparseMatrix matrix(MPI_COMM_WORLD, true, blockSize, nRows, nCols, nNZ);
215
216 int rowOffset = matrix.getRowGlobalOffset();
217 int colOffset = matrix.getColGlobalOffset();
218#else
219 SparseMatrix matrix(blockSize, nRows, nCols, nNZ);
220
221 int rowOffset = 0;
222 int colOffset = 0;
223#endif
224
225 for (int i = 0; i < nRows; ++i) {
226 rowPattern[0] = colOffset + i;
227 for (int k = 0; k < blockSize; ++k) {
228 int kk = linearalgebra::linearIndexRowMajor(k, k, blockSize, blockSize);
229
230 rowValues[kk] = 1. / (double) (blockSize * (rowOffset + i) + k + 1);
231 }
232
233 matrix.addRow(rowPattern, rowValues);
234 }
235
236 matrix.assembly();
237
238 // Build solver
239 log::cout() << "Building solver..." << std::endl;
240
241 bool multigrid = false;
242 bool debug = true;
243 bool transpose = false;
244 AMGSplitSystemSolver solver(transpose, multigrid, debug);
245
246 std::vector<int> splitSizes(2);
247 splitSizes[0] = 4;
248 splitSizes[1] = blockSize - splitSizes[0];
249
250 solver.assembly(matrix, SystemSplitStrategy::SYSTEM_SPLIT_STRATEGY_FULL, splitSizes);
251
252 double *rhs = solver.getRHSRawPtr();
253 for (int i = 0; i < nCols; ++i) {
254 int field = 0;
255 for (std::size_t split = 0; split < splitSizes.size(); ++split) {
256 for (int k = 0; k < splitSizes[split]; ++k) {
257 rhs[blockSize * i + field] = std::pow(10, split);
258 ++field;
259
260 }
261 }
262 }
263 solver.restoreRHSRawPtr(rhs);
264
265 double *initialSolution = solver.getSolutionRawPtr();
266 for (int i = 0; i < nRows; ++i) {
267 initialSolution[i] = 0;
268 }
269 solver.restoreSolutionRawPtr(initialSolution);
270
271 // Export system
272 solver.exportMatrix("LA_example_0002_matrix.txt", SystemSolver::FILE_ASCII);
273 solver.exportRHS("LA_example_0002_rhs.txt", SystemSolver::FILE_ASCII);
274 solver.exportSolution("LA_example_0002_solution.txt", SystemSolver::FILE_ASCII);
275
276 // Dump system
277 log::cout() << "Dumping initialized linear system..." << std::endl;
278
279 solver.dumpSystem("bitpit linear system", ".", "LA_example_0002_linear_system_");
280
281 // Set KSP options
282 KSPOptions options;
283 options.atol = SOLVER_ATOL;
284 options.rtol = SOLVER_RTOL;
285 options.maxits = SOLVER_MAXITS;
286 options.initial_non_zero = PETSC_FALSE;
287
288 KSPOptions &externalOptions = solver.getKSPOptions();
289 externalOptions = options;
290
291 for (int i = 0; i < solver.getSplitCount(); ++i) {
292 KSPOptions &splitOptions = solver.getSplitKSPOptions(i);
293 splitOptions = options;
294 }
295
296 // Solve System
297 log::cout() << "Solve linear system..." << std::endl;
298 solver.solve();
299
300 const KSPStatus &externalStatus = solver.getKSPStatus();
301 log::cout() << " External convergence reason: " << externalStatus.convergence << " in its: " << externalStatus.its << std::endl;
302
303 for (int split = 0; split < solver.getSplitCount(); ++split) {
304 const KSPStatus &splitStatus = solver.getSplitKSPStatus(split);
305 log::cout() << " Split #" << split << " convergence reason: " << splitStatus.convergence << " in its: " << splitStatus.its << std::endl;
306 }
307 log::cout() << "Linear system solved." << std::endl;
308
309 // Export solution
310 log::cout() << "Export solution..." << std::endl;
311 solver.exportSolution("LA_example_0002_linear_system_solution.dat", bitpit::SystemSolver::FILE_BINARY);
312
313 // Compare computed solution with expected one
314 //
315 // Set comparison tolerance to the linear system relative tolerance
316 log::cout() << "Comparing solutions..." << std::endl;
317
318 log::cout() << " Tolerance = " << SOLVER_RTOL << std::endl;
319
320 std::size_t nRowElements = solver.getRowElementCount();
321
322 bool isSolutionCorrect = true;
323 const double *solution = solver.getSolutionRawReadPtr();
324 for (std::size_t i = 0; i < nRowElements; ++i) {
325 std::size_t globalDOF = rowOffset * blockSize + i;
326
327 // Check for absolute tolerance only
328 double expectedSolution;
329 if (globalDOF == 0) {
330 expectedSolution = 1;
331 } else if ((globalDOF == 1) || ((globalDOF + 1) % blockSize) != 0) {
332 expectedSolution = static_cast<double>(globalDOF + 1);
333 } else {
334 expectedSolution = static_cast<double>(10 * (globalDOF + 1));
335 }
336
337 if (!utils::DoubleFloatingEqual()(expectedSolution - solution[i], 0.0, SOLVER_RTOL, SOLVER_RTOL)) {
338 std::stringstream message;
339 message << "Solutions do not match for global DOF #" << globalDOF << ".";
340 message << " Expected solution is " << expectedSolution;
341 message << ", current solution is " << solution[i] << ".";
342 log::cout() << message.str() << std::endl;
343 isSolutionCorrect = false;
344 }
345 }
346 solver.restoreSolutionRawReadPtr(solution);
347 if (isSolutionCorrect) {
348 log::cout() << "Solutions match." << std::endl;
349 }
350
351 return 0;
352}
353
360int run_restore(int rank, int nProcs)
361{
362 BITPIT_UNUSED(rank);
363 BITPIT_UNUSED(nProcs);
364
365 log::cout() << std::endl;
366 log::cout() << "Running restore example..." << std::endl;
367
368 // Restore solver with initial guess
369 log::cout() << "Restoring linear system ..." << std::endl;
370 bool multigrid = false;
371 bool debug = true;
372 bool transpose = false;
373 AMGSplitSystemSolver solver(transpose, multigrid, debug);
374
375#if BITPIT_ENABLE_MPI==1
376 solver.restoreSystem(MPI_COMM_WORLD, false, ".", "LA_example_0002_linear_system_");
377#else
378 solver.restoreSystem(".", "LA_example_0002_linear_system_");
379#endif
380 log::cout() << "Linear system restored." << std::endl;
381
382 // Export system
383 solver.exportMatrix("LA_example_0002_restored_matrix.txt", SystemSolver::FILE_ASCII);
384 solver.exportRHS("LA_example_0002_restored_rhs.txt", SystemSolver::FILE_ASCII);
385 solver.exportSolution("LA_example_0002_restored_solution.txt", SystemSolver::FILE_ASCII);
386
387 // Set KSP options
388 KSPOptions options;
389 options.atol = SOLVER_ATOL;
390 options.rtol = SOLVER_RTOL;
391 options.maxits = SOLVER_MAXITS;
392 options.initial_non_zero = PETSC_FALSE;
393
394 KSPOptions &externalOptions = solver.getKSPOptions();
395 externalOptions = options;
396
397 for (int i = 0; i < solver.getSplitCount(); ++i) {
398 KSPOptions &splitOptions = solver.getSplitKSPOptions(i);
399 splitOptions = options;
400 }
401
402 // Solve linear system
403 log::cout() << "Solving linear system..." << std::endl;
404 solver.solve();
405
406 const KSPStatus &externalStatus = solver.getKSPStatus();
407 log::cout() << " External convergence reason: " << externalStatus.convergence << " in its: " << externalStatus.its << std::endl;
408
409 for (int split = 0; split < solver.getSplitCount(); ++split) {
410 const KSPStatus &splitStatus = solver.getSplitKSPStatus(split);
411 log::cout() << " Split #" << split << " convergence reason: " << splitStatus.convergence << " in its: " << splitStatus.its << std::endl;
412 }
413 log::cout() << "Linear system solved." << std::endl;
414
415 // Turn solution comparison on
416 bool compareSolutions = true;
417 if (compareSolutions) {
418 // Store expected solution for comparison
419 log::cout() << "Storing computed solution for comparison..." << std::endl;
420 std::size_t nRowElements = solver.getRowElementCount();
421 std::vector<double> expectedSolution(nRowElements, 0.0);
422 double *computedSolution = solver.getSolutionRawPtr();
423 for (std::size_t i = 0; i < nRowElements; ++i) {
424 expectedSolution[i] = computedSolution[i];
425 }
426 solver.restoreSolutionRawPtr(computedSolution);
427
428 // Import solution with solution from outside
429 log::cout() << "Restoring solution..." << std::endl;
430 solver.importSolution("LA_example_0002_linear_system_solution.dat");
431 log::cout() << "Solution restored." << std::endl;
432
433 // Compare computed solution with restored one
434 //
435 // Set comparison tolerance to the linear system relative tolerance
436 log::cout() << "Comparing solutions..." << std::endl;
437
438 log::cout() << " Tolerance = " << SOLVER_RTOL << std::endl;
439
440 bool isSolutionCorrect = true;
441 const double *solution = solver.getSolutionRawReadPtr();
442 for (std::size_t i = 0; i < nRowElements; ++i) {
443 if (!utils::DoubleFloatingEqual()(expectedSolution[i] - solution[i], 0.0, SOLVER_RTOL, SOLVER_RTOL)) {
444 std::stringstream message;
445 message << "Solutions do not match for local DOF #" << i << ".";
446 message << " Expected solution is " << expectedSolution[i];
447 message << ", current solution is " << solution[i] << ".";
448 log::cout() << message.str() << std::endl;
449 isSolutionCorrect = false;
450 }
451 }
452 solver.restoreSolutionRawReadPtr(solution);
453 if (isSolutionCorrect) {
454 log::cout() << "Solutions match." << std::endl;
455 }
456 }
457
458 return 0;
459}
460
464int main(int argc, char *argv[])
465{
466#if BITPIT_ENABLE_MPI==1
467 MPI_Init(&argc, &argv);
468#else
469 BITPIT_UNUSED(argc);
470 BITPIT_UNUSED(argv);
471#endif
472
473 // Initialize the logger
474 int nProcs;
475 int rank;
476#if BITPIT_ENABLE_MPI==1
477 MPI_Comm_size(MPI_COMM_WORLD, &nProcs);
478 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
479#else
480 rank = 0;
481 nProcs = 1;
482#endif
483 log::manager().initialize(log::COMBINED, true, nProcs, rank);
484 log::cout().setDefaultVisibility(log::GLOBAL);
485
486 // Run the subtests
487 log::cout() << "Build, dump, solve and restore split linear system" << std::endl;
488
489 int status;
490 try {
491 status = run_dump(rank, nProcs);
492 if (status != 0) {
493 return status;
494 }
495
496 status = run_restore(rank, nProcs);
497 if (status != 0) {
498 return status;
499 }
500 } catch (const std::exception &exception) {
501 log::cout() << exception.what();
502 exit(1);
503 }
504
505#if BITPIT_ENABLE_MPI==1
506 MPI_Finalize();
507#endif
508}
The class AMGSplitSystemSolver is derived form SplitSystemSolver and it allows to solve the linear sy...
AMGSplitSystemSolver(bool transpose, bool multigrid, bool debug)
void setupPreconditioner(PC pc, const KSPOptions &options) const override
void initialize(log::Mode mode, bool reset, int nProcesses, int rank)
Definition logger.cpp:1268
void setDefaultVisibility(log::Visibility visibility)
Definition logger.cpp:579
The SplitSystemSolver class allows to solve a split linear system.
#define BITPIT_UNUSED(variable)
Definition compiler.hpp:63
int linearIndexRowMajor(int row, int col, int nRows, int nCols)
void transpose(std::vector< std::vector< T > > &, std::vector< std::vector< T > > &)
Logger & cout(log::Level defaultSeverity, log::Visibility defaultVisibility)
Definition logger.cpp:1705
Logger & debug(log::Visibility defaultVisibility)
Definition logger.cpp:1882
LoggerManager & manager()
Definition logger.cpp:1685
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.
--- layout: doxygen_footer ---