TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Op_Conv_EF_Stab_PolyMAC_MPFA_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_MPFA_Face.h>
17#include <Op_Grad_PolyMAC_MPFA_Face.h>
18#include <Champ_Face_PolyMAC_MPFA.h>
19#include <Masse_ajoutee_base.h>
20#include <Domaine_Cl_PolyMAC_family.h>
21#include <Schema_Temps_base.h>
22#include <Domaine_Poly_base.h>
23#include <Option_PolyMAC_family.h>
24#include <Pb_Multiphase.h>
25#include <Matrix_tools.h>
26#include <Array_tools.h>
27#include <TRUSTLists.h>
28#include <Dirichlet.h>
29#include <Param.h>
30#include <cmath>
31#include <Dirichlet_homogene.h>
32#include <Symetrie.h>
33
34Implemente_instanciable( Op_Conv_EF_Stab_PolyMAC_MPFA_Face, "Op_Conv_EF_Stab_PolyMAC_MPFA_Face", Op_Conv_EF_Stab_PolyMAC_HFV_Face ) ;
35Implemente_instanciable(Op_Conv_Amont_PolyMAC_MPFA_Face, "Op_Conv_Amont_PolyMAC_MPFA_Face", Op_Conv_EF_Stab_PolyMAC_MPFA_Face);
36Implemente_instanciable(Op_Conv_Centre_PolyMAC_MPFA_Face, "Op_Conv_Centre_PolyMAC_MPFA_Face", Op_Conv_EF_Stab_PolyMAC_MPFA_Face);
37
38// XD Op_Conv_EF_Stab_PolyMAC_MPFA_Face interprete Op_Conv_EF_Stab_PolyMAC_MPFA_Face BRACE Class
39// XD_CONT Op_Conv_EF_Stab_PolyMAC_MPFA_Face
43
45
47{
48 alpha_ = 1.0;
50}
52{
53 alpha_ = 0.0;
55}
56
58{
60 ref_cast(Champ_Face_PolyMAC_MPFA, vitesse_.valeur()).init_auxiliary_variables();
61}
62
63/*! @brief Computes the stability time step for the convection operator.
64 *
65 * This method calculates the maximum allowable time step based on the CFL stability condition
66 * for the convection operator. The computation considers incoming fluxes through
67 * each face of every element and determines the most restrictive time step constraint across the
68 * entire domain. For multiphase flows, elements with negligible phase presence are excluded from
69 * the time step calculation.
70 *
71 * @return The global minimum stability time step across all MPI processes
72 *
73 * @note Only incoming convective fluxes are considered in the stability analysis.
74 * @note For multiphase problems, elements with phase fraction below 1e-3 are ignored.
75 * @note In axisymmetric calculations, boundary faces with specific conditions may be excluded.
76 * @note The final time step is synchronized across all MPI processes using the minimum value.
77 * @note Flux contributions account for face porosity and surface area weighting.
78 */
80{
81 double dt = 1e10;
82 const Domaine_Poly_base& domaine = le_dom_poly_.valeur();
83 const DoubleVect& fs = domaine.face_surfaces(), &pf = equation().milieu().porosite_face(), &ve = domaine.volumes(),
84 &pe = equation().milieu().porosite_elem();
85 const DoubleTab& vit = vitesse_->valeurs(),
86 *alp = sub_type(Pb_Multiphase, equation().probleme()) ? &ref_cast(Pb_Multiphase, equation().probleme()).equation_masse().inconnue().passe() : nullptr;
87 const IntTab& e_f = domaine.elem_faces(), &f_e = domaine.face_voisins();
88 const IntTab *fcl = polymac_flica5 ? nullptr : &ref_cast(Champ_Face_PolyMAC_MPFA, equation().inconnue()).fcl();
89 const int N = vit.line_size();
90 DoubleTrav flux(N); //sum of fluxes pf * |f| * vf, minimum volume of elements/faces affected by this flux
91
92 for (int e = 0; e < domaine.nb_elem(); e++)
93 {
94 const double vol = pe(e) * ve(e);
95 flux = 0.;
96
97 for (int i = 0; i < e_f.dimension(1); i++)
98 {
99 const int f = e_f(e, i);
100 if (f < 0) continue;
101 if (fcl && Option_PolyMAC_family::TRAITEMENT_AXI && (*fcl)(f, 0) == 2) continue;
102
103 for (int n = 0; n < N; n++)
104 flux(n) += pf(f) * fs(f) * std::max((e == f_e(f, 1) ? 1 : -1) * vit(f, n), 0.);
105 }
106
107 for (int n = 0; n < N; n++)
108 if ((!alp || (*alp)(e, n) > 1e-3) && std::abs(flux(n)) > 1e-12)
109 dt = std::min(dt, vol / flux(n));
110 }
111
112 return Process::mp_min(dt);
113}
114
115/*! @brief Dimensions the matrix blocks for the PolyMAC_MPFA Face convection operator with EF stabilization.
116 *
117 * This method constructs the sparsity pattern and allocates memory for the system matrix by analyzing
118 * face-element connectivity and establishing the stencil relationships between degrees of freedom.
119 * The resulting matrix structure accounts for face-face and element-element contributions based on
120 * the PolyMAC_MPFA Face discretization scheme.
121 *
122 * @param matrices Map containing the system matrices indexed by unknown field names
123 * @param semi_impl Map of semi-implicit terms indexed by unknown field names
124 *
125 * @note The method returns early if no diagonal block exists or if semi-implicit treatment is requested.
126 * @note For multiphase problems with added mass correlation, cross-coupling terms between phases are included.
127 * @note The stencil construction handles face equivalence relationships and boundary conditions appropriately.
128 * @note Duplicate entries in the stencil are automatically removed before matrix allocation.
129 */
130void Op_Conv_EF_Stab_PolyMAC_MPFA_Face::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
131{
132 const Domaine_Poly_base& domaine = le_dom_poly_.valeur();
133 const Champ_Face_PolyMAC_MPFA& ch = ref_cast(Champ_Face_PolyMAC_MPFA, equation().inconnue());
134
135 const std::string& nom_inco = ch.le_nom().getString();
136 if (!matrices.count(nom_inco) || semi_impl.count(nom_inco))
137 return; //no diagonal block or semi-implicit -> nothing to do
138
139 const IntTab& f_e = domaine.face_voisins(), &e_f = domaine.elem_faces(), &fcl = ch.fcl(), &equiv = domaine.equiv();
140 const DoubleTab& nf = domaine.face_normales();
141 const DoubleVect& fs = domaine.face_surfaces();
142
143 const Pb_Multiphase *pbm = sub_type(Pb_Multiphase, equation().probleme()) ? &ref_cast(Pb_Multiphase, equation().probleme()) : nullptr;
144 const Masse_ajoutee_base *corr = pbm && pbm->has_correlation("masse_ajoutee") ? &ref_cast(Masse_ajoutee_base, pbm->get_correlation("masse_ajoutee")) : nullptr;
145 Matrice_Morse& mat = *matrices.at(nom_inco), mat2;
146
147 const int ne_tot = domaine.nb_elem_tot(), nf_tot = domaine.nb_faces_tot(), N = equation().inconnue().valeurs().line_size(), D = dimension;
148
149 Stencil stencil(0, 2);
150
151 // Loop over all faces of the domain
152 for (int f = 0; f < domaine.nb_faces_tot(); f++)
153 if (f_e(f, 0) >= 0 && (f_e(f, 1) >= 0 || fcl(f, 0) == 3))
154 {
155 // Loop over the two adjacent elements of the face
156 for (int i = 0; i < 2; i++)
157 {
158 const int e = f_e(f, i);
159 if (e < 0) continue; // virtual elem
160
161 for (int j = 0; j < 2; j++)
162 {
163 const int eb = f_e(f, j);
164 // Contribution of faces connected to the element
165 if (eb < 0) continue; // virtual elem
166
167 for (int k = 0; k < e_f.dimension(1); k++)
168 {
169 const int fb = e_f(e, k);
170 if (fb < 0) continue;
171
172 if (fb < domaine.nb_faces() && fcl(fb, 0) < 2)
173 {
174 int fc = equiv(f, i, k);
175 if (fc >= 0) // real face
176 {
177 // Equivalence case: face -> face
178 for (int n = 0; n < N; n++)
179 for (int m = (corr ? 0 : n); m < (corr ? N : n + 1); m++)
180 stencil.append_line(N * fb + n, N * fc + m);
181 }
182 else if (f_e(f, 1) >= 0) // boundary
183 {
184 // No equivalence: element -> face
185 for (int d = 0; d < D; d++)
186 if (std::fabs(nf(fb, d)) > 1e-6 * fs(fb))
187 for (int n = 0; n < N; n++)
188 for (int m = (corr ? 0 : n); m < (corr ? N : n + 1); m++)
189 stencil.append_line(N * fb + n, N * (nf_tot + D * eb + d) + m);
190 }
191 }
192 }
193
194 // Contribution element -element
195 for (int d = 0; d < D; d++)
196 for (int n = 0; n < N; n++)
197 for (int m = (corr ? 0 : n); m < (corr ? N : n + 1); m++)
198 stencil.append_line(N * (nf_tot + D * e + d) + n, N * (nf_tot + D * eb + d) + m);
199 }
200 }
201 }
202
203 // Remove duplicates and allocate the matrix
204 tableau_trier_retirer_doublons(stencil);
205 Matrix_tools::allocate_morse_matrix(N * (nf_tot + D * ne_tot), N * (nf_tot + D * ne_tot), stencil, mat2);
206 mat.nb_colonnes() ? mat += mat2 : mat = mat2;
207}
208
209/*! @brief Adds convection contributions to the system matrix and right-hand side vector.
210 *
211 * This method implements the convection operator with EF stabilization for PolyMAC_MPFA Face discretization.
212 * It computes face-based convection fluxes using upwind stabilization and assembles the corresponding
213 * matrix coefficients and source terms. The method handles both face-face and element-element contributions,
214 * accounting for face equivalence relationships and boundary conditions.
215 *
216 * @param matrices Map containing the system matrices indexed by unknown field names
217 * @param secmem Right-hand side vector to be updated with convection contributions
218 * @param semi_impl Map of semi-implicit field values indexed by field names
219 *
220 * @note The convection flux computation uses a blended upwind scheme with stabilization parameter alpha_.
221 * @note For multiphase flows, added mass correlations are included in the mass matrix contributions.
222 * @note The method distinguishes between compressible and incompressible flow formulations.
223 * @note Dirichlet boundary conditions are enforced through direct substitution in the source term.
224 * @note Face equivalence relationships are handled to maintain consistency across mesh interfaces.
225 * @note Performance statistics are automatically tracked during execution.
226 */
227void Op_Conv_EF_Stab_PolyMAC_MPFA_Face::ajouter_blocs(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
228{
229 if (polymac_flica5)
230 {
231 const Domaine_Poly_base& domaine = le_dom_poly_.valeur();
232 const Champ_Face_PolyMAC_MPFA& ch = ref_cast(Champ_Face_PolyMAC_MPFA, le_champ_inco ? le_champ_inco.valeur() : equation().inconnue());
233 const Conds_lim& cls = la_zcl_poly_->les_conditions_limites();
234 const IntTab& f_e = domaine.face_voisins(), &e_f = domaine.elem_faces(), &fcl = ch.fcl(), &equiv = domaine.equiv();
235 const DoubleTab& vit = vitesse_->valeurs(), &nf = domaine.face_normales(), &vfd = domaine.volumes_entrelaces_dir();
236 const DoubleVect& fs = domaine.face_surfaces(), &pe = porosite_e, &pf = porosite_f, &ve = domaine.volumes();
237
238 /* a_r : alpha_rho product if Pb_Multiphase -> via semi-implicit, or by retrieving the conserved field from the mass equation */
239 const std::string& nom_inco = ch.le_nom().getString();
240 const DoubleTab& inco = semi_impl.count(nom_inco) ? semi_impl.at(nom_inco) : ch.valeurs();
241 Matrice_Morse *mat = matrices.count(nom_inco) && !semi_impl.count(nom_inco) ? matrices.at(nom_inco) : nullptr;
242
243 const int nf_tot = domaine.nb_faces_tot(), N = inco.line_size(), D = dimension;
244
245 DoubleTrav dfac(2, N, N), masse(N, N);
246 // Loop over all faces of the domain
247 for (int f = 0; f < domaine.nb_faces_tot(); f++)
248 {
249 if (f_e(f, 0) >= 0 && (f_e(f, 1) >= 0 || fcl(f, 0) == 1 || fcl(f, 0) == 3))
250 {
251 // Compute face contributions
252 dfac = 0.;
253 for (int i = 0; i < 2; i++)
254 {
255 // Mass: diagonal + correction
256 masse(0, 0) = std::fabs(vit[f]) > 1e-10 ? inco(f) / vit[f] : 1.0;
257
258 // Contribution to dfac
259 const int eb = f_e(f, i);
260 for (int n = 0; n < N; n++)
261 for (int m = 0; m < N; m++)
262 {
263 const double signe = (vit(f, m) * (i ? -1 : 1) >= 0) ? 1. : (vit(f, m) ? -1. : 0.);
264 dfac((fcl(f, 0) == 1) ? 0 : i, n, m) += fs(f) * inco[f] * pe(eb >= 0 ? eb : f_e(f, 0)) * (1. + signe * alpha_) / 2;
265 }
266 }
267
268 // Compute contributions to the matrix and right-hand side
269 for (int i = 0; i < 2; i++)
270 {
271 const int e = f_e(f, i);
272 if (e < 0) continue; // virtual elem
273
274 // partie "faces"
275 for (int k = 0; k < e_f.dimension(1); k++)
276 {
277 const int fb = e_f(e, k);
278 if (fb < 0) continue; // face in-existante (polyhedre)
279
280 if (fb < domaine.nb_faces() && fcl(fb, 0) < 2)
281 {
282 // Equivalence case: face -> face
283 int fc = equiv(f, i, k);
284 if (fc >= 0 || f_e(f, 1) < 0)
285 {
286 for (int j = 0; j < 2; j++)
287 {
288 int eb = f_e(f, j);
289 const int fd = (j == i) ? fb : fc; // Source face
290 //multiplier to convert from vf to ve
291 double mult = (fd < 0 || domaine.dot(&nf(fb, 0), &nf(fd, 0)) > 0) ? 1 : -1;
292 mult *= (fd >= 0) ? pf(fd) / pe(eb) : 1;
293
294 for (int n = 0; n < N; n++)
295 for (int m = 0; m < N; m++)
296 if (dfac(j, n, m))
297 {
298 const double fac = (i ? -1 : 1) * vfd(fb, e != f_e(fb, 0)) * dfac(j, n, m) / ve(e);
299
300 // Update the right-hand side
301 if (fd >= 0)
302 secmem(fb, n) -= fac * mult * vit[fd];
303 else
304 // Dirichlet boundary condition
305 for (int d = 0; d < D; d++)
306 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) / masse(0, 0);
307
308 if (!incompressible_)
309 secmem(fb, n) += fac * vit[fb];
310
311 // Update the matrix
312 if (mat && fac)
313 {
314 if (fd >= 0 && fcl(fd, 0) < 2)
315 (*mat)(N * fb + n, N * fd + m) += fac * mult;
316 if (!incompressible_)
317 (*mat)(N * fb + n, N * fb + m) -= fac;
318 }
319 }
320 }
321 }
322 // No equivalence: connected elements
323 else
324 {
325 for (int j = 0; j < 2; j++)
326 {
327 const int eb = f_e(f, j);
328 for (int d = 0; d < D; d++)
329 if (std::fabs(nf(fb, d)) > 1e-6 * fs(fb))
330 for (int n = 0; n < N; n++)
331 for (int m = 0; m < N; m++)
332 if (dfac(j, n, m))
333 {
334 const double fac = (i ? -1 : 1) * vfd(fb, e != f_e(fb, 0)) * dfac(j, n, m) / ve(e) * nf(fb, d) / fs(fb);
335
336 // Update of the right-hand side
337 secmem(fb, n) -= fac * vit[nf_tot + D * eb + d];
338 if (!incompressible_)
339 secmem(fb, n) += fac * vit[nf_tot + D * e + d];
340
341 // Update of the matrix
342 if (mat && fac)
343 {
344 (*mat)(N * fb + n, N * (nf_tot + D * eb + d) + m) += fac;
345 if (!incompressible_)
346 (*mat)(N * fb + n, N * (nf_tot + D * e + d) + m) -= fac;
347 }
348 }
349 }
350 }
351 }
352 }
353
354 // "elem" part
355 for (int j = 0; j < 2; j++)
356 {
357 const int eb = f_e(f, j);
358 for (int d = 0; d < D; d++)
359 for (int n = 0; n < N; n++)
360 for (int m = 0; m < N; m++)
361 if (dfac(j, n, m))
362 {
363 const double fac = (i ? -1 : 1) * dfac(j, n, m);
364
365 // Update the right-hand side
366 secmem(nf_tot + D * e + d, n) -= fac * (eb >= 0 ? vit[nf_tot + D * eb + d] : ref_cast(Dirichlet, cls[fcl(f, 1)].valeur()).val_imp(fcl(f, 2), N * d + m));
367 if (!incompressible_)
368 secmem(nf_tot + D * e + d, n) += fac * vit[nf_tot + D * e + d]; //part v div(alpha rho v)
369
370 if (mat && fac)
371 {
372 if (eb >= 0)
373 (*mat)(N * (nf_tot + D * e + d) + n, N * (nf_tot + D * eb + d) + m) += fac;
374 if (!incompressible_)
375 (*mat)(N * (nf_tot + D * e + d) + n, N * (nf_tot + D * e + d) + m) -= fac;
376 }
377 }
378 }
379 }
380 }
381 }
382 return;
383 }
384
385 const Domaine_Poly_base& domaine = le_dom_poly_.valeur();
386 const Champ_Face_PolyMAC_MPFA& ch = ref_cast(Champ_Face_PolyMAC_MPFA, equation().inconnue());
387 const Conds_lim& cls = la_zcl_poly_->les_conditions_limites();
388 const IntTab& f_e = domaine.face_voisins(), &e_f = domaine.elem_faces(), &fcl = ch.fcl(), &equiv = domaine.equiv();
389 const DoubleTab& vit = ch.passe(), &nf = domaine.face_normales(), &vfd = domaine.volumes_entrelaces_dir();
390 const DoubleVect& fs = domaine.face_surfaces(), &pe = porosite_e, &pf = porosite_f, &ve = domaine.volumes();
391
392 /* a_r : alpha_rho product if Pb_Multiphase -> via semi-implicit, or by retrieving the conserved field from the mass equation */
393 const std::string& nom_inco = ch.le_nom().getString();
394 const Pb_Multiphase *pbm = sub_type(Pb_Multiphase, equation().probleme()) ? &ref_cast(Pb_Multiphase, equation().probleme()) : nullptr;
395 const Masse_ajoutee_base *corr = pbm && pbm->has_correlation("masse_ajoutee") ? &ref_cast(Masse_ajoutee_base, pbm->get_correlation("masse_ajoutee")) : nullptr;
396 const DoubleTab& inco = semi_impl.count(nom_inco) ? semi_impl.at(nom_inco) : ch.valeurs(),
397 *a_r = !pbm ? nullptr : semi_impl.count("alpha_rho") ? &semi_impl.at("alpha_rho") : &pbm->equation_masse().champ_conserve().valeurs(),
398 *alp = pbm ? &pbm->equation_masse().inconnue().passe() : nullptr, &rho = equation().milieu().masse_volumique().passe();
399 Matrice_Morse *mat = matrices.count(nom_inco) && !semi_impl.count(nom_inco) ? matrices.at(nom_inco) : nullptr;
400
401 const int nf_tot = domaine.nb_faces_tot(), N = inco.line_size(), D = dimension;
402
403 DoubleTrav dfac(2, N, N), masse(N, N);
404 // Loop over all faces of the domain
405 for (int f = 0; f < domaine.nb_faces_tot(); f++)
406 {
407 if (f_e(f, 0) >= 0 && (f_e(f, 1) >= 0 || fcl(f, 0) == 1 || fcl(f, 0) == 3))
408 {
409 // Compute face contributions
410 dfac = 0.;
411 for (int i = 0; i < 2; i++)
412 {
413 const int e = f_e(f, (f_e(f, i) >= 0) ? i : 0);
414
415 // Mass: diagonal + correction
416 masse = 0.;
417 for (int n = 0; n < N; n++)
418 masse(n, n) = a_r ? (*a_r)(e, n) : 1;
419
420 if (corr)
421 corr->ajouter(&(*alp)(e, 0), &rho(e, 0), masse);
422
423 // Contribution to dfac
424 const int eb = f_e(f, i);
425 for (int n = 0; n < N; n++)
426 for (int m = 0; m < N; m++)
427 {
428 const double signe = (vit(f, m) * (i ? -1 : 1) >= 0) ? 1. : (vit(f, m) ? -1. : 0.);
429 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;
430 }
431 }
432
433 // Compute contributions to the matrix and right-hand side
434 for (int i = 0; i < 2 ; i++)
435 {
436 const int e = f_e(f, i);
437 if (e < 0) continue; // virtual elem
438
439 // "faces" part
440 for (int k = 0; k < e_f.dimension(1); k++)
441 {
442 const int fb = e_f(e, k);
443 if (fb < 0) continue; // face in-existante (polyhedre)
444
445 if (fb < domaine.nb_faces() && fcl(fb, 0) < 2)
446 {
447 // Equivalence case: face -> face
448 int fc = equiv(f, i, k);
449 if (fc >= 0 || f_e(f, 1) < 0)
450 {
451 for (int j = 0; j < 2; j++)
452 {
453 int eb = f_e(f, j);
454 const int fd = (j == i) ? fb : fc; // Source face
455 //multiplier to convert from vf to ve
456 double mult = (fd < 0 || domaine.dot(&nf(fb, 0), &nf(fd, 0)) > 0) ? 1 : -1;
457 mult *= (fd >= 0) ? pf(fd) / pe(eb) : 1;
458
459 for (int n = 0; n < N; n++)
460 for (int m = 0; m < N; m++)
461 if (dfac(j, n, m))
462 {
463 const double fac = (i ? -1 : 1) * vfd(fb, e != f_e(fb, 0)) * dfac(j, n, m) / ve(e);
464
465 // Update the right-hand side
466 if (fd >= 0)
467 secmem(fb, n) -= fac * mult * inco(fd, m);
468 else
469 // Dirichlet boundary condition
470 for (int d = 0; d < D; d++)
471 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);
472
473 if (!incompressible_)
474 secmem(fb, n) += fac * inco(fb, m);
475
476 // Update the matrix
477 if (mat && fac)
478 {
479 if (fd >= 0 && fcl(fd, 0) < 2)
480 (*mat)(N * fb + n, N * fd + m) += fac * mult;
481 if (!incompressible_)
482 (*mat)(N * fb + n, N * fb + m) -= fac;
483 }
484 }
485 }
486 }
487 // No equivalence: connected elements
488 else
489 {
490 for (int j = 0; j < 2; j++)
491 {
492 const int eb = f_e(f, j);
493 for (int d = 0; d < D; d++)
494 if (std::fabs(nf(fb, d)) > 1e-6 * fs(fb))
495 for (int n = 0; n < N; n++)
496 for (int m = 0; m < N; m++)
497 if (dfac(j, n, m))
498 {
499 const double fac = (i ? -1 : 1) * vfd(fb, e != f_e(fb, 0)) * dfac(j, n, m) / ve(e) * nf(fb, d) / fs(fb);
500
501 // Update the right-hand side
502 secmem(fb, n) -= fac * inco(nf_tot + D * eb + d, m);
503 if (!incompressible_)
504 secmem(fb, n) += fac * inco(nf_tot + D * e + d, m);
505
506 // Update the matrix
507 if (mat && fac)
508 {
509 (*mat)(N * fb + n, N * (nf_tot + D * eb + d) + m) += fac;
510 if (!incompressible_)
511 (*mat)(N * fb + n, N * (nf_tot + D * e + d) + m) -= fac;
512 }
513 }
514 }
515 }
516 }
517 }
518
519 // "elem" part
520 for (int j = 0; j < 2; j++)
521 {
522 const int eb = f_e(f, j);
523 for (int d = 0; d < D; d++)
524 for (int n = 0; n < N; n++)
525 for (int m = 0; m < N; m++)
526 if (dfac(j, n, m))
527 {
528 const double fac = (i ? -1 : 1) * dfac(j, n, m);
529
530 // Update the right-hand side
531 secmem(nf_tot + D * e + d, n) -= fac * (eb >= 0 ? inco(nf_tot + D * eb + d, m) : ref_cast(Dirichlet, cls[fcl(f, 1)].valeur()).val_imp(fcl(f, 2), N * d + m));
532 if (!incompressible_)
533 secmem(nf_tot + D * e + d, n) += fac * inco(nf_tot + D * e + d, m); //part v div(alpha rho v)
534
535 if (mat && fac)
536 {
537 if (eb >= 0)
538 (*mat)(N * (nf_tot + D * e + d) + n, N * (nf_tot + D * eb + d) + m) += fac;
539 if (!incompressible_)
540 (*mat)(N * (nf_tot + D * e + d) + n, N * (nf_tot + D * e + d) + m) -= fac;
541 }
542 }
543 }
544 }
545 }
546 }
547}
: class Champ_Face_PolyMAC_MPFA
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
void completer() override
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its equation.
double calculer_dt_stab() const override
Computes the stability time step for the convection operator.
void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={ }) const override
Dimensions the matrix blocks for the PolyMAC_MPFA Face convection operator with EF stabilization.
void ajouter_blocs(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={ }) const override
Adds convection contributions to the system matrix and right-hand side vector.
virtual void completer()
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its equation.
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