TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Op_Grad_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_Grad_PolyMAC_MPFA_Face.h>
17#include <Champ_Elem_PolyMAC_MPFA.h>
18#include <Masse_PolyMAC_MPFA_Face.h>
19#include <Champ_Face_PolyMAC_MPFA.h>
20#include <Neumann_sortie_libre.h>
21#include <Domaine_Cl_PolyMAC_family.h>
22#include <Navier_Stokes_std.h>
23#include <Pb_Multiphase.h>
24#include <Probleme_base.h>
25#include <Matrix_tools.h>
26#include <Array_tools.h>
27#include <Milieu_base.h>
28#include <Periodique.h>
29#include <TRUSTTrav.h>
30#include <Check_espace_virtuel.h>
31#include <Dirichlet_homogene.h>
32#include <Schema_Temps_base.h>
33#include <Dirichlet.h>
34#include <Symetrie.h>
35
36Implemente_instanciable(Op_Grad_PolyMAC_MPFA_Face, "Op_Grad_PolyMAC_MPFA_Face", Op_Grad_PolyMAC_HFV_Face);
37
39
41
43{
45
46 const Domaine_PolyMAC_MPFA& domaine = ref_cast(Domaine_PolyMAC_MPFA, ref_domaine.valeur());
47
48 /* besoin d'un joint de 1 */
49 if (domaine.domaine().nb_joints() && domaine.domaine().joint(0).epaisseur() < 1)
50 {
51 Cerr << "Op_Grad_PolyMAC_MPFA_Face : largeur de joint insuffisante (minimum 1)!" << finl;
53 }
54
55 if (sub_type(Navier_Stokes_std, equation()) && ref_cast(Navier_Stokes_std, equation()).has_grad_P())
56 {
57 Champ_Face_PolyMAC_MPFA& gradp = ref_cast(Champ_Face_PolyMAC_MPFA, ref_cast(Navier_Stokes_std, equation()).grad_P());
59 }
60}
61
62void Op_Grad_PolyMAC_MPFA_Face::update_grad(int full_stencil) const
63{
64 const Domaine_PolyMAC_MPFA& domaine = ref_cast(Domaine_PolyMAC_MPFA, ref_domaine.valeur());
65 const Champ_Face_PolyMAC_MPFA& ch = ref_cast(Champ_Face_PolyMAC_MPFA, equation().inconnue());
66 const DoubleTab& press = le_champ_inco ? le_champ_inco->valeurs() : ref_cast(Navier_Stokes_std, equation()).pression().valeurs(),
67 *alp = sub_type(Pb_Multiphase, equation().probleme()) ? &ref_cast(Pb_Multiphase, equation().probleme()).equation_masse().inconnue().passe() : nullptr;
68 const int M = press.line_size();
69 double t_past = equation().inconnue().recuperer_temps_passe();
70 if (!domaine.domaine().mesh_update_required() && !full_stencil && (alp ? (last_gradp_ >= t_past) : (last_gradp_ != -DBL_MAX)))
71 return; //deja calcule a ce temps -> rien a faire
72
73 /* gradient */
74 domaine.fgrad(M, 1, ref_dcl->les_conditions_limites(), ch.fcl(), nullptr, nullptr, 1, full_stencil, fgrad_d, fgrad_e, fgrad_c);
75 last_gradp_ = t_past;
76}
77
78void Op_Grad_PolyMAC_MPFA_Face::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
79{
80 const Domaine_PolyMAC_MPFA& domaine = ref_cast(Domaine_PolyMAC_MPFA, ref_domaine.valeur());
81 const Champ_Face_PolyMAC_MPFA& ch = ref_cast(Champ_Face_PolyMAC_MPFA, equation().inconnue());
82 const IntTab& f_e = domaine.face_voisins(), &e_f = domaine.elem_faces(), &fcl = ch.fcl();
83 const DoubleTab& nf = domaine.face_normales(), &xp = domaine.xp(), &xv = domaine.xv();
84 const DoubleVect& fs = domaine.face_surfaces(), &ve = domaine.volumes();
85 const int ne_tot = domaine.nb_elem_tot(), nf_tot = domaine.nb_faces_tot(), D = dimension, N = ch.valeurs().line_size(),
86 M = (le_champ_inco ? le_champ_inco->valeurs() : ref_cast(Navier_Stokes_std, equation()).pression().valeurs()).line_size();
87
88 update_grad(domaine.domaine().deformable() || sub_type(Pb_Multiphase, equation().probleme())); //provoque le calcul du gradient
89
90 Stencil sten_p(0, 2), sten_v(0, 2); //stencils (NS, pression), (NS, vitesse)
91
92 const std::string& nom_inc = ch.le_nom().getString();
93 Matrice_Morse *mat_p = matrices["pression"],
94 *mat_v = !semi_impl.count(nom_inc) && matrices.count(nom_inc) ? matrices.at(nom_inc) : nullptr,
95 mat2_p, mat2_v;
96
97 std::map<int, std::set<int>> dpb_v, dgp_pb; //dependances vitesses -(dpb_v)-> pressions au bord -(dgp_pb)-> gradient
98
99 if (mat_v)
100 for (int f = 0; f < domaine.nb_faces_tot(); f++)
101 if (fcl(f, 0) > 1)
102 {
103 const int e = f_e(f, 0);
104 int m = 0;
105 for (int n = 0; n < N; n++, m += (M > 1))
106 {
107 int i = nf_tot + D * e;
108 for (int d = 0; d < D; d++, i++)
109 if (std::fabs(nf(f, d)) > 1e-6 * fs(f))
110 {
111 dpb_v[M * f + m].insert(N * i + n);
112
113 for (auto j = mat_v->get_tab1()(N * i + n) - 1; j < mat_v->get_tab1()(N * i + n + 1) - 1; j++)
114 dpb_v[M * f + m].insert(mat_v->get_tab2()(j) - 1);
115 }
116 }
117 }
118
119 /* aux faces : gradient aux faces + remplissage de dgp_pb */
120 std::vector<std::set<int>> dfgpf(N); //dfgpf[n][idx] = coeff : dependance en les pfb variables (presents dans dpf_ve)
121 for (int f = 0; f < domaine.nb_faces_tot(); f++)
122 {
123 /* |f| grad p */
124 for (int i = fgrad_d(f); i < fgrad_d(f + 1); i++) //face interne -> flux multipoints
125 {
126 const int e = fgrad_e(i);
127 int m = 0;
128 for (int n = 0; n < N; n++, m += (M > 1))
129 {
130 if (f < domaine.nb_faces() && e < ne_tot)
131 sten_p.append_line(N * f + n, M * e + m);
132
133 if (e >= ne_tot && dpb_v.count(M * (e - ne_tot) + m))
134 dfgpf[n].insert(M * (e - ne_tot) + m);
135 }
136 }
137
138 /* face -> vf(f) * phi grad p */
139 if (fcl(f, 0) < 2 && f < domaine.nb_faces())
140 {
141 int m = 0;
142 for (int n = 0; n < N; n++, m += (M > 1))
143 for (auto &c : dfgpf[n])
144 dgp_pb[N * f + n].insert(M * c + m);
145 }
146
147 /* elems amont/aval -> ve(e) * phi grad p */
148 for (int i = 0; i < 2; i++)
149 {
150 const int e = f_e(f, i);
151 if (e < 0) continue; // elem virt
152
153 if (e < domaine.nb_elem())
154 for (int d = 0; d < D; d++)
155 if (fs(f) * std::fabs(xv(f, d) - xp(e, d)) > 1e-6 * ve(e))
156 {
157 int m = 0;
158 for (int n = 0; n < N; n++, m += (M > 1))
159 for (auto &c : dfgpf[n])
160 dgp_pb[N * (nf_tot + D * e + d) + n].insert(M * c + m);
161 }
162 }
163
164 for (int n = 0; n < N; n++)
165 dfgpf[n].clear();
166 }
167
168 /* aux elements : gradient aux elems */
169 for (int e = 0; e < domaine.nb_elem(); e++)
170 for (int i = 0; i < e_f.dimension(1); i++)
171 {
172 const int f = e_f(e, i);
173 if (f < 0) continue; // face in-existante
174
175 for (int j = fgrad_d(f); j < fgrad_d(f + 1); j++)
176 {
177 const int eb = fgrad_e(j);
178 if (eb < ne_tot)
179 for (int d = 0; d < D; d++)
180 if (std::fabs(fs(f) * (xv(f, d) - xp(e, d))) > 1e-6 * ve(e))
181 {
182 int m = 0;
183 for (int n = 0; n < N; n++, m += (M > 1))
184 sten_p.append_line(N * (nf_tot + D * e + d) + n, M * eb + m);
185 }
186 }
187 }
188
189 /* sten_v en une ligne */
190 for (auto &i_sc : dgp_pb)
191 for (auto &c : i_sc.second)
192 for (auto &k : dpb_v.at(c))
193 sten_v.append_line(i_sc.first, k);
194
195 /* allocation / remplissage */
196 tableau_trier_retirer_doublons(sten_p);
197 tableau_trier_retirer_doublons(sten_v);
198
199 if (mat_p)
200 {
201 Matrix_tools::allocate_morse_matrix(N * (nf_tot + ne_tot * D), M * ne_tot, sten_p, mat2_p);
202
203 if (mat_p->nb_colonnes())
204 *mat_p += mat2_p;
205 else
206 *mat_p = mat2_p;
207 }
208
209 if (mat_v)
210 {
211 Matrix_tools::allocate_morse_matrix(N * (nf_tot + ne_tot * D), N * (nf_tot + ne_tot * D), sten_v, mat2_v);
212
213 if (mat_v->nb_colonnes())
214 *mat_v += mat2_v;
215 else
216 *mat_v = mat2_v;
217 }
218}
219
220void Op_Grad_PolyMAC_MPFA_Face::ajouter_blocs(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
221{
222 const Domaine_PolyMAC_MPFA& domaine = ref_cast(Domaine_PolyMAC_MPFA, ref_domaine.valeur());
223 const Champ_Face_PolyMAC_MPFA& ch = ref_cast(Champ_Face_PolyMAC_MPFA, equation().inconnue());
224 const Conds_lim& cls = ref_dcl->les_conditions_limites();
225 const IntTab& f_e = domaine.face_voisins(), &fcl = ch.fcl();
226 const DoubleTab& nf = domaine.face_normales(), &xp = domaine.xp(), &xv = domaine.xv(), &vfd = domaine.volumes_entrelaces_dir(),
227 &press = semi_impl.count("pression") ? semi_impl.at("pression") : (le_champ_inco ? le_champ_inco->valeurs() : ref_cast(Navier_Stokes_std, equation()).pression().valeurs()),
228 *alp = sub_type(Pb_Multiphase, equation().probleme()) ? &ref_cast(Pb_Multiphase, equation().probleme()).equation_masse().inconnue().passe() : nullptr;
229
230 const DoubleVect& fs = domaine.face_surfaces(), &ve = domaine.volumes(), &pe = equation().milieu().porosite_elem(), &pf = equation().milieu().porosite_face();
231
232 const int ne_tot = domaine.nb_elem_tot(), nf_tot = domaine.nb_faces_tot(), D = dimension, N = secmem.line_size(), M = press.line_size();
233
234 update_grad(domaine.domaine().deformable());
235
236 const std::string& nom_inc = ch.le_nom().getString();
237 Matrice_Morse *mat_p = !semi_impl.count("pression") && matrices.count("pression") ? matrices.at("pression") : nullptr, *mat_v =
238 !semi_impl.count(nom_inc) && matrices.count(nom_inc) ? matrices.at(nom_inc) : nullptr;
239
240 DoubleTrav gb(nf_tot, M), gf(N), a_v(N); //-grad p aux bords , (grad p)_f, produit alpha * vol
241
242 //std::map<int, std::map<int, double>> dgp_gb, dgb_v; //dependances vitesses -(dgb_v)-> -grad p aux bords -(dgp_gb)-> grad p ailleurs
243 dgp_gb_.clear();
244 dgb_v_.clear();
245
246 for (int f = 0; f < domaine.nb_faces_tot(); f++)
247 if (fs(f) > 0 && fcl(f, 0) > 1) //Dirichlet/Symetrie : pression du voisin + correction en regardant l'eq de NS dans celui-ci
248 {
249 const int e = f_e(f, 0);
250 int m = 0;
251 for (int n = 0; n < N; n++, m += (M > 1))
252 {
253 double fac = 1. / (fs(f) * ve(e));
254 std::map<int, double> *dv = mat_v ? &dgb_v_[M * f + m] : nullptr; //dv[indice dans mat_NS] = coeff
255 int i = nf_tot + D * e;
256 for (int d = 0; d < D; d++, i++)
257 if (std::fabs(nf(f, d)) > 1e-6 * fs(f)) //boucle sur la direction : i est l'indice dans mat_v
258 {
259 gb(f, m) += fac * nf(f, d) * secmem(i, n); //partie constante -> directement dans pfb
260
261 if (dv)
262 for (auto j = mat_v->get_tab1()(N * i + n) - 1; j < mat_v->get_tab1()(N * i + n + 1) - 1; j++) //partie lineaire -> dans dgb_v
263 if (mat_v->get_coeff()(j))
264 (*dv)[mat_v->get_tab2()(j) - 1] -= fac * nf(f, d) * mat_v->get_coeff()(j);
265 }
266 }
267 }
268
269 for (int f = 0; f < domaine.nb_faces(); f++)
270 if (fgrad_d(f + 1) == fgrad_d(f))
271 abort();
272
273 /* aux faces */
274 //std::vector<std::map<int, double>> dgf_pe(N), dgf_gb(N); //dependance de [grad p]_f en les pressions aux elements, en les grad p aux faces de bord
275 if (dgf_pe_.size()==0)
276 {
277 dgf_pe_.resize(N);
278 dgf_gb_.resize(N);
279 }
280
281 for (int f = 0; f < domaine.nb_faces_tot(); f++)
282 {
283 for (int n = 0; n < N; n++)
284 dgf_pe_[n].clear(), dgf_gb_[n].clear();
285
286 a_v = 0.;
287
288 for (int i = 0; i < 2; i++)
289 {
290 const int e = f_e(f, i);
291 if (e < 0) continue;
292
293 for (int n = 0; n < N; n++)
294 a_v(n) += vfd(f, i) * (alp ? (*alp)(e, n) : 1);
295 }
296
297 /* |f| grad p */
298 gf = 0.;
299 for (int i = fgrad_d(f); i < fgrad_d(f + 1); i++)
300 {
301 const int e = fgrad_e(i);
302 const int fb = e - ne_tot;
303 int m = 0;
304
305 for (int n = 0; n < N; n++, m += (M > 1))
306 {
307 const double fac = fgrad_c(i, m);
308 const double val = (e < ne_tot ? press(e, m) : fcl(fb, 0) == 1 ? ref_cast(Neumann, cls[fcl(fb, 1)].valeur()).flux_impose(fcl(fb, 2), m) : gb(e - ne_tot, m));
309
310 gf(n) += fac * val;
311
312 if (mat_p && e < ne_tot)
313 dgf_pe_[n].push_back({e, fac});
314
315 if (mat_v && fb >= 0 && dgb_v_.count(M * fb + m))
316 dgf_gb_[n].push_back({M * fb + m, fac});
317 }
318 }
319
320 /* face -> vf(f) * phi grad p */
321 if (fcl(f, 0) < 2 && f < domaine.nb_faces())
322 {
323 int m = 0;
324 for (int n = 0; n < N; n++, m += (M > 1))
325 {
326 const double fac = a_v(n) * pf(f);
327 secmem(f, n) -= fac * gf(n);
328
329 for (auto &&i_c : dgf_pe_[n])
330 (*mat_p)(N * f + n, M * i_c.first + m) += fac * i_c.second;
331
332 for (auto &&i_c : dgf_gb_[n])
333 dgp_gb_[N * f + n][M * i_c.first + m] += fac * i_c.second;
334 }
335 }
336
337 /* elems amont/aval -> ve(e) * phi grad p */
338 for (int i = 0; i < 2; i++)
339 {
340 const int e = f_e(f, i);
341 if (e < 0) continue;
342
343 if (e < domaine.nb_elem())
344 for (int d = 0; d < D; d++)
345 if (fs(f) * std::fabs(xv(f, d) - xp(e, d)) > 1e-6 * ve(e))
346 {
347 int m = 0;
348 for (int n = 0; n < N; n++, m += (M > 1))
349 {
350 const double fac = (i ? -1 : 1) * fs(f) * pe(e) * (xv(f, d) - xp(e, d)) * (alp ? (*alp)(e, n) : 1);
351
352 secmem(nf_tot + D * e + d, n) -= fac * gf(n);
353
354 for (auto &i_c : dgf_pe_[n])
355 (*mat_p)(N * (nf_tot + D * e + d) + n, M * i_c.first + m) += fac * i_c.second;
356
357 for (auto &i_c : dgf_gb_[n])
358 dgp_gb_[N * (nf_tot + D * e + d) + n][M * i_c.first + m] += fac * i_c.second;
359 }
360 }
361 }
362 }
363
364 /* correction de mat_NS : en une seule ligne! */
365 if (mat_v)
366 for (auto &i_jc : dgp_gb_)
367 for (auto &j_c : i_jc.second)
368 if (dgb_v_.count(j_c.first))
369 for (auto &k_d : dgb_v_.at(j_c.first))
370 (*mat_v)(i_jc.first, k_d.first) += j_c.second * k_d.second;
371
372}
: class Champ_Face_PolyMAC_MPFA
const IntTab & fcl() const
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
double recuperer_temps_passe(int i=1) const
Retourne le temps du ieme champ passe.
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
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
classe Navier_Stokes_std Cette classe porte les termes de l'equation de la dynamique
Classe Neumann Cette classe est la classe de base de la hierarchie des conditions aux limites de type...
Definition Neumann.h:31
const std::string & getString() const
Definition Nom.h:92
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
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
class Op_Grad_PolyMAC_HFV_Face
class Op_Grad_PolyMAC_MPFA_Face
void update_grad(int full_stencil=0) const
std::map< int, std::map< int, double > > dgb_v_
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
void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={ }) const override
std::map< int, std::map< int, double > > dgp_gb_
std::vector< std::vector< std::pair< int, double > > > dgf_pe_
std::vector< std::vector< std::pair< int, double > > > dgf_gb_
virtual void completer()
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
classe Pb_Multiphase Cette classe represente un probleme de thermohydraulique multiphase de type "3*N...
static void abort()
Routine de sortie de Trio-U sur une erreur abort().
Definition Process.cpp:570
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
void append_line(_TYPE_)
Definition TRUSTTab.tpp:213
int line_size() const
Definition TRUSTVect.tpp:67