TrioCFD 1.9.9_beta
TrioCFD documentation
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 /* requires a ghost layer of width 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; //already computed at this time step, nothing to do
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())); //triggers gradient computation
89
90 Stencil sten_p(0, 2), sten_v(0, 2); //stencils (NS, pressure), (NS, velocity)
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; //dependencies: velocities -(dpb_v)-> boundary pressures -(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 /* at faces: gradient at faces + filling of dgp_pb */
120 std::vector<std::set<int>> dfgpf(N); //dfgpf[n][idx] = coeff: dependency on pfb variables (present in 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++) //internal face -> multi-point flux
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 /* upwind/downwind elements -> 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; // virtual element
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 /* at elements: gradient at elements */
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 in a single row */
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 / filling */
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 at boundaries, (grad p)_f, alpha * vol product
241
242 //std::map<int, std::map<int, double>> dgp_gb, dgb_v; //velocity dependencies -(dgb_v)-> -grad p at boundaries -(dgp_gb)-> grad p elsewhere
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/Symmetry: neighbor pressure + correction from the NS equation in that cell
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[index in 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)) //loop over directions: i is the index in mat_v
258 {
259 gb(f, m) += fac * nf(f, d) * secmem(i, n); //constant part -> directly into 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++) //linear part -> into 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 /* at faces */
274 //std::vector<std::map<int, double>> dgf_pe(N), dgf_gb(N); //dependence of [grad p]_f on element pressures and on grad p at boundary faces
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 /* upwind/downwind elements -> 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 of mat_NS: in a single line! */
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
Returns the array of field values at the current time.
double recuperer_temps_passe(int i=1) const
Returns the time of the i-th past field.
class Conds_lim This class represents a vector of boundary conditions.
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
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
Navier_Stokes_std This class carries the terms of the momentum equation.
Classe Neumann This class is the base class of the hierarchy of Neumann-type boundary conditions.
Definition Neumann.h:31
const std::string & getString() const
Definition Nom.h:92
static int dimension
Definition Objet_U.h:94
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
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
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
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
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()
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":
static void abort()
Abort routine for TRUST on a fatal error.
Definition Process.cpp:573
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
void append_line(_TYPE_)
Definition TRUSTTab.tpp:213
int line_size() const
Definition TRUSTVect.tpp:67