Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
AlephHypre.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/* AlephHypre.cc (C) 2000-2025 */
9/* */
10/* Implémentation Hypre de Aleph. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#define HAVE_MPI
15#define MPI_COMM_SUB (*(MPI_Comm*)(m_kernel->subParallelMng(m_index)->getMPICommunicator()))
16#define OMPI_SKIP_MPICXX
17#ifndef MPICH_SKIP_MPICXX
18#define MPICH_SKIP_MPICXX
19#endif
20#include <HYPRE.h>
21#include <HYPRE_utilities.h>
22#include <HYPRE_IJ_mv.h>
23#include <HYPRE_parcsr_mv.h>
24#include <HYPRE_parcsr_ls.h>
25#include <_hypre_parcsr_mv.h>
26
27#if HYPRE_RELEASE_NUMBER >= 30000
28#include <_hypre_krylov.h>
29#else
30#include <krylov.h>
31#endif
32
33#ifndef ItacRegion
34#define ItacRegion(a, x)
35#endif
36
37#include "arcane/aleph/AlephArcane.h"
38
39// Le type HYPRE_BigInt n'existe qu'à partir de Hypre 2.16.0
40#if HYPRE_RELEASE_NUMBER < 21600
41using HYPRE_BigInt = HYPRE_Int;
42#endif
43
44/*---------------------------------------------------------------------------*/
45/*---------------------------------------------------------------------------*/
46
47namespace Arcane
48{
49
50/*---------------------------------------------------------------------------*/
51/*---------------------------------------------------------------------------*/
52
53/*
54 * NOTE: A partir de la version 2.14 de hypre (peut-être un peu avant),
55 * hypre_TAlloc() et hypre_CAlloc() prennent un 3ème argument qui est
56 * sur quel peripherique on alloue la mémoire (GPU ou CPU). Il n'y a pas
57 * de moyens simples de savoir quelle est la version de hypre à partir
58 * des .h mais par contre HYPRE_MEMORY_DEVICE et HYPRE_MEMORY_HOST sont
59 * des macros donc on peut tester leur existance pour savoir s'il faut
60 * appeler les méthodes hypre_TAlloc() et hypre_CAlloc() avec 2 ou 3 arguments.
61 */
62namespace
63{
64 inline void
65 check(const char* hypre_func, HYPRE_Int error_code)
66 {
67 if (error_code == 0)
68 return;
69 char buf[8192];
70 HYPRE_DescribeError(error_code, buf);
71 std::cout << "\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
72 << "\nHYPRE ERROR in function "
73 << hypre_func
74 << "\nError_code=" << error_code
75 << "\nMessage=" << buf
76 << "\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
77 << "\n"
78 << std::flush;
79 throw Exception("HYPRE Check", hypre_func);
80 }
81
82 template <typename T>
83 inline T*
84 _allocHypre(Integer size)
85 {
86 size_t s = sizeof(T) * size;
87 return reinterpret_cast<T*>(hypre_TAlloc(char, s, HYPRE_MEMORY_HOST));
88 }
89
90 template <typename T>
91 inline T*
92 _callocHypre(Integer size)
93 {
94 size_t s = sizeof(T) * size;
95 return reinterpret_cast<T*>(hypre_CTAlloc(char, s, HYPRE_MEMORY_HOST));
96 }
97
98 inline void
99 hypreCheck(const char* hypre_func, HYPRE_Int error_code)
100 {
101 check(hypre_func, error_code);
102 HYPRE_Int r = HYPRE_GetError();
103 if (r != 0)
104 std::cout << "HYPRE GET ERROR r=" << r
105 << " error_code=" << error_code << " func=" << hypre_func << '\n';
106 }
107
108} // namespace
109
110/******************************************************************************
111 AlephVectorHypre
112 *****************************************************************************/
113class AlephVectorHypre
114: public IAlephVector
115{
116 public:
117
118 AlephVectorHypre(ITraceMng* tm, AlephKernel* kernel, Integer index)
119 : IAlephVector(tm, kernel, index)
120 , jSize(0)
121 , jUpper(0)
122 , jLower(-1)
123 {
124 debug() << "[AlephVectorHypre::AlephVectorHypre] new SolverVectorHypre";
125 }
126 ~AlephVectorHypre()
127 {
128 if (m_hypre_ijvector)
129 HYPRE_IJVectorDestroy(m_hypre_ijvector);
130 }
131
132 public:
133
134 /******************************************************************************
135 * La routine Create() crée un objet vecteur vide qui vit sur le communicateur de communication. Il s'agit
136 * d'un appel collectif, chaque processus passant ses propres étendues d'index, jLower et jupper. Les noms
137 * de ces paramètres d'étendue commencent par un j car nous considérons généralement les multiplications matrice-vecteur
138 * comme l'opération fondamentale impliquant à la fois les matrices et les vecteurs. Pour les multiplications matrice-vecteur,
139 * le partitionnement du vecteur doit correspondre au partitionnement des colonnes de la matrice (qui utilise également la
140 * notation j). Pour la résolution de systèmes linéaires, ces étendues correspondront généralement également au partitionnement des lignes de la matrice.
141 *****************************************************************************/
142 void AlephVectorCreate(void)
143 {
144 debug() << "[AlephVectorHypre::AlephVectorCreate] HYPRE VectorCreate";
145 void* object;
146
147 for (int iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
148 if (m_kernel->rank() != m_kernel->solverRanks(m_index)[iCpu])
149 continue;
150 debug() << "[AlephVectorHypre::AlephVectorCreate] adding contibution of core #" << iCpu;
151 if (jLower == -1)
152 jLower = m_kernel->topology()->gathered_nb_row(iCpu);
153 jUpper = m_kernel->topology()->gathered_nb_row(iCpu + 1) - 1;
154 }
155
156 debug() << "[AlephVectorHypre::AlephVectorCreate] jLower=" << jLower << ", jupper=" << jUpper;
157 // Mise à jour de la taille locale du buffer pour le calcul plus tard de la norme max, par exemple
158 jSize = jUpper - jLower + 1;
159
160 hypreCheck("IJVectorCreate",
161 HYPRE_IJVectorCreate(MPI_COMM_SUB,
162 jLower,
163 jUpper,
164 &m_hypre_ijvector));
165
166 debug() << "[AlephVectorHypre::AlephVectorCreate] HYPRE IJVectorSetObjectType";
167 hypreCheck("IJVectorSetObjectType", HYPRE_IJVectorSetObjectType(m_hypre_ijvector, HYPRE_PARCSR));
168
169 debug() << "[AlephVectorHypre::AlephVectorCreate] HYPRE IJVectorInitialize";
170 hypreCheck("HYPRE_IJVectorInitialize", HYPRE_IJVectorInitialize(m_hypre_ijvector));
171
172 HYPRE_IJVectorGetObject(m_hypre_ijvector, &object);
173 m_hypre_parvector = (HYPRE_ParVector)object;
174 debug() << "[AlephVectorHypre::AlephVectorCreate] done";
175 }
176
177 /******************************************************************************
178 *****************************************************************************/
179 void AlephVectorSet(const double* bfr_val, const AlephInt* bfr_idx, Integer size)
180 {
181 debug() << "[AlephVectorHypre::AlephVectorSet] size=" << size;
182 hypreCheck("IJVectorSetValues", HYPRE_IJVectorSetValues(m_hypre_ijvector, size, bfr_idx, bfr_val));
183 }
184
185 /******************************************************************************
186 *****************************************************************************/
187 int AlephVectorAssemble(void)
188 {
189 debug() << "[AlephVectorHypre::AlephVectorAssemble]";
190 hypreCheck("IJVectorAssemble", HYPRE_IJVectorAssemble(m_hypre_ijvector));
191 return 0;
192 }
193
194 /******************************************************************************
195 *****************************************************************************/
196 void AlephVectorGet(double* bfr_val, const AlephInt* bfr_idx, Integer size)
197 {
198 //HYPRE_Int* hypre_bfr_idx = static
199 debug() << "[AlephVectorHypre::AlephVectorGet] size=" << size;
200 hypreCheck("HYPRE_IJVectorGetValues", HYPRE_IJVectorGetValues(m_hypre_ijvector, size, bfr_idx, bfr_val));
201 }
202
203 /******************************************************************************
204 * norm_max
205 *****************************************************************************/
206 Real norm_max()
207 {
208 Real normInf = 0.0;
209 UniqueArray<HYPRE_BigInt> bfr_idx(jSize);
210 UniqueArray<double> bfr_val(jSize);
211
212 for (HYPRE_Int i = 0; i < jSize; ++i)
213 bfr_idx[i] = jLower + i;
214
215 hypreCheck("HYPRE_IJVectorGetValues", HYPRE_IJVectorGetValues(m_hypre_ijvector, jSize, bfr_idx.data(), bfr_val.data()));
216 for (HYPRE_Int i = 0; i < jSize; ++i) {
217 const Real abs_val = math::abs(bfr_val[i]);
218 if (abs_val > normInf)
219 normInf = abs_val;
220 }
221 normInf = m_kernel->subParallelMng(m_index)->reduce(Parallel::ReduceMax, normInf);
222 return normInf;
223 }
224
225 /******************************************************************************
226 *****************************************************************************/
227 void writeToFile(const String filename)
228 {
229 String filename_idx = filename; // + "_" + (int)m_kernel->subDomain()->commonVariables().globalIteration();
230 debug() << "[AlephVectorHypre::writeToFile]";
231 hypreCheck("HYPRE_IJVectorPrint",
232 HYPRE_IJVectorPrint(m_hypre_ijvector, filename_idx.localstr()));
233 }
234
235 public:
236
237 HYPRE_IJVector m_hypre_ijvector = nullptr;
238 HYPRE_ParVector m_hypre_parvector = nullptr;
239 HYPRE_Int jSize;
240 HYPRE_Int jUpper;
241 HYPRE_Int jLower;
242};
243
244/******************************************************************************
245 AlephMatrixHypre
246*****************************************************************************/
247class AlephMatrixHypre
248: public IAlephMatrix
249{
250 public:
251
252 /******************************************************************************
253 AlephMatrixHypre
254 *****************************************************************************/
255 AlephMatrixHypre(ITraceMng* tm, AlephKernel* kernel, Integer index)
256 : IAlephMatrix(tm, kernel, index)
257 , m_hypre_ijmatrix(0)
258 {
259 debug() << "[AlephMatrixHypre] new AlephMatrixHypre";
260 }
261
262 ~AlephMatrixHypre()
263 {
264 debug() << "[~AlephMatrixHypre]";
265 if (m_hypre_ijmatrix)
266 HYPRE_IJMatrixDestroy(m_hypre_ijmatrix);
267 }
268
269 public:
270
271 /******************************************************************************
272 * Chaque sous-matrice Ap est « possédée » par un seul processus et ses numéros de ligne de début et de fin sont
273 * donnés par les indices globaux ilower et iupper dans l'appel Create() ci-dessous.
274 *******************************************************************************
275 * La routine Create() crée un objet matrice vide qui vit sur le communicateur de communication. Il s'agit
276 * d'un appel collectif (c'est-à-dire qu'il doit être appelé sur tous les processus à partir d'un point de synchronisation commun),
277 * chaque processus passant ses propres étendues de lignes, ilower et iupper. Le partitionnement des lignes doit être
278 * contigu, c'est-à-dire que iupper pour le processus i doit être égal à ilower-1 pour le processus i+1. Notez que cela permet
279 * aux matrices d'avoir un indexage basé sur 0 ou 1. Les paramètres jlower et jupper définissent un partitionnement des colonnes,
280 * et doivent correspondre à ilower et iupper lors de la résolution de systèmes linéaires carrés.
281 *****************************************************************************/
282 void AlephMatrixCreate(void)
283 {
284 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE MatrixCreate idx:" << m_index;
285 void* object;
286 AlephInt ilower = -1;
287 AlephInt iupper = 0;
288 for (int iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
289 if (m_kernel->rank() != m_kernel->solverRanks(m_index)[iCpu])
290 continue;
291 if (ilower == -1)
292 ilower = m_kernel->topology()->gathered_nb_row(iCpu);
293 iupper = m_kernel->topology()->gathered_nb_row(iCpu + 1) - 1;
294 }
295 debug() << "[AlephMatrixHypre::AlephMatrixCreate] ilower=" << ilower << ", iupper=" << iupper;
296
297 AlephInt jlower = ilower; //0;
298 AlephInt jupper = iupper; //m_kernel->topology()->gathered_nb_row(m_kernel->size())-1;
299 debug() << "[AlephMatrixHypre::AlephMatrixCreate] jlower=" << jlower << ", jupper=" << jupper;
300
301 hypreCheck("HYPRE_IJMatrixCreate",
302 HYPRE_IJMatrixCreate(MPI_COMM_SUB,
303 ilower, iupper,
304 jlower, jupper,
305 &m_hypre_ijmatrix));
306
307 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE IJMatrixSetObjectType";
308 HYPRE_IJMatrixSetObjectType(m_hypre_ijmatrix, HYPRE_PARCSR);
309 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE IJMatrixSetRowSizes";
310 HYPRE_IJMatrixSetRowSizes(m_hypre_ijmatrix, m_kernel->topology()->gathered_nb_row_elements().data());
311 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE IJMatrixInitialize";
312 HYPRE_IJMatrixInitialize(m_hypre_ijmatrix);
313 HYPRE_IJMatrixGetObject(m_hypre_ijmatrix, &object);
314 m_hypre_parmatrix = (HYPRE_ParCSRMatrix)object;
315 }
316
317 /******************************************************************************
318 *****************************************************************************/
319 void AlephMatrixSetFilled(bool) {}
320
321 /******************************************************************************
322 *****************************************************************************/
323 int AlephMatrixAssemble(void)
324 {
325 debug() << "[AlephMatrixHypre::AlephMatrixAssemble]";
326 hypreCheck("HYPRE_IJMatrixAssemble",
327 HYPRE_IJMatrixAssemble(m_hypre_ijmatrix));
328 return 0;
329 }
330
331 /******************************************************************************
332 *****************************************************************************/
333 void AlephMatrixFill(int size, HYPRE_Int* rows, HYPRE_Int* cols, double* values)
334 {
335 debug() << "[AlephMatrixHypre::AlephMatrixFill] size=" << size;
336 HYPRE_Int rtn = 0;
337 HYPRE_Int col[1] = { 1 };
338 for (int i = 0; i < size; i++) {
339 rtn += HYPRE_IJMatrixSetValues(m_hypre_ijmatrix, 1, col, &rows[i], &cols[i], &values[i]);
340 }
341 hypreCheck("HYPRE_IJMatrixSetValues", rtn);
342 //HYPRE_IJMatrixSetValues(m_hypre_ijmatrix, nrows, ncols, rows, cols, values);
343 debug() << "[AlephMatrixHypre::AlephMatrixFill] done";
344 }
345
346 /******************************************************************************
347 * isAlreadySolved
348 *****************************************************************************/
349 bool isAlreadySolved(AlephVectorHypre* x,
351 AlephVectorHypre* tmp,
352 Real* residual_norm,
353 AlephParams* params)
354 {
355 HYPRE_ClearAllErrors();
356 const bool convergence_analyse = params->convergenceAnalyse();
357
358 // test le second membre du système linéaire
359 const Real res0 = b->norm_max();
360
361 if (convergence_analyse)
362 info() << "analyse convergence : norme max du second membre res0 : " << res0;
363
364 const Real considered_as_null = params->minRHSNorm();
365 if (res0 < considered_as_null) {
366 HYPRE_ParVectorSetConstantValues(x->m_hypre_parvector, 0.0);
367 residual_norm[0] = res0;
368 if (convergence_analyse)
369 info() << "analyse convergence : le second membre du système linéaire est inférieur à : " << considered_as_null;
370 return true;
371 }
372
373 if (params->xoUser()) {
374 // on test si b est déjà solution du système à epsilon près
375 //matrix->vectorProduct(b, tmp_vector); tmp_vector->sub(x);
376 //M->vector_multiply(*tmp,*x); // tmp=A*x
377 //tmp->substract(*tmp,*b); // tmp=A*x-b
378
379 // X= alpha* M.B + beta * X (lu dans les sources de HYPRE)
380 HYPRE_ParCSRMatrixMatvec(1.0, m_hypre_parmatrix, x->m_hypre_parvector, 0., tmp->m_hypre_parvector);
381 HYPRE_ParVectorAxpy(-1.0, b->m_hypre_parvector, tmp->m_hypre_parvector);
382
383 const Real residu = tmp->norm_max();
384 //info() << "[IAlephHypre::isAlreadySolved] residu="<<residu;
385
386 if (residu < considered_as_null) {
387 if (convergence_analyse) {
388 info() << "analyse convergence : |Ax0-b| est inférieur à " << considered_as_null;
389 info() << "analyse convergence : x0 est déjà solution du système.";
390 }
391 residual_norm[0] = residu;
392 return true;
393 }
394
395 const Real relative_error = residu / res0;
396 if (convergence_analyse)
397 info() << "analyse convergence : résidu initial : " << residu
398 << " --- residu relatif initial (residu/res0) : " << residu / res0;
399
400 if (relative_error < (params->epsilon())) {
401 if (convergence_analyse)
402 info() << "analyse convergence : X est déjà solution du système";
403 residual_norm[0] = residu;
404 return true;
405 }
406 }
407 return false;
408 }
409
410 /******************************************************************************
411 *****************************************************************************/
412 int AlephMatrixSolve(AlephVector* x,
413 AlephVector* b,
414 AlephVector* t,
415 Integer& nb_iteration,
416 Real* residual_norm,
417 AlephParams* solver_param)
418 {
419 solver_param->setAmgCoarseningMethod(TypesSolver::AMG_COARSENING_AUTO);
420 const String func_name("SolverMatrixHypre::solve");
421 void* object;
422 int ierr = 0;
423
424 auto* ximpl = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(x->implementation()));
425 auto* bimpl = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(b->implementation()));
426
427 HYPRE_IJVector solution = ximpl->m_hypre_ijvector;
428 HYPRE_IJVector RHS = bimpl->m_hypre_ijvector;
429 //HYPRE_IJVector tmp = (dynamic_cast<AlephVectorHypre*> (t->implementation()))->m_hypre_ijvector;
430
431 HYPRE_IJMatrixGetObject(m_hypre_ijmatrix, &object);
432 HYPRE_ParCSRMatrix M = (HYPRE_ParCSRMatrix)object;
433 HYPRE_IJVectorGetObject(solution, &object);
434 HYPRE_ParVector X = (HYPRE_ParVector)object;
435 HYPRE_IJVectorGetObject(RHS, &object);
436 HYPRE_ParVector B = (HYPRE_ParVector)object;
437 //HYPRE_IJVectorGetObject(tmp,&object);
438 //HYPRE_ParVector T = (HYPRE_ParVector)object;
439
440 auto* ximpl2 = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(x->implementation()));
441 auto* bimpl2 = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(b->implementation()));
442 auto* timpl2 = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(t->implementation()));
443 if (isAlreadySolved(ximpl2, bimpl2, timpl2, residual_norm, solver_param)) {
444 ItacRegion(isAlreadySolved, AlephMatrixHypre);
445 debug() << "[AlephMatrixHypre::AlephMatrixSolve] isAlreadySolved !";
446 nb_iteration = 0;
447 return 0;
448 }
449
450 TypesSolver::ePreconditionerMethod preconditioner_method = solver_param->precond();
451 // TypesSolver::ePreconditionerMethod preconditioner_method = TypesSolver::NONE;
452 TypesSolver::eSolverMethod solver_method = solver_param->method();
453
454 // déclaration et initialisation du solveur
455 HYPRE_Solver solver = 0;
456
457 switch (solver_method) {
458 case TypesSolver::PCG:
459 initSolverPCG(solver_param, solver);
460 break;
461 case TypesSolver::BiCGStab:
462 initSolverBiCGStab(solver_param, solver);
463 break;
464 case TypesSolver::GMRES:
465 initSolverGMRES(solver_param, solver);
466 break;
467 default:
468 throw ArgumentException(func_name, "solveur inconnu");
469 }
470
471 // déclaration et initialisation du preconditionneur
472 HYPRE_Solver precond = 0;
473
474 switch (preconditioner_method) {
475 case TypesSolver::NONE:
476 break;
477 case TypesSolver::DIAGONAL:
478 setDiagonalPreconditioner(solver_method, solver, precond);
479 break;
480 case TypesSolver::ILU:
481 setILUPreconditioner(solver_method, solver, precond);
482 break;
483 case TypesSolver::SPAIstat:
484 setSpaiStatPreconditioner(solver_method, solver, solver_param, precond);
485 break;
486 case TypesSolver::AMG:
487 setAMGPreconditioner(solver_method, solver, solver_param, precond);
488 break;
489 case TypesSolver::AINV:
490 throw ArgumentException(func_name, "preconditionnement AINV indisponible");
491 case TypesSolver::SPAIdyn:
492 throw ArgumentException(func_name, "preconditionnement SPAIdyn indisponible");
493 case TypesSolver::ILUp:
494 throw ArgumentException(func_name, "preconditionnement ILUp indisponible");
495 case TypesSolver::IC:
496 throw ArgumentException(func_name, "preconditionnement IC indisponible");
497 case TypesSolver::POLY:
498 throw ArgumentException(func_name, "preconditionnement POLY indisponible");
499 default:
500 throw ArgumentException(func_name, "preconditionnement inconnu");
501 }
502
503 // résolution du système algébrique
504 HYPRE_Int iteration = 0;
505 double residue = 0.0;
506
507 switch (solver_method) {
508 case TypesSolver::PCG:
509 ierr = solvePCG(solver_param, solver, M, B, X, iteration, residue);
510 break;
511 case TypesSolver::BiCGStab:
512 ierr = solveBiCGStab(solver, M, B, X, iteration, residue);
513 break;
514 case TypesSolver::GMRES:
515 ierr = solveGMRES(solver, M, B, X, iteration, residue);
516 break;
517 default:
518 ierr = -3;
519 return ierr;
520 }
521 nb_iteration = static_cast<Integer>(iteration);
522 residual_norm[0] = static_cast<Real>(residue);
523
524 /* for(int i=0;i<8;++i){
525 int idx[1];
526 double valx[1]={-1.};
527 //double valb[1]={-1.};
528 idx[0]=i;
529 HYPRE_IJVectorGetValues(solution, 1, idx, valx);
530 debug()<<"[AlephMatrixHypre::AlephMatrixSolve] X["<<i<<"]="<<valx[0];
531 //(static_cast<AlephVectorHypre*> (x->implementation()))->AlephVectorGet(valx,idx,1);
532 //debug()<<"[AlephMatrixHypre::AlephMatrixSolve] x["<<i<<"]="<<valx[0];
533 //HYPRE_IJVectorGetValues(RHS, 1, idx, valb);
534 //debug()<<"[AlephMatrixHypre::AlephMatrixSolve] B["<<i<<"]="<<valb[0];
535 }
536*/
537 switch (preconditioner_method) {
538 case TypesSolver::NONE:
539 break;
540 case TypesSolver::DIAGONAL:
541 break;
542 case TypesSolver::ILU:
543 HYPRE_ParCSRPilutDestroy(precond);
544 break;
545 case TypesSolver::SPAIstat:
546 HYPRE_ParCSRParaSailsDestroy(precond);
547 break;
548 case TypesSolver::AMG:
549 HYPRE_BoomerAMGDestroy(precond);
550 break;
551 default:
552 throw ArgumentException(func_name, "preconditionnement inconnu");
553 }
554
555 if (iteration == solver_param->maxIter() && solver_param->stopErrorStrategy()) {
556 info() << "\n============================================================";
557 info() << "\nCette erreur est retournée après " << iteration << "\n";
558 info() << "\nOn a atteind le nombre max d'itérations du solveur.";
559 info() << "\nIl est possible de demander au code de ne pas tenir compte de cette erreur.";
560 info() << "\nVoir la documentation du jeu de données concernant le service solveur.";
561 info() << "\n======================================================";
562 throw Exception("AlephMatrixHypre::Solve", "On a atteind le nombre max d'itérations du solveur");
563 }
564 return ierr;
565 }
566
567 /******************************************************************************
568 *****************************************************************************/
569 void writeToFile(const String filename)
570 {
571 HYPRE_IJMatrixPrint(m_hypre_ijmatrix, filename.localstr());
572 }
573
574 /******************************************************************************
575 *****************************************************************************/
576 void initSolverPCG(const AlephParams* solver_param, HYPRE_Solver& solver)
577 {
578 const String func_name = "SolverMatrixHypre::initSolverPCG";
579 double epsilon = solver_param->epsilon();
580 int max_it = solver_param->maxIter();
581 int output_level = solver_param->getOutputLevel();
582
583 HYPRE_ParCSRPCGCreate(MPI_COMM_SUB, &solver);
584 HYPRE_ParCSRPCGSetMaxIter(solver, max_it);
585 HYPRE_ParCSRPCGSetTol(solver, epsilon);
586 HYPRE_ParCSRPCGSetTwoNorm(solver, 1);
587 HYPRE_ParCSRPCGSetPrintLevel(solver, output_level);
588 }
589
590 /******************************************************************************
591 *****************************************************************************/
592 void initSolverBiCGStab(const AlephParams* solver_param, HYPRE_Solver& solver)
593 {
594 const String func_name = "SolverMatrixHypre::initSolverBiCGStab";
595 double epsilon = solver_param->epsilon();
596 int max_it = solver_param->maxIter();
597 int output_level = solver_param->getOutputLevel();
598
599 HYPRE_ParCSRBiCGSTABCreate(MPI_COMM_SUB, &solver);
600 HYPRE_ParCSRBiCGSTABSetMaxIter(solver, max_it);
601 HYPRE_ParCSRBiCGSTABSetTol(solver, epsilon);
602 HYPRE_ParCSRBiCGSTABSetPrintLevel(solver, output_level);
603 }
604
605 /******************************************************************************
606 *****************************************************************************/
607 void initSolverGMRES(const AlephParams* solver_param, HYPRE_Solver& solver)
608 {
609 const String func_name = "SolverMatrixHypre::initSolverGMRES";
610 double epsilon = solver_param->epsilon();
611 int max_it = solver_param->maxIter();
612 int output_level = solver_param->getOutputLevel();
613
614 HYPRE_ParCSRGMRESCreate(MPI_COMM_SUB, &solver);
615 const int krylov_dim = 20; // dimension de l'espace de Krylov pour GMRES
616 HYPRE_ParCSRGMRESSetKDim(solver, krylov_dim);
617 HYPRE_ParCSRGMRESSetMaxIter(solver, max_it);
618 HYPRE_ParCSRGMRESSetTol(solver, epsilon);
619 HYPRE_ParCSRGMRESSetPrintLevel(solver, output_level);
620 }
621
622 /******************************************************************************
623 *****************************************************************************/
624 void setDiagonalPreconditioner(const TypesSolver::eSolverMethod solver_method,
625 const HYPRE_Solver& solver,
626 HYPRE_Solver& precond)
627 {
628 const String func_name = "SolverMatrixHypre::setDiagonalPreconditioner";
629 switch (solver_method) {
630 case TypesSolver::PCG:
631 HYPRE_ParCSRPCGSetPrecond(solver,
632 HYPRE_ParCSRDiagScale,
633 HYPRE_ParCSRDiagScaleSetup,
634 precond);
635 break;
636 case TypesSolver::BiCGStab:
637 HYPRE_ParCSRBiCGSTABSetPrecond(solver,
638 HYPRE_ParCSRDiagScale,
639 HYPRE_ParCSRDiagScaleSetup,
640 precond);
641 break;
642 case TypesSolver::GMRES:
643 HYPRE_ParCSRGMRESSetPrecond(solver,
644 HYPRE_ParCSRDiagScale,
645 HYPRE_ParCSRDiagScaleSetup,
646 precond);
647 break;
648 default:
649 throw ArgumentException(func_name, "solveur inconnu pour le préconditionneur 'Diagonal'");
650 }
651 }
652
653 /******************************************************************************
654 *****************************************************************************/
655 void setILUPreconditioner(const TypesSolver::eSolverMethod solver_method,
656 const HYPRE_Solver& solver,
657 HYPRE_Solver& precond)
658 {
659 const String func_name = "SolverMatrixHypre::setILUPreconditioner";
660 switch (solver_method) {
661 case TypesSolver::PCG:
662 throw ArgumentException(func_name, "solveur PCG indisponible avec le préconditionneur 'ILU'");
663 break;
664 case TypesSolver::BiCGStab:
665 HYPRE_ParCSRPilutCreate(MPI_COMM_SUB, &precond);
666 HYPRE_ParCSRBiCGSTABSetPrecond(solver,
667 HYPRE_ParCSRPilutSolve,
668 HYPRE_ParCSRPilutSetup,
669 precond);
670 break;
671 case TypesSolver::GMRES:
672 HYPRE_ParCSRPilutCreate(MPI_COMM_SUB,
673 &precond);
674 HYPRE_ParCSRGMRESSetPrecond(solver,
675 HYPRE_ParCSRPilutSolve,
676 HYPRE_ParCSRPilutSetup,
677 precond);
678 break;
679 default:
680 throw ArgumentException(func_name, "solveur inconnu pour le préconditionneur ILU\n");
681 }
682 }
683
684 /******************************************************************************
685 *****************************************************************************/
686 void setSpaiStatPreconditioner(const TypesSolver::eSolverMethod solver_method,
687 const HYPRE_Solver& solver,
688 const AlephParams* solver_param,
689 HYPRE_Solver& precond)
690 {
691 HYPRE_ParCSRParaSailsCreate(MPI_COMM_SUB, &precond);
692 double alpha = solver_param->alpha();
693 int gamma = solver_param->gamma();
694 if (alpha < 0.0)
695 alpha = 0.1; // valeur par défaut pour le paramètre de tolérance
696 if (gamma == -1)
697 gamma = 1; // valeur par défaut pour le paramètre de remplissage
698 HYPRE_ParCSRParaSailsSetParams(precond, alpha, gamma);
699 switch (solver_method) {
700 case TypesSolver::PCG:
701 HYPRE_ParCSRPCGSetPrecond(solver, HYPRE_ParCSRParaSailsSolve, HYPRE_ParCSRParaSailsSetup, precond);
702 break;
703 case TypesSolver::BiCGStab:
704 throw ArgumentException("AlephMatrixHypre::setSpaiStatPreconditioner", "solveur 'BiCGStab' invalide pour préconditionnement 'SPAIstat'");
705 break;
706 case TypesSolver::GMRES:
707 // matrice non symétrique
708 HYPRE_ParCSRParaSailsSetSym(precond, 0);
709 HYPRE_ParCSRGMRESSetPrecond(solver, HYPRE_ParaSailsSolve, HYPRE_ParaSailsSetup, precond);
710 break;
711 default:
712 throw ArgumentException("AlephMatrixHypre::setSpaiStatPreconditioner", "solveur inconnu pour le préconditionneur 'SPAIstat'\n");
713 break;
714 }
715 }
716
717 /******************************************************************************
718 *****************************************************************************/
719 void setAMGPreconditioner(const TypesSolver::eSolverMethod solver_method,
720 const HYPRE_Solver& solver,
721 const AlephParams* solver_param,
722 HYPRE_Solver& precond)
723 {
724 // valeurs par défaut pour BoomerAMG à partir de l'exemple hypre -- lc
725 // TODO : les options et les valeurs par défaut doivent être complétées
726 double trunc_factor = 0.1; // définir le facteur de troncature d'interpolation AMG = val
727 int cycle_type = solver_param->getAmgCycle(); // définir les cycles AMG (1=V, 2=W, etc.)
728 int coarsen_type = solver_param->amgCoarseningMethod();
729 // Raffinement Ruge (local) si <val> == 1
730 int relax_default = 3; // type de relaxation <val> :
731 // 0=Jacobi pondéré
732 // 1=Gauss-Seidel (très lent!)
733 // 3=Jacobi/Gauss-Seidel hybride
734 int num_sweep = 1; // Utilise <val> balayages à chaque niveau (ici 1)
735 int hybrid = 1; // pas de changement dans le raffinement si -1
736 int measure_type = 1; // utilise des mesures globales
737 double max_row_sum = 1.0; // définis le seuil de somme de ligne maximale AMG pour l'affaiblissement des dépendances
738
739 int max_levels = 50; // 25; // nombre maximum de niveaux AMG
740 const int gamma = solver_param->gamma();
741 if (gamma != -1)
742 max_levels = gamma; // utilise la valeur du jeu de données
743
744 double strong_threshold = 0.1; // 0.25; // définis le seuil AMG Theta = val
745 const double alpha = solver_param->alpha();
746 if (alpha > 0.0)
747 strong_threshold = alpha; // utilise la valeur du jeu de données
748 // nouveauté
749 Integer output_level = solver_param->getOutputLevel();
750
751 HYPRE_Int* num_grid_sweeps = _allocHypre<HYPRE_Int>(4);
752 HYPRE_Int* grid_relax_type = _allocHypre<HYPRE_Int>(4);
753 HYPRE_Int** grid_relax_points = _allocHypre<HYPRE_Int*>(4);
754 double* relax_weight = _allocHypre<double>(max_levels);
755
756 for (int i = 0; i < max_levels; i++)
757 relax_weight[i] = 1.0;
758
759 if (coarsen_type == 5) {
760 /* grille fine */
761 num_grid_sweeps[0] = 3;
762 grid_relax_type[0] = relax_default;
763 grid_relax_points[0] = _allocHypre<HYPRE_Int>(3);
764 grid_relax_points[0][0] = -2;
765 grid_relax_points[0][1] = -1;
766 grid_relax_points[0][2] = 1;
767
768 /* cycle descendant */
769 num_grid_sweeps[1] = 4;
770 grid_relax_type[1] = relax_default;
771 grid_relax_points[1] = _callocHypre<HYPRE_Int>(4);
772 grid_relax_points[1][0] = -1;
773 grid_relax_points[1][1] = 1;
774 grid_relax_points[1][2] = -2;
775 grid_relax_points[1][3] = -2;
776
777 /* cycle ascendant */
778 num_grid_sweeps[2] = 4;
779 grid_relax_type[2] = relax_default;
780 grid_relax_points[2] = _allocHypre<HYPRE_Int>(4);
781 grid_relax_points[2][0] = -2;
782 grid_relax_points[2][1] = -2;
783 grid_relax_points[2][2] = 1;
784 grid_relax_points[2][3] = -1;
785 }
786 else {
787 /* grille fine */
788 num_grid_sweeps[0] = 2 * num_sweep;
789 grid_relax_type[0] = relax_default;
790 grid_relax_points[0] = _allocHypre<HYPRE_Int>(2 * num_sweep);
791 for (int i = 0; i < 2 * num_sweep; i += 2) {
792 grid_relax_points[0][i] = -1;
793 grid_relax_points[0][i + 1] = 1;
794 }
795
796 /* cycle descendant */
797 num_grid_sweeps[1] = 2 * num_sweep;
798 grid_relax_type[1] = relax_default;
799 grid_relax_points[1] = _allocHypre<HYPRE_Int>(2 * num_sweep);
800 for (int i = 0; i < 2 * num_sweep; i += 2) {
801 grid_relax_points[1][i] = -1;
802 grid_relax_points[1][i + 1] = 1;
803 }
804
805 /* cycle ascendant */
806 num_grid_sweeps[2] = 2 * num_sweep;
807 grid_relax_type[2] = relax_default;
808 grid_relax_points[2] = _allocHypre<HYPRE_Int>(2 * num_sweep);
809 for (int i = 0; i < 2 * num_sweep; i += 2) {
810 grid_relax_points[2][i] = -1;
811 grid_relax_points[2][i + 1] = 1;
812 }
813 }
814
815 /* grille la plus grossière */
816 num_grid_sweeps[3] = 1;
817 grid_relax_type[3] = 9;
818 grid_relax_points[3] = _allocHypre<HYPRE_Int>(1);
819 grid_relax_points[3][0] = 0;
820
821 // fin des paramètres par défaut
822
823 HYPRE_BoomerAMGCreate(&precond);
824 HYPRE_BoomerAMGSetPrintLevel(precond, output_level);
825 HYPRE_BoomerAMGSetCoarsenType(precond, (hybrid * coarsen_type));
826 HYPRE_BoomerAMGSetMeasureType(precond, measure_type);
827 HYPRE_BoomerAMGSetStrongThreshold(precond, strong_threshold);
828 HYPRE_BoomerAMGSetTruncFactor(precond, trunc_factor);
829 HYPRE_BoomerAMGSetMaxIter(precond, 1);
830 HYPRE_BoomerAMGSetCycleType(precond, cycle_type);
831 HYPRE_BoomerAMGSetNumGridSweeps(precond, num_grid_sweeps);
832 HYPRE_BoomerAMGSetGridRelaxType(precond, grid_relax_type);
833 HYPRE_BoomerAMGSetRelaxWeight(precond, relax_weight);
834 HYPRE_BoomerAMGSetGridRelaxPoints(precond, grid_relax_points);
835 HYPRE_BoomerAMGSetTol(precond, 0.0);
836 HYPRE_BoomerAMGSetMaxLevels(precond, max_levels);
837 HYPRE_BoomerAMGSetMaxRowSum(precond, max_row_sum);
838
839 switch (solver_method) {
840 case TypesSolver::PCG:
841 HYPRE_ParCSRPCGSetPrecond(solver,
842 HYPRE_BoomerAMGSolve,
843 HYPRE_BoomerAMGSetup,
844 precond);
845 break;
846 case TypesSolver::BiCGStab:
847 HYPRE_ParCSRBiCGSTABSetPrecond(solver,
848 HYPRE_BoomerAMGSolve,
849 HYPRE_BoomerAMGSetup,
850 precond);
851 break;
852 case TypesSolver::GMRES:
853 HYPRE_ParCSRGMRESSetPrecond(solver,
854 HYPRE_BoomerAMGSolve,
855 HYPRE_BoomerAMGSetup,
856 precond);
857 break;
858 default:
859 throw ArgumentException("AlephMatrixHypre::setAMGPreconditioner", "solveur inconnu pour préconditionnement 'AMG'\n");
860 }
861 }
862
863 /******************************************************************************
864 *****************************************************************************/
865 bool solvePCG(const AlephParams* solver_param,
866 HYPRE_Solver& solver,
867 HYPRE_ParCSRMatrix& M,
868 HYPRE_ParVector& B,
869 HYPRE_ParVector& X,
870 HYPRE_Int& iteration,
871 double& residue)
872 {
873 const String func_name = "SolverMatrixHypre::solvePCG";
874 const bool xo = solver_param->xoUser();
875 bool error = false;
876
877 if (!xo)
878 HYPRE_ParVectorSetConstantValues(X, 0.0);
879 HYPRE_ParCSRPCGSetup(solver, M, B, X);
880 HYPRE_ParCSRPCGSolve(solver, M, B, X);
881 HYPRE_ParCSRPCGGetNumIterations(solver, &iteration);
882 HYPRE_ParCSRPCGGetFinalRelativeResidualNorm(solver, &residue);
883
884 HYPRE_Int converged = 0;
885 HYPRE_PCGGetConverged(solver, &converged);
886 error |= (!converged);
887
888 HYPRE_ParCSRPCGDestroy(solver);
889
890 return !error;
891 }
892
893 /******************************************************************************
894 *****************************************************************************/
895 bool solveBiCGStab(HYPRE_Solver& solver,
896 HYPRE_ParCSRMatrix& M,
897 HYPRE_ParVector& B,
898 HYPRE_ParVector& X,
899 HYPRE_Int& iteration,
900 double& residue)
901 {
902 const String func_name = "SolverMatrixHypre::solveBiCGStab";
903 bool error = false;
904 HYPRE_ParVectorSetRandomValues(X, 775);
905 HYPRE_ParCSRBiCGSTABSetup(solver, M, B, X);
906 HYPRE_ParCSRBiCGSTABSolve(solver, M, B, X);
907 HYPRE_ParCSRBiCGSTABGetNumIterations(solver, &iteration);
908 HYPRE_ParCSRBiCGSTABGetFinalRelativeResidualNorm(solver, &residue);
909
910 HYPRE_Int converged = 0;
911 hypre_BiCGSTABGetConverged(solver, &converged);
912 error |= (!converged);
913
914 HYPRE_ParCSRBiCGSTABDestroy(solver);
915
916 return !error;
917 }
918
919 /******************************************************************************
920 *****************************************************************************/
921 bool solveGMRES(HYPRE_Solver& solver,
922 HYPRE_ParCSRMatrix& M,
923 HYPRE_ParVector& B,
924 HYPRE_ParVector& X,
925 HYPRE_Int& iteration,
926 double& residue)
927 {
928 const String func_name = "SolverMatrixHypre::solveGMRES";
929 bool error = false;
930 HYPRE_ParCSRGMRESSetup(solver, M, B, X);
931 HYPRE_ParCSRGMRESSolve(solver, M, B, X);
932 HYPRE_ParCSRGMRESGetNumIterations(solver, &iteration);
933 HYPRE_ParCSRGMRESGetFinalRelativeResidualNorm(solver, &residue);
934
935 HYPRE_Int converged = 0;
936 HYPRE_GMRESGetConverged(solver, &converged);
937 error |= (!converged);
938
939 HYPRE_ParCSRGMRESDestroy(solver);
940 return !error;
941 }
942
943 private:
944
945 HYPRE_IJMatrix m_hypre_ijmatrix = nullptr;
946 HYPRE_ParCSRMatrix m_hypre_parmatrix = nullptr;
947};
948
949/*---------------------------------------------------------------------------*/
950/*---------------------------------------------------------------------------*/
951
952class HypreAlephFactoryImpl
953: public AbstractService
954, public IAlephFactoryImpl
955{
956 public:
957
958 HypreAlephFactoryImpl(const ServiceBuildInfo& sbi)
959 : AbstractService(sbi)
960 {}
961 ~HypreAlephFactoryImpl()
962 {
963 for (auto* v : m_IAlephVectors)
964 delete v;
965 for (auto* v : m_IAlephMatrixs)
966 delete v;
967 }
968
969 public:
970
971 void initialize() override
972 {
973 // NOTE : À partir de 2.29, nous pouvons utiliser
974 // HYPRE_Initialize() et tester si l'initialisation
975 // a déjà été effectuée via HYPRE_Initialized().
976#if HYPRE_RELEASE_NUMBER >= 22900
977 if (!HYPRE_Initialized()) {
978 info() << "Initialisation de HYPRE";
979 HYPRE_Initialize();
980 }
981#elif HYPRE_RELEASE_NUMBER >= 22700
982 info() << "Initialisation de HYPRE";
983 HYPRE_Init();
984#endif
985
986#if HYPRE_RELEASE_NUMBER >= 22700
987 HYPRE_SetMemoryLocation(HYPRE_MEMORY_HOST);
988 HYPRE_SetExecutionPolicy(HYPRE_EXEC_HOST);
989#endif
990 }
991
992 IAlephTopology* createTopology(ITraceMng* tm,
993 AlephKernel* kernel,
994 Integer index,
995 Integer nb_row_size) override
996 {
997 ARCANE_UNUSED(tm);
998 ARCANE_UNUSED(kernel);
999 ARCANE_UNUSED(index);
1000 ARCANE_UNUSED(nb_row_size);
1001 return NULL;
1002 }
1003
1004 IAlephVector* createVector(ITraceMng* tm,
1005 AlephKernel* kernel,
1006 Integer index) override
1007 {
1008 IAlephVector* new_vector = new AlephVectorHypre(tm, kernel, index);
1009 m_IAlephVectors.add(new_vector);
1010 return new_vector;
1011 }
1012
1013 IAlephMatrix* createMatrix(ITraceMng* tm,
1014 AlephKernel* kernel,
1015 Integer index) override
1016 {
1017 IAlephMatrix* new_matrix = new AlephMatrixHypre(tm, kernel, index);
1018 m_IAlephMatrixs.add(new_matrix);
1019 return new_matrix;
1020 }
1021
1022 private:
1023
1024 UniqueArray<IAlephVector*> m_IAlephVectors;
1025 UniqueArray<IAlephMatrix*> m_IAlephMatrixs;
1026};
1027
1028/*---------------------------------------------------------------------------*/
1029/*---------------------------------------------------------------------------*/
1030
1032
1033/*---------------------------------------------------------------------------*/
1034/*---------------------------------------------------------------------------*/
1035
1036} // namespace Arcane
1037
1038/*---------------------------------------------------------------------------*/
1039/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCANE_REGISTER_APPLICATION_FACTORY(aclass, ainterface, aname)
Enregistre un service de fabrique pour la classe aclass.
AbstractService(const ServiceBuildInfo &)
Constructeur à partir d'un ServiceBuildInfo.
Paramètres d'un système linéraire.
Definition AlephParams.h:34
Vecteur d'un système linéaire.
Definition AlephVector.h:33
Exception lorsqu'un argument est invalide.
const T * data() const
Accès à la racine du tableau hors toute protection.
Classe de base d'une exception.
Interface d'une fabrique d'implémentation pour Aleph.
Interface du gestionnaire de traces.
Structure contenant les informations pour créer un service.
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:228
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage error() const
Flot pour un message d'erreur.
Vecteur 1D de données avec sémantique par valeur (style STL).
@ ReduceMax
Maximum des valeurs.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Int32 Integer
Type représentant un entier.
double Real
Type représentant un réel.
int AlephInt
Type par défaut pour indexer les lignes et les colonnes des matrices et vecteurs.
Definition AlephGlobal.h:50