TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
QDM_Multiphase.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 <Operateur_Diff_base.h>
17#include <Discretisation_base.h>
18#include <Schema_Temps_base.h>
19#include <Pb_Multiphase_HEM.h>
20#include <Champ_Composite.h>
21#include <TRUSTTab_parts.h>
22#include <QDM_Multiphase.h>
23#include <Discret_Thyd.h>
24#include <Fluide_base.h>
25#include <EChaine.h>
26#include <Param.h>
27#include <vector>
28#include <Nom.h>
29
30Implemente_instanciable(QDM_Multiphase,"QDM_Multiphase",Navier_Stokes_std);
31// XD QDM_Multiphase eqn_base QDM_Multiphase INHERITS_BRACE Momentum conservation equation for a multi-phase problem
32// XD_CONT where the unknown is the velocity
33// XD attr solveur_pression solveur_sys_base solveur_pression OPT Linear pressure system resolution method.
34// XD attr evanescence bloc_lecture evanescence OPT Management of the vanishing phase (when alpha tends to 0 or 1)
35
36// evanescence interprete evanescence 1 Management of the vanishing phase (when alpha tends to 0 or 1)
37// attr homogene chaine homogene 1 Vanishing phases management : tends to homogeneous model when a phase vanishes (vl = vg)
38// attr bloc_val bloc_lecture bloc_val 1 not set
39
40// bloc_lecture interprete nul 1 not set
41// attr alpha_res_min flottant alpha_res_min 0 Activation threshold for full replacement of vanishing phase equation (default value : 0)
42// attr alpha_res flottant alpha_res 0 Activation threshold for gradual replacement of vanishing phase equation (tends to full replacement when alpha tends to alpha_res_min)
43
45{
46 return Equation_base::printOn(is);
47}
48
49/*! @brief Calls Equation_base::readOn(Entree& is). Verifies that the following have been read:
50 *
51 * - the diffusive term,
52 * - the convective term,
53 * - the pressure solver
54 *
55 * @param is Input stream.
56 * @return Modified input stream.
57 * @throws diffusive term not specified in dataset; specify a negligible type for the operator if it is to be neglected
58 * @throws convective term not specified in dataset; specify a negligible type for the operator if it is to be neglected
59 * @throws pressure solver not defined in dataset
60 */
61
63{
64 evanescence_.associer_eqn(*this);
66 assert(le_fluide);
67 if (!sub_type(Fluide_base,le_fluide.valeur()))
68 {
69 Cerr<<"ERROR : the QDM_Multiphase equation can be associated only to a fluid."<<finl;
70 exit();
71 }
72 divergence.set_description((Nom)"Mass flow rate=Integral(rho*u*ndS) [kg.s-1]");
73 terme_convectif->set_incompressible(0);
74
75 const Pb_Multiphase& pb = ref_cast(Pb_Multiphase, probleme());
76 if (!evanescence_ && pb.nb_phases() > 1)
77 {
78 // Special treatment for Pb_Multiphase_HEM : We enforce the evanescence to a specific value
79 if (sub_type(Pb_Multiphase_HEM, probleme()))
80 {
81 EChaine eva("{ homogene { alpha_res 1 alpha_res_min 0.5 } }");
82 eva >> evanescence_;
83 }
84 else
85 {
86 EChaine eva("{ homogene { alpha_res 1e-6 } }");
87 eva >> evanescence_;
88 }
89 }
90
91 /* velocity fields per phase for post-processing */
92 noms_vit_phases_.dimensionner(pb.nb_phases()), vit_phases_.resize(pb.nb_phases());
93 for (int i = 0; i < pb.nb_phases(); i++)
94 noms_vit_phases_[i] = Nom("vitesse_") + pb.nom_phase(i);
95
96 noms_grad_vit_phases_.dimensionner(pb.nb_phases()), grad_vit_phases_.resize(pb.nb_phases());
97 for (int i = 0; i < pb.nb_phases(); i++)
98 noms_grad_vit_phases_[i] = Nom("gradient_vitesse_") + pb.nom_phase(i);
99
100 return is;
101}
102
104{
106 param.ajouter_non_std("evanescence|vanishing",(this));
107}
108
110{
111 if (mot=="evanescence") is >> evanescence_;
113 return 1;
114}
115
121
123{
125 if (evanescence_) ok &= evanescence_->has_interface_blocs();
126 return ok;
127}
128
129/* evanescence is processed last */
130void QDM_Multiphase::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
131{
132 Navier_Stokes_std::dimensionner_blocs(matrices, semi_impl);
133 if (evanescence_) evanescence_->dimensionner_blocs(matrices, semi_impl);
134}
135
136void QDM_Multiphase::assembler_blocs_avec_inertie(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl)
137{
138 Navier_Stokes_std::assembler_blocs_avec_inertie(matrices, secmem, semi_impl);
139 if (evanescence_) evanescence_->ajouter_blocs(matrices, secmem, semi_impl);
140}
141
143{
144 Equation_base::mettre_a_jour(temps); // skip Navier_Stokes_std::mettre_a_jour
145 pression().mettre_a_jour(temps);
146 pression_pa().mettre_a_jour(temps);
147
148 int i, j, n, N = ref_cast(Pb_Multiphase, probleme()).nb_phases(), d, D = dimension;
149 for (n = 0; n < N; n++)
150 if (vit_phases_[n])
151 {
152 vit_phases_[n]->mettre_a_jour(temps);
153 DoubleTab_parts psrc(inconnue().valeurs()), pdst(vit_phases_[n]->valeurs());
154 for (i = 0; i < std::min(psrc.size(), pdst.size()); i++)
155 {
156 DoubleTab& src = psrc[i], &dst = pdst[i];
157 if (src.line_size() == N) /* one column per component */
158 for (j = 0; j < src.dimension_tot(0); j++) dst(j) = src(j, n);
159 else if (src.line_size() == N * D) /* storage N * d + n */
160 for (j = 0; j < src.dimension_tot(0); j++)
161 for (d = 0; d < D; d++)
162 dst(j, d) = src(j, N * d + n);
163 else abort(); // unknown storage layout
164 }
165 }
166
167 if (grad_u) grad_u->mettre_a_jour(temps);
168 if (la_vorticite) la_vorticite->mettre_a_jour(temps);
169 if (Taux_cisaillement) Taux_cisaillement->mettre_a_jour(temps);
170
171 const bool is_vdf = discretisation().is_vdf();
172 for (n = 0; n < N; n++)
173 if (grad_vit_phases_[n])
174 {
175 if (is_vdf)
176 {
177 for (int e = 0; e < domaine_dis().nb_elem(); e++)
178 for (i = 0; i < D; i++)
179 for (j = 0; j < D; j++)
180 grad_vit_phases_[n]->valeurs()(e, D * i + j) = grad_u->valeurs()(e, N * (D * i + j) + n);
181 }
182 else
183 {
184 DoubleTab_parts psrc(grad_u->valeurs()), pdst(grad_vit_phases_[n]->valeurs());
185 for (i = 0; i < psrc.size(); i++)
186 for (j = 0; j < pdst.size(); j++)
187 {
188 DoubleTab& src = psrc[i], &dst = pdst[j];
189 if (src.line_size() == N * D * D && dst.line_size() == D * D) /* une colonne par composante */
190 {
191 for (int k = 0; k < src.dimension_tot(0); k++)
192 for (int dU = 0; dU < D; dU++)
193 for (int dX = 0; dX < D; dX++)
194 dst(k, dX + D * dU) = src(k, dX, dU + n * D); // rows and columns are swapped when going through DoubleTab_parts
195 }
196 }
197 }
198 grad_vit_phases_[n]->mettre_a_jour(temps);
199 }
200 if (gradient_P)
201 {
202 gradient_P->valeurs() = 0;
203 gradient->ajouter(la_pression->valeurs(), gradient_P->valeurs());
205 }
206}
207
209{
211 ConstDoubleTab_parts ppart(pression().valeurs());
212 /* if pression_pa() is smaller than pression() (e.g., auxiliary variables PolyMAC_HFV), copy only the first part */
213 const DoubleTab& p_red = pression_pa().valeurs().dimension_tot(0) < pression().valeurs().dimension_tot(0) ? ppart[0] : pression().valeurs();
214 for (int i=1; i<=sch.nb_valeurs_futures(); i++)
215 {
216 // Update time in the pressure field
220 pression_pa().futur(i) = p_red;
221 }
223}
224
229
231{
232 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
233 dis.vitesse(schema_temps(), domaine_dis(), la_vitesse, ref_cast(Pb_Multiphase, probleme()).nb_phases());
234}
235
237{
238// Does nothing! Called by default in Navier_Stokes_std.discretiser() but not required in Pb_Multiphase.
239// The discretization happens in QDM_Multiphase.creer_champ()
240}
241
243{
244 return le_fluide->viscosite_dynamique();
245}
246
248{
249 return le_fluide->viscosite_cinematique();
250}
251
253{
254 return la_vitesse;
255}
256
257/*! @brief Completes the base equation, associates the pressure to the equation,
258 *
259 * completes the divergence, gradient and pressure solver.
260 * Adds 2 source terms: one representing the centrifugal force
261 * in the axisymmetric case, the other involved in the
262 * 2D axisymmetric resolution.
263 *
264 */
266{
267 Cerr<<" Navier_Stokes_std::completer_deb"<<finl;
269 Cerr<<" Navier_Stokes_std::completer_fin"<<finl;
270 Cerr<<"unknow field type "<<inconnue().que_suis_je()<<finl;
271 Cerr<<"unknow field name "<<inconnue().le_nom()<<finl;
272 Cerr<<"equation type "<<inconnue().equation().que_suis_je()<<finl;
273
274 /* list of things that must be compatible with multiphase */
275 std::vector<const MorEqn*> morceaux = { &solveur_masse.valeur(), &les_sources, &terme_convectif.valeur(), &terme_diffusif.valeur(), &gradient.valeur() };
276 for (auto mor : morceaux) mor->check_multiphase_compatibility();
277}
278
280{
282
283 Noms noms_compris;
284 const Pb_Multiphase& pb = ref_cast(Pb_Multiphase, probleme());
285 for (int i = 0; i < pb.nb_phases(); i++)
286 {
287 noms_compris.add(noms_grad_vit_phases_[i]);
288 noms_compris.add(noms_vit_phases_[i]);
289 }
290 if (opt==DESCRIPTION)
291 Cerr<<" QDM_Multiphase : "<< noms_compris <<finl;
292 else
293 noms.add(noms_compris);
294}
295
297{
299 if (la_vorticite)
300 if (!grad_u) creer_champ("gradient_vitesse");
301 int i = noms_vit_phases_.rang(motlu);
302 if (i >= 0 && !vit_phases_[i])
303 {
305 champs_compris_.ajoute_champ(vit_phases_[i]);
306 }
307 i = noms_grad_vit_phases_.rang(motlu);
308 if (i >= 0 && !grad_vit_phases_[i])
309 {
310 int D = dimension ;
311 Noms noms(D * D), unites(D * D);
312 std::vector<Nom> composantsVitesse({Nom("dU"), Nom("dV"), Nom("dW")});
313 std::vector<Nom> composantsDerivee({Nom("dx"), Nom("dy"), Nom("dz")});
314 for (int dU = 0 ; dU< D ; dU++)
315 for (int dX = 0 ; dX < D ; dX++)
316 {
317 noms[ D * dU + dX]=Nom(composantsVitesse[dU] + composantsDerivee[dX]);
318 unites[ D * dU + dX] = Nom("m2/s");
319 }
320 noms[0] = noms_grad_vit_phases_[i]; // To give it the correct name in discretiser_champ; consequence: the first output coordinate does not have the right name
321 Motcle typeChamp = "champ_elem" ;
322 discretisation().discretiser_champ(typeChamp, domaine_dis(), multi_scalaire, noms , unites, D*D, 0, grad_vit_phases_[0]);
323 champs_compris_.ajoute_champ(grad_vit_phases_[i]);
324 }
325
326 if (motlu == "gradient_pression")
327 {
328 if (!gradient_P)
329 {
330 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
331 dis.gradient_P(schema_temps(), domaine_dis(), gradient_P, ref_cast(Pb_Multiphase, probleme()).nb_phases());
332 champs_compris_.ajoute_champ(gradient_P);
333 }
334 }
335
336}
337
339{
340 Cerr << "Reading of initial conditions\n";
341 Nom nom;
342 is >> nom;
343 if (nom != "{")
344 {
345 Cerr << que_suis_je() << ": expected { instead of " << nom << finl;
347 }
348 int vit_lu = 0, press_lu = 0;
349 for (is >> nom; nom != "}"; is >> nom)
350 if (nom == "vitesse" || nom == "velocity")
351 {
353 is >> src;
354
355 if (src->que_suis_je() == "Champ_Composite")
356 {
357 const int nb_phases = ref_cast(Pb_Multiphase, probleme()).nb_phases(), nb_dim = ref_cast(Champ_Composite,src.valeur()).get_champ_composite_dim();
358 if ( nb_dim != nb_phases)
359 {
360 Cerr << que_suis_je() << ": velocity initial condition Champ_Composite should have "<< nb_phases << " fields and not " << nb_dim << " !" << finl;
362 }
363 }
364
365 verifie_ch_init_nb_comp(la_vitesse, src->nb_comp());
366 la_vitesse->affecter(src), vit_lu = 1;
367 la_vitesse->passe() = la_vitesse->valeurs();
368 }
369 else if (nom == "pression" || nom == "pressure")
370 {
372 is >> src, verifie_ch_init_nb_comp(la_pression, src->nb_comp());
373 la_pression->affecter(src);
374 la_pression_en_pa->passe() = la_pression_en_pa->valeurs() = la_pression->passe() = la_pression->valeurs();
375 press_lu = 1;
376 }
377 else
378 {
379 Cerr << que_suis_je() << ": expected vitesse|velocity|pression|pressure instead of " << nom << finl;
381 }
382
383 if (!vit_lu)
384 {
385 Cerr << que_suis_je() << ": velocity initial condition not found." << finl;
387 }
388 if (!press_lu)
389 {
390 Cerr << que_suis_je() << ": pressure initial condition not found." << finl;
392 }
393
394 return is;
395}
396
398{
399 Equation_base::preparer_calcul(); // to avoid calling Navier_Stokes_std::preparer_calcul() !
400
401 // XXX Elie Saikali : useful for restart case!
402 const double temps = schema_temps().temps_courant();
403 pression().changer_temps(temps);
404 pression_pa().changer_temps(temps);
405
406 if (evanescence_)
407 evanescence_->preparer_calcul();
408
409 return 1;
410}
411
413{
414 const Pb_Multiphase& pb = ref_cast(Pb_Multiphase, probleme());
415 if (pb.nb_phases() == 1) return 0.;
416 if (!evanescence_) Process::exit( "QDM_Multiphase::alpha_res : the evanescence operator should have been created already !" );
417 if sub_type(Operateur_Evanescence_base, evanescence_.valeur()) return ref_cast(Operateur_Evanescence_base, evanescence_.valeur()).alpha_res();
418 return -1.;
419}
class Champ_Don_base base class of Given Fields (not calculated)
DoubleTab & futur(int i=1) override
Returns field values at instant t+i.
void mettre_a_jour(double temps) override
Performs a time update of the unknown field.
double changer_temps(const double temps) override
Sets the time of the field.
DoubleTab & valeurs() override
Returns the array of field values at the current time.
double changer_temps_futur(double, int i=1)
Sets the time of the i-th future field.
class Champ_base This class is the base of the fields hierarchy.
Definition Champ_base.h:43
class Discret_Thyd This class is the base class representing a discretization
void gradient_P(const Schema_Temps_base &, Domaine_dis_base &, OWN_PTR(Champ_Inc_base)&, int nb_comp=1) const
void vitesse(const Schema_Temps_base &, Domaine_dis_base &, OWN_PTR(Champ_Inc_base)&, int nb_comp=1) const
virtual bool is_vdf() const
void discretiser_champ(const Motcle &directive, const Domaine_dis_base &z, const Nom &nom, const Nom &unite, int nb_comp, int nb_pas_dt, double temps, OWN_PTR(Champ_Inc_base)&champ, const Nom &sous_type=NOM_VIDE) const
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual void assembler_blocs_avec_inertie(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={})
const Discretisation_base & discretisation() const
Returns the discretization associated with the equation.
Solveur_Masse_base & solv_masse()
Returns the mass solver associated with the equation.
virtual void mettre_a_jour(double temps)
The value of the unknown at the time step has been calculated.
virtual void abortTimeStep()
Reinitialize what must be.
Sources les_sources
virtual int preparer_calcul()
Everything that does not depend on other possible problems.
Probleme_base & probleme()
Returns the problem associated with the equation.
virtual void verifie_ch_init_nb_comp(const Champ_Inc_base &ch_ref, const int nb_comp) const
Verification of the number of components read for the specification of a field.
Schema_Temps_base & schema_temps()
Returns the time scheme associated with the equation.
virtual bool initTimeStep(double dt)
Allocation and initialization of the unknown and boundary conditions until present+dt.
Champs_compris champs_compris_
Domaine_dis_base & domaine_dis()
Returns the discretized domain associated with the equation.
const Nom & le_nom() const override
Returns the name of the field.
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
const Equation_base & equation() const
Returns the reference to the equation pointed to by MorEqn::mon_equation.
Definition MorEqn.h:62
A character string (Nom) in uppercase.
Definition Motcle.h:26
Navier_Stokes_std This class carries the terms of the momentum equation.
Operateur_Diff terme_diffusif
void dimensionner_matrice_sans_mem(Matrice_Morse &matrice) override
Operateur_Grad gradient
Operateur_Conv terme_convectif
const Champ_Inc_base & inconnue() const override
Returns the velocity (unknown field of the equation) (const version).
void creer_champ(const Motcle &motlu) override
int lire_motcle_non_standard(const Motcle &, Entree &) override
Reads non-simple-type parameters of an Objet_U from an input stream.
void completer() override
Completes the base equation, associates the pressure with the equation,.
Champ_Inc_base & pression_pa()
void get_noms_champs_postraitables(Noms &nom, Option opt=NONE) const override
Operateur_Div divergence
int has_interface_blocs() const override
void set_param(Param &titi) const override
void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={}) const override
OWN_PTR(Assembleur_base) &assembleur_pression()
Champ_Inc_base & pression()
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
An array of character strings (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:71
static int dimension
Definition Objet_U.h:94
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
Generic base class in the operator hierarchy for evanescence management terms.
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter_non_std(const char *keyword, const Objet_U *value, Param::Nature nat=Param::OPTIONAL)
Register a keyword handled by Objet_U::lire_motcle_non_standard.
Definition Param.cpp:489
Multiphase thermohydraulics problem of type "3*N equations":
const Nom & nom_phase(int i) const
int nb_phases() const
static void abort()
Abort routine for TRUST on a fatal error.
Definition Process.cpp:573
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
Carries the terms of the momentum equation for multiphase flow without turbulence modelling.
void completer() override
Completes the base equation, associates the pressure to the equation,.
void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={}) const override
bool initTimeStep(double dt) override
Allocation and initialization of the unknown and boundary conditions until present+dt.
Operateur_Evanescence evanescence_
void get_noms_champs_postraitables(Noms &nom, Option opt=NONE) const override
const Champ_Don_base & diffusivite_pour_transport() const override
void creer_champ(const Motcle &motlu) override
Motcles noms_grad_vit_phases_
void discretiser_vitesse() override
std::vector< OWN_PTR(Champ_Inc_base)> vit_phases_
const Champ_base & vitesse_pour_transport() const override
void discretiser_grad_p() override
void abortTimeStep() override
Reinitialize what must be.
int preparer_calcul() override
cf Equation_base::preparer_calcul() Assembly of the pressure solver and
void assembler_blocs_avec_inertie(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={}) override
double alpha_res() const
Entree & lire_cond_init(Entree &) override
Reading of initial conditions in an input stream.
void set_param(Param &param) const override
void mettre_a_jour(double temps) override
Performs a time update of the equation.
std::vector< OWN_PTR(Champ_Fonc_base)> grad_vit_phases_
int has_interface_blocs() const override
Motcles noms_vit_phases_
const Champ_base & diffusivite_pour_pas_de_temps() const override
void dimensionner_matrice_sans_mem(Matrice_Morse &matrice) override
int lire_motcle_non_standard(const Motcle &, Entree &) override
Reads non-simple-type parameters of an Objet_U from an input stream.
class Schema_Temps_base
double temps_courant() const
Returns the current time.
virtual double temps_futur(int i) const =0
virtual int nb_valeurs_futures() const =0
virtual DoubleTab & appliquer_impl(DoubleTab &x) const =0
Base class for output streams.
Definition Sortie.h:52
int size() const
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
int line_size() const
Definition TRUSTVect.tpp:67