TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Sch_CN_EX_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 <Sch_CN_EX_iteratif.h>
17#include <Probleme_base.h>
18#include <Navier_Stokes_std.h>
19#include <Param.h>
20#include <SFichier.h>
21
22Implemente_instanciable(Sch_CN_EX_iteratif,"Sch_CN_EX_iteratif",Sch_CN_iteratif);
23// XD Sch_CN_EX_iteratif Sch_CN_iteratif Sch_CN_EX_iteratif INHERITS_BRACE This keyword also describes a Crank-Nicholson
24// XD_CONT method of second order accuracy but here, for scalars, because of instablities encountered when dt>dt_CFL,
25// XD_CONT the Crank Nicholson scheme is not applied to scalar quantities. Scalars are treated according to
26// XD_CONT Euler-Explicite scheme at the end of the CN treatment for velocity flow fields (by doing p Euler explicite
27// XD_CONT under-iterations at dt<=dt_CFL). Parameters are the sames (but default values may change) compare to the
28// XD_CONT Sch_CN_iterative scheme plus a relaxation keyword: niter_min (2 by default), niter_max (6 by default),
29// XD_CONT niter_avg (3 by default), facsec_max (20 by default), seuil (0.05 by default)
30
32{
34}
35
36
38{
39 seuil=0.05;
40 niter_min=2;
41 niter_max=6;
42 niter_avg=3;
43 facsec_max=20;
44
46
47 return s;
48}
49
51{
52 param.ajouter("omega",&omega); // XD attr omega floattant omega OPT relaxation factor (0.1 by default)
54}
55
56/*! @brief Only takes into account the Navier-Stokes equation of the problem (if there is one). The other equations are not limiting: they perform as many sub-time-steps as needed.
57 *
58 * Code shamelessly copied from Probleme_base::calculer_pas_de_temps()
59 *
60 *
61 */
63{
64 imprimer(Cout);
65 // dt_=dt_max_; The upper bound by dt_max_ is applied in corriger_dt_calcule
66 dt_stab_=DMAXFLOAT;
67 const Probleme_base& prob=pb_base();
68
69 for(int i=0; i<prob.nombre_d_equations(); i++)
70 {
71 const Equation_base& eqn=prob.equation(i);
72 if (sub_type(Navier_Stokes_std,eqn))
73 {
75 break; // At most one Navier-Stokes equation per problem
76 }
77 }
78}
80{
81 Probleme_base& pb = pb_base();
82 Equation_base& eqn = pb.equation(i);
83
84 // Choose based on whether the equation is of Navier_Stokes type or not
85 if (sub_type(Navier_Stokes_std,eqn))
86 return iterateTimeStepOnNS(i,converged);
87 else
88 return iterateTimeStepOnOther(i,converged);
89}
90
91// Very similar to Sch_CN_iteratif::iterateTimeStepOnEquation but applies
92// a relaxation factor omega between iterations.
93
94bool Sch_CN_EX_iteratif::iterateTimeStepOnNS(int i,bool& converged)
95{
96
97 Probleme_base& pb = pb_base();
98 Equation_base& eqn = pb.equation(i);
99
100 double temps_intermediaire=temps_futur(1);
101 double temps_final=temps_futur(2);
102 double dt_intermediaire=temps_intermediaire-temps_courant();
103 double dt_final=temps_final-temps_courant();
104
105 DoubleTab& present = eqn.inconnue().valeurs();
106 DoubleTab& intermediaire = eqn.inconnue().valeurs(temps_intermediaire);
107 DoubleTab& final = eqn.inconnue().valeurs(temps_final);
108
109 DoubleTab dudt(present);
110
111 DoubleTab delta(intermediaire);
112 DoubleTab old(intermediaire);
113
114 // Impose the Dirichlet BCs at the intermediate time.
115 // Indeed, the diffusion operators only use the unknown
116 // and do not read the BCs.
117 // This ensures in particular flux equality in a
118 // coupled thermal VEF problem with Champ_front_contact_VEF, even before convergence.
119 // WEC : /!\ the velocity at the intermediate time
120 // is not necessarily divergence-free.
121 eqn.domaine_Cl_dis().imposer_cond_lim(eqn.inconnue(),temps_intermediaire);
122
123 // Compute the derivative dudt for the intermediate value of the unknown.
124 // Workaround: since operators take the present value by default,
125 // the unknown is temporarily advanced.
126
127 eqn.inconnue().avancer();
128 eqn.derivee_en_temps_inco(dudt);
129 eqn.inconnue().reculer();
130
131 // Update the unknown values at intermediate and final times:
132 // intermediaire = present + dt_intermediaire * dudt;
133 // intermediaire = (1-omega)*new_intermediaire + omega*old_intermediaire
134 // final = present + dt_final * dudt;
135 intermediaire = dudt;
136 intermediaire*= dt_intermediaire;
137 intermediaire+= present;
138 intermediaire*= (1-omega);
139 old*= omega;
140 intermediaire+= old;
141 eqn.domaine_Cl_dis().imposer_cond_lim(eqn.inconnue(),temps_intermediaire);
142 intermediaire.echange_espace_virtuel();
143 final = dudt;
144 final*= dt_final;
145 final+= present;
146
147 eqn.domaine_Cl_dis().imposer_cond_lim(eqn.inconnue(),temps_final);
148 final.echange_espace_virtuel();
149
150 delta*=-1;
151 delta+=intermediaire; // delta = contains u(n+1/2,p+1) - u(n+1/2,p)
152
153 // If the equation has diverged
154 if (divergence(present,intermediaire,delta,iteration))
155 {
156 converged=false;
157 return false;
158 }
159
160 // If the equation has converged
161 if (convergence(present,intermediaire,delta,iteration))
162 {
163 converged=true;
164 delta=final;
165 delta-=present;
166 delta/=dt_final;
167 update_critere_statio(delta, eqn);
168 }
169 else
170 {
172 converged=false;
173 }
174 return true;
175
176}
177
178// Perform several explicit Euler time steps with facsec<=1.
179// One step is required to land exactly on the intermediate time
180// and another exactly on the final time.
181
183{
184 Probleme_base& pb = pb_base();
185 Equation_base& eqn = pb.equation(i);
186
187 double dt_eq=eqn.calculer_pas_de_temps();
188
189 double temps_intermediaire=temps_futur(1);
190 double temps_final=temps_futur(2);
191 double dt_1=temps_intermediaire-temps_courant();
192 double dt_2=temps_final-temps_intermediaire;
193
194 DoubleTab& present = eqn.inconnue().valeurs();
195 DoubleTab& intermediaire = eqn.inconnue().valeurs(temps_intermediaire);
196 DoubleTab& final = eqn.inconnue().valeurs(temps_final);
197
198 DoubleTab dIdt(present); // Pour dimensionner.
199
200 // See Schema_Temps_base::limpr for information on epsilon and modf
201 double nb_dt_1, nb_dt_2;
202 modf(ceil(dt_1/dt_eq), &nb_dt_1); // Number of time steps in the first and second interval.
203 modf(ceil(dt_2/dt_eq), &nb_dt_2);
204
205 double dt_eq_1=dt_1/nb_dt_1; // Duration of time steps in the first and second interval.
206 double dt_eq_2=dt_2/nb_dt_2;
207
208 // Computations on the first time step
209 intermediaire=present;
210 for (double k=0.; k<nb_dt_1; k=k+1.)
211 {
212
213 // Compute the derivative dIdt for the intermediate value of the unknown.
214 // Workaround: since operators take the present value by default,
215 // the unknown is temporarily advanced.
216 eqn.inconnue().avancer();
217 eqn.derivee_en_temps_inco(dIdt);
218 eqn.inconnue().reculer();
219
220 // intermediaire = intermediaire + dt_eq_1 * dIdt
221 dIdt*=dt_eq_1;
222 intermediaire+= dIdt;
223 intermediaire.echange_espace_virtuel();
224
225 }
226
227 // Impose the BCs at the intermediate time
228 eqn.domaine_Cl_dis().imposer_cond_lim(eqn.inconnue(),temps_intermediaire);
229
230
231 // Computations (same) on the second time step
232 final=intermediaire;
233 for (double k=0.; k<nb_dt_2; k=k+1.)
234 {
235
236 // Compute the derivative dIdt for the final value of the unknown.
237 eqn.inconnue().avancer();
238 eqn.inconnue().avancer();
239 eqn.derivee_en_temps_inco(dIdt);
240 eqn.inconnue().reculer();
241 eqn.inconnue().reculer();
242
243 // intermediaire = intermediaire + dt_eq_2 * dIdt
244 dIdt*=dt_eq_2;
245 final+= dIdt;
247
248 }
249 dIdt=final;
250 dIdt-=present;
251 dIdt/=dt_2;
252 update_critere_statio(dIdt, eqn);
253 // Impose the BCs at the final time
254 eqn.domaine_Cl_dis().imposer_cond_lim(eqn.inconnue(),temps_final);
255
256 converged=true;
257 return true;
258
259}
260
261
263{
264
265 if (facsec_!=last_facsec) // Adjust only once per initTimeStep.
266 return;
267
268 switch (cv)
269 {
270 case DIVERGENCE:
271 // the divergence criterion has been reached
273 omega=0.5*(0.5+omega); // drives omega towards 0.5
274 break;
275 case NON_CONVERGENCE:
276 // neither the divergence criterion nor the convergence criterion
277 // was reached in niter_max iterations
279 omega=0.5*(0.5+omega); // (0.5+3*omega)/4; // drives omega towards 0.5, more slowly
280 break;
282 // the convergence criterion was reached in more than niter_avg
283 // iterations
285 if(omega>0.1)
286 omega*=0.95;
287 break;
289 // the convergence criterion was reached in fewer than niter_avg
290 // iterations
292 if(omega>0.1)
293 omega*=0.75;
294 break;
295 case CONVERGENCE_OK:
296 // the convergence criterion was reached in exactly niter_avg iterations
297 facsec_=last_facsec*1.01;
298 break;
299 default:
300 break;
301 }
302 facsec_=std::min(facsec_,facsec_max);
303}
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 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.
virtual double calculer_pas_de_temps() const
Calculation of the next time step.
Navier_Stokes_std This class carries the terms of the momentum equation.
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
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
Extended iterative Crank-Nicolson scheme with additional stabilisation tricks.
virtual bool iterateTimeStepOnOther(int i, bool &converged)
void mettre_a_jour_dt_stab() override
Only takes into account the Navier-Stokes equation of the problem (if there is one)....
virtual bool iterateTimeStepOnNS(int i, bool &converged)
void ajuster_facsec(type_convergence cv) override
void set_param(Param &titi) const override
bool iterateTimeStepOnEquation(int i, bool &converged) override
Computes one iteration of the resolution on equation i.
Time scheme alternating a half implicit Euler step and a half LeapFrog step.
virtual bool divergence(const DoubleTab &u0, const DoubleTab &up1, const DoubleTab &delta, int p) const
Indicates whether the iterative computation has diverged.
virtual bool convergence(const DoubleTab &u0, const DoubleTab &up1, const DoubleTab &delta, int p) const
Indicates whether the iterative computation has converged.
void set_param(Param &titi) const override
double temps_futur(int i) const override
Returns the time at the i-th future value.
double temps_courant() const
Returns the current time.
Probleme_base & pb_base()
virtual void imprimer(Sortie &os) const
Prints the time step to an output stream if appropriate.
double dt_stab_
Stability time step.
void update_critere_statio(const DoubleTab &tab_critere, Equation_base &equation)
Updates stationnaire_atteint_ and residu_ (criterion: residu_ < seuil_statio_).
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")