12#ifndef ARCCORE_ALINA_COARSENING_H
13#define ARCCORE_ALINA_COARSENING_H
34#include "arccore/alina/BuiltinBackend.h"
35#include "arccore/alina/AlinaUtils.h"
36#include "arccore/alina/QRFactorizationImpl.h"
37#include "arccore/alina/Adapters.h"
38#include "arccore/alina/ValueTypeInterface.h"
45namespace Arcane::Alina::detail
54template <
class Matrix>
55std::shared_ptr<Matrix> galerkin(
const Matrix& A,
const Matrix& P,
const Matrix& R)
57 return product(R, *product(A, P));
65template <
class Matrix>
66std::shared_ptr<Matrix> scaled_galerkin(
const Matrix& A,
const Matrix& P,
const Matrix& R,
float s)
68 auto a = galerkin(A, P, R);
81namespace Arcane::Alina
87struct nullspace_params
111 rows = p.get(
"rows", rows);
113 precondition(
cols > 0,
"Error in nullspace parameters: "
114 "B is set, but cols is not");
116 precondition(rows > 0,
"Error in nullspace parameters: "
117 "B is set, but rows is not");
119 B.assign(b, b + rows *
cols);
122 precondition(
cols == 0,
"Error in nullspace parameters: "
123 "cols > 0, but B is empty");
126 p.check_params( {
"cols",
"rows",
"B" });
129 void get(PropertyTree&,
const std::string&)
const {}
166 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
eps_strong)
168 p.check_params( {
"eps_strong",
"block_size" });
171 void get(PropertyTree& p,
const std::string& path)
const
173 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path,
eps_strong);
177 static const ptrdiff_t undefined = -1;
178 static const ptrdiff_t removed = -2;
205 template <
class Matrix>
209 ,
id(backend::nbRow(A))
211 typedef typename backend::value_type<Matrix>::type value_type;
212 typedef typename math::scalar_of<value_type>::type scalar_type;
216 const size_t n = backend::nbRow(A);
219 auto dia = diagonal(A);
221 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
222 value_type eps_dia_i = eps_squared * (*dia)[i];
224 for (ptrdiff_t j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j) {
225 ptrdiff_t c = A.col[j];
226 value_type v = A.val[j];
237 for (
size_t i = 0; i < n; ++i) {
238 ptrdiff_t j = A.ptr[i], e = A.ptr[i + 1];
239 max_neib = std::max<size_t>(max_neib, e - j);
241 ptrdiff_t state = removed;
255 for (
size_t i = 0; i < n; ++i) {
256 if (
id[i] != undefined)
261 ptrdiff_t cur_id =
static_cast<ptrdiff_t
>(
count++);
266 for (ptrdiff_t j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j) {
267 ptrdiff_t c = A.col[j];
277 for (ptrdiff_t c : neib) {
278 for (ptrdiff_t j = A.ptr[c], e = A.ptr[c + 1]; j < e; ++j) {
279 ptrdiff_t cc = A.col[j];
292 for (ptrdiff_t i :
id)
297 if (
static_cast<ptrdiff_t
>(
count) > cnt.
back()) {
300 for (
size_t i = 0; i < n; ++i)
302 id[i] = cnt[
id[i]] - 1;
319 , block_size(block_size)
322 bool operator()(ptrdiff_t i, ptrdiff_t j)
const
325 return static_cast<size_t>(key[i]) / block_size <
326 static_cast<size_t>(key[j]) / block_size;
339template <
class Matrix>
340std::shared_ptr<Matrix>
341tentative_prolongation(
size_t n,
347 typedef typename backend::value_type<Matrix>::type value_type;
348 typedef typename backend::col_type<Matrix>::type
col_type;
350 auto P = std::make_shared<Matrix>();
352 ARCCORE_ALINA_TIC(
"tentative");
353 if (nullspace.
cols > 0) {
354 ptrdiff_t nba = naggr / block_size;
359 for (
size_t i = 0; i < n; ++i)
363 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
364 ptrdiff_t a = aggr[order[i]];
367 ++aggr_ptr[a / block_size + 1];
369 std::partial_sum(aggr_ptr.begin(), aggr_ptr.end(), aggr_ptr.begin());
374 P->set_size(n, nullspace.
cols * nba);
378 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
379 P->ptr[i + 1] = aggr[i] < 0 ? 0 : nullspace.
cols;
388 UniqueArray<double> Bnew;
389 Bnew.resize(nba * nullspace.
cols * nullspace.
cols);
392 Alina::detail::QRFactorization<double> qr;
393 UniqueArray<double> Bpart;
395 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
396 auto aggr_beg = aggr_ptr[i];
397 auto aggr_end = aggr_ptr[i + 1];
398 auto d = aggr_end - aggr_beg;
400 Bpart.resize(d * nullspace.
cols);
402 for (ptrdiff_t j = aggr_beg, jj = 0; j < aggr_end; ++j, ++jj) {
403 ptrdiff_t ib = nullspace.
cols * order[j];
404 for (
int k = 0; k < nullspace.
cols; ++k)
405 Bpart[jj + d * k] = nullspace.
B[ib + k];
408 qr.factorize(d, nullspace.
cols, &Bpart[0], Alina::detail::col_major);
410 for (
int ii = 0, kk = 0; ii < nullspace.
cols; ++ii)
411 for (
int jj = 0; jj < nullspace.
cols; ++jj, ++kk)
412 Bnew[i * nullspace.
cols * nullspace.
cols + kk] = qr.R(ii, jj);
414 for (ptrdiff_t j = aggr_beg, ii = 0; j < aggr_end; ++j, ++ii) {
415 col_type* c = &P->col[P->ptr[order[j]]];
416 value_type* v = &P->val[P->ptr[order[j]]];
418 for (
int jj = 0; jj < nullspace.
cols; ++jj) {
419 c[jj] = i * nullspace.
cols + jj;
422 v[jj] = qr.Q(ii, jj) * math::identity<value_type>();
428 std::swap(nullspace.
B, Bnew);
431 P->set_size(n, naggr);
434 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
435 P->ptr[i + 1] = (aggr[i] >= 0);
439 P->set_nonzeros(P->scan_row_sizes());
442 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
444 P->col[P->ptr[i]] = aggr[i];
445 P->val[P->ptr[i]] = math::identity<value_type>();
450 ARCCORE_ALINA_TOC(
"tentative");
483 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
block_size)
485 p.check_params( {
"eps_strong",
"block_size" });
490 plain_aggregates::params::get(p, path);
491 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, block_size);
495 static const ptrdiff_t undefined = -1;
496 static const ptrdiff_t removed = -2;
508 template <
class Matrix>
513 plain_aggregates aggr(A, prm);
515 remove_small_aggregates(A.nbRow(), 1, min_aggregate, aggr);
518 strong_connection.swap(aggr.strong_connection);
522 strong_connection.resize(backend::nonzeros(A));
523 id.resize(backend::nbRow(A));
525 auto ap = pointwise_matrix(A, prm.block_size);
528 plain_aggregates pw_aggr(Ap, prm);
530 remove_small_aggregates(Ap.nbRow(), prm.block_size, min_aggregate, pw_aggr);
532 count = pw_aggr.count * prm.block_size;
534 arccoreParallelFor(0, Ap.nbRow(), ForLoopRunInfo{}, [&](
Int32 begin,
Int32 size) {
535 UniqueArray<ptrdiff_t> j(prm.block_size);
536 UniqueArray<ptrdiff_t> e(prm.block_size);
538 for (ptrdiff_t ip = begin; ip < (begin + size); ++ip) {
539 ptrdiff_t ia = ip * prm.block_size;
541 for (unsigned k = 0; k < prm.block_size; ++k, ++ia) {
542 id[ia] = prm.block_size * pw_aggr.id[ip] + k;
545 e[k] = A.ptr[ia + 1];
548 for (ptrdiff_t jp = Ap.ptr[ip], ep = Ap.ptr[ip + 1]; jp < ep; ++jp) {
549 ptrdiff_t cp = Ap.col[jp];
550 bool sp = (cp == ip) || pw_aggr.strong_connection[jp];
552 ptrdiff_t col_end = (cp + 1) * prm.block_size;
554 for (unsigned k = 0; k < prm.block_size; ++k) {
555 ptrdiff_t beg = j[k];
556 ptrdiff_t end = e[k];
558 while (beg < end && A.col[beg] < col_end) {
559 strong_connection[beg] = sp && A.col[beg] != (ia + k);
571 static void remove_small_aggregates(
size_t n,
unsigned block_size,
unsigned min_aggregate,
572 plain_aggregates& aggr)
574 if (min_aggregate <= 1)
578 UniqueArray<ptrdiff_t> count(aggr.count, 0);
580 for (
size_t i = 0; i < n; ++i) {
581 ptrdiff_t
id = aggr.id[i];
589 for (
size_t i = 0; i < aggr.count; ++i) {
590 if (block_size * count[i] < min_aggregate) {
601 for (
size_t i = 0; i < n; ++i) {
602 ptrdiff_t
id = aggr.id[i];
604 aggr.id[i] = count[id];
629template <
class Backend>
630struct AggregationCoarsening
660 :
over_interp(math::static_rows<typename Backend::value_type>::value == 1 ? 1.5f : 2.0f)
664 : ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, aggr)
665 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, nullspace)
666 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, over_interp)
668 p.check_params( {
"aggr",
"nullspace",
"over_interp" });
671 void get(PropertyTree& p,
const std::string& path)
const
673 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, aggr);
674 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, nullspace);
675 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, over_interp);
679 explicit AggregationCoarsening(
const params& prm = params())
690 template <
class Matrix>
691 std::tuple<std::shared_ptr<Matrix>, std::shared_ptr<Matrix>>
694 const size_t n = backend::nbRow(A);
696 ARCCORE_ALINA_TIC(
"aggregates");
697 Aggregates aggr(A, prm.aggr, prm.nullspace.cols);
698 ARCCORE_ALINA_TOC(
"aggregates");
700 ARCCORE_ALINA_TIC(
"interpolation");
701 auto P = tentative_prolongation<Matrix>(
702 n, aggr.
count, aggr.
id, prm.nullspace, prm.aggr.block_size);
703 ARCCORE_ALINA_TOC(
"interpolation");
705 return std::make_tuple(P, transpose(*P));
716 template <
class Matrix>
717 std::shared_ptr<Matrix>
720 return detail::scaled_galerkin(A, P, R, 1 / prm.over_interp);
732template <
template <
class>
class Coarsening>
735 template <
class Backend>
738 typedef math::element_of<typename Backend::value_type>::type Scalar;
740 typedef Coarsening<BaseBackend> Base;
742 typedef typename Base::params params;
745 type(
const params& prm = params())
748 template <
class Matrix>
749 typename std::enable_if<backend::coarsening_is_supported<BaseBackend, Coarsening>::value &&
751 std::tuple<std::shared_ptr<Matrix>, std::shared_ptr<Matrix>>>::type
752 transfer_operators(
const Matrix& B)
754 typedef typename backend::value_type<Matrix>::type Block;
755 auto T = base.transfer_operators(*adapter::unblock_matrix(B));
757 auto& P = *std::get<0>(T);
758 auto& R = *std::get<1>(T);
763 return std::make_tuple(
764 std::make_shared<Matrix>(adapter::block_matrix<Block>(P)),
765 std::make_shared<Matrix>(adapter::block_matrix<Block>(R)));
768 template <
class Matrix>
769 typename std::enable_if<backend::coarsening_is_supported<BaseBackend, Coarsening>::value &&
771 std::tuple<std::shared_ptr<Matrix>, std::shared_ptr<Matrix>>>::type
772 transfer_operators(
const Matrix& A)
774 return base.transfer_operators(A);
777 template <
class Matrix>
778 typename std::enable_if<!backend::coarsening_is_supported<BaseBackend, Coarsening>::value,
779 std::tuple<std::shared_ptr<Matrix>, std::shared_ptr<Matrix>>>::type
780 transfer_operators(
const Matrix&)
782 throw std::logic_error(
"The coarsening is not supported by the backend");
785 template <
class Matrix>
786 std::shared_ptr<Matrix>
789 return base.coarse_operator(A, P, R);
802template <
typename Vector1,
typename Vector2>
803int rigid_body_modes(
int ndim,
const Vector1& coo,
Vector2& B,
bool transpose =
false)
805 precondition(ndim == 2 || ndim == 3,
"Only 2D or 3D problems are supported");
806 precondition(coo.size() % ndim == 0,
"Coordinate vector size should be divisible by ndim");
808 size_t n = coo.size();
809 int nmodes = (ndim == 2 ? 3 : 6);
810 B.resize(n * nmodes, 0.0);
812 const int stride1 = transpose ? 1 : nmodes;
813 const int stride2 = transpose ? n : 1;
815 double sn = 1 / sqrt(n);
818 for (
size_t i = 0; i < n; ++i) {
819 size_t nod = i / ndim;
820 size_t dim = i % ndim;
822 double x = coo[nod * 2 + 0];
823 double y = coo[nod * 2 + 1];
826 B[i * stride1 + dim * stride2] = sn;
831 B[i * stride1 + 2 * stride2] = -y;
834 B[i * stride1 + 2 * stride2] = x;
839 else if (ndim == 3) {
840 for (
size_t i = 0; i < n; ++i) {
841 size_t nod = i / ndim;
842 size_t dim = i % ndim;
844 double x = coo[nod * 3 + 0];
845 double y = coo[nod * 3 + 1];
846 double z = coo[nod * 3 + 2];
849 B[i * stride1 + dim * stride2] = sn;
854 B[i * stride1 + 3 * stride2] = y;
855 B[i * stride1 + 5 * stride2] = z;
858 B[i * stride1 + 3 * stride2] = -x;
859 B[i * stride1 + 4 * stride2] = -z;
862 B[i * stride1 + 4 * stride2] = y;
863 B[i * stride1 + 5 * stride2] = -x;
870 std::array<double, 6>
dot;
871 for (
int i = ndim; i < nmodes; ++i) {
872 std::fill(
dot.begin(),
dot.end(), 0.0);
873 for (
size_t j = 0; j < n; ++j) {
874 for (
int k = 0; k < i; ++k)
875 dot[k] += B[j * stride1 + k * stride2] * B[j * stride1 + i * stride2];
878 for (
size_t j = 0; j < n; ++j) {
879 for (
int k = 0; k < i; ++k)
880 B[j * stride1 + i * stride2] -= dot[k] * B[j * stride1 + k * stride2];
881 s += B[j * stride1 + i * stride2] * B[j * stride1 + i * stride2];
884 for (
size_t j = 0; j < n; ++j)
885 B[j * stride1 + i * stride2] /= s;
899template <
class Backend>
900struct RugeStubenCoarsening
935 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
eps_strong)
936 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
do_trunc)
937 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
eps_trunc)
939 p.check_params( {
"eps_strong",
"do_trunc",
"eps_trunc" });
942 void get(
PropertyTree& p,
const std::string& path)
const
944 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, eps_strong);
945 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, do_trunc);
946 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, eps_trunc);
950 explicit RugeStubenCoarsening(
const params& prm = params())
954 template <
class Matrix>
955 std::tuple<std::shared_ptr<Matrix>, std::shared_ptr<Matrix>>
956 transfer_operators(
const Matrix& A)
const
958 typedef typename backend::value_type<Matrix>::type Val;
959 typedef typename backend::col_type<Matrix>::type Col;
960 typedef typename backend::ptr_type<Matrix>::type Ptr;
961 typedef typename math::scalar_of<Val>::type Scalar;
963 const size_t n = backend::nbRow(A);
965 static const Scalar eps = Alina::detail::eps<Scalar>(1);
967 static const Val zero = math::zero<Val>();
969 UniqueArray<char> cf(n,
'U');
970 CSRMatrix<char, Col, Ptr> S;
972 ARCCORE_ALINA_TIC(
"C/F split");
973 connect(A, prm.eps_strong, S, cf);
975 ARCCORE_ALINA_TOC(
"C/F split");
977 ARCCORE_ALINA_TIC(
"interpolation");
979 UniqueArray<ptrdiff_t> cidx(n);
980 for (
size_t i = 0; i < n; ++i)
982 cidx[i] =
static_cast<ptrdiff_t
>(nc++);
985 throw error::empty_level();
987 auto P = std::make_shared<Matrix>();
988 P->set_size(n, nc,
true);
990 UniqueArray<Val> Amin, Amax;
997 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
998 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1005 Val amin = zero, amax = zero;
1007 for (ptrdiff_t j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j) {
1008 if (!S.val[j] || cf[A.col[j]] !=
'C')
1011 amin = std::min(amin, A.val[j]);
1012 amax = std::max(amax, A.val[j]);
1015 Amin[i] = (amin *= prm.eps_trunc);
1016 Amax[i] = (amax *= prm.eps_trunc);
1018 for (ptrdiff_t j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j) {
1019 if (!S.val[j] || cf[A.col[j]] !=
'C')
1022 if (A.val[j] < amin || amax < A.val[j])
1027 for (ptrdiff_t j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j)
1028 if (S.val[j] && cf[A.col[j]] ==
'C')
1034 P->set_nonzeros(P->scan_row_sizes());
1036 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
1037 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1038 ptrdiff_t row_head = P->ptr[i];
1041 P->col[row_head] = cidx[i];
1042 P->val[row_head] = math::identity<Val>();
1047 Val a_num = zero, a_den = zero;
1048 Val b_num = zero, b_den = zero;
1049 Val d_neg = zero, d_pos = zero;
1051 for (ptrdiff_t j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j) {
1052 ptrdiff_t c = A.col[j];
1062 if (S.val[j] && cf[c] ==
'C') {
1064 if (prm.do_trunc && Amin[i] < v)
1070 if (S.val[j] && cf[c] ==
'C') {
1072 if (prm.do_trunc && v < Amax[i])
1082 if (math::norm(
static_cast<Val
>(a_den - d_neg)) > eps)
1083 cf_neg = math::norm(a_den) / math::norm(
static_cast<Val
>(a_den - d_neg));
1085 if (math::norm(
static_cast<Val
>(b_den - d_pos)) > eps)
1086 cf_pos = math::norm(b_den) / math::norm(
static_cast<Val
>(b_den - d_pos));
1089 if (zero < b_num && math::norm(b_den) < eps)
1092 Scalar alpha = math::norm(a_den) > eps ? -cf_neg * math::norm(a_num) / (math::norm(dia) * math::norm(a_den)) : 0;
1093 Scalar beta = math::norm(b_den) > eps ? -cf_pos * math::norm(b_num) / (math::norm(dia) * math::norm(b_den)) : 0;
1095 for (ptrdiff_t j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j) {
1096 ptrdiff_t c = A.col[j];
1099 if (!S.val[j] || cf[c] !=
'C')
1101 if (prm.do_trunc && Amin[i] <= v && v <= Amax[i])
1104 P->col[row_head] = cidx[c];
1105 P->val[row_head] = (v < zero ? alpha : beta) * v;
1110 ARCCORE_ALINA_TOC(
"interpolation");
1112 return std::make_tuple(P,
transpose(*P));
1115 template <
class Matrix>
1116 std::shared_ptr<Matrix>
1117 coarse_operator(
const Matrix& A,
const Matrix& P,
const Matrix& R)
const
1119 return detail::galerkin(A, P, R);
1131 template <
typename Val,
typename Col,
typename Ptr>
1132 static void connect(CSRMatrix<Val, Col, Ptr>
const& A,
float eps_strong,
1133 CSRMatrix<char, Col, Ptr>& S,
1134 UniqueArray<char>& cf)
1136 typedef typename math::scalar_of<Val>::type Scalar;
1138 const size_t n = backend::nbRow(A);
1139 const size_t nnz = backend::nonzeros(A);
1140 const Scalar eps = Alina::detail::eps<Scalar>(1);
1144 S.ptr.resize(n + 1);
1148 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
1149 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1153 Val a_min = math::zero<Val>();
1155 for (
auto a = backend::row_begin(A, i); a; ++a)
1157 a_min = std::min(a_min, a.value());
1159 if (math::norm(a_min) < eps) {
1164 a_min *= eps_strong;
1166 for (Ptr j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j)
1167 S.val[j] = (A.col[j] != i && A.val[j] < a_min);
1172 for (
size_t i = 0; i < nnz; ++i)
1174 ++(S.ptr[A.col[i] + 1]);
1177 S.col.resize(S.ptr[n]);
1179 for (
size_t i = 0; i < n; ++i)
1180 for (Ptr j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j)
1182 S.col[S.ptr[A.col[j]]++] = i;
1184 std::rotate(S.ptr.data(), S.ptr.data() + n, S.ptr.data() + n + 1);
1189 template <
typename Val,
typename Col,
typename Ptr>
1190 static void cfsplit(CSRMatrix<Val, Col, Ptr>
const& A,
1191 CSRMatrix<char, Col, Ptr>
const& S,
1192 UniqueArray<char>& cf)
1194 const size_t n = A.nbRow();
1196 UniqueArray<Col> lambda(n);
1199 for (
size_t i = 0; i < n; ++i) {
1201 for (Ptr j = S.ptr[i], e = S.ptr[i + 1]; j < e; ++j)
1202 temp += (cf[S.col[j]] ==
'U' ? 1 : 2);
1211 UniqueArray<Ptr> ptr(n + 1, 0);
1212 UniqueArray<Ptr> cnt(n, 0);
1213 UniqueArray<Ptr> i2n(n);
1214 UniqueArray<Ptr> n2i(n);
1216 for (
size_t i = 0; i < n; ++i)
1217 ++ptr[lambda[i] + 1];
1219 std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());
1221 for (
size_t i = 0; i < n; ++i) {
1222 Col lam = lambda[i];
1223 Ptr idx = ptr[lam] + cnt[lam]++;
1232 for (
size_t top = n; top-- > 0;) {
1234 Col lam = lambda[i];
1237 std::replace(cf.begin(), cf.end(),
'U',
'C');
1251 for (Ptr j = S.ptr[i], e = S.ptr[i + 1]; j < e; ++j) {
1260 for (Ptr aj = A.ptr[c], ae = A.ptr[c + 1]; aj < ae; ++aj) {
1265 Col lam_a = lambda[ac];
1267 if (cf[ac] !=
'U' ||
static_cast<size_t>(lam_a) + 1 >= n)
1270 Ptr old_pos = n2i[ac];
1271 Ptr new_pos = ptr[lam_a] + cnt[lam_a] - 1;
1273 n2i[i2n[old_pos]] = new_pos;
1274 n2i[i2n[new_pos]] = old_pos;
1276 std::swap(i2n[old_pos], i2n[new_pos]);
1280 ptr[lam_a + 1] = ptr[lam_a] + cnt[lam_a];
1282 lambda[ac] = lam_a + 1;
1287 for (Ptr j = A.ptr[i], e = A.ptr[i + 1]; j < e; j++) {
1292 Col lam = lambda[c];
1294 if (cf[c] !=
'U' || lam == 0)
1297 Ptr old_pos = n2i[c];
1298 Ptr new_pos = ptr[lam];
1300 n2i[i2n[old_pos]] = new_pos;
1301 n2i[i2n[new_pos]] = old_pos;
1303 std::swap(i2n[old_pos], i2n[new_pos]);
1308 lambda[c] = lam - 1;
1322template <
class Backend>
1323struct SmoothedAggregationCoarserning
1366 bool estimate_spectral_radius =
false;
1369 int power_iters = 0;
1374 : ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p,
aggr)
1375 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p,
nullspace)
1376 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p,
relax)
1377 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, estimate_spectral_radius)
1378 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, power_iters)
1380 p.check_params({
"aggr",
"nullspace",
"relax",
"estimate_spectral_radius",
"power_iters" });
1383 void get(
PropertyTree& p,
const std::string& path)
const
1385 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, aggr);
1386 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, nullspace);
1387 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, relax);
1388 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, estimate_spectral_radius);
1389 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, power_iters);
1393 SmoothedAggregationCoarserning(
const params& prm = params())
1397 template <
class Matrix>
1398 std::tuple<std::shared_ptr<Matrix>, std::shared_ptr<Matrix>>
1399 transfer_operators(
const Matrix& A)
1401 typedef typename backend::value_type<Matrix>::type value_type;
1402 typedef typename math::scalar_of<value_type>::type scalar_type;
1404 const size_t n = backend::nbRow(A);
1406 ARCCORE_ALINA_TIC(
"aggregates");
1407 Aggregates aggr(A, prm.aggr, prm.nullspace.cols);
1408 prm.aggr.eps_strong *= 0.5;
1409 ARCCORE_ALINA_TOC(
"aggregates");
1411 auto P_tent = tentative_prolongation<Matrix>(n, aggr.count, aggr.id, prm.nullspace, prm.aggr.
block_size);
1413 auto P = std::make_shared<Matrix>();
1414 P->set_size(backend::nbRow(*P_tent), backend::nbColumn(*P_tent),
true);
1416 scalar_type omega = prm.relax;
1417 if (prm.estimate_spectral_radius) {
1418 omega *=
static_cast<scalar_type
>(4.0 / 3) / spectral_radius<true>(A, prm.power_iters);
1421 omega *=
static_cast<scalar_type
>(2.0 / 3);
1424 ARCCORE_ALINA_TIC(
"smoothing");
1425 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
1426 UniqueArray<ptrdiff_t> marker(P->ncols, -1);
1429 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1430 for (ptrdiff_t ja = A.ptr[i], ea = A.ptr[i + 1]; ja < ea; ++ja) {
1431 ptrdiff_t ca = A.col[ja];
1434 if (ca != i && !aggr.strong_connection[ja])
1437 for (ptrdiff_t jp = P_tent->ptr[ca], ep = P_tent->ptr[ca + 1]; jp < ep; ++jp) {
1438 ptrdiff_t cp = P_tent->col[jp];
1440 if (marker[cp] != i) {
1449 P->scan_row_sizes();
1452 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
1453 UniqueArray<ptrdiff_t> marker(P->ncols, -1);
1456 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1460 value_type dia = math::zero<value_type>();
1461 for (ptrdiff_t j = A.ptr[i], e = A.ptr[i + 1]; j < e; ++j) {
1462 if (A.col[j] == i || !aggr.strong_connection[j])
1465 if (!math::is_zero(dia))
1466 dia = -omega * math::inverse(dia);
1468 ptrdiff_t row_beg = P->ptr[i];
1469 ptrdiff_t row_end = row_beg;
1470 for (ptrdiff_t ja = A.ptr[i], ea = A.ptr[i + 1]; ja < ea; ++ja) {
1471 ptrdiff_t ca = A.col[ja];
1474 if (ca != i && !aggr.strong_connection[ja])
1477 value_type va = (ca == i)
1478 ?
static_cast<value_type
>(
static_cast<scalar_type
>(1 - omega) * math::identity<value_type>())
1481 for (ptrdiff_t jp = P_tent->ptr[ca], ep = P_tent->ptr[ca + 1]; jp < ep; ++jp) {
1482 ptrdiff_t cp = P_tent->col[jp];
1483 value_type vp = P_tent->val[jp];
1485 if (marker[cp] < row_beg) {
1486 marker[cp] = row_end;
1487 P->col[row_end] = cp;
1488 P->val[row_end] = va * vp;
1492 P->val[marker[cp]] += va * vp;
1498 ARCCORE_ALINA_TOC(
"smoothing");
1500 return std::make_tuple(P,
transpose(*P));
1503 template <
class Matrix>
1504 std::shared_ptr<Matrix>
1505 coarse_operator(
const Matrix& A,
const Matrix& P,
const Matrix& R)
const
1507 return detail::galerkin(A, P, R);
1521template <
class Backend>
1522struct SmoothedAggregationEnergyMinCoarsening
1538 : ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, aggr)
1539 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, nullspace)
1541 p.check_params( {
"aggr",
"nullspace" });
1544 void get(PropertyTree& p,
const std::string& path)
const
1546 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, aggr);
1547 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, nullspace);
1551 SmoothedAggregationEnergyMinCoarsening(
const params& prm = params())
1555 template <
class Matrix>
1556 std::tuple<std::shared_ptr<Matrix>, std::shared_ptr<Matrix>>
1557 transfer_operators(
const Matrix& A)
1559 typedef typename backend::value_type<Matrix>::type Val;
1560 typedef typename backend::col_type<Matrix>::type Col;
1561 typedef typename backend::ptr_type<Matrix>::type Ptr;
1562 typedef ptrdiff_t Idx;
1564 ARCCORE_ALINA_TIC(
"aggregates");
1565 Aggregates aggr(A, prm.aggr, prm.nullspace.cols);
1566 prm.aggr.eps_strong *= 0.5;
1567 ARCCORE_ALINA_TOC(
"aggregates");
1569 ARCCORE_ALINA_TIC(
"interpolation");
1570 auto P_tent = tentative_prolongation<Matrix>(backend::nbRow(A), aggr.count, aggr.id, prm.nullspace, prm.aggr.
block_size);
1573 CSRMatrix<Val, Col, Ptr> Af;
1574 Af.set_size(backend::nbRow(A), backend::nbColumn(A));
1577 UniqueArray<Val> dia(Af.nbRow());
1579 arccoreParallelFor(0, Af.nbRow(), ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
1580 for (Idx i = begin; i < (begin + size); ++i) {
1581 Idx row_begin = A.ptr[i];
1582 Idx row_end = A.ptr[i + 1];
1583 Idx row_width = row_end - row_begin;
1585 Val D = math::zero<Val>();
1586 for (Idx j = row_begin; j < row_end; ++j) {
1592 else if (!aggr.strong_connection[j]) {
1599 Af.ptr[i + 1] = row_width;
1603 Af.set_nonzeros(Af.scan_row_sizes());
1605 arccoreParallelFor(0, Af.nbRow(), ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
1606 for (Idx i = begin; i < (begin + size); ++i) {
1608 Idx row_begin = A.ptr[i];
1609 Idx row_end = A.ptr[i + 1];
1610 Idx row_head = Af.ptr[i];
1612 for (Idx j = row_begin; j < row_end; ++j) {
1616 Af.col[row_head] = i;
1617 Af.val[row_head] = dia[i];
1620 else if (aggr.strong_connection[j]) {
1621 Af.col[row_head] = c;
1622 Af.val[row_head] = A.val[j];
1629 UniqueArray<Val> omega;
1631 auto P = interpolation(Af, dia, *P_tent, omega);
1632 auto R = restriction(Af, dia, *P_tent, omega);
1633 ARCCORE_ALINA_TOC(
"interpolation");
1635 return std::make_tuple(P, R);
1638 template <
class Matrix>
1639 std::shared_ptr<Matrix>
1640 coarse_operator(
const Matrix& A,
const Matrix& P,
const Matrix& R)
const
1642 return detail::galerkin(A, P, R);
1647 template <
class AMatrix,
typename Val,
typename Col,
typename Ptr>
1648 static std::shared_ptr<CSRMatrix<Val, Col, Ptr>>
1649 interpolation(
const AMatrix& A,
const UniqueArray<Val>& Adia,
1650 const CSRMatrix<Val, Col, Ptr>& P_tent,
1651 UniqueArray<Val>& omega)
1653 const size_t n = backend::nbRow(P_tent);
1654 const size_t nc = backend::nbColumn(P_tent);
1656 auto AP = product(A, P_tent,
true);
1658 omega.resize(nc, math::zero<Val>());
1659 UniqueArray<Val> denum(nc, math::zero<Val>());
1665 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
1666 UniqueArray<ptrdiff_t> marker(nc, -1);
1671 UniqueArray<Col> adap_col(128);
1672 UniqueArray<Val> adap_val(128);
1674 for (ptrdiff_t ia = begin; ia < (begin + size); ++ia) {
1679 for (
auto a = A.row_begin(ia); a; ++a) {
1681 Val va = math::inverse(Adia[ca]) * a.value();
1683 for (
auto p = AP->row_begin(ca); p; ++p) {
1685 Val v = va * p.value();
1687 if (marker[c] < 0) {
1688 marker[c] = adap_col.size();
1689 adap_col.push_back(c);
1690 adap_val.push_back(v);
1693 adap_val[marker[c]] += v;
1698 if (adap_col.size() != 0)
1699 detail::sort_row(&adap_col[0], &adap_val[0], adap_col.size());
1704 Ptr ja = AP->ptr[ia], ea = AP->ptr[ia + 1],
1705 jb = 0, eb = adap_col.size();
1706 ja < ea && jb < eb;) {
1707 Col ca = AP->col[ja];
1708 Col cb = adap_col[jb];
1715 Val v = AP->val[ja] * adap_val[jb];
1717 std::scoped_lock lock(mutex1);
1726 for (
size_t j = 0, e = adap_col.size(); j < e; ++j) {
1727 Col c = adap_col[j];
1728 Val v = adap_val[j];
1730 std::scoped_lock lock(mutex2);
1738 for (
size_t i = 0, m = omega.size(); i < m; ++i)
1739 omega[i] = math::inverse(denum[i]) * omega[i];
1748 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
1749 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1750 Val dia = math::inverse(Adia[i]);
1752 for (Ptr ja = AP->ptr[i], ea = AP->ptr[i + 1],
1753 jp = P_tent.ptr[i], ep = P_tent.ptr[i + 1];
1755 Col ca = AP->col[ja];
1756 Val va = -dia * AP->val[ja] * omega[ca];
1758 for (; jp < ep; ++jp) {
1759 Col cp = P_tent.col[jp];
1764 va += P_tent.val[jp];
1777 template <
typename AMatrix,
typename Val,
typename Col,
typename Ptr>
1778 static std::shared_ptr<CSRMatrix<Val, Col, Ptr>>
1779 restriction(
const AMatrix& A,
const UniqueArray<Val>& Adia,
1780 const CSRMatrix<Val, Col, Ptr>& P_tent,
1781 const UniqueArray<Val>& omega)
1783 const size_t nc = backend::nbColumn(P_tent);
1788 auto RA = product(*R_tent, A,
true);
1797 arccoreParallelFor(0, nc, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
1798 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1801 for (Ptr ja = RA->ptr[i], ea = RA->ptr[i + 1],
1802 jr = R_tent->ptr[i], er = R_tent->ptr[i + 1];
1804 Col ca = RA->col[ja];
1805 Val va = -w * math::inverse(Adia[ca]) * RA->val[ja];
1807 for (; jr < er; ++jr) {
1808 Col cr = R_tent->col[jr];
1813 va += R_tent->val[jr];
1835namespace Arcane::Alina::backend
1838template <
class Backend>
1840 typename std::enable_if<!std::is_arithmetic<typename backend::value_type<Backend>::type>::value>
::type> : std::false_type
Classe pour stocker les paramètres sous forme d'arbre hiérarchique clé/valeur.
UniqueArray< char > strong_connection
Matrice de connectivité forte.
size_t count
Nombre d'agrégats.
UniqueArray< ptrdiff_t > id
ID de l'agrégat auquel appartient chaque variable de niveau fin.
pointwise_aggregates(const Matrix &A, const params &prm, unsigned min_aggregate)
Construit les agrégats pour une matrice donnée.
void clear()
Supprime les éléments du tableau.
iterator end()
Itérateur sur le premier élément après la fin du tableau.
void reserve(Int64 new_capacity)
Réserve le mémoire pour new_capacity éléments.
void push_back(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
iterator begin()
Itérateur sur le premier élément du tableau.
T & back()
Dernier élément du tableau.
Informations d'exécution d'une boucle.
Matrix class, to be used by user.
Vecteur 1D de données avec sémantique par valeur (style STL).
Classe gérant un vecteur de dimension 2 de type T.
__host__ __device__ Real dot(Real2 u, Real2 v)
Produit scalaire de u par v dans .
apfloat sqrt(apfloat v)
Racine carrée de v.
__host__ __device__ Real3x3 transpose(const Real3x3 &t)
Transpose la matrice.
void arccoreParallelFor(const ComplexForLoopRanges< RankValue, IndexType_ > &loop_ranges, const ForLoopRunInfo &run_info, const LambdaType &lambda_function, const ReducerArgs &... reducer_args)
Applique en concurrence la fonction lambda lambda_function sur l'intervalle d'itération donné par loo...
std::int32_t Int32
Type entier signé sur 32 bits.
Paramètres de dé-raffinement.
float over_interp
Facteur de sur-interpolation .
nullspace_params nullspace
Paramètres de quasi-nullspace.
Aggregates::params aggr
Paramètres d'agrégation.
std::tuple< std::shared_ptr< Matrix >, std::shared_ptr< Matrix > > transfer_operators(const Matrix &A)
Crée les opérateurs de transfert pour la matrice système donnée.
std::shared_ptr< Matrix > coarse_operator(const Matrix &A, const Matrix &P, const Matrix &R) const
Crée la matrice système pour le niveau plus grossier.
Applique un dé-raffinement scalaire sur une matrice de blocs.
bool do_trunc
Tronquer l'opérateur de prolongation ?
float eps_trunc
Paramètre de troncature .
float eps_strong
Paramètre définissant les couplages forts.
Coarsening Ruge-Stuben classique avec interpolation directe.
float relax
Facteur de relaxation.
Aggregates::params aggr
Paramètres d'agrégation.
nullspace_params nullspace
Paramètres de l'espace nul proche.
Paramètres de dé-raffinement.
Aggregates::params aggr
Paramètres d'agrégation.
nullspace_params nullspace
Paramètres de l'espace nul proche.
Is the coarsening supported by the backend?
Number of rows for statically sized matrix types.
UniqueArray< double > B
Vecteurs de l'espace nul proche.
int cols
Nombre de vecteurs dans l'espace nul proche.
float eps_strong
Paramètre définissant les couplages forts.
UniqueArray< ptrdiff_t > id
ID de l'agrégat auquel appartient chaque variable de niveau fin.
plain_aggregates(const Matrix &A, const params &prm)
Construit les agrégats pour une matrice donnée.
size_t count
Nombre d'agrégats.
UniqueArray< char > strong_connection
Matrice de connectivité forte.
Int32 block_size
Taille du bloc pour la matrice système.