Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
AMG.cc
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/* AMG.cc (C) 2000-2026 */
9/* */
10/* Algebraic multigrid. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/Array.h"
15#include "arcane/utils/ArgumentException.h"
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/TraceAccessor.h"
18#include "arcane/utils/OStringStream.h"
19#include "arcane/utils/StringBuilder.h"
20
21#include "arcane/core/matvec/Matrix.h"
22
23#include <set>
24#include <fstream>
25
26/*---------------------------------------------------------------------------*/
27/*---------------------------------------------------------------------------*/
28
29namespace Arcane::math
30{
31Real divide(Real a, Real b)
32{
33 if (b == 0.0)
34 ARCANE_FATAL("Division by zero");
35 return a / b;
36}
37} // namespace Arcane::math
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
42namespace Arcane::MatVec
43{
44
45/*---------------------------------------------------------------------------*/
46/*---------------------------------------------------------------------------*/
47
48void DirectSolver::
49solve(const Matrix& matrix, const Vector& vector_b, Vector& vector_x)
50{
51 IntegerConstArrayView rows = matrix.rowsIndex();
52 IntegerConstArrayView columns = matrix.columns();
53 RealConstArrayView mat_values = matrix.values();
54
55 Integer nb_row = matrix.nbRow();
56 RealUniqueArray solution_values(nb_row);
57 RealUniqueArray full_matrix_values(nb_row * nb_row);
58 full_matrix_values.fill(0.0);
59 solution_values.copy(vector_b.values());
60 for (Integer row = 0; row < nb_row; ++row) {
61 for (Integer j = rows[row]; j < rows[row + 1]; ++j) {
62 full_matrix_values[row * nb_row + columns[j]] = mat_values[j];
63 }
64 }
65 _solve(full_matrix_values, solution_values, nb_row);
66 vector_x.values().copy(solution_values);
67}
68
69/*---------------------------------------------------------------------------*/
70/*---------------------------------------------------------------------------*/
71
72void DirectSolver::
73_solve(RealArrayView mat_values, RealArrayView vec_values, Integer size)
74{
75 if (size == 1) {
76 if (math::isZero(mat_values[0]))
77 throw FatalErrorException("DirectSolver", "Null matrix");
78 vec_values[0] /= mat_values[0];
79 return;
80 }
81
82 for (Integer k = 0; k < size - 1; ++k) {
83 if (!math::isZero(mat_values[k * size + k])) {
84 for (Integer j = k + 1; j < size; ++j) {
85 if (!math::isZero(mat_values[j * size + k])) {
86 Real factor = mat_values[j * size + k] / mat_values[k * size + k];
87 for (Integer m = k + 1; m < size; ++m)
88 mat_values[j * size + m] -= factor * mat_values[k * size + m];
89 vec_values[j] -= factor * vec_values[k];
90 }
91 }
92 }
93 }
94
95 for (Integer k = (size - 1); k > 0; --k) {
96 vec_values[k] /= mat_values[k * size + k];
97 for (Integer j = 0; j < k; ++j) {
98 if (!math::isZero(mat_values[j * size + k]))
99 vec_values[j] -= vec_values[k] * mat_values[j * size + k];
100 }
101 }
102
103 vec_values[0] /= mat_values[0];
104}
105
106/*---------------------------------------------------------------------------*/
107/*---------------------------------------------------------------------------*/
108
109Matrix MatrixOperation2::
110matrixMatrixProduct(const Matrix& left_matrix, const Matrix& right_matrix)
111{
112 Integer nb_left_col = left_matrix.nbColumn();
113 Integer nb_right_col = right_matrix.nbColumn();
114 Integer nb_right_row = right_matrix.nbRow();
115 Integer nb_left_row = left_matrix.nbRow();
116 if (nb_left_col != nb_right_row)
117 ARCANE_THROW(ArgumentException, "Bad size nb_left_column={0} nb_right_row={1}",
118 nb_left_col, nb_right_row);
119 Integer nb_row_col = nb_left_col;
120
121 Matrix new_matrix(nb_left_row, nb_right_col);
122 IntegerUniqueArray new_matrix_rows_size(nb_left_row);
123 RealUniqueArray new_matrix_values;
124 IntegerUniqueArray new_matrix_columns;
125
126 for (Integer i = 0; i < nb_left_row; ++i) {
127 Integer local_nb_col = 0;
128 for (Integer j = 0; j < nb_right_col; ++j) {
129 Real v = 0.0;
130 for (Integer k = 0; k < nb_row_col; ++k) {
131 //if (i==1 && j==0){
132 // Real v0 = left_matrix.value(i,k) * right_matrix.value(k,j);
133 // cout << "** CHECK CONTRIBUTION k=" << k
134 // << " l=" << left_matrix.value(i,k) << " r=" << right_matrix.value(k,j) << '\n';
135 // if (!math::isZero(v0))
136 // cout << "** ADD CONTRIBUTION k=" << k << " v0=" << v0
137 // << " l=" << left_matrix.value(i,k) << " r=" << right_matrix.value(k,j) << '\n';
138 // }
139 v += left_matrix.value(i, k) * right_matrix.value(k, j);
140 }
141 if (!math::isZero(v)) {
142 ++local_nb_col;
143 new_matrix_columns.add(j);
144 new_matrix_values.add(v);
145 }
146 }
147 new_matrix_rows_size[i] = local_nb_col;
148 }
149 new_matrix.setRowsSize(new_matrix_rows_size);
150 new_matrix.setValues(new_matrix_columns, new_matrix_values);
151 return new_matrix;
152}
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
156
157Matrix MatrixOperation2::
158matrixMatrixProductFast(const Matrix& left_matrix, const Matrix& right_matrix)
159{
160 Integer nb_left_col = left_matrix.nbColumn();
161 Integer nb_right_col = right_matrix.nbColumn();
162 Integer nb_right_row = right_matrix.nbRow();
163 Integer nb_left_row = left_matrix.nbRow();
164 if (nb_left_col != nb_right_row)
165 ARCANE_THROW(ArgumentException, "Bad size nb_left_column={0} nb_right_row={1}",
166 nb_left_col, nb_right_row);
167 //Integer nb_row_col = nb_left_col;
168
169 IntegerConstArrayView left_rows_index = left_matrix.rowsIndex();
170 IntegerConstArrayView left_columns = left_matrix.columns();
171 RealConstArrayView left_values = left_matrix.values();
172
173 IntegerConstArrayView right_rows_index = right_matrix.rowsIndex();
174 IntegerConstArrayView right_columns = right_matrix.columns();
175 RealConstArrayView right_values = right_matrix.values();
176
177 Matrix new_matrix(nb_left_row, nb_right_col);
178 IntegerUniqueArray new_matrix_rows_size(nb_left_row);
179 RealUniqueArray new_matrix_values;
180 IntegerUniqueArray new_matrix_columns;
181
182 IntegerUniqueArray col_right_columns_index(nb_right_col + 1);
183 IntegerUniqueArray col_right_rows;
184 RealUniqueArray col_right_values;
185 IntegerUniqueArray col_right_columns_size(nb_right_col);
186 {
187 // Calculates the number of elements in each column
188 col_right_columns_size.fill(0);
189 for (Integer i = 0; i < nb_right_row; ++i) {
190 for (Integer j = right_rows_index[i]; j < right_rows_index[i + 1]; ++j) {
191 ++col_right_columns_size[right_columns[j]];
192 }
193 }
194 // Calculates the index of the first element of each column.
195 Integer index = 0;
196 for (Integer j = 0; j < nb_right_col; ++j) {
197 col_right_columns_index[j] = index;
198 index += col_right_columns_size[j];
199 }
200 col_right_columns_index[nb_right_col] = index;
201
202 col_right_rows.resize(index);
203 col_right_values.resize(index);
204 index = 0;
205 // Fills the values by column
206 col_right_columns_size.fill(0);
207 for (Integer i = 0; i < nb_right_row; ++i) {
208 for (Integer j = right_rows_index[i]; j < right_rows_index[i + 1]; ++j) {
209 Integer col = right_columns[j];
210 Real value = right_values[j];
211 Integer col_index = col_right_columns_size[col] + col_right_columns_index[col];
212 ++col_right_columns_size[col];
213 col_right_rows[col_index] = i;
214 col_right_values[col_index] = value;
215 }
216 }
217 }
218 //_dumpColumnMatrix(cout,col_right_columns_index,col_right_rows,col_right_values);
219 //cout << '\n';
220 RealUniqueArray current_row_values(nb_left_col);
221 current_row_values.fill(0.0);
222 for (Integer i = 0; i < nb_left_row; ++i) {
223 Integer local_nb_col = 0;
224 // Fills the row with the current values
225 for (Integer z = left_rows_index[i], zs = left_rows_index[i + 1]; z < zs; ++z) {
226 current_row_values[left_columns[z]] = left_values[z];
227 //if (i==1)
228 //cout << " ** FILL VALUE col=" << left_columns[z] << " v=" << left_values[z] << '\n';
229 }
230 //if (i==1){
231 //for( Integer z=0; z<nb_left_col; ++z ){
232 //current_row_values[ left_columns[z] ] = left_values[z];
233 // cout << " ** VALUE col=" << z << " v=" << current_row_values[z] << '\n';
234 //}
235 //}
236
237 for (Integer j = 0; j < nb_right_col; ++j) {
238 Real v = 0.0;
239 for (Integer zj = col_right_columns_index[j]; zj < col_right_columns_index[j + 1]; ++zj) {
240 //if (i==1 && j==0){
241 // Real v0 = col_right_values[zj] * current_row_values[ col_right_rows[zj] ];
242 // cout << "** CHECK CONTRIBUTION2 k=" << col_right_rows[zj]
243 // << " l=" << current_row_values[ col_right_rows[zj] ] << " r=" << col_right_values[zj] << '\n';
244 // if (!math::isZero(v0))
245 // cout << "** ADD CONTRIBUTION2 k=" << col_right_rows[zj] << " v0=" << v0
246 // << " l=" << current_row_values[ col_right_rows[zj] ] << " r=" << col_right_values[zj] << '\n';
247 // }
248 v += col_right_values[zj] * current_row_values[col_right_rows[zj]];
249 }
250 if (!math::isZero(v)) {
251 ++local_nb_col;
252 new_matrix_columns.add(j);
253 new_matrix_values.add(v);
254 }
255 }
256
257 new_matrix_rows_size[i] = local_nb_col;
258
259 // Resets zeros in the current row.
260 for (Integer z = left_rows_index[i], zs = left_rows_index[i + 1]; z < zs; ++z)
261 current_row_values[left_columns[z]] = 0.0;
262 }
263 new_matrix.setRowsSize(new_matrix_rows_size);
264 new_matrix.setValues(new_matrix_columns, new_matrix_values);
265 return new_matrix;
266}
267
268/*---------------------------------------------------------------------------*/
269/*---------------------------------------------------------------------------*/
270
271void MatrixOperation2::
272_dumpColumnMatrix(std::ostream& o, IntegerConstArrayView columns_index, IntegerConstArrayView rows,
273 RealConstArrayView values)
274{
275 Integer nb_col = columns_index.size() - 1;
276 o << "(ColumnMatrix nb_col=" << nb_col;
277 for (Integer j = 0; j < nb_col; ++j) {
278 for (Integer z = columns_index[j], zs = columns_index[j + 1]; z < zs; ++z) {
279 Integer i = rows[z];
280 Real v = values[z];
281 o << " [" << i << "," << j << "]=" << v;
282 }
283 }
284 o << ")";
285}
286
287/*---------------------------------------------------------------------------*/
288/*---------------------------------------------------------------------------*/
289
290Matrix MatrixOperation2::
291transpose(const Matrix& matrix)
292{
293 Integer nb_column = matrix.nbColumn();
294 Integer nb_row = matrix.nbRow();
295
296 Integer new_matrix_nb_row = nb_column;
297 Integer new_matrix_nb_column = nb_row;
298 Matrix new_matrix(new_matrix_nb_row, new_matrix_nb_column);
299 IntegerUniqueArray new_matrix_rows_size(new_matrix_nb_row);
300 RealUniqueArray new_matrix_values;
301 IntegerUniqueArray new_matrix_columns;
302
303 for (Integer i = 0; i < new_matrix_nb_row; ++i) {
304 Integer local_nb_col = 0;
305 for (Integer j = 0; j < new_matrix_nb_column; ++j) {
306 Real v = matrix.value(j, i);
307 if (!math::isZero(v)) {
308 ++local_nb_col;
309 new_matrix_columns.add(j);
310 new_matrix_values.add(v);
311 }
312 }
313 new_matrix_rows_size[i] = local_nb_col;
314 }
315 new_matrix.setRowsSize(new_matrix_rows_size);
316 new_matrix.setValues(new_matrix_columns, new_matrix_values);
317 return new_matrix;
318}
319
320/*---------------------------------------------------------------------------*/
321/*---------------------------------------------------------------------------*/
322
323Matrix MatrixOperation2::
324transposeFast(const Matrix& matrix)
325{
326 Integer nb_column = matrix.nbColumn();
327 Integer nb_row = matrix.nbRow();
328
329 IntegerConstArrayView rows_index = matrix.rowsIndex();
330 IntegerConstArrayView columns = matrix.columns();
331 RealConstArrayView values = matrix.values();
332
333 Integer new_matrix_nb_row = nb_column;
334 Integer new_matrix_nb_column = nb_row;
335 Matrix new_matrix(new_matrix_nb_row, new_matrix_nb_column);
336
337 IntegerUniqueArray new_matrix_rows_size(new_matrix_nb_row);
338
339 // Calculates the number of columns of each row of the transpose.
340 new_matrix_rows_size.fill(0);
341 Integer nb_element = values.size();
342 for (Integer i = 0, is = columns.size(); i < is; ++i) {
343 ++new_matrix_rows_size[columns[i]];
344 }
345 new_matrix.setRowsSize(new_matrix_rows_size);
346
347 IntegerConstArrayView new_matrix_rows_index = new_matrix.rowsIndex();
348 new_matrix_rows_size.fill(0);
349
350 RealUniqueArray new_matrix_values(nb_element);
351 IntegerUniqueArray new_matrix_columns(nb_element);
352
353 for (Integer row = 0, is = nb_row; row < is; ++row) {
354 for (Integer j = rows_index[row]; j < rows_index[row + 1]; ++j) {
355 Integer col_index = columns[j];
356 Integer pos = new_matrix_rows_index[col_index] + new_matrix_rows_size[col_index];
357 //cout << "** CURRENT row=" << row << " col=" << col_index << " v=" << values[col_index]
358 new_matrix_columns[pos] = row;
359 new_matrix_values[pos] = values[j];
360 ++new_matrix_rows_size[col_index];
361 }
362 }
363
364 new_matrix.setValues(new_matrix_columns, new_matrix_values);
365 return new_matrix;
366}
367
368/*---------------------------------------------------------------------------*/
369/*---------------------------------------------------------------------------*/
370
371Matrix MatrixOperation2::
372applyGalerkinOperator(const Matrix& left_matrix, const Matrix& matrix,
373 const Matrix& right_matrix)
374{
375 Integer nb_original_row = matrix.nbRow();
376 Integer nb_final_row = left_matrix.nbRow();
377 IntegerUniqueArray p_marker(nb_final_row);
378 IntegerUniqueArray a_marker(nb_original_row);
379 p_marker.fill(-1);
380 a_marker.fill(-1);
381
382 IntegerConstArrayView left_matrix_rows = left_matrix.rowsIndex();
383 IntegerConstArrayView left_matrix_columns = left_matrix.columns();
384 RealConstArrayView left_matrix_values = left_matrix.values();
385
386 IntegerConstArrayView right_matrix_rows = right_matrix.rowsIndex();
387 IntegerConstArrayView right_matrix_columns = right_matrix.columns();
388 RealConstArrayView right_matrix_values = right_matrix.values();
389
390 IntegerConstArrayView matrix_rows = matrix.rowsIndex();
391 IntegerConstArrayView matrix_columns = matrix.columns();
392 RealConstArrayView matrix_values = matrix.values();
393
394 Integer jj_counter = 0;
395 Integer jj_row_begining = 0;
396
397 IntegerUniqueArray new_matrix_rows_size(nb_final_row);
398
399 // First, determines the number of columns of each row of the
400 // final matrix
401 for (Integer ic = 0; ic < nb_final_row; ++ic) {
402 // Adds the diagonal
403 p_marker[ic] = jj_counter;
404 jj_row_begining = jj_counter;
405 ++jj_counter;
406
407 // Loop over the columns of row ic of matrix
408 for (Integer jj1 = left_matrix_rows[ic]; jj1 < left_matrix_rows[ic + 1]; ++jj1) {
409 Integer i1 = left_matrix_columns[jj1];
410
411 // Loop over the columns of row i1 of matrix
412 for (Integer jj2 = matrix_rows[i1]; jj2 < matrix_rows[i1 + 1]; ++jj2) {
413 Integer i2 = matrix_columns[jj2];
414 /*--------------------------------------------------------------
415 * Check A_marker to see if point i2 has been previously
416 * visited. New entries in RAP only occur from unmarked points.
417 *--------------------------------------------------------------*/
418 if (a_marker[i2] != ic) {
419 a_marker[i2] = ic;
420 /*-----------------------------------------------------------
421 * Loop over entries in row i2 of P.
422 *-----------------------------------------------------------*/
423 for (Integer jj3 = right_matrix_rows[i2]; jj3 < right_matrix_rows[i2 + 1]; ++jj3) {
424 Integer i3 = right_matrix_columns[jj3];
425 /*--------------------------------------------------------
426 * Check P_marker to see that RAP_{ic,i3} has not already
427 * been accounted for. If it has not, mark it and increment
428 * counter.
429 *--------------------------------------------------------*/
430 if (p_marker[i3] < jj_row_begining) {
431 p_marker[i3] = jj_counter;
432 ++jj_counter;
433 }
434 }
435 }
436 }
437 }
438 new_matrix_rows_size[ic] = jj_counter - jj_row_begining;
439 }
440 static Integer total_rap_size = 0;
441 total_rap_size += jj_counter;
442
443 std::cout << "** RAP_SIZE=" << jj_counter << " TOTAL=" << total_rap_size << '\n';
444 Matrix new_matrix(nb_final_row, nb_final_row);
445 new_matrix.setRowsSize(new_matrix_rows_size);
446
447 //IntegerConstArrayView new_matrix_rows = new_matrix.rowsIndex();
448 IntegerArrayView new_matrix_columns = new_matrix.columns();
449 RealArrayView new_matrix_values = new_matrix.values();
450
451 // Now, fill the matrix coefficients
452 p_marker.fill(-1);
453 a_marker.fill(-1);
454 jj_counter = 0;
455 for (Integer ic = 0; ic < nb_final_row; ++ic) {
456 // Add the diagonal
457 p_marker[ic] = jj_counter;
458 jj_row_begining = jj_counter;
459 new_matrix_columns[jj_counter] = ic;
460 new_matrix_values[jj_counter] = 0.0;
461 ++jj_counter;
462 // Loop over the columns of row ic of matrix
463 for (Integer jj1 = left_matrix_rows[ic]; jj1 < left_matrix_rows[ic + 1]; ++jj1) {
464 Integer i1 = left_matrix_columns[jj1];
465 Real r_entry = left_matrix_values[jj1];
466
467 // Loop over the columns of row i1 of matrix
468 for (Integer jj2 = matrix_rows[i1]; jj2 < matrix_rows[i1 + 1]; ++jj2) {
469 Integer i2 = matrix_columns[jj2];
470 Real r_a_product = r_entry * matrix_values[jj2];
471 /*--------------------------------------------------------------
472 * Check A_marker to see if point i2 has been previously
473 * visited. New entries in RAP only occur from unmarked points.
474 *--------------------------------------------------------------*/
475 if (a_marker[i2] != ic) {
476 a_marker[i2] = ic;
477 /*-----------------------------------------------------------
478 * Loop over entries in row i2 of P.
479 *-----------------------------------------------------------*/
480 for (Integer jj3 = right_matrix_rows[i2]; jj3 < right_matrix_rows[i2 + 1]; ++jj3) {
481 Integer i3 = right_matrix_columns[jj3];
482 Real r_a_p_product = r_a_product * right_matrix_values[jj3];
483 /*--------------------------------------------------------
484 * Check P_marker to see that RAP_{ic,i3} has not already
485 * been accounted for. If it has not, create a new entry.
486 * If it has, add new contribution.
487 *--------------------------------------------------------*/
488 if (p_marker[i3] < jj_row_begining) {
489 p_marker[i3] = jj_counter;
490 new_matrix_values[jj_counter] = r_a_p_product;
491 new_matrix_columns[jj_counter] = i3;
492 ++jj_counter;
493 }
494 else {
495 new_matrix_values[p_marker[i3]] += r_a_p_product;
496 }
497 }
498 }
499 else {
500 /*--------------------------------------------------------------
501 * If i2 is previously visited ( A_marker[12]=ic ) it yields
502 * no new entries in RAP and can just add new contributions.
503 *--------------------------------------------------------------*/
504 for (Integer jj3 = right_matrix_rows[i2]; jj3 < right_matrix_rows[i2 + 1]; ++jj3) {
505 Integer i3 = right_matrix_columns[jj3];
506 Real r_a_p_product = r_a_product * right_matrix_values[jj3];
507 new_matrix_values[p_marker[i3]] += r_a_p_product;
508 }
509 }
510 }
511 }
512 }
513 return new_matrix;
514}
515
516/*---------------------------------------------------------------------------*/
517/*---------------------------------------------------------------------------*/
518
519Matrix MatrixOperation2::
520applyGalerkinOperator2(const Matrix& left_matrix, const Matrix& matrix,
521 const Matrix& right_matrix)
522{
523 Integer nb_original_row = matrix.nbRow();
524 Integer nb_final_row = left_matrix.nbRow();
525 IntegerUniqueArray p_marker(nb_final_row);
526 IntegerUniqueArray a_marker(nb_original_row);
527 p_marker.fill(-1);
528 a_marker.fill(-1);
529
530 const Integer* left_matrix_rows = left_matrix.rowsIndex().data();
531 const Integer* left_matrix_columns = left_matrix.columns().data();
532 const Real* left_matrix_values = left_matrix.values().data();
533
534 const Integer* right_matrix_rows = right_matrix.rowsIndex().data();
535 const Integer* right_matrix_columns = right_matrix.columns().data();
536 const Real* right_matrix_values = right_matrix.values().data();
537
538 const Integer* matrix_rows = matrix.rowsIndex().data();
539 const Integer* matrix_columns = matrix.columns().data();
540 const Real* matrix_values = matrix.values().data();
541
542 Integer jj_counter = 0;
543 Integer jj_row_begining = 0;
544
545 IntegerUniqueArray new_matrix_rows_size(nb_final_row);
546
547 // First, determine the number of columns for each row of the
548 // final matrix
549 for (Integer ic = 0; ic < nb_final_row; ++ic) {
550 // Add the diagonal
551 p_marker[ic] = jj_counter;
552 jj_row_begining = jj_counter;
553 ++jj_counter;
554
555 // Loop over the columns of row ic of matrix
556 for (Integer jj1 = left_matrix_rows[ic]; jj1 < left_matrix_rows[ic + 1]; ++jj1) {
557 Integer i1 = left_matrix_columns[jj1];
558
559 // Loop over the columns of row i1 of matrix
560 for (Integer jj2 = matrix_rows[i1]; jj2 < matrix_rows[i1 + 1]; ++jj2) {
561 Integer i2 = matrix_columns[jj2];
562 /*--------------------------------------------------------------
563 * Check A_marker to see if point i2 has been previously
564 * visited. New entries in RAP only occur from unmarked points.
565 *--------------------------------------------------------------*/
566 if (a_marker[i2] != ic) {
567 a_marker[i2] = ic;
568 /*-----------------------------------------------------------
569 * Loop over entries in row i2 of P.
570 *-----------------------------------------------------------*/
571 for (Integer jj3 = right_matrix_rows[i2]; jj3 < right_matrix_rows[i2 + 1]; ++jj3) {
572 Integer i3 = right_matrix_columns[jj3];
573 /*--------------------------------------------------------
574 * Check P_marker to see that RAP_{ic,i3} has not already
575 * been accounted for. If it has not, mark it and increment
576 * counter.
577 *--------------------------------------------------------*/
578 if (p_marker[i3] < jj_row_begining) {
579 p_marker[i3] = jj_counter;
580 ++jj_counter;
581 }
582 }
583 }
584 }
585 }
586 new_matrix_rows_size[ic] = jj_counter - jj_row_begining;
587 }
588
589 Matrix new_matrix(nb_final_row, nb_final_row);
590 new_matrix.setRowsSize(new_matrix_rows_size);
591
592 //Integer* new_matrix_rows = new_matrix.rowsIndex();
593 Integer* ARCANE_RESTRICT new_matrix_columns = new_matrix.columns().data();
594 Real* ARCANE_RESTRICT new_matrix_values = new_matrix.values().data();
595
596 // Now, fill the matrix coefficients
597 p_marker.fill(-1);
598 a_marker.fill(-1);
599 jj_counter = 0;
600 for (Integer ic = 0; ic < nb_final_row; ++ic) {
601 // Add the diagonal
602 p_marker[ic] = jj_counter;
603 jj_row_begining = jj_counter;
604 new_matrix_columns[jj_counter] = ic;
605 new_matrix_values[jj_counter] = 0.0;
606 ++jj_counter;
607 // Loop over the columns of row ic of matrix
608 for (Integer jj1 = left_matrix_rows[ic]; jj1 < left_matrix_rows[ic + 1]; ++jj1) {
609 Integer i1 = left_matrix_columns[jj1];
610 Real r_entry = left_matrix_values[jj1];
611
612 // Loop over the columns of row i1 of matrix
613 for (Integer jj2 = matrix_rows[i1]; jj2 < matrix_rows[i1 + 1]; ++jj2) {
614 Integer i2 = matrix_columns[jj2];
615 Real r_a_product = r_entry * matrix_values[jj2];
616 /*--------------------------------------------------------------
617 * Check A_marker to see if point i2 has been previously
618 * visited. New entries in RAP only occur from unmarked points.
619 *--------------------------------------------------------------*/
620 if (a_marker[i2] != ic) {
621 a_marker[i2] = ic;
622 /*-----------------------------------------------------------
623 * Loop over entries in row i2 of P.
624 *-----------------------------------------------------------*/
625 for (Integer jj3 = right_matrix_rows[i2]; jj3 < right_matrix_rows[i2 + 1]; ++jj3) {
626 Integer i3 = right_matrix_columns[jj3];
627 Real r_a_p_product = r_a_product * right_matrix_values[jj3];
628 /*--------------------------------------------------------
629 * Check P_marker to see that RAP_{ic,i3} has not already
630 * been accounted for. If it has not, create a new entry.
631 * If it has, add new contribution.
632 *--------------------------------------------------------*/
633 if (p_marker[i3] < jj_row_begining) {
634 p_marker[i3] = jj_counter;
635 new_matrix_values[jj_counter] = r_a_p_product;
636 new_matrix_columns[jj_counter] = i3;
637 ++jj_counter;
638 }
639 else {
640 new_matrix_values[p_marker[i3]] += r_a_p_product;
641 }
642 }
643 }
644 else {
645 /*--------------------------------------------------------------
646 * If i2 is previously visited ( A_marker[12]=ic ) it yields
647 * no new entries in RAP and can just add new contributions.
648 *--------------------------------------------------------------*/
649 for (Integer jj3 = right_matrix_rows[i2]; jj3 < right_matrix_rows[i2 + 1]; ++jj3) {
650 Integer i3 = right_matrix_columns[jj3];
651 Real r_a_p_product = r_a_product * right_matrix_values[jj3];
652 new_matrix_values[p_marker[i3]] += r_a_p_product;
653 }
654 }
655 }
656 }
657 }
658 return new_matrix;
659}
660
661/*---------------------------------------------------------------------------*/
662/*---------------------------------------------------------------------------*/
663
664enum
665{
666 TYPE_UNDEFINED = 0,
667 TYPE_COARSE = 1,
668 TYPE_FINE = 2,
669 TYPE_SPECIAL_FINE = 3
670};
671
672/*---------------------------------------------------------------------------*/
673/*---------------------------------------------------------------------------*/
674
675class AMGLevel
676: public TraceAccessor
677{
678 public:
679
680 AMGLevel(ITraceMng* tm, Integer level)
681 : TraceAccessor(tm)
682 , m_level(level)
683 , m_is_verbose(false)
684 {}
685 virtual ~AMGLevel() {}
686
687 public:
688
689 virtual void buildLevel(Matrix matrix, Real alpha);
690
691 public:
692
693 Matrix fineMatrix()
694 {
695 return m_fine_matrix;
696 }
697 Matrix coarseMatrix()
698 {
699 return m_coarse_matrix;
700 }
701 Matrix prolongationMatrix()
702 {
703 return m_prolongation_matrix;
704 }
705 Matrix restrictionMatrix()
706 {
707 return m_restriction_matrix;
708 }
709 Integer nbCoarsePoint() const
710 {
711 return m_coarse_matrix.nbRow();
712 }
713 Int32ConstArrayView pointsType() const
714 {
715 return m_points_type;
716 }
717 void printLevelInfo();
718
719 private:
720
721 Integer m_level;
722 Matrix m_fine_matrix;
723 Matrix m_coarse_matrix;
724 Matrix m_prolongation_matrix;
725 Matrix m_restriction_matrix;
726 Int32UniqueArray m_points_type;
727
728 bool m_is_verbose;
729
730 private:
731
732 void _buildCoarsePoints(Real alpha,
733 RealArray& rows_max_val,
735 IntegerArray& weak_depends);
736 void _buildInterpolationMatrix(RealConstArrayView rows_max_val,
738 IntegerArray& weak_depends);
739 void _printLevelInfo(Matrix matrix);
740};
741
742/*---------------------------------------------------------------------------*/
743/*---------------------------------------------------------------------------*/
744
745class AMG
746: public TraceAccessor
747{
748 public:
749
750 AMG(ITraceMng* tm)
751 : TraceAccessor(tm)
752 {}
753 ~AMG();
754
755 public:
756
757 void build(Matrix matrix);
758 void solve(const Vector& vector_b, Vector& vector_x);
759
760 private:
761
762 UniqueArray<AMGLevel*> m_levels;
763 Matrix m_matrix;
764
765 private:
766
767 void _solve(const Vector& vector_b, Vector& vector_x, Integer level);
768 void _relax(const Matrix& matrix, const Vector& vector_b, Vector& vector_x,
769 Integer nb_relax);
770 void _relax1(const Matrix& matrix, const Vector& vector_b, Vector& vector_x,
771 Integer nb_relax);
772 void _relaxJacobi(const Matrix& matrix, const Vector& vector_b, Vector& vector_x,
773 Real weight);
774 void _relaxGaussSeidel(const Matrix& matrix, const Vector& vector_b, Vector& vector_x,
775 Integer point_type, Int32ConstArrayView points_type);
776 void _relaxSymmetricGaussSeidel(const Matrix& matrix, const Vector& vector_b, Vector& vector_x);
777 void _printResidualInfo(const Matrix& matrix, const Vector& vector_b,
778 const Vector& vector_x);
779};
780
781/*---------------------------------------------------------------------------*/
782/*---------------------------------------------------------------------------*/
783
784AMG::
785~AMG()
786{
787 for (Integer i = 0; i < m_levels.size(); ++i)
788 delete m_levels[i];
789}
790
791/*---------------------------------------------------------------------------*/
792/*---------------------------------------------------------------------------*/
793
794void AMG::
795build(Matrix matrix)
796{
797 Matrix current_matrix = matrix;
798 m_matrix = matrix;
799 for (Integer i = 1; i < 100; ++i) {
800 AMGLevel* level = new AMGLevel(traceMng(), i);
801 level->buildLevel(current_matrix, 0.25);
802 m_levels.add(level);
803 Integer nb_coarse_point = level->nbCoarsePoint();
804 if (nb_coarse_point < 20)
805 break;
806 current_matrix = level->coarseMatrix();
807 }
808 //for( Integer i=0; i<m_levels.size(); ++i )
809 //m_levels[i]->printLevelInfo();
810}
811
812/*---------------------------------------------------------------------------*/
813/*---------------------------------------------------------------------------*/
814
815void AMG::
816solve(const Vector& vector_b, Vector& vector_x)
817{
818 //info() << "AMG::solve";
819 if (0) {
820 OStringStream ostr;
821 RealConstArrayView v_values(vector_b.values());
822 for (Integer i = 0; i < 20; ++i)
823 ostr() << "VECTOR_F_" << i << " = " << v_values[i] << " X=" << vector_x.values()[i] << '\n';
824 for (Integer i = 0; i < v_values.size(); ++i)
825 if (math::abs(v_values[i]) > 1e-5)
826 ostr() << "VECTOR_F_" << i << " = " << v_values[i] << '\n';
827 info() << "VECTOR_F\n"
828 << ostr.str();
829 }
830 //_printResidualInfo(m_matrix,vector_b,vector_x);
831 _solve(vector_b, vector_x, 0);
832 //info() << "END SOLVE";
833 //_printResidualInfo(m_matrix,vector_b,vector_x);
834 //info() << "END AMG::solve";
835 /*{
836 OStringStream ostr;
837 ostr() << "\nVECTOR_X ";
838 vector_x.dump(ostr());
839 info() << ostr.str();
840 }*/
841}
842
843/*---------------------------------------------------------------------------*/
844/*---------------------------------------------------------------------------*/
845
846void AMG::
847_relax1(const Matrix& matrix, const Vector& vector_b, Vector& vector_x,
848 Integer nb_relax)
849{
850 Vector r(vector_x.size());
851 MatrixOperation mat_op;
852 for (Integer i = 0; i < nb_relax; ++i) {
853 // r = b - A * x
854 mat_op.matrixVectorProduct(matrix, vector_x, r);
855 mat_op.negateVector(r);
856 mat_op.addVector(r, vector_b);
857
858 // x = x + r
859 mat_op.addVector(vector_x, r);
860 }
861}
862
863/*---------------------------------------------------------------------------*/
864/*---------------------------------------------------------------------------*/
865
866void AMG::
867_relax(const Matrix& matrix, const Vector& vector_b, Vector& vector_x,
868 Integer nb_relax)
869{
870 Real epsilon = 1.0e-10;
871 DiagonalPreconditioner p(matrix);
872 ConjugateGradientSolver solver;
873 solver.setMaxIteration(nb_relax);
874 //mat_op.matrixVectorProduct(restriction_matrix,vector_x,new_x);
875 //new_x.values().fill(0.0);
876
877 //OStringStream ostr;
878 //vector_x.dump(ostr());
879 //info() << " RELAX BEFORE VECTOR_X=" << ostr.str();
880
881 solver.solve(matrix, vector_b, vector_x, epsilon, &p);
882 //OStringStream ostr;
883 //ostr() << " COARSE_B=";
884 //new_b.dump(ostr());
885 //ostr() << "\nCOARSE_X=";
886 //new_x.dump(ostr());
887 //info() << "SOLVE COARSE MATRIX nb_iter=" << solver.nbIteration()
888 // << ostr.str();
889}
890
891/*---------------------------------------------------------------------------*/
892/*---------------------------------------------------------------------------*/
893
894void AMG::
895_relaxJacobi(const Matrix& matrix, const Vector& vector_b, Vector& vector_x,
896 Real weight)
897{
898 IntegerConstArrayView rows = matrix.rowsIndex();
899 IntegerConstArrayView columns = matrix.columns();
900 RealConstArrayView mat_values = matrix.values();
901
902 RealArrayView x_values = vector_x.values();
903 RealConstArrayView b_values = vector_b.values();
904
905 Integer nb_row = matrix.nbRow();
906 RealConstArrayView cx_values(vector_x.values());
907 RealUniqueArray tmp_values(cx_values);
908 if (0) {
909 Integer v = math::min(40, nb_row);
910 OStringStream ostr;
911 for (Integer i = (nb_row - 1); i > (nb_row - v); --i)
912 ostr() << "BEFORE_B=" << i << "=" << b_values[i] << " U=" << x_values[i] << " T=" << tmp_values[i] << '\n';
913 info() << "B = X=" << x_values.data() << " T=" << tmp_values.data() << "\n"
914 << ostr.str();
915 }
916 Real one_minus_weight = 1.0 - weight;
917 for (Integer row = 0; row < nb_row; ++row) {
918 Real diag = mat_values[rows[row]];
919 if (math::isZero(diag))
920 continue;
921 Real res = b_values[row];
922 for (Integer j = rows[row] + 1; j < rows[row + 1]; ++j) {
923 Integer col = columns[j];
924 res -= mat_values[j] * tmp_values[col];
925 }
926 x_values[row] *= one_minus_weight;
927 x_values[row] += (weight * res) / diag;
928 }
929 if (0) {
930 Integer v = math::min(40, nb_row);
931 OStringStream ostr;
932 for (Integer i = (nb_row - 1); i > (nb_row - v); --i)
933 ostr() << "AFTER_B=" << i << "=" << b_values[i] << " U=" << x_values[i] << '\n';
934 info() << "B\n"
935 << ostr.str();
936 }
937}
938
939/*---------------------------------------------------------------------------*/
940/*---------------------------------------------------------------------------*/
941
942void AMG::
943_relaxGaussSeidel(const Matrix& matrix, const Vector& vector_b, Vector& vector_x,
944 Integer point_type, Int32ConstArrayView points_type2)
945{
946#if 1
947 IntegerConstArrayView rows = matrix.rowsIndex();
948 IntegerConstArrayView columns = matrix.columns();
949 RealConstArrayView mat_values = matrix.values();
950
951 RealArrayView x_values = vector_x.values();
952 RealConstArrayView b_values = vector_b.values();
953 Int32ConstArrayView points_type = points_type2;
954#else
955 const Integer* rows = matrix.rowsIndex().data();
956 const Integer* columns = matrix.columns().data();
957 const Real* mat_values = matrix.values().data();
958
959 Real* ARCANE_RESTRICT x_values = vector_x.values().data();
960 const Real* b_values = vector_b.values().data();
961 const Integer* points_type = points_type2.data();
962#endif
963
964 Integer nb_row = matrix.nbRow();
965 if (0) {
966 info() << " RELAX nb_relax=" << " nb_row=" << nb_row
967 << " point_type=" << point_type;
968 Integer v = math::min(40, nb_row);
969 OStringStream ostr;
970 for (Integer i = (nb_row - 1); i > (nb_row - v); --i)
971 ostr() << "BEFORE_B=" << i << "=" << b_values[i] << " U=" << x_values[i] << '\n';
972 info() << "B\n"
973 << ostr.str();
974 }
975 for (Integer row = 0; row < nb_row; ++row) {
976 Real diag = mat_values[rows[row]];
977 if (points_type[row] != point_type || math::isZero(diag))
978 continue;
979 Real res = b_values[row];
980 for (Integer j = rows[row] + 1; j < rows[row + 1]; ++j) {
981 Integer col = columns[j];
982 res -= mat_values[j] * x_values[col];
983 }
984 x_values[row] = res / diag;
985 }
986 if (0) {
987 Integer v = math::min(40, nb_row);
988 OStringStream ostr;
989 for (Integer i = (nb_row - 1); i > (nb_row - v); --i)
990 ostr() << "AFTER_B=" << i << "=" << b_values[i] << " U=" << x_values[i] << '\n';
991 info() << "B\n"
992 << ostr.str();
993 }
994}
995
996/*---------------------------------------------------------------------------*/
997/*---------------------------------------------------------------------------*/
998
999void AMG::
1000_relaxSymmetricGaussSeidel(const Matrix& matrix, const Vector& vector_b, Vector& vector_x)
1001{
1002 IntegerConstArrayView rows = matrix.rowsIndex();
1003 IntegerConstArrayView columns = matrix.columns();
1004 RealConstArrayView mat_values = matrix.values();
1005
1006 RealArrayView x_values = vector_x.values();
1007 RealConstArrayView b_values = vector_b.values();
1008
1009 Integer nb_row = matrix.nbRow();
1010 //info() << " RELAX nb_relax=" << nb_relax << " nb_row=" << nb_row
1011 // << " point_type=" << point_type;
1012 for (Integer row = 0; row < nb_row; ++row) {
1013 Real diag = mat_values[rows[row]];
1014 if (math::isZero(diag))
1015 continue;
1016 Real res = b_values[row];
1017 for (Integer j = rows[row] + 1; j < rows[row + 1]; ++j) {
1018 Integer col = columns[j];
1019 res -= mat_values[j] * x_values[col];
1020 }
1021 x_values[row] = res / diag;
1022 }
1023
1024 for (Integer row = nb_row - 1; row > -1; --row) {
1025 Real diag = mat_values[rows[row]];
1026 if (math::isZero(diag))
1027 continue;
1028 Real res = b_values[row];
1029 for (Integer j = rows[row] + 1; j < rows[row + 1]; ++j) {
1030 Integer col = columns[j];
1031 res -= mat_values[j] * x_values[col];
1032 }
1033 x_values[row] = res / diag;
1034 }
1035}
1036
1037/*---------------------------------------------------------------------------*/
1038/*---------------------------------------------------------------------------*/
1039
1040void AMG::
1041_solve(const Vector& vector_b, Vector& vector_x, Integer level)
1042{
1043 AMGLevel* current_level = m_levels[level];
1044 Integer vector_size = vector_b.size();
1045 Integer nb_coarse = current_level->nbCoarsePoint();
1046 Matrix fine_matrix = current_level->fineMatrix();
1047 Matrix restriction_matrix = current_level->restrictionMatrix();
1048 Matrix coarse_matrix = current_level->coarseMatrix();
1049 Matrix prolongation_matrix = current_level->prolongationMatrix();
1050
1051 Integer new_nb_row = nb_coarse;
1052 Vector new_b(new_nb_row);
1053 Vector new_x(new_nb_row);
1054 Vector tmp(vector_size);
1055
1056 MatrixOperation mat_op;
1057
1058 bool is_final_level = (level + 1) == m_levels.size();
1059
1060 const bool use_gauss_seidel = false;
1061 Integer nb_relax1 = 2;
1062 Real jacobi_weight = 2.0 / 3.0;
1063 if (use_gauss_seidel) {
1064 for (Integer i = 0; i < nb_relax1; ++i)
1065 _relaxGaussSeidel(fine_matrix, vector_b, vector_x, TYPE_FINE, current_level->pointsType());
1066 for (Integer i = 0; i < nb_relax1; ++i)
1067 _relaxGaussSeidel(fine_matrix, vector_b, vector_x, TYPE_COARSE, current_level->pointsType());
1068 }
1069 else {
1070 //info() << "BEFORE SMOOTH";
1071 //_printResidualInfo(fine_matrix,vector_b,vector_x);
1072 for (Integer i = 0; i < nb_relax1; ++i) {
1073 //_relaxSymmetricGaussSeidel(fine_matrix,vector_b,vector_x);
1074 _relaxJacobi(fine_matrix, vector_b, vector_x, jacobi_weight);
1075 }
1076 //info() << "AFTER SMOOTH";
1077 //_printResidualInfo(fine_matrix,vector_b,vector_x);
1078 //_relax(fine_matrix,vector_b,vector_x,nb_relax1);
1079 }
1080
1081 // Restrict the new b from the current b
1082 // b(k+1) = I * (b(k) - A * x)
1083 {
1084 OStringStream ostr;
1085 mat_op.matrixVectorProduct(fine_matrix, vector_x, tmp);
1086 //ostr() << "\nCOARSE_B TMP(A*x) level=" << level << " ";
1087 //tmp.dump(ostr());
1088 mat_op.negateVector(tmp);
1089 mat_op.addVector(tmp, vector_b);
1090 //ostr() << "\nCOARSE_B TMP(b-A*x) level=" << level << " ";
1091 //tmp.dump(ostr());
1092 mat_op.matrixVectorProduct(restriction_matrix, tmp, new_b);
1093 //ostr() << "\nCOARSE_B level=" << level << " ";
1094 //new_b.dump(ostr());
1095 info() << ostr.str();
1096 }
1097
1098 //mat_op.matrixVectorProduct(transpose_prolongation_matrix,vector_x,tmp);
1099
1100 // If final level reached, solve the matrix.
1101 // Otherwise, continue by restricting the matrix anew
1102 if (is_final_level) {
1103
1104 //info() << " SOLVE FINAL LEVEL";
1105
1106 if (1) {
1107 DirectSolver ds;
1108 ds.solve(coarse_matrix, new_b, new_x);
1109 //_printResidualInfo(coarse_matrix,new_b,new_x);
1110 }
1111 else {
1112 Real epsilon = 1.0e-14;
1113 DiagonalPreconditioner p(coarse_matrix);
1114 ConjugateGradientSolver solver;
1115 //mat_op.matrixVectorProduct(restriction_matrix,vector_x,new_x);
1116 new_x.values().fill(0.0);
1117 solver.solve(coarse_matrix, new_b, new_x, epsilon, &p);
1118 OStringStream ostr;
1119 //ostr() << " COARSE_B=";
1120 //new_b.dump(ostr());
1121 //ostr() << "\nCOARSE_X=";
1122 //new_x.dump(ostr());
1123 //if (m_is_verbose)
1124 info() << "SOLVE COARSE MATRIX nb_iter=" << solver.nbIteration();
1125 // << ostr.str();
1126 //_printResidualInfo(coarse_matrix,new_b,new_x);
1127 }
1128 }
1129 else {
1130 new_x.values().fill(0.0);
1131 _solve(new_b, new_x, level + 1);
1132 }
1133
1134 // Interpolate the new x from the solution found
1135 // x(k) = x(k) + tI * x(k+1)
1136 mat_op.matrixVectorProduct(prolongation_matrix, new_x, tmp);
1137 mat_op.addVector(vector_x, tmp);
1138 /*{
1139 OStringStream ostr;
1140 vector_x.dump(ostr());
1141 info() << "NEW_X level=" << level << " X=" << ostr.str();
1142 _printResidualInfo(fine_matrix,vector_b,vector_x);
1143 }*/
1144
1145 // Richardson relaxation
1146 if (use_gauss_seidel) {
1147 for (Integer i = 0; i < nb_relax1; ++i)
1148 _relaxGaussSeidel(fine_matrix, vector_b, vector_x, TYPE_FINE, current_level->pointsType());
1149 for (Integer i = 0; i < nb_relax1; ++i)
1150 _relaxGaussSeidel(fine_matrix, vector_b, vector_x, TYPE_COARSE, current_level->pointsType());
1151 }
1152 else {
1153 //info() << "BEFORE SMOOTH 2";
1154 //_printResidualInfo(fine_matrix,vector_b,vector_x);
1155 for (Integer i = 0; i < nb_relax1; ++i) {
1156 //_relaxSymmetricGaussSeidel(fine_matrix,vector_b,vector_x);
1157 _relaxJacobi(fine_matrix, vector_b, vector_x, jacobi_weight);
1158 }
1159 //info() << "AFTER SMOOTH 2";
1160 //_printResidualInfo(fine_matrix,vector_b,vector_x);
1161 //_relax(fine_matrix,vector_b,vector_x,nb_relax2);
1162 }
1163}
1164
1165/*---------------------------------------------------------------------------*/
1166/*---------------------------------------------------------------------------*/
1167
1168void AMG::
1169_printResidualInfo(const Matrix& a, const Vector& b, const Vector& x)
1170{
1171 OStringStream ostr;
1172 Vector tmp(b.size());
1173 // tmp = b - Ax
1174 MatrixOperation mat_op;
1175 mat_op.matrixVectorProduct(a, x, tmp);
1176 //ostr() << "\nAX=";
1177 //tmp.dump(ostr());
1178 mat_op.negateVector(tmp);
1179 mat_op.addVector(tmp, b);
1180 Real r = mat_op.dot(tmp);
1181 if (0) {
1182 Integer v = math::min(10, tmp.size());
1183 for (Integer i = 0; i < v; ++i)
1184 info() << "R_" << i << " = " << tmp.values()[i];
1185 }
1186 info() << " AMG_RESIDUAL_NORM=" << r << " sqrt=" << math::sqrt(r);
1187
1188 //ostr() << "\nR=";
1189 //tmp.dump(ostr());
1190 //info() << " AMG_RESIDUAL_NORM=" << r << " AMG_RESIDUAL=" << ostr.str();
1191}
1192
1193/*---------------------------------------------------------------------------*/
1194/*---------------------------------------------------------------------------*/
1195
1196/*---------------------------------------------------------------------------*/
1197/*---------------------------------------------------------------------------*/
1198
1199class PointInfo
1200{
1201 public:
1202
1203 PointInfo()
1204 : m_lambda(0)
1205 , m_index(0)
1206 {}
1207 PointInfo(Integer lambda, Integer index)
1208 : m_lambda(lambda)
1209 , m_index(index)
1210 {}
1211 Integer m_lambda;
1212 Integer m_index;
1217 bool operator<(const PointInfo& rhs) const
1218 {
1219 if (m_lambda == rhs.m_lambda)
1220 return m_index < rhs.m_index;
1221 return (m_lambda > rhs.m_lambda);
1222 }
1223};
1224
1225/*---------------------------------------------------------------------------*/
1226/*---------------------------------------------------------------------------*/
1227
1228void AMGLevel::
1229printLevelInfo()
1230{
1231 _printLevelInfo(m_prolongation_matrix);
1232 _printLevelInfo(m_coarse_matrix);
1233}
1234
1235void AMGLevel::
1236_printLevelInfo(Matrix matrix)
1237{
1238 OStringStream ostr;
1239 Integer nb_row = matrix.nbRow();
1240 Integer nb_column = matrix.nbColumn();
1241
1242 IntegerConstArrayView rows = matrix.rowsIndex();
1243 //IntegerConstArrayView columns = matrix.columns();
1244 RealConstArrayView values = matrix.values();
1245 Integer nb_value = values.size();
1246
1247 Real max_val = 0.0;
1248 Real min_val = 0.0;
1249 if (nb_value > 0) {
1250 max_val = values[0];
1251 min_val = values[0];
1252 }
1253
1254 Real max_row_sum = 0.0;
1255 Real min_row_sum = 0.0;
1256 for (Integer row = 0; row < nb_row; ++row) {
1257 Real row_sum = 0.0;
1258 for (Integer z = rows[row], zs = rows[row + 1]; z < zs; ++z) {
1259 //Integer col = columns[z];
1260 Real v = values[z];
1261 if (v > max_val)
1262 max_val = v;
1263 if (v < min_val)
1264 min_val = v;
1265 row_sum += v;
1266 }
1267 if (row == 0) {
1268 max_row_sum = row_sum;
1269 min_row_sum = row_sum;
1270 }
1271 if (row_sum > max_row_sum)
1272 max_row_sum = row_sum;
1273 if (row_sum < max_row_sum)
1274 min_row_sum = row_sum;
1275 }
1276
1277 Real sparsity = ((Real)nb_value) / ((Real)nb_row * (Real)nb_column);
1278
1279 ostr() << "level=" << m_level
1280 << " nb_row=" << nb_row
1281 << " nb_col=" << nb_column
1282 << " nb_nonzero=" << nb_value
1283 << " sparsity=" << sparsity
1284 << " min=" << min_val
1285 << " max=" << max_val
1286 << " min_row=" << min_row_sum
1287 << " max_row=" << max_row_sum;
1288
1289 info() << "INFO: " << ostr.str();
1290}
1291
1292/*---------------------------------------------------------------------------*/
1293/*---------------------------------------------------------------------------*/
1294
1295void AMGLevel::
1296_buildCoarsePoints(Real alpha,
1297 RealArray& rows_max_val,
1298 UniqueArray<SharedArray<Integer>>& depends,
1299 IntegerArray& weak_depends)
1300{
1301 IntegerConstArrayView rows_index = m_fine_matrix.rowsIndex();
1302 IntegerConstArrayView columns = m_fine_matrix.columns();
1303 RealConstArrayView mat_values = m_fine_matrix.values();
1304 Integer nb_row = m_fine_matrix.nbRow();
1305
1306 Int32UniqueArray lambdas(nb_row);
1307 lambdas.fill(0);
1308 UniqueArray<SharedArray<Integer>> influences(nb_row);
1309 depends.resize(nb_row);
1310 //UniqueArray<IntegerUniqueArray> weak_depends(nb_row);
1311 m_points_type.resize(nb_row);
1312 m_points_type.fill(TYPE_UNDEFINED);
1313
1314 weak_depends.resize(mat_values.size());
1315 weak_depends.fill(0);
1316
1317 const bool type_hypre = true;
1318 //Values of each row that influences
1319 rows_max_val.resize(nb_row);
1320 for (Integer row = 0; row < nb_row; ++row) {
1321 Real max_val = 0.0;
1322 Real min_val = 0.0;
1323 Real diag_val = mat_values[rows_index[row]];
1324 // Cherche le max (en valeur absolue) de la colonne, autre que la diagonale
1325 for (Integer z = rows_index[row] + 1, zs = rows_index[row + 1]; z < zs; ++z) {
1326 //Real mv = math::abs(mat_values[z]);
1327 Real mv = mat_values[z];
1328 if (!type_hypre)
1329 mv = math::abs(mv);
1330 if (mv > max_val)
1331 max_val = mv;
1332 if (mv < min_val)
1333 min_val = mv;
1334 }
1335 // Prend tous les éléments supérieurs à alpha * max_val
1336 //rows_max_val[row] = max_val * alpha;
1337 if (type_hypre) {
1338 if (diag_val < 0.0)
1339 rows_max_val[row] = max_val * alpha;
1340 else
1341 rows_max_val[row] = min_val * alpha;
1342 }
1343 else
1344 rows_max_val[row] = max_val * alpha;
1345 }
1346
1347 for (Integer row = 0; row < nb_row; ++row) {
1348 // Prend tous les éléments supérieurs à max_val
1349 Real max_val = rows_max_val[row];
1350 Real diag_val = mat_values[rows_index[row]];
1351 for (Integer z = rows_index[row] + 1, zs = rows_index[row + 1]; z < zs; ++z) {
1352 //Real mv = math::abs(mat_values[z]);
1353 Real mv = mat_values[z];
1354 if (type_hypre) {
1355 if (diag_val < 0.0) {
1356 if (mv > max_val) {
1357 Integer column = columns[z];
1358 if (m_is_verbose)
1359 info() << " ADD INFLUENCE: ROW=" << row << " COL=" << column;
1360 ++lambdas[column];
1361 depends[row].add(column);
1362 influences[column].add(row);
1363 weak_depends[z] = 2;
1364 }
1365 else
1366 weak_depends[z] = 1;
1367 }
1368 else {
1369 if (mv < max_val) {
1370 Integer column = columns[z];
1371 if (m_is_verbose)
1372 info() << " ADD INFLUENCE: ROW=" << row << " COL=" << column;
1373 ++lambdas[column];
1374 depends[row].add(column);
1375 influences[column].add(row);
1376 weak_depends[z] = 2;
1377 }
1378 else
1379 weak_depends[z] = 1;
1380 }
1381 }
1382 else {
1383 if (math::abs(mv) > max_val) {
1384 Integer column = columns[z];
1385 if (m_is_verbose)
1386 info() << " ADD INFLUENCE: ROW=" << row << " COL=" << column;
1387 ++lambdas[column];
1388 depends[row].add(column);
1389 influences[column].add(row);
1390 weak_depends[z] = 2;
1391 }
1392 else {
1393 weak_depends[z] = 1;
1394 }
1395 }
1396 //else
1397 //weak_depends[row].add(column);
1398 }
1399 }
1400
1401 if (0) {
1402 OStringStream ostr;
1403 Integer index = 0;
1404 int n = math::min(nb_row, 800);
1405 ostr() << "GRAPH\n";
1406 for (Integer i = 0; i < n; ++i) {
1407 ostr() << " GRAPH I=" << i << " ";
1408 for (Integer j = 0; j < depends[i].size(); ++j) {
1409 ++index;
1410 ostr() << " " << depends[i][j];
1411 }
1412 ostr() << " index=" << index << '\n';
1413 }
1414 ostr() << "\n MAXTRIX\n";
1415 index = 0;
1416 for (Integer i = 0; i < n; ++i) {
1417 ostr() << "MATRIX I=" << i << " ";
1418 for (Integer j = rows_index[i]; j < rows_index[i + 1]; ++j) {
1419 ++index;
1420 ostr() << " " << columns[j] << " " << mat_values[j];
1421 }
1422 ostr() << " index=" << index << '\n';
1423 }
1424 info() << ostr.str();
1425 }
1426
1427 Integer nb_done = 0;
1428 Integer nb_iter = 0;
1429 Integer nb_fine = 0;
1430 Integer nb_coarse = 0;
1431 m_is_verbose = false;
1432 {
1433 // Marque comme point fin tous les points n'ayant aucune dépendance
1434 for (Integer row = 0; row < nb_row; ++row) {
1435 if (depends[row].size() == 0) {
1436 m_points_type[row] = TYPE_FINE;
1437 ++nb_done;
1438 if (m_is_verbose)
1439 info() << "FIRST MARK FINE point=" << row;
1440 }
1441 }
1442
1443 // Les points qui n'influencent personne sont forcément fins.
1444 for (Integer row = 0; row < nb_row; ++row) {
1445 if (m_points_type[row] != TYPE_FINE && lambdas[row] <= 0) {
1446 m_points_type[row] = TYPE_FINE;
1447 ++nb_done;
1448 if (m_is_verbose)
1449 info() << "INIT MARK FINE NULL MEASURE point=" << row << " measure=" << lambdas[row];
1450 for (Integer j = 0, js = depends[row].size(); j < js; ++j) {
1451 Integer col = depends[row][j];
1452 if (m_points_type[col] != TYPE_FINE)
1453 if (col < row) {
1454 ++lambdas[col];
1455 if (m_is_verbose)
1456 printf("ADD MEASURE NULL point=%d measure=%d\n", (int)col, lambdas[col]);
1457 }
1458 }
1459 }
1460 }
1461
1462 typedef std::set<PointInfo> PointSet;
1463 PointSet undefined_points;
1464 for (Integer i = 0; i < nb_row; ++i) {
1465 if (m_points_type[i] == TYPE_UNDEFINED)
1466 undefined_points.insert(PointInfo(lambdas[i], i));
1467 }
1468
1469 while (nb_done < nb_row && nb_iter < 100000) {
1470 ++nb_iter;
1471 //for( PointSet::const_iterator i(undefined_points.data()); i!=undefined_points.end(); ++i ){
1472 //info() << " SET index=" << i->m_index << " value=" << i->m_lambda;
1473 //}
1474 // Prend le lambda max et note le point C
1475 //Integer max_value = -1;
1476 //Integer max_value_index = -1;
1477 //for( Integer i=0; i<nb_row; ++i ){
1478 //if (lambdas[i]>max_value && points_type[i]==TYPE_UNDEFINED){
1479 // max_value = lambdas[i];
1480 // max_value_index = i;
1481 //}
1482 //}
1483 if (undefined_points.empty())
1484 fatal() << "Undefined points is empty";
1485 PointSet::iterator max_point = undefined_points.begin();
1486 Integer max_value_index = max_point->m_index;
1487 Integer max_value = max_point->m_lambda;
1488 m_points_type[max_value_index] = TYPE_COARSE;
1489 ++nb_done;
1490 ++nb_coarse;
1491 undefined_points.erase(max_point);
1492 if (m_is_verbose)
1493 std::cout << "MARK COARSE point=" << max_value_index
1494 << " measure=" << max_value
1495 << " left=" << (nb_row - nb_done)
1496 << "\n";
1497 IntegerConstArrayView point_influences = influences[max_value_index];
1498 for (Integer i = 0, is = point_influences.size(); i < is; ++i) {
1499 //for( Integer i=0, is=depends[max_value_index].size(); i<is; ++i ){
1500 Integer pt = point_influences[i];
1501 //Integer pt = depends[max_value_index][i];
1502 if (m_points_type[pt] == TYPE_UNDEFINED) {
1503 m_points_type[pt] = TYPE_FINE;
1504 ++nb_done;
1505 ++nb_fine;
1506 undefined_points.erase(PointInfo(lambdas[pt], pt));
1507 if (m_is_verbose)
1508 std::cout << "MARK FINE point=" << pt
1509 << " measure=" << lambdas[pt]
1510 << " left=" << (nb_row - nb_done)
1511 << "\n";
1512 for (Integer z = 0, zs = depends[pt].size(); z < zs; ++z) {
1513 Integer pt2 = depends[pt][z];
1514 //for( Integer z=0, zs=point_influences.size(); z<zs; ++z ){
1515 //Integer pt2 = point_influences[z];
1516 if (m_points_type[pt2] == TYPE_UNDEFINED) {
1517 undefined_points.erase(PointInfo(lambdas[pt2], pt2));
1518 ++lambdas[pt2];
1519 undefined_points.insert(PointInfo(lambdas[pt2], pt2));
1520 }
1521 }
1522 }
1523 }
1524 for (Integer i = 0, is = depends[max_value_index].size(); i < is; ++i) {
1525 Integer pt3 = depends[max_value_index][i];
1526 if (m_points_type[pt3] == TYPE_UNDEFINED) {
1527 undefined_points.erase(PointInfo(lambdas[pt3], pt3));
1528 Integer n = lambdas[pt3];
1529 if (n < 0)
1530 info() << "N < 0";
1531 --lambdas[pt3];
1532 undefined_points.insert(PointInfo(lambdas[pt3], pt3));
1533 }
1534 }
1535 if (m_is_verbose)
1536 info() << "LAMBDA MAX = " << max_value << " index=" << max_value_index << " nb_done=" << nb_done;
1537 }
1538 }
1539
1540 if (m_is_verbose)
1541 info() << "NB ROW=" << nb_row << " nb_done=" << nb_done << " nb_fine=" << nb_fine
1542 << " nb_coarse=" << nb_coarse << " nb_iter=" << nb_iter;
1543 if (nb_done != nb_row)
1544 fatal() << "Can not find all COARSE or FINE points nb_done=" << nb_done << " nb_point=" << nb_row;
1545
1546 {
1547 //Now, we must ensure that two F-F connections have at least one
1548 // common C point. If not, the first F is changed to C
1549 //info() << "SECOND PASS !!!";
1550 Int32UniqueArray points_marker(nb_row);
1551 points_marker.fill(-1);
1552 Integer ci_tilde_mark = -1;
1553 Integer ci_tilde = -1;
1554 bool C_i_nonempty = false;
1555 for (Integer row = 0; row < nb_row; ++row) {
1556 if ((ci_tilde_mark |= row))
1557 ci_tilde = -1;
1558 if (m_points_type[row] == TYPE_FINE) {
1559 for (Integer z = 0, zs = depends[row].size(); z < zs; ++z) {
1560 //for( Integer z=rows_index[row] ,zs=rows_index[row+1]; z<zs; ++z ){
1561 //Integer col = columns[z];
1562 Integer col = depends[row][z];
1563 if (m_points_type[col] == TYPE_COARSE)
1564 points_marker[col] = row;
1565 }
1566 for (Integer z = 0, zs = depends[row].size(); z < zs; ++z) {
1567 //for( Integer z=rows_index[row] ,zs=rows_index[row+1]; z<zs; ++z ){
1568 //Integer col = columns[z];
1569 Integer col = depends[row][z];
1570 if (m_points_type[col] == TYPE_FINE) {
1571 bool set_empty = true;
1572 for (Integer z2 = 0, zs2 = depends[row].size(); z2 < zs2; ++z2) {
1573 //for( Integer z2=rows_index[row] ,zs2=rows_index[row+1]; z2<zs2; ++z2 ){
1574 //Integer col2 = columns[z2];
1575 Integer col2 = depends[row][z2];
1576 if (points_marker[col2] == row) {
1577 set_empty = false;
1578 break;
1579 }
1580 }
1581 if (set_empty) {
1582 if (C_i_nonempty) {
1583 m_points_type[row] = TYPE_COARSE;
1584 //printf("SECOND PASS MARK COARSE1 point=%d\n",row);
1585 if (ci_tilde > -1) {
1586 m_points_type[ci_tilde] = TYPE_FINE;
1587 if (m_is_verbose)
1588 printf("SECOND PASS MARK FINE point=%d\n", ci_tilde);
1589 ci_tilde = -1;
1590 }
1591 C_i_nonempty = false;
1592 }
1593 else {
1594 ci_tilde = col;
1595 ci_tilde_mark = row;
1596 m_points_type[col] = TYPE_COARSE;
1597 if (m_is_verbose)
1598 printf("SECOND PASS MARK COARSE2 point=%d\n", col);
1599 C_i_nonempty = true;
1600 --row;
1601 break;
1602 }
1603 }
1604 }
1605 }
1606 }
1607 }
1608 }
1609
1610 if (0) {
1611 //Reading from Hypre
1612 static int matrix_number = 0;
1613 ++matrix_number;
1614 info() << "READ HYPRE CF_marker n=" << matrix_number;
1615 StringBuilder fname("CF_marker-");
1616 fname += matrix_number;
1617 std::ifstream ifile(fname.toString().localstr());
1618 Integer nb_read_point = 0;
1619 ifile >> std::ws >> nb_read_point >> std::ws;
1620 if (nb_read_point != nb_row)
1621 fatal() << "Bad number of points for reading Hypre CF_marker read=" << nb_read_point
1622 << " expected=" << nb_row << " matrix_number=" << matrix_number;
1623 nb_coarse = 0;
1624 nb_fine = 0;
1625 for (Integer i = 0; i < nb_row; ++i) {
1626 int pt = 0;
1627 ifile >> pt;
1628 if (!ifile)
1629 fatal() << "Can not read marker point number=" << i;
1630 if (pt == (-1) || pt == (-3)) {
1631 m_points_type[i] = TYPE_FINE;
1632 ++nb_fine;
1633 }
1634 else if (pt == 1) {
1635 m_points_type[i] = TYPE_COARSE;
1636 ++nb_coarse;
1637 }
1638 else
1639 fatal() << "Bad value read=" << pt << " expected 1 or -1";
1640 }
1641 }
1642
1643 // Checks that all fine points have at least one influencing point
1644 nb_coarse = 0;
1645 for (Integer i = 0; i < nb_row; ++i) {
1646 if (m_points_type[i] == TYPE_UNDEFINED)
1647 fatal() << " Point " << i << " is undefined";
1648 if (m_points_type[i] != TYPE_FINE) {
1649 ++nb_coarse;
1650 continue;
1651 }
1652#if 0
1653 bool is_ok = false;
1654 //info() << "CHECK POINT point=" << i
1655 // << " depend_size=" << depends[i].size();
1656 for( Integer z=0, zs=depends[i].size(); z<zs; ++z ){
1657 if (m_points_type[depends[i][z]]==TYPE_COARSE){
1658 is_ok = true;
1659 break;
1660 }
1661 }
1662 //if (!is_ok)
1663 // fatal() << " Point " << i << " has no coarse point";
1664#endif
1665 }
1666
1667 if (m_is_verbose) {
1668 OStringStream ostr;
1669 for (Integer i = 0; i < nb_row; ++i) {
1670 ostr() << " POINT i=" << i << " type=" << m_points_type[i] << " depends=";
1671 for (Integer j = 0, js = depends[i].size(); j < js; ++j)
1672 ostr() << depends[i][j] << ' ';
1673 ostr() << '\n';
1674 }
1675 info() << ostr.str();
1676 }
1677
1678 nb_fine = nb_row - nb_coarse;
1679 Integer graph_size = 0;
1680 for (Integer i = 0; i < nb_row; ++i)
1681 graph_size += depends[i].size();
1682
1683 info() << " NB COARSE=" << nb_coarse << " NB FINE=" << nb_fine
1684 << " MAXTRIX NON_ZEROS=" << m_fine_matrix.rowsIndex()[nb_row]
1685 << " GRAPH_SIZE=" << graph_size;
1686 bool dump_matrix = false;
1687 bool has_error = false;
1688 if (nb_fine == 0 || graph_size == 0) {
1689 has_error = true;
1690 dump_matrix = true;
1691 }
1692
1693 if (dump_matrix) {
1694 OStringStream ostr;
1695 Integer index = 0;
1696 int n = math::min(nb_row, 40);
1697 if (0) {
1698 ostr() << "GRAPH\n";
1699 for (Integer i = 0; i < n; ++i) {
1700 ostr() << " GRAPH I=" << i << " ";
1701 for (Integer j = 0; j < depends[i].size(); ++j) {
1702 ++index;
1703 ostr() << " " << depends[i][j];
1704 }
1705 ostr() << " index=" << index << '\n';
1706 }
1707 }
1708 ostr() << "\n MAXTRIX\n";
1709 index = 0;
1710 for (Integer i = 0; i < n; ++i) {
1711 ostr() << "MATRIX I=" << i << " ";
1712 for (Integer j = rows_index[i]; j < rows_index[i + 1]; ++j) {
1713 ++index;
1714 ostr() << " " << columns[j] << " " << mat_values[j];
1715 }
1716 ostr() << " index=" << index << '\n';
1717 }
1718 info() << ostr.str();
1719 }
1720 if (has_error)
1721 throw FatalErrorException("AMGLevel::_buildCoarsePoints");
1722}
1723
1724/*---------------------------------------------------------------------------*/
1725/*---------------------------------------------------------------------------*/
1726
1727void AMGLevel::
1728buildLevel(Matrix matrix, Real alpha)
1729{
1730 //Integer nb_row = matrix.nbRow();
1731 //if (nb_row<20)
1732 //return;
1733
1734 m_fine_matrix = matrix;
1735
1736 //bool is_verbose = false;
1737 matrix.sortDiagonale();
1738
1739 IntegerUniqueArray points_type;
1740 RealUniqueArray rows_max_val;
1741 UniqueArray<SharedArray<Integer>> depends;
1742 IntegerUniqueArray weak_depends;
1743
1744 _buildCoarsePoints(alpha, rows_max_val, depends, weak_depends);
1745 _buildInterpolationMatrix(rows_max_val, depends, weak_depends);
1746}
1747
1748/*---------------------------------------------------------------------------*/
1749/*---------------------------------------------------------------------------*/
1750
1751void AMGLevel::
1752_buildInterpolationMatrix(RealConstArrayView rows_max_val,
1753 UniqueArray<SharedArray<Integer>>& depends,
1754 IntegerArray& weak_depends)
1755{
1756 ARCANE_UNUSED(rows_max_val);
1757
1758 IntegerConstArrayView rows_index = m_fine_matrix.rowsIndex();
1759 IntegerConstArrayView columns = m_fine_matrix.columns();
1760 RealConstArrayView mat_values = m_fine_matrix.values();
1761 Integer nb_row = m_fine_matrix.nbRow();
1762
1763 IntegerUniqueArray points_in_coarse(nb_row);
1764 points_in_coarse.fill(-1);
1765 Integer nb_coarse = 0;
1766 {
1767 //Integer index = 0;
1768 nb_coarse = 0;
1769 for (Integer i = 0; i < nb_row; ++i) {
1770 if (m_points_type[i] == TYPE_COARSE) {
1771 points_in_coarse[i] = nb_coarse;
1772 ++nb_coarse;
1773 }
1774 }
1775 }
1776 bool type_hypre = true;
1777
1778 // Now, calculate the elements of the influence matrix
1779 IntegerUniqueArray prolongation_matrix_columns;
1780 RealUniqueArray prolongation_matrix_values;
1781 IntegerUniqueArray prolongation_matrix_rows_size(nb_row);
1782
1783 for (Integer row = 0; row < nb_row; ++row) {
1784 Integer nb_column = 0;
1785 if (m_points_type[row] == TYPE_FINE) {
1786 Real weak_connect_sum = 0.0;
1787 //Real max_value = rows_max_val[row];
1788 Real diag = mat_values[rows_index[row]];
1789 Real sign = 1.0;
1790 if (diag < 0.0)
1791 sign = -1.0;
1792 for (Integer z = rows_index[row] + 1, zs = rows_index[row + 1]; z < zs; ++z) {
1793 //Integer column = columns[z];
1794 if (weak_depends[z] == 1) {
1795 Real mv = mat_values[z];
1796 if (type_hypre)
1797 weak_connect_sum += mv;
1798 else {
1799 //weak_connect_sum += math::abs(mv);
1800 weak_connect_sum += mv;
1801 }
1802 //if (m_is_verbose || row<=5)
1803 //info() << "ADD WEAK_SUM mv=" << mv << " sum=" << weak_connect_sum
1804 // << " row=" << row << " column=" << column;
1805 }
1806 }
1807 if (m_is_verbose)
1808 info() << "ROW row=" << row << " weak_connect_sum=" << weak_connect_sum;
1809 //for( Integer z=0, zs=depends[row].size(); z<zs; ++ z){
1810 //Integer j_column = dependcolumns[z];
1811 for (Integer z = rows_index[row] + 1, zs = rows_index[row + 1]; z < zs; ++z) {
1812 Integer j_column = columns[z];
1813 if (m_points_type[j_column] != TYPE_COARSE)
1814 continue;
1815 if (weak_depends[z] != 2)
1816 continue;
1817 Real num_add = 0.0;
1818 Real mv = mat_values[z];
1819 for (Integer z2 = 0, zs2 = depends[row].size(); z2 < zs2; ++z2) {
1820 Integer k_column = depends[row][z2];
1821 //if (m_is_verbose || row<=5)
1822 //info() << "CHECK K_COLUMN row=" << row << " col=" << k_column << " val=" << mv;
1823 if (m_points_type[k_column] != TYPE_FINE)
1824 continue;
1825 Real sum_coarse = 0.0;
1826 //if (m_is_verbose || row<=5)
1827 //info() << "CHECK COARSE row=" << row;
1828 //for( Integer z3=rows_index[row]+1 ,zs3=rows_index[row+1]; z3<zs3; ++z3 ){
1829 //Integer m_column = columns[z3];
1830 for (Integer z3 = 0, zs3 = depends[row].size(); z3 < zs3; ++z3) {
1831 Integer m_column = depends[row][z3];
1832 //if (m_is_verbose || row<=5)
1833 //info() << "CHECK COLUMN column=" << m_column;
1834 if (m_points_type[m_column] == TYPE_COARSE) {
1835 Real w = m_fine_matrix.value(k_column, m_column);
1836 //if (m_is_verbose || row<=5)
1837 //info() << "ADD SUM k=" << k_column << " m="<< m_column << " w=" << w;
1838 //if (math::isZero(w)){
1839 //fatal() << "WEIGHT is null k=" << k_column << " m=" << m_column << " row=" << row
1840 // << " j=" << j_column;
1841 //}
1842 if (type_hypre) {
1843 if (w * sign < 0.0)
1844 sum_coarse += w;
1845 }
1846 else {
1847 sum_coarse += math::abs(w);
1848 //if (w*sign<0.0)
1849 //sum_coarse += w;
1850 }
1851 }
1852 }
1853 Real to_add = 0.0;
1854 if (!math::isZero(sum_coarse)) {
1855 Real akj = m_fine_matrix.value(k_column, j_column);
1856 bool do_add = false;
1857 if (type_hypre) {
1858 if ((akj * sign) < 0.0)
1859 do_add = true;
1860 }
1861 else {
1862 //if ((akj*sign)<0.0)
1863 //do_add = true;
1864 akj = math::abs(akj);
1865 do_add = true;
1866 }
1867 if (do_add)
1868 //fatal() << "SUM_WEIGHT is null k=" << k_column << " row=" << row << " j=" << j_column;
1869 to_add = math::divide(m_fine_matrix.value(row, k_column) * akj, sum_coarse);
1870 }
1871 num_add += to_add;
1872 }
1873 Real weight = -(mv + num_add) / (diag + weak_connect_sum);
1874 Integer new_column = points_in_coarse[j_column];
1875 //if (m_is_verbose || row<=5)
1876 //info() << " ** WEIGHT row=" << row << " j_column=" << j_column
1877 // << " weight=" << weight << " num_add=" << num_add << " mv=" << mv << " new_column=" << new_column
1878 // << " diag=" << diag << " weak_sum=" << weak_connect_sum
1879 // << " diag+wk=" << (diag+weak_connect_sum);
1880 if (new_column >= nb_coarse || new_column < 0)
1881 fatal() << " BAD COLUMN for fine point column=" << new_column << " nb=" << nb_coarse
1882 << " jcolumn=" << j_column;
1883 prolongation_matrix_columns.add(new_column);
1884 prolongation_matrix_values.add(weight);
1885 ++nb_column;
1886 }
1887 }
1888 else {
1889 // Coarse point, sets 1.0 on the diagonal
1890 Integer column = points_in_coarse[row];
1891 if (column >= nb_coarse || column < 0)
1892 fatal() << " BAD COLUMN for coarse point j=" << column << " nb=" << nb_coarse
1893 << " row=" << row;
1894 prolongation_matrix_columns.add(column);
1895 prolongation_matrix_values.add(1.0);
1896 ++nb_column;
1897 }
1898 prolongation_matrix_rows_size[row] = nb_column;
1899 }
1900
1901 m_prolongation_matrix = Matrix(nb_row, nb_coarse);
1902 m_prolongation_matrix.setRowsSize(prolongation_matrix_rows_size);
1903 //info() << "PROLONGATION_MATRIX_SIZE=" << m_prolongation_matrix.rowsIndex()[nb_row];
1904 m_prolongation_matrix.setValues(prolongation_matrix_columns, prolongation_matrix_values);
1905
1906 if (0) {
1907 OStringStream ostr;
1908 Integer index = 0;
1909 int n = math::min(nb_row, 50);
1910 IntegerConstArrayView p_rows(m_prolongation_matrix.rowsIndex());
1911 IntegerConstArrayView p_columns(m_prolongation_matrix.columns());
1912 RealConstArrayView p_values(m_prolongation_matrix.values());
1913 for (Integer i = 0; i < n; ++i) {
1914 ostr() << "PROLONG I=" << i << " ";
1915 for (Integer j = p_rows[i]; j < p_rows[i + 1]; ++j) {
1916 ++index;
1917 ostr() << " " << p_columns[j] << " " << p_values[j];
1918 }
1919 ostr() << " index=" << index << '\n';
1920 }
1921 info() << "PROLONG\n"
1922 << ostr.str();
1923 }
1924
1925 MatrixOperation2 mat_op2;
1926 if (1)
1927 m_restriction_matrix = mat_op2.transposeFast(m_prolongation_matrix);
1928 else
1929 m_restriction_matrix = mat_op2.transpose(m_prolongation_matrix);
1930 if (m_is_verbose) {
1931 OStringStream ostr;
1932 ostr() << "PROLONGATION_MATRIX ";
1933 m_prolongation_matrix.dump(ostr());
1934 ostr() << '\n';
1935 ostr() << "RESTRICTION_MATRIX ";
1936 m_restriction_matrix.dump(ostr());
1937 info() << ostr.str();
1938 }
1939 //info() << " ** TOTAL SUM=" << total_sum;
1940 // Calculate the coarse matrix Ak+1 = I * Ak * tI
1941 //MatrixOperation mat_op;
1942 const bool old = false;
1943 if (old) {
1944 Matrix n1 = mat_op2.matrixMatrixProductFast(m_fine_matrix, m_prolongation_matrix);
1945 if (m_is_verbose) {
1946 OStringStream ostr;
1947 n1.dump(ostr());
1948 info() << "N1_MATRIX " << ostr.str();
1949 }
1950 m_coarse_matrix = mat_op2.matrixMatrixProductFast(m_restriction_matrix, n1);
1951 }
1952 else
1953 m_coarse_matrix = mat_op2.applyGalerkinOperator2(m_restriction_matrix, m_fine_matrix, m_prolongation_matrix);
1954 if (m_is_verbose) {
1955 OStringStream ostr;
1956 m_coarse_matrix.dump(ostr());
1957 info() << "level= " << m_level << " COARSE_MATRIX=" << ostr.str();
1958 }
1959}
1960
1961/*---------------------------------------------------------------------------*/
1962/*---------------------------------------------------------------------------*/
1963
1964AMGPreconditioner::
1965~AMGPreconditioner()
1966{
1967 delete m_amg;
1968}
1969
1970/*---------------------------------------------------------------------------*/
1971/*---------------------------------------------------------------------------*/
1972
1973void AMGPreconditioner::
1974apply(Vector& out_vec, const Vector& vec)
1975{
1976 m_amg->solve(vec, out_vec);
1977}
1978
1979/*---------------------------------------------------------------------------*/
1980/*---------------------------------------------------------------------------*/
1981
1982void AMGPreconditioner::
1983build(const Matrix& matrix)
1984{
1985 delete m_amg;
1986 m_amg = new AMG(m_trace_mng);
1987 m_amg->build(matrix);
1988}
1989
1990/*---------------------------------------------------------------------------*/
1991/*---------------------------------------------------------------------------*/
1992
1993/*---------------------------------------------------------------------------*/
1994/*---------------------------------------------------------------------------*/
1995
1996AMGSolver::
1997~AMGSolver()
1998{
1999 delete m_amg;
2000}
2001
2002/*---------------------------------------------------------------------------*/
2003/*---------------------------------------------------------------------------*/
2004
2005void AMGSolver::
2006build(const Matrix& matrix)
2007{
2008 delete m_amg;
2009 m_amg = new AMG(m_trace_mng);
2010 m_amg->build(matrix);
2011}
2012
2013/*---------------------------------------------------------------------------*/
2014/*---------------------------------------------------------------------------*/
2015
2016void AMGSolver::
2017solve(const Vector& vector_b, Vector& vector_x)
2018{
2019 m_amg->solve(vector_b, vector_x);
2020}
2021
2022/*---------------------------------------------------------------------------*/
2023/*---------------------------------------------------------------------------*/
2024
2025} // namespace Arcane::MatVec
2026
2027/*---------------------------------------------------------------------------*/
2028/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
void fill(const T &o) noexcept
Fills the array with the value o.
constexpr const_pointer data() const noexcept
Pointer to the allocated memory.
constexpr Integer size() const noexcept
Number of elements in the array.
Matrix with CSR storage.
bool operator<(const PointInfo &rhs) const
Definition AMG.cc:1217
Linear algebra vector.
Matrix class, to be used by user.
1D vector of data with reference semantics.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage fatal() const
Flow for a fatal error message.
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
1D data vector with value semantics (STL style).
__host__ __device__ Real2 min(Real2 a, Real2 b)
Returns the minimum of two Real2.
Definition MathUtils.h:346
Namespace for mathematical functions.
Definition MathUtils.h:36
bool isZero(const BuiltInProxy< _Type > &a)
Tests if a value is exactly equal to zero.
apfloat sqrt(apfloat v)
Square root of v.
Definition MathApfloat.h:69
Int32 Integer
Type representing an integer.
ConstArrayView< Int32 > Int32ConstArrayView
C equivalent of a 1D array of 32-bit integers.
Definition UtilsTypes.h:476
ArrayView< Integer > IntegerArrayView
C equivalent of a 1D array of integers.
Definition UtilsTypes.h:451
Array< Integer > IntegerArray
Dynamic one-dimensional array of integers.
Definition UtilsTypes.h:127
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
Definition UtilsTypes.h:335
UniqueArray< Real > RealUniqueArray
Dynamic 1D array of reals.
Definition UtilsTypes.h:343
double Real
Type representing a real number.
Array< Real > RealArray
Dynamic one-dimensional array of reals.
Definition UtilsTypes.h:129
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
Definition UtilsTypes.h:341
ConstArrayView< Integer > IntegerConstArrayView
C equivalent of a 1D array of integers.
Definition UtilsTypes.h:480
ArrayView< Real > RealArrayView
C equivalent of a 1D array of reals.
Definition UtilsTypes.h:453
ConstArrayView< Real > RealConstArrayView
C equivalent of a 1D array of reals.
Definition UtilsTypes.h:482