TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Sch_CN_iteratif.cpp
1/****************************************************************************
2* Copyright (c) 2026, 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 <Navier_Stokes_std.h>
17#include <Sch_CN_iteratif.h>
18#include <communications.h>
19#include <Probleme_base.h>
20#include <Equation_base.h>
21#include <SFichier.h>
22#include <TRUSTTab.h>
23#include <Param.h>
24
25Implemente_instanciable(Sch_CN_iteratif, "Sch_CN_iteratif", Schema_Temps_base);
26// XD Sch_CN_iteratif schema_temps_base Sch_CN_iteratif INHERITS_BRACE The Crank-Nicholson method of second order
27// XD_CONT accuracy. A mid-point rule formulation is used (Euler-centered scheme). The basic scheme is: $$u(t+1) = u(t)
28// XD_CONT + du/dt(t+1/2)*dt$$ The estimation of the time derivative du/dt at the level (t+1/2) is obtained either by
29// XD_CONT iterative process. The time derivative du/dt at the level (t+1/2) is calculated iteratively with a simple
30// XD_CONT under-relaxations method. Since the method is implicit, neither the cfl nor the fourier stability criteria
31// XD_CONT must be respected. The time step is calculated in a way that the iterative procedure converges with the less
32// XD_CONT iterations as possible. NL2 Remark : for stationary or RANS calculations, no limitation can be given for time
33// XD_CONT step through high value of facsec_max parameter (for instance : facsec_max 1000). In counterpart, for LES
34// XD_CONT calculations, high values of facsec_max may engender numerical instabilities.
35
36
38
40
42{
43
44 if (facsec_!=last_facsec) // On n'ajuste qu'une fois pour un initTimeStep.
45 return;
46
47 switch (cv)
48 {
49 case DIVERGENCE:
50 // le critere de divergence a ete atteint
52 break;
53 case NON_CONVERGENCE:
54 // ni le critere de divergence ni le critere de convergence
55 // n'ont ete atteints en niter_max iterations
57 break;
59 // le critere de convergence a ete atteint en plus que niter_avg
60 // iterations
62 break;
64 // le critere de convergence a ete atteint en moins que niter_avg
65 // iterations
67 break;
68 case CONVERGENCE_OK:
69 // le critere de convergence a ete atteint en niter_avg iterations
70 break;
71 default:
72 break;
73 }
74 facsec_=std::min(facsec_,facsec_max);
75}
77{
78 param.ajouter("seuil",&seuil); // XD attr seuil floattant seuil OPT criteria for ending iterative process (Max( ||
79 // XD_CONT u(p) - u(p-1)||/Max || u(p) ||) < seuil) (0.001 by default)
80 param.ajouter("niter_min",&niter_min); // XD attr niter_min entier niter_min OPT minimal number of p-iterations to
81 // XD_CONT satisfy convergence criteria (2 by default)
82 param.ajouter("niter_max",&niter_max); // XD attr niter_max entier niter_max OPT number of maximum p-iterations
83 // XD_CONT allowed to satisfy convergence criteria (6 by default)
84 param.ajouter("niter_avg",&niter_avg); // XD attr niter_avg entier niter_avg OPT threshold of p-iterations (3 by
85 // XD_CONT default). If the number of p-iterations is greater than niter_avg, facsec is reduced, if lesser than
86 // XD_CONT niter_avg, facsec is increased (but limited by the facsec_max value).
87 param.ajouter("facsec_max",&facsec_max);// XD attr facsec_max floattant facsec_max OPT maximum ratio allowed between
88 // XD_CONT dynamical time step returned by iterative process and stability time returned by CFL condition (2 by
89 // XD_CONT default).
91}
92
93
94////////////////////////////////
95// //
96// Caracteristiques du schema //
97// //
98////////////////////////////////
99
100/*! @brief Renvoie le nombre de valeurs temporelles a conserver.
101 *
102 * Ici : n, n+1/2 et n+1, donc 3
103 *
104 */
106{
107 return 3;
108}
109
110/*! @brief Renvoie le nombre de valeurs temporelles futures.
111 *
112 * Ici : n+1/2 et n+1 donc 2.
113 *
114 */
116{
117 return 2;
118}
119
120/*! @brief Renvoie le le temps a la i-eme valeur future.
121 *
122 */
124{
125 assert(i>0 && i<=2);
126 if (i==2)
127 return temps_courant()+pas_de_temps();
128 else
129 return temps_courant()+pas_de_temps()/2;
130}
131
132/*! @brief Renvoie le temps que doivent utiliser les champs a l'appel de valeurs()
133 *
134 * Ici : t(n+1/2)
135 *
136 */
138{
139 return temps_futur(1);
140}
141
142/////////////////////////////////////////
143// //
144// Fin des caracteristiques du schema //
145// //
146/////////////////////////////////////////
147
149{
150
151 if (nb_pas_dt()==0)
152 mettre_a_jour_dt_stab(); // sinon deja appele par validateTimeStep
153 //Plus necessaire car desormais dt_ est mis a jour dans Schema_Temps_base::computeTimeStep(bool& stop)
154 //facsec_=dt/dt_;
156
157 iteration=0;
158
160}
161
162/*! @brief
163 *
164 */
166{
167
168 Probleme_base& pb = pb_base();
169 const int nb_eqn=pb.nombre_d_equations();
170
171 SFichier fic;
172 fic.ouvrir("dt_CN",ios::app);
173
174 if (je_suis_maitre())
175 {
176 fic << "Sch_CN_iteratif : pb= " << pb.le_nom()
177 << " present= " << temps_courant()
178 << " dt= " << dt_
179 << " iteration= " << iteration
180 << " last_facsec= " << last_facsec;
181 }
182 converged=true;
183 bool diverged=false;
184
185 for(int i=0; i<nb_eqn && !diverged; i++)
186 {
187 bool cv;
188 diverged = diverged || !iterateTimeStepOnEquation(i,cv);
189 converged = converged && cv;
190 }
191
192 iteration ++;
194 converged=false; // Continuer a iterer de toutes facons
195
196 // Un peu de bon sens...
197 assert(!(converged&&diverged));
198
199 // Si convergence
200 if (converged)
201 {
202 if (iteration<niter_avg) // Convergence trop rapide, augmenter facsec
204 else if (iteration>niter_avg) // Convergence trop lente, reduire facsec
206 else
208 if (je_suis_maitre())
209 {
210 fic << " facsec= " << facsec_
211 << " result= CONVERGENCE" << finl;
212 }
213 fic.close();
214 return true;
215 }
216
217 // Si divergence
218 else if (diverged)
219 {
221 if (je_suis_maitre())
222 {
223 fic << " facsec= " << facsec_
224 << " result= DIVERGENCE" << finl;
225 }
226 return false;
227 }
228
229 // Si pas converge assez vite
230 else if (iteration==niter_max-1)
231 {
233 if (je_suis_maitre())
234 {
235 fic << " facsec= " << facsec_
236 << " result= NON_CONVERGENCE" << finl;
237 }
238 return false;
239 }
240
241 // Sinon, en cours de convergence
242 if (je_suis_maitre())
243 {
244 fic << " facsec= " << facsec_
245 << " result= CONTINUE" << finl;
246 }
247 return true;
248}
249
250
251/*! @brief Calcule une iteration de la resolution sur l'equation i.
252 *
253 * Calcule u(n+1/2,p+1)=u(n)+f(u(n+1/2,p))*dt/2
254 * et u(n+1,p+1)=u(n)+f(u(n+1/2,p))*dt
255 * ou f donne du/dt en fonction de u
256 * Retourne true dans converged si ca ne bouge plus d'une iteration a l'autre, false sinon
257 * Renvoie true si OK pour continuer a iterer, false sinon (diverge ou trop d'iterations)
258 *
259 */
261{
262
263 Probleme_base& pb = pb_base();
264 Equation_base& eqn = pb.equation(i);
265 if (eqn.equation_non_resolue())
266 {
267 Cout<< "====================================================" << finl;
268 Cout<< eqn.que_suis_je()<<" equation is not solved."<<finl;
269 Cout<< "====================================================" << finl;
270 // On calcule une fois la derivee pour avoir les flux bord
271 if (eqn.schema_temps().nb_pas_dt()==0)
272 {
273 DoubleTab inconnue_valeurs(eqn.inconnue().valeurs());
274 eqn.derivee_en_temps_inco(inconnue_valeurs);
275 }
276 converged=true;
277 return true;
278 }
279 double temps_intermediaire=temps_futur(1);
280 double temps_final=temps_futur(2);
281 double dt_intermediaire=temps_intermediaire-temps_courant();
282 double dt_final=temps_final-temps_courant();
283
284 DoubleTab& present = eqn.inconnue().valeurs();
285 DoubleTab& intermediaire = eqn.inconnue().valeurs(temps_intermediaire);
286 DoubleTab& final = eqn.inconnue().valeurs(temps_final);
287
288 DoubleTab dudt(present);
289
290 DoubleTab delta(intermediaire);
291 delta*=-1;
292
293 // On impose les CLs Dirichlet au temps intermediaire.
294 // En effet, les operateurs de diffusion n'utilisent que
295 // l'inconnue et ne vont pas lire les CLs.
296 // Cela permet en particulier d'avoir l'egalite des flux en pb
297 // couple thermique VEF avec Chap_front_contact_VEF, meme avant convergence.
298 // WEC : /!\ la vitesse au temps intermediaire
299 // n'est pas forcement a divergence nulle.
300 eqn.domaine_Cl_dis().imposer_cond_lim(eqn.inconnue(),temps_intermediaire);
301
302 // Calcul de la derivee dudt pour la valeur intermediaire de l'inconnue.
303 // Bidouille : Comme les operateurs prennent par defaut le present,
304 // on avance temporairement l'inconnue.
305
306 eqn.inconnue().avancer();
307 eqn.derivee_en_temps_inco(dudt);
308 eqn.inconnue().reculer();
309
310 // Mise a jour des valeurs de l'inconnue aux temps intermediaire et final
311 // intermediaire = present + dt_intermediaire * dudt;
312 // final = present + dt_final * dudt;
313 intermediaire = dudt;
314 intermediaire*= dt_intermediaire;
315 intermediaire+= present;
316 eqn.domaine_Cl_dis().imposer_cond_lim(eqn.inconnue(),temps_intermediaire);
317 intermediaire.echange_espace_virtuel();
318 final = dudt;
319 final*= dt_final;
320 final+= present;
321 eqn.domaine_Cl_dis().imposer_cond_lim(eqn.inconnue(),temps_final);
322 final.echange_espace_virtuel();
323
324 delta+=intermediaire; // delta = Contient u(n+1/2,p+1) - u(n+1/2,p)
325
326 // Si l'equation a diverge
327 if (divergence(present,intermediaire,delta,iteration))
328 {
329 converged=false;
330 return false;
331 }
332
333 // Si l'equation a converge
334 if (convergence(present,intermediaire,delta,iteration))
335 {
336 converged=true;
337 delta=final;
338 delta-=present;
339 delta/=dt_final;
340 update_critere_statio(delta, eqn);
341 }
342 else
343 {
345 converged=false;
346 }
347 return true;
348}
349
350
351// WEC : on pourrait le coder, mais ca ne semble pas utile.
352// Ce serait une boucle de IterateTimeStepOnEquation
354{
355 Cerr << "Sch_CN_iteratif::faire_un_pas_de_temps_eqn_base non code!" << finl;
356 exit();
357 return 0;
358}
359
360
361/*! @brief Indique si le calcul iteratif a converge.
362 *
363 * Critere de convergence utilise :
364 * || u(n+1,p+1) - u(n+1,p) || < seuil * || u(n+1/2,p+1) ||
365 * C'est equivalent a
366 * || u(n+1,p) - u(n+1) || < seuil * || (Id-(dt/2).(df/du))^-1 || * || u(n+1/2,p+1) ||
367 * ou u(n+1) est la solution exacte en n+1,
368 * df/du est le lagrangien de f(u), pris en u(n+1/2)
369 * et les normes sont compatibles entre matrices et vecteurs (ici norme infinie).
370 *
371 * @param (DoubleTab& u0) L'inconnue au debut de l'intervalle de temps u(n). C'est aussi la premiere estimation u(n+1/2,0) de l'inconnue en tn+1/2.
372 * @param (DoubleTab& up1) Estimation de l'inconnue en tn+1/2 a l'iteration p+1 : u(n+1/2,p+1)
373 * @param (DoubleTab& delta) u(n+1/2,p+1) - u(n+1/2,p)
374 * @return (bool) true=converge, false=non converge
375 */
376bool Sch_CN_iteratif::convergence(const DoubleTab& u0, const DoubleTab& up1, const DoubleTab& delta, int p) const
377{
378 double a = mp_max_abs_vect(delta);
379 double b = mp_max_abs_vect(up1);
380 int resu = (2. * a) < (seuil * b);
381 envoyer_broadcast(resu, 0); // pour etre certain que tout le monde fait la meme chose
382 return resu;
383}
384
385/*! @brief Indique si le calcul iteratif a diverge.
386 *
387 * @param (DoubleTab& u0) L'inconnue au debut de l'intervalle de temps u(n). C'est aussi la premiere estimation u(n+1/2,0) de l'inconnue en tn+1/2.
388 * @param (DoubleTab& up1) Estimation de l'inconnue en tn+1/2 a l'iteration p+1 : u(n+1/2,p+1)
389 * @param (DoubleTab& delta) u(n+1/2,p+1) - u(n+1/2,p)
390 * @return (bool) true=diverge, false=non diverge
391 */
392bool Sch_CN_iteratif::divergence(const DoubleTab& u0, const DoubleTab& up1, const DoubleTab& delta, int p) const
393{
394 // WEC : ameliorable...
395 return false;
396}
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
Champ_Inc_base & avancer(int i=1)
Avance le pointeur courant de i pas de temps, dans la liste des valeurs temporelles conservees.
Champ_Inc_base & reculer(int i=1)
Recule le pointeur courant de i pas de temps, dans la liste des valeurs temporelles conservees.
virtual void imposer_cond_lim(Champ_Inc_base &, double)=0
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....
virtual int equation_non_resolue() const
virtual const Champ_Inc_base & inconnue() const =0
virtual DoubleTab & derivee_en_temps_inco(DoubleTab &)
Returns the time derivative of the unknown I of the equation: dI/dt = M-1*(sum(operators(I) + sources...
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Renvoie le domaine des conditions aux limite discretisee associee a l'equation.
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
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Probleme_U.h:109
classe Probleme_base C'est un Probleme_U qui n'est pas un couplage.
virtual int nombre_d_equations() const =0
virtual const Equation_base & equation(int) const =0
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
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 Sch_CN_iteratif Schema en temps alternant un demi-pas de temps d'Euler implicite et un demi-pa...
virtual bool iterateTimeStepOnEquation(int i, bool &converged)
Calcule une iteration de la resolution sur l'equation i.
bool initTimeStep(double dt) override
int faire_un_pas_de_temps_eqn_base(Equation_base &) override
virtual bool divergence(const DoubleTab &u0, const DoubleTab &up1, const DoubleTab &delta, int p) const
Indique si le calcul iteratif a diverge.
bool iterateTimeStep(bool &converged) override
Calculate the U(n+1) unknown for each equation (if solved) of the problem with the selected time sche...
virtual bool convergence(const DoubleTab &u0, const DoubleTab &up1, const DoubleTab &delta, int p) const
Indique si le calcul iteratif a converge.
int nb_valeurs_futures() const override
Renvoie le nombre de valeurs temporelles futures.
void set_param(Param &titi) const override
int nb_valeurs_temporelles() const override
Renvoie le nombre de valeurs temporelles a conserver.
double temps_futur(int i) const override
Renvoie le le temps a la i-eme valeur future.
double temps_defaut() const override
Renvoie le temps que doivent utiliser les champs a l'appel de valeurs().
virtual void ajuster_facsec(type_convergence cv)
class Schema_Temps_base
double temps_courant() const
Renvoie le temps courant.
virtual void set_param(Param &titi) const override
double dt_
Pas de temps de calcul.
Probleme_base & pb_base()
double pas_de_temps() const
Renvoie le pas de temps (delta_t) courant.
virtual bool initTimeStep(double dt)
int nb_pas_dt() const
Renvoie le nombre de pas de temps effectues.
virtual void mettre_a_jour_dt_stab()
void update_critere_statio(const DoubleTab &tab_critere, Equation_base &equation)
//Actualisation de stationnaire_atteint_ et residu_ (critere residu_<seuil_statio_)
virtual int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::out)
Classe de base des flux de sortie.
Definition Sortie.h:52
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")