FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
multigrid.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, FEAT
9#include <kernel/solver/base.hpp>
10
11// includes, system
12#include <deque>
13#include <vector>
14
15namespace FEAT
16{
17 namespace Solver
18 {
24 enum class MultiGridCycle
25 {
27 V,
29 F,
31 W
32 };
33
38 {
40 Fixed,
45 };
46
48 inline std::ostream& operator<<(std::ostream& os, MultiGridCycle cycle)
49 {
50 switch(cycle)
51 {
53 return os << "V";
55 return os << "F";
57 return os << "W";
58 default:
59 return os << "?";
60 }
61 }
62
63 inline std::istream& operator>>(std::istream& is, MultiGridCycle& cycle)
64 {
65 // read character
66 char c(' ');
67 if((is >> c).fail())
68 return is;
69
70 switch(c)
71 {
72 case 'v':
73 case 'V':
74 cycle = MultiGridCycle::V;
75 break;
76
77 case 'f':
78 case 'F':
79 cycle = MultiGridCycle::F;
80 break;
81
82 case 'w':
83 case 'W':
84 cycle = MultiGridCycle::W;
85 break;
86
87 default:
88 // invalid character
89 is.putback(c);
90 is.setstate(std::ios_base::failbit);
91 break;
92 }
93
94 return is;
95 }
97
127 template<
128 typename SystemMatrix_,
129 typename SystemFilter_,
130 typename TransferOperator_>
132 {
133 public:
135 typedef SystemMatrix_ SystemMatrixType;
137 typedef SystemFilter_ SystemFilterType;
139 typedef TransferOperator_ TransferOperatorType;
141 typedef typename SystemMatrix_::VectorTypeR SystemVectorType;
144
145 public:
148 {
149 }
150
154 virtual const SystemMatrixType& get_system_matrix() const = 0;
155
159 virtual const SystemFilterType& get_system_filter() const = 0;
160
167 virtual const TransferOperatorType* get_transfer_operator() const = 0;
168
175 virtual std::shared_ptr<SolverType> get_coarse_solver() = 0;
176
184 virtual std::shared_ptr<SolverType> get_smoother_pre() = 0;
185
193 virtual std::shared_ptr<SolverType> get_smoother_post() = 0;
194
202 virtual std::shared_ptr<SolverType> get_smoother_peak() = 0;
203 }; // class MultiGridLevelBase<...>
204
228 template<
229 typename SystemMatrix_,
230 typename SystemFilter_,
231 typename TransferOperator_>
233 public MultiGridLevelBase<SystemMatrix_, SystemFilter_, TransferOperator_>
234 {
235 public:
248
249 protected:
257 std::shared_ptr<SolverType> coarse_solver;
259 std::shared_ptr<SolverType> smoother_pre;
261 std::shared_ptr<SolverType> smoother_post;
263 std::shared_ptr<SolverType> smoother_peak;
264
265 public:
281 const SystemMatrixType& sys_matrix,
282 const SystemFilterType& sys_filter,
283 std::shared_ptr<SolverType> crs_solver)
284 :
285 system_matrix(sys_matrix),
286 system_filter(sys_filter),
287 transfer_operator(nullptr),
288 coarse_solver(crs_solver),
289 smoother_pre(),
292 {
293 }
294
324 const SystemMatrixType& sys_matrix,
325 const SystemFilterType& sys_filter,
326 const TransferOperatorType& trans_operat,
327 std::shared_ptr<SolverType> smooth_pre,
328 std::shared_ptr<SolverType> smooth_post,
329 std::shared_ptr<SolverType> smooth_peak,
330 std::shared_ptr<SolverType> crs_solver = nullptr)
331 :
332 system_matrix(sys_matrix),
333 system_filter(sys_filter),
334 transfer_operator(&trans_operat),
335 coarse_solver(crs_solver),
336 smoother_pre(smooth_pre),
337 smoother_post(smooth_post),
338 smoother_peak(smooth_peak)
339 {
340 }
341
344 {
345 }
346
348 virtual const SystemMatrixType& get_system_matrix() const override
349 {
350 return system_matrix;
351 }
352
354 virtual const SystemFilterType& get_system_filter() const override
355 {
356 return system_filter;
357 }
358
360 virtual const TransferOperatorType* get_transfer_operator() const override
361 {
362 return transfer_operator;
363 }
364
366 virtual std::shared_ptr<SolverType> get_coarse_solver() override
367 {
368 return coarse_solver;
369 }
370
372 virtual std::shared_ptr<SolverType> get_smoother_pre() override
373 {
374 return smoother_pre;
375 }
376
378 virtual std::shared_ptr<SolverType> get_smoother_post() override
379 {
380 return smoother_post;
381 }
382
384 virtual std::shared_ptr<SolverType> get_smoother_peak() override
385 {
386 return smoother_peak;
387 }
388 }; // class MultiGridLevelStd<...>
389
390 // forward declaration
391 template<
392 typename SystemMatrix_,
393 typename SystemFilter_,
394 typename TransferOperator_>
395 class MultiGrid;
396
413 template<
414 typename SystemMatrix_,
415 typename SystemFilter_,
416 typename TransferOperator_>
418 {
419 public:
421 friend class MultiGrid<SystemMatrix_, SystemFilter_, TransferOperator_>;
422
427
438
439 protected:
447 {
448 public:
450 std::shared_ptr<LevelType> level;
452 std::deque<SolverType*> unique_solvers;
454 SystemVectorType vec_rhs, vec_sol, vec_def, vec_cor, vec_tmp;
455
458
461
464
467
468 explicit LevelInfo(std::shared_ptr<LevelType> lvl) :
469 level(lvl),
471 {
472 reset_timings();
473 }
474
475 void reset_timings()
476 {
478 }
479
480 void init_symbolic()
481 {
482 // build unique solver list
483 unique_solvers.clear();
484 _push_solver(level->get_coarse_solver().get());
485 _push_solver(level->get_smoother_pre().get());
486 _push_solver(level->get_smoother_post().get());
487 _push_solver(level->get_smoother_peak().get());
488
489 // initialize all unique solvers in forward order
490 for(auto it = unique_solvers.begin(); it != unique_solvers.end(); ++it)
491 (*it)->init_symbolic();
492
493 // get level system matrix
494 const SystemMatrixType& matrix = level->get_system_matrix();
495
496 // create our vectors
497 vec_rhs = matrix.create_vector_r();
498 vec_sol = matrix.create_vector_r();
499 vec_def = matrix.create_vector_r();
500 vec_cor = matrix.create_vector_r();
501 vec_tmp = matrix.create_vector_r();
502 }
503
504 void done_symbolic()
505 {
506 // release our vectors
507 vec_tmp.clear();
508 vec_cor.clear();
509 vec_def.clear();
510 vec_sol.clear();
511 vec_rhs.clear();
512
513 // release all unique solvers in reverse order
514 for(auto it = unique_solvers.rbegin(); it != unique_solvers.rend(); ++it)
515 (*it)->done_symbolic();
516 }
517
518 void init_numeric()
519 {
520 // initialize all unique solvers in forward order
521 for(auto it = unique_solvers.begin(); it != unique_solvers.end(); ++it)
522 (*it)->init_numeric();
523 }
524
525 void done_numeric()
526 {
527 // release all unique solvers in reverse order
528 for(auto it = unique_solvers.rbegin(); it != unique_solvers.rend(); ++it)
529 (*it)->done_numeric();
530 }
531
532 protected:
533 void _push_solver(SolverType* solver)
534 {
535 if(solver == nullptr)
536 return;
537
538 // loop over all existing solvers to determine uniqueness
539 for(auto it = unique_solvers.begin(); it != unique_solvers.end(); ++it)
540 {
541 // do we already have this solver object?
542 if(*it == solver)
543 return;
544 }
545
546 // alright, that's a new unique solver object, so add it
547 unique_solvers.push_back(solver);
548 }
549 }; // class LevelInfo
550
564 {
565 XASSERTM(lvl < size_physical(), "invalid level index");
566 return _levels.at(std::size_t(lvl));
567 }
568
569 protected:
571 std::deque<LevelInfo> _levels;
573 std::size_t _virt_size;
578
579 public:
586 explicit MultiGridHierarchy(std::size_t size_virt) :
587 _levels(),
588 _virt_size(size_virt),
589 _have_init_symbolic(false),
590 _have_init_numeric(false)
591 {
592 }
593
598 {
599 // delete levels in reverse order
600 while(!_levels.empty())
601 _levels.pop_back();
602 }
603
610 void push_level(std::shared_ptr<LevelType> level)
611 {
612 XASSERTM(!_have_init_symbolic, "cannot push new level, init_symbolic() was already called");
613 XASSERTM(!_have_init_numeric, "cannot push new level, init_numeric() was already called");
614 XASSERTM(_levels.size() < _virt_size, "cannot push new level, already have maximum number of levels");
615 _levels.push_back(LevelInfo(level));
616 }
617
632 const SystemMatrixType& system_matrix,
633 const SystemFilterType& system_filter,
634 std::shared_ptr<SolverType> coarse_solver)
635 {
636 push_level(std::make_shared<StdLevelType>(system_matrix, system_filter, coarse_solver));
637 }
638
676 const SystemMatrixType& system_matrix,
677 const SystemFilterType& system_filter,
678 const TransferOperatorType& transfer_operator,
679 std::shared_ptr<SolverType> smoother_pre,
680 std::shared_ptr<SolverType> smoother_post,
681 std::shared_ptr<SolverType> smoother_peak,
682 std::shared_ptr<SolverType> coarse_solver = nullptr
683 )
684 {
685 push_level(std::make_shared<StdLevelType>(system_matrix, system_filter, transfer_operator,
686 smoother_pre, smoother_post, smoother_peak, coarse_solver));
687 }
688
695 {
696 return Index(_levels.size());
697 }
698
705 {
706 return Index(_virt_size);
707 }
708
719 {
720 XASSERTM(lvl < size_physical(), "invalid level index");
721 return *(_levels.at(std::size_t(lvl)).level);
722 }
723
725 const LevelType& get_level(Index lvl) const
726 {
727 XASSERTM(lvl < size_physical(), "invalid level index");
728 return *(_levels.at(std::size_t(lvl)).level);
729 }
730
738 {
739 XASSERTM(!_have_init_numeric, "cannot call init_symbolic(): init_numeric() has already been called");
740 XASSERTM(!_have_init_symbolic, "cannot call init_symbolic(): init_symbolic() has already been called");
741
742 // initialize all levels in forward order
743 for(auto it = _levels.begin(); it != _levels.end(); ++it)
744 it->init_symbolic();
745
746 _have_init_symbolic = true;
747 }
748
756 {
757 XASSERTM(!_have_init_numeric, "cannot call done_symbolic(): done_numeric() has not been called yet");
758 XASSERTM(_have_init_symbolic, "cannot call done_symbolic(): init_symbolic() has not been called yet");
759
760 // release all levels in reverse order
761 for(auto it = _levels.rbegin(); it != _levels.rend(); ++it)
762 it->done_symbolic();
763
764 _have_init_symbolic = false;
765 }
766
775 {
776 XASSERTM(!_have_init_numeric, "cannot call init_numeric(): init_numeric() has already been called");
777 XASSERTM(_have_init_symbolic, "cannot call init_numeric(): init_symbolic() has not been called yet");
778
779 // initialize all levels in forward order
780 for(auto it = _levels.begin(); it != _levels.end(); ++it)
781 it->init_numeric();
782
783 _have_init_numeric = true;
784 }
785
793 {
794 XASSERTM(_have_init_numeric, "cannot call done_numeric(): init_numeric() has not been called yet");
795
796 // release all levels in reverse order
797 for(auto it = _levels.rbegin(); it != _levels.rend(); ++it)
798 it->done_numeric();
799
800 _have_init_numeric = false;
801 }
802
812 void init()
813 {
815 init_numeric();
816 }
817
827 void done()
828 {
829 done_numeric();
831 }
832
839 bool have_symbolic() const
840 {
841 return _have_init_symbolic;
842 }
843
850 bool have_numeric() const
851 {
852 return _have_init_numeric;
853 }
854
859 {
860 for(auto& li : _levels)
861 li.reset_timings();
862 }
863
873 double get_time_smooth(int lvl = -1) const
874 {
875 if(lvl < 0)
876 {
877 double t(0.0);
878 for(const auto& li : _levels)
879 t += li.time_smooth;
880 return t;
881 }
882
883 XASSERT(lvl < int(_levels.size()));
884 return _levels.at(std::size_t(lvl)).time_smooth;
885 }
886
896 double get_time_coarse(int lvl = -1) const
897 {
898 if(lvl < 0)
899 {
900 double t(0.0);
901 for(const auto& li : _levels)
902 t += li.time_coarse;
903 return t;
904 }
905
906 XASSERT(lvl < int(_levels.size()));
907 return _levels.at(std::size_t(lvl)).time_coarse;
908 }
909
919 double get_time_defect(int lvl = -1) const
920 {
921 if(lvl < 0)
922 {
923 double t(0.0);
924 for(const auto& li : _levels)
925 t += li.time_defect;
926 return t;
927 }
928
929 XASSERT(lvl < int(_levels.size()));
930 return _levels.at(std::size_t(lvl)).time_defect;
931 }
932
942 double get_time_transfer(int lvl = -1) const
943 {
944 if(lvl < 0)
945 {
946 double t(0.0);
947 for(const auto& li : _levels)
948 t += li.time_transfer;
949 return t;
950 }
951
952 XASSERT(lvl < int(_levels.size()));
953 return _levels.at(std::size_t(lvl)).time_transfer;
954 }
955 }; // class MultiGridHierarchy<...>
956
978 template<
979 typename SystemMatrix_,
980 typename SystemFilter_,
981 typename TransferOperator_>
982 class MultiGrid :
983 public SolverBase<typename SystemMatrix_::VectorTypeR>
984 {
985 public:
988
991
996
1007
1009 typedef typename MatrixType::DataType DataType;
1010
1011 protected:
1013 std::shared_ptr<HierarchyType> _hierarchy;
1022
1024 std::vector<int> _counters;
1025
1027 std::vector<double> _toes;
1029 std::vector<double> _mpi_execs_reduction;
1031 std::vector<double> _mpi_execs_blas2;
1033 std::vector<double> _mpi_execs_blas3;
1035 std::vector<double> _mpi_execs_collective;
1037 std::vector<double> _mpi_waits_reduction;
1039 std::vector<double> _mpi_waits_blas2;
1041 std::vector<double> _mpi_waits_blas3;
1043 std::vector<double> _mpi_waits_collective;
1044
1045 public:
1066 explicit MultiGrid(std::shared_ptr<HierarchyType> hierarchy, MultiGridCycle cycle, int top_level = 0, int crs_level = -1) :
1067 BaseClass(),
1068 _hierarchy(hierarchy),
1069 _cycle(cycle),
1071 _top_level(Index(top_level)),
1072 _crs_level(crs_level >= 0 ? Index(crs_level) : Index(int(_hierarchy->size_virtual()) + crs_level))
1073 {
1074 XASSERTM(_crs_level < _hierarchy->size_virtual(), "invalid coarse level");
1075 XASSERTM(_top_level <= _crs_level, "invalid top/coarse level combination");
1076 }
1077
1079 virtual ~MultiGrid()
1080 {
1081 }
1082
1090 {
1091 _adapt_cgc = adapt_cgc;
1092 }
1093
1101 {
1102 _cycle = cycle;
1103 }
1104
1111 {
1112 return _cycle;
1113 }
1114
1126 void set_levels(int top_level, int crs_level)
1127 {
1128 _top_level = Index(top_level);
1129 _crs_level = (crs_level >= 0 ? Index(crs_level) : Index(int(_hierarchy->size_virtual()) + crs_level));
1130
1131 XASSERTM(_crs_level < _hierarchy->size_virtual(), "invalid coarse level");
1132 XASSERTM(_top_level <= _crs_level, "invalid top/coarse level combination");
1133 }
1134
1141 {
1142 return _top_level;
1143 }
1144
1151 {
1152 return _crs_level;
1153 }
1154
1160 virtual String name() const override
1161 {
1162 return "MultiGrid-" + stringify(_cycle);
1163 }
1164
1174 virtual void init_symbolic() override
1175 {
1177
1178 // ensure that the hierarchy was initialized
1179 XASSERTM(_hierarchy->have_symbolic(), "init_symbolic() of multigrid hierarchy was not called yet");
1180
1181 // get the virtual hierarchy size
1182 const std::size_t num_lvls = _hierarchy->size_virtual();
1183
1184 // allocate counter vector
1185 _counters.resize(num_lvls, 0);
1186
1187 // allocate statistics vectors
1188 _toes.resize(num_lvls, 0.0);
1189 _mpi_execs_reduction.resize(num_lvls, 0.0);
1190 _mpi_execs_blas2.resize(num_lvls, 0.0);
1191 _mpi_execs_blas3.resize(num_lvls, 0.0);
1192 _mpi_execs_collective.resize(num_lvls, 0.0);
1193 _mpi_waits_reduction.resize(num_lvls, 0.0);
1194 _mpi_waits_blas2.resize(num_lvls, 0.0);
1195 _mpi_waits_blas3.resize(num_lvls, 0.0);
1196 _mpi_waits_collective.resize(num_lvls, 0.0);
1197 }
1198
1208 virtual void done_symbolic() override
1209 {
1210 _toes.clear();
1211 _mpi_execs_reduction.clear();
1212 _mpi_execs_blas2.clear();
1213 _mpi_execs_blas3.clear();
1214 _mpi_execs_collective.clear();
1215 _mpi_waits_reduction.clear();
1216 _mpi_waits_blas2.clear();
1217 _mpi_waits_blas3.clear();
1218 _mpi_waits_collective.clear();
1219 _counters.clear();
1220
1222 }
1223
1233 virtual void init_numeric() override
1234 {
1236
1237 // ensure that the hierarchy was initialized
1238 XASSERTM(_hierarchy->have_numeric(), "init_numeric() of multigrid hierarchy was not called yet");
1239 }
1240
1250 virtual void done_numeric() override
1251 {
1253 }
1254
1268 virtual Status apply(VectorType& vec_cor, const VectorType& vec_def) override
1269 {
1270 Statistics::add_solver_expression(std::make_shared<ExpressionStartSolve>(this->name()));
1271
1272 // reset statistics counters
1273 for(std::size_t i(0); i < std::size_t(_hierarchy->size_virtual()); ++i)
1274 {
1275 _toes.at(i) = 0.0;
1276 _mpi_execs_reduction.at(i) = 0.0;
1277 _mpi_execs_blas2.at(i) = 0.0;
1278 _mpi_execs_blas3.at(i) = 0.0;
1279 _mpi_execs_collective.at(i) = 0.0;
1280 _mpi_waits_reduction.at(i) = 0.0;
1281 _mpi_waits_blas2.at(i) = 0.0;
1282 _mpi_waits_blas3.at(i) = 0.0;
1283 _mpi_waits_collective.at(i) = 0.0;
1284 }
1285
1286 // get a reference to the finest level
1287 LevelInfo& lvl_top = _hierarchy->_get_level_info(_top_level);
1288
1289 // copy defect to RHS vector
1290 lvl_top.vec_rhs.copy(vec_def);
1291
1292 // apply the corresponding cycle
1293 Status status(Status::undefined);
1294 switch(_cycle)
1295 {
1296 case MultiGridCycle::V:
1297 status = this->_apply_cycle_v();
1298 break;
1299
1300 case MultiGridCycle::F:
1301 status = this->_apply_cycle_f();
1302 break;
1303
1304 case MultiGridCycle::W:
1305 status = this->_apply_cycle_w();
1306 break;
1307
1308 default:
1309 // whoops...
1310 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, 1));
1311 status = Status::aborted;
1312 break;
1313 }
1314
1315 // copy solution to correction vector
1316 vec_cor.copy(lvl_top.vec_sol);
1317
1318 // propagate solver statistics
1319 for(std::size_t i(0); i < std::size_t(_hierarchy->size_virtual()); ++i)
1320 {
1321 Statistics::add_solver_expression(std::make_shared<ExpressionLevelTimings>(this->name(), Index(i),
1324 }
1325
1326 // okay
1327 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::success, 1));
1328 return status;
1329 }
1330
1331 protected:
1334 {
1335 // The V-cycle is pretty simple:
1336 // 1) Restrict from the top level to the coarse level
1337 // 2) Solve coarse level system
1338 // 3) Prolongate from the coarse level to the top level
1339
1340 // restrict (apply top-level pre-smoother if it exists)
1341 this->_apply_rest(_top_level, true);
1342
1343 // solve coarse level
1344 this->_apply_coarse();
1345
1346 // prolongate (apply top-level post-smoother if it exists)
1347 this->_apply_prol(_top_level, true);
1348
1349 // okay
1350 return Status::success;
1351 }
1352
1355 {
1356 // The F-cycle is slightly more complex than the V-cycle:
1357 // 1) Restrict from the top level to the coarse level
1358 //
1359 // 2) For each intermediate level (that's everything between the
1360 // coarse and top level) in ascending order:
1361 // 2.1) solve the coarse system
1362 // 2.2) prolongate to the intermediate level without applying
1363 // the post-smoother on the intermediate level
1364 // 2.3) apply peak-smoother
1365 // 2.4) restrict to the coarse level without applying
1366 // the pre-smoother on the intermediate level
1367 //
1368 // 3) Solve the coarse level system
1369 //
1370 // 4) Prolongate from the coarse level to the top level
1371
1372 // restrict (apply top-level pre-smoother if it exists)
1373 this->_apply_rest(_top_level, true);
1374
1375 // get the coarsest level on this process; that's either the
1376 // coarse level or the last level for this process:
1377 const Index last_level = Math::min(_crs_level, _hierarchy->size_physical());
1378
1379 // ensure that we do not apply this if there is just one level
1380 if(last_level > Index(0))
1381 {
1382 // F-cycle intermediate peak-level loop
1383 for(Index peak_lvl(last_level-1); peak_lvl > _top_level; --peak_lvl)
1384 {
1385 // solve coarse level
1386 this->_apply_coarse();
1387
1388 // prolongate to current peak-level without post-smoothing
1389 this->_apply_prol(peak_lvl, false);
1390
1391 // apply peak-smoother
1392 this->_apply_smooth_peak(peak_lvl);
1393
1394 // restrict from current peak-level without pre-smoothing
1395 this->_apply_rest(peak_lvl, false);
1396 }
1397 }
1398
1399 // solve coarse level
1400 this->_apply_coarse();
1401
1402 // prolongate (apply top-level post-smoother if it exists)
1403 this->_apply_prol(_top_level, true);
1404
1405 // okay
1406 return Status::success;
1407 }
1408
1411 {
1412 // The W-cycle is a tough nut to implement/understand:
1413 // As always, we start by restricting from the top level to the
1414 // coarse level and solving the coarse level system afterwards.
1415 //
1416 // The next part is the tricky bit:
1417 // We need to implement the "inner W-cycle part". In theory,
1418 // this is usually defined as a "recursive 2x V-cycle application",
1419 // but we do not want to use recursion here explicitly.
1420 // We know that the W-cycle performs 2^(top_level - crs_level)
1421 // coarse grid solves, so we use that for our for-loop.
1422 // Moreover, we manage a counter for each level above the coarse
1423 // level and count how often we have applied the peak-smoother.
1424 // Each iteration we choose the lowest level that has a peak-smooth
1425 // count equal to 0 as the next intermediate level, increment
1426 // its counter by 1 and reset all level counters below this level
1427 // back to 0. This may sound perfectly confusing, but it actually
1428 // does the job :) See the description of the multigrid cycles
1429 // in the documentation for further explanations and a fancy image
1430 // of the W-cycle level counters in action.
1431 //
1432 // Oh yes, and finally we also need to prolongate from the
1433 // coarse level to the top level, of course.
1434
1435 // restrict (apply top-level pre-smoother if it exists)
1436 this->_apply_rest(_top_level, true);
1437
1438 // solve coarse level
1439 this->_apply_coarse();
1440
1441 // get the coarsest level on this process; that's either the
1442 // coarse level or the last level for this process:
1443 const Index last_level = Math::min(_crs_level, _hierarchy->size_physical());
1444
1445 // reset all level counters to 0
1446 for(std::size_t i(_top_level); i <= std::size_t(last_level); ++i)
1447 {
1448 _counters[i] = 0;
1449 }
1450
1451 // compute the total number of coarse-grid solves to perform:
1452 // that's = 2^(top_level - crs_level)
1453 const int num_cgs = 1 << (last_level - _top_level);
1454
1455 // W-cycle loop: count the number of coarse-grid solves
1456 for(int cgs(1); cgs < num_cgs; ++cgs)
1457 {
1458 // find the next peak level; that's the lowest level
1459 // above the coarse level whose counter is 0
1460 std::size_t peak_lvl = std::size_t(last_level);
1461 while(peak_lvl > std::size_t(_top_level))
1462 {
1463 // if the counter is 0, we have our next peak level
1464 if(_counters[--peak_lvl] == 0)
1465 break;
1466 }
1467
1468 // >>>>> DEBUG >>>>>
1469 //std::cout << stringify(cgs).pad_front(3) << " ";
1470 //std::cout << stringify(peak_lvl).pad_front(2) << ":";
1471 //for(std::size_t i(0); i <= std::size_t(top_lvl); ++i)
1472 // std::cout << " " << _counters[i];
1473 // <<<<< DEBUG <<<<<
1474
1475 // sanity check: do not go beyond our top level
1476 XASSERTM(peak_lvl >= _top_level, "W-cycle sanity check failed: invalid peak level");
1477
1478 // reset all counters below our peak level to 0
1479 for(std::size_t i = std::size_t(last_level-1); i > peak_lvl; --i)
1480 _counters[i] = 0;
1481
1482 // increment the counter of our peak level by 1,
1483 // indicating that we are going to perform an
1484 // peak-smoother step on this level
1485 ++_counters[peak_lvl];
1486
1487 // >>>>> DEBUG >>>>>
1488 //std::cout << " >";
1489 //for(std::size_t i(0); i <= std::size_t(top_lvl); ++i)
1490 // std::cout << " " << _counters[i];
1491 //std::cout << "\n";
1492 // <<<<< DEBUG <<<<<
1493
1494 // prolongate to current peak-level without post-smoothing
1495 this->_apply_prol(Index(peak_lvl), false);
1496
1497 // apply peak-smoother
1498 this->_apply_smooth_peak(Index(peak_lvl));
1499
1500 // restrict from current peak-level without pre-smoothing
1501 this->_apply_rest(Index(peak_lvl), false);
1502
1503 // solve coarse level
1504 this->_apply_coarse();
1505 }
1506
1507 // sanity check: all level counters above the coarse level must be 1
1508 for(std::size_t i(last_level); i > std::size_t(_top_level); )
1509 {
1510 --i;
1511 XASSERTM(this->_counters[i] == 1, "W-cycle sanity check failed: invalid counters");
1512 }
1513
1514 // prolongate (apply top-level post-smoother if it exists)
1515 this->_apply_prol(_top_level, true);
1516
1517 // okay
1518 return Status::success;
1519 }
1520
1525 {
1526 // no coarse level on this process?
1527 if(_crs_level >= _hierarchy->size_physical())
1528 return Status::success;
1529
1530 // process the coarse grid level
1531 TimeStamp at;
1532 double mpi_exec_reduction_start(Statistics::get_time_mpi_execute_reduction());
1533 double mpi_exec_blas2_start(Statistics::get_time_mpi_execute_blas2());
1534 double mpi_exec_blas3_start(Statistics::get_time_mpi_execute_blas3());
1535 double mpi_exec_collective_start(Statistics::get_time_mpi_execute_collective());
1536 double mpi_wait_start_reduction(Statistics::get_time_mpi_wait_reduction());
1537 double mpi_wait_start_blas2(Statistics::get_time_mpi_wait_blas2());
1538 double mpi_wait_start_blas3(Statistics::get_time_mpi_wait_blas3());
1539 double mpi_wait_start_collective(Statistics::get_time_mpi_wait_collective());
1540
1541 // get the coarse level info
1542 LevelInfo& lvl_crs = _hierarchy->_get_level_info(_crs_level);
1543
1544 // get the system filter
1545 const FilterType& system_filter = lvl_crs.level->get_system_filter();
1546
1547 // get the coarse grid solver
1548 std::shared_ptr<SolverType> coarse_solver = lvl_crs.level->get_coarse_solver();
1549
1550 // if the have a coarse grid solver, apply it
1551 TimeStamp stamp_coarse;
1552 if(coarse_solver)
1553 {
1554 Statistics::add_solver_expression(std::make_shared<ExpressionCallCoarseSolver>(this->name(), coarse_solver->name()));
1555 if(!status_success(coarse_solver->apply(lvl_crs.vec_sol, lvl_crs.vec_rhs)))
1556 return Status::aborted;
1557 }
1558 else
1559 {
1560 // simply copy the RHS thus emulating an identity solver
1561 lvl_crs.vec_sol.copy(lvl_crs.vec_rhs);
1562
1563 // apply the correction filter
1564 system_filter.filter_cor(lvl_crs.vec_sol);
1565 }
1566 lvl_crs.time_coarse += stamp_coarse.elapsed_now();
1567
1568 _toes.at(std::size_t(_crs_level)) += at.elapsed_now();
1569 double mpi_exec_reduction_stop(Statistics::get_time_mpi_execute_reduction());
1570 double mpi_exec_blas2_stop(Statistics::get_time_mpi_execute_blas2());
1571 double mpi_exec_blas3_stop(Statistics::get_time_mpi_execute_blas3());
1572 double mpi_exec_collective_stop(Statistics::get_time_mpi_execute_collective());
1573 double mpi_wait_stop_reduction(Statistics::get_time_mpi_wait_reduction());
1574 double mpi_wait_stop_blas2(Statistics::get_time_mpi_wait_blas2());
1575 double mpi_wait_stop_blas3(Statistics::get_time_mpi_wait_blas3());
1576 double mpi_wait_stop_collective(Statistics::get_time_mpi_wait_collective());
1577 _mpi_execs_reduction.at(std::size_t(_crs_level)) += mpi_exec_reduction_stop - mpi_exec_reduction_start;
1578 _mpi_execs_blas2.at(std::size_t(_crs_level)) += mpi_exec_blas2_stop - mpi_exec_blas2_start;
1579 _mpi_execs_blas3.at(std::size_t(_crs_level)) += mpi_exec_blas3_stop - mpi_exec_blas3_start;
1580 _mpi_execs_collective.at(std::size_t(_crs_level)) += mpi_exec_collective_stop - mpi_exec_collective_start;
1581 _mpi_waits_reduction.at(std::size_t(_crs_level)) += mpi_wait_stop_reduction - mpi_wait_start_reduction;
1582 _mpi_waits_blas2.at(std::size_t(_crs_level)) += mpi_wait_stop_blas2 - mpi_wait_start_blas2;
1583 _mpi_waits_blas3.at(std::size_t(_crs_level)) += mpi_wait_stop_blas3 - mpi_wait_start_blas3;
1584 _mpi_waits_collective.at(std::size_t(_crs_level)) += mpi_wait_stop_collective - mpi_wait_start_collective;
1585
1586 return Status::success;
1587 }
1588
1589 bool _apply_smooth_def(Index cur_lvl, SolverType& smoother)
1590 {
1591 // get the level info
1592 LevelInfo& lvl = _hierarchy->_get_level_info(cur_lvl);
1593
1594 // get the system matrix and filter
1595 const MatrixType& system_matrix = lvl.level->get_system_matrix();
1596 const FilterType& system_filter = lvl.level->get_system_filter();
1597
1598 // apply peak-smoother
1599 TimeStamp stamp_smooth;
1600 Statistics::add_solver_expression(std::make_shared<ExpressionCallSmoother>(this->name(), smoother.name()));
1601 smoother.apply(lvl.vec_cor, lvl.vec_def);
1602 //if(!status_success(smoother.apply(lvl.vec_cor, lvl.vec_def)))
1603 //return false;
1604 lvl.time_smooth += stamp_smooth.elapsed_now();
1605
1606 // apply correction filter
1607 system_filter.filter_cor(lvl.vec_cor);
1608
1609 // update solution vector
1610 lvl.vec_sol.axpy(lvl.vec_cor);
1611
1612 // re-compute defect
1613 TimeStamp stamp_defect;
1614 system_matrix.apply(lvl.vec_def, lvl.vec_sol, lvl.vec_rhs, -DataType(1));
1615 lvl.time_defect += stamp_defect.elapsed_now();
1616
1617 // apply defect filter
1618 system_filter.filter_def(lvl.vec_def);
1619
1620 // okay
1621 return true;
1622 }
1623
1631 {
1632 TimeStamp at;
1633 double mpi_exec_reduction_start(Statistics::get_time_mpi_execute_reduction());
1634 double mpi_exec_blas2_start(Statistics::get_time_mpi_execute_blas2());
1635 double mpi_exec_blas3_start(Statistics::get_time_mpi_execute_blas3());
1636 double mpi_exec_collective_start(Statistics::get_time_mpi_execute_collective());
1637 double mpi_wait_start_reduction(Statistics::get_time_mpi_wait_reduction());
1638 double mpi_wait_start_blas2(Statistics::get_time_mpi_wait_blas2());
1639 double mpi_wait_start_blas3(Statistics::get_time_mpi_wait_blas3());
1640 double mpi_wait_start_collective(Statistics::get_time_mpi_wait_collective());
1641
1642 // get the level info
1643 LevelInfo& lvl = _hierarchy->_get_level_info(cur_lvl);
1644
1645 // get the system matrix and filter
1646 const MatrixType& system_matrix = lvl.level->get_system_matrix();
1647 const FilterType& system_filter = lvl.level->get_system_filter();
1648
1649 // compute defect
1650 TimeStamp stamp_defect;
1651 system_matrix.apply(lvl.vec_def, lvl.vec_sol, lvl.vec_rhs, -DataType(1));
1652 lvl.time_defect += stamp_defect.elapsed_now();
1653
1654 // apply defect filter
1655 system_filter.filter_def(lvl.vec_def);
1656
1657 // get the peak-smoother
1658 std::shared_ptr<SolverType> smoother_peak = lvl.level->get_smoother_peak();
1659
1660 // do we have a peak-smoother?
1661 if(smoother_peak)
1662 {
1663 // apply peak-smoother
1664 if(!this->_apply_smooth_def(cur_lvl, *smoother_peak))
1665 return Status::aborted;
1666 }
1667 else
1668 {
1669 // no peak-smoother given
1670 // apply the pre- and post-smoothers instead
1671 std::shared_ptr<SolverType> smoother_pre = lvl.level->get_smoother_pre();
1672 std::shared_ptr<SolverType> smoother_post = lvl.level->get_smoother_post();
1673
1674 if((smoother_pre) && (!this->_apply_smooth_def(cur_lvl, *smoother_pre)))
1675 return Status::aborted;
1676 if((smoother_post) && (!this->_apply_smooth_def(cur_lvl, *smoother_post)))
1677 return Status::aborted;
1678 }
1679
1680 TimeStamp bt;
1681 _toes.at(std::size_t(cur_lvl)) += bt.elapsed(at);
1682 double mpi_exec_reduction_stop(Statistics::get_time_mpi_execute_reduction());
1683 double mpi_exec_blas2_stop(Statistics::get_time_mpi_execute_blas2());
1684 double mpi_exec_blas3_stop(Statistics::get_time_mpi_execute_blas3());
1685 double mpi_exec_collective_stop(Statistics::get_time_mpi_execute_collective());
1686 double mpi_wait_stop_reduction(Statistics::get_time_mpi_wait_reduction());
1687 double mpi_wait_stop_blas2(Statistics::get_time_mpi_wait_blas2());
1688 double mpi_wait_stop_blas3(Statistics::get_time_mpi_wait_blas3());
1689 double mpi_wait_stop_collective(Statistics::get_time_mpi_wait_collective());
1690 _mpi_execs_reduction.at(std::size_t(cur_lvl)) += mpi_exec_reduction_stop - mpi_exec_reduction_start;
1691 _mpi_execs_blas2.at(std::size_t(cur_lvl)) += mpi_exec_blas2_stop - mpi_exec_blas2_start;
1692 _mpi_execs_blas3.at(std::size_t(cur_lvl)) += mpi_exec_blas3_stop - mpi_exec_blas3_start;
1693 _mpi_execs_collective.at(std::size_t(cur_lvl)) += mpi_exec_collective_stop - mpi_exec_collective_start;
1694 _mpi_waits_reduction.at(std::size_t(cur_lvl)) += mpi_wait_stop_reduction - mpi_wait_start_reduction;
1695 _mpi_waits_blas2.at(std::size_t(cur_lvl)) += mpi_wait_stop_blas2 - mpi_wait_start_blas2;
1696 _mpi_waits_blas3.at(std::size_t(cur_lvl)) += mpi_wait_stop_blas3 - mpi_wait_start_blas3;
1697 _mpi_waits_collective.at(std::size_t(cur_lvl)) += mpi_wait_stop_collective - mpi_wait_start_collective;
1698
1699 return Status::success;
1700 }
1701
1711 Status _apply_rest(const Index cur_lvl, bool cur_smooth)
1712 {
1713 const Index last_level = Math::min(_crs_level, _hierarchy->size_physical());
1714
1715 // restriction loop: from current level to last level
1716 for(Index i(cur_lvl); i < last_level; ++i)
1717 {
1718 TimeStamp at;
1719 double mpi_exec_reduction_start(Statistics::get_time_mpi_execute_reduction());
1720 double mpi_exec_blas2_start(Statistics::get_time_mpi_execute_blas2());
1721 double mpi_exec_blas3_start(Statistics::get_time_mpi_execute_blas3());
1722 double mpi_exec_collective_start(Statistics::get_time_mpi_execute_collective());
1723 double mpi_wait_start_reduction(Statistics::get_time_mpi_wait_reduction());
1724 double mpi_wait_start_blas2(Statistics::get_time_mpi_wait_blas2());
1725 double mpi_wait_start_blas3(Statistics::get_time_mpi_wait_blas3());
1726 double mpi_wait_start_collective(Statistics::get_time_mpi_wait_collective());
1727
1728 // get our fine and coarse levels
1729 LevelInfo& lvl_f = _hierarchy->_get_level_info(i);
1730
1731 // get system matrix and filters
1732 const MatrixType& system_matrix = lvl_f.level->get_system_matrix();
1733 const FilterType& system_filter_f = lvl_f.level->get_system_filter();
1734
1735 // get our pre-smoother
1736 std::shared_ptr<SolverType> smoother = lvl_f.level->get_smoother_pre();
1737
1738 // The following if-block ensures that we never apply the pre-smoother
1739 // when restricting from an intermediate peak-level in the F- or W-cycle,
1740 // as otherwise the following statements would discard the solution vector
1741 // approximation that has already been computed by prior restriction and
1742 // peak-smoothing operations.
1743 if(cur_smooth || (i > cur_lvl))
1744 {
1745 // apply pre-smoother if we have one
1746 if(smoother)
1747 {
1748 // apply pre-smoother
1749 TimeStamp stamp_smooth;
1750 Statistics::add_solver_expression(std::make_shared<ExpressionCallSmoother>(this->name(), smoother->name()));
1751 smoother->apply(lvl_f.vec_sol, lvl_f.vec_rhs);
1752 //if(!status_success(smoother->apply(lvl_f.vec_sol, lvl_f.vec_rhs)))
1753 //return Status::aborted;
1754 lvl_f.time_smooth += stamp_smooth.elapsed_now();
1755
1756 // compute defect
1757 TimeStamp stamp_defect;
1758 system_matrix.apply(lvl_f.vec_def, lvl_f.vec_sol, lvl_f.vec_rhs, -DataType(1));
1759 lvl_f.time_defect += stamp_defect.elapsed_now();
1760 }
1761 else
1762 {
1763 // format solution
1764 lvl_f.vec_sol.format();
1765
1766 // set our rhs as defect
1767 lvl_f.vec_def.copy(lvl_f.vec_rhs);
1768 }
1769 }
1770
1771 // filter our defect
1772 system_filter_f.filter_def(lvl_f.vec_def);
1773
1774 // get our transfer operator
1775 const TransferOperatorType* transfer_operator = lvl_f.level->get_transfer_operator();
1776 XASSERTM(transfer_operator != nullptr, "transfer operator is missing");
1777
1778 // break loop?
1779 bool break_loop = false;
1780
1781 // ghost transfer?
1782 if(transfer_operator->is_ghost())
1783 {
1784 // send restriction to parent processes and return
1785 TimeStamp stamp_rest;
1786 transfer_operator->rest_send(lvl_f.vec_def);
1787 lvl_f.time_transfer += stamp_rest.elapsed_now();
1788 break_loop = true;
1789 }
1790 else
1791 {
1792 // okay, get coarse level
1793 LevelInfo& lvl_c = _hierarchy->_get_level_info(i+1);
1794 const FilterType& system_filter_c = lvl_c.level->get_system_filter();
1795
1796 // restrict onto coarse level
1797 //Statistics::add_solver_expression(std::make_shared<ExpressionRestriction>(this->name(), i));
1798 TimeStamp stamp_rest;
1799 transfer_operator->rest(lvl_f.vec_def, lvl_c.vec_rhs);
1800 lvl_f.time_transfer += stamp_rest.elapsed_now();
1801
1802 // filter coarse defect
1803 system_filter_c.filter_def(lvl_c.vec_rhs);
1804 }
1805
1806 // collect timings
1807 _toes.at((size_t)i) += at.elapsed_now();
1808 double mpi_exec_reduction_stop(Statistics::get_time_mpi_execute_reduction());
1809 double mpi_exec_blas2_stop(Statistics::get_time_mpi_execute_blas2());
1810 double mpi_exec_blas3_stop(Statistics::get_time_mpi_execute_blas3());
1811 double mpi_exec_collective_stop(Statistics::get_time_mpi_execute_collective());
1812 double mpi_wait_stop_reduction(Statistics::get_time_mpi_wait_reduction());
1813 double mpi_wait_stop_blas2(Statistics::get_time_mpi_wait_blas2());
1814 double mpi_wait_stop_blas3(Statistics::get_time_mpi_wait_blas3());
1815 double mpi_wait_stop_collective(Statistics::get_time_mpi_wait_collective());
1816 _mpi_execs_reduction.at((size_t)i) += mpi_exec_reduction_stop - mpi_exec_reduction_start;
1817 _mpi_execs_blas2.at((size_t)i) += mpi_exec_blas2_stop - mpi_exec_blas2_start;
1818 _mpi_execs_blas3.at((size_t)i) += mpi_exec_blas3_stop - mpi_exec_blas3_start;
1819 _mpi_execs_collective.at((size_t)i) += mpi_exec_collective_stop - mpi_exec_collective_start;
1820 _mpi_waits_reduction.at((size_t)i) += mpi_wait_stop_reduction - mpi_wait_start_reduction;
1821 _mpi_waits_blas2.at((size_t)i) += mpi_wait_stop_blas2 - mpi_wait_start_blas2;
1822 _mpi_waits_blas3.at((size_t)i) += mpi_wait_stop_blas3 - mpi_wait_start_blas3;
1823 _mpi_waits_collective.at((size_t)i) += mpi_wait_stop_collective - mpi_wait_start_collective;
1824
1825 if(break_loop)
1826 break;
1827
1828 // descent to prior level
1829 }
1830
1831 return Status::success;
1832 }
1833
1843 virtual Status _apply_prol(const Index cur_lvl, bool cur_smooth)
1844 {
1845 const Index last_level = Math::min(_crs_level, _hierarchy->size_physical());
1846
1847 // prolongation loop: from last level to current level
1848 for(Index i(last_level); i > cur_lvl;)
1849 {
1850 --i;
1851 TimeStamp at;
1852 double mpi_exec_reduction_start(Statistics::get_time_mpi_execute_reduction());
1853 double mpi_exec_blas2_start(Statistics::get_time_mpi_execute_blas2());
1854 double mpi_exec_blas3_start(Statistics::get_time_mpi_execute_blas3());
1855 double mpi_exec_collective_start(Statistics::get_time_mpi_execute_collective());
1856 double mpi_wait_start_reduction(Statistics::get_time_mpi_wait_reduction());
1857 double mpi_wait_start_blas2(Statistics::get_time_mpi_wait_blas2());
1858 double mpi_wait_start_blas3(Statistics::get_time_mpi_wait_blas3());
1859 double mpi_wait_start_collective(Statistics::get_time_mpi_wait_collective());
1860
1861 // get our fine level
1862 LevelInfo& lvl_f = _hierarchy->_get_level_info(i);
1863
1864 // get our transfer operator
1865 const TransferOperatorType* transfer_operator = lvl_f.level->get_transfer_operator();
1866 XASSERTM(transfer_operator != nullptr, "transfer operator is missing");
1867
1868 // ghost transfer?
1869 if(transfer_operator->is_ghost())
1870 {
1871 // receive prolongation
1872 TimeStamp stamp_prol;
1873 transfer_operator->prol_recv(lvl_f.vec_cor);
1874 lvl_f.time_transfer += stamp_prol.elapsed_now();
1875 }
1876 else
1877 {
1878 // get coarse level
1879 LevelInfo& lvl_c = _hierarchy->_get_level_info(i+1);
1880
1881 // prolongate
1882 TimeStamp stamp_prol;
1883 transfer_operator->prol(lvl_f.vec_cor, lvl_c.vec_sol);
1884 lvl_f.time_transfer += stamp_prol.elapsed_now();
1885 }
1886
1887 // get system matrix and filters
1888 const MatrixType& system_matrix = lvl_f.level->get_system_matrix();
1889 const FilterType& system_filter_f = lvl_f.level->get_system_filter();
1890
1891 // apply correction filter
1892 system_filter_f.filter_cor(lvl_f.vec_cor);
1893
1894 // initialize omega for (adaptive) coarse grid correction
1895 DataType omega_cgc = DataType(1);
1896
1897 // use some sort of adaptive cgc?
1899 {
1900 // multiply coarse grid correction by system matrix
1901 TimeStamp stamp_defect;
1902 system_matrix.apply(lvl_f.vec_tmp, lvl_f.vec_cor);
1903 lvl_f.time_defect += stamp_defect.elapsed_now();
1904
1905 // apply filter
1906 system_filter_f.filter_def(lvl_f.vec_tmp);
1907
1908 // compute adaptive omega
1909 switch(_adapt_cgc)
1910 {
1912 omega_cgc = lvl_f.vec_def.dot(lvl_f.vec_cor)
1913 / lvl_f.vec_tmp.dot(lvl_f.vec_cor);
1914 break;
1915
1917 omega_cgc = lvl_f.vec_def.dot(lvl_f.vec_tmp)
1918 / lvl_f.vec_tmp.dot(lvl_f.vec_tmp);
1919 break;
1920
1921 default:
1922 // This default block is required to make the GCC happy...
1923 break;
1924 }
1925 }
1926
1927 // update our solution vector
1928 lvl_f.vec_sol.axpy(lvl_f.vec_cor, omega_cgc);
1929
1930 // get our post-smoother
1931 std::shared_ptr<SolverType> smoother = lvl_f.level->get_smoother_post();
1932
1933 // apply post-smoother if we have one
1934 if(smoother && (cur_smooth || (i > cur_lvl)))
1935 {
1936 // compute new defect
1938 {
1939 // We have used some sort of adaptive coarse grid correction.
1940 // In this case, the current solution vector is
1941 // sol_new = sol_old + omega * cor
1942 //
1943 // Moreover, we have the following vectors at hand:
1944 // 1) tmp = A*cor
1945 // 2) def_old = rhs - A*sol_old
1946 //
1947 // So we can apply the same "trick" as in the PCG method to update our
1948 // defect vector instead of recomputing it by a matrix-vector mult, i.e.:
1949 // def_new = rhs - A * sol_new
1950 // = rhs - A * (sol_old + omega * cor)
1951 // = rhs - A * sol_old - omega * A * cor
1952 // = def_old - omega * tmp
1953 lvl_f.vec_def.axpy(lvl_f.vec_tmp, -omega_cgc);
1954 }
1955 else
1956 {
1957 // we have to recompute the defect by (rhs - A*sol_new)
1958 TimeStamp stamp_defect;
1959 system_matrix.apply(lvl_f.vec_def, lvl_f.vec_sol, lvl_f.vec_rhs, -DataType(1));
1960 lvl_f.time_defect += stamp_defect.elapsed_now();
1961
1962 // apply defect filter
1963 system_filter_f.filter_def(lvl_f.vec_def);
1964 }
1965
1966 // apply post-smoother
1967 Statistics::add_solver_expression(std::make_shared<ExpressionCallSmoother>(this->name(), smoother->name()));
1968 TimeStamp stamp_smooth;
1969 smoother->apply(lvl_f.vec_cor, lvl_f.vec_def);
1970 //if(!status_success(smoother->apply(lvl_f.vec_cor, lvl_f.vec_def)))
1971 //return Status::aborted;
1972 lvl_f.time_smooth += stamp_smooth.elapsed_now();
1973
1974 // update solution vector
1975 lvl_f.vec_sol.axpy(lvl_f.vec_cor);
1976 }
1977
1978 _toes.at((size_t)i) += at.elapsed_now();
1979 double mpi_exec_reduction_stop(Statistics::get_time_mpi_execute_reduction());
1980 double mpi_exec_blas2_stop(Statistics::get_time_mpi_execute_blas2());
1981 double mpi_exec_blas3_stop(Statistics::get_time_mpi_execute_blas3());
1982 double mpi_exec_collective_stop(Statistics::get_time_mpi_execute_collective());
1983 double mpi_wait_stop_reduction(Statistics::get_time_mpi_wait_reduction());
1984 double mpi_wait_stop_blas2(Statistics::get_time_mpi_wait_blas2());
1985 double mpi_wait_stop_blas3(Statistics::get_time_mpi_wait_blas3());
1986 double mpi_wait_stop_collective(Statistics::get_time_mpi_wait_collective());
1987 _mpi_execs_reduction.at((size_t)i) += mpi_exec_reduction_stop - mpi_exec_reduction_start;
1988 _mpi_execs_blas2.at((size_t)i) += mpi_exec_blas2_stop - mpi_exec_blas2_start;
1989 _mpi_execs_blas3.at((size_t)i) += mpi_exec_blas3_stop - mpi_exec_blas3_start;
1990 _mpi_execs_collective.at((size_t)i) += mpi_exec_collective_stop - mpi_exec_collective_start;
1991 _mpi_waits_reduction.at((size_t)i) += mpi_wait_stop_reduction - mpi_wait_start_reduction;
1992 _mpi_waits_blas2.at((size_t)i) += mpi_wait_stop_blas2 - mpi_wait_start_blas2;
1993 _mpi_waits_blas3.at((size_t)i) += mpi_wait_stop_blas3 - mpi_wait_start_blas3;
1994 _mpi_waits_collective.at((size_t)i) += mpi_wait_stop_collective - mpi_wait_start_collective;
1995
1996 // ascend to next level
1997 }
1998
1999 return Status::success;
2000 }
2001 }; // class MultiGrid<...>
2002
2023 template<
2024 typename SystemMatrix_,
2025 typename SystemFilter_,
2026 typename TransferOperator_>
2027 std::shared_ptr<MultiGrid<SystemMatrix_, SystemFilter_, TransferOperator_>> new_multigrid(
2030 int top_level = 0,
2031 int crs_level = -1)
2032 {
2033 return std::make_shared<MultiGrid<SystemMatrix_, SystemFilter_, TransferOperator_>>
2034 (hierarchy, cycle, top_level, crs_level);
2035 }
2036 } // namespace Solver
2037} // namespace FEAT
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
std::shared_ptr< LevelType > level
the actual multigrid level
Definition: multigrid.hpp:450
double time_smooth
total smoother application time
Definition: multigrid.hpp:457
double time_coarse
coarse grid solver application time
Definition: multigrid.hpp:460
SystemVectorType vec_rhs
four temporary vectors
Definition: multigrid.hpp:454
double time_defect
defect computation time
Definition: multigrid.hpp:463
double time_transfer
prolongation/restriction times
Definition: multigrid.hpp:466
std::deque< SolverType * > unique_solvers
deque of unique solver object pointers
Definition: multigrid.hpp:452
Multigrid hierarchy management class template.
Definition: multigrid.hpp:418
double get_time_smooth(int lvl=-1) const
Returns the time for smoother application.
Definition: multigrid.hpp:873
LevelType & get_level(Index lvl)
Returns a level in the hierarchy.
Definition: multigrid.hpp:718
void done_symbolic()
Symbolic finalization method.
Definition: multigrid.hpp:755
MultiGridLevelBase< SystemMatrix_, SystemFilter_, TransferOperator_ > LevelType
the level base class type
Definition: multigrid.hpp:424
void init_numeric()
Numeric initialization method.
Definition: multigrid.hpp:774
void push_level(const SystemMatrixType &system_matrix, const SystemFilterType &system_filter, std::shared_ptr< SolverType > coarse_solver)
Pushes a standard coarse-grid level into the hierarchy.
Definition: multigrid.hpp:631
Index size_virtual() const
Returns the virtual hierarchy size.
Definition: multigrid.hpp:704
LevelInfo & _get_level_info(Index lvl)
Returns a level info in the hierarchy.
Definition: multigrid.hpp:563
virtual ~MultiGridHierarchy()
Destructor.
Definition: multigrid.hpp:597
LevelType::SystemFilterType SystemFilterType
the system filter type
Definition: multigrid.hpp:431
LevelType::TransferOperatorType TransferOperatorType
the transfer operator type
Definition: multigrid.hpp:435
void init_symbolic()
Symbolic initialization method.
Definition: multigrid.hpp:737
void push_level(std::shared_ptr< LevelType > level)
Pushes a new (custom) level into the hierarchy.
Definition: multigrid.hpp:610
std::size_t _virt_size
the virtual multigrid hierarchy sizes
Definition: multigrid.hpp:573
void done_numeric()
Numeric finalization method.
Definition: multigrid.hpp:792
void done()
Finalization method.
Definition: multigrid.hpp:827
std::deque< LevelInfo > _levels
the deque of all level info objects
Definition: multigrid.hpp:571
LevelType::SystemMatrixType SystemMatrixType
the system matrix type
Definition: multigrid.hpp:429
double get_time_transfer(int lvl=-1) const
Returns the time for grid transfer application.
Definition: multigrid.hpp:942
void reset_timings()
Resets the internal timing statistics.
Definition: multigrid.hpp:858
Index size_physical() const
Returns the physical hierarchy size.
Definition: multigrid.hpp:694
bool have_numeric() const
Specifies whether the symbolic initialization was performed.
Definition: multigrid.hpp:850
double get_time_coarse(int lvl=-1) const
Returns the time for coarse grid solver application.
Definition: multigrid.hpp:896
void init()
Initialization method.
Definition: multigrid.hpp:812
bool _have_init_symbolic
specifies whether init_symbolic() has been called
Definition: multigrid.hpp:575
LevelType::SystemVectorType SystemVectorType
the system vector type
Definition: multigrid.hpp:433
bool have_symbolic() const
Specifies whether the symbolic initialization was performed.
Definition: multigrid.hpp:839
LevelType::SolverType SolverType
the coarse-grid solver/smoother type
Definition: multigrid.hpp:437
MultiGridLevelStd< SystemMatrix_, SystemFilter_, TransferOperator_ > StdLevelType
the standard level class type
Definition: multigrid.hpp:426
MultiGridHierarchy(std::size_t size_virt)
Constructor.
Definition: multigrid.hpp:586
bool _have_init_numeric
specifies whether init_numeric() has been called
Definition: multigrid.hpp:577
void push_level(const SystemMatrixType &system_matrix, const SystemFilterType &system_filter, const TransferOperatorType &transfer_operator, std::shared_ptr< SolverType > smoother_pre, std::shared_ptr< SolverType > smoother_post, std::shared_ptr< SolverType > smoother_peak, std::shared_ptr< SolverType > coarse_solver=nullptr)
Pushes a standard refined level into the hierarchy.
Definition: multigrid.hpp:675
const LevelType & get_level(Index lvl) const
Returns a level in the hierarchy.
Definition: multigrid.hpp:725
double get_time_defect(int lvl=-1) const
Returns the time for defect computation.
Definition: multigrid.hpp:919
Multigrid preconditioner implementation.
Definition: multigrid.hpp:984
std::vector< double > _mpi_waits_blas3
array containing toe of mpi wait blas3 for each processed level
Definition: multigrid.hpp:1041
std::vector< double > _mpi_execs_reduction
array containing toe of mpi execution reduction for each processed level
Definition: multigrid.hpp:1029
Status _apply_coarse()
Applies the coarse grid solver on the coarse level.
Definition: multigrid.hpp:1524
LevelType::TransferOperatorType TransferOperatorType
the transfer operator type
Definition: multigrid.hpp:1004
Status _apply_cycle_w()
Applies a single W-cycle.
Definition: multigrid.hpp:1410
LevelType::SolverType SolverType
the sub-solver type
Definition: multigrid.hpp:1006
Status _apply_cycle_f()
Applies a single F-cycle.
Definition: multigrid.hpp:1354
Status _apply_cycle_v()
Applies a single V-cycle.
Definition: multigrid.hpp:1333
LevelType::SystemVectorType VectorType
the system vector type
Definition: multigrid.hpp:1002
Status _apply_rest(const Index cur_lvl, bool cur_smooth)
Restricts from the current level onto the coarse level.
Definition: multigrid.hpp:1711
virtual ~MultiGrid()
virtual destructor
Definition: multigrid.hpp:1079
virtual void init_numeric() override
Numeric initialization function.
Definition: multigrid.hpp:1233
std::vector< double > _mpi_execs_blas2
array containing toe of mpi execution blas2 for each processed level
Definition: multigrid.hpp:1031
Index _crs_level
the coarse-level of this multigrid
Definition: multigrid.hpp:1021
MultiGridCycle get_cycle() const
Returns the currently selected cycle.
Definition: multigrid.hpp:1110
MultiGridCycle _cycle
the multigrid cycle
Definition: multigrid.hpp:1015
virtual void done_symbolic() override
Symbolic finalization function.
Definition: multigrid.hpp:1208
void set_adapt_cgc(MultiGridAdaptCGC adapt_cgc)
Sets the adaption mode for the coarse grid correction.
Definition: multigrid.hpp:1089
HierarchyType::LevelType LevelType
the level type
Definition: multigrid.hpp:993
std::vector< double > _mpi_waits_collective
array containing toe of mpi wait collective for each processed level
Definition: multigrid.hpp:1043
Index _top_level
the top-level of this multigrid
Definition: multigrid.hpp:1019
MultiGridAdaptCGC _adapt_cgc
the coarse grid correction type
Definition: multigrid.hpp:1017
Index get_crs_level() const
Returns the currently selected coarse-level index.
Definition: multigrid.hpp:1150
MatrixType::DataType DataType
our data type
Definition: multigrid.hpp:1009
std::vector< double > _mpi_execs_blas3
array containing toe of mpi execution blas3 for each processed level
Definition: multigrid.hpp:1033
virtual Status _apply_prol(const Index cur_lvl, bool cur_smooth)
Prolongates from the coarse level onto the current level.
Definition: multigrid.hpp:1843
std::vector< double > _mpi_waits_reduction
array containing toe of mpi wait reduction for each processed level
Definition: multigrid.hpp:1037
std::vector< double > _toes
array containing toe for each processed level
Definition: multigrid.hpp:1027
virtual void init_symbolic() override
Symbolic initialization function.
Definition: multigrid.hpp:1174
virtual Status apply(VectorType &vec_cor, const VectorType &vec_def) override
Applies the multigrid preconditioner.
Definition: multigrid.hpp:1268
Index get_top_level() const
Returns the currently selected top-level index.
Definition: multigrid.hpp:1140
std::vector< int > _counters
W-cycle level counter vector.
Definition: multigrid.hpp:1024
void set_cycle(MultiGridCycle cycle)
Sets a new cycle.
Definition: multigrid.hpp:1100
virtual void done_numeric() override
Numeric finalization function.
Definition: multigrid.hpp:1250
virtual String name() const override
Returns a descriptive string.
Definition: multigrid.hpp:1160
void set_levels(int top_level, int crs_level)
Sets the level range for this multigrid.
Definition: multigrid.hpp:1126
std::vector< double > _mpi_execs_collective
array containing toe of mpi execution collective for each processed level
Definition: multigrid.hpp:1035
LevelType::SystemFilterType FilterType
the system filter type
Definition: multigrid.hpp:1000
LevelType::SystemMatrixType MatrixType
the system matrix type
Definition: multigrid.hpp:998
SolverBase< typename SystemMatrix_::VectorTypeR > BaseClass
our base-class
Definition: multigrid.hpp:987
Status _apply_smooth_peak(Index cur_lvl)
Applies the peak-smoother on the current level.
Definition: multigrid.hpp:1630
std::vector< double > _mpi_waits_blas2
array containing toe of mpi wait blas2 for each processed level
Definition: multigrid.hpp:1039
HierarchyType::LevelInfo LevelInfo
the level info type
Definition: multigrid.hpp:995
MultiGrid(std::shared_ptr< HierarchyType > hierarchy, MultiGridCycle cycle, int top_level=0, int crs_level=-1)
Constructor.
Definition: multigrid.hpp:1066
std::shared_ptr< HierarchyType > _hierarchy
the multigrid hierarchy object
Definition: multigrid.hpp:1013
MultiGridHierarchy< SystemMatrix_, SystemFilter_, TransferOperator_ > HierarchyType
our compatible multigrid hierarchy class
Definition: multigrid.hpp:990
Multigrid level base class.
Definition: multigrid.hpp:132
virtual const SystemMatrixType & get_system_matrix() const =0
Returns a const reference to the system matrix.
virtual std::shared_ptr< SolverType > get_smoother_post()=0
Returns a shared pointer to the post-smoother.
SystemMatrix_::VectorTypeR SystemVectorType
the system vector type
Definition: multigrid.hpp:141
SolverBase< SystemVectorType > SolverType
the coarse-grid solver/smoother type
Definition: multigrid.hpp:143
virtual ~MultiGridLevelBase()
virtual destructor
Definition: multigrid.hpp:147
virtual std::shared_ptr< SolverType > get_smoother_pre()=0
Returns a shared pointer to the pre-smoother.
SystemMatrix_ SystemMatrixType
the system matrix type
Definition: multigrid.hpp:135
virtual std::shared_ptr< SolverType > get_smoother_peak()=0
Returns a shared pointer to the peak-smoother.
virtual std::shared_ptr< SolverType > get_coarse_solver()=0
Returns a shared pointer to the coarse grid solver.
virtual const SystemFilterType & get_system_filter() const =0
Returns a const reference to the system filter.
TransferOperator_ TransferOperatorType
the transfer operator type
Definition: multigrid.hpp:139
SystemFilter_ SystemFilterType
the system filter type
Definition: multigrid.hpp:137
virtual const TransferOperatorType * get_transfer_operator() const =0
Returns a const pointer to the transfer operator.
Standard Multigrid level class implementation.
Definition: multigrid.hpp:234
const TransferOperatorType * transfer_operator
the transfer matrix
Definition: multigrid.hpp:255
BaseClass::SystemMatrixType SystemMatrixType
the system-matrix type
Definition: multigrid.hpp:239
virtual ~MultiGridLevelStd()
virtual destructor
Definition: multigrid.hpp:343
MultiGridLevelStd(const SystemMatrixType &sys_matrix, const SystemFilterType &sys_filter, std::shared_ptr< SolverType > crs_solver)
Coarse-Grid level constructor.
Definition: multigrid.hpp:280
virtual std::shared_ptr< SolverType > get_smoother_pre() override
Returns a shared pointer to the pre-smoother.
Definition: multigrid.hpp:372
std::shared_ptr< SolverType > coarse_solver
the coarse-grid solver
Definition: multigrid.hpp:257
BaseClass::TransferOperatorType TransferOperatorType
the transfer operator type
Definition: multigrid.hpp:245
virtual const SystemFilterType & get_system_filter() const override
Returns a const reference to the system filter.
Definition: multigrid.hpp:354
std::shared_ptr< SolverType > smoother_peak
the peak-smoother
Definition: multigrid.hpp:263
virtual std::shared_ptr< SolverType > get_smoother_peak() override
Returns a shared pointer to the peak-smoother.
Definition: multigrid.hpp:384
const SystemMatrixType & system_matrix
the system matrix
Definition: multigrid.hpp:251
MultiGridLevelStd(const SystemMatrixType &sys_matrix, const SystemFilterType &sys_filter, const TransferOperatorType &trans_operat, std::shared_ptr< SolverType > smooth_pre, std::shared_ptr< SolverType > smooth_post, std::shared_ptr< SolverType > smooth_peak, std::shared_ptr< SolverType > crs_solver=nullptr)
Refined level constructor.
Definition: multigrid.hpp:323
BaseClass::SystemFilterType SystemFilterType
the system-filter type
Definition: multigrid.hpp:241
std::shared_ptr< SolverType > smoother_post
the post-smoother
Definition: multigrid.hpp:261
std::shared_ptr< SolverType > smoother_pre
the pre-smoother
Definition: multigrid.hpp:259
virtual std::shared_ptr< SolverType > get_smoother_post() override
Returns a shared pointer to the post-smoother.
Definition: multigrid.hpp:378
virtual const TransferOperatorType * get_transfer_operator() const override
Returns a const pointer to the transfer operator.
Definition: multigrid.hpp:360
BaseClass::SystemVectorType SystemVectorType
the system-vector type
Definition: multigrid.hpp:243
virtual std::shared_ptr< SolverType > get_coarse_solver() override
Returns a shared pointer to the coarse grid solver.
Definition: multigrid.hpp:366
virtual const SystemMatrixType & get_system_matrix() const override
Returns a const reference to the system matrix.
Definition: multigrid.hpp:348
BaseClass::SolverType SolverType
the coarse-grid solver/smoother type
Definition: multigrid.hpp:247
const SystemFilterType & system_filter
the system filter
Definition: multigrid.hpp:253
MultiGridLevelBase< SystemMatrix_, SystemFilter_, TransferOperator_ > BaseClass
the base-class type
Definition: multigrid.hpp:237
Polymorphic solver interface.
Definition: base.hpp:183
virtual void init_symbolic()
Symbolic initialization method.
Definition: base.hpp:227
virtual void init_numeric()
Numeric initialization method.
Definition: base.hpp:237
virtual void done_symbolic()
Symbolic finalization method.
Definition: base.hpp:255
virtual void done_numeric()
Numeric finalization method.
Definition: base.hpp:246
String class implementation.
Definition: string.hpp:46
Time stamp class.
Definition: time_stamp.hpp:54
double elapsed(const TimeStamp &before) const
Calculates the time elapsed between two time stamps.
Definition: time_stamp.hpp:100
double elapsed_now() const
Calculates the time elapsed between the time stamp and now.
Definition: time_stamp.hpp:121
T_ min(T_ a, T_ b)
Returns the minimum of two values.
Definition: math.hpp:123
std::istream & operator>>(std::istream &is, Pack::Type &t)
stream input operator for Pack::Type
Definition: pack.hpp:189
bool status_success(Status status)
Status success check function.
Definition: base.hpp:108
std::shared_ptr< MultiGrid< SystemMatrix_, SystemFilter_, TransferOperator_ > > new_multigrid(std::shared_ptr< MultiGridHierarchy< SystemMatrix_, SystemFilter_, TransferOperator_ > > hierarchy, MultiGridCycle cycle=MultiGridCycle::V, int top_level=0, int crs_level=-1)
Creates a new Multigrid preconditioner object.
Definition: multigrid.hpp:2027
MultiGridCycle
Multigrid Cycle enumeration.
Definition: multigrid.hpp:25
@ V
Multigrid V-Cycle.
@ W
Multigrid W-Cycle.
@ F
Multigrid F-Cycle.
MultiGridAdaptCGC
Multigrid adaptive Coarse-Grid-Correction enumeration.
Definition: multigrid.hpp:38
@ Fixed
fixed coarse grid correction damping
@ MinDefect
Defect-Minimization.
@ MinEnergy
Energy-Minimization.
Status
Solver status return codes enumeration.
Definition: base.hpp:47
@ success
solving successful (convergence criterion fulfilled)
@ undefined
undefined status
@ aborted
premature abort (solver aborted due to internal errors or preconditioner failure)
FEAT namespace.
Definition: adjactor.hpp:12
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:944
std::uint64_t Index
Index data type.