Alien  1.3.0
Developer documentation
Loading...
Searching...
No Matches
ILU0Preconditioner.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7
8#pragma once
9#if defined (ALIEN_USE_EIGEN3)
10#if defined(ALIEN_USE_SYCL)
11 #ifdef __ACPP__
12 //#define EIGEN3_DISABLED
13 //#warning "EIGEN USE SYCL"
14 #ifdef SYCL_DEVICE_ONLY
15 #undef SYCL_DEVICE_ONLY
16 #include <Eigen/Dense>
17 #define SYCL_DEVICE_ONLY
18 #else
19 #include <Eigen/Dense>
20 #endif
21 #else
22 #include <Eigen/Dense>
23 #endif
24#else
25 #include <Eigen/Dense>
26#endif
27#endif
28#include <alien/handlers/scalar/CSRModifierViewT.h>
29
30namespace Alien
31{
32
33 template <typename ValueT>
34 struct Block1D
35 {
36 using ValueType = ValueT ;
37
38 ValueType& operator()(std::size_t i) {
39 return m_values[i];
40 }
41
42 ValueType operator()(std::size_t i) const {
43 return m_values[i];
44 }
45 ValueType* m_values = nullptr;
46 };
47
48 template <typename ValueT>
49 struct Block2D
50 {
51 using ValueType = ValueT ;
52 Block2D(int N)
53 : m_N(N)
54 , m_buffer(N*N)
55 {
56 m_values = m_buffer.data();
57 }
58
59 Block2D(ValueType* values, int N)
60 : m_values(values)
61 , m_N(N)
62 {}
63
64 Block2D(Block2D const& rhs)
65 : m_values(rhs.m_values)
66 , m_N(rhs.m_N)
67 {}
68
69 Block2D& operator = (Block2D const& rhs) {
70 for(int i=0;i<m_N*m_N;++i)
71 m_values[i] = rhs.m_values[i] ;
72 return *this ;
73 }
74
75 Block2D& operator += (Block2D const& rhs) {
76 for(int i=0;i<m_N*m_N;++i)
77 m_values[i] += rhs.m_values[i] ;
78 return *this ;
79 }
80
81 Block2D& operator -= (Block2D const& rhs) {
82 for(int i=0;i<m_N*m_N;++i)
83 m_values[i] -= rhs.m_values[i] ;
84 return *this ;
85 }
86
87 ValueType& operator()(std::size_t i, std::size_t j) {
88 return m_values[i*m_N+j];
89 }
90
91 ValueType operator()(std::size_t i, std::size_t j) const {
92 return m_values[i*m_N+j];
93 }
94 ValueType* m_values = nullptr ;
95 int m_N = 0;
96 std::vector<ValueType> m_buffer ;
97 };
98
99 template <typename ValueT>
100 struct LU
101 {
102 public:
104 using ValueType = ValueT ;
105 using Block2DType = Block2D<ValueType> ;
106
107
108 LU(int N)
109 : A(N)
110 {
111 setZero() ;
112 }
113
114 LU inv(Block2DType const& r)
115 {
116 std::copy(r.m_values,r.m_values+r.m_N*r.m_N,A.m_values) ;
117 for (int k = 0; k < A.m_N; ++k)
118 {
119 assert(A(k,k) != 0);
120 A(k,k) = 1 / A(k,k);
121 for (int i = k + 1; i < A.m_N; ++i) {
122 A(i,k) *= A(k,k);
123 }
124 for (int i = k + 1; i < A.m_N; ++i) {
125 for (int j = k + 1; j < A.m_N; ++j) {
126 A(i,j) -= A(i,k) * A(k,j);
127 }
128 }
129 }
130 return *this ;
131 }
132
135 {
136 for (int i = 0; i < A.m_N; ++i)
137 {
138 for (int j = 0; j < i; ++j) {
139 A(i,j) = 0;
140 }
141 A(i,i) = 1;
142 for (int j = i + 1; j < A.m_N; ++j) {
143 A(i,j) = 0;
144 }
145 }
146 }
147
149 void setZero()
150 {
151 Real* ptr = A.m_values;
152 for (int i = 0; i < A.m_N * A.m_N; ++i) {
153 ptr[i] = 0;
154 }
155 }
156
157 void LSolve(Block2DType& X) const
158 {
159 for (int i = 1; i < A.m_N; ++i)
160 {
161 for (int j = 0; j < i; ++j)
162 {
163 for(int k=0;k<A.m_N;++k)
164 X(i,k) -= A(i,j) * X(j,k);
165 }
166 }
167 }
168
169 void USolve(Block2DType& X) const
170 {
171 for (int i = A.m_N - 1; i >= 0; --i) {
172 for (int j = A.m_N - 1; j > i; --j) {
173 for(int k=0;k<A.m_N;++k)
174 X(i,k) -= A(i,j) * X(j,k);
175 }
176 for(int k=0;k<A.m_N;++k)
177 X(i,k) *= A(i,i);
178 }
179 }
180
181 Block2DType solve(Block2DType const& r) const
182 {
183 Block2DType results(A.m_N) ;
184 results = r ;
185 LSolve(results);
186 USolve(results);
187 return results ;
188 }
189
190 private:
191 Block2DType A;
192 };
193
194 template<typename ValueT>
195 Block2D<ValueT> operator*(Block2D<ValueT> const& l, Block2D<ValueT> const& r)
196 {
197 auto N = l.m_N;
198 Block2D<ValueT> value{l.m_N} ;
199 for(int i=0;i<N;++i)
200 for(int j=0;j<N;++j)
201 for(int k=0;k<N;++k)
202 value(i,k) += l(i,j)*r(j,k) ;
203 return value ;
204 }
205
206
207 template<typename ValueT>
208 Block2D<ValueT> operator*(Block2D<ValueT> const& l, LU<ValueT> const& r)
209 {
210 return r.solve(l) ;
211 }
212
213template <typename MatrixT, typename VectorT>
214class LUFactorisationAlgo
215{
216 public:
217 // clang-format off
218 typedef MatrixT MatrixType;
219 typedef VectorT VectorType;
220 typedef typename MatrixType::ProfileType ProfileType ;
221 typedef typename MatrixType::ValueType ValueType;
222 typedef typename MatrixType::TagType TagType ;
223 // clang-format on
224
225 LUFactorisationAlgo()
226 {}
227
228 virtual ~LUFactorisationAlgo()
229 {}
230
231 template <typename AlgebraT>
232 void baseInit(AlgebraT& algebra, MatrixT const& matrix)
233 {
234 m_is_parallel = matrix.isParallel();
235 m_alloc_size = matrix.getAllocSize();
236 if constexpr (requires{matrix.blockSize();})
237 m_block_size = matrix.blockSize();
238 else
239 m_block_size = 1 ;
240 m_distribution = matrix.distribution();
241 m_lu_matrix.reset(matrix.cloneTo(nullptr));
242 m_profile = &m_lu_matrix->getProfile();
243 m_work.resize(m_alloc_size);
244 m_work.assign(m_work.size(), -1);
245 algebra.allocate(AlgebraT::resource(matrix), m_x);
246 }
247
248 template <typename AlgebraT>
249 void init(AlgebraT& algebra, MatrixT const& matrix)
250 {
251 baseInit(algebra, matrix);
252 if(m_block_size==1)
253 factorize(*m_lu_matrix);
254 else
255 blockFactorize(*m_lu_matrix);
256
257 m_work.clear();
258 }
259
260 void factorize(MatrixT& matrix, bool bjacobi = true)
261 {
262 /*
263 *
264 For i = 1, . . . ,N Do:
265 For k = 1, . . . , i - 1 and if (i, k) 2 NZ(A) Do:
266 Compute aik := aik/akk
267 For j = k + 1, . . . and if (i, j) 2 NZ(A), Do:
268 compute aij := aij - aik.ak,j.
269 EndFor
270 EndFor
271 EndFor
272 *
273 */
274 m_bjacobi = bjacobi;
275 CSRModifierViewT<MatrixT> modifier(matrix);
276
277 // clang-format off
278 auto nrows = modifier.nrows() ;
279 auto kcol = modifier.kcol() ;
280 auto dcol = modifier.dcol() ;
281 auto cols = modifier.cols() ;
282 auto values = modifier.data() ;
283 // clang-format on
284 if (m_is_parallel) {
285 auto& local_row_size = matrix.getDistStructInfo().m_local_row_size;
286 if (m_bjacobi) {
287 for (std::size_t irow = 1; irow < nrows; ++irow) // i=1->nrow
288 {
289 for (int k = kcol[irow]; k < dcol[irow]; ++k) // k=1 ->i-1
290 {
291 int krow = cols[k];
292 ValueType aik = values[k] / values[dcol[krow]]; // aik = aik/akk
293 values[k] = aik;
294 for (int l = kcol[krow]; l < kcol[krow] + local_row_size[krow]; ++l)
295 m_work[cols[l]] = l;
296 for (int j = k + 1; j < kcol[krow] + local_row_size[irow]; ++j) // j=k+1->n
297 {
298 int jcol = cols[j];
299 int kj = m_work[jcol];
300 if (kj != -1) {
301 values[j] -= aik * values[kj]; // aij = aij - aik*akj
302 }
303 }
304 for (int l = kcol[krow]; l < kcol[krow] + local_row_size[krow]; ++l)
305 m_work[cols[l]] = -1;
306 }
307 }
308 }
309 else {
310 typename LUSendRecvTraits<TagType>::matrix_op_type op(matrix, m_distribution, m_work);
311 op.recvLowerNeighbLUData(values);
312 int first_upper_ghost_index = matrix.getDistStructInfo().m_first_upper_ghost_index;
313 for (std::size_t irow = 1; irow < nrows; ++irow) // i=1->nrow
314 {
315 for (int k = kcol[irow]; k < dcol[irow]; ++k) // k=1 ->i-1
316 {
317 int krow = cols[k];
318 ValueType aik = values[k] / values[dcol[krow]]; // aik = aik/akk
319 values[k] = aik;
320 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
321 m_work[cols[l]] = l;
322 for (int j = k + 1; j < kcol[irow] + local_row_size[irow]; ++j) // j=k+1->n
323 {
324 int jcol = cols[j];
325 int kj = m_work[jcol];
326 if (kj != -1) {
327 values[j] -= aik * values[kj]; // aij = aij - aik*akj
328 }
329 }
330 for (int j = kcol[irow] + local_row_size[irow]; j < kcol[irow + 1]; ++j) // j=k+1->n
331 {
332 int jcol = cols[j];
333 int kj = m_work[jcol];
334 if ((kj != -1) && (jcol >= first_upper_ghost_index)) {
335 values[j] -= aik * values[kj]; // aij = aij - aik*akj
336 }
337 }
338 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
339 m_work[cols[l]] = -1;
340 }
341 }
342 op.sendUpperNeighbLUData(values);
343 }
344 }
345 else {
346 for (std::size_t irow = 1; irow < nrows; ++irow) // i=1->nrow
347 {
348 for (int k = kcol[irow]; k < dcol[irow]; ++k) // k=1 ->i-1
349 {
350 int krow = cols[k];
351 ValueType aik = values[k] / values[dcol[krow]]; // aik = aik/akk
352 values[k] = aik;
353 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
354 m_work[cols[l]] = l;
355 for (int j = k + 1; j < kcol[irow + 1]; ++j) // j=k+1->n
356 {
357 int jcol = cols[j];
358 int kj = m_work[jcol];
359 if (kj != -1) {
360 values[j] -= aik * values[kj]; // aij = aij - aik*akj
361 }
362 }
363 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
364 m_work[cols[l]] = -1;
365 }
366 }
367 }
368 }
369
370 void solveL(ValueType const* y, ValueType* x) const
371 {
372 CSRConstViewT<MatrixT> view(*m_lu_matrix);
373 // clang-format off
374 auto nrows = view.nrows() ;
375 auto kcol = view.kcol() ;
376 auto dcol = view.dcol() ;
377 auto cols = view.cols() ;
378 auto values = view.data() ;
379 // clang-format on
380
381 for (std::size_t irow = 0; irow < nrows; ++irow) {
382 ValueType val = y[irow];
383 for (int k = kcol[irow]; k < dcol[irow]; ++k)
384 val -= values[k] * x[cols[k]];
385 x[irow] = val;
386 }
387 }
388
389 void solveU(ValueType const* y, ValueType* x) const
390 {
391 CSRConstViewT<MatrixT> view(*m_lu_matrix);
392 // clang-format off
393 auto nrows = view.nrows() ;
394 auto kcol = view.kcol() ;
395 auto dcol = view.dcol() ;
396 auto cols = view.cols() ;
397 auto values = view.data() ;
398 // clang-format on
399 if (m_is_parallel) {
400 auto& local_row_size = m_lu_matrix->getDistStructInfo().m_local_row_size;
401 for (int irow = (int)nrows - 1; irow > -1; --irow) {
402 int dk = dcol[irow];
403 ValueType val = y[irow];
404 for (int k = dk + 1; k < kcol[irow] + local_row_size[irow]; ++k) {
405 val -= values[k] * x[cols[k]];
406 }
407 x[irow] = val / values[dk];
408 }
409 }
410 else {
411 for (int irow = (int)nrows - 1; irow > -1; --irow) {
412 int dk = dcol[irow];
413 ValueType val = y[irow];
414 for (int k = dk + 1; k < kcol[irow + 1]; ++k) {
415 val -= values[k] * x[cols[k]];
416 }
417 x[irow] = val / values[dk];
418 }
419 }
420 }
421
422#if defined (ALIEN_USE_EIGEN3) && !defined(EIGEN3_DISABLED)
423 inline auto inv(Eigen::Map<Eigen::Matrix<ValueType,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor>>const & block) const
424 {
425 assert(block.determinant()!=0) ;
426 return block.inverse() ;
427 }
428#endif
429
430 void blockFactorize(MatrixT& matrix, bool bjacobi = true)
431 {
432 /*
433 *
434 For i = 1, . . . ,N Do:
435 For k = 1, . . . , i - 1 and if (i, k) 2 NZ(A) Do:
436 Compute aik := aik/akk
437 For j = k + 1, . . . and if (i, j) 2 NZ(A), Do:
438 compute aij := aij - aik.ak,j.
439 EndFor
440 EndFor
441 EndFor
442 *
443 */
444 //if constexpr (MatrixType::on_host_only)
445 {
446#if defined (ALIEN_USE_EIGEN3) && !defined(EIGEN3_DISABLED)
447 using namespace Eigen;
448 using Block2D = Eigen::Matrix<ValueType,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> ;
449 using Block2DView = Eigen::Map<Block2D> ;
450
451 int N = m_block_size;
452 int N2 = N*N;
453
454 m_bjacobi = bjacobi;
455 CSRModifierViewT<MatrixT> modifier(matrix);
456
457 // clang-format off
458 auto nrows = modifier.nrows() ;
459 auto kcol = modifier.kcol() ;
460 auto dcol = modifier.dcol() ;
461 auto cols = modifier.cols() ;
462 auto values = modifier.data() ;
463
464 Block2D aik(N,N) ;
465 // clang-format on
466 /*
467 alien_info([&] {
468 cout()<<"BLOCK FACTORIZATION : "<<m_is_parallel<<" "<<m_bjacobi;
469 });*/
470 if (m_is_parallel) {
471 auto& local_row_size = matrix.getDistStructInfo().m_local_row_size;
472
473 if (m_bjacobi) {
474 for (std::size_t irow = 1; irow < nrows; ++irow) // i=1->nrow
475 {
476 /*alien_info([&] {
477 cout()<<"ROW : "<<irow<<" "<<kcol[irow]<<" "<<dcol[irow]<<" "<<kcol[irow+1]-kcol[irow]<<" "<<local_row_size[irow];
478 });*/
479 for (int k = kcol[irow]; k < dcol[irow]; ++k) // k=1 ->i-1
480 {
481 int krow = cols[k];
482 /*alien_info([&] {
483 cout()<<"\tCOL : "<<k<<" "<<cols[k]<<" "<<kcol[krow]<<" "<<local_row_size[krow];
484 });*/
485
486 //ValueType aik = values[k] / values[dcol[krow]]; // aik = aik/akk
487 //values[k] = aik;
488 aik = Block2DView(values+k*N2,N,N) * inv(Block2DView(values+dcol[krow]*N2,N,N)) ;
489 Block2DView(values+k*N2,N,N) = aik ;
490 /*alien_info([&] {
491 cout()<<"\t\tVALUES["<<k<<"]=";
492 for(int i=0;i<N;++i)
493 for(int j=0;j<N;++j)
494 cout()<<"\t\t\t MAT("<<i<<","<<j<<")="<<values[k*N2+i*N+j];
495 });*/
496 for (int l = kcol[krow]; l < kcol[krow] + local_row_size[krow]; ++l)
497 m_work[cols[l]] = l;
498 for (int j = k + 1; j < kcol[irow] + local_row_size[irow]; ++j) // j=k+1->n
499 {
500 int jcol = cols[j];
501 int kj = m_work[jcol];
502 if (kj != -1) {
503 //values[j] -= aik * values[kj]; // aij = aij - aik*akj
504 Block2DView(values+j*N2,N,N) -= aik * Block2DView(values+kj*N2,N,N) ;
505 /*alien_info([&] {
506 cout()<<"\t\tVALUES["<<j<<"]=";
507 for(int ii=0;ii<N;++ii)
508 for(int jj=0;jj<N;++jj)
509 cout()<<"\t\t\t MAT("<<ii<<","<<jj<<")="<<values[j*N2+ii*N+jj];
510 });*/
511 }
512 }
513 for (int l = kcol[krow]; l < kcol[krow] + local_row_size[krow]; ++l)
514 m_work[cols[l]] = -1;
515 }
516 }
517 }
518 else {
519 typename LUSendRecvTraits<TagType>::matrix_op_type op(matrix, m_distribution, m_work);
520 op.recvLowerNeighbLUData(values);
521 int first_upper_ghost_index = matrix.getDistStructInfo().m_first_upper_ghost_index;
522 for (std::size_t irow = 1; irow < nrows; ++irow) // i=1->nrow
523 {
524 for (int k = kcol[irow]; k < dcol[irow]; ++k) // k=1 ->i-1
525 {
526 int krow = cols[k];
527 //ValueType aik = values[k] / values[dcol[krow]]; // aik = aik/akk
528 //values[k] = aik;
529 aik = Block2DView(values+k*N2,N,N) * inv(Block2DView(values+dcol[krow]*N2,N,N)) ;
530 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
531 m_work[cols[l]] = l;
532 for (int j = k + 1; j < kcol[irow] + local_row_size[irow]; ++j) // j=k+1->n
533 {
534 int jcol = cols[j];
535 int kj = m_work[jcol];
536 if (kj != -1) {
537 //values[j] -= aik * values[kj]; // aij = aij - aik*akj
538 Block2DView(values+j*N2,N,N) -= aik * Block2DView(values+kj*N2,N,N) ;
539 }
540 }
541 for (int j = kcol[irow] + local_row_size[irow]; j < kcol[irow + 1]; ++j) // j=k+1->n
542 {
543 int jcol = cols[j];
544 int kj = m_work[jcol];
545 if ((kj != -1) && (jcol >= first_upper_ghost_index)) {
546 //values[j] -= aik * values[kj]; // aij = aij - aik*akj
547 Block2DView(values+j*N2,N,N) -= aik * Block2DView(values+kj*N2,N,N) ;
548 }
549 }
550 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
551 m_work[cols[l]] = -1;
552 }
553 }
554 op.sendUpperNeighbLUData(values);
555 }
556
557 if(m_use_inv_diag)
558 {
559 m_inv_diag_matrix.reserve(nrows);
560 for (std::size_t irow = 0; irow < nrows; ++irow)
561 {
562 m_inv_diag_matrix.emplace_back(Block2DView(values+dcol[irow]*N2,N,N)) ;
563 }
564 }
565 }
566 else {
567 for (std::size_t irow = 1; irow < nrows; ++irow) // i=1->nrow
568 {
569 /*alien_info([&] {
570 cout()<<"ROW : "<<irow<<" "<<kcol[irow]<<" "<<dcol[irow]<<" "<<kcol[irow+1]-kcol[irow];
571 });*/
572 for (int k = kcol[irow]; k < dcol[irow]; ++k) // k=1 ->i-1
573 {
574 int krow = cols[k];
575 /*alien_info([&] {
576 cout()<<"\tCOL : "<<k<<" "<<cols[k];
577 });*/
578
579 //ValueType aik = values[k] / values[dcol[krow]]; // aik = aik/akk
580 //values[k] = aik;
581 aik = Block2DView(values+k*N2,N,N) * inv(Block2DView(values+dcol[krow]*N2,N,N)) ;
582 Block2DView(values+k*N2,N,N) = aik ;
583 /*alien_info([&] {
584 cout()<<"\t\tVALUES["<<k<<"]=";
585 for(int i=0;i<N;++i)
586 for(int j=0;j<N;++j)
587 cout()<<"\t\t\t MAT("<<i<<","<<j<<")="<<values[k*N2+i*N+j];
588 });*/
589
590 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
591 m_work[cols[l]] = l;
592 for (int j = k + 1; j < kcol[irow + 1]; ++j) // j=k+1->n
593 {
594 int jcol = cols[j];
595 int kj = m_work[jcol];
596 if (kj != -1) {
597 //values[j] -= aik * values[kj]; // aij = aij - aik*akj
598 Block2DView(values+j*N2,N,N) -= aik * Block2DView(values+kj*N2,N,N) ;
599 /*alien_info([&] {
600 cout()<<"\t\tVALUES["<<j<<"]=";
601 for(int ii=0;ii<N;++ii)
602 for(int jj=0;jj<N;++jj)
603 cout()<<"\t\t\t MAT("<<ii<<","<<jj<<")="<<values[j*N2+ii*N+jj];
604 });*/
605 }
606 }
607 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
608 m_work[cols[l]] = -1;
609 }
610 }
611
612 if(m_use_inv_diag)
613 {
614 m_inv_diag_matrix.reserve(nrows);
615 for (std::size_t irow = 0; irow < nrows; ++irow)
616 {
617 m_inv_diag_matrix.emplace_back(Block2DView(values+dcol[irow]*N2,N,N)) ;
618 }
619 }
620 }
621#else
622 throw Arccore::FatalErrorException(
623 A_FUNCINFO, "Eigen is required for BlockILU factorization");
624#endif
625 }
626#if defined(EIGEN3_DISABLED)
627 else
628 {
629 using Block2DType = Block2D<ValueType> ;
630
631 int N = m_block_size;
632 int NxN = N*N;
633
634 m_bjacobi = bjacobi;
635 CSRModifierViewT<MatrixT> modifier(matrix);
636
637 // clang-format off
638 auto nrows = modifier.nrows() ;
639 auto kcol = modifier.kcol() ;
640 auto dcol = modifier.dcol() ;
641 auto cols = modifier.cols() ;
642 auto values = modifier.data() ;
643
644 Block2DType aik{N};
645 LU<ValueType> lu{N};
646 // clang-format on
647 if (m_is_parallel)
648 {
649 auto& local_row_size = matrix.getDistStructInfo().m_local_row_size;
650 if (m_bjacobi) {
651 for (std::size_t irow = 1; irow < nrows; ++irow) // i=1->nrow
652 {
653 for (int k = kcol[irow]; k < dcol[irow]; ++k) // k=1 ->i-1
654 {
655 int krow = cols[k];
656 //ValueType aik = values[k] / values[dcol[krow]]; // aik = aik/akk
657 //values[k] = aik;
658 aik = Block2DType{values+k*NxN,N} * lu.inv(Block2DType{values+dcol[krow]*NxN,N});
659 Block2DType{values+k*NxN,N} = aik ;
660 for (int l = kcol[krow]; l < kcol[krow] + local_row_size[krow]; ++l)
661 m_work[cols[l]] = l;
662 for (int j = k + 1; j < kcol[krow] + local_row_size[irow]; ++j) // j=k+1->n
663 {
664 int jcol = cols[j];
665 int kj = m_work[jcol];
666 if (kj != -1) {
667 //values[j] -= aik * values[kj]; // aij = aij - aik*akj
668 Block2DType{values+j*NxN,N} -= (aik * Block2DType{values+kj*NxN,N}) ;
669 }
670 }
671 for (int l = kcol[krow]; l < kcol[krow] + local_row_size[krow]; ++l)
672 m_work[cols[l]] = -1;
673 }
674 }
675 }
676 else {
677 typename LUSendRecvTraits<TagType>::matrix_op_type op(matrix, m_distribution, m_work);
678 op.recvLowerNeighbLUData(values);
679 int first_upper_ghost_index = matrix.getDistStructInfo().m_first_upper_ghost_index;
680 for (std::size_t irow = 1; irow < nrows; ++irow) // i=1->nrow
681 {
682 for (int k = kcol[irow]; k < dcol[irow]; ++k) // k=1 ->i-1
683 {
684 int krow = cols[k];
685 //ValueType aik = values[k] / values[dcol[krow]]; // aik = aik/akk
686 //values[k] = aik;
687 aik = Block2DType{values+k*NxN,N} * lu.inv(Block2DType{values+dcol[krow]*NxN,N}) ;
688 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
689 m_work[cols[l]] = l;
690 for (int j = k + 1; j < kcol[irow] + local_row_size[irow]; ++j) // j=k+1->n
691 {
692 int jcol = cols[j];
693 int kj = m_work[jcol];
694 if (kj != -1) {
695 //values[j] -= aik * values[kj]; // aij = aij - aik*akj
696 Block2DType{values+j*NxN,N} -= aik * Block2DType{values+kj*NxN,N} ;
697 }
698 }
699 for (int j = kcol[irow] + local_row_size[irow]; j < kcol[irow + 1]; ++j) // j=k+1->n
700 {
701 int jcol = cols[j];
702 int kj = m_work[jcol];
703 if ((kj != -1) && (jcol >= first_upper_ghost_index)) {
704 //values[j] -= aik * values[kj]; // aij = aij - aik*akj
705 Block2DType{values+j*NxN,N} -= aik * Block2DType{values+kj*NxN,N} ;
706 }
707 }
708 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
709 m_work[cols[l]] = -1;
710 }
711 }
712 op.sendUpperNeighbLUData(values);
713 }
714 }
715 else
716 {
717 for (std::size_t irow = 1; irow < nrows; ++irow) // i=1->nrow
718 {
719 for (int k = kcol[irow]; k < dcol[irow]; ++k) // k=1 ->i-1
720 {
721 int krow = cols[k];
722 //ValueType aik = values[k] / values[dcol[krow]]; // aik = aik/akk
723 //values[k] = aik;
724 aik = Block2DType{values+k*NxN,N} * lu.inv(Block2DType{values+dcol[krow]*NxN,N}) ;
725 Block2DType{values+k*NxN,N} = aik ;
726 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
727 m_work[cols[l]] = l;
728 for (int j = k + 1; j < kcol[irow + 1]; ++j) // j=k+1->n
729 {
730 int jcol = cols[j];
731 int kj = m_work[jcol];
732 if (kj != -1) {
733 //values[j] -= aik * values[kj]; // aij = aij - aik*akj
734 Block2DType{values+j*NxN,N} -= aik * Block2DType{values+kj*NxN,N} ;
735 }
736 }
737 for (int l = kcol[krow]; l < kcol[krow + 1]; ++l)
738 m_work[cols[l]] = -1;
739 }
740 }
741 }
742 }
743#endif
744 }
745
746 void blockSolveL(ValueType const* y, ValueType* x) const
747 {
748 if constexpr (MatrixType::on_host_only)
749 {
750#if defined (ALIEN_USE_EIGEN3) && !defined(EIGEN3_DISABLED)
751 using namespace Eigen;
752 using Block2D = Eigen::Matrix<ValueType,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> ;
753 using Block2DView = Eigen::Map<Block2D> ;
754 using Block1D = Eigen::Matrix<ValueType,Dynamic,1> ;
755 using Block1DView = Eigen::Map<Block1D> ;
756
757 int N = m_block_size ;
758 int N2 = N*N;
759
760
761 Block1D val(N);
762
763 CSRConstViewT<MatrixT> view(*m_lu_matrix);
764 // clang-format off
765 auto nrows = view.nrows() ;
766 auto kcol = view.kcol() ;
767 auto dcol = view.dcol() ;
768 auto cols = view.cols() ;
769 auto values = view.data() ;
770 // clang-format on
771
772 for (std::size_t irow = 0; irow < nrows; ++irow) {
773 //ValueType val = y[irow];
774 val = Block1DView(const_cast<ValueType*>(y+irow*N),N) ;
775 for (int k = kcol[irow]; k < dcol[irow]; ++k)
776 {
777 //val -= values[k] * x[cols[k]];
778 val -= Block2DView(const_cast<ValueType*>(values+k*N2),N,N) * Block1DView(x+cols[k]*N,N) ;
779 }
780 //x[irow] = val;
781 Block1DView(x+irow*N,N) = val ;
782 }
783#endif
784 }
785 }
786
787 void blockSolveU(ValueType const* y, ValueType* x) const
788 {
789 if constexpr (MatrixType::on_host_only)
790 {
791#if defined (ALIEN_USE_EIGEN3) && !defined(EIGEN3_DISABLED)
792 using namespace Eigen;
793 using Block2D = Eigen::Matrix<ValueType,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> ;
794 using Block2DView = Eigen::Map<Block2D> ;
795 using Block1D = Eigen::Matrix<ValueType,Dynamic,1> ;
796 using Block1DView = Eigen::Map<Block1D> ;
797
798 int N = m_block_size;
799 int N2 = N*N;
800
801 Block1D val(N);
802
803 CSRConstViewT<MatrixT> view(*m_lu_matrix);
804 // clang-format off
805 auto nrows = view.nrows() ;
806 auto kcol = view.kcol() ;
807 auto dcol = view.dcol() ;
808 auto cols = view.cols() ;
809 auto values = view.data() ;
810 // clang-format on
811 if (m_is_parallel) {
812 auto& local_row_size = m_lu_matrix->getDistStructInfo().m_local_row_size;
813 for (int irow = (int)nrows - 1; irow > -1; --irow) {
814 int dk = dcol[irow];
815 //ValueType val = y[irow];
816 val = Block1DView(const_cast<ValueType*>(y+irow*N),N) ;
817 for (int k = dk + 1; k < kcol[irow] + local_row_size[irow]; ++k) {
818 //val -= values[k] * x[cols[k]];
819 val -= Block2DView(const_cast<ValueType*>(values+k*N2),N,N) * Block1DView(x+cols[k]*N,N) ;
820 }
821 //x[irow] = val / values[dk];
822 if(m_use_inv_diag)
823 Block1DView(x+irow*N,N) = m_inv_diag_matrix[irow].solve(val);
824 else
825 Block1DView(x+irow*N,N) = inv(Block2DView(const_cast<ValueType*>(values+dk*N2),N,N)) * val;
826 }
827 }
828 else {
829 for (int irow = (int)nrows - 1; irow > -1; --irow) {
830 int dk = dcol[irow];
831 //ValueType val = y[irow];
832 val = Block1DView(const_cast<ValueType*>(y+irow*N),N) ;
833 for (int k = dk + 1; k < kcol[irow + 1]; ++k) {
834 //val -= values[k] * x[cols[k]];
835 val -= Block2DView(const_cast<ValueType*>(values+k*N2),N,N) * Block1DView(x+cols[k]*N,N) ;
836 }
837 //x[irow] = val / values[dk];
838 if(m_use_inv_diag)
839 Block1DView(x+irow*N,N) = m_inv_diag_matrix[irow].solve(val);
840 else
841 Block1DView(x+irow*N,N) = inv(Block2DView(const_cast<ValueType*>(values+dk*N2),N,N)) * val;
842 }
843 }
844#endif
845 }
846 }
847
848
849 template <typename AlgebraT>
850 void solve([[maybe_unused]] AlgebraT& algebra, VectorType const& y, VectorType& x) const
851 {
852 if(m_block_size==1)
853 {
855 //
856 // L.X1 = Y
857 //
858 solveL(y.data(), m_x.data());
859
861 //
862 // U.X = X1
863 //
864 solveU(m_x.data(), x.data());
865 }
866 else
867 {
869 //
870 // L.X1 = Y
871 //
872 blockSolveL(y.data(), m_x.data());
873
875 //
876 // U.X = X1
877 //
878 blockSolveU(m_x.data(), x.data());
879 }
880 }
881
882 const MatrixType& getLUMatrix() const
883 {
884 return *m_lu_matrix;
885 }
886
887 protected:
888 // clang-format off
889 std::unique_ptr<MatrixType> m_lu_matrix ;
890 int m_block_size = 1;
891 ProfileType const* m_profile = nullptr;
892 mutable VectorType m_x ;
893
894 MatrixDistribution m_distribution ;
895 std::vector<int> m_work ;
896 std::size_t m_alloc_size = 0 ;
897 bool m_is_parallel = false ;
898 bool m_bjacobi = false ;
899
900 std::vector<int> m_send_lu_ibuffer ;
901 std::vector<std::vector<ValueType>> m_send_lu_buffer ;
902
903 bool m_use_inv_diag = true ;
904#if defined (ALIEN_USE_EIGEN3) && !defined(EIGEN3_DISABLED)
905 using EigenMatrix = Eigen::Matrix<ValueType,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> ;
906 std::vector<Eigen::PartialPivLU<EigenMatrix>> m_inv_diag_matrix;
907#endif
908 // clang-format on
909};
910
911template <typename AlgebraT>
912class ILU0Preconditioner
913{
914 public:
915 // clang-format off
916 typedef AlgebraT AlgebraType ;
917 typedef typename AlgebraType::Matrix MatrixType;
918 typedef typename AlgebraType::Vector VectorType;
919 typedef typename MatrixType::ProfileType ProfileType ;
920 typedef typename MatrixType::ValueType ValueType;
921 // clang-format on
922
924
925 ILU0Preconditioner(AlgebraType& algebra, MatrixType const& matrix, ITraceMng* trace_mng = nullptr)
926 : m_algebra(algebra)
927 , m_matrix(matrix)
928 , m_trace_mng(trace_mng)
929 {
930 }
931
932 virtual ~ILU0Preconditioner(){};
933
934 void init()
935 {
936 m_algo.init(m_algebra, m_matrix);
937 }
938
939 void solve(VectorType const& y, VectorType& x) const
940 {
941 m_algo.solve(m_algebra, y, x);
942 }
943
944 void solve(AlgebraType& algebra, VectorType const& y, VectorType& x) const
945 {
946 m_algo.solve(algebra, y, x);
947 }
948
949 void update()
950 {
951 // update value from m_matrix
952 }
953
954 private:
955 // clang-format off
956 AlgebraType& m_algebra ;
957 MatrixType const& m_matrix;
958 AlgoType m_algo ;
959
960 ITraceMng* m_trace_mng = nullptr ;
961 // clang-format on
962};
963
964} // namespace Alien
Computes a matrix distribution.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Definition BackEnd.h:17
ValueT ValueType
Type of the blocks.
void setZero()
Set zero.
void setIdentity()
Set identity.