TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Schema_Euler_Implicite_Stationnaire.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 <Equation_base.h>
17#include <Probleme_base.h>
18#include <Probleme_Couple.h>
19#include <Milieu_base.h>
20#include <Param.h>
21#include <Debog.h>
22#include <LecFicDiffuse.h>
23#include <communications.h>
24#include <string>
25#include <Schema_Euler_Implicite_Stationnaire.h>
26
27Implemente_instanciable(Schema_Euler_Implicite_Stationnaire,"Schema_Euler_Implicite_Stationnaire|Implicit_Euler_Steady_Scheme",Schema_Euler_Implicite);
28// XD Implicit_Euler_Steady_Scheme schema_implicite_base schema_euler_implicite_stationnaire BRACE This is the Implicit
29// XD_CONT Euler scheme using a dual time step procedure (using local and global dt) for steady problems. The only
30// XD_CONT possible solver choice for this scheme is the implicit_steady solver. The stationarity criterion checks all
31// XD_CONT equations (velocity, turbulence, temperature, etc.) using the global seuil_statio threshold. For RANS
32// XD_CONT turbulence models (k-epsilon, k-omega), turbulence variables may exhibit persistent low-amplitude
33// XD_CONT oscillations that prevent the stationarity criterion from being reached. In such cases, it is recommended to
34// XD_CONT set nb_pas_dt_max as the primary stopping criterion and monitor residuals manually. The local time step used
35// XD_CONT as pseudo-inertia is dt_loc = steady_security_factor * facsec * dt_CFL. When facsec_max is set to a finite
36// XD_CONT value, facsec grows dynamically (based on residual reduction) up to facsec_max, accelerating convergence
37// XD_CONT similarly to the standard implicit scheme. Without facsec_max, facsec stays fixed at its initial value
38// XD_CONT (default 1). The pseudo-time displayed in outputs (TIME in .dt_ev) equals the iteration count (dt=1 per
39// XD_CONT step), making it comparable across meshes and convection schemes.
40// XD attr facsec_max floattant facsec_max OPT Maximum ratio allowed between local pseudo-time step and stability time
41// XD_CONT returned by the CFL condition; default is 1 (facsec stays fixed). Setting a value greater than 1 enables
42// XD_CONT dynamic facsec growth.
43
44
46{
48}
49
50
52{
53 // Set default facsec_max to 1 for the steady scheme (parent default is DMAXFLOAT).
54 // With facsec_max = 1, facsec stays fixed at 1 and calcul_fac_sec is never called.
55 // The user can override this by explicitly setting facsec_max > 1 in the data file.
56 facsec_max_ = 1.0;
58 if(!le_solveur)
59 {
60 Cerr << "A solver must be selected." << finl;
61 Cerr << "Syntax : " << finl
62 << "Solveur solver_name [ solver parameters ] " << finl;
64 }
66 {
67 Cerr << "diffusion_implicite option cannot be used with an implicit time scheme." << finl;
69 }
70
71 if (le_solveur->le_nom()!="Implicit_steady")
72 {
73 Cerr << "You can only select the Implicit_steady solver" << finl;
74 Cerr << "Syntax : " << finl
75 << "Solveur Implicit_steady [ solver parameters ] " << finl;
77 }
78
79 return s;
80}
81
88
93
94
96{
97 // Skip Schema_Euler_Implicite::mettre_a_jour() intentionally to avoid
98 // calling calcul_fac_sec() unconditionally.
99 // facsec_ acts as a dynamic CFL multiplier for dt_loc_ (see calculer_pas_de_temps_local_pb).
100 // Default facsec_max = 1: facsec_ stays fixed at 1 (no growth).
101 // Growth is enabled only when the user sets facsec_max > 1.
102 if (facsec_max_ > 1.0)
105}
106
108{
109 // Restore parent data
111 // Force pressure matrix reassembly after restart —
112 // dt_loc_ from previous run is no longer valid
113 dt_loc_.resize(0);
114 return ok;
115}
116
117void Schema_Euler_Implicite_Stationnaire::ajouter_inertie(Matrice_Base& mat_morse,DoubleTab& secmem,const Equation_base& eqn) const
118{
119 // Implicit Euler inertia: adds M/dt_loc to the matrix and M/dt_loc*U^n to the RHS
120 DoubleVect dt_loc = dt_loc_;
121
122 // No penalty on Dirichlet or symmetry boundary faces
123 int pen=0;
124 if (dt_loc.size()!= secmem.size()) // VEF velocity: size = nb_dim*nb_faces, while dt_loc has size nb_faces
125 {
126 int nb_dim=eqn.inconnue().dimension;
127 if(dt_loc.size()* nb_dim == secmem.size())
128 {
129 DoubleVect dt_loc_velocity(secmem);
130 int j = 0;
131 for(int i=0; i<dt_loc_velocity.size(); i++)
132 {
133 if(i != 0 && i%nb_dim == 0) j++;
134 dt_loc_velocity[i]= dt_loc[j];
135 }
136 dt_loc_velocity.echange_espace_virtuel();
137 eqn.solv_masse().ajouter_masse_dt_local(dt_loc_velocity,secmem,eqn.inconnue().passe(),pen);
138 eqn.solv_masse().ajouter_masse_dt_local(dt_loc_velocity,mat_morse,pen);
139 }
140 else if (dt_loc.size()*2==secmem.size())
141 {
142 // k-eps: 2 DOFs per face
143 DoubleVect dt_loc_velocity(secmem);
144 int j = 0;
145 for(int i=0; i<dt_loc_velocity.size(); i++)
146 {
147 if(i != 0 && i%2 == 0) j++;
148 dt_loc_velocity[i]= dt_loc[j];
149 }
150 dt_loc_velocity.echange_espace_virtuel();
151 eqn.solv_masse().ajouter_masse_dt_local(dt_loc_velocity,secmem,eqn.inconnue().passe(),pen);
152 eqn.solv_masse().ajouter_masse_dt_local(dt_loc_velocity,mat_morse,pen);
153 }
154 else
155 {
156 // dt_loc is face-sized (nb_faces), but secmem has a different size.
157 // Known compatible cases:
158 // - VEF velocity: secmem.size() == dt_loc.size() * nb_dim (nb_dim components per face)
159 // - VEF k-eps/k-omega: secmem.size() == dt_loc.size() * 2 (k and eps/omega face-centered)
160 // A mismatch that falls here almost always means the scheme is used with VDF
161 // and a scalar equation (RANS k-eps, k-omega, temperature ...) whose unknowns
162 // are element-centered (nb_elem DOFs) instead of face-centered (nb_faces DOFs).
163 // Implicit_Euler_Steady_Scheme / Implicit_steady is only compatible with VEF
164 // discretization for multi-equation problems (turbulence, thermohydraulics).
165 Cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << finl;
166 Cerr << "Implicit_Euler_Steady_Scheme: incompatible equation detected." << finl;
167 Cerr << " Equation : " << eqn.que_suis_je() << finl;
168 Cerr << " dt_loc.size() = " << dt_loc.size() << " (face-sized, from NS convection operator)" << finl;
169 Cerr << " secmem.size() = " << secmem.size() << " (unknown DOF count for this equation)" << finl;
170 Cerr << finl;
171 Cerr << "This scheme is ONLY compatible with VEF discretization when used" << finl;
172 Cerr << "with RANS turbulence (k-eps, k-omega) or temperature equations." << finl;
173 Cerr << "In VDF, turbulence and scalar unknowns are element-centered (nb_elem)" << finl;
174 Cerr << "while dt_loc is face-centered (nb_faces), which are incompatible." << finl;
175 Cerr << "Please switch to a VEF discretization or use a different time scheme." << finl;
176 Cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << finl;
178 }
179 }
180 else
181 {
182 eqn.solv_masse().ajouter_masse_dt_local(dt_loc,secmem,eqn.inconnue().passe(),pen);
183 eqn.solv_masse().ajouter_masse_dt_local(dt_loc,mat_morse,pen);
184 }
185}
186
188{
189
191 for(int i=1; i< pb_base().nombre_d_equations(); i++)
192 {
193 DoubleTab dt_temp (dt_locaux_);
195 for (int count=0; count<dt_locaux_.size(); count++)
196 {
197 if (dt_locaux_[count] > dt_temp[count])
198 dt_locaux_[count] = dt_temp[count];
199 }
200 }
201
203}
205{
206 // VDF is not supported for multi-equation or turbulent problems:
207 // - Thermohydraulics: nombre_d_equations() > 1 (NS + temperature)
208 // - RANS turbulence: nombre_d_equations() == 1 BUT the NS equation is of type
209 // Navier_Stokes_Turbulent, which internally drives a transport equation (k-eps,
210 // k-omega ...) that Schema_Euler_Implicite solves via faire_un_pas_de_temps_eqn_base.
211 // The local dt_loc coupling is not validated for these cases in VDF and diverges.
212 if (pb_base().discretisation().is_vdf())
213 {
214 bool unsupported = (pb_base().nombre_d_equations() > 1);
215 if (!unsupported)
216 unsupported = pb_base().equation(0).que_suis_je().contient("Turbulent");
217 if (unsupported)
218 {
219 Cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << finl;
220 Cerr << "Implicit_Euler_Steady_Scheme is NOT compatible with VDF" << finl;
221 Cerr << "for turbulent or multi-equation problems." << finl;
222 Cerr << " Discretization : VDF" << finl;
223 Cerr << " Equation(0) : " << pb_base().equation(0).que_suis_je() << finl;
224 Cerr << " Nb equations : " << pb_base().nombre_d_equations() << finl;
225 Cerr << "RANS turbulence (k-eps, k-omega) and temperature equations are" << finl;
226 Cerr << "not supported with this scheme in VDF: the local time-step" << finl;
227 Cerr << "coupling diverges due to inconsistent DOF layout." << finl;
228 Cerr << "Please switch to VEF discretization or use a standard time scheme." << finl;
229 Cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << finl;
231 }
232 }
235 // Force pressure matrix reassembly at first iteration
236 dt_loc_.resize(0);
237}
238
240{
241 imprimer(Cout);
242 if(nb_pas_dt_ <1)
245 max_dt_loc_= dt_locaux_.mp_max_abs_vect();
246
247 // Print dt_loc statistics for the first 5 steps to help the user
248 // assess mesh heterogeneity and check local time step stability.
249 // Skipped afterwards to avoid costly MPI reductions at every step.
250 if (nb_pas_dt_ < 5)
251 {
252 double dt_loc_min = dt_locaux_.mp_min_vect();
253 double dt_loc_max = max_dt_loc_;
254 double dt_loc_sum = mp_somme_vect(dt_locaux_);
255 int dt_loc_n = (int)mp_sum(dt_locaux_.size_reelle());
256 Cout << "dt_loc stats: min=" << dt_loc_min
257 << " max=" << dt_loc_max
258 << " mean=" << dt_loc_sum / dt_loc_n
259 << " ratio_max/min=" << dt_loc_max / (dt_loc_min + 1.e-300) << finl;
260 }
261}
263{
264 bool ok = Schema_Euler_Implicite::iterateTimeStep(converged);
265
266 // After the parent's iterateTimeStep(), test_stationnaire() has run with
267 // divisor dt_ (the CFL-based pseudo-timestep), giving a wrong absolute criterion.
268 // We recompute the stationarity check at every step with the relative criterion:
269 // ||U^{n+1} - U^n|| / ||U^n|| < seuil_statio
270 //
271 // Post-condition left by test_stationnaire():
272 // valeurs() = U^n (restored by "present = passe")
273 // futur() = U^{n+1}
274 {
276 residu_ = 0.;
277 for (int i = 0; i < pb_base().nombre_d_equations(); i++)
278 {
279 Equation_base& eqn = pb_base().equation(i);
280 const DoubleTab& un = eqn.inconnue().valeurs(); // U^n
281 const DoubleTab& unp1 = eqn.inconnue().futur(); // U^{n+1}
282 const double norm_un = mp_norme_vect(un);
283 DoubleTab tab_critere(unp1);
284 tab_critere -= un;
285 tab_critere /= std::max(norm_un, 1.e-10);
286 update_critere_statio(tab_critere, eqn);
287 }
288 }
289
290 return ok;
291}
292
294{
295 // Replicate the RAM print from Schema_Temps_base::corriger_dt_calcule,
296 if (limpr())
297 {
298 Cout << finl;
300 }
301
302 // Set the global pseudo-timestep to 1 so that temps_courant_ = nb_pas_dt.
303 // This makes the TIME axis in outputs and .dt_ev equal to the iteration count,
304 // which is scheme- and mesh-independent and allows meaningful cross-case comparison.
305 dt_global = 1.0;
306 return 1;
307}
DoubleTab & futur(int i=1) override
Renvoie les valeurs du champs a l'instant t+i.
DoubleTab & passe(int i=1) override
Renvoie les valeurs du champs a l'instant t-i.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
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....
Solveur_Masse_base & solv_masse()
Renvoie le solveur de masse associe a l'equation.
virtual const Champ_Inc_base & inconnue() const =0
void calculer_pas_de_temps_locaux(DoubleTab &) const
Classe Matrice_Base Classe de base de la hierarchie des matrices.
bool contient(const Nom &nom) const
Definition Nom.h:86
static int dimension
Definition Objet_U.h:99
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
virtual double calculer_pas_de_temps() const
Calcul la valeur du prochain pas de temps du probleme.
virtual int nombre_d_equations() const =0
virtual const Equation_base & equation(int) const =0
static double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static void imprimer_ram_totale(int all_process=0)
Definition Process.cpp:651
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
bool isStationary() const override
Retourne 1 si lors du dernier pas de temps, le probleme n'a pas evolue.
bool iterateTimeStep(bool &converged) override
Calculate the U(n+1) unknown for each equation (if solved) of the problem with the selected time sche...
int mettre_a_jour() override
Mise a jour du temps courant (t+=dt) et du nombre de pas de temps effectue (nb_pas_dt_++).
bool corriger_dt_calcule(double &dt_calc) const override
Corrige le pas de temps calcule que l'on passe en parametre et verifie qu'il n'est pas "trop" petit (...
void ajouter_inertie(Matrice_Base &mat_morse, DoubleTab &secmem, const Equation_base &eqn) const override
int reprendre(Entree &) override
Reprise d'un Objet_U sur un flot d'entree Methode a surcharger.
int reprendre(Entree &) override
Reprise d'un Objet_U sur un flot d'entree Methode a surcharger.
void set_param(Param &) const override
bool iterateTimeStep(bool &converged) override
Calculate the U(n+1) unknown for each equation (if solved) of the problem with the selected time sche...
void calcul_fac_sec(double &residu_, double &residu_old, double &facsec_)
int diffusion_implicite() const
Renvoie 1 si le schema en temps a ete lu diffusion_implicite.
int limpr() const
Renvoie 1 s'il y a lieu d'effectuer une impression (cf dt_impr) Renvoie 0 sinon.
virtual bool isStationary() const
Retourne 1 si lors du dernier pas de temps, le probleme n'a pas evolue.
Probleme_base & pb_base()
DoubleTab dt_locaux_
Local time steps: Vector of size nb faces of the mesh.
virtual void imprimer(Sortie &os) const
Imprime le pas de temps sur un flot de sortie s'il y a lieu.
virtual void initialize()
virtual int mettre_a_jour()
Mise a jour du temps courant (t+=dt) et du nombre de pas de temps effectue (nb_pas_dt_++).
double dt_stab_
Pas de temps de stabilite.
void update_critere_statio(const DoubleTab &tab_critere, Equation_base &equation)
//Actualisation de stationnaire_atteint_ et residu_ (critere residu_<seuil_statio_)
virtual Matrice_Base & ajouter_masse_dt_local(DoubleVect &dt_locaux, Matrice_Base &matrice, int penalisation=1) const
Classe de base des flux de sortie.
Definition Sortie.h:52
_SIZE_ size() const
Definition TRUSTVect.tpp:45
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")