TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Domaine_PolyMAC_MPFA.cpp
1/****************************************************************************
2* Copyright (c) 2025, 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 <Echange_contact_PolyMAC_MPFA.h>
17#include <Frottement_externe_impose.h>
18#include <Linear_algebra_tools_impl.h>
19#include <Frottement_global_impose.h>
20#include <Champ_implementation_P1.h>
21#include <Connectivite_som_elem.h>
22#include <MD_Vector_composite.h>
23#include <Dirichlet_homogene.h>
24#include <MD_Vector_tools.h>
25#include <Domaine_PolyMAC_MPFA.h>
26#include <Domaine_Cl_PolyMAC_family.h>
27#include <TRUSTTab_parts.h>
28#include <Comm_Group_MPI.h>
29#include <Quadrangle_VEF.h>
30#include <communications.h>
31#include <Hexaedre_VEF.h>
32#include <Matrix_tools.h>
33#include <unordered_map>
34#include <Array_tools.h>
35#include <TRUSTLists.h>
36#include <Tetraedre.h>
37#include <Rectangle.h>
38#include <PE_Groups.h>
39#include <Hexaedre.h>
40#include <Triangle.h>
41#include <EFichier.h>
42#include <SFichier.h>
43#include <Segment.h>
44#include <Domaine.h>
45#include <Scatter.h>
46#include <EChaine.h>
47#include <LireMED.h>
48#include <Ecrire_MED.h>
49#include <unistd.h>
50#include <Lapack.h>
51#include <numeric>
52#include <vector>
53#include <cfloat>
54#include <tuple>
55#include <cmath>
56#include <cfenv>
57#include <set>
58#include <map>
59
60Implemente_instanciable(Domaine_PolyMAC_MPFA, "Domaine_PolyMAC_MPFA", Domaine_PolyMAC_HFV);
61
63
65
67{
68 /* on saut le discretiser() de Domaine_PolyMAC_HFV pour eviter d'initialiser les variables de PolyMAC_HFV_V1 */
70
71 //MD_vector pour Champ_Face_PolyMAC_MPFA (faces + dimension * champ_p0)
72 MD_Vector_composite mdc_ch_face;
73 mdc_ch_face.add_part(md_vector_faces());
74 mdc_ch_face.add_part(domaine().md_vector_elements(), dimension);
75 mdv_ch_face.copy(mdc_ch_face);
76}
77
78/*! @brief Initializes the face stencils for gradient computation
79 *
80 * This method builds the connectivity stencils required for face-based gradient calculations
81 * in the PolyMAC_MPFA discretization scheme. It establishes the relationship between faces
82 * and all elements/boundary faces that are connected through shared vertices.
83 *
84 * The stencil for each face includes:
85 * - All elements connected to the face through any of its vertices
86 * - All boundary faces connected to the face through shared vertices
87 * - The face's direct neighboring elements
88 *
89 * @note This method is called lazily - it only performs initialization if stencils
90 * haven't been built yet (checked via fsten_d.size())
91 *
92 * @note The method populates two main data structures:
93 * - fsten_d: Index array for stencil boundaries
94 * - fsten_eb: Flat array containing all stencil elements/boundary faces
95 *
96 * @details Algorithm overview:
97 * 1. Build vertex-to-element connectivity (som_eb)
98 * 2. Add boundary faces to vertex connectivity
99 * 3. For each face, collect all elements/boundary faces connected via vertices
100 * 4. Store results in compressed sparse format
101 *
102 * @post After execution:
103 * - fsten_d(f) gives the starting index in fsten_eb for face f's stencil
104 * - fsten_d(f+1) gives the ending index (exclusive) for face f's stencil
105 * - fsten_eb contains the actual element/boundary face indices
106 * - Boundary faces are represented as (ne_tot + face_index)
107 *
108 * @note Memory is optimized using CRIMP() to reduce storage overhead
109 *
110 * @note Only processes faces that have at least one valid neighbor:
111 * - Internal faces: both neighbors must be valid
112 * - Boundary faces: at least one neighbor must be valid
113 *
114 * @see fgrad() which uses these stencils for gradient computation
115 */
117{
118 if (fsten_d.size())
119 return;
120
121 const IntTab& f_s = face_sommets(), &f_e = face_voisins(), &e_s = domaine().les_elems();
122 const int ne_tot = nb_elem_tot(), ns_tot = domaine().nb_som_tot();
123 fsten_d.resize(1);
124
125 /* connectivite sommets -> elems / faces de bord */
126 std::vector<std::set<int>> som_eb(ns_tot);
127 for (int e = 0; e < nb_elem_tot(); e++)
128 for (int i = 0; i < e_s.dimension(1); i++)
129 {
130 const int s = e_s(e, i);
131 if (s < 0) continue;
132
133 som_eb[s].insert(e);
134 }
135
136 for (int f = 0; f < nb_faces_tot(); f++)
137 if (fbord(f) >= 0)
138 for (int i = 0; i < f_s.dimension(1); i++)
139 {
140 const int s = f_s(f, i);
141 if (s < 0) continue;
142
143 som_eb[s].insert(ne_tot + f);
144 }
145
146 std::set<int> f_eb; //sommets de la face f, elems connectes a e par soms, sommets / faces connectes par une face commune
147 for (int f = 0; f < nb_faces_tot(); fsten_d.append_line(fsten_eb.size()), f++)
148 if (f_e(f, 0) >= 0 && (fbord(f) >= 0 || f_e(f, 1) >= 0))
149 {
150 /* connectivite par un sommet de f */
151 f_eb.clear();
152 for (int i = 0; i < f_s.dimension(1); i++)
153 {
154 const int s = f_s(f, i);
155 if (s < 0) continue;
156
157 for (auto &&el : som_eb[s])
158 f_eb.insert(el);
159 }
160
161 /* remplissage */
162 for (auto &&el : f_eb)
163 fsten_eb.append_line(el);
164 }
165
166 CRIMP(fsten_d);
167 CRIMP(fsten_eb);
168}
169
170/*! @brief Computes field gradient interpolation at faces while preserving constant fields
171 *
172 * This method computes the interpolation [n_f.grad T]_f (if nu_grad = 0) or [n_f.nu.grad T]_f
173 * while exactly preserving fields satisfying [nu grad T]_e = constant.
174 * It uses MPFA (Multi-Point Flux Approximation) methods with three strategies:
175 * - Attempt 0: Standard MPFA-O
176 * - Attempt 1: MPFA-eta: variant of MPFA-O where auxiliary variables are not in the barycenter of the face
177 * - Attempt 2: Symmetric MPFA if previous attempts fail (coercive but not always consistent, especially on complex meshes)
178 *
179 * @param N Number of field components
180 * @param is_p Pressure field indicator (1 for pressure, 0 otherwise)
181 * Controls Neumann/Dirichlet inversion for boundary conditions
182 * @param cls Domain boundary conditions
183 * @param fcl Boundary condition data
184 * fcl(f, 0/1/2): (BC type, BC index, index within BC)
185 * See Champ_{P0,Face}_PolyMAC_MPFA for format
186 * @param nu Element diffusivity (optional, can be nullptr)
187 * Array nu(e, n, ..) for element e and component n
188 * @param som_ext List of vertices to exclude from processing (optional)
189 * Example: direct treatment of Echange_Contact in Op_Diff_PolyMAC_MPFA_Elem
190 * @param virt Virtual faces indicator (1 to include, 0 otherwise)
191 * @param full_stencil Complete stencil indicator (1 for full dimensioning)
192 *
193 * @param[out] phif_d Start/end indices in phif_{e,c} / phif_{pe,pc}
194 * phif_d(f, 0/1): flux indices at face f in interval
195 * [phif_d(f, 0/1), phif_d(f + 1, 0/1)[
196 * @param[out] phif_e Element indices in stencil for each contribution
197 * phif_e(i): element index for i-th contribution
198 * @param[out] phif_c Stencil coefficients
199 * phif_c(i, n, c): coefficient for element i, component n, contribution c
200 * Contains local indices/coefficients (without Echange_contact)
201 * and diagonal terms (independent components)
202 *
203 * @note The method checks positivity of bilinear form eigenvalues to ensure scheme stability and choose the MPFA method accordingly
204 *
205 * @note The method returns also a percentage of which MPFA method is used. Be careful of the validity of the solution if the percentage of MPFA-sym is high
206 *
207 * @note Special handling for different boundary condition types:
208 * - Dirichlet/Neumann
209 * - Imposed global/external friction
210 * - Imposed global/external exchange
211 *
212 */
213void Domaine_PolyMAC_MPFA::fgrad(int N, int is_p, const Conds_lim& cls, const IntTab& fcl, const DoubleTab *nu, const IntTab *som_ext,
214 int virt, int full_stencil, IntTab& phif_d, IntTab& phif_e, DoubleTab& phif_c) const
215{
216#ifdef _COMPILE_AVEC_PGCC_AVANT_22_7
217 Cerr << "Internal error with nvc++: Internal error: read_memory_region: not all expected entries were read." << finl;
219#else
220 const IntTab& f_e = face_voisins(), &e_f = elem_faces(), &f_s = face_sommets();
221 const DoubleTab& nf = face_normales(), &xs = domaine().coord_sommets();
222 const DoubleVect& fs = face_surfaces(), &vf = volumes_entrelaces();
223 const Static_Int_Lists& s_e = som_elem();
224 int i, i_s, j, k, l, e, f, s, sb, n_f, n_m, n_ef, n_e, n_eb, m, n, ne_tot = nb_elem_tot(), sgn, nw, infoo=-1, d, db,
225 D = dimension, rk=-1, nl, nc, un = 1, il, ok, essai;
226
227 unsigned long ll;
228
229 double x, eps_g = 1e-6, eps = 1e-10, i3[3][3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }}, fac[3], vol_s;
230
232 phif_e.resize(0);
233 phif_c.resize(fsten_eb.dimension(0), N);
234 phif_c = 0;
235
236 std::vector<int> s_eb, s_f; //listes d'elements/bord, de faces autour du sommet
237 std::vector<double> surf_fs, vol_es; //surfaces partielles des faces connectees au sommet (meme ordre que s_f)
238 std::vector<std::array<std::array<double, 3>,2>> vec_fs;//pour chaque facette, base de (D-1) vecteurs permettant de la parcourir
239 std::vector<std::vector<int>> se_f; /* se_f[i][.] : faces connectees au i-eme element connecte au sommet s */
240 DoubleTrav M, B, X, Ff, Feb, Mf, Meb, W(1), x_fs, A, S; //systeme M.(grad u) = B dans chaque element, flux a la face Ff.u_fs + Feb.u_eb, equations Mf.u_fs = Meb.u_eb
241 IntTrav piv, ctr[3];
242 for (i = 0; first_fgrad_ && i < 3; i++) domaine().creer_tableau_sommets(ctr[i]);
243
244 /* contributions aux sommets : en evitant ceux de som_ext */
245 for (i_s = 0; i_s <= (som_ext ? som_ext->size() : 0); i_s++)
246 for (s = (som_ext && i_s ? (*som_ext)(i_s - 1) + 1 : 0); s < (som_ext && i_s < som_ext->size() ? (*som_ext)(i_s) : (virt ? nb_som_tot() : nb_som())); s++)
247 {
248 /* elements connectes a s : a partir de som_elem (deja classes) */
249 for (s_eb.clear(), n_e = 0; n_e < s_e.get_list_size(s); n_e++) s_eb.push_back(s_e(s, n_e));
250 /* faces et leurs surfaces partielles */
251 for (s_f.clear(), surf_fs.clear(), vec_fs.clear(), se_f.resize(std::max(int(se_f.size()), n_e)), i = 0, ok = 1; i < n_e; i++)
252 for (se_f[i].clear(), e = s_eb[i], j = 0; j < e_f.dimension(1) && (f = e_f(e, j)) >= 0; j++)
253 {
254 for (k = 0, sb = 0; k < f_s.dimension(1) && (sb = f_s(f, k)) >= 0; k++)
255 if (sb == s) break;
256 if (sb != s) continue; /* face de e non connectee a s -> on saute */
257 if (fbord(f) >= 0) s_eb.insert(std::lower_bound(s_eb.begin(), s_eb.end(), ne_tot + f), ne_tot + f); //si f est de bord, on ajoute l'indice correspondant a s_eb
258 else ok &= (f_e(f, 0) >= 0 && f_e(f, 1) >= 0); //si f est interne, alors l'amont/aval doivent etre presents
259 se_f[i].push_back(f); //faces connectees a e et s
260 if ((ll = std::lower_bound(s_f.begin(), s_f.end(), f) - s_f.begin()) == s_f.size() || s_f[ll] != f) /* si f n'est pas dans s_f, on l'ajoute */
261 {
262 s_f.insert(s_f.begin() + ll, f); //face -> dans s_f
263 if (D < 3) surf_fs.insert(surf_fs.begin() + ll, fs(f) / 2), vec_fs.insert(vec_fs.begin() + ll, {{{ xs(s, 0) - xv_(f, 0), xs(s, 1) - xv_(f, 1), 0}, { 0, 0, 0 }}}); //2D -> facile
264 else for (surf_fs.insert(surf_fs.begin() + ll, 0), vec_fs.insert(vec_fs.begin() + ll, {{{ 0, 0, 0}, {0, 0, 0 }}}), m = 0; m < 2; m++) //3D -> deux sous-triangles
265 {
266 if (m == 1 || k > 0) sb = f_s(f, m ? (k + 1 < f_s.dimension(1) && f_s(f, k + 1) >= 0 ? k + 1 : 0) : k - 1); //sommet suivant (m = 1) ou precedent avec k > 0 -> facile
267 else for (n = f_s.dimension(1) - 1; (sb = f_s(f, n)) == -1; ) n--; //sommet precedent avec k = 0 -> on cherche a partir de la fin
268 auto v = cross(D, D, &xs(s, 0), &xs(sb, 0), &xv_(f, 0), &xv_(f, 0));//produit vectoriel (xs - xf)x(xsb - xf)
269 if (fs(f) > 0) surf_fs[ll] += std::fabs(dot(&v[0], &nf(f, 0))) / fs(f) / 4; //surface a ajouter
270 for (d = 0; d < D; d++) vec_fs[ll][m][d] = (xs(s, d) + xs(sb, d)) / 2 - xv_(f, d); //vecteur face -> arete
271 }
272 }
273 }
274 if (!ok) continue; //au moins un voisin manquant
275 n_eb = (int)s_eb.size(), n_f = (int)s_f.size();
276
277 /* conversion de se_f en indices dans s_f */
278 for (i = 0; i < n_e; i++)
279 for (j = 0; j < (int) se_f[i].size(); j++) se_f[i][j] = (int)(std::lower_bound(s_f.begin(), s_f.end(), se_f[i][j]) - s_f.begin());
280 for (vol_es.resize(n_e), vol_s = 0, i = 0; i < n_e; vol_s += vol_es[i], i++)
281 for (e = s_eb[i], vol_es[i] = 0, j = 0; j < (int) se_f[i].size(); j++)
282 {
283 f = s_f[k = se_f[i][j]];
284 if (fs(f) > 0) vol_es[i] += surf_fs[k] * std::fabs(dot(&xp_(e, 0), &nf(f, 0), &xv_(f, 0))) / fs(f) / D;
285 }
286
287 for (essai = 0; essai < 3; essai++) /* essai 0 : MPFA O -> essai 1 : MPFA O avec x_fs mobiles -> essai 2 : MPFA symetrique (corecive, mais pas tres consistante) */
288 {
289 if (essai == 1) /* essai 1 : choix des points x_fs de continuite aux facettes pour obtenir un schema symetrique */
290 {
291 /* systeme lineaire */
292 for (M.resize(N, nc = (D - 1) * n_f, nl = D * (D - 1) / 2 * n_e), B.resize(N, n_m = std::max(nc, nl)), M = 0, B = 0, i = 0, il = 0; i < n_e; i++)
293 for (d = 0; d < D; d++)
294 for (db = 0; db < d; db++, il++)
295 for (e = s_eb[i], j = 0; j < (int) se_f[i].size(); j++)
296 for (sgn = e == f_e(f = s_f[k = se_f[i][j]], 0) ? 1 : -1, n = 0; n < N; n++)
297 {
298 const double inv_fs = fs(f) > 0 ? 1. / fs(f) : 0.;
299 for (l = 0; l < D; l++) fac[l] = sgn * nu_dot(nu, e, n, &nf(f, 0), i3[l]) * surf_fs[k] * inv_fs / vol_es[i]; //vecteur lambda_e nf sortant * facteur commun
300 B(n, il) += fac[d] * (xv_(f, db) - xp_(e, db)) - fac[db] * (xv_(f, d) - xp_(e, d)); //second membre
301 for (l = 0; l < D - 1; l++) M(n, (D - 1) * k + l, il) += fac[db] * vec_fs[k][l][d] - fac[d] * vec_fs[k][l][db]; //matrice
302 }
303
304 /* resolution -> DEGLSY */
305 nw = -1, piv.resize(nc), F77NAME(dgelsy)(&nl, &nc, &un, &M(0, 0, 0), &nl, &B(0, 0), &n_m, &piv(0), &eps_g, &rk, &W(0), &nw, &infoo);
306 for (W.resize(nw = (int)std::lrint(W(0))), n = 0; n < N; n++) piv = 0, F77NAME(dgelsy)(&nl, &nc, &un, &M(n, 0, 0), &nl, &B(n, 0), &n_m, &piv(0), &eps_g, &rk, &W(0), &nw, &infoo);
307 /* x_fs = xf + corrections */
308 for (x_fs.resize(N, n_f, D), n = 0; n < N; n++)
309 for (i = 0; i < n_f; i++)
310 for (f = s_f[i], d = 0; d < D; d++)
311 for (x_fs(n, i, d) = xv_(f, d), k = 0; k < D - 1; k++) x_fs(n, i, d) += std::min(std::max(B(n, (D - 1) * i + k), 0.), 0.5) * vec_fs[i][k][d];
312 }
313
314 /* gradients par maille en fonctions des (u_eb, u_fs), flux F = Ff.u_fs + Feb.u_eb, et systeme Mf.u_fs = Feb.u_eb */
315 Ff.resize(n_f, n_f, N), Feb.resize(n_f, n_eb, N), Mf.resize(N, n_f, n_f), Meb.resize(N, n_eb, n_f);
316 for (Ff = 0, Feb = 0, Mf = 0, Meb = 0, i = 0; i < n_e; i++)
317 for (e = s_eb[i], M.resize(n_ef = (int)se_f[i].size(), D), B.resize(D, n_m = std::max(D, n_ef)), X.resize(n_ef, D), piv.resize(n_ef), n = 0; n < N; n++)
318 {
319 if (essai < 2) /* essais 0 et 1 : gradient consistant donne par (u_e, (u_fs)_{f v e, s})*/
320 {
321 /* gradient dans (e, s) -> matrice / second membre M.x = B du systeme (grad u)_i = sum_f b_{fi} (x_fs_i - x_e), avec x_fs le pt de continuite de u_fs */
322 for (j = 0; j < n_ef; j++)
323 for (f = s_f[k = se_f[i][j]], d = 0; d < D; d++) M(j, d) = (essai ? x_fs(n, k, d) : xv_(f, d)) - xp_(e, d);
324 for (B = 0, d = 0; d < D; d++) B(d, d) = 1;
325 nw = -1, piv = 0, F77NAME(dgelsy)(&D, &n_ef, &D, &M(0, 0), &D, &B(0, 0), &n_m, &piv(0), &eps_g, &rk, &W(0), &nw, &infoo);
326 W.resize(nw = (int)std::lrint(W(0))), F77NAME(dgelsy)(&D, &n_ef, &D, &M(0, 0), &D, &B(0, 0), &n_m, &piv(0), &eps_g, &rk, &W(0), &nw, &infoo);
327 for (j = 0; j < n_ef; j++)
328 for (d = 0; d < D; d++) X(j, d) = B(d, j); /* pour pouvoir utiliser nu_dot */
329 }
330 else for (j = 0; j < n_ef; j++)
331 for (sgn = e == f_e(f = s_f[k = se_f[i][j]], 0) ? 1 : -1, d = 0; d < D; d++) /* essai 2 : gradient non consistant */
332 {
333 const double inv_fs = fs(f) > 0 ? 1. / fs(f) : 0.;
334 X(j, d) = surf_fs[k] / vol_es[i] * sgn * nf(f, d) * inv_fs;
335 }
336
337 /* flux et equation. Remarque : les CLs complexes des equations scalaires sont gerees directement dans Op_Diff_PolyMAC_MPFA_Elem */
338 for (j = 0; j < n_ef; j++)
339 {
340 k = se_f[i][j], f = s_f[k], sgn = e == f_e(f, 0) ? 1 : -1; //face et son indice
341 const Cond_lim_base *cl = fcl(f, 0) ? &cls[fcl(f, 1)].valeur() : nullptr; //si on est sur une CL, pointeur vers celle-ci
342 int is_dir = cl && (is_p ? sub_type(Neumann, *cl) : sub_type(Dirichlet, *cl) || sub_type(Dirichlet_homogene, *cl)); //est-elle de Dirichlet?
343 for (l = 0; l < n_ef; l++)
344 {
345 const double inv_fs = fs(f) > 0 ? 1. / fs(f) : 0.;
346 x = sgn * nu_dot(nu, e, n, &nf(f, 0), &X(l, 0)) * surf_fs[k] * inv_fs; //contribution au flux
347 if (sgn > 0) Ff(k, se_f[i][l], n) += x, Feb(k, i, n) -= x; //flux amont->aval
348 if (!is_dir) Mf(n, se_f[i][l], k) += x, Meb(n, i, k) += x; //equation sur u_fs (sauf si CL Dirichlet)
349 }
350 if (!cl) continue; //rien de l'autre cote
351 else if (is_dir) Mf(n, k, k) = Meb(n, (int)(std::find(s_eb.begin(), s_eb.end(), ne_tot + f) - s_eb.begin()), k) = 1; //Dirichlet -> equation u_fs = u_b
352 else if (is_p ? !is_dir : sub_type(Neumann, *cl)) //Neumann -> ajout du flux au bord
353 Meb(n, (int)(std::find(s_eb.begin(), s_eb.end(), ne_tot + f) - s_eb.begin()), k) += surf_fs[k];
354 else if (sub_type(Frottement_global_impose, *cl)) //Frottement_global_impose -> flux = - coeff * v_e
355 Meb(n, i, k) -= surf_fs[k] * ((nu) ? ref_cast(Frottement_global_impose, *cl).coefficient_frottement(fcl(f, 2), n) : ref_cast(Frottement_global_impose, *cl).coefficient_frottement_grad(fcl(f, 2), n) ) ;
356 else if (sub_type(Frottement_externe_impose, *cl)) //Frottement_externe_impose -> flux = - coeff * v_f
357 Mf(n, k, k) += surf_fs[k] * ((nu) ? ref_cast(Frottement_externe_impose, *cl).coefficient_frottement(fcl(f, 2), n) : ref_cast(Frottement_externe_impose, *cl).coefficient_frottement_grad(fcl(f, 2), n) );
358 else if (sub_type(Echange_impose_base, *cl)) //Echange_impose_base -> flux = - h * (T_{e,f} - T_ext)
359 {
360 double h = (nu) ? ref_cast(Echange_impose_base, *cl).h_imp(fcl(f, 2), n) : ref_cast(Echange_impose_base, *cl).h_imp_grad(fcl(f, 2), n) ;
361 Meb(n, (int)(std::find(s_eb.begin(), s_eb.end(), ne_tot + f) - s_eb.begin()), k) += surf_fs[k] * h; //partie h * T_ext
362 if (sub_type(Echange_externe_impose, *cl)) Mf(n, k, k) += surf_fs[k] * h; //Echange_externe_impose : partie h * T_f
363 else Meb(n, i, k) -= surf_fs[k] * h; //Echange_global_impose : partie h * T_e
364 }
365 }
366 }
367 /* resolution de Mf.u_fs = Meb.u_eb : DGELSY, au cas ou */
368 nw = -1, piv.resize(n_f), F77NAME(dgelsy)(&n_f, &n_f, &n_eb, &Mf(0, 0, 0), &n_f, &Meb(0, 0, 0), &n_f, &piv(0), &eps, &rk, &W(0), &nw, &infoo);
369 for (W.resize(nw = (int)std::lrint(W(0))), n = 0; n < N; n++)
370 piv = 0, F77NAME(dgelsy)(&n_f, &n_f, &n_eb, &Mf(n, 0, 0), &n_f, &Meb(n, 0, 0), &n_f, &piv(0), &eps, &rk, &W(0), &nw, &infoo);
371
372 /* substitution dans Feb */
373 for (i = 0; i < n_f; i++)
374 for (j = 0; j < n_eb; j++)
375 for (n = 0; n < N; n++)
376 for (k = 0; k < n_f; k++)
377 Feb(i, j, n) += Ff(i, k, n) * Meb(n, j, k);
378
379 /* A : forme bilineaire */
380 if (essai == 2) break;//pas la peine pour VFSYM
381 for (A.resize(N, n_e, n_e), A = 0, i = 0; i < n_e; i++)
382 for (e = s_eb[i], j = 0; j < (int) se_f[i].size(); j++)
383 for (sgn = e == f_e(f = s_f[k = se_f[i][j]], 0) ? 1 : -1, l = 0; l < n_e; l++)
384 for (n = 0; n < N; n++)
385 A(n, i, l) -= sgn * Feb(k, l, n);
386 /* symmetrisation */
387 for (n = 0; n < N; n++)
388 for (i = 0; i < n_e; i++)
389 for (j = 0; j <= i; j++) A(n, i, j) = A(n, j, i) = (A(n, i, j) + A(n, j, i)) / 2;
390 /* v.p. la plus petite : DSYEV */
391 nw = -1, F77NAME(DSYEV)("N", "U", &n_e, &A(0, 0, 0), &n_e, S.addr(), &W(0), &nw, &infoo);
392 for (W.resize(nw = (int)std::lrint(W(0))), S.resize(n_e), n = 0, ok = 1; n < N; n++)
393 F77NAME(DSYEV)("N", "U", &n_e, &A(n, 0, 0), &n_e, &S(0), &W(0), &nw, &infoo), ok &= S(0) > -1e-8 * vol_s;
394 if (ok) break; //pour qu' "essai" ait la bonne valeur en sortie
395 }
396 if (first_fgrad_) ctr[essai](s) = 1;
397
398 /* stockage dans phif_c */
399 for (i = 0; i < n_f; i++)
400 for (f = s_f[i], j = 0; j < n_eb; j++)
401 for (k = (int)(std::lower_bound(fsten_eb.addr() + fsten_d(f), fsten_eb.addr() + fsten_d(f + 1), s_eb[j]) - fsten_eb.addr()), n = 0; n < N; n++)
402 if (fs(f) > 0) phif_c(k, n) += Feb(i, j, n) / fs(f);
403 }
404
405
406 /* simplification du stencil */
407
408 int skip;
409 DoubleTrav scale(N);
410 for (phif_d.resize(1), phif_d = 0, phif_e.resize(0), f = 0, i = 0; f < nb_faces_tot(); f++, phif_d.append_line(i))
411 if (fbord(f) >= 0 || (f_e(f, 0) >= 0 && f_e(f, 1) >= 0))
412 {
413 for (n = 0; n < N; n++)
414 if (fs(f) > 0) scale(n) = nu_dot(nu, f_e(f, 0), n, &nf(f, 0), &nf(f, 0)) / (fs(f) * vf(f)); //ordre de grandeur des coefficients
415 for (j = fsten_d(f); j < fsten_d(f + 1); j++)
416 {
417 for (skip = !full_stencil && fsten_eb(j) != f_e(f, 0), n = 0; n < N; n++) skip &= std::fabs(phif_c(j, n)) < 1e-8 * scale(n); //que mettre ici?
418 if (skip) continue;
419 for (n = 0; n < N; n++) phif_c(i, n) = phif_c(j, n);
420 phif_e.append_line(fsten_eb(j)), i++;
421 }
422 }
423 /* comptage */
424 if (!first_fgrad_) return;
425 double count[3] = { mp_somme_vect_as_double(ctr[0]), mp_somme_vect_as_double(ctr[1]), mp_somme_vect_as_double(ctr[2]) }, tot = count[0] + count[1] + count[2];
426 if (tot > 1.0e-4)
427 Cerr << domaine().le_nom() << "::fgrad(): " << 100. * count[0] / tot << "% MPFA-O "
428 << 100. * count[1] / tot << "% MPFA-O(h) " << 100. * count[2] / tot << "% MPFA-SYM" << finl;
429 first_fgrad_ = 0;
430#endif
431}
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
Classe Dirichlet_homogene Cette classe est la classe de base de la hierarchie des conditions aux limi...
classe Dirichlet Cette classe est la classe de base de la hierarchie des conditions aux limites de ty...
Definition Dirichlet.h:31
IntTab_t & les_elems()
Definition Domaine.h:129
const DoubleTab_t & coord_sommets() const
Definition Domaine.h:112
virtual void creer_tableau_sommets(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
Cree un tableau ayant une "ligne" par sommet du maillage.
Definition Domaine.cpp:1000
int_t nb_som_tot() const
Renvoie le nombre total de sommets du domaine i.e. le nombre de sommets reels et virtuels sur le proc...
Definition Domaine.h:123
double dot(const double *a, const double *b, const double *ma=nullptr, const double *mb=nullptr) const
void fgrad(int N, int is_p, const Conds_lim &cls, const IntTab &fcl, const DoubleTab *nu, const IntTab *som_ext, int virt, int full_stencil, IntTab &phif_d, IntTab &phif_e, DoubleTab &phif_c) const
Computes field gradient interpolation at faces while preserving constant fields.
void init_stencils() const
Initializes the face stencils for gradient computation.
const Static_Int_Lists & som_elem() const
void discretiser() override
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
IntTab & face_sommets() override
renvoie le tableau de connectivite faces/sommets.
Definition Domaine_VF.h:591
const MD_Vector & md_vector_faces() const
Definition Domaine_VF.h:158
DoubleVect & volumes_entrelaces()
Definition Domaine_VF.h:99
int nb_faces_tot() const
renvoie le nombre total de faces.
Definition Domaine_VF.h:481
DoubleTab xv_
Definition Domaine_VF.h:219
IntTab & elem_faces()
renvoie le tableau de connectivite element/faces
Definition Domaine_VF.h:551
std::array< double, 3 > cross(int dima, int dimb, const double *a, const double *b, const double *ma=nullptr, const double *mb=nullptr) const
Definition Domaine_VF.h:711
int fbord(int f) const
Definition Domaine_VF.h:146
virtual DoubleTab & face_normales()
Definition Domaine_VF.h:48
IntTab & face_voisins() override
renvoie le tableaux des volumes des connectivites face elements cf au dessus.
Definition Domaine_VF.h:426
int nb_elem_tot() const
const Domaine & domaine() const
int nb_som_tot() const
Classe Echange_externe_impose: Cette classe represente le cas particulier de la classe.
classe Echange_impose_base: Cette condition limite sert uniquement pour l'equation d'energie.
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
Classe Frottement_externe_impose Classe de base pour des conditions aux limites de type Navier (v.
Classe Frottement_global_impose Classe de base pour des conditions aux limites de type Navier (v.
Metadata for a distributed composite vector.
void add_part(const MD_Vector &part, int shape=0, Nom name="")
Append the "part" descriptor to the composite vector.
Classe Neumann Cette classe est la classe de base de la hierarchie des conditions aux limites de type...
Definition Neumann.h:31
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
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
int_t get_list_size(int_t i_liste) const
renvoie le nombre d'elements de la liste i
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45