TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
SNES_JFNK.cpp
1/****************************************************************************
2* Copyright (c) 2021, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <SNES_JFNK.h>
17#include <Cahn_Hilliard.h>
18#include <Schema_Cahn_Hilliard.h>
19#include <Debog.h>
20#include <EcrFicPartageBin.h>
21#include <petsc_for_kernel.h>
22#ifdef PETSCKSP_H
23// Include PETSC library
24#include <petscsnes.h>
25#endif
26
27// XD snes_jfnk solveur_non_lineaire snes_jfnk BRACE Matrix-free Newton-Krylov (JFNK) non-linear solver built on the
28// XD_CONT PETSc SNES framework, used by the Cahn-Hilliard phase-field time schemes.
29Implemente_instanciable(SNES_JFNK,"SNES_JFNK",Solveur_non_lineaire);
30
32{
33 os << "--------------------------------------------------" << finl;
34 os << "SOLVER TYPE = " << que_suis_je() << " " << le_nom() << finl;
35 os << " -- absolute tolerance = " << atol_ << finl ;
36 os << " -- relative tolerance = " << rtol_ << finl;
37 os << " -- stagnation tolerance = " << stol_ << finl;
38 os << " -- max number of iterations of Newton = " << maxit_newton_ << finl;
39 os << " -- max number of iterations of GMRES = " << maxit_gmres_ << finl;
40 os << " -- dimension of Krylov space = " << nkr_ << finl;
41 os << " -- Matrix Free: <<erel>> parameter to compute finite difference step = " << erel_ << finl;
42 os << " -- Matrix Free: <<umin>> parameter to compute finite difference step = " << umin_ << finl;
43 os << "--------------------------------------------------" << finl;
44 return os ;
45}
46
48{
49 Cerr << "Reading parameters of " << que_suis_je() << " solver ..." << finl;
50 nommer("SNES");
51
52 Param param(que_suis_je());
53 param.ajouter("absolute_tol", &atol_, Param::REQUIRED); // XD_ADD_P floattant
54 // XD_CONT Absolute residual tolerance of the Newton iterations.
55 param.ajouter("relative_tol", &rtol_, Param::REQUIRED); // XD_ADD_P floattant
56 // XD_CONT Relative residual tolerance of the Newton iterations.
57 param.ajouter("stagn_tol", &stol_, Param::REQUIRED); // XD_ADD_P floattant
58 // XD_CONT Stagnation (step-size) tolerance of the Newton iterations.
59 param.ajouter("max_it_newton", &maxit_newton_, Param::REQUIRED); // XD_ADD_P entier
60 // XD_CONT Maximum number of Newton iterations.
61 param.ajouter("max_it_GMRES", &maxit_gmres_, Param::REQUIRED); // XD_ADD_P entier
62 // XD_CONT Maximum number of GMRES iterations of the inner linear solve.
63 param.ajouter("dimension_espace_de_krylov", &nkr_, Param::REQUIRED); // XD_ADD_P entier
64 // XD_CONT Dimension (restart) of the GMRES Krylov space.
65 param.ajouter("matrix_free_erel", &erel_, Param::REQUIRED); // XD_ADD_P floattant
66 // XD_CONT Relative step used to build the matrix-free finite-difference Jacobian.
67 param.ajouter("matrix_free_umin", &umin_, Param::REQUIRED); // XD_ADD_P floattant
68 // XD_CONT Minimum step used to build the matrix-free finite-difference Jacobian.
69
70 param.lire_avec_accolades_depuis(is);
71
72 printOn(Cout);
73
74 return is;
75}
76
77/*! @brief FormFunction de PETSc : calcule le résidu du JFNK
78 *
79 * Le vecteur v en entrée est uniquement la concentration
80 */
81#ifdef PETSCKSP_H
82PetscErrorCode FormFunction(SNES snes, Vec v, Vec f, void* ctx)
83{
84 std::pair<Equation_base&, ArrOfTID&>* pair = static_cast< std::pair<Equation_base&, ArrOfTID&> * >(ctx);
85
86 Cahn_Hilliard& ch = ref_cast(Cahn_Hilliard, pair->first);
87 auto& ix = pair->second;
88
89 DoubleTrav c_theta(ch.inconnue().valeurs());
90 DoubleTrav residu(c_theta);
91
92 VecGetValues(v, ix.size_array(), (PetscInt*)ix.addr(), c_theta.addr());
93
94 c_theta.echange_espace_virtuel(); // Virt values are zeros ...
95
96 residu = ch.fonction_residu(c_theta);
97
98 VecSetOption(f, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE);
99 VecSetValues(f, ix.size_array(), (PetscInt*)ix.addr(), residu.addr(), INSERT_VALUES);
100
101 VecAssemblyBegin(f);
102 VecAssemblyEnd(f);
103
104 return 0;
105}
106
107PetscErrorCode SNESMonitor(SNES snes, PetscInt its, PetscReal norm, void* ctx)
108{
109 Equation_base* eqn = static_cast<Equation_base*>(ctx);
110
111 // statistiques().set_debug_level(9);
112 double temps_exec = statistics().get_time_since_last_open(STD_COUNTERS::total_execution_time);
113
114 Cerr << "[SNES] Iteration " << its << " : ||F(x)|| = " << norm << finl;
115
116 if (!Process::me())
117 {
118 SFichier fichier_residu("residu.out", ios::app);
119 fichier_residu << temps_exec << "\t" << eqn->schema_temps().temps_courant() << "\t" << (double)norm << finl;
120 }
121
122 return 0;
123}
124
125PetscErrorCode KSPMonitor(KSP ksp, PetscInt its, PetscReal rnorm, void* ctx)
126{
127 Cerr << " [KSP] Iteration " << its << " : residu = " << rnorm << finl;
128
129 return 0;
130}
131#endif
132/*! @brief Permet de résoudre l'équation non linéaire H(c) = c_theta - c_n - theta * dt * M^-1 * D * mu_theta = 0
133 *
134 * inconnue = passe
135 * result = present
136 */
137bool SNES_JFNK::iterer_eqn(Equation_base& equation, const DoubleTab& inconnue, DoubleTab& result, double dt, int numero_iteration, int& ok)
138{
139#ifdef PETSCKSP_H
140 Debog::verifier("SNES_JFNK::iterer_eqn avant result ", result);
141 // Pour le moment, Adhoc_JFNK n'est utilisé que pour l'équation de Cahn_Hilliard
142 if (sub_type(Cahn_Hilliard, equation))
143 {
144 Cout << " -------- [SNES_JFNK] Solving..." << finl;
145 }
146 else
147 {
148 Cerr << "[SNES_JFNK] Cannot solve any other equation than Cahn_Hilliard yet. Needs to be generalized." << finl;
149 exit();
150 }
151 Cahn_Hilliard& ch = ref_cast(Cahn_Hilliard, equation);
152
153 if (ix.size_array() == 0)
154 construit_renum(inconnue);
155
156 DoubleTrav residu(result);
157 residu = inconnue;
158
159 // Variables SNES ########################################
160 SNES snes; // Contexte SNES
161 Vec v, r; // Vecteurs : solution, résidu
162 KSP ksp;
163 Mat J;
164 PC pc;
165 // #######################################################
166
167 // INITIALISATION DU VECTEUR D'INCONNUES v
168 VecCreate(PETSC_COMM_WORLD, &v);
169 VecSetSizes(v, nb_rows_, nb_rows_tot_);
170 VecSetFromOptions(v);
171
172 // INITIAL GUESS of v
173 VecSetOption(v, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE);
174 VecSetValues(v, ix.size_array(), (PetscInt*)ix.addr(), residu.addr(), INSERT_VALUES);
175 VecAssemblyBegin(v);
176 VecAssemblyEnd(v);
177
178 VecDuplicate(v, &r);
179
180 // Vérification tailles
181 PetscInt v_size, r_size;
182 VecGetSize(v, &v_size);
183 VecGetSize(r, &r_size);
184// assert(v_size == taille_vec && r_size == taille_vec);
185
186 // ---------------------- Compute real values of tolerances ---------------------------
187 // Appel explicite de ta fonction de résidu
188 std::pair<Equation_base&, ArrOfTID&> pair = { ch, ix };
189 FormFunction(nullptr, v, r, &pair);
190
191 // Affiche le résidu (par exemple sa norme)
192 PetscReal norm;
193 VecNorm(r, NORM_2, &norm);
194 PetscPrintf(PETSC_COMM_WORLD, "Résidu F(x) = %g\n", (double)norm);
195
196 // ------------------------------------ SNES ------------------------------------------
197 SNESCreate(PETSC_COMM_WORLD, &snes);
198
199 SNESSetType(snes, SNESNEWTONLS);
200
201 // ========== Associate the FormFunction to the SNES context ============
202 SNESSetFunction(snes, r, FormFunction, &pair);
203 // ======================================================================
204
205 SNESLineSearch linesearch;
206 SNESGetLineSearch(snes, &linesearch); // Newton Line Search ne marche pas dans notre cas
207 // C'est pour ça qu'on le désactive ici
208 SNESLineSearchSetType(linesearch, SNESLINESEARCHNONE); // Désactive la recherche de pas
209
210 // Checking if linesearch is desactivated
211 const char* ls_type;
212 SNESLineSearchGetType(linesearch, &ls_type);
213 PetscPrintf(PETSC_COMM_WORLD, "Type of Line Search used: %s\n", ls_type); // Printing linesearch type
214
215 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
216
217 // Crée la matrice matrix-free à partir du SNES
218 MatCreateSNESMF(snes, &J);
219
220 // Fixe epsilon sur la vraie matrice MF
221 // MatMFFDSetBase(J, delta);
222 MatMFFDSetFunctionError(J, erel_);
223 MatMFFDSetType(J, "ds"); // default: ds (difference scaled), alternative: wp (Walker–Pernice)
224 MatMFFDDSSetUmin(J, umin_);
225
226 SNESSetJacobian(snes, J, J, MatMFFDComputeJacobian, nullptr);
227 // SNESSetJacobian(snes, J, nullptr, nullptr, nullptr);
228
229 MatView(J, PETSC_VIEWER_STDOUT_WORLD);
230 SNESView(snes, PETSC_VIEWER_STDOUT_WORLD);
231 PetscInt local_size, global_size;
232 VecGetLocalSize(v, &local_size);
233 VecGetSize(v, &global_size);
234
235 PetscSynchronizedPrintf(PETSC_COMM_WORLD,
236 "Proc %d : local=%d, global=%d\n",
237 (int)PetscGlobalRank, (int)local_size, (int)global_size);
238 PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT);
239 PetscSynchronizedPrintf(PETSC_COMM_WORLD,
240 "Proc %d : nb_rows=%d, nb_rows_tot=%d\n",
242 PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT);
243 // Pas de Jacobien explicite => JFNK par défaut : SNES construit la matrice par DF entre colonnes
244 // SNESSetJacobian(snes, nullptr, nullptr, SNESComputeJacobianDefault, nullptr);
245 // SNESSetUseMatrixFree(snes, PETSC_TRUE, PETSC_TRUE); // Impose l'option Matrix-Free
246
247 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
248
249 // Tolerance for Newton
250 SNESSetTolerances(snes, atol_, rtol_, stol_, maxit_newton_, 100000);
251
252 // TRES IMPORTANT : Force à continuer l'algorithme de Newton même si la méthode de Krylov n'a pas convergé
253 SNESSetForceIteration(snes, PETSC_TRUE);
254 SNESSetMaxLinearSolveFailures(snes, 200);
255
256 // Vérification
257 PetscBool force_it;
258 SNESGetForceIteration(snes, &force_it);
259 PetscPrintf(PETSC_COMM_WORLD, "Force iteration: %s\n", force_it ? "ON" : "OFF");
260
261 // --------------------------------------- KSP ---------------------------------------------
262 SNESGetKSP(snes, &ksp);
263 KSPSetType(ksp, KSPGMRES); // GMRES
264 KSPGMRESSetRestart(ksp, nkr_); // GMRES(m) avec m la dimension de l'espace de Krylov définie par l'utilisateur
265 // KSPSetType(ksp, KSPCG); // CG
266 // KSPSetInitialGuessNonzero(ksp, PETSC_TRUE); // XXX Luis : PAS BON DU TOUT
267 // PetscOptionsSetValue(nullptr, "-ksp_gmres_orthogonalization", "classical"); // Facultatif : dans notre config, on ne peut pas changer le type d'orthogonalisation
268 KSPSetTolerances(ksp, rtol_, atol_, 5000., maxit_gmres_);
269
270 // -------------------------------- Préconditionneur --------------------------------------
271 KSPGetPC(ksp, &pc);
272 PCSetType(pc, PCNONE); // No preconditionning
273 // PCSetFromOptions(pc);
274
275 // Monitoring
276 // KSPMonitorSet(ksp, KSPMonitor, nullptr, nullptr);
277 SNESMonitorSet(snes, SNESMonitor, &ch, nullptr);
278 //SNESMonitorSet(snes, MySNESMonitorBis, nullptr, nullptr);
279
280 // =============================== Setting from options ===================================
281 // KSPSetFromOptions(ksp); // Lire les options
282
283 // Injecte les options comme si elles venaient de la ligne de commande
284 // PetscOptionsSetValue(nullptr, "-pc_type", "none"); // désactive le préconditionneur
285 // PetscOptionsSetValue(nullptr, "-snes_mf", nullptr); // active matrix-free
286 // PetscOptionsSetValue(nullptr, "-snes_mf_relstep", "1e-5"); // contrôle l’epsilon de l’approximation par différences finies
287
288 PetscOptionsView(nullptr, PETSC_VIEWER_STDOUT_WORLD); // Visu de la liste des options
289 PetscOptionsLeft(nullptr); // Liste celles qui n'ont PAS été utilisées
290
291 // Lecture des options ligne de commande de SNES
292 SNESSetOptionsPrefix(snes, "mysolver_");
293
294 SNESSetFromOptions(snes);
295
296 SNESView(snes, PETSC_VIEWER_STDOUT_SELF);
297
298 // ############################### SOLVING ################################################
299 SNESSolve(snes, nullptr, v); // #
300 // ########################################################################################
301
302
303 const char *reasonstr;
304 SNESGetConvergedReasonString(snes, &reasonstr);
305 Cout << "SNES converged for this reason: " << reasonstr << finl;
306
307 residu = 0;
308 VecGetValues(v, ix.size_array(), (PetscInt*)ix.addr(), residu.addr());
309
310 result = residu;
311 result.echange_espace_virtuel();
312 Debog::verifier("SNES_JFNK::iterer_eqn apres result ", result);
313
314 // Nettoyage
315 VecDestroy(&v);
316 VecDestroy(&r);
317 MatDestroy(&J);
318 SNESDestroy(&snes);
319
320#endif
321 return true;
322}
classe Cahn_Hilliard
static void verifier(const char *const msg, double)
Definition Debog.cpp:21
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
classe Equation_base Le role d'une equation est le calcul d'un ou plusieurs champs....
Schema_Temps_base & schema_temps()
Renvoie le schema en temps associe a l'equation.
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
@ REQUIRED
Definition Param.h:115
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Cette classe est a la classe C++ ofstream ce que la classe Sortie est a la classe C++ ostream Elle re...
Definition SFichier.h:27
classe SNES_JFNK
Definition SNES_JFNK.h:43
void nommer(const Nom &name) override
Donne un nom a l'Objet_U Methode virtuelle a surcharger.
Definition SNES_JFNK.h:49
double umin_
Definition SNES_JFNK.h:64
double atol_
Definition SNES_JFNK.h:57
double erel_
Definition SNES_JFNK.h:63
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition SNES_JFNK.h:48
double stol_
Definition SNES_JFNK.h:59
bool iterer_eqn(Equation_base &equation, const DoubleTab &inconnue, DoubleTab &result, double dt, int numero_iteration, int &ok) override
FormFunction de PETSc : calcule le résidu du JFNK.
int maxit_gmres_
Definition SNES_JFNK.h:61
double rtol_
Definition SNES_JFNK.h:58
int maxit_newton_
Definition SNES_JFNK.h:60
double temps_courant() const
Renvoie le temps courant.
ArrOfTID ix
Definition Solv_tools.h:32
trustIdType nb_rows_tot_
Definition Solv_tools.h:35
void construit_renum(const DoubleVect &)
class Solveur_non_lineaire
Classe de base des flux de sortie.
Definition Sortie.h:52
_TYPE_ * addr()
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")