Arcane  v3.14.10.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-2024 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-2024 */
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 , m_hypre_ijvector(0)
115 , m_hypre_parvector(0)
116 , jSize(0)
117 , jUpper(0)
118 , jLower(-1)
119 {
120 debug() << "[AlephVectorHypre::AlephVectorHypre] new SolverVectorHypre";
121 }
122
123 public:
124 /******************************************************************************
125 * The Create() routine creates an empty vector object that lives on the comm communicator. This is
126 * a collective call, with each process passing its own index extents, jLower and jupper. The names
127 * of these extent parameters begin with a j because we typically think of matrix-vector multiplies
128 * as the fundamental operation involving both matrices and vectors. For matrix-vector multiplies,
129 * the vector partitioning should match the column partitioning of the matrix (which also uses the j
130 * notation). For linear system solves, these extents will typically match the row partitioning of the
131 * matrix as well.
132 *****************************************************************************/
133 void AlephVectorCreate(void)
134 {
135 debug() << "[AlephVectorHypre::AlephVectorCreate] HYPRE VectorCreate";
136 void* object;
137
138 for (int iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
139 if (m_kernel->rank() != m_kernel->solverRanks(m_index)[iCpu])
140 continue;
141 debug() << "[AlephVectorHypre::AlephVectorCreate] adding contibution of core #" << iCpu;
142 if (jLower == -1)
143 jLower = m_kernel->topology()->gathered_nb_row(iCpu);
144 jUpper = m_kernel->topology()->gathered_nb_row(iCpu + 1) - 1;
145 }
146
147 debug() << "[AlephVectorHypre::AlephVectorCreate] jLower=" << jLower << ", jupper=" << jUpper;
148 // Mise à jour de la taille locale du buffer pour le calcul plus tard de la norme max, par exemple
149 jSize = jUpper - jLower + 1;
150
151 hypreCheck("IJVectorCreate",
152 HYPRE_IJVectorCreate(MPI_COMM_SUB,
153 jLower,
154 jUpper,
155 &m_hypre_ijvector));
156
157 debug() << "[AlephVectorHypre::AlephVectorCreate] HYPRE IJVectorSetObjectType";
158 hypreCheck("IJVectorSetObjectType", HYPRE_IJVectorSetObjectType(m_hypre_ijvector, HYPRE_PARCSR));
159
160 debug() << "[AlephVectorHypre::AlephVectorCreate] HYPRE IJVectorInitialize";
161 hypreCheck("HYPRE_IJVectorInitialize", HYPRE_IJVectorInitialize(m_hypre_ijvector));
162
163 HYPRE_IJVectorGetObject(m_hypre_ijvector, &object);
164 m_hypre_parvector = (HYPRE_ParVector)object;
165 debug() << "[AlephVectorHypre::AlephVectorCreate] done";
166 }
167
168 /******************************************************************************
169 *****************************************************************************/
170 void AlephVectorSet(const double* bfr_val, const AlephInt* bfr_idx, Integer size)
171 {
172 debug() << "[AlephVectorHypre::AlephVectorSet] size=" << size;
173 hypreCheck("IJVectorSetValues", HYPRE_IJVectorSetValues(m_hypre_ijvector, size, bfr_idx, bfr_val));
174 }
175
176 /******************************************************************************
177 *****************************************************************************/
178 int AlephVectorAssemble(void)
179 {
180 debug() << "[AlephVectorHypre::AlephVectorAssemble]";
181 hypreCheck("IJVectorAssemble", HYPRE_IJVectorAssemble(m_hypre_ijvector));
182 return 0;
183 }
184
185 /******************************************************************************
186 *****************************************************************************/
187 void AlephVectorGet(double* bfr_val, const AlephInt* bfr_idx, Integer size)
188 {
189 //HYPRE_Int* hypre_bfr_idx = static
190 debug() << "[AlephVectorHypre::AlephVectorGet] size=" << size;
191 hypreCheck("HYPRE_IJVectorGetValues", HYPRE_IJVectorGetValues(m_hypre_ijvector, size, bfr_idx, bfr_val));
192 }
193
194 /******************************************************************************
195 * norm_max
196 *****************************************************************************/
197 Real norm_max()
198 {
199 Real normInf = 0.0;
202
203 for (HYPRE_Int i = 0; i < jSize; ++i)
204 bfr_idx[i] = jLower + i;
205
206 hypreCheck("HYPRE_IJVectorGetValues", HYPRE_IJVectorGetValues(m_hypre_ijvector, jSize, bfr_idx.data(), bfr_val.data()));
207 for (HYPRE_Int i = 0; i < jSize; ++i) {
208 const Real abs_val = math::abs(bfr_val[i]);
209 if (abs_val > normInf)
210 normInf = abs_val;
211 }
212 normInf = m_kernel->subParallelMng(m_index)->reduce(Parallel::ReduceMax, normInf);
213 return normInf;
214 }
215
216 /******************************************************************************
217 *****************************************************************************/
218 void writeToFile(const String filename)
219 {
220 String filename_idx = filename; // + "_" + (int)m_kernel->subDomain()->commonVariables().globalIteration();
221 debug() << "[AlephVectorHypre::writeToFile]";
222 hypreCheck("HYPRE_IJVectorPrint",
223 HYPRE_IJVectorPrint(m_hypre_ijvector, filename_idx.localstr()));
224 }
225
226 public:
227 HYPRE_IJVector m_hypre_ijvector;
228 HYPRE_ParVector m_hypre_parvector;
229 HYPRE_Int jSize;
230 HYPRE_Int jUpper;
231 HYPRE_Int jLower;
232};
233
234/******************************************************************************
235 AlephMatrixHypre
236*****************************************************************************/
238: public IAlephMatrix
239{
240 public:
241 /******************************************************************************
242 AlephMatrixHypre
243 *****************************************************************************/
244 AlephMatrixHypre(ITraceMng* tm, AlephKernel* kernel, Integer index)
245 : IAlephMatrix(tm, kernel, index)
246 , m_hypre_ijmatrix(0)
247 {
248 debug() << "[AlephMatrixHypre] new AlephMatrixHypre";
249 }
250
252 {
253 debug() << "[~AlephMatrixHypre]";
254 }
255
256 public:
257 /******************************************************************************
258 * Each submatrix Ap is "owned" by a single process and its first and last row numbers are
259 * given by the global indices ilower and iupper in the Create() call below.
260 *******************************************************************************
261 * The Create() routine creates an empty matrix object that lives on the comm communicator. This
262 * is a collective call (i.e., must be called on all processes from a common synchronization point),
263 * with each process passing its own row extents, ilower and iupper. The row partitioning must be
264 * contiguous, i.e., iupper for process i must equal ilower-1 for process i+1. Note that this allows
265 * matrices to have 0- or 1-based indexing. The parameters jlower and jupper define a column
266 * partitioning, and should match ilower and iupper when solving square linear systems.
267 *****************************************************************************/
268 void AlephMatrixCreate(void)
269 {
270 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE MatrixCreate idx:" << m_index;
271 void* object;
272 AlephInt ilower = -1;
273 AlephInt iupper = 0;
274 for (int iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
275 if (m_kernel->rank() != m_kernel->solverRanks(m_index)[iCpu])
276 continue;
277 if (ilower == -1)
278 ilower = m_kernel->topology()->gathered_nb_row(iCpu);
279 iupper = m_kernel->topology()->gathered_nb_row(iCpu + 1) - 1;
280 }
281 debug() << "[AlephMatrixHypre::AlephMatrixCreate] ilower=" << ilower << ", iupper=" << iupper;
282
283 AlephInt jlower = ilower; //0;
284 AlephInt jupper = iupper; //m_kernel->topology()->gathered_nb_row(m_kernel->size())-1;
285 debug() << "[AlephMatrixHypre::AlephMatrixCreate] jlower=" << jlower << ", jupper=" << jupper;
286
287 hypreCheck("HYPRE_IJMatrixCreate",
288 HYPRE_IJMatrixCreate(MPI_COMM_SUB,
289 ilower, iupper,
290 jlower, jupper,
291 &m_hypre_ijmatrix));
292
293 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE IJMatrixSetObjectType";
294 HYPRE_IJMatrixSetObjectType(m_hypre_ijmatrix, HYPRE_PARCSR);
295 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE IJMatrixSetRowSizes";
296 HYPRE_IJMatrixSetRowSizes(m_hypre_ijmatrix, m_kernel->topology()->gathered_nb_row_elements().data());
297 debug() << "[AlephMatrixHypre::AlephMatrixCreate] HYPRE IJMatrixInitialize";
298 HYPRE_IJMatrixInitialize(m_hypre_ijmatrix);
299 HYPRE_IJMatrixGetObject(m_hypre_ijmatrix, &object);
300 m_hypre_parmatrix = (HYPRE_ParCSRMatrix)object;
301 }
302
303 /******************************************************************************
304 *****************************************************************************/
305 void AlephMatrixSetFilled(bool) {}
306
307 /******************************************************************************
308 *****************************************************************************/
309 int AlephMatrixAssemble(void)
310 {
311 debug() << "[AlephMatrixHypre::AlephMatrixAssemble]";
312 hypreCheck("HYPRE_IJMatrixAssemble",
313 HYPRE_IJMatrixAssemble(m_hypre_ijmatrix));
314 return 0;
315 }
316
317 /******************************************************************************
318 *****************************************************************************/
319 void AlephMatrixFill(int size, HYPRE_Int* rows, HYPRE_Int* cols, double* values)
320 {
321 debug() << "[AlephMatrixHypre::AlephMatrixFill] size=" << size;
322 HYPRE_Int rtn = 0;
323 HYPRE_Int col[1] = { 1 };
324 for (int i = 0; i < size; i++) {
325 rtn += HYPRE_IJMatrixSetValues(m_hypre_ijmatrix, 1, col, &rows[i], &cols[i], &values[i]);
326 }
327 hypreCheck("HYPRE_IJMatrixSetValues", rtn);
328 //HYPRE_IJMatrixSetValues(m_hypre_ijmatrix, nrows, ncols, rows, cols, values);
329 debug() << "[AlephMatrixHypre::AlephMatrixFill] done";
330 }
331
332 /******************************************************************************
333 * isAlreadySolved
334 *****************************************************************************/
335 bool isAlreadySolved(AlephVectorHypre* x,
338 Real* residual_norm,
339 AlephParams* params)
340 {
342 const bool convergence_analyse = params->convergenceAnalyse();
343
344 // test le second membre du système linéaire
345 const Real res0 = b->norm_max();
346
348 info() << "analyse convergence : norme max du second membre res0 : " << res0;
349
350 const Real considered_as_null = params->minRHSNorm();
351 if (res0 < considered_as_null) {
352 HYPRE_ParVectorSetConstantValues(x->m_hypre_parvector, 0.0);
353 residual_norm[0] = res0;
355 info() << "analyse convergence : le second membre du système linéaire est inférieur à : " << considered_as_null;
356 return true;
357 }
358
359 if (params->xoUser()) {
360 // on test si b est déjà solution du système à epsilon près
361 //matrix->vectorProduct(b, tmp_vector); tmp_vector->sub(x);
362 //M->vector_multiply(*tmp,*x); // tmp=A*x
363 //tmp->substract(*tmp,*b); // tmp=A*x-b
364
365 // X= alpha* M.B + beta * X (lu dans les sources de HYPRE)
366 HYPRE_ParCSRMatrixMatvec(1.0, m_hypre_parmatrix, x->m_hypre_parvector, 0., tmp->m_hypre_parvector);
367 HYPRE_ParVectorAxpy(-1.0, b->m_hypre_parvector, tmp->m_hypre_parvector);
368
369 const Real residu = tmp->norm_max();
370 //info() << "[IAlephHypre::isAlreadySolved] residu="<<residu;
371
374 info() << "analyse convergence : |Ax0-b| est inférieur à " << considered_as_null;
375 info() << "analyse convergence : x0 est déjà solution du système.";
376 }
378 return true;
379 }
380
381 const Real relative_error = residu / res0;
383 info() << "analyse convergence : résidu initial : " << residu
384 << " --- residu relatif initial (residu/res0) : " << residu / res0;
385
386 if (relative_error < (params->epsilon())) {
388 info() << "analyse convergence : X est déjà solution du système";
390 return true;
391 }
392 }
393 return false;
394 }
395
396 /******************************************************************************
397 *****************************************************************************/
398 int AlephMatrixSolve(AlephVector* x,
399 AlephVector* b,
400 AlephVector* t,
401 Integer& nb_iteration,
402 Real* residual_norm,
404 {
405 solver_param->setAmgCoarseningMethod(TypesSolver::AMG_COARSENING_AUTO);
406 const String func_name("SolverMatrixHypre::solve");
407 void* object;
408 int ierr = 0;
409
410 auto* ximpl = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(x->implementation()));
411 auto* bimpl = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(b->implementation()));
412
413 HYPRE_IJVector solution = ximpl->m_hypre_ijvector;
414 HYPRE_IJVector RHS = bimpl->m_hypre_ijvector;
415 //HYPRE_IJVector tmp = (dynamic_cast<AlephVectorHypre*> (t->implementation()))->m_hypre_ijvector;
416
417 HYPRE_IJMatrixGetObject(m_hypre_ijmatrix, &object);
423 //HYPRE_IJVectorGetObject(tmp,&object);
424 //HYPRE_ParVector T = (HYPRE_ParVector)object;
425
426 auto* ximpl2 = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(x->implementation()));
427 auto* bimpl2 = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(b->implementation()));
428 auto* timpl2 = ARCANE_CHECK_POINTER(dynamic_cast<AlephVectorHypre*>(t->implementation()));
429 if (isAlreadySolved(ximpl2, bimpl2, timpl2, residual_norm, solver_param)) {
430 ItacRegion(isAlreadySolved, AlephMatrixHypre);
431 debug() << "[AlephMatrixHypre::AlephMatrixSolve] isAlreadySolved !";
432 nb_iteration = 0;
433 return 0;
434 }
435
436 TypesSolver::ePreconditionerMethod preconditioner_method = solver_param->precond();
437 // TypesSolver::ePreconditionerMethod preconditioner_method = TypesSolver::NONE;
438 TypesSolver::eSolverMethod solver_method = solver_param->method();
439
440 // déclaration et initialisation du solveur
442
443 switch (solver_method) {
444 case TypesSolver::PCG:
445 initSolverPCG(solver_param, solver);
446 break;
447 case TypesSolver::BiCGStab:
448 initSolverBiCGStab(solver_param, solver);
449 break;
450 case TypesSolver::GMRES:
451 initSolverGMRES(solver_param, solver);
452 break;
453 default:
454 throw ArgumentException(func_name, "solveur inconnu");
455 }
456
457 // déclaration et initialisation du preconditionneur
458 HYPRE_Solver precond = 0;
459
460 switch (preconditioner_method) {
461 case TypesSolver::NONE:
462 break;
463 case TypesSolver::DIAGONAL:
464 setDiagonalPreconditioner(solver_method, solver, precond);
465 break;
466 case TypesSolver::ILU:
467 setILUPreconditioner(solver_method, solver, precond);
468 break;
469 case TypesSolver::SPAIstat:
470 setSpaiStatPreconditioner(solver_method, solver, solver_param, precond);
471 break;
472 case TypesSolver::AMG:
473 setAMGPreconditioner(solver_method, solver, solver_param, precond);
474 break;
475 case TypesSolver::AINV:
476 throw ArgumentException(func_name, "preconditionnement AINV indisponible");
477 case TypesSolver::SPAIdyn:
478 throw ArgumentException(func_name, "preconditionnement SPAIdyn indisponible");
479 case TypesSolver::ILUp:
480 throw ArgumentException(func_name, "preconditionnement ILUp indisponible");
481 case TypesSolver::IC:
482 throw ArgumentException(func_name, "preconditionnement IC indisponible");
483 case TypesSolver::POLY:
484 throw ArgumentException(func_name, "preconditionnement POLY indisponible");
485 default:
486 throw ArgumentException(func_name, "preconditionnement inconnu");
487 }
488
489 // résolution du système algébrique
490 HYPRE_Int iteration = 0;
491 double residue = 0.0;
492
493 switch (solver_method) {
494 case TypesSolver::PCG:
495 ierr = solvePCG(solver_param, solver, M, B, X, iteration, residue);
496 break;
497 case TypesSolver::BiCGStab:
498 ierr = solveBiCGStab(solver, M, B, X, iteration, residue);
499 break;
500 case TypesSolver::GMRES:
501 ierr = solveGMRES(solver, M, B, X, iteration, residue);
502 break;
503 default:
504 ierr = -3;
505 return ierr;
506 }
507 nb_iteration = static_cast<Integer>(iteration);
508 residual_norm[0] = static_cast<Real>(residue);
509
510 /* for(int i=0;i<8;++i){
511 int idx[1];
512 double valx[1]={-1.};
513 //double valb[1]={-1.};
514 idx[0]=i;
515 HYPRE_IJVectorGetValues(solution, 1, idx, valx);
516 debug()<<"[AlephMatrixHypre::AlephMatrixSolve] X["<<i<<"]="<<valx[0];
517 //(static_cast<AlephVectorHypre*> (x->implementation()))->AlephVectorGet(valx,idx,1);
518 //debug()<<"[AlephMatrixHypre::AlephMatrixSolve] x["<<i<<"]="<<valx[0];
519 //HYPRE_IJVectorGetValues(RHS, 1, idx, valb);
520 //debug()<<"[AlephMatrixHypre::AlephMatrixSolve] B["<<i<<"]="<<valb[0];
521 }
522*/
523 switch (preconditioner_method) {
524 case TypesSolver::NONE:
525 break;
526 case TypesSolver::DIAGONAL:
527 break;
528 case TypesSolver::ILU:
530 break;
531 case TypesSolver::SPAIstat:
533 break;
534 case TypesSolver::AMG:
535 HYPRE_BoomerAMGDestroy(precond);
536 break;
537 default:
538 throw ArgumentException(func_name, "preconditionnement inconnu");
539 }
540
541 if (iteration == solver_param->maxIter() && solver_param->stopErrorStrategy()) {
542 info() << "\n============================================================";
543 info() << "\nCette erreur est retournée après " << iteration << "\n";
544 info() << "\nOn a atteind le nombre max d'itérations du solveur.";
545 info() << "\nIl est possible de demander au code de ne pas tenir compte de cette erreur.";
546 info() << "\nVoir la documentation du jeu de données concernant le service solveur.";
547 info() << "\n======================================================";
548 throw Exception("AlephMatrixHypre::Solve", "On a atteind le nombre max d'itérations du solveur");
549 }
550 return ierr;
551 }
552
553 /******************************************************************************
554 *****************************************************************************/
555 void writeToFile(const String filename)
556 {
557 HYPRE_IJMatrixPrint(m_hypre_ijmatrix, filename.localstr());
558 }
559
560 /******************************************************************************
561 *****************************************************************************/
562 void initSolverPCG(const AlephParams* solver_param, HYPRE_Solver& solver)
563 {
564 const String func_name = "SolverMatrixHypre::initSolverPCG";
565 double epsilon = solver_param->epsilon();
566 int max_it = solver_param->maxIter();
567 int output_level = solver_param->getOutputLevel();
568
569 HYPRE_ParCSRPCGCreate(MPI_COMM_SUB, &solver);
574 }
575
576 /******************************************************************************
577 *****************************************************************************/
578 void initSolverBiCGStab(const AlephParams* solver_param, HYPRE_Solver& solver)
579 {
580 const String func_name = "SolverMatrixHypre::initSolverBiCGStab";
581 double epsilon = solver_param->epsilon();
582 int max_it = solver_param->maxIter();
583 int output_level = solver_param->getOutputLevel();
584
585 HYPRE_ParCSRBiCGSTABCreate(MPI_COMM_SUB, &solver);
589 }
590
591 /******************************************************************************
592 *****************************************************************************/
593 void initSolverGMRES(const AlephParams* solver_param, HYPRE_Solver& solver)
594 {
595 const String func_name = "SolverMatrixHypre::initSolverGMRES";
596 double epsilon = solver_param->epsilon();
597 int max_it = solver_param->maxIter();
598 int output_level = solver_param->getOutputLevel();
599
600 HYPRE_ParCSRGMRESCreate(MPI_COMM_SUB, &solver);
601 const int krylov_dim = 20; // dimension Krylov space for GMRES
606 }
607
608 /******************************************************************************
609 *****************************************************************************/
610 void setDiagonalPreconditioner(const TypesSolver::eSolverMethod solver_method,
611 const HYPRE_Solver& solver,
612 HYPRE_Solver& precond)
613 {
614 const String func_name = "SolverMatrixHypre::setDiagonalPreconditioner";
615 switch (solver_method) {
616 case TypesSolver::PCG:
620 precond);
621 break;
622 case TypesSolver::BiCGStab:
626 precond);
627 break;
628 case TypesSolver::GMRES:
632 precond);
633 break;
634 default:
635 throw ArgumentException(func_name, "solveur inconnu pour preconditionnement 'Diagonal'");
636 }
637 }
638
639 /******************************************************************************
640 *****************************************************************************/
641 void setILUPreconditioner(const TypesSolver::eSolverMethod solver_method,
642 const HYPRE_Solver& solver,
643 HYPRE_Solver& precond)
644 {
645 const String func_name = "SolverMatrixHypre::setILUPreconditioner";
646 switch (solver_method) {
647 case TypesSolver::PCG:
648 throw ArgumentException(func_name, "solveur PCG indisponible avec le preconditionnement 'ILU'");
649 break;
650 case TypesSolver::BiCGStab:
651 HYPRE_ParCSRPilutCreate(MPI_COMM_SUB, &precond);
655 precond);
656 break;
657 case TypesSolver::GMRES:
658 HYPRE_ParCSRPilutCreate(MPI_COMM_SUB,
659 &precond);
663 precond);
664 break;
665 default:
666 throw ArgumentException(func_name, "solveur inconnu pour preconditionnement ILU\n");
667 }
668 }
669
670 /******************************************************************************
671 *****************************************************************************/
672 void setSpaiStatPreconditioner(const TypesSolver::eSolverMethod solver_method,
673 const HYPRE_Solver& solver,
675 HYPRE_Solver& precond)
676 {
677 HYPRE_ParCSRParaSailsCreate(MPI_COMM_SUB, &precond);
678 double alpha = solver_param->alpha();
679 int gamma = solver_param->gamma();
680 if (alpha < 0.0)
681 alpha = 0.1; // valeur par defaut pour le parametre de tolerance
682 if (gamma == -1)
683 gamma = 1; // valeur par defaut pour le parametre de remplissage
684 HYPRE_ParCSRParaSailsSetParams(precond, alpha, gamma);
685 switch (solver_method) {
686 case TypesSolver::PCG:
688 break;
689 case TypesSolver::BiCGStab:
690 throw ArgumentException("AlephMatrixHypre::setSpaiStatPreconditioner", "solveur 'BiCGStab' invalide pour preconditionnement 'SPAIstat'");
691 break;
692 case TypesSolver::GMRES:
693 // matrice non symétrique
694 HYPRE_ParCSRParaSailsSetSym(precond, 0);
696 break;
697 default:
698 throw ArgumentException("AlephMatrixHypre::setSpaiStatPreconditioner", "solveur inconnu pour preconditionnement 'SPAIstat'\n");
699 break;
700 }
701 }
702
703 /******************************************************************************
704 *****************************************************************************/
705 void setAMGPreconditioner(const TypesSolver::eSolverMethod solver_method,
706 const HYPRE_Solver& solver,
708 HYPRE_Solver& precond)
709 {
710 // defaults for BoomerAMG from hypre example -- lc
711 // TODO : options and defaults values must be completed
712 double trunc_factor = 0.1; // set AMG interpolation truncation factor = val
713 int cycle_type = solver_param->getAmgCycle(); // set AMG cycles (1=V, 2=W, etc.)
714 int coarsen_type = solver_param->amgCoarseningMethod();
715 // Ruge coarsening (local) if <val> == 1
716 int relax_default = 3; // relaxation type <val> :
717 // 0=Weighted Jacobi
718 // 1=Gauss-Seidel (very slow!)
719 // 3=Hybrid Jacobi/Gauss-Seidel
720 int num_sweep = 1; // Use <val> sweeps on each level (here 1)
721 int hybrid = 1; // no switch in coarsening if -1
722 int measure_type = 1; // use globale measures
723 double max_row_sum = 1.0; // set AMG maximum row sum threshold for dependency weakening
724
725 int max_levels = 50; // 25; // maximum number of AMG levels
726 const int gamma = solver_param->gamma();
727 if (gamma != -1)
728 max_levels = gamma; // utilisation de la valeur du jeu de donnees
729
730 double strong_threshold = 0.1; // 0.25; // set AMG threshold Theta = val
731 const double alpha = solver_param->alpha();
732 if (alpha > 0.0)
733 strong_threshold = alpha; // utilisation de la valeur du jeu de donnees
734 // news
735 Integer output_level = solver_param->getOutputLevel();
736
741
742 for (int i = 0; i < max_levels; i++)
743 relax_weight[i] = 1.0;
744
745 if (coarsen_type == 5) {
746 /* fine grid */
747 num_grid_sweeps[0] = 3;
750 grid_relax_points[0][0] = -2;
751 grid_relax_points[0][1] = -1;
752 grid_relax_points[0][2] = 1;
753
754 /* down cycle */
755 num_grid_sweeps[1] = 4;
758 grid_relax_points[1][0] = -1;
759 grid_relax_points[1][1] = 1;
760 grid_relax_points[1][2] = -2;
761 grid_relax_points[1][3] = -2;
762
763 /* up cycle */
764 num_grid_sweeps[2] = 4;
767 grid_relax_points[2][0] = -2;
768 grid_relax_points[2][1] = -2;
769 grid_relax_points[2][2] = 1;
770 grid_relax_points[2][3] = -1;
771 }
772 else {
773 /* fine grid */
774 num_grid_sweeps[0] = 2 * num_sweep;
777 for (int i = 0; i < 2 * num_sweep; i += 2) {
778 grid_relax_points[0][i] = -1;
779 grid_relax_points[0][i + 1] = 1;
780 }
781
782 /* down cycle */
783 num_grid_sweeps[1] = 2 * num_sweep;
786 for (int i = 0; i < 2 * num_sweep; i += 2) {
787 grid_relax_points[1][i] = -1;
788 grid_relax_points[1][i + 1] = 1;
789 }
790
791 /* up cycle */
792 num_grid_sweeps[2] = 2 * num_sweep;
795 for (int i = 0; i < 2 * num_sweep; i += 2) {
796 grid_relax_points[2][i] = -1;
797 grid_relax_points[2][i + 1] = 1;
798 }
799 }
800
801 /* coarsest grid */
802 num_grid_sweeps[3] = 1;
803 grid_relax_type[3] = 9;
805 grid_relax_points[3][0] = 0;
806
807 // end of default seting
808
809 HYPRE_BoomerAMGCreate(&precond);
815 HYPRE_BoomerAMGSetMaxIter(precond, 1);
821 HYPRE_BoomerAMGSetTol(precond, 0.0);
824
825 switch (solver_method) {
826 case TypesSolver::PCG:
830 precond);
831 break;
832 case TypesSolver::BiCGStab:
836 precond);
837 break;
838 case TypesSolver::GMRES:
842 precond);
843 break;
844 default:
845 throw ArgumentException("AlephMatrixHypre::setAMGPreconditioner", "solveur inconnu pour preconditionnement 'AMG'\n");
846 }
847 }
848
849 /******************************************************************************
850 *****************************************************************************/
851 bool solvePCG(const AlephParams* solver_param,
856 HYPRE_Int& iteration,
857 double& residue)
858 {
859 const String func_name = "SolverMatrixHypre::solvePCG";
860 const bool xo = solver_param->xoUser();
861 bool error = false;
862
863 if (!xo)
869
872 error |= (!converged);
873
875
876 return !error;
877 }
878
879 /******************************************************************************
880 *****************************************************************************/
881 bool solveBiCGStab(HYPRE_Solver& solver,
885 HYPRE_Int& iteration,
886 double& residue)
887 {
888 const String func_name = "SolverMatrixHypre::solveBiCGStab";
889 bool error = false;
895
898 error |= (!converged);
899
901
902 return !error;
903 }
904
905 /******************************************************************************
906 *****************************************************************************/
907 bool solveGMRES(HYPRE_Solver& solver,
911 HYPRE_Int& iteration,
912 double& residue)
913 {
914 const String func_name = "SolverMatrixHypre::solveGMRES";
915 bool error = false;
920
923 error |= (!converged);
924
926 return !error;
927 }
928
929 private:
930
931 HYPRE_IJMatrix m_hypre_ijmatrix = nullptr;
932 HYPRE_ParCSRMatrix m_hypre_parmatrix = nullptr;
933};
934
935/*---------------------------------------------------------------------------*/
936/*---------------------------------------------------------------------------*/
937
939: public AbstractService
940, public IAlephFactoryImpl
941{
942 public:
945 {}
947 {
948 for ( auto* v : m_IAlephVectors )
949 delete v;
950 for ( auto* v : m_IAlephMatrixs )
951 delete v;
952 }
953
954 public:
955
956 void initialize() override
957 {
958 // NOTE: A partir de la 2.29, on peut utiliser
959 // HYPRE_Initialize() et tester si l'initialisation
960 // a déjà été faite via HYPRE_Initialized().
961#if HYPRE_RELEASE_NUMBER >= 22900
962 if (!HYPRE_Initialized()){
963 info() << "Initializing HYPRE";
965 }
966#elif HYPRE_RELEASE_NUMBER >= 22700
967 info() << "Initializing HYPRE";
968 HYPRE_Init();
969#endif
970
971#if HYPRE_RELEASE_NUMBER >= 22700
974#endif
975 }
976
977 IAlephTopology* createTopology(ITraceMng* tm,
978 AlephKernel* kernel,
979 Integer index,
980 Integer nb_row_size) override
981 {
982 ARCANE_UNUSED(tm);
983 ARCANE_UNUSED(kernel);
984 ARCANE_UNUSED(index);
985 ARCANE_UNUSED(nb_row_size);
986 return NULL;
987 }
988
989 IAlephVector* createVector(ITraceMng* tm,
990 AlephKernel* kernel,
991 Integer index) override
992 {
993 IAlephVector* new_vector = new AlephVectorHypre(tm, kernel, index);
994 m_IAlephVectors.add(new_vector);
995 return new_vector;
996 }
997
998 IAlephMatrix* createMatrix(ITraceMng* tm,
999 AlephKernel* kernel,
1000 Integer index) override
1001 {
1002 IAlephMatrix* new_matrix = new AlephMatrixHypre(tm, kernel, index);
1003 m_IAlephMatrixs.add(new_matrix);
1004 return new_matrix;
1005 }
1006
1007 private:
1008 UniqueArray<IAlephVector*> m_IAlephVectors;
1009 UniqueArray<IAlephMatrix*> m_IAlephMatrixs;
1010};
1011
1012/*---------------------------------------------------------------------------*/
1013/*---------------------------------------------------------------------------*/
1014
1016
1017/*---------------------------------------------------------------------------*/
1018/*---------------------------------------------------------------------------*/
1019
1020}
1021
1022/*---------------------------------------------------------------------------*/
1023/*---------------------------------------------------------------------------*/
#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:120
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