TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Op_Diff_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_Diff_PolyMAC_MPFA_Face.h>
17#include <Champ_Face_PolyMAC_MPFA.h>
18#include <Domaine_PolyMAC_MPFA.h>
19#include <Domaine_Cl_PolyMAC_family.h>
20#include <Option_PolyMAC_family.h>
21#include <Champ_Uniforme.h>
22#include <Synonyme_info.h>
23#include <Pb_Multiphase.h>
24#include <Matrix_tools.h>
25#include <Array_tools.h>
26
27Implemente_instanciable( Op_Diff_PolyMAC_MPFA_Face, "Op_Diff_PolyMAC_MPFA_Face|Op_Dift_PolyMAC_MPFA_Face_PolyMAC_MPFA", Op_Diff_PolyMAC_MPFA_base );
28Add_synonym(Op_Diff_PolyMAC_MPFA_Face, "Op_Diff_PolyMAC_MPFA_var_Face");
29Add_synonym(Op_Diff_PolyMAC_MPFA_Face, "Op_Dift_PolyMAC_MPFA_var_Face_PolyMAC_MPFA");
30
32
34
36{
38
39 const Domaine_PolyMAC_MPFA& domaine = ref_cast(Domaine_PolyMAC_MPFA, le_dom_poly_.valeur());
40 Champ_Face_PolyMAC_MPFA& ch = ref_cast(Champ_Face_PolyMAC_MPFA, le_champ_inco ? le_champ_inco.valeur() : equation().inconnue());
41 if (le_champ_inco)
42 ch.init_auxiliary_variables(); // flica5 case: the unknown is not used directly, so auxiliary variables are created here
43
44 flux_bords_.resize(domaine.premiere_face_int(), dimension * ch.valeurs().line_size());
45 if (domaine.domaine().nb_joints() && domaine.domaine().joint(0).epaisseur() < 1)
46 {
47 Cerr << "Op_Diff_PolyMAC_MPFA_Face : largeur de joint insuffisante (minimum 1)!" << finl;
49 }
50 porosite_e.ref(equation().milieu().porosite_elem());
51 porosite_f.ref(equation().milieu().porosite_face());
52}
53
55{
56 const Domaine_PolyMAC_MPFA& domaine = ref_cast(Domaine_PolyMAC_MPFA, le_dom_poly_.valeur());
57 const IntTab& e_f = domaine.elem_faces(), &f_e = domaine.face_voisins(), &fcl = ref_cast(Champ_Face_PolyMAC_MPFA, equation().inconnue()).fcl();
58
59 const DoubleTab& nf = domaine.face_normales(), &vfd = domaine.volumes_entrelaces_dir(),
60 *alp = sub_type(Pb_Multiphase, equation().probleme()) ?
61 &ref_cast(Pb_Multiphase, equation().probleme()).equation_masse().inconnue().passe() : nullptr,
62 *a_r = sub_type(Pb_Multiphase, equation().probleme())
63 ? &ref_cast(Pb_Multiphase, equation().probleme()).equation_masse().champ_conserve().passe()
64 : (has_champ_masse_volumique() ? &get_champ_masse_volumique().valeurs() : nullptr); /* alpha * rho product */
65
66 const DoubleVect& pe = equation().milieu().porosite_elem(), &pf = equation().milieu().porosite_face(),
67 &vf = domaine.volumes_entrelaces(), &ve = domaine.volumes();
68
69 update_nu();
70
71 const int N = equation().inconnue().valeurs().line_size();
72 double dt = 1e10;
73
74 DoubleTrav flux(N);
75
76 for (int e = 0; e < domaine.nb_elem(); e++)
77 {
78 flux = 0.;
79 double vol = pe(e) * ve(e);
80
81 for (int i = 0; i < e_f.dimension(1); i++)
82 {
83 const int f = e_f(e, i);
84 if (f < 0) continue;
85
87 for (int n = 0; n < N; n++)
88 {
89 flux(n) += domaine.nu_dot(&nu_, e, n, &nf(f, 0), &nf(f, 0)) / vf(f);
90 if (fcl(f, 0) < 2)
91 vol = std::min(vol, pf(f) * vf(f) / vfd(f, e != f_e(f, 0)) * vf(f)); //cf. Op_Conv_EF_Stab_PolyMAC_MPFA_Face.cpp
92 }
93 }
94
95 for (int n = 0; n < N; n++)
96 if ((!alp || (*alp)(e, n) > 0.25) && flux(n)) /* below 0.5e-6, assume evanescence handles it */
97 dt = std::min(dt, vol * (a_r ? (*a_r)(e, n) : 1) / flux(n));
98 }
99 return Process::mp_min(dt);
100}
101/*! @brief Dimensions the blocks of matrices for the PolyMAC_MPFA face diffusion operator
102 *
103 * This method is responsible for dimensioning the matrix blocks used in the diffusion
104 * operation for the PolyMAC_MPFA face discretization scheme. It calculates the stencil
105 * for the diffusion operator and allocates the necessary memory for the matrix.
106 *
107 * @param matrices A map of matrices where the matrix for the unknown field will be stored.
108 * @param semi_impl A map indicating semi-implicit fields.
109 */
110void Op_Diff_PolyMAC_MPFA_Face::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
111{
112 const Champ_Face_PolyMAC_MPFA& ch = ref_cast(Champ_Face_PolyMAC_MPFA, equation().inconnue());
113 const std::string& nom_inco = ch.le_nom().getString();
114 if (!matrices.count(nom_inco) || semi_impl.count(nom_inco))
115 return; //semi-implicit or no diagonal block -> nothing to do
116
117 const Domaine_PolyMAC_MPFA& domaine = ref_cast(Domaine_PolyMAC_MPFA, le_dom_poly_.valeur());
118 const IntTab& f_e = domaine.face_voisins(), &e_f = domaine.elem_faces(), &fcl = ch.fcl(), &equiv = domaine.equiv();
119 const DoubleTab& nf = domaine.face_normales();
120 const DoubleVect& fs = domaine.face_surfaces();
121
122 Matrice_Morse& mat = *matrices.at(nom_inco), mat2;
123
124 const int N = ch.valeurs().line_size(), ne_tot = domaine.nb_elem_tot(), nf_tot = domaine.nb_faces_tot(), D = dimension;
125
126 Stencil stencil(0, 2), tpfa(0, N);
127
128 domaine.creer_tableau_faces(tpfa);
129
130 /* flux stencils: reduced stencils from update_nu if nu is constant or scalar, full domain stencils otherwise */
131 update_phif(!nu_constant_ or equation().domaine_dis().domaine().deformable()); //if nu is variable, full stencil
132
133 Cerr << "Op_Diff_PolyMAC_MPFA_Face::dimensionner() : ";
134
135 for (int f = 0; f < domaine.nb_faces(); f++)
136 if (fcl(f, 0) < 2)
137 for (int i = 0; i < 2; i++)
138 {
139 const int e = f_e(f, i); /* operator at faces: contribution from element e */
140 if (e < 0) continue;
141
142 //find i_f: index of f in element e
143 int i_f = -1;
144 for (int j = 0; j < e_f.dimension(1); j++)
145 {
146 const int fb = e_f(e, j);
147 if (fb < 0) continue;
148
149 if (fb == f)
150 i_f = j;
151 }
152
153 //contribution of diffusion to face fb
154 for (int j = 0; j < e_f.dimension(1); j++)
155 {
156 const int fb = e_f(e, j);
157 if (fb < 0) continue;
158
159 const int c = (e != f_e(fb, 0));
160 for (int k = phif_d(fb); k < phif_d(fb + 1); k++)
161 {
162 const int e_s = phif_e(k);
163
164 if (e_s >= ne_tot) continue; //boundary -> no matrix term
165
166 const int fc = equiv(fb, c, i_f);
167 const int f_s = (e_s == e) ? f : fc;
168
169 if (fc >= 0 && fcl(f_s, 0) < 2) /* upwind/downwind if equivalence: operator between faces */
170 for (int n = 0; n < N; n++)
171 stencil.append_line(N * f + n, N * f_s + n);
172
173 /* otherwise: element -> face, with special handling when e_s == e to avoid checkerboard modes in diffusion */
174 for (int d = 0; d < D; d++)
175 if (std::fabs(nf(f, d)) > 1e-6 * fs(f))
176 for (int n = 0; n < N; n++)
177 stencil.append_line(N * f + n, N * (nf_tot + D * e_s + d) + n);
178
179 if (e_s == e)
180 for (int n = 0; n < N; n++)
181 stencil.append_line(N * f + n, N * f + n);
182 }
183
184 }
185 }
186
187 for (int e = 0; e < ne_tot; e++)
188 for (int i = 0; i < e_f.dimension(1); i++) /* at elements: virtual elements must also be processed */
189 {
190 const int f = e_f(e, i);
191 if (f < 0) continue;
192
193 for (int j = phif_d(f); j < phif_d(f + 1); j++)
194 {
195 const int e_s = phif_e(j);
196 if (e_s < ne_tot) //contribution from an element
197 for (int d = 0; d < D; d++)
198 for (int n = 0; n < N; n++)
199 stencil.append_line(N * (nf_tot + D * e + d) + n, N * (nf_tot + D * e_s + d) + n);
200 }
201 }
202
203 tpfa = 1;
204
205 for (int f = 0; f < domaine.nb_faces(); f++)
206 for (int i = phif_d(f); i < phif_d(f + 1); i++)
207 {
208 const int e_s = phif_e(i);
209 if (e_s < ne_tot && e_s != f_e(f, 0) && e_s != f_e(f, 1))
210 for (int n = 0; n < N; n++)
211 if (phif_c(i, n))
212 tpfa(f, n) = 0;
213 }
214
215 tableau_trier_retirer_doublons(stencil);
216#ifndef TRUST_USE_GPU
217 const double face_t = static_cast<double>(domaine.md_vector_faces()->nb_items_seq_tot()),
218 elem_t = static_cast<double>(domaine.domaine().md_vector_elements()->nb_items_seq_tot());
219 const double width = mp_sum_as_double(stencil.dimension(0)) / (N * (face_t + D * elem_t));
220 const double perc = mp_somme_vect_as_double(tpfa) * 100. / (N * face_t);
221 Cerr << "width " << width << " " << perc << "% TPFA " << finl;
222#endif
223 Matrix_tools::allocate_morse_matrix(N * (nf_tot + ne_tot * D), N * (nf_tot + ne_tot * D), stencil, mat2);
224
225 if (mat.nb_colonnes())
226 mat += mat2;
227 else
228 mat = mat2;
229}
230
231
232/*! @brief Adds blocks to the matrices for the PolyMAC_MPFA face diffusion operator.
233 *
234 * This method adds the diffusion contributions to the matrix and the secondary memory.
235 * It handles both internal and boundary faces, and updates the matrix and secondary
236 * memory based on the diffusion coefficients and the stencil computed in the
237 * dimensioning step.
238 *
239 * @param matrices A map of matrices where the matrix for the unknown field will be stored.
240 * @param secmem Secondary memory array to store additional contributions.
241 * @param semi_impl A map indicating semi-implicit fields.
242 */
243void Op_Diff_PolyMAC_MPFA_Face::ajouter_blocs(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
244{
245 const std::string& nom_inco = equation().inconnue().le_nom().getString();
246 Matrice_Morse *mat = matrices.count(nom_inco) && !semi_impl.count(nom_inco) ? matrices[nom_inco] : nullptr; //facultatif
247
248 const DoubleTab& inco = semi_impl.count(nom_inco) ? semi_impl.at(nom_inco) : le_champ_inco ? le_champ_inco->valeurs() : equation().inconnue().valeurs();
249
250 const Champ_Face_PolyMAC_MPFA& ch = ref_cast(Champ_Face_PolyMAC_MPFA, equation().inconnue());
251 const Domaine_PolyMAC_MPFA& domaine = ref_cast(Domaine_PolyMAC_MPFA, le_dom_poly_.valeur());
252 const Conds_lim& cls = la_zcl_poly_->les_conditions_limites();
253 const IntTab& f_e = domaine.face_voisins(), &e_f = domaine.elem_faces(), &fcl = ch.fcl(), &equiv = domaine.equiv();
254 const DoubleVect& fs = domaine.face_surfaces(), &vf = domaine.volumes_entrelaces(), &ve = domaine.volumes(), &pf = porosite_f, &pe = porosite_e;
255 const DoubleTab& nf = domaine.face_normales(), &xp = domaine.xp(), &xv = domaine.xv(), &vfd = domaine.volumes_entrelaces_dir();
256
257 const int N = inco.line_size(), D = dimension, ne_tot = domaine.nb_elem_tot(), nf_tot = domaine.nb_faces_tot();
258
259 update_phif(equation().domaine_dis().domaine().deformable());
260
261 DoubleTrav coeff(N), fac(N);
262
263 for (int f = 0; f < domaine.nb_faces(); f++)
264 {
265 if (fcl(f, 0) < 2)
266 {
267 for (int i = 0; i < 2; i++ )
268 {
269 int e = f_e(f, i);
270 if (e < 0) continue;
271
272 // Find i_f: index of face f in element e
273 int i_f = -1;
274 for (int j = 0; i_f < 0 && j < e_f.dimension(1); j++)
275 {
276 const int fb = e_f(e, j);
277 if (fb < 0) continue;
278
279 if (fb == f)
280 i_f = j;
281 }
282
283 // Contribution of diffusion to face fb
284 for (int j = 0; j < e_f.dimension(1); j++)
285 {
286 int fb = e_f(e, j);
287 if (fb < 0) continue;
288
289 int tpfa = 1;
290 for (int k = phif_d(fb); k < phif_d(fb + 1); k++)
291 {
292 int e_s = phif_e(k);
293 if (e_s < ne_tot && e_s != f_e(fb, 0) && e_s != f_e(fb, 1))
294 tpfa = 0;
295 }
296
297 double df_sur_d = tpfa && fcl(fb, 0) && fs(fb) > 0.0 ?
298 std::max(std::fabs(domaine.dot(&xv(fb, 0), &nf(fb, 0), &xv(f, 0)) / domaine.dot(&xv(fb, 0), &nf(fb, 0), &xp(e, 0))), 1.0) : 1.0;
299
300 int c = (e != f_e(fb, 0));
301 for (int n = 0; n < N; n++)
302 coeff[n] = vfd(f, i) / ve(e) * fs(fb) * (c ? 1 : -1) / df_sur_d;
303
304 for (int k = phif_d(fb); k < phif_d(fb + 1); k++)
305 {
306 for (int n = 0; n < N; n++)
307 fac[n] = coeff[n] * phif_c(k, n);
308
309 int e_s = phif_e(k);
310 int fc = equiv(fb, c, i_f);
311
312 if (e_s >= ne_tot)
313 {
314 // Contribution from a boundary
315 int f_s = e_s - ne_tot;
316 if (fcl(f_s, 0) == 3 && sub_type(Dirichlet, cls[fcl(f_s, 1)].valeur()))
317 {
318 for (int d = 0; d < D; d++)
319 for (int n = 0; n < N; n++)
320 secmem(f, n) -= fac[n] * ref_cast(Dirichlet, cls[fcl(f_s, 1)].valeur()).val_imp(fcl(f_s, 2), N * d + n) * nf(f, d) / fs(f);
321 }
322 }
323 else if (tpfa && fc >= 0)
324 {
325 // Upwind/downwind if equivalence: operator between faces
326 int f_s = (e_s == e) ? f : fc;
327 int sgn = (domaine.dot(&nf(f_s, 0), &nf(f, 0)) > 0) ? 1 : -1;
328 for (int n = 0; n < N; n++)
329 secmem(f, n) -= fac[n] * sgn * pf(f_s) / pe(e_s) * inco(f_s, n);
330
331 if (mat && fcl(f_s, 0) < 2)
332 for (int n = 0; n < N; n++)
333 (*mat)(N * f + n, N * f_s + n) += fac[n] * sgn * pf(f_s) / pe(e_s);
334 }
335 else
336 {
337 // Otherwise: element -> face, with special handling
338 double f_eps = (e_s != e) ? 0 : tpfa && fcl(fb, 0) ? 1 : std::min(eps, 1000 * std::pow(vf(f) / fs(f), 2));
339
340 for (int d = 0; d < D; d++)
341 for (int n = 0; n < N; n++)
342 secmem(f, n) -= fac[n] * (1 - f_eps) * inco(nf_tot + D * e_s + d, n) * nf(f, d) / fs(f);
343
344 if (mat)
345 for (int d = 0; d < D; d++)
346 if (std::fabs(nf(f, d)) > 1e-6 * fs(f))
347 for (int n = 0; n < N; n++)
348 (*mat)(N * f + n, N * (nf_tot + D * e_s + d) + n) += fac[n] * (1 - f_eps) * nf(f, d) / fs(f);
349
350 if (!f_eps) continue;
351
352 for (int n = 0; n < N; n++)
353 secmem(f, n) -= fac[n] * f_eps * inco(f, n);
354
355 if (mat)
356 for (int n = 0; n < N; n++)
357 (*mat)(N * f + n, N * f + n) += fac[n] * f_eps;
358 }
359 }
360 }
361 }
362 }
363 }
364
365 for (int e = 0; e < ne_tot; e++)
366 for (int i = 0; i < e_f.dimension(1); i++) /* at elements: virtual elements must also be processed */
367 {
368 const int f = e_f(e, i);
369 if (f < 0) continue;
370
371 const int c = (e != f_e(f, 0));
372
373 for (int j = phif_d(f); j < phif_d(f + 1); j++)
374 {
375 for (int n = 0; n < N; n++)
376 coeff(n) = fs(f) * (c ? 1 : -1) * phif_c(j, n);
377
378 const int e_s = phif_e(j);
379 const int f_s = e_s - ne_tot;
380
381 if (e_s < ne_tot) //contribution from an element
382 {
383 for (int d = 0; d < D; d++)
384 for (int n = 0; n < N; n++)
385 secmem(nf_tot + D * e + d, n) -= coeff(n) * inco(nf_tot + D * e_s + d, n);
386
387 if (mat)
388 for (int d = 0; d < D; d++)
389 for (int n = 0; n < N; n++)
390 (*mat)(N * (nf_tot + D * e + d) + n, N * (nf_tot + D * e_s + d) + n) += coeff(n);
391 }
392 else if (fcl(f_s, 0) == 3 && sub_type(Dirichlet, cls[fcl(f_s, 1)].valeur())) //contribution from a boundary: only Dirichlet contributes
393 for (int d = 0; d < D; d++)
394 for (int n = 0; n < N; n++)
395 secmem(nf_tot + D * e + d, n) -= coeff(n) * ref_cast(Dirichlet, cls[fcl(f_s, 1)].valeur()).val_imp(fcl(f_s, 2), N * d + n);
396 }
397 }
398}
: class Champ_Face_PolyMAC_MPFA
const IntTab & fcl() const
DoubleTab & valeurs() override
Returns the array of field values at the current time.
virtual DoubleTab & valeurs()=0
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 defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual const Milieu_base & milieu() const =0
virtual const Champ_Inc_base & inconnue() const =0
const Nom & le_nom() const override
Returns the name of the field.
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
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
Dimensions the blocks of matrices for the PolyMAC_MPFA face diffusion operator.
void completer() override
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its equation.
void ajouter_blocs(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={ }) const override
Adds blocks to the matrices for the PolyMAC_MPFA face diffusion operator.
class Op_Diff_PolyMAC_MPFA_base
void completer() override
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its equation.
void update_phif(int full_stencil=0) const
DoubleTab flux_bords_
Multiphase thermohydraulics problem of type "3*N equations":
static double mp_min(double)
Definition Process.cpp:391
static double mp_sum_as_double(int v)
Definition Process.h:97
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
Base class for output streams.
Definition Sortie.h:52
virtual const Champ_base & get_champ_masse_volumique() const
Returns the density field.
virtual int has_champ_masse_volumique() const
Returns 1 if the density field has been associated, 0 otherwise.
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
int line_size() const
Definition TRUSTVect.tpp:67