TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Implicit_steady.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 <Implicit_steady.h>
17#include <Schema_Euler_Implicite_Stationnaire.h>
18#include <Domaine_VF.h>
19#include <Domaine_Cl_VEF.h>
20#include <Navier_Stokes_std.h>
21#include <EChaine.h>
22#include <Debog.h>
23#include <Matrice_Bloc.h>
24#include <Assembleur_base.h>
25#include <Schema_Temps_base.h>
26#include <TRUSTTrav.h>
27#include <Fluide_Quasi_Compressible.h>
28#include <Dirichlet.h>
29#include <Probleme_base.h>
30#include <assert.h>
31
32Implemente_instanciable(Implicit_steady,"Implicit_steady",Simpler);
33// XD implicit_steady implicite implicit_steady BRACE this is the implicit solver using a dual time step. Remark: this
34// XD_CONT solver can be used only with the Implicit_Euler_Steady_Scheme time scheme.
35
37{
38 return Simpler::printOn(os);
39}
40
42{
44 return is;
45}
46
47void test_impose_bound_cond(Equation_base& eqn,DoubleTab& current2,const char * msg,int flag)
48{
49 return;
50 DoubleTab& present = eqn.inconnue().futur();
51 DoubleTab sauv(present);
52 const Schema_Temps_base& sch = eqn.probleme().schema_temps();
54 present -= sauv;
55 double ecart_max=mp_max_abs_vect(present);
56 Cout<<msg <<" "<<ecart_max<<finl;
57
58 if ((ecart_max>1e-10))
59 abort();
60 present = sauv;
61}
62
63
64//This function slightly modifies the "Piso :: iterate_NS with avancement_crank_=0" function in order to take into account a variable time step
65//Use of a variable time step with the IMPLICITE algorithm
66//replaces the global time step with a local time step
67void Implicit_steady::iterer_NS(Equation_base& eqn,DoubleTab& current,DoubleTab& pression, double dt,
68 Matrice_Morse& matrice,double seuil_resol,DoubleTrav& secmem,int nb_iter,int& converge, int& ok)
69{
72 SolveurSys& le_solveur_ = param_eqn.solveur();
73 converge = 1;
74 Navier_Stokes_std& eqnNS = ref_cast(Navier_Stokes_std,eqn);
76 {
77 Cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << finl;
78 Cerr << "Implicit_steady solveur can be used only with the Implicit_Euler_Steady_Scheme or Schema_Euler_Implicite_Stationnaire scheme!" << finl;
79 Cerr << "Please, contact TRUST support." << finl;
81 }
82
83 DoubleTrav gradP(current);
84 DoubleTrav correction_en_pression(pression);
85 DoubleTrav resu(current);
86
87 Operateur_Grad& gradient = eqnNS.operateur_gradient();
88 Operateur_Div& divergence = eqnNS.operateur_divergence();
89
92
93 // --- Update dt_loc_ and decide whether to reassemble the pressure matrix ---
94 // dt_loc_ is compared against the freshly computed dt_locaux_.
95 // If the max relative variation exceeds seuil_variation_dt_ (default 25%),
96 // dt_loc_ is updated and the pressure matrix is reassembled.
97 // Otherwise dt_loc_ is kept from the previous iteration.
98 // All 3 steps use the same dt_loc_, ensuring mathematical consistency:
99 // Step 1 (predictor matrix M/dt_loc + K),
100 // Step 2 (pressure matrix B*(M/dt_loc)^-1*Bt),
101 // Step 3 (velocity correction U = U* - dt_loc * grad(P')).
102 DoubleVect& dt_loc = sch_steady.get_dt_loc();
103 bool need_reassembly = (dt_loc.size() == 0); // first iteration
104 double max_var = 0.;
105 {
106 const DoubleVect dt_loc_new = sch.pas_de_temps_locaux();
107 if (!need_reassembly)
108 {
109 for (int i = 0; i < dt_loc_new.size(); i++)
110 {
111 double var = std::abs(dt_loc_new[i] - dt_loc[i]) / (dt_loc[i] + 1.e-30);
112 max_var = std::max(max_var, var);
113 }
114 max_var = Process::mp_max(max_var);
115 // Reassemble only if variation > threshold AND at a reassembly interval
116 need_reassembly = (max_var > seuil_variation_dt_) && (sch.nb_pas_dt() % reassembly_interval_ == 0);
117 }
118 if (need_reassembly)
119 dt_loc = dt_loc_new;
120 }
121
122 if (max_var == 0. && need_reassembly)
123 Cout << "Implicit_steady: first iteration -> dt_loc_ initialised, pressure matrix reassembled" << finl;
124 else
125 {
126 if (sch.limpr())
127 Cout << "Implicit_steady: dt_loc max relative variation: " << max_var
128 << (need_reassembly ? " -> dt_loc_ updated, pressure matrix reassembled"
129 : " -> dt_loc_ unchanged, pressure matrix reused") << finl;
130 }
131
132 // Step 1: Predictor — assemble K = M/dt_loc + CONV + DIFF and RHS = M/dt_loc*Un - Bt*Pn + Sv
133 // M/dt_loc is incorporated by assembler_avec_inertie via the virtual call
134 // Schema_Euler_Implicite_Stationnaire::ajouter_inertie() which uses dt_loc_.
135 gradient.calculer(pression,gradP);
136 resu -= gradP;
137
138 eqnNS.assembler_avec_inertie(matrice,current,resu);
139 le_solveur_->reinit();
140 Debog::verifier("Implicit_steady::iterer_NS resu apres assembler_avec_inertie",resu);
141
142 Matrice& matrice_en_pression_2 = eqnNS.matrice_pression();
143 SolveurSys& solveur_pression_ = eqnNS.solveur_pression();
144
145 // Solve K*U* = RHS -> current = U*
146 Cout << "Compute U* :" << finl;
147 le_solveur_.resoudre_systeme(matrice,resu,current);
148 test_impose_bound_cond(eqn,current,"apres resolution ",0);
149 Debog::verifier("Implicit_steady::iterer_NS current apres CL",current);
150
151 current.echange_espace_virtuel();
152
153 // Compute RHS of pressure equation: secmem = B*U*
154 if (eqn.probleme().is_dilatable())
155 {
156 Cerr<<"Steady option is not compatible with the quasi/weakly compressible models !"<<finl;
157 Cerr << "Please, contact TRUST support." << finl;
159 }
160 else
161 {
162 divergence.calculer(current,secmem);
163 }
164 secmem *= -1;
165 secmem.echange_espace_virtuel();
166
167 // Step 2: Pressure solve — solve (B*(M/dt_loc)^-1*Bt)*P' = B*U*
168 // correction_en_pression = P'
169 Cout << "Implicit_steady: solving mass equation :" << finl;
170
171 // Compute M/dt_loc using dt_loc_ (same as step 1)
172 DoubleVect m_dt(dt_loc);
173 calcul_mat_masse_diviser_par_dt(eqnNS, m_dt, dt_loc);
174
175 // Reassemble B*(M/dt_loc)^-1*Bt only if dt_loc_ was updated above
176 if (need_reassembly)
177 {
178 eqnNS.assembleur_pression()->assembler_mat(matrice_en_pression_2, m_dt, 1, 1);
179 solveur_pression_->reinit();
180 }
181
182 // Solve (B*(M/dt_loc)^-1*Bt)*P' = B*U*
183 solveur_pression_.resoudre_systeme(matrice_en_pression_2.valeur(),
184 secmem,correction_en_pression);
185 correction_en_pression.echange_espace_virtuel();
186 // Compute M^-1*Bt*P' = grad(P')
187 gradient->multvect(correction_en_pression,gradP);
188 eqn.solv_masse().appliquer(gradP);
189 // Step 3: Velocity correction — U^{n+1} = U* - dt_loc * M^{-1} * Bt * P'
190 int size=gradP.size();
191
192 // Expand dt_loc (face-sized) to velocity-sized: line_size()==1 in VDF, nb_dim in VEF.
193 DoubleVect dt_loc_velocity(current);
194 const int nb_dim = eqnNS.inconnue().valeurs().line_size();
195 assert(dt_loc.size() * nb_dim == dt_loc_velocity.size());
196 int j = 0;
197 for (int i = 0; i < dt_loc_velocity.size(); i++)
198 {
199 if (i != 0 && i % nb_dim == 0) j++;
200 dt_loc_velocity[i] = dt_loc[j];
201 }
202 dt_loc_velocity.echange_espace_virtuel();
203
204 for(int i=0; i<size; i++)
205 {
206 gradP.addr()[i] *=dt_loc_velocity[i]; // dt_loc * grad(P')
207 }
208
210 current -= gradP;
211 test_impose_bound_cond(eqn,current,"apres resolution ",0);
212 // current = U^{n+1}
213 current.echange_espace_virtuel();
214 divergence.calculer(current,secmem);
215
216 // P^{n+1} = P^n + P'
217 pression += correction_en_pression;
218 Debog::verifier("Implicit_steady::iterer_NS pression fin", pression);
219 eqnNS.assembleur_pression()->modifier_solution(pression);
220 pression.echange_espace_virtuel();
221 return;
222}
223// Compute M/dt_loc = rho * V_entrelace * porosite / dt_loc per face.
224void Implicit_steady::calcul_mat_masse_diviser_par_dt(Navier_Stokes_std& eqnNS, DoubleVect& m_dt, const DoubleVect& dt_loc)
225{
226 const Domaine_VF& le_dom = ref_cast(Domaine_VF, eqnNS.domaine_dis());
227 DoubleVect volumes(le_dom.volumes_entrelaces());
228
229 // VEF: override boundary and non-standard interior faces with CL-corrected volumes
230 // (same logic as Assembleur_P_VEF::assembler). VDF has no such correction.
231 if (sub_type(Domaine_Cl_VEF, eqnNS.domaine_Cl_dis()))
232 {
233 const DoubleVect& volumes_cl = ref_cast(Domaine_Cl_VEF, eqnNS.domaine_Cl_dis()).volumes_entrelaces_Cl();
234 for (int f = 0; f < volumes_cl.size(); f++)
235 if (volumes_cl(f) != 0)
236 volumes(f) = volumes_cl(f);
237 }
238 volumes.echange_espace_virtuel();
239
240 const int size = volumes.size_totale();
241 const DoubleVect& porosite = eqnNS.milieu().porosite_face();
242 const bool has_porosity = (porosite.size_totale() == size);
243 const DoubleVect& rho = eqnNS.fluide().masse_volumique().valeurs();
244 const bool rho_per_face = (rho.size_totale() == size);
245 for (int face = 0; face < size; face++)
246 {
247 const double rho_f = rho_per_face ? rho(face) : 1.0;
248 const double por_f = has_porosity ? porosite(face) : 1.0;
249 m_dt(face) = volumes(face) * por_f * rho_f / dt_loc(face);
250 }
252}
DoubleTab & futur(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.
virtual DoubleTab & valeurs()=0
static void verifier(const char *const msg, double)
Definition Debog.cpp:21
virtual void imposer_cond_lim(Champ_Inc_base &, double)=0
class Domaine_VF
Definition Domaine_VF.h:44
DoubleVect & volumes_entrelaces()
Definition Domaine_VF.h:99
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
virtual void assembler_avec_inertie(Matrice_Morse &mat_morse, const DoubleTab &present, DoubleTab &secmem)
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Renvoie le domaine des conditions aux limite discretisee associee a l'equation.
Probleme_base & probleme()
Renvoie le probleme associe a l'equation.
Domaine_dis_base & domaine_dis()
Renvoie le domaine discretise associe a l'equation.
void iterer_NS(Equation_base &, DoubleTab &current, DoubleTab &pression, double, Matrice_Morse &, double, DoubleTrav &, int nb_iter, int &converge, int &ok) override
void calcul_mat_masse_diviser_par_dt(Navier_Stokes_std &eqnNS, DoubleVect &m_dt, const DoubleVect &dt_loc)
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
Classe Matrice Classe generique de la hierarchie des matrices.
Definition Matrice.h:34
virtual const Champ_base & masse_volumique() const
Renvoie la masse volumique du milieu.
DoubleVect & porosite_face()
Definition Milieu_base.h:62
classe Navier_Stokes_std Cette classe porte les termes de l'equation de la dynamique
const Milieu_base & milieu() const override
Renvoie le milieu physique de l'equation (le Fluide_base upcaste en Milieu_base).
const Champ_Inc_base & inconnue() const override
Renvoie la vitesse (champ inconnue de l'equation) (version const).
const Fluide_base & fluide() const
Renvoie le fluide incompressible (milieu physique de l'equation) associe a l'equation.
Operateur_Div & operateur_divergence()
Renvoie l'operateur de calcul de la divergence associe a l'equation.
Operateur_Grad & operateur_gradient()
Renvoie l'operateur de calcul du gradient associe a l'equation.
Matrice & matrice_pression()
SolveurSys & solveur_pression()
Renvoie le solveur en pression (version const).
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
classe Operateur_Div Classe generique de la hierarchie des operateurs calculant la divergence
Classe Operateur_Grad Classe generique de la hierarchie des operateurs calculant le gradient.
classe Parametre_implicite Un objet Parametre_implicite est un objet regroupant les differentes
bool is_dilatable() const
const Schema_Temps_base & schema_temps() const
Renvoie le schema en temps associe au probleme.
static double mp_max(double)
Definition Process.cpp:376
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
class Schema_Temps_base
int limpr() const
Renvoie 1 s'il y a lieu d'effectuer une impression (cf dt_impr) Renvoie 0 sinon.
double temps_courant() const
Renvoie le temps courant.
double pas_de_temps() const
Renvoie le pas de temps (delta_t) courant.
const DoubleTab & pas_de_temps_locaux() const
int nb_pas_dt() const
Renvoie le nombre de pas de temps effectues.
class SolveurSys Un SolveurSys represente n'importe qu'elle classe
Definition SolveurSys.h:32
int resoudre_systeme(const Matrice_Base &matrice, const DoubleVect &secmem, DoubleVect &solution)
Parametre_implicite & get_and_set_parametre_implicite(Equation_base &eqn)
virtual DoubleTab & appliquer(DoubleTab &) const
renvoie appliquer_impl(x/coeffient_temporelle) si on a un coefficient temporel sinon renvoie applique...
Classe de base des flux de sortie.
Definition Sortie.h:52
_TYPE_ * addr()
_SIZE_ size() const
Definition TRUSTVect.tpp:45
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
int line_size() const
Definition TRUSTVect.tpp:67
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")