55 using backend_type = Backend;
56 using BackendType = Backend;
59 typedef typename Backend::value_type value_type;
60 typedef typename math::scalar_of<value_type>::type scalar_type;
62 typedef typename Backend::vector vector;
66 typedef typename Coarsening::params coarsening_params;
67 typedef typename Relaxation::params relax_params;
68 typedef typename DirectSolver::params direct_params;
69 typedef typename Repartition::params repart_params;
120 : ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p,
coarsening)
121 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p,
relax)
122 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p,
direct)
123 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p,
repart)
126 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
max_levels)
127 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
npre)
128 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
npost)
129 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
ncycle)
130 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
pre_cycles)
133 p.check_params({
"coarsening",
"relax",
"direct",
"repart",
"coarse_enough",
"direct_coarse",
"max_levels",
"npre",
"npost",
"ncycle",
"pre_cycles",
"allow_rebuild" });
135 Alina::precondition(
max_levels > 0,
"max_levels should be positive");
140 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path,
coarsening);
141 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path,
relax);
142 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path,
direct);
143 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, repart);
146 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
max_levels);
147 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
npre);
148 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
npost);
149 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
ncycle);
150 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
pre_cycles);
155 template <
class Matrix>
156 DistributedAMG([[maybe_unused]]
const AlinaContext& context,
157 AlinaCommunicator comm,
159 const params& prm = params(),
160 const backend_params& bprm = backend_params())
165 init(std::make_shared<matrix>(comm, A, backend::nbRow(A)), bprm);
168 DistributedAMG([[maybe_unused]]
const AlinaContext& context,
169 AlinaCommunicator comm,
170 std::shared_ptr<matrix> A,
171 const params& prm = params(),
172 const backend_params& bprm = backend_params())
186 template <
class Matrix>
188 const backend_params& bprm = backend_params())
190 rebuild(std::make_shared<matrix>(comm, M, backend::nbRow(M)), bprm);
193 template <
class OtherBackend>
194 typename std::enable_if<!std::is_same<Backend, OtherBackend>::value,
void>::type
196 const backend_params& bprm = backend_params())
198 return rebuild(std::make_shared<matrix>(*A), bprm);
201 void rebuild(std::shared_ptr<matrix> A,
202 const backend_params& bprm = backend_params())
204 precondition(prm.
allow_rebuild,
"allow_rebuild is not set!");
205 precondition(A->glob_rows() == system_matrix().glob_rows() &&
206 A->glob_cols() == system_matrix().glob_cols(),
207 "Matrix dimensions differ from the original ones!");
209 ARCCORE_ALINA_TIC(
"rebuild");
212 for (
auto& level : levels) {
213 A = level.rebuild(A, C, prm, bprm);
215 this->A->move_to_backend(bprm);
216 ARCCORE_ALINA_TOC(
"rebuild");
219 template <
class Vec1,
class Vec2>
220 void cycle(
const Vec1& rhs, Vec2&& x)
const
222 cycle(levels.begin(), rhs, x);
225 template <
class Vec1,
class Vec2>
226 void apply(
const Vec1& rhs, Vec2&& x)
const
228 if (prm.pre_cycles) {
230 for (
unsigned i = 0; i < prm.pre_cycles; ++i)
231 cycle(levels.begin(), rhs, x);
234 backend::copy(rhs, x);
244 const matrix& system_matrix()
const
251 struct DistributedAMGLevel
253 ptrdiff_t nrows, nnz;
256 std::shared_ptr<matrix> A, P, R;
257 std::shared_ptr<vector> f, u, t;
258 std::shared_ptr<Relaxation> relax;
259 std::shared_ptr<DirectSolver> solve;
261 DistributedAMGLevel() =
default;
263 DistributedAMGLevel(std::shared_ptr<matrix> a,
265 const backend_params& bprm,
267 : nrows(a->glob_rows())
268 , nnz(a->glob_nonzeros())
269 , f(Backend::create_vector(a->loc_rows(), bprm))
270 , u(Backend::create_vector(a->loc_rows(), bprm))
272 int active = (a->loc_rows() > 0);
273 active_procs = a->comm().reduceSum(active);
278 ARCCORE_ALINA_TIC(
"direct solver");
279 solve = std::make_shared<DirectSolver>(a->comm(), *a, prm.direct);
280 ARCCORE_ALINA_TOC(
"direct solver");
284 t = Backend::create_vector(a->loc_rows(), bprm);
286 ARCCORE_ALINA_TIC(
"relaxation");
287 relax = std::make_shared<Relaxation>(*a, prm.relax, bprm);
288 ARCCORE_ALINA_TOC(
"relaxation");
292 std::shared_ptr<matrix> step_down(Coarsening& C,
const Repartition& repart)
294 ARCCORE_ALINA_TIC(
"transfer operators");
295 std::tie(P, R) = C.transfer_operators(*A);
297 ARCCORE_ALINA_TIC(
"sort");
300 ARCCORE_ALINA_TOC(
"sort");
302 ARCCORE_ALINA_TOC(
"transfer operators");
304 if (P->glob_cols() == 0) {
306 return std::shared_ptr<matrix>();
309 ARCCORE_ALINA_TIC(
"coarse operator");
310 auto Ac = C.coarse_operator(*A, *P, *R);
311 ARCCORE_ALINA_TOC(
"coarse operator");
313 if (repart.is_needed(*Ac)) {
314 ARCCORE_ALINA_TIC(
"partition");
315 auto I = repart(*Ac, block_size(C));
316 auto J = transpose(*I);
320 Ac = product(*J, *product(*Ac, *I));
321 ARCCORE_ALINA_TOC(
"partition");
327 std::shared_ptr<matrix> rebuild(std::shared_ptr<matrix> A,
330 const backend_params& bprm)
333 relax = std::make_shared<Relaxation>(*A, prm.relax, bprm);
334 std::cout <<
"DistributedAMG: relaxation=" << relax <<
"\n";
338 solve = std::make_shared<DirectSolver>(A->comm(), *A, prm.direct);
346 A = C.coarse_operator(*A, *P, *R);
350 this->A->move_to_backend(bprm);
356 void move_to_backend(
const backend_params& bprm,
bool keep_src =
false)
358 ARCCORE_ALINA_TIC(
"move to backend");
360 A->move_to_backend(bprm);
362 P->move_to_backend(bprm, keep_src);
364 R->move_to_backend(bprm, keep_src);
365 ARCCORE_ALINA_TOC(
"move to backend");
368 ptrdiff_t rows()
const
373 ptrdiff_t nonzeros()
const
379 typedef typename std::list<DistributedAMGLevel>::const_iterator level_iterator;
382 std::shared_ptr<matrix> A;
384 std::list<DistributedAMGLevel> levels;
386 void init(std::shared_ptr<matrix> A,
const backend_params& bprm)
388 A->comm().
check(A->glob_rows() == A->glob_cols(),
"Matrix should be square!");
391 Coarsening C(prm.coarsening);
393 bool need_coarse =
true;
395 while (A->glob_rows() > prm.coarse_enough) {
398 if (levels.size() >= prm.max_levels) {
399 levels.back().move_to_backend(bprm, prm.allow_rebuild);
403 A = levels.back().step_down(C, repart);
420 if (A && need_coarse) {
422 levels.back().move_to_backend(bprm, prm.allow_rebuild);
425 ARCCORE_ALINA_TIC(
"move to backend");
426 this->A->move_to_backend(bprm, prm.allow_rebuild);
427 ARCCORE_ALINA_TOC(
"move to backend");
430 template <
class Vec1,
class Vec2>
431 void cycle(level_iterator lvl,
const Vec1& rhs, Vec2& x)
const
433 level_iterator nxt = lvl, end = levels.end();
438 ARCCORE_ALINA_TIC(
"direct solver");
439 (*lvl->solve)(rhs, x);
440 ARCCORE_ALINA_TOC(
"direct solver");
443 ARCCORE_ALINA_TIC(
"relax");
444 for (
size_t i = 0; i < prm.npre; ++i)
445 lvl->relax->apply_pre(*lvl->A, rhs, x, *lvl->t);
446 for (
size_t i = 0; i < prm.npost; ++i)
447 lvl->relax->apply_post(*lvl->A, rhs, x, *lvl->t);
448 ARCCORE_ALINA_TOC(
"relax");
452 for (
size_t j = 0; j < prm.ncycle; ++j) {
453 ARCCORE_ALINA_TIC(
"relax");
454 for (
size_t i = 0; i < prm.npre; ++i)
455 lvl->relax->apply_pre(*lvl->A, rhs, x, *lvl->t);
456 ARCCORE_ALINA_TOC(
"relax");
458 backend::residual(rhs, *lvl->A, x, *lvl->t);
460 backend::spmv(math::identity<scalar_type>(), *lvl->R, *lvl->t, math::zero<scalar_type>(), *nxt->f);
462 backend::clear(*nxt->u);
463 cycle(nxt, *nxt->f, *nxt->u);
465 backend::spmv(math::identity<scalar_type>(), *lvl->P, *nxt->u, math::identity<scalar_type>(), x);
467 ARCCORE_ALINA_TIC(
"relax");
468 for (
size_t i = 0; i < prm.npost; ++i)
469 lvl->relax->apply_post(*lvl->A, rhs, x, *lvl->t);
470 ARCCORE_ALINA_TOC(
"relax");
475 template <
class B,
class C,
class R,
class D,
class I>
476 friend std::ostream& operator<<(std::ostream& os,
const DistributedAMG<B, C, R, D, I>& a);