TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Perte_Charge_VEF.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 <Perte_Charge_VEF.h>
17#include <Schema_Temps_base.h>
18#include <Domaine_VEF.h>
19#include <Fluide_Incompressible.h>
20#include <Probleme_base.h>
21#include <Domaine.h>
22#include <Champ_Uniforme.h>
23#include <Sous_Domaine.h>
24#include <Sous_domaine_VF.h>
25#include <Sous_domaine_dis_base.h>
26#include <Champ_P1NC.h>
27#include <Check_espace_virtuel.h>
28#include <Champ_Don_Fonc_xyz.h>
29#include <Champ_Don_Fonc_txyz.h>
30#include <Param.h>
31
32Implemente_base_sans_constructeur(Perte_Charge_VEF,"Perte_Charge_VEF",Source_base);
33
34Perte_Charge_VEF::Perte_Charge_VEF():implicite_(1) { }
35
37{
38 return s << que_suis_je() << finl;
39}
40
42{
43 Param param(que_suis_je());
44 Cerr << que_suis_je() << "::readOn " << finl;
45 lambda.setNbVar(4+dimension);
46 set_param(param);
47 param.lire_avec_accolades_depuis(is);
48 Cerr << "Parsing function " << lambda.getString() << " ... ";
49 lambda.parseString();
50 Cerr << " Ok" << finl;
51 if (diam_hydr->nb_comp()!=1)
52 {
53 Cerr << "The diam_hydr field must be defined with one component" << finl;
54 exit();
55 }
56 return is;
57}
58
60{
61 param.ajouter_non_std("lambda",(this),Param::REQUIRED);
62 param.ajouter("diam_hydr",&diam_hydr,Param::REQUIRED);
63 param.ajouter_non_std("sous_domaine|sous_zone",(this));
64 param.ajouter("implicite",&implicite_);
65}
66
68{
69 if (mot=="lambda")
70 {
71 Nom tmp;
72 is >> tmp;
73 lambda.setString(tmp);
74 lambda.addVar("Re");
75 lambda.addVar("t");
76 lambda.addVar("x");
77 if (dimension>1)
78 lambda.addVar("y");
79 if (dimension>2)
80 lambda.addVar("z");
81 return 1;
82 }
83 else if (mot=="sous_domaine")
84 {
85 is >> nom_sous_domaine;
86 sous_domaine=true;
87 return 1;
88 }
89 else // not recognized
90 {
91 Cerr << "Keyword \"" << mot << "\" not understood when reading a "
92 << que_suis_je() << finl;
93 exit();
94 }
95 return -1;
96}
97
98////////////////////////////////////////////////////////////////
99// //
100// Main function: ajouter //
101// //
102////////////////////////////////////////////////////////////////
103
104namespace
105{
106double valeur_a_la_face(const Champ_Don_base& le_ch, const IntTab& f_e, int f)
107{
108 assert(le_ch.valeurs().line_size() == 1);
109 double s = 0.0, val = 0.0;
110 for (int i = 0, e; i < 2; i++)
111 if ((e = f_e(f, i)) > -1)
112 {
113 val += le_ch.valeurs()(e, 0);
114 s += 1.0;
115 }
116 val /= s;
117 return val;
118}
119}
120
121DoubleTab& Perte_Charge_VEF::ajouter(DoubleTab& resu) const
122{
123 const Domaine_VEF& zvef=le_dom_VEF.valeur();
124 const Champ_Don_base& nu=le_fluide->viscosite_cinematique(); // kinematic viscosity
125 const DoubleTab& xv=zvef.xv() ; // face centers of gravity
126 const DoubleTab& vit=la_vitesse->valeurs();
127 // Otherwise segfault at initialization of ssz when there is no sub-domain!
128 const Sous_domaine_VF& ssz = sous_domaine ? le_sous_domaine_dis.valeur() : Sous_domaine_VF();
129 const IntTab& f_e = zvef.face_voisins();
130
131 // Parameters for perte_charge()
132 DoubleVect u(dimension);
133 DoubleVect pos(dimension);
134 DoubleVect v_valeur(dimension);
135 // Optimizations for cases where nu or diam_hydr are constant
136 const bool nu_constant = sub_type(Champ_Uniforme, nu), dh_constant = sub_type(Champ_Uniforme, diam_hydr.valeur()),
137 nu_xyz = sub_type(Champ_Don_Fonc_xyz, nu) || sub_type(Champ_Don_Fonc_txyz, nu),
138 dh_xyz = sub_type(Champ_Don_Fonc_xyz, diam_hydr.valeur()) || sub_type(Champ_Don_Fonc_txyz, diam_hydr.valeur());
139
140 // Current time
141 double t=equation().schema_temps().temps_courant();
142
143 // Number of faces to process.
144 int max_faces = sous_domaine ? ssz.les_faces().size() : zvef.nb_faces();
145
146 for (int face=0; face<max_faces; face++)
147 {
148 // face index in domaine_VEF
149 int la_face = sous_domaine ? ssz.les_faces()[face] : face;
150
151 if (la_face<zvef.nb_faces())
152 {
153 // Retrieve velocity at the face and compute its magnitude
154 double norme_u=0;
155 for (int dim=0; dim<dimension; dim++)
156 {
157 u[dim]=vit(la_face,dim);
158 norme_u+=u[dim]*u[dim];
159 }
160 norme_u=sqrt(norme_u) ;
161
162 // Compute position
163 for (int i=0; i<dimension; i++)
164 pos[i]=xv(la_face,i);
165
166 const double nu_valeur = nu_constant ? nu.valeurs()(0,0) : (nu_xyz ? nu.valeur_a_compo(pos,0) : ::valeur_a_la_face(nu, f_e, la_face));
167 const double dh_valeur = dh_constant ? diam_hydr->valeurs()(0,0) : (dh_xyz ? diam_hydr->valeur_a_compo(pos,0) : ::valeur_a_la_face(diam_hydr, f_e, la_face));
168
169 // Compute Reynolds number
170 double reynolds=norme_u*dh_valeur/nu_valeur;
171 // Lambda is often undefined for Re->0
172 if (reynolds < 1.e-10)
173 reynolds=1e-10;
174
175 // Compute the integration volume
176 double volume=sous_domaine?
177 ssz.volumes_entrelaces(face) :
178 zvef.volumes_entrelaces(la_face);
179 volume*=equation().milieu().porosite_face(la_face);
180
181 // Compute the final result
182 double coeff_ortho,coeff_long,u_l;
183 coeffs_perte_charge(u,pos,t,norme_u,dh_valeur,nu_valeur,reynolds,coeff_ortho,coeff_long,u_l,v_valeur);
184 for (int dim=0; dim<dimension; dim++)
185 {
186 // The pressure drop equals -coeff_long*u_l*v_valeur[dim] -coeff_ortho(u[dim] -u_v*v_valeur[dim])
187 // i.e. -coeff_ortho* u[dim] - (coeff_long-coeff_ortho)* u_l*v_valeur[dim]
188 resu(la_face,dim)-=(coeff_ortho* u[dim] + (coeff_long-coeff_ortho)* u_l*v_valeur[dim])*volume;
189 }
190 }
191 }
192 return resu;
193}
194
195/*! @brief Copy of ajouter except the last line.
196 *
197 */
198void Perte_Charge_VEF::contribuer_a_avec(const DoubleTab& inco, Matrice_Morse& matrice) const
199{
200 if (implicite_==0) return; // The pressure drop is not implicitized, exit
201
202 // Shortcuts
203 const Champ_Don_base& nu=le_fluide->viscosite_cinematique(); // kinematic viscosity
204 const DoubleTab& xv=le_dom_VEF->xv() ; // face centers of gravity
205 const DoubleTab& vit=la_vitesse->valeurs();
206 // Otherwise segfault at initialization of ssz when there is no sub-domain!
207 const Sous_domaine_VF& ssz=sous_domaine?le_sous_domaine_dis.valeur():Sous_domaine_VF();
208 const Domaine_VEF& zvef=le_dom_VEF.valeur();
209 const IntTab& f_e = zvef.face_voisins();
210
211 // Parameters for perte_charge()
212 DoubleVect u(dimension);
213 double norme_u;
214 double reynolds;
215 DoubleVect pos(dimension);
216 DoubleVect v_valeur(dimension);
217 // Optimizations for cases where nu or diam_hydr are constant
218 const bool nu_constant = sub_type(Champ_Uniforme, nu), dh_constant = sub_type(Champ_Uniforme, diam_hydr.valeur()),
219 nu_xyz = sub_type(Champ_Don_Fonc_xyz, nu) || sub_type(Champ_Don_Fonc_txyz, nu),
220 dh_xyz = sub_type(Champ_Don_Fonc_xyz, diam_hydr.valeur()) || sub_type(Champ_Don_Fonc_txyz, diam_hydr.valeur());
221
222 // Current time
223 double t=equation().schema_temps().temps_courant();
224
225 // Number of faces to process.
226 int max_faces=sous_domaine?
227 ssz.les_faces().size() :
228
229 zvef.nb_faces();
230
231 // To ensure that nu_valeur will not be zero
232 // and not have a division by zero for the calculation of Reynolds
233 assert_espace_virtuel_vect(nu.valeurs());
234
235 for (int face=0; face<max_faces; face++)
236 {
237
238 // face index in domaine_VEF
239 int la_face=sous_domaine?
240 ssz.les_faces()[face] :
241 face;
242
243 // Fixed bug by GF: if the face is a virtual face, skip it because nu is poorly computed and coef(no,no) is invalid
244 if (la_face>=zvef.nb_faces())
245 continue;
246
247 // Retrieve velocity at the face and compute its magnitude
248 norme_u=0;
249 for (int dim=0; dim<dimension; dim++)
250 {
251 u[dim]=vit(la_face,dim);
252 norme_u+=u[dim]*u[dim];
253 }
254 norme_u=sqrt(norme_u) ;
255
256 // Compute position
257 for (int i=0; i<dimension; i++)
258 pos[i]=xv(la_face,i);
259
260 const double nu_valeur = nu_constant ? nu.valeurs()(0,0) : (nu_xyz ? nu.valeur_a_compo(pos,0) : ::valeur_a_la_face(nu, f_e, la_face));
261 const double dh_valeur = dh_constant ? diam_hydr->valeurs()(0,0) : (dh_xyz ? diam_hydr->valeur_a_compo(pos,0) : ::valeur_a_la_face(diam_hydr, f_e, la_face));
262
263 // Compute Reynolds number
264 reynolds=norme_u*dh_valeur/nu_valeur;
265 // Lambda is often undefined for Re->0
266 if (reynolds < 1.e-10)
267 reynolds=1e-10;
268
269 // Compute the integration volume
270 double volume=sous_domaine?
271 ssz.volumes_entrelaces(face) :
272 zvef.volumes_entrelaces(la_face);
273 volume*=equation().milieu().porosite_face(la_face);
274
275 // Compute the final result
276 double coeff_ortho,coeff_long,u_l;
277 coeffs_perte_charge(u,pos,t,norme_u,dh_valeur,nu_valeur,reynolds,coeff_ortho,coeff_long,u_l,v_valeur);
278 for (int dim=0; dim<dimension; dim++)
279 {
280 int n0=la_face*dimension+dim;
281 // matrice.coef(n0,n0) += (coeff_ortho + (coeff_long-coeff_ortho)* v_valeur[dim]*v_valeur[dim]); // Fixed bug
282 matrice.coef(n0,n0) += (coeff_ortho + (coeff_long-coeff_ortho)* v_valeur[dim]*v_valeur[dim])*volume;
283 // The pressure drop equals -coeff_long*u_l*v_valeur[dim] -coeff_ortho(u[dim] -u_v*v_valeur[dim])
284 // i.e. -coeff_ortho* u[dim] - (coeff_long-coeff_ortho)* u_l*v_valeur[dim]
285 // resu(la_face,dim)-=(coeff_ortho* u[dim] + (coeff_long-coeff_ortho)* u_l*v_valeur[dim]);
286 }
287 }
288}
289
290DoubleTab& Perte_Charge_VEF::calculer(DoubleTab& resu) const
291{
292 resu=0;
293 return ajouter(resu);
294}
295
296
298{
300
301 if (sous_domaine)
302 {
303 sous_domaine=false;
304 const Sous_Domaine& le_sous_domaine=equation().probleme().domaine().ss_domaine(nom_sous_domaine);
305 const Domaine_dis_base& le_domaine_dis=le_dom_VEF.valeur();
306 for (int ssz=0; ssz<le_domaine_dis.nombre_de_sous_domaines_dis(); ssz++)
307 {
308 if (le_domaine_dis.sous_domaine_dis(ssz).sous_domaine().est_egal_a(le_sous_domaine))
309 {
310 sous_domaine=true;
311 le_sous_domaine_dis=ref_cast(Sous_domaine_VF,le_domaine_dis.sous_domaine_dis(ssz));
312 }
313 }
314
315 if(!sous_domaine)
316 {
317 Cerr << "Cannot find the discretized sub-domain associated with " << nom_sous_domaine << finl;
318 exit();
319 }
320 }
321}
322
323////////////////////////////////////////////////////////////////
324// //
325// Pure virtual functions of Source_base //
326// //
327////////////////////////////////////////////////////////////////
328
329
331{
332 la_vitesse = ref_cast(Champ_P1NC,equation().inconnue());
333 le_fluide = ref_cast(Fluide_base,equation().milieu());
334}
335
337 const Domaine_Cl_dis_base& domaine_Cl_dis)
338{
339 le_dom_VEF = ref_cast(Domaine_VEF, domaine_dis);
340 le_dom_Cl_VEF = ref_cast(Domaine_Cl_VEF, domaine_Cl_dis);
341}
class Champ_Don_Fonc_txyz This class represents a data field that is a function
class Champ_Don_Fonc_xyz This class represents a data field that is a function
class Champ_Don_base base class of Given Fields (not calculated)
DoubleTab & valeurs() override
Overrides Champ_base::valeurs() Returns the array of values.
Champ_Uniforme Represents a field that is constant in space and time.
virtual double valeur_a_compo(const DoubleVect &position, int ncomp) const
Computes the point value of the component "compo" of the field at the point with coordinates pos.
const Sous_Domaine_t & ss_domaine(int i) const
Definition Domaine.h:290
class Domaine_Cl_dis_base Domaine_Cl_dis_base objects represent discretized boundary conditions
class Domaine_VEF
Definition Domaine_VEF.h:53
int nb_faces() const
Returns the total number of faces.
Definition Domaine_VF.h:471
DoubleVect & volumes_entrelaces()
Definition Domaine_VF.h:99
double xv(int num_face, int k) const
Definition Domaine_VF.h:76
int face_voisins(int num_face, int i) const
Returns the neighbouring element of num_face in direction i.
Definition Domaine_VF.h:418
class Domaine_dis_base This class is the base of the hierarchy of discretized domains.
int nombre_de_sous_domaines_dis() const
const Sous_domaine_dis_base & sous_domaine_dis(int i) const
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual const Milieu_base & milieu() const =0
Probleme_base & probleme()
Returns the problem associated with the equation.
Schema_Temps_base & schema_temps()
Returns the time scheme associated with the equation.
Base class for an incompressible fluid and its properties:
Definition Fluide_base.h:36
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
double coef(int i, int j) const
DoubleVect & porosite_face()
Definition Milieu_base.h:62
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
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
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 int est_egal_a(const Objet_U &) const
Returns 1 if x and *this are the same instance (same memory address).
Definition Objet_U.cpp:299
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
@ REQUIRED
Definition Param.h:115
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
Factorizes the common functionality of several pressure drop operators in VEF, velocity at faces.
int lire_motcle_non_standard(const Motcle &, Entree &) override
Reads non-simple-type parameters of an Objet_U from an input stream.
DoubleTab & calculer(DoubleTab &) const override
virtual void set_param(Param &param) const override
void contribuer_a_avec(const DoubleTab &, Matrice_Morse &) const override
Copy of ajouter except the last line.
void associer_pb(const Probleme_base &) override
Associates le_fluide and la_vitesse.
DoubleTab & ajouter(DoubleTab &) const override
Calls perte_charge for each face where needed.
Nom nom_sous_domaine
Name of the sub-domain, initialized in readOn().
virtual void coeffs_perte_charge(const DoubleVect &u, const DoubleVect &pos, double t, double norme_u, double dh, double nu, double reynolds, double &coeff_ortho, double &coeff_long, double &u_l, DoubleVect &v_valeur) const =0
Called for each face by ajouter().
void associer_domaines(const Domaine_dis_base &, const Domaine_Cl_dis_base &) override
Associates le_dom_VEF and le_dom_Cl_VEF.
void completer() override
Updates internal references of the Source_base object.
bool sous_domaine
Is the term restricted to a sub-domain?
class Probleme_base It is a Probleme_U that is not a coupling.
const Domaine & domaine() const
Returns the domain associated with the problem.
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
double temps_courant() const
Returns the current time.
Base class for output streams.
Definition Sortie.h:52
Source_base A Source_base object is a term appearing on the right-hand side of an.
Definition Source_base.h:42
virtual void completer()
Updates internal references of the Source_base object.
This abstract class contains the geometrical subdomain information common to finite-volume methods (V...
const IntTab & les_faces() const
double volumes_entrelaces(int) const
Returns the interlaced volume restricted to the sub-domain. face is the index in the les_faces_ array...
const Sous_Domaine & sous_domaine() const
_SIZE_ size() const
Definition TRUSTVect.tpp:45
int line_size() const
Definition TRUSTVect.tpp:67