TrioCFD 1.9.9_beta
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
Returns field values at instant t+i.
DoubleTab & valeurs() override
Returns the array of field values at the current time.
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
class Equation_base The role of an equation is the calculation of one or more fields....
Solveur_Masse_base & solv_masse()
Returns the mass solver associated with the 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()
Returns the discretized boundary condition domain associated with the equation.
Probleme_base & probleme()
Returns the problem associated with the equation.
Domaine_dis_base & domaine_dis()
Returns the discretized domain associated with the 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)
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
Matrice class - Generic class in the matrix hierarchy.
Definition Matrice.h:34
virtual const Champ_base & masse_volumique() const
Returns the mass density of the medium (const version).
DoubleVect & porosite_face()
Definition Milieu_base.h:62
Navier_Stokes_std This class carries the terms of the momentum equation.
const Milieu_base & milieu() const override
Returns the physical medium of the equation (Fluide_base upcast to Milieu_base).
const Champ_Inc_base & inconnue() const override
Returns the velocity (unknown field of the equation) (const version).
const Fluide_base & fluide() const
Returns the incompressible fluid (physical medium of the equation) associated with the equation.
Operateur_Div & operateur_divergence()
Returns the divergence operator associated with the equation.
Operateur_Grad & operateur_gradient()
Returns the gradient operator associated with the equation.
Matrice & matrice_pression()
SolveurSys & solveur_pression()
Returns the pressure solver (const version).
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
Operateur_Div Generic class of the hierarchy of operators computing the divergence.
Classe Operateur_Grad Generic class of the hierarchy of operators computing the gradient.
class Parametre_implicite A Parametre_implicite object groups together the various
bool is_dilatable() const
const Schema_Temps_base & schema_temps() const
Returns the time scheme associated with the problem.
static double mp_max(double)
Definition Process.cpp:379
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
class Schema_Temps_base
int limpr() const
Returns 1 if there is a need to perform a print (cf dt_impr) Returns 0 otherwise.
double temps_courant() const
Returns the current time.
double pas_de_temps() const
Returns the current time step (delta_t).
const DoubleTab & pas_de_temps_locaux() const
int nb_pas_dt() const
Returns the number of time steps performed.
class SolveurSys A SolveurSys represents any class
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
Returns appliquer_impl(x/temporal_coefficient) if a temporal coefficient is set, otherwise returns ap...
Base class for output streams.
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")