TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Adhoc_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 <Adhoc_JFNK.h>
17#include <Schema_Euler_Semi_Implicite.h>
18#include <Schema_Cahn_Hilliard.h>
19#include <Fermeture_Thermo_base.h>
20#include <Potentiel_Chimique_base.h>
21
22// XD adhoc_jfnk solveur_non_lineaire adhoc_jfnk BRACE Hand-rolled (matrix-free) Newton-Krylov GMRES non-linear solver
23// XD_CONT for the Cahn-Hilliard phase-field equation, used when PETSc is not available.
24Implemente_instanciable(Adhoc_JFNK,"Adhoc_JFNK",Solveur_non_lineaire);
25
27{
28 os << "--------------------------------------------------" << finl;
29 os << "SOLVER TYPE = " << que_suis_je() << " " << le_nom() << finl;
30 os << " -- residual threshold = " << tol_ << finl ;
31 os << " -- residue min = " << tol_min_ << finl;
32 os << " -- residue max = " << tol_max_ << finl;
33 os << " -- number of iterations = " << maxit_ << finl;
34 os << " -- Krylov space dimension = " << nkr_ << finl;
35 os << "--------------------------------------------------" << finl;
36 return os ;
37}
38
40{
41 Cerr << "Reading parameters of " << que_suis_je() << " solver ..." << finl;
42 nommer("Captain Adhoc");
43
44 Param param(que_suis_je());
45 param.ajouter("seuil_residu", &tol_, Param::REQUIRED); // XD_ADD_P floattant
46 // XD_CONT Relative convergence threshold of the residual.
47 param.ajouter("dimension_espace_de_krylov", &nkr_, Param::REQUIRED); // XD_ADD_P entier
48 // XD_CONT Dimension of the GMRES Krylov space.
49 param.ajouter("nb_iterations", &maxit_, Param::REQUIRED); // XD_ADD_P entier
50 // XD_CONT Maximum number of GMRES iterations.
51 param.ajouter("residu_min", &tol_min_, Param::REQUIRED); // XD_ADD_P floattant
52 // XD_CONT Minimum (absolute) convergence threshold of the residual.
53 param.ajouter("residu_max", &tol_max_, Param::REQUIRED); // XD_ADD_P floattant
54 // XD_CONT Maximum (absolute) convergence threshold of the residual.
55
56 param.lire_avec_accolades_depuis(is);
57
58 printOn(Cout);
59
60 return is;
61}
62
63/*! @brief Construire le jacobien
64 *
65 */
66DoubleTab Adhoc_JFNK::jacobian_vect(const DoubleTab& v0, DoubleTab& c_theta, Cahn_Hilliard& equation)
67{
68 const double delta = 1.e-5;
69
70 DoubleTrav c_autre_direction(c_theta);
71
72 c_autre_direction = v0;
73 c_autre_direction *= delta;
74 c_autre_direction += c_theta; // c_autre_direction = c_theta + delta * v0
75
76 DoubleTrav v1(v0);
77 DoubleTab v2(v1);
78 v2 = 0.;
79
80 // Construction de la differentielle (dans la direction v0)
81 v2 = equation.fonction_residu(c_autre_direction);
82 v1 = equation.fonction_residu(c_theta);
83
84 v2 -= v1;
85 v2 /= delta; // v2 = [ H(c_autre_direction) - H(c_theta) ] / delta
86
87 return v2;
88}
89
90/*! @brief Permet de résoudre l'équation non linéaire H(c) = c_theta - c_n - theta * dt * M^-1 * D * mu_theta = 0
91 *
92 * inconnue = passe
93 * result = present
94 */
95bool Adhoc_JFNK::iterer_eqn(Equation_base& equation, const DoubleTab& inconnue, DoubleTab& result, double dt, int numero_iteration, int& ok)
96{
97 // Pour le moment, Adhoc_JFNK n'est utilisé que pour l'équation de Cahn_Hilliard
98 if (sub_type(Cahn_Hilliard, equation))
99 {
100 Cout << " -------- [Adhoc_JFNK] Solving..." << finl;
101 }
102 else
103 {
104 Cerr << "[Adhoc_JFNK] Cannot solve any other equation than Cahn_Hilliard yet. Needs to be generalized." << finl;
105 exit();
106 }
107 Cahn_Hilliard& ch = ref_cast(Cahn_Hilliard, equation);
108
109 DoubleTrav c_n(inconnue);
110 DoubleTrav c_theta(inconnue);
111
112 c_n = inconnue;
113 c_theta = result;
114
115 double res;
116
117 DoubleTabs v(nkr_); // Krylov vectors
118 DoubleTrav h(nkr_ + 1, nkr_); // Hessenberg matrix of coefficients
119 DoubleTrav r(nkr_ + 1);
120 DoubleTrav v0(c_theta);
121 DoubleTrav v1(c_theta);
122
123 // v0 = H(c_n)
124 v0 = ch.fonction_residu(c_theta);
125 v0 *= -1.;
127 res = 0.;
128 const int nb_param = v0.line_size();
129
130 // Calcul du premier résidu
131 res = mp_norme_vect(v0); // Norme L2 du champ v0 = H(c_n) (on veut que cela tende vers 0)
132
133 Cout << " - At it = " << 0 << ", residu scalar = " << res << finl;
134
135 if (!Process::me())
136 {
137 SFichier fichier_residu("residu.out", ios::app);
138 fichier_residu << statistics().get_time_since_last_open(STD_COUNTERS::total_execution_time)
139 << "\t" << ch.schema_temps().temps_courant() << "\t" << (double)res << finl;
140 }
141
142 if (res < tol_min_)
143 return 0; // nothing to do
144
145 tol_min_ = (tol_min_ < res * tol_) ? res * tol_ : tol_min_;
147
148 // Ancienne façon de fixer la tolérance : voir avec Didier Jamet...
149 Cout << "Stopping rule scalar : " << tol_min_ << finl;
150
151 // iterations
152 for (int it = 1; it < maxit_+1; it++)
153 {
154
155 // Dimension espace de Krylov
156 int nk = nkr_;
157 v0 /= res; // v0 = H(c_n) normalisé
158 r = 0.;
159 r[0] = res; // Stockage du résidu
160 h = 0.;
161
162 // Début orthogonalisation d'Arnoldi
163 for (int j = 0; j < nkr_; j++)
164 {
166 // Remplissage des vecteurs de base de l'espace de Krylov (stockés dans v)
167 v[j] = v0;
168
169 // Calcul de J*v0 (approximation de la jacobienne par DF)
170 v1 = jacobian_vect(v0, c_theta, ch);
171 v0 = v1;
172
173 // Remplissage de la matrice de Hessenberg
174 for (int i = 0; i <= j; i++)
175 {
176 // Produit scalaire : H_ij = v_i . v_(j+1)
177 DoubleTab& vvi = v[i];
178 h(i,j) += mp_prodscal(v0,vvi);
179
180 // v_(j+1) = v_(j+1) - H_ij v_i
181 for (int ii = 0; ii < v0.dimension(0); ii++)
182 for (int k = 0; k < nb_param; k++)
183 v0(ii, k) -= h(i,j) * vvi(ii, k);
184
186 }
187
188 double tem = mp_norme_vect(v0);
189
190 // H_(j+1,j) = || v_(j+1) ||
191 h(j + 1, j) = tem;
192
193 // Si tem = 0, alors || v_(j+1) || = 0, donc l'espace de Krylov a cessé de grandir --> on sort
194 // Happy breakdown du GMRES
195 if (tem < tol_min_)
196 {
197 nk = j + 1;
198 goto l5naire;
199 }
200 // Normalisation de v_(j+1)
201 v0 /= tem;
202 }
203
204 // Résolution GMRES
205l5naire:
206 // Utilisation de la rotation de Givens
207 // pour triangulariser la matrice de Hessenberg (se débarrasser de la diagonale inférieure)
208 for (int i = 0; i < nk; i++)
209 {
210 int iplus1 = i + 1;
211 double tem = 1. / sqrt(h(i, i) * h(i, i) + h(iplus1, i) * h(iplus1, i));
212 double ccos = h(i, i) * tem;
213 double ssin = -h(iplus1, i) * tem;
214 for (int j = i; j < nk; j++)
215 {
216 tem = h(i, j);
217 h(i, j) = ccos * tem - ssin * h(iplus1,j);
218 h(iplus1, j) = ssin * tem + ccos * h(iplus1,j);
219 }
220 r[iplus1] = ssin * r[i];
221 r[i] *= ccos;
222 }
223
224 // Solution du système linéaire
225 for (int i = nk - 1; i >= 0; i--)
226 {
227 r[i] /= h(i, i);
228 for (int i0 = i - 1; i0 >= 0; i0--)
229 r[i0] -= h(i0, i) * r[i];
230 }
231
232 // La solution est formée d'une combinaison linéaire des vecteurs de base de l'espace de Krylov
233 for(int i=0; i<nk; i++)
234 {
235 DoubleTrav vvi = v[i];
236 vvi = v[i];
237 for (int ii = 0; ii < c_theta.dimension(0); ii++)
238 for (int k = 0; k < nb_param; k++)
239 c_theta(ii, k) += r[i] * vvi(ii, k);
240 }
241 c_theta.echange_espace_virtuel();
242
243 // v0 = H(c_k+1)
244 v0 = ch.fonction_residu(c_theta);
245 v0 *= -1.;
246
247 res = 0.;
248 res=mp_norme_vect(v0);
249
250 Cout << " - At it = " << it << ", residu scalar = " << res << finl;
251
252 double temps_exec = statistics().get_time_since_last_open(STD_COUNTERS::total_execution_time);
253 if (!Process::me())
254 {
255 SFichier fichier_residu("residu.out", ios::app);
256 fichier_residu << temps_exec << "\t" << ch.schema_temps().temps_courant() << "\t" << (double)res << finl;
257 }
258
259 if (res < tol_min_)
260 {
261 // Pour être sûr que ch.inconnue().valeurs() est mis à jour
262 result = c_theta;
263 return it;
264 }
265 else if (it == maxit_)
266 {
267 result = c_theta;
268 // Pour être sûr que ch.inconnue().valeurs() est mis à jour
269 Cerr << "Stopped before convergence" << finl;
270 }
271 }
272
273 return true;
274}
275
276
classe Adhoc_JFNK
Definition Adhoc_JFNK.h:45
double tol_
Definition Adhoc_JFNK.h:61
double tol_max_
Definition Adhoc_JFNK.h:63
bool iterer_eqn(Equation_base &equation, const DoubleTab &inconnue, DoubleTab &result, double dt, int numero_iteration, int &ok) override
Permet de résoudre l'équation non linéaire H(c) = c_theta - c_n - theta * dt * M^-1 * D * mu_theta = ...
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Adhoc_JFNK.h:50
DoubleTab jacobian_vect(const DoubleTab &, DoubleTab &, Cahn_Hilliard &)
Construire le jacobien.
double tol_min_
Definition Adhoc_JFNK.h:62
void nommer(const Nom &name) override
Donne un nom a l'Objet_U Methode virtuelle a surcharger.
Definition Adhoc_JFNK.h:51
classe Cahn_Hilliard
virtual DoubleTab fonction_residu(const DoubleTab &)
Construit la fonction résidu pour un algorithme de Newton :
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
double temps_courant() const
Renvoie le temps courant.
class Solveur_non_lineaire
Classe de base des flux de sortie.
Definition Sortie.h:52
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
int line_size() const
Definition TRUSTVect.tpp:67
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")