TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Op_Conv_EF_Stab_PolyMAC_HFV_Face.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 <Op_Conv_EF_Stab_PolyMAC_HFV_Face.h>
17#include <Champ_Face_PolyMAC_HFV.h>
18#include <Dirichlet_homogene.h>
19#include <Masse_ajoutee_base.h>
20#include <Schema_Temps_base.h>
21#include <Domaine_Cl_PolyMAC_family.h>
22#include <Domaine_Poly_base.h>
23#include <Pb_Multiphase.h>
24#include <Matrix_tools.h>
25#include <Array_tools.h>
26#include <TRUSTLists.h>
27#include <Dirichlet.h>
28#include <Param.h>
29#include <cmath>
30
31Implemente_instanciable( Op_Conv_EF_Stab_PolyMAC_HFV_Face, "Op_Conv_EF_Stab_PolyMAC_HFV_Face", Op_Conv_EF_Stab_PolyMAC_CDO_Face );
32Implemente_instanciable( Op_Conv_Amont_PolyMAC_HFV_Face, "Op_Conv_Amont_PolyMAC_HFV_Face", Op_Conv_EF_Stab_PolyMAC_HFV_Face );
33Implemente_instanciable( Op_Conv_Centre_PolyMAC_HFV_Face, "Op_Conv_Centre_PolyMAC_HFV_Face", Op_Conv_EF_Stab_PolyMAC_HFV_Face );
34
35// XD Op_Conv_EF_Stab_PolyMAC_HFV_Face interprete Op_Conv_EF_Stab_PolyMAC_HFV_Face BRACE Class
36// XD_CONT Op_Conv_EF_Stab_PolyMAC_HFV_Face
37
41
43
45{
46 alpha_ = 1.0;
48}
49
51{
52 alpha_ = 0.0;
54}
55
57{
58 double dt = 1e10;
59 const Domaine_Poly_base& domaine = le_dom_poly_.valeur();
60 const DoubleVect& fs = domaine.face_surfaces(), &pf = equation().milieu().porosite_face(), &ve = domaine.volumes(), &pe = equation().milieu().porosite_elem();
61 const DoubleTab& vit = vitesse_->valeurs(),
62 *alp = sub_type(Pb_Multiphase, equation().probleme()) ? &ref_cast(Pb_Multiphase, equation().probleme()).equation_masse().inconnue().passe() : nullptr;
63 const IntTab& e_f = domaine.elem_faces(), &f_e = domaine.face_voisins();
64 const int N = vit.line_size();
65 DoubleTrav flux(N); //sum of fluxes pf * |f| * vf, minimum volume of elements/faces affected by this flux
66
67 for (int e = 0; e < domaine.nb_elem(); e++)
68 {
69 // Compute the effective volume of the element
70 const double vol = pe(e) * ve(e);
71 flux = 0.;
72
73 // Loop over faces associated with the element
74 for (int i = 0; i < e_f.dimension(1); i++)
75 {
76 int f = e_f(e, i);
77 if (f < 0) continue; // non-existent face
78
79 for (int n = 0; n < N; n++)
80 {
81 // Add incoming flux for component n: only incoming fluxes count
82 double flux_f = pf(f) * fs(f) * std::max((e == f_e(f, 1) ? 1 : -1) * vit(f, n), 0.);
83 flux(n) += flux_f;
84 }
85 }
86
87 // Compute the time step for each component n
88 for (int n = 0; n < N; n++)
89 if ((!alp || (*alp)(e, n) > 1e-3) && std::abs(flux(n)) > 1e-12)
90 dt = std::min(dt, vol / flux(n));
91 }
92
93 return Process::mp_min(dt);
94}
95
96void Op_Conv_EF_Stab_PolyMAC_HFV_Face::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
97{
98 const Domaine_Poly_base& domaine = le_dom_poly_.valeur();
99 const Champ_Face_PolyMAC_HFV& ch = ref_cast(Champ_Face_PolyMAC_HFV, equation().inconnue());
100 const IntTab& f_e = domaine.face_voisins(), &e_f = domaine.elem_faces(), &fcl = ch.fcl(), &equiv = domaine.equiv();
101 const DoubleTab& nf = domaine.face_normales(), &inco = ch.valeurs(), &xp = domaine.xp(), &xv = domaine.xv();
102 const DoubleVect& fs = domaine.face_surfaces(), &ve = domaine.volumes();
103
104 const std::string& nom_inco = ch.le_nom().getString();
105
106 if (!matrices.count(nom_inco) || semi_impl.count(nom_inco))
107 return; //no diagonal block or semi-implicit -> nothing to do
108
109 const Pb_Multiphase *pbm = sub_type(Pb_Multiphase, equation().probleme()) ? &ref_cast(Pb_Multiphase, equation().probleme()) : nullptr;
110 const Masse_ajoutee_base *corr = pbm && pbm->has_correlation("masse_ajoutee") ? &ref_cast(Masse_ajoutee_base, pbm->get_correlation("masse_ajoutee")) : nullptr;
111 Matrice_Morse& mat = *matrices.at(nom_inco), mat2;
112
113 const int N = equation().inconnue().valeurs().line_size();
114
115 Stencil stencil(0, 2);
116
117 /* This block acts on elements only; the diagonal of the matrix is omitted. */
118 for (int f = 0; f < domaine.nb_faces_tot(); f++)
119 {
120 // Check if the face is internal or satisfies boundary conditions
121 if (f_e(f, 0) >= 0 && (f_e(f, 1) >= 0 || fcl(f, 0) == 3))
122 {
123 // Loop over elements associated with this face
124 for (int i = 0; i < 2 ; i++)
125 {
126 const int e = f_e(f, i);
127 if (e < 0) continue; // virtual elem
128
129 for (int j = 0; j < 2 ; j++)
130 {
131 const int eb = f_e(f, j);
132 // Loop over faces connected to the current element
133 if (eb < 0) continue;
134
135 for (int k = 0; k < e_f.dimension(1); k++)
136 {
137 const int fb = e_f(e, k);
138 if (fb <0) continue;
139
140 if (fb < domaine.nb_faces())
141 {
142 int fc = equiv(f, i, k);
143 // Case where a face equivalence exists
144 if (fc >= 0)
145 {
146 for (int n = 0; n < N; n++)
147 for (int m = (corr ? 0 : n); m < (corr ? N : n + 1); m++)
148 stencil.append_line(N * fb + n, N * fc + m);
149 }
150 // Case without equivalence: contributions between element faces
151 else if (f_e(f, 1) >= 0)
152 {
153 for (int l = 0; l < e_f.dimension(1); l++)
154 {
155 fc = e_f(eb, l);
156 if (fc < 0) continue;
157
158 const double critere = fs(fc) * domaine.dot(&xv(fc, 0), &nf(fb, 0), &xp(eb, 0));
159 if (std::abs(critere) > 1e-6 * ve(eb) * fs(fb))
160 for (int n = 0; n < N; n++)
161 for (int m = (corr ? 0 : n); m < (corr ? N : n + 1); m++)
162 stencil.append_line(N * fb + n, N * fc + m);
163 }
164 }
165 }
166 }
167 }
168 }
169 }
170 }
171
172 // Sort and remove duplicates from the stencil
173 tableau_trier_retirer_doublons(stencil);
174
175 // Allocate a sparse matrix based on the stencil
176 Matrix_tools::allocate_morse_matrix(inco.size_totale(), inco.size_totale(), stencil, mat2);
177
178 // Add mat2 to the existing matrix or initialize 'mat'
179 if (mat.nb_colonnes())
180 mat += mat2;
181 else
182 mat = mat2;
183}
184
185// adds the convection contribution to the right-hand side resu
186// returns resu
187void Op_Conv_EF_Stab_PolyMAC_HFV_Face::ajouter_blocs(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
188{
189 const Domaine_Poly_base& domaine = le_dom_poly_.valeur();
190 const Champ_Face_PolyMAC_HFV& ch = ref_cast(Champ_Face_PolyMAC_HFV, equation().inconnue());
191 const Conds_lim& cls = la_zcl_poly_->les_conditions_limites();
192 const IntTab& f_e = domaine.face_voisins(), &e_f = domaine.elem_faces(), &fcl = ch.fcl(), &equiv = domaine.equiv();
193 const DoubleTab& vit = ch.passe(), &nf = domaine.face_normales(), &vfd = domaine.volumes_entrelaces_dir(), &xp = domaine.xp(), &xv = domaine.xv();
194 const DoubleVect& fs = domaine.face_surfaces(), &pe = porosite_e, &pf = porosite_f, &ve = domaine.volumes();
195
196 /* a_r : alpha_rho product if Pb_Multiphase -> via semi-implicit, or by retrieving the conserved field from the mass equation */
197 const std::string& nom_inco = ch.le_nom().getString();
198 const Pb_Multiphase *pbm = sub_type(Pb_Multiphase, equation().probleme()) ? &ref_cast(Pb_Multiphase, equation().probleme()) : nullptr;
199 const Masse_ajoutee_base *corr = pbm && pbm->has_correlation("masse_ajoutee") ? &ref_cast(Masse_ajoutee_base, pbm->get_correlation("masse_ajoutee")) : nullptr;
200 const DoubleTab& inco = semi_impl.count(nom_inco) ? semi_impl.at(nom_inco) : ch.valeurs(),
201 *a_r = !pbm ? nullptr : semi_impl.count("alpha_rho") ? &semi_impl.at("alpha_rho") : &pbm->equation_masse().champ_conserve().valeurs(),
202 *alp = pbm ? &pbm->equation_masse().inconnue().passe() : nullptr,
203 &rho = equation().milieu().masse_volumique().passe();
204
205 Matrice_Morse *mat = matrices.count(nom_inco) && !semi_impl.count(nom_inco) ? matrices.at(nom_inco) : nullptr;
206
207 const int N = inco.line_size(), D = dimension;
208
209 DoubleTrav dfac(2, N, N), masse(N, N);
210
211 // Loop over all faces of the domain
212 for (int f = 0; f < domaine.nb_faces_tot(); f++)
213 {
214 if (f_e(f, 0) >= 0 && (f_e(f, 1) >= 0 || fcl(f, 0) == 1 || fcl(f, 0) == 3))
215 {
216 // Compute face contributions
217 dfac = 0.;
218 for (int i = 0; i < 2; i++)
219 {
220 // Diagonal mass with correction if needed
221 masse = 0.;
222 int e = f_e(f, (f_e(f, i) >= 0) ? i : 0);
223 for (int n = 0; n < N; n++)
224 masse(n, n) = a_r ? (*a_r)(e, n) : 1.;
225
226 if (corr)
227 corr->ajouter(&(*alp)(e, 0), &rho(e, 0), masse);
228
229 // Contribution a dfac
230 e = f_e(f, i);
231 int eb = f_e(f, i);
232 for (int n = 0; n < N; n++)
233 for (int m = 0; m < N; m++)
234 {
235 const double signe = (vit(f, m) * (i ? -1 : 1) >= 0) ? 1. : (vit(f, m) ? -1. : 0.);
236 dfac((fcl(f, 0) == 1) ? 0 : i, n, m) += fs(f) * vit(f, m) * pe((eb >= 0) ? eb : f_e(f, 0)) * masse(n, m) * (1. + signe * alpha_) / 2;
237 }
238 }
239
240 // Contributions to matrices and right-hand side
241 for (int i = 0; i < 2 ; i++)
242 {
243 const int e = f_e(f, i);
244 if (e < 0) continue;
245
246 for (int k = 0; k < e_f.dimension(1) ; k++)
247 {
248 const int fb = e_f(e, k);
249 if (fb < 0) continue;
250
251 if (fb < domaine.nb_faces())
252 {
253 int fc = equiv(f, i, k);
254 // Equivalence case: source face -> target face
255 if (fc >= 0 || f_e(f, 1) < 0)
256 {
257 for (int j = 0; j < 2; j++)
258 {
259 int eb = f_e(f, j);
260 int fd = (j == i) ? fb : fc; // source face or element
261
262 //multiplier to convert from vf to ve
263 double mult = (fd < 0 || domaine.dot(&nf(fb, 0), &nf(fd, 0)) > 0) ? 1 : -1;
264 mult *= (fd >= 0) ? pf(fd) / pe(eb) : 1;
265
266 for (int n = 0; n < N; n++)
267 for (int m = 0; m < N; m++)
268 {
269 if (dfac(j, n, m))
270 {
271 double fac = (i ? -1 : 1) * vfd(fb, e != f_e(fb, 0)) * dfac(j, n, m) / ve(e);
272
273 // Update the right-hand side
274 if (fd >= 0)
275 secmem(fb, n) -= fac * mult * inco(fd, m);
276 else
277 {
278 // Dirichlet boundary condition
279 for (int d = 0; d < D; d++)
280 secmem(fb, n) -= fac * nf(fb, d) / fs(fb) * ref_cast(Dirichlet, cls[fcl(f, 1)].valeur()).val_imp(fcl(f, 2), N * d + m);
281 }
282 if (!incompressible_)
283 secmem(fb, n) += fac * inco(fb, m);
284
285 // Update the matrix
286 if (mat)
287 {
288 if (fd >= 0)
289 (*mat)(N * fb + n, N * fd + m) += fac * mult;
290
291 if (!incompressible_)
292 (*mat)(N * fb + n, N * fb + m) -= fac;
293 }
294 }
295 }
296 }
297 }
298 // No equivalence: n_f * element operator
299 else
300 {
301 for (int j = 0; j < 2; j++)
302 {
303 const int eb = f_e(f, j);
304 for (int l = 0; l < e_f.dimension(1) ; l++)
305 {
306 fc = e_f(eb, l);
307 if (fc < 0) continue;
308
309 double critere = fs(fc) * domaine.dot(&xv(fc, 0), &nf(fb, 0), &xp(eb, 0));
310 if (std::abs(critere) > 1e-6 * ve(eb) * fs(fb))
311 {
312 for (int n = 0; n < N; n++)
313 for (int m = 0; m < N; m++)
314 if (dfac(j, n, m))
315 {
316 double fac = (i ? -1 : 1) * vfd(fb, e != f_e(fb, 0)) * dfac(j, n, m) * ((eb == f_e(fc, 0)) ? 1 : -1) * critere / (ve(e) * ve(eb) * fs(fb));
317 secmem(fb, n) -= fac * inco(fc, m);
318 if (mat && fac)
319 (*mat)(N * fb + n, N * fc + m) += fac;
320 }
321 }
322 }
323 // Correction part if 'comp'
324 if (!incompressible_)
325 {
326 for (int l = 0; l < e_f.dimension(1) ; l++)
327 {
328 fc = e_f(e, l);
329 if (fc < 0) continue;
330
331 double critere = fs(fc) * domaine.dot(&xv(fc, 0), &nf(fb, 0), &xp(e, 0));
332 if (std::abs(critere) > 1e-6 * ve(e) * fs(fb))
333 {
334 for (int n = 0; n < N; n++)
335 for (int m = 0; m < N; m++)
336 {
337 if (dfac(j, n, m))
338 {
339 double fac = (i ? -1 : 1) * vfd(fb, e != f_e(fb, 0)) * dfac(j, n, m) * ((e == f_e(fc, 0)) ? 1 : -1) * critere / (ve(e) * ve(e) * fs(fb));
340 secmem(fb, n) += fac * inco(fc, m);
341 if (mat && fac)
342 (*mat)(N * fb + n, N * fc + m) -= fac;
343 }
344 }
345 }
346 }
347 }
348 }
349 }
350 }
351 }
352 }
353 }
354 }
355}
: class Champ_Face_PolyMAC_HFV
const IntTab & fcl() const
DoubleTab & passe(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 & passe(int i=1)
Definition Champ_Proto.h:50
class Conds_lim This class represents a vector of boundary conditions.
Definition Conds_lim.h:32
Dirichlet This class is the base class of the hierarchy of Dirichlet-type boundary conditions.
Definition Dirichlet.h:31
class Domaine_Poly_base
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
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
Champ_Inc_base & champ_conserve() const
virtual const Champ_Inc_base & inconnue() const =0
const Nom & le_nom() const override
Returns the name of the field.
Added-mass correlation of the form: alpha_k rho_k Dv_k / Dt -> alpha_k rho_k Dv_k / Dt + sum_l ma(k,...
virtual void ajouter(const double *alpha, const double *rho, DoubleTab &a_r) const =0
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
static void allocate_morse_matrix(const int nb_lines, const int nb_columns, const Stencil &stencil, Matrice_Morse &matrix, const bool &attach_stencil_to_matrix=false)
DoubleVect & porosite_elem()
Definition Milieu_base.h:58
virtual const Champ_base & masse_volumique() const
Returns the mass density of the medium (const version).
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
const std::string & getString() const
Definition Nom.h:92
static int dimension
Definition Objet_U.h:94
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
double calculer_dt_stab() const override
Computes dt_stab.
void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={ }) const override
void ajouter_blocs(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={ }) const override
Multiphase thermohydraulics problem of type "3*N equations":
virtual Equation_base & equation_masse()
int has_correlation(std::string nom_correlation) const
const Correlation_base & get_correlation(std::string nom_correlation) const
static double mp_min(double)
Definition Process.cpp:391
Base class for output streams.
Definition Sortie.h:52
void append_line(_TYPE_)
Definition TRUSTTab.tpp:213
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
int line_size() const
Definition TRUSTVect.tpp:67