TrioCFD 1.9.8
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(); // cas flica5 : ce n'est pas l'inconnue qui est utilisee, donc on cree les variables auxiliaires ici
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); /* produit alpha * rho */
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)) /* sous 0.5e-6, on suppose que l'evanescence fait le job */
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-implicite ou pas de bloc diagonal -> rien a faire
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 /* stencils du flux : ceux (reduits) de update_nu si nu constant ou scalaire, ceux (complets) du domaine sinon */
131 update_phif(!nu_constant_ or equation().domaine_dis().domaine().deformable()); //si nu variable, stencil complet
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); /* op. aux faces : contrib de l'elem e */
140 if (e < 0) continue;
141
142 //recherche de i_f : indice de f dans l'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 de la diffusion a la 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; //bord -> pas de terme de matrice
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) /* amont/aval si equivalence : operateur entre faces */
170 for (int n = 0; n < N; n++)
171 stencil.append_line(N * f + n, N * f_s + n);
172
173 /* sinon : elem -> face, avec un traitement particulier de e_s == e pour eviter les modes en echiquier dans la 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++) /* aux elements : on doit traiter aussi les elems virtuels */
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) //contrib d'un 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 // Recherche de i_f : indice de la face f dans l'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 de la diffusion a la 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 d'un bord
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 // Amont/aval si equivalence : operateur entre 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 // Sinon : element -> face, avec traitement particulier
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++) /* aux elements : on doit traiter aussi les elems virtuels */
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) //contrib d'un 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())) //contrib d'un bord : seul Dirichlet contribue
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
Renvoie le tableau des valeurs du champ au temps courant.
virtual DoubleTab & valeurs()=0
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
classe Dirichlet Cette classe est la classe de base de la hierarchie des conditions aux limites de ty...
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
Renvoie le nom du champ.
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
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
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
const std::string & getString() const
Definition Nom.h:92
static int dimension
Definition Objet_U.h:99
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
double calculer_dt_stab() const override
Calcul 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
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son 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
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
void update_phif(int full_stencil=0) const
DoubleTab flux_bords_
classe Pb_Multiphase Cette classe represente un probleme de thermohydraulique multiphase de type "3*N...
static double mp_min(double)
Definition Process.cpp:386
static double mp_sum_as_double(int v)
Definition Process.h:99
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Classe de base des flux de sortie.
Definition Sortie.h:52
virtual const Champ_base & get_champ_masse_volumique() const
Renvoie le champ de masse volumique.
virtual int has_champ_masse_volumique() const
Renvoie 1 si la masse volumique a ete associee, 0 sinon.
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
int line_size() const
Definition TRUSTVect.tpp:67