Arcane  v3.15.3.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-2025 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#include <krylov.h>
27
28#ifndef ItacRegion
29#define ItacRegion(a, x)
30#endif
31
32#include "arcane/aleph/AlephArcane.h"
33
34// Le type HYPRE_BigInt n'existe qu'à partir de Hypre 2.16.0
35#if HYPRE_RELEASE_NUMBER < 21600
36using HYPRE_BigInt = HYPRE_Int;
37#endif
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
42namespace Arcane
43{
44
45/*---------------------------------------------------------------------------*/
46/*---------------------------------------------------------------------------*/
47
48/*
49 * NOTE: A partir de la version 2.14 de hypre (peut-être un peu avant),
50 * hypre_TAlloc() et hypre_CAlloc() prennent un 3ème argument qui est
51 * sur quel peripherique on alloue la mémoire (GPU ou CPU). Il n'y a pas
52 * de moyens simples de savoir quelle est la version de hypre à partir
53 * des .h mais par contre HYPRE_MEMORY_DEVICE et HYPRE_MEMORY_HOST sont
54 * des macros donc on peut tester leur existance pour savoir s'il faut
55 * appeler les méthodes hypre_TAlloc() et hypre_CAlloc() avec 2 ou 3 arguments.
56 */
57namespace
58{
59inline void
60check(const char* hypre_func, HYPRE_Int error_code)
61{
62 if (error_code == 0)
63 return;
64 char buf[8192];
65 HYPRE_DescribeError(error_code, buf);
66 cout << "\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
67 << "\nHYPRE ERROR in function "
68 << hypre_func
69 << "\nError_code=" << error_code
70 << "\nMessage=" << buf
71 << "\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
72 << "\n"
73 << std::flush;
74 throw Exception("HYPRE Check", hypre_func);
75}
76
77template <typename T>
78inline T*
79_allocHypre(Integer size)
80{
81 size_t s = sizeof(T) * size;
82 return reinterpret_cast<T*>(hypre_TAlloc(char, s, HYPRE_MEMORY_HOST));
83}
84
85template <typename T>
86inline T*
87_callocHypre(Integer size)
88{
89 size_t s = sizeof(T) * size;
90 return reinterpret_cast<T*>(hypre_CTAlloc(char, s, HYPRE_MEMORY_HOST));
91}
92
93inline void
94hypreCheck(const char* hypre_func, HYPRE_Int error_code)
95{
96 check(hypre_func, error_code);
97 HYPRE_Int r = HYPRE_GetError();
98 if (r != 0)
99 cout << "HYPRE GET ERROR r=" << r
100 << " error_code=" << error_code << " func=" << hypre_func << '\n';
101}
102
103} // namespace
104
105/******************************************************************************
106 AlephVectorHypre
107 *****************************************************************************/
109: public IAlephVector
110{
111 public:
112 AlephVectorHypre(ITraceMng* tm, AlephKernel* kernel, Integer index)
113 : IAlephVector(tm, kernel, index)
114 , jSize(0)
115 , jUpper(0)
116 , jLower(-1)
117 {
118 debug() << "[AlephVectorHypre::AlephVectorHypre] new SolverVectorHypre";
119 }
121 {
122 if (m_hypre_ijvector)
123 HYPRE_IJVectorDestroy(m_hypre_ijvector);
124 }
125
126 public:
127
128 /******************************************************************************
129 * The Create() routine creates an empty vector object that lives on the comm communicator. This is
130 * a collective call, with each process passing its own index extents, jLower and jupper. The names
131 * of these extent parameters begin with a j because we typically think of matrix-vector multiplies
132 * as the fundamental operation involving both matrices and vectors. For matrix-vector multiplies,
133 * the vector partitioning should match the column partitioning of the matrix (which also uses the j
134 * notation). For linear system solves, these extents will typically match the row partitioning of the
135 * matrix as well.
136 *****************************************************************************/
137 void AlephVectorCreate(void)
138 {
139 debug() << "[AlephVectorHypre::AlephVectorCreate] HYPRE VectorCreate";
140 void* object;
141
142 for (int iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
143 if (m_kernel->rank() != m_kernel->solverRanks(m_index)[iCpu])
144 continue;
145 debug() << "[AlephVectorHypre::AlephVectorCreate] adding contibution of core #" << iCpu;
146 if (jLower == -1)
147 jLower = m_kernel->topology()->gathered_nb_row(iCpu);
148 jUpper = m_kernel->topology()->gathered_nb_row(iCpu + 1) - 1;
149 }
150
151 debug() << "[AlephVectorHypre::AlephVectorCreate] jLower=" << jLower << ", jupper=" << jUpper;
152 // Mise à jour de la taille locale du buffer pour le calcul plus tard de la norme max, par exemple
153 jSize = jUpper - jLower + 1;
154
155 hypreCheck("IJVectorCreate",
156 HYPRE_IJVectorCreate(MPI_COMM_SUB,
157 jLower,
158 jUpper,
159 &m_hypre_ijvector));
160
161 debug() << "[AlephVectorHypre::AlephVectorCreate] HYPRE IJVectorSetObjectType";
162 hypreCheck("IJVectorSetObjectType", HYPRE_IJVectorSetObjectType(m_hypre_ijvector, HYPRE_PARCSR));
163
164 debug() << "[AlephVectorHypre::AlephVectorCreate] HYPRE IJVectorInitialize";
165 hypreCheck("HYPRE_IJVectorInitialize", HYPRE_IJVectorInitialize(m_hypre_ijvector));
166
167 HYPRE_IJVectorGetObject(m_hypre_ijvector, &object);
168 m_hypre_parvector = (HYPRE_ParVector)object;
169 debug() << "[AlephVectorHypre::AlephVectorCreate] done";
170 }
171
172 /******************************************************************************
173 *****************************************************************************/
174 void AlephVectorSet(const double* bfr_val, const AlephInt* bfr_idx, Integer size)
175 {
176 debug() << "[AlephVectorHypre::AlephVectorSet] size=" << size;
177 hypreCheck("IJVectorSetValues", HYPRE_IJVectorSetValues(m_hypre_ijvector, size, bfr_idx, bfr_val));
178 }
179
180 /******************************************************************************
181 *****************************************************************************/
182 int AlephVectorAssemble(void)
183 {
184 debug() << "[AlephVectorHypre::AlephVectorAssemble]";
185 hypreCheck("IJVectorAssemble", HYPRE_IJVectorAssemble(m_hypre_ijvector));
186 return 0;
187 }
188
189 /******************************************************************************
190 *****************************************************************************/
191 void AlephVectorGet(double* bfr_val, const AlephInt* bfr_idx, Integer size)
192 {
193 //HYPRE_Int* hypre_bfr_idx = static
194 debug() << "[AlephVectorHypre::AlephVectorGet] size=" << size;
195 hypreCheck("HYPRE_IJVectorGetValues", HYPRE_IJVectorGetValues(m_hypre_ijvector, size, bfr_idx, bfr_val));
196 }
197
198 /******************************************************************************
199 * norm_max
200 *****************************************************************************/
201 Real norm_max()
202 {
203 Real normInf = 0.0;
206
207 for (HYPRE_Int i = 0; i < jSize; ++i)
208 bfr_idx[i] = jLower + i;
209
210 hypreCheck("HYPRE_IJVectorGetValues", HYPRE_IJVectorGetValues(m_hypre_ijvector, jSize, bfr_idx.data(), bfr_val.data()));
211 for (HYPRE_Int i = 0; i < jSize; ++i) {
212 const Real abs_val = math::abs(bfr_val[i]);
213 if (abs_val > normInf)
214 normInf = abs_val;
215 }
216 normInf = m_kernel->subParallelMng(m_index)->reduce(Parallel::ReduceMax, normInf);
217 return normInf;
218 }
219
220 /******************************************************************************
221 *****************************************************************************/
222 void writeToFile(const String filename)
223 {
224 String filename_idx = filename; // + "_" + (int)m_kernel->subDomain()->commonVariables().globalIteration();
225 debug() << "[AlephVectorHypre::writeToFile]";
226 hypreCheck("HYPRE_IJVectorPrint",
227 HYPRE_IJVectorPrint(m_hypre_ijvector, filename_idx.localstr()));
228 }
229
230 public:
231 HYPRE_IJVector m_hypre_ijvector = nullptr;
232 HYPRE_ParVector m_hypre_parvector = nullptr;
233 HYPRE_Int jSize;
234 HYPRE_Int jUpper;
235 HYPRE_Int jLower;
236};
237
238/******************************************************************************
239 AlephMatrixHypre
240*****************************************************************************/
242: public IAlephMatrix
243{
244 public:
245 /******************************************************************************
246 AlephMatrixHypre
247 *****************************************************************************/
248 AlephMatrixHypre(ITraceMng* tm, AlephKernel* kernel, Integer index)
249 : IAlephMatrix(tm, kernel, index)
250 , m_hypre_ijmatrix(0)
251 {
252 debug() << "[AlephMatrixHypre] new AlephMatrixHypre";
253 }
254
256 {
257 debug() << "[~AlephMatrixHypre]";
258 if (m_hypre_ijmatrix)
259 HYPRE_IJMatrixDestroy(m_hypre_ijmatrix);
260 }
261
262 public:
263 /******************************************************************************
264 * Each submatrix Ap is "owned" by a single process and its first and last row numbers are
265 * given by the global indices ilower and iupper in the Create() call below.
266 *******************************************************************************
267 * The Create() routine creates an empty matrix object that lives on the comm communicator. This
268 * is a collective call (i.e., must be called on all processes from a common synchronization point),
269 * with each process passing its own row extents, ilower and iupper. The row partitioning must be
270 * contiguous, i.e., iupper for process i must equal ilower-1 for process i+1. Note that this allows
271 * matrices to have 0- or 1-based indexing. The parameters jlower and jupper define a column
272 * partitioning, and should match ilower and iupper when solving square linear systems.
273 *****************************************************************************/
274 void AlephMatrixCreate(void)
275 {
276 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE MatrixCreate idx:" << m_index;
277 void* object;
278 AlephInt ilower = -1;
279 AlephInt iupper = 0;
280 for (int iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
281 if (m_kernel->rank() != m_kernel->solverRanks(m_index)[iCpu])
282 continue;
283 if (ilower == -1)
284 ilower = m_kernel->topology()->gathered_nb_row(iCpu);
285 iupper = m_kernel->topology()->gathered_nb_row(iCpu + 1) - 1;
286 }
287 debug() << "[AlephMatrixHypre::AlephMatrixCreate] ilower=" << ilower << ", iupper=" << iupper;
288
289 AlephInt jlower = ilower; //0;
290 AlephInt jupper = iupper; //m_kernel->topology()->gathered_nb_row(m_kernel->size())-1;
291 debug() << "[AlephMatrixHypre::AlephMatrixCreate] jlower=" << jlower << ", jupper=" << jupper;
292
293 hypreCheck("HYPRE_IJMatrixCreate",
294 HYPRE_IJMatrixCreate(MPI_COMM_SUB,
295 ilower, iupper,
296 jlower, jupper,
297 &m_hypre_ijmatrix));
298
299 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE IJMatrixSetObjectType";
300 HYPRE_IJMatrixSetObjectType(m_hypre_ijmatrix, HYPRE_PARCSR);
301 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE IJMatrixSetRowSizes";
302 HYPRE_IJMatrixSetRowSizes(m_hypre_ijmatrix, m_kernel->topology()->gathered_nb_row_elements().data());
303 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE IJMatrixInitialize";
304 HYPRE_IJMatrixInitialize(m_hypre_ijmatrix);
305 HYPRE_IJMatrixGetObject(m_hypre_ijmatrix, &object);
306 m_hypre_parmatrix = (HYPRE_ParCSRMatrix)object;
307 }
308
309 /******************************************************************************
310 *****************************************************************************/
311 void AlephMatrixSetFilled(bool) {}
312
313 /******************************************************************************
314 *****************************************************************************/
315 int AlephMatrixAssemble(void)
316 {
317 debug() << "[AlephMatrixHypre::AlephMatrixAssemble]";
318 hypreCheck("HYPRE_IJMatrixAssemble",
319 HYPRE_IJMatrixAssemble(m_hypre_ijmatrix));
320 return 0;
321 }
322
323 /******************************************************************************
324 *****************************************************************************/
325 void AlephMatrixFill(int size, HYPRE_Int* rows, HYPRE_Int* cols, double* values)
326 {
327 debug() << "[AlephMatrixHypre::AlephMatrixFill] size=" << size;
328 HYPRE_Int rtn = 0;
329 HYPRE_Int col[1] = { 1 };
330 for (int i = 0; i < size; i++) {
331 rtn += HYPRE_IJMatrixSetValues(m_hypre_ijmatrix, 1, col, &rows[i], &cols[i], &values[i]);
332 }
333 hypreCheck("HYPRE_IJMatrixSetValues", rtn);
334 //HYPRE_IJMatrixSetValues(m_hypre_ijmatrix, nrows, ncols, rows, cols, values);
335 debug() << "[AlephMatrixHypre::AlephMatrixFill] done";
336 }
337
338 /******************************************************************************
339 * isAlreadySolved
340 *****************************************************************************/
341 bool isAlreadySolved(AlephVectorHypre* x,
344 Real* residual_norm,
345 AlephParams* params)
346 {
348 const bool convergence_analyse = params->convergenceAnalyse();
349
350 // test le second membre du système linéaire
351 const Real res0 = b->norm_max();
352
354 info() << "analyse convergence : norme max du second membre res0 : " << res0;
355
356 const Real considered_as_null = params->minRHSNorm();
357 if (res0 < considered_as_null) {
358 HYPRE_ParVectorSetConstantValues(x->m_hypre_parvector, 0.0);
359 residual_norm[0] = res0;
361 info() << "analyse convergence : le second membre du système linéaire est inférieur à : " << considered_as_null;
362 return true;
363 }
364
365 if (params->xoUser()) {
366 // on test si b est déjà solution du système à epsilon près
367 //matrix->vectorProduct(b, tmp_vector); tmp_vector->sub(x);
368 //M->vector_multiply(*tmp,*x); // tmp=A*x
369 //tmp->substract(*tmp,*b); // tmp=A*x-b
370
371 // X= alpha* M.B + beta * X (lu dans les sources de HYPRE)
372 HYPRE_ParCSRMatrixMatvec(1.0, m_hypre_parmatrix, x->m_hypre_parvector, 0., tmp->m_hypre_parvector);
373 HYPRE_ParVectorAxpy(-1.0, b->m_hypre_parvector, tmp->m_hypre_parvector);
374
375 const Real residu = tmp->norm_max();
376 //info() << "[IAlephHypre::isAlreadySolved] residu="<<residu;
377
380 info() << "analyse convergence : |Ax0-b| est inférieur à " << considered_as_null;
381 info() << "analyse convergence : x0 est déjà solution du système.";
382 }
384 return true;
385 }
386
387 const Real relative_error = residu / res0;
389 info() << "analyse convergence : résidu initial : " << residu
390 << " --- residu relatif initial (residu/res0) : " << residu / res0;
391
392 if (relative_error < (params->epsilon())) {
394 info() << "analyse convergence : X est déjà solution du système";
396 return true;
397 }
398 }
399 return false;
400 }
401
402 /******************************************************************************
403 *****************************************************************************/
404 int AlephMatrixSolve(AlephVector* x,
405 AlephVector* b,
406 AlephVector* t,
407 Integer& nb_iteration,
408 Real* residual_norm,
410 {
411 solver_param->setAmgCoarseningMethod(TypesSolver::AMG_COARSENING_AUTO);
412 const String func_name("SolverMatrixHypre::solve");
413 void* object;
414 int ierr = 0;
415
416 auto* ximpl = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(x->implementation()));
417 auto* bimpl = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(b->implementation()));
418
419 HYPRE_IJVector solution = ximpl->m_hypre_ijvector;
420 HYPRE_IJVector RHS = bimpl->m_hypre_ijvector;
421 //HYPRE_IJVector tmp = (dynamic_cast<AlephVectorHypre*> (t->implementation()))->m_hypre_ijvector;
422
423 HYPRE_IJMatrixGetObject(m_hypre_ijmatrix, &object);
429 //HYPRE_IJVectorGetObject(tmp,&object);
430 //HYPRE_ParVector T = (HYPRE_ParVector)object;
431
432 auto* ximpl2 = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(x->implementation()));
433 auto* bimpl2 = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(b->implementation()));
434 auto* timpl2 = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(t->implementation()));
435 if (isAlreadySolved(ximpl2, bimpl2, timpl2, residual_norm, solver_param)) {
436 ItacRegion(isAlreadySolved, AlephMatrixHypre);
437 debug() << "[AlephMatrixHypre::AlephMatrixSolve] isAlreadySolved !";
438 nb_iteration = 0;
439 return 0;
440 }
441
442 TypesSolver::ePreconditionerMethod preconditioner_method = solver_param->precond();
443 // TypesSolver::ePreconditionerMethod preconditioner_method = TypesSolver::NONE;
444 TypesSolver::eSolverMethod solver_method = solver_param->method();
445
446 // déclaration et initialisation du solveur
448
449 switch (solver_method) {
450 case TypesSolver::PCG:
451 initSolverPCG(solver_param, solver);
452 break;
453 case TypesSolver::BiCGStab:
454 initSolverBiCGStab(solver_param, solver);
455 break;
456 case TypesSolver::GMRES:
457 initSolverGMRES(solver_param, solver);
458 break;
459 default:
460 throw ArgumentException(func_name, "solveur inconnu");
461 }
462
463 // déclaration et initialisation du preconditionneur
464 HYPRE_Solver precond = 0;
465
466 switch (preconditioner_method) {
467 case TypesSolver::NONE:
468 break;
469 case TypesSolver::DIAGONAL:
470 setDiagonalPreconditioner(solver_method, solver, precond);
471 break;
472 case TypesSolver::ILU:
473 setILUPreconditioner(solver_method, solver, precond);
474 break;
475 case TypesSolver::SPAIstat:
476 setSpaiStatPreconditioner(solver_method, solver, solver_param, precond);
477 break;
478 case TypesSolver::AMG:
479 setAMGPreconditioner(solver_method, solver, solver_param, precond);
480 break;
481 case TypesSolver::AINV:
482 throw ArgumentException(func_name, "preconditionnement AINV indisponible");
483 case TypesSolver::SPAIdyn:
484 throw ArgumentException(func_name, "preconditionnement SPAIdyn indisponible");
485 case TypesSolver::ILUp:
486 throw ArgumentException(func_name, "preconditionnement ILUp indisponible");
487 case TypesSolver::IC:
488 throw ArgumentException(func_name, "preconditionnement IC indisponible");
489 case TypesSolver::POLY:
490 throw ArgumentException(func_name, "preconditionnement POLY indisponible");
491 default:
492 throw ArgumentException(func_name, "preconditionnement inconnu");
493 }
494
495 // résolution du système algébrique
496 HYPRE_Int iteration = 0;
497 double residue = 0.0;
498
499 switch (solver_method) {
500 case TypesSolver::PCG:
501 ierr = solvePCG(solver_param, solver, M, B, X, iteration, residue);
502 break;
503 case TypesSolver::BiCGStab:
504 ierr = solveBiCGStab(solver, M, B, X, iteration, residue);
505 break;
506 case TypesSolver::GMRES:
507 ierr = solveGMRES(solver, M, B, X, iteration, residue);
508 break;
509 default:
510 ierr = -3;
511 return ierr;
512 }
513 nb_iteration = static_cast<Integer>(iteration);
514 residual_norm[0] = static_cast<Real>(residue);
515
516 /* for(int i=0;i<8;++i){
517 int idx[1];
518 double valx[1]={-1.};
519 //double valb[1]={-1.};
520 idx[0]=i;
521 HYPRE_IJVectorGetValues(solution, 1, idx, valx);
522 debug()<<"[AlephMatrixHypre::AlephMatrixSolve] X["<<i<<"]="<<valx[0];
523 //(static_cast<AlephVectorHypre*> (x->implementation()))->AlephVectorGet(valx,idx,1);
524 //debug()<<"[AlephMatrixHypre::AlephMatrixSolve] x["<<i<<"]="<<valx[0];
525 //HYPRE_IJVectorGetValues(RHS, 1, idx, valb);
526 //debug()<<"[AlephMatrixHypre::AlephMatrixSolve] B["<<i<<"]="<<valb[0];
527 }
528*/
529 switch (preconditioner_method) {
530 case TypesSolver::NONE:
531 break;
532 case TypesSolver::DIAGONAL:
533 break;
534 case TypesSolver::ILU:
536 break;
537 case TypesSolver::SPAIstat:
539 break;
540 case TypesSolver::AMG:
541 HYPRE_BoomerAMGDestroy(precond);
542 break;
543 default:
544 throw ArgumentException(func_name, "preconditionnement inconnu");
545 }
546
547 if (iteration == solver_param->maxIter() && solver_param->stopErrorStrategy()) {
548 info() << "\n============================================================";
549 info() << "\nCette erreur est retournée après " << iteration << "\n";
550 info() << "\nOn a atteind le nombre max d'itérations du solveur.";
551 info() << "\nIl est possible de demander au code de ne pas tenir compte de cette erreur.";
552 info() << "\nVoir la documentation du jeu de données concernant le service solveur.";
553 info() << "\n======================================================";
554 throw Exception("AlephMatrixHypre::Solve", "On a atteind le nombre max d'itérations du solveur");
555 }
556 return ierr;
557 }
558
559 /******************************************************************************
560 *****************************************************************************/
561 void writeToFile(const String filename)
562 {
563 HYPRE_IJMatrixPrint(m_hypre_ijmatrix, filename.localstr());
564 }
565
566 /******************************************************************************
567 *****************************************************************************/
568 void initSolverPCG(const AlephParams* solver_param, HYPRE_Solver& solver)
569 {
570 const String func_name = "SolverMatrixHypre::initSolverPCG";
571 double epsilon = solver_param->epsilon();
572 int max_it = solver_param->maxIter();
573 int output_level = solver_param->getOutputLevel();
574
575 HYPRE_ParCSRPCGCreate(MPI_COMM_SUB, &solver);
580 }
581
582 /******************************************************************************
583 *****************************************************************************/
584 void initSolverBiCGStab(const AlephParams* solver_param, HYPRE_Solver& solver)
585 {
586 const String func_name = "SolverMatrixHypre::initSolverBiCGStab";
587 double epsilon = solver_param->epsilon();
588 int max_it = solver_param->maxIter();
589 int output_level = solver_param->getOutputLevel();
590
591 HYPRE_ParCSRBiCGSTABCreate(MPI_COMM_SUB, &solver);
595 }
596
597 /******************************************************************************
598 *****************************************************************************/
599 void initSolverGMRES(const AlephParams* solver_param, HYPRE_Solver& solver)
600 {
601 const String func_name = "SolverMatrixHypre::initSolverGMRES";
602 double epsilon = solver_param->epsilon();
603 int max_it = solver_param->maxIter();
604 int output_level = solver_param->getOutputLevel();
605
606 HYPRE_ParCSRGMRESCreate(MPI_COMM_SUB, &solver);
607 const int krylov_dim = 20; // dimension Krylov space for GMRES
612 }
613
614 /******************************************************************************
615 *****************************************************************************/
616 void setDiagonalPreconditioner(const TypesSolver::eSolverMethod solver_method,
617 const HYPRE_Solver& solver,
618 HYPRE_Solver& precond)
619 {
620 const String func_name = "SolverMatrixHypre::setDiagonalPreconditioner";
621 switch (solver_method) {
622 case TypesSolver::PCG:
626 precond);
627 break;
628 case TypesSolver::BiCGStab:
632 precond);
633 break;
634 case TypesSolver::GMRES:
638 precond);
639 break;
640 default:
641 throw ArgumentException(func_name, "solveur inconnu pour preconditionnement 'Diagonal'");
642 }
643 }
644
645 /******************************************************************************
646 *****************************************************************************/
647 void setILUPreconditioner(const TypesSolver::eSolverMethod solver_method,
648 const HYPRE_Solver& solver,
649 HYPRE_Solver& precond)
650 {
651 const String func_name = "SolverMatrixHypre::setILUPreconditioner";
652 switch (solver_method) {
653 case TypesSolver::PCG:
654 throw ArgumentException(func_name, "solveur PCG indisponible avec le preconditionnement 'ILU'");
655 break;
656 case TypesSolver::BiCGStab:
657 HYPRE_ParCSRPilutCreate(MPI_COMM_SUB, &precond);
661 precond);
662 break;
663 case TypesSolver::GMRES:
664 HYPRE_ParCSRPilutCreate(MPI_COMM_SUB,
665 &precond);
669 precond);
670 break;
671 default:
672 throw ArgumentException(func_name, "solveur inconnu pour preconditionnement ILU\n");
673 }
674 }
675
676 /******************************************************************************
677 *****************************************************************************/
678 void setSpaiStatPreconditioner(const TypesSolver::eSolverMethod solver_method,
679 const HYPRE_Solver& solver,
681 HYPRE_Solver& precond)
682 {
683 HYPRE_ParCSRParaSailsCreate(MPI_COMM_SUB, &precond);
684 double alpha = solver_param->alpha();
685 int gamma = solver_param->gamma();
686 if (alpha < 0.0)
687 alpha = 0.1; // valeur par defaut pour le parametre de tolerance
688 if (gamma == -1)
689 gamma = 1; // valeur par defaut pour le parametre de remplissage
690 HYPRE_ParCSRParaSailsSetParams(precond, alpha, gamma);
691 switch (solver_method) {
692 case TypesSolver::PCG:
694 break;
695 case TypesSolver::BiCGStab:
696 throw ArgumentException("AlephMatrixHypre::setSpaiStatPreconditioner", "solveur 'BiCGStab' invalide pour preconditionnement 'SPAIstat'");
697 break;
698 case TypesSolver::GMRES:
699 // matrice non symétrique
700 HYPRE_ParCSRParaSailsSetSym(precond, 0);
702 break;
703 default:
704 throw ArgumentException("AlephMatrixHypre::setSpaiStatPreconditioner", "solveur inconnu pour preconditionnement 'SPAIstat'\n");
705 break;
706 }
707 }
708
709 /******************************************************************************
710 *****************************************************************************/
711 void setAMGPreconditioner(const TypesSolver::eSolverMethod solver_method,
712 const HYPRE_Solver& solver,
714 HYPRE_Solver& precond)
715 {
716 // defaults for BoomerAMG from hypre example -- lc
717 // TODO : options and defaults values must be completed
718 double trunc_factor = 0.1; // set AMG interpolation truncation factor = val
719 int cycle_type = solver_param->getAmgCycle(); // set AMG cycles (1=V, 2=W, etc.)
720 int coarsen_type = solver_param->amgCoarseningMethod();
721 // Ruge coarsening (local) if <val> == 1
722 int relax_default = 3; // relaxation type <val> :
723 // 0=Weighted Jacobi
724 // 1=Gauss-Seidel (very slow!)
725 // 3=Hybrid Jacobi/Gauss-Seidel
726 int num_sweep = 1; // Use <val> sweeps on each level (here 1)
727 int hybrid = 1; // no switch in coarsening if -1
728 int measure_type = 1; // use globale measures
729 double max_row_sum = 1.0; // set AMG maximum row sum threshold for dependency weakening
730
731 int max_levels = 50; // 25; // maximum number of AMG levels
732 const int gamma = solver_param->gamma();
733 if (gamma != -1)
734 max_levels = gamma; // utilisation de la valeur du jeu de donnees
735
736 double strong_threshold = 0.1; // 0.25; // set AMG threshold Theta = val
737 const double alpha = solver_param->alpha();
738 if (alpha > 0.0)
739 strong_threshold = alpha; // utilisation de la valeur du jeu de donnees
740 // news
741 Integer output_level = solver_param->getOutputLevel();
742
747
748 for (int i = 0; i < max_levels; i++)
749 relax_weight[i] = 1.0;
750
751 if (coarsen_type == 5) {
752 /* fine grid */
753 num_grid_sweeps[0] = 3;
756 grid_relax_points[0][0] = -2;
757 grid_relax_points[0][1] = -1;
758 grid_relax_points[0][2] = 1;
759
760 /* down cycle */
761 num_grid_sweeps[1] = 4;
764 grid_relax_points[1][0] = -1;
765 grid_relax_points[1][1] = 1;
766 grid_relax_points[1][2] = -2;
767 grid_relax_points[1][3] = -2;
768
769 /* up cycle */
770 num_grid_sweeps[2] = 4;
773 grid_relax_points[2][0] = -2;
774 grid_relax_points[2][1] = -2;
775 grid_relax_points[2][2] = 1;
776 grid_relax_points[2][3] = -1;
777 }
778 else {
779 /* fine grid */
780 num_grid_sweeps[0] = 2 * num_sweep;
783 for (int i = 0; i < 2 * num_sweep; i += 2) {
784 grid_relax_points[0][i] = -1;
785 grid_relax_points[0][i + 1] = 1;
786 }
787
788 /* down cycle */
789 num_grid_sweeps[1] = 2 * num_sweep;
792 for (int i = 0; i < 2 * num_sweep; i += 2) {
793 grid_relax_points[1][i] = -1;
794 grid_relax_points[1][i + 1] = 1;
795 }
796
797 /* up cycle */
798 num_grid_sweeps[2] = 2 * num_sweep;
801 for (int i = 0; i < 2 * num_sweep; i += 2) {
802 grid_relax_points[2][i] = -1;
803 grid_relax_points[2][i + 1] = 1;
804 }
805 }
806
807 /* coarsest grid */
808 num_grid_sweeps[3] = 1;
809 grid_relax_type[3] = 9;
811 grid_relax_points[3][0] = 0;
812
813 // end of default seting
814
815 HYPRE_BoomerAMGCreate(&precond);
821 HYPRE_BoomerAMGSetMaxIter(precond, 1);
827 HYPRE_BoomerAMGSetTol(precond, 0.0);
830
831 switch (solver_method) {
832 case TypesSolver::PCG:
836 precond);
837 break;
838 case TypesSolver::BiCGStab:
842 precond);
843 break;
844 case TypesSolver::GMRES:
848 precond);
849 break;
850 default:
851 throw ArgumentException("AlephMatrixHypre::setAMGPreconditioner", "solveur inconnu pour preconditionnement 'AMG'\n");
852 }
853 }
854
855 /******************************************************************************
856 *****************************************************************************/
857 bool solvePCG(const AlephParams* solver_param,
862 HYPRE_Int& iteration,
863 double& residue)
864 {
865 const String func_name = "SolverMatrixHypre::solvePCG";
866 const bool xo = solver_param->xoUser();
867 bool error = false;
868
869 if (!xo)
875
878 error |= (!converged);
879
881
882 return !error;
883 }
884
885 /******************************************************************************
886 *****************************************************************************/
887 bool solveBiCGStab(HYPRE_Solver& solver,
891 HYPRE_Int& iteration,
892 double& residue)
893 {
894 const String func_name = "SolverMatrixHypre::solveBiCGStab";
895 bool error = false;
901
904 error |= (!converged);
905
907
908 return !error;
909 }
910
911 /******************************************************************************
912 *****************************************************************************/
913 bool solveGMRES(HYPRE_Solver& solver,
917 HYPRE_Int& iteration,
918 double& residue)
919 {
920 const String func_name = "SolverMatrixHypre::solveGMRES";
921 bool error = false;
926
929 error |= (!converged);
930
932 return !error;
933 }
934
935 private:
936
937 HYPRE_IJMatrix m_hypre_ijmatrix = nullptr;
938 HYPRE_ParCSRMatrix m_hypre_parmatrix = nullptr;
939};
940
941/*---------------------------------------------------------------------------*/
942/*---------------------------------------------------------------------------*/
943
945: public AbstractService
946, public IAlephFactoryImpl
947{
948 public:
951 {}
953 {
954 for ( auto* v : m_IAlephVectors )
955 delete v;
956 for ( auto* v : m_IAlephMatrixs )
957 delete v;
958 }
959
960 public:
961
962 void initialize() override
963 {
964 // NOTE: A partir de la 2.29, on peut utiliser
965 // HYPRE_Initialize() et tester si l'initialisation
966 // a déjà été faite via HYPRE_Initialized().
967#if HYPRE_RELEASE_NUMBER >= 22900
968 if (!HYPRE_Initialized()){
969 info() << "Initializing HYPRE";
971 }
972#elif HYPRE_RELEASE_NUMBER >= 22700
973 info() << "Initializing HYPRE";
974 HYPRE_Init();
975#endif
976
977#if HYPRE_RELEASE_NUMBER >= 22700
980#endif
981 }
982
983 IAlephTopology* createTopology(ITraceMng* tm,
984 AlephKernel* kernel,
985 Integer index,
986 Integer nb_row_size) override
987 {
988 ARCANE_UNUSED(tm);
989 ARCANE_UNUSED(kernel);
990 ARCANE_UNUSED(index);
991 ARCANE_UNUSED(nb_row_size);
992 return NULL;
993 }
994
995 IAlephVector* createVector(ITraceMng* tm,
996 AlephKernel* kernel,
997 Integer index) override
998 {
999 IAlephVector* new_vector = new AlephVectorHypre(tm, kernel, index);
1000 m_IAlephVectors.add(new_vector);
1001 return new_vector;
1002 }
1003
1004 IAlephMatrix* createMatrix(ITraceMng* tm,
1005 AlephKernel* kernel,
1006 Integer index) override
1007 {
1008 IAlephMatrix* new_matrix = new AlephMatrixHypre(tm, kernel, index);
1009 m_IAlephMatrixs.add(new_matrix);
1010 return new_matrix;
1011 }
1012
1013 private:
1014 UniqueArray<IAlephVector*> m_IAlephVectors;
1015 UniqueArray<IAlephMatrix*> m_IAlephMatrixs;
1016};
1017
1018/*---------------------------------------------------------------------------*/
1019/*---------------------------------------------------------------------------*/
1020
1022
1023/*---------------------------------------------------------------------------*/
1024/*---------------------------------------------------------------------------*/
1025
1026}
1027
1028/*---------------------------------------------------------------------------*/
1029/*---------------------------------------------------------------------------*/
#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.
Classe de base d'un service.
Paramètres d'un système linéraire.
Definition AlephParams.h:34
Vecteur d'un système linéaire.
Definition AlephVector.h:33
Interface d'une fabrique d'implémentation pour Aleph.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:149
Structure contenant les informations pour créer un service.
Exception lorsqu'un argument est invalide.
Classe de base d'une exception.
Interface du gestionnaire de traces.
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:227
TraceMessage error() const
Flot pour un message d'erreur.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
TraceMessage info() const
Flot pour un message d'information.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
int AlephInt
Type par défaut pour indexer les lignes et les colonnes des matrices et vecteurs.
Definition AlephGlobal.h:50