Arcane  v3.15.3.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
AlephTrilinos.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/* AlephTrilinos.cc (C) 2000-2025 */
9/* */
10/* Implémentation Trilinos/Epetra de Aleph. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/aleph/AlephArcane.h"
15
16#include "Epetra_config.h"
17#include "Epetra_Vector.h"
18#include "Epetra_MpiComm.h"
19#include "Epetra_Map.h"
20#include "Epetra_CrsMatrix.h"
21#include "Epetra_LinearProblem.h"
22#include "AztecOO.h"
23#include "ml_MultiLevelPreconditioner.h"
24#include "Ifpack_IC.h"
25
26/*---------------------------------------------------------------------------*/
27/*---------------------------------------------------------------------------*/
28
29namespace Arcane
30{
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
39{
40 public:
41
42 AlephVectorTrilinos(ITraceMng* tm, AlephKernel* kernel, Integer index)
43 : IAlephVector(tm, kernel, index)
44 {
45 debug() << "\t\t[AlephVectorTrilinos::AlephVectorTrilinos] new SolverVectorTrilinos";
46#ifdef HAVE_MPI
47 m_trilinos_Comm = new Epetra_MpiComm(*(MPI_Comm*)(m_kernel->subParallelMng(m_index)->getMPICommunicator()));
48#else
49 m_trilinos_Comm = new Epetra_SerialComm();
50#endif // HAVE_MPI
51 }
52
54 {
55 delete m_trilinos_vector;
56 delete m_trilinos_Comm;
57 }
58
59 public:
60
61 /******************************************************************************
62 * AlephVectorCreate
63 *****************************************************************************/
64 void AlephVectorCreate(void)
65 {
66 debug() << "\t\t[AlephVectorTrilinos::AlephVectorCreate] TRILINOS VectorCreate";
67 Integer jlower = -1;
68 Integer jupper = 0;
69 for (int iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
70 if (m_kernel->rank() != m_kernel->solverRanks(m_index)[iCpu])
71 continue;
72 if (jlower == -1)
73 jlower = m_kernel->topology()->gathered_nb_row(iCpu);
74 jupper = m_kernel->topology()->gathered_nb_row(iCpu + 1) - 1;
75 }
76 Integer size = jupper - jlower + 1;
77 debug() << "\t\t[AlephVectorTrilinos::AlephVectorCreate] jlower=" << jlower << ", jupper=" << jupper;
78 Epetra_Map trilinos_Map = Epetra_Map(m_kernel->topology()->nb_row_size(),
79 size,
80 0,
81 *m_trilinos_Comm);
82 m_trilinos_vector = new Epetra_Vector(trilinos_Map);
83 debug() << "\t\t[AlephVectorTrilinos::AlephVectorCreate] done";
84 }
85
86 /******************************************************************************
87 * AlephVectorSet
88 *****************************************************************************/
89 void AlephVectorSet(const double* bfr_val, const int* bfr_idx, Integer size)
90 {
91 debug() << "\t\t[AlephVectorTrilinos::AlephVectorSet]";
92 m_trilinos_vector->ReplaceGlobalValues(size, bfr_val, bfr_idx);
93 /*#warning DUMPING trilinos
94 for(int i=0; i<size;++i){
95 debug()<<"\t\t[AlephVectorTrilinos::AlephVectorSet] @["<<bfr_idx[i]<<"]="<<bfr_val[i];
96 }*/
97 }
98
99 int AlephVectorAssemble(void)
100 {
101 //m_trilinos_vector->FillComplete();
102 return 0;
103 }
104
105 /******************************************************************************
106 * AlephVectorGet
107 *****************************************************************************/
108 void AlephVectorGet(double* bfr_val, const int* bfr_idx, Integer size)
109 {
110 ARCANE_UNUSED(bfr_idx);
111 debug() << "\t\t[AlephVectorTrilinos::AlephVectorGet]";
112 for (int i = 0; i < size; ++i) {
113 // bfr_val[i]=(*m_trilinos_vector)[bfr_idx[i]];
114 bfr_val[i] = (*m_trilinos_vector)[i];
115 /*#warning DUMPING trilinos
116 debug()<<"\t\t[AlephVectorTrilinos::AlephVectorGet] @["<<i<<"]="<<bfr_val[i];
117*/
118 }
119 }
120
121 /******************************************************************************
122 * writeToFile
123 *****************************************************************************/
124 void writeToFile(const String filename)
125 {
126 ARCANE_UNUSED(filename);
127 debug() << "\t\t[AlephVectorTrilinos::writeToFile]";
128 }
129
130 /******************************************************************************
131 * LinftyNorm
132 * int NormInf (double * Result) const;
133 *****************************************************************************/
134 Real LinftyNorm(void)
135 {
136 Real Result;
137 if (m_trilinos_vector->NormInf(&Result) != 0)
138 throw Exception("LinftyNorm", "NormInf error");
139 return Result;
140 }
141
142 /******************************************************************************
143 * LinftyNorm
144 *****************************************************************************/
145 void fill(Real value)
146 {
147 m_trilinos_vector->PutScalar(value);
148 }
149
150 public:
151 Epetra_Vector* m_trilinos_vector = nullptr;
152 Epetra_Comm* m_trilinos_Comm = nullptr;
153};
154
155/*---------------------------------------------------------------------------*/
156/*---------------------------------------------------------------------------*/
157
158/*---------------------------------------------------------------------------*/
159/*---------------------------------------------------------------------------*/
160
162: public IAlephMatrix
163{
164 public:
165 /******************************************************************************
166 AlephMatrixTrilinos
167 *****************************************************************************/
168 AlephMatrixTrilinos(ITraceMng* tm, AlephKernel* kernel, Integer index)
169 : IAlephMatrix(tm, kernel, index)
170 {
171 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixTrilinos] new AlephMatrixTrilinos";
172#ifdef HAVE_MPI
173 m_trilinos_Comm = new Epetra_MpiComm(*(MPI_Comm*)(m_kernel->subParallelMng(m_index)->getMPICommunicator()));
174#else
175 m_trilinos_Comm = new Epetra_SerialComm();
176#endif // HAVE_MPI
177 }
178
180 {
181 delete m_trilinos_matrix;
182 delete m_trilinos_Comm;
183 }
184
185 /******************************************************************************
186 * AlephMatrixCreate
187 *****************************************************************************/
188 void AlephMatrixCreate(void)
189 {
190 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixCreate] TRILINOS MatrixCreate idx:" << m_index;
191 Integer ilower = -1;
192 Integer iupper = 0;
193 for ( int iCpu = 0; iCpu < m_kernel->size(); ++iCpu) {
194 if (m_kernel->rank() != m_kernel->solverRanks(m_index)[iCpu])
195 continue;
196 if (ilower == -1)
197 ilower = m_kernel->topology()->gathered_nb_row(iCpu);
198 iupper = m_kernel->topology()->gathered_nb_row(iCpu + 1) - 1;
199 }
200 Integer size = iupper - ilower + 1;
201
202 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixCreate] ilower=" << ilower << ", iupper=" << iupper;
203 Integer jlower = ilower;
204 Integer jupper = iupper;
205
206 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixCreate] jlower=" << jlower << ", jupper=" << jupper;
207 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixCreate] global=" << m_kernel->topology()->nb_row_size();
208 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixCreate] size=" << size;
209
210 Epetra_Map trilinos_Map = Epetra_Map(m_kernel->topology()->nb_row_size(),
211 size,
212 0,
213 *m_trilinos_Comm);
214 m_trilinos_matrix = new Epetra_CrsMatrix(Copy,
216 m_kernel->topology()->gathered_nb_row_elements().subView(ilower, size).unguardedBasePointer(),
217 false);
218 }
219
220 /******************************************************************************
221 * AlephMatrixSetFilled
222 *****************************************************************************/
223 void AlephMatrixSetFilled(bool) {}
224
225 /******************************************************************************
226 * AlephMatrixConfigure
227 *****************************************************************************/
228 int AlephMatrixAssemble(void)
229 {
230 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixAssemble] AlephMatrixAssemble";
231 m_trilinos_matrix->FillComplete();
232 return true;
233 }
234
235 /******************************************************************************
236 * AlephMatrixFill
237 *****************************************************************************/
238 void AlephMatrixFill(int size, int* rows, int* cols, double* values)
239 {
240 [[maybe_unused]] int rtn = 0;
241 for (int i = 0; i < size; i++) {
242 // int InsertGlobalValues(int GlobalRow, int NumEntries, double* Values, int* Indices);
243 /*#warning TRILINOS DUMP
244 debug()<<"\t\t[AlephMatrixTrilinos::AlephMatrixFill] A["<<rows[i]<<"]["<<cols[i]<<"]="<<values[i];
245*/
246 rtn += m_trilinos_matrix->InsertGlobalValues(rows[i], 1, &values[i], &cols[i]);
247 }
248
249 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixFill] done";
250 }
251
252 /******************************************************************************
253 * LinftyNormVectorProductAndSub
254 *****************************************************************************/
255 Real LinftyNormVectorProductAndSub(AlephVector* x,
256 AlephVector* b)
257 {
258 ARCANE_UNUSED(x);
259 ARCANE_UNUSED(b);
260 throw FatalErrorException("LinftyNormVectorProductAndSub", "error");
261 }
262
263 /******************************************************************************
264 * isAlreadySolved
265 *****************************************************************************/
266 bool isAlreadySolved(AlephVectorTrilinos* x,
269 Real* residual_norm,
270 AlephParams* params)
271 {
272 const bool convergence_analyse = true; //params->convergenceAnalyse();
273
274 // test le second membre du système linéaire
275 const Real res0 = b->LinftyNorm();
276
278 debug() << "analyse convergence : norme max du second membre res0 : " << res0;
279
280 const Real considered_as_null = params->minRHSNorm();
281 if (res0 < considered_as_null) {
282 x->fill(Real(0.0));
283 residual_norm[0] = res0;
285 debug() << "analyse convergence : le second membre du système linéaire est inférieur à : " << considered_as_null;
286 return true;
287 }
288
289 if (params->xoUser()) {
290 // on test si b est déjà solution du système à epsilon près
291 //matrix->vectorProduct(b, tmp_vector); tmp_vector->sub(x);
292 m_trilinos_matrix->Multiply(false,
293 *x->m_trilinos_vector,
294 *tmp->m_trilinos_vector); // tmp=A*x
295 tmp->m_trilinos_vector->Update(-1.0,
296 *b->m_trilinos_vector,
297 1.0); // tmp=A*x-b
298 const Real residu = tmp->LinftyNorm();
299 //debug() << "[IAlephTrilinos::isAlreadySolved] residu="<<residu;
300
303 debug() << "analyse convergence : |Ax0-b| est inférieur à " << considered_as_null;
304 debug() << "analyse convergence : x0 est déjà solution du système.";
305 }
307 return true;
308 }
309
310 const Real relative_error = residu / res0;
312 debug() << "analyse convergence : résidu initial : " << residu
313 << " --- residu relatif initial (residu/res0) : " << residu / res0;
314
315 if (relative_error < (params->epsilon())) {
317 debug() << "analyse convergence : X est déjà solution du système";
319 return true;
320 }
321 }
323 debug() << "analyse convergence : return false";
324 return false;
325 }
326
327 /******************************************************************************
328 * AlephMatrixSolve
329 *****************************************************************************/
330 int AlephMatrixSolve(AlephVector* x,
331 AlephVector* b,
332 AlephVector* t,
333 Integer& nb_iteration,
334 Real* residual_norm,
336 {
337 Ifpack_IC* ICPrecond = nullptr;
338 Teuchos::ParameterList* MLList = nullptr;
339 ML_Epetra::MultiLevelPreconditioner* MLPrecond = nullptr;
340 const String func_name("SolverMatrixTrilinos::solve");
341
342 AlephVectorTrilinos* x_tri = dynamic_cast<AlephVectorTrilinos*>(x->implementation());
343 AlephVectorTrilinos* b_tri = dynamic_cast<AlephVectorTrilinos*>(b->implementation());
344 AlephVectorTrilinos* t_tri = dynamic_cast<AlephVectorTrilinos*>(t->implementation());
345
349
350 if (isAlreadySolved(x_tri, b_tri, t_tri, residual_norm, solver_param)) {
351 ItacRegion(isAlreadySolved, AlephMatrixSloop);
352 debug() << "\t[AlephMatrixSloop::AlephMatrixSolve] isAlreadySolved !";
353 nb_iteration = 0;
354 return 0;
355 }
356
357 Epetra_Vector* X = x_tri->m_trilinos_vector;
358 Epetra_Vector* B = b_tri->m_trilinos_vector;
359
360 if (!solver_param->xoUser())
361 x_tri->fill(0.0);
362
363 // Create Linear Problem
364 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixSolve] Create Linear Problem";
365 Epetra_LinearProblem problem(m_trilinos_matrix, X, B);
366
367 // Create AztecOO instance
368 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixSolve] Create AztecOO instance";
370 // Options can be: AZ_none AZ_last AZ_summary AZ_warnings
371 solver.SetAztecOption(AZ_output, solver_param->getOutputLevel());
372
373 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixSolve] Setting options";
374 switch (solver_param->method()) {
375 case TypesSolver::PCG:
376 solver.SetAztecOption(AZ_solver, AZ_cg);
377 break;
378 case TypesSolver::BiCGStab:
379 solver.SetAztecOption(AZ_solver, AZ_bicgstab);
380 break;
381 case TypesSolver::BiCGStab2:
382 solver.SetAztecOption(AZ_solver, AZ_bicgstab);
383 break;
384 case TypesSolver::GMRES:
385 solver.SetAztecOption(AZ_solver, AZ_gmres);
386 break;
387 case TypesSolver::SuperLU:
388 solver.SetAztecOption(AZ_solver, AZ_slu);
389 break;
390 default:
391 throw ArgumentException(func_name, "solveur inconnu");
392 }
393
394 switch (solver_param->precond()) {
395 case TypesSolver::NONE:
396 solver.SetAztecOption(AZ_precond, AZ_none);
397 break;
398 case TypesSolver::DIAGONAL:
399 solver.SetAztecOption(AZ_precond, AZ_Jacobi);
400 break;
401 case TypesSolver::ILU: {
402 solver.SetAztecOption(AZ_precond, AZ_dom_decomp);
403 solver.SetAztecOption(AZ_subdomain_solve, AZ_ilu);
404 break;
405 }
406 case TypesSolver::ILUp:
407 solver.SetAztecOption(AZ_precond, AZ_bilu);
408 break;
409 case TypesSolver::POLY:
410 solver.SetAztecOption(AZ_precond, AZ_Neumann);
411 break;
412 case TypesSolver::AMG: { // Taken from trilinos-x.y.z-Source/packages/ml/examples/BasicExamples/*
413 MLList = new Teuchos::ParameterList();
414 /* Setting parameter for aggregation-based preconditioners:
415 - "SA" : classical smoothed aggregation preconditioners;
416 - "NSSA" : default values for Petrov-Galerkin preconditioner for nonsymmetric systems
417 - "maxwell" : default values for aggregation preconditioner for eddy current systems
418 - "DD" : defaults for 2-level domain decomposition preconditioners based on aggregation;
419 - "DD-LU" : Like "DD", but use exact LU decompositions on each subdomain;
420 - "DD-ML" : 3-level domain decomposition preconditioners, with coarser spaces defined by aggregation;
421 - "DD-ML-LU" : Like "DD-ML", but with LU decompositions on each subdomain.
422 */
423 ML_Epetra::SetDefaults("SA", *MLList);
424 //MLList->set("ML output", 10); // output level, 0 being silent and 10 verbose
425 //MLList->set("max levels",16); // maximum number of levels
426 //MLList->set("increasing or decreasing","increasing"); // set finest level to 0
427 MLList->set("cycle applications", solver_param->getAmgSolverIter());
428 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixSolve] Setting cycle application=" << solver_param->getAmgSolverIter();
429 //MLList->set("aggregation: type", "MIS"); // use MIS scheme to create the aggregate
430 //MLList->set("smoother: type","Chebyshev"); // smoother is Chebyshev
431 MLList->set("smoother: sweeps", solver_param->getAmgSmootherIter());
432 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixSolve] Setting smoother: sweeps=" << solver_param->getAmgSmootherIter();
433 //MLList->set("smoother: pre or post", "both"); // use both pre and post smoothing
434 //MLList->set("coarse: type","Amesos-KLU"); // solve with serial direct solver KLU
435 //MLList->set("coarse: max size",32); // maximum allowed coarse size
436 MLList->set("ML debug mode", false);
437
438 MLPrecond = new ML_Epetra::MultiLevelPreconditioner(*m_trilinos_matrix, *MLList);
439 //MLPrecond->PrintUnused(0); // verify unused parameters on process 0 (put -1 to print on all processes)
440 //MLPrecond->AnalyzeHierarchy(true,1,1,1);
441 // MLPrec->ReComputePreconditioner(); // Cheap recompute the preconditioner
442 // It is supposed that the linear system matrix has different values, but
443 // **exactly** the same structure and layout. The code re-built the
444 // hierarchy and re-setup the smoothers and the coarse solver using
445 // already available information on the hierarchy. A particular
446 // care is required to use ReComputePreconditioner() with nonzero threshold.
447 // tell AztecOO to use the ML preconditioner
448 solver.SetPrecOperator(MLPrecond);
449 break;
450 }
451 case TypesSolver::IC: {
452 ICPrecond = new Ifpack_IC(m_trilinos_matrix);
453 IFPACK_CHK_ERR(ICPrecond->Compute());
454 solver.SetPrecOperator(ICPrecond);
455 break;
456 }
457 case TypesSolver::SPAIstat:
458 throw ArgumentException(func_name, "preconditionnement AztecOO::SPAIstat indisponible");
459 case TypesSolver::AINV:
460 throw ArgumentException(func_name, "preconditionnement AztecOO::AINV indisponible");
461 case TypesSolver::SPAIdyn:
462 throw ArgumentException(func_name, "preconditionnement AztecOO::SPAIdyn indisponible");
463 default:
464 throw ArgumentException(func_name, "preconditionnement inconnu");
465 }
466
467 // Déclenchement du solver
468 // Iterates on the current problem until MaxIters or Tolerance is reached.
469 solver.Iterate(solver_param->maxIter(), solver_param->epsilon());
470
471 double norm[1];
472 solver.GetLHS()->Norm2(norm);
473 double real_residual;
474 X->Norm2(&real_residual);
475
476 debug() << "[AlephMatrixTrilinos::AlephMatrixSolve]"
477 // Returns the total number of iterations performed on this problem
478 << "\n\t\tNumIters=" << solver.NumIters()
479 // Returns the true unscaled residual for this problem
480 << "\n\t\tTrueResidual=" << solver.TrueResidual()
481 // Returns the true scaled residual for this problem
482 << "\n\t\tScaledResidual=" << solver.ScaledResidual()
483 // Returns the recursive residual for this problem
484 << "\n\t\tRecursiveResidual=" << solver.RecursiveResidual()
485 << "\n\t\tnorm=" << norm[0]
486 << "\n\t\tRealResidual=" << real_residual;
487
488 nb_iteration = static_cast<Integer>(solver.NumIters());
489 residual_norm[0] = static_cast<Real>(solver.TrueResidual()); // vs ScaledResidual ?
490
491 if (solver_param->maxIter() <= nb_iteration)
492 throw Exception("Nombre max d'itérations du solveur atteint!",
493 "AlephMatrixTrilinos::AlephMatrixSolve");
494 /*if (solver_param->epsilon()<residual_norm[0])
495 throw Exception("Convergence non atteinte!", "AlephMatrixTrilinos::AlephMatrixSolve");
496 */
497
498 if (MLList != NULL)
499 delete MLList;
500 if (MLPrecond != NULL)
501 delete MLPrecond;
502 if (ICPrecond != NULL)
503 delete ICPrecond;
504
505 debug() << "\t\t[AlephMatrixTrilinos::AlephMatrixSolve] done";
506 return nb_iteration;
507 }
508
509 /******************************************************************************
510 * writeToFile
511 *****************************************************************************/
512 void writeToFile(const String filename)
513 {
514 ARCANE_UNUSED(filename);
515 }
516
517 private:
518 Epetra_CrsMatrix* m_trilinos_matrix = nullptr;
519 Epetra_Comm* m_trilinos_Comm = nullptr;
520};
521
522/*---------------------------------------------------------------------------*/
523/*---------------------------------------------------------------------------*/
524
526, public IAlephFactoryImpl
527{
528 public:
531 , m_IAlephVectors(0)
532 , m_IAlephMatrixs(0)
533 {}
535 {
536 for ( auto* v : m_IAlephVectors )
537 delete v;
538 for ( auto* v : m_IAlephMatrixs )
539 delete v;
540 }
541
542 public:
543 virtual void initialize() {}
544 virtual IAlephTopology* createTopology(ITraceMng* tm,
545 AlephKernel* kernel,
546 Integer index,
547 Integer nb_row_size)
548 {
549 ARCANE_UNUSED(tm);
550 ARCANE_UNUSED(kernel);
551 ARCANE_UNUSED(index);
552 ARCANE_UNUSED(nb_row_size);
553 return nullptr;
554 }
555 virtual IAlephVector* createVector(ITraceMng* tm,
556 AlephKernel* kernel,
557 Integer index)
558 {
559 IAlephVector* new_vector = new AlephVectorTrilinos(tm, kernel, index);
560 m_IAlephVectors.add(new_vector);
561 return new_vector;
562 }
563
564 virtual IAlephMatrix* createMatrix(ITraceMng* tm,
565 AlephKernel* kernel,
566 Integer index)
567 {
568 IAlephMatrix* new_matrix = new AlephMatrixTrilinos(tm, kernel, index);
569 m_IAlephMatrixs.add(new_matrix);
570 return new_matrix;
571 }
572
573 private:
574 UniqueArray<IAlephVector*> m_IAlephVectors;
575 UniqueArray<IAlephMatrix*> m_IAlephMatrixs;
576};
577
578/*---------------------------------------------------------------------------*/
579/*---------------------------------------------------------------------------*/
580
582
583/*---------------------------------------------------------------------------*/
584/*---------------------------------------------------------------------------*/
585
586} // End namespace Arcane
587
588/*---------------------------------------------------------------------------*/
589/*---------------------------------------------------------------------------*/
#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 void * getMPICommunicator()=0
Adresse du communicateur MPI associé à ce gestionnaire.
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.
Exception lorsqu'une erreur fatale est survenue.
Interface du gestionnaire de traces.
Chaîne de caractères unicode.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-