TrioCFD 1.9.9_beta
TrioCFD documentation
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) // Only adjust once per initTimeStep.
45 return;
46
47 switch (cv)
48 {
49 case DIVERGENCE:
50 // the divergence criterion has been reached
52 break;
53 case NON_CONVERGENCE:
54 // neither the divergence nor the convergence criterion
55 // was reached in niter_max iterations
57 break;
59 // the convergence criterion was reached in more than niter_avg
60 // iterations
62 break;
64 // the convergence criterion was reached in fewer than niter_avg
65 // iterations
67 break;
68 case CONVERGENCE_OK:
69 // the convergence criterion was reached in exactly 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// Scheme characteristics //
97// //
98////////////////////////////////
99
100/*! @brief Returns the number of time values to keep.
101 *
102 * Here: n, n+1/2 and n+1, so 3.
103 *
104 */
106{
107 return 3;
108}
109
110/*! @brief Returns the number of future time values.
111 *
112 * Here: n+1/2 and n+1, so 2.
113 *
114 */
116{
117 return 2;
118}
119
120/*! @brief Returns the time at the i-th future value.
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 Returns the time that fields should use when calling valeurs().
133 *
134 * Here: t(n+1/2).
135 *
136 */
138{
139 return temps_futur(1);
140}
141
142/////////////////////////////////////////
143// //
144// End of scheme characteristics //
145// //
146/////////////////////////////////////////
147
149{
150
151 if (nb_pas_dt()==0)
152 mettre_a_jour_dt_stab(); // otherwise already called by validateTimeStep
153 //No longer necessary since dt_ is now updated in 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; // Continue iterating anyway
195
196 // Sanity check...
197 assert(!(converged&&diverged));
198
199 // If convergence
200 if (converged)
201 {
202 if (iteration<niter_avg) // Convergence too fast, increase facsec
204 else if (iteration>niter_avg) // Convergence too slow, reduce 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 // If 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 // If not converged fast enough
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 // Otherwise, still converging
242 if (je_suis_maitre())
243 {
244 fic << " facsec= " << facsec_
245 << " result= CONTINUE" << finl;
246 }
247 return true;
248}
249
250
251/*! @brief Computes one iteration of the resolution on equation i.
252 *
253 * Computes u(n+1/2,p+1)=u(n)+f(u(n+1/2,p))*dt/2
254 * and u(n+1,p+1)=u(n)+f(u(n+1/2,p))*dt
255 * where f gives du/dt as a function of u.
256 * Returns true in converged if no change between iterations, false otherwise.
257 * Returns true if OK to continue iterating, false otherwise (diverged or too many 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 // Compute the derivative once to obtain the boundary fluxes
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 // Impose Dirichlet BCs at the intermediate time.
294 // Indeed, diffusion operators only use the unknown
295 // and do not read the BCs.
296 // This ensures in particular equal fluxes for coupled
297 // thermal VEF problems with Chap_front_contact_VEF, even before convergence.
298 // WEC: /!\ the velocity at the intermediate time
299 // is not necessarily divergence-free.
300 eqn.domaine_Cl_dis().imposer_cond_lim(eqn.inconnue(),temps_intermediaire);
301
302 // Compute the time derivative dudt for the intermediate value of the unknown.
303 // Trick: since operators take the present value by default,
304 // we temporarily advance the unknown.
305
306 eqn.inconnue().avancer();
307 eqn.derivee_en_temps_inco(dudt);
308 eqn.inconnue().reculer();
309
310 // Update the unknown values at the intermediate and final times:
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 = contains u(n+1/2,p+1) - u(n+1/2,p)
325
326 // If the equation has diverged
327 if (divergence(present,intermediaire,delta,iteration))
328 {
329 converged=false;
330 return false;
331 }
332
333 // If the equation has converged
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: this could be coded, but it doesn't seem useful.
352// It would be a loop over 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 Indicates whether the iterative computation has converged.
362 *
363 * Convergence criterion used:
364 * || u(n+1,p+1) - u(n+1,p) || < seuil * || u(n+1/2,p+1) ||
365 * This is equivalent to:
366 * || u(n+1,p) - u(n+1) || < seuil * || (Id-(dt/2).(df/du))^-1 || * || u(n+1/2,p+1) ||
367 * where u(n+1) is the exact solution at n+1,
368 * df/du is the Jacobian of f(u), taken at u(n+1/2),
369 * and the norms are compatible between matrices and vectors (here the infinity norm).
370 *
371 * @param u0 The unknown at the beginning of the time interval u(n). Also the first estimate u(n+1/2,0).
372 * @param up1 Estimate of the unknown at tn+1/2 at iteration p+1: u(n+1/2,p+1).
373 * @param delta u(n+1/2,p+1) - u(n+1/2,p).
374 * @return true if converged, false otherwise.
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); // to ensure all processes make the same decision
382 return resu;
383}
384
385/*! @brief Indicates whether the iterative computation has diverged.
386 *
387 * @param u0 The unknown at the beginning of the time interval u(n). Also the first estimate u(n+1/2,0).
388 * @param up1 Estimate of the unknown at tn+1/2 at iteration p+1: u(n+1/2,p+1).
389 * @param delta u(n+1/2,p+1) - u(n+1/2,p).
390 * @return true if diverged, false otherwise.
391 */
392bool Sch_CN_iteratif::divergence(const DoubleTab& u0, const DoubleTab& up1, const DoubleTab& delta, int p) const
393{
394 // WEC: could be improved...
395 return false;
396}
DoubleTab & valeurs() override
Returns the array of field values at the current time.
Champ_Inc_base & avancer(int i=1)
Advances the current pointer by i time steps, in the list of kept temporal values.
Champ_Inc_base & reculer(int i=1)
Rewinds the current pointer by i time steps, in the list of kept temporal values.
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
class Equation_base The role of an equation is the calculation of one or more fields....
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()
Returns the discretized boundary condition domain associated with the equation.
Schema_Temps_base & schema_temps()
Returns the time scheme associated with the equation.
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
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
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
Definition Probleme_U.h:109
class Probleme_base It is a Probleme_U that is not a coupling.
virtual int nombre_d_equations() const =0
virtual const Equation_base & equation(int) const =0
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
static int je_suis_maitre()
Returns 1 if on the master processor of the current group (i.e. me() == 0), 0 otherwise.
Definition Process.cpp:82
SFichier is to the C++ ofstream class what Sortie is to the C++ ostream class.
Definition SFichier.h:29
Time scheme alternating a half implicit Euler step and a half LeapFrog step.
virtual bool iterateTimeStepOnEquation(int i, bool &converged)
Computes one iteration of the resolution on 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
Indicates whether the iterative computation has diverged.
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
Indicates whether the iterative computation has converged.
int nb_valeurs_futures() const override
Returns the number of future time values.
void set_param(Param &titi) const override
int nb_valeurs_temporelles() const override
Returns the number of time values to keep.
double temps_futur(int i) const override
Returns the time at the i-th future value.
double temps_defaut() const override
Returns the time that fields should use when calling valeurs().
virtual void ajuster_facsec(type_convergence cv)
class Schema_Temps_base
double temps_courant() const
Returns the current time.
virtual void set_param(Param &titi) const override
double dt_
Computation time step.
Probleme_base & pb_base()
double pas_de_temps() const
Returns the current time step (delta_t).
virtual bool initTimeStep(double dt)
int nb_pas_dt() const
Returns the number of time steps performed.
virtual void mettre_a_jour_dt_stab()
void update_critere_statio(const DoubleTab &tab_critere, Equation_base &equation)
Updates stationnaire_atteint_ and residu_ (criterion: residu_ < seuil_statio_).
virtual int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::out)
Base class for output streams.
Definition Sortie.h:52
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")