TrioCFD 1.9.9_beta
TrioCFD documentation
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 /* skip the discretiser() of Domaine_PolyMAC_HFV to avoid initializing PolyMAC_HFV_V1 variables */
70
71 //MD_vector for 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 /* vertex -> element / boundary face connectivity */
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; //vertices of face f, elements connected to e via vertices, vertices / faces connected through a common face
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 /* connectivity through a vertex of 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 /* fill */
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; //lists of elements/boundary items, faces around the vertex
237 std::vector<double> surf_fs, vol_es; //partial surfaces of faces connected to the vertex (same order as s_f)
238 std::vector<std::array<std::array<double, 3>,2>> vec_fs;//for each facet, a basis of (D-1) vectors spanning it
239 std::vector<std::vector<int>> se_f; /* se_f[i][.]: faces connected to the i-th element connected to vertex s */
240 DoubleTrav M, B, X, Ff, Feb, Mf, Meb, W(1), x_fs, A, S; //system M.(grad u) = B in each element, flux at 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 at vertices: skipping those in 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 connected to s: from som_elem (already sorted) */
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 and their partial surfaces */
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 of e not connected to s -> skip */
257 if (fbord(f) >= 0) s_eb.insert(std::lower_bound(s_eb.begin(), s_eb.end(), ne_tot + f), ne_tot + f); //if f is a boundary face, add its index to s_eb
258 else ok &= (f_e(f, 0) >= 0 && f_e(f, 1) >= 0); //if f is internal, upstream/downstream must be present
259 se_f[i].push_back(f); //faces connected to both e and s
260 if ((ll = std::lower_bound(s_f.begin(), s_f.end(), f) - s_f.begin()) == s_f.size() || s_f[ll] != f) /* if f is not in s_f, add it */
261 {
262 s_f.insert(s_f.begin() + ll, f); //add face to 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 -> straightforward
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 -> two sub-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); //next vertex (m = 1) or previous with k > 0 -> straightforward
267 else for (n = f_s.dimension(1) - 1; (sb = f_s(f, n)) == -1; ) n--; //previous vertex with k = 0 -> search from the end
268 auto v = cross(D, D, &xs(s, 0), &xs(sb, 0), &xv_(f, 0), &xv_(f, 0));//cross product (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 to add
270 for (d = 0; d < D; d++) vec_fs[ll][m][d] = (xs(s, d) + xs(sb, d)) / 2 - xv_(f, d); //vector face -> edge
271 }
272 }
273 }
274 if (!ok) continue; //at least one missing neighbor
275 n_eb = (int)s_eb.size(), n_f = (int)s_f.size();
276
277 /* convert se_f to indices in 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++) /* attempt 0: MPFA-O -> attempt 1: MPFA-O with mobile x_fs -> attempt 2: symmetric MPFA (coercive but not very consistent) */
288 {
289 if (essai == 1) /* attempt 1: choose x_fs continuity points at facets to obtain a symmetric scheme */
290 {
291 /* linear system */
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]; //outward lambda_e nf vector * common factor
300 B(n, il) += fac[d] * (xv_(f, db) - xp_(e, db)) - fac[db] * (xv_(f, d) - xp_(e, d)); //right-hand side
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]; //matrix
302 }
303
304 /* solve -> DGELSY */
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 (clamped to [0, 0.5]) */
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 /* per-cell gradients as functions of (u_eb, u_fs), flux F = Ff.u_fs + Feb.u_eb, and system 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) /* attempts 0 and 1: consistent gradient given by (u_e, (u_fs)_{f adj e, s})*/
320 {
321 /* gradient in (e, s) -> matrix / right-hand side M.x = B of the system (grad u)_i = sum_f b_{fi} (x_fs_i - x_e), where x_fs is the continuity point of 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); /* transposed to enable 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++) /* attempt 2: inconsistent gradient */
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 and equation. Note: complex BCs for scalar equations are handled directly in 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 and its index
341 const Cond_lim_base *cl = fcl(f, 0) ? &cls[fcl(f, 1)].valeur() : nullptr; //pointer to BC if on a boundary
342 int is_dir = cl && (is_p ? sub_type(Neumann, *cl) : sub_type(Dirichlet, *cl) || sub_type(Dirichlet_homogene, *cl)); //is it 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 to the flux
347 if (sgn > 0) Ff(k, se_f[i][l], n) += x, Feb(k, i, n) -= x; //flux upstream->downstream
348 if (!is_dir) Mf(n, se_f[i][l], k) += x, Meb(n, i, k) += x; //equation on u_fs (except if Dirichlet BC)
349 }
350 if (!cl) continue; //nothing on the other side
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 -> add boundary flux
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; //h * T_ext contribution
362 if (sub_type(Echange_externe_impose, *cl)) Mf(n, k, k) += surf_fs[k] * h; //Echange_externe_impose: h * T_f contribution
363 else Meb(n, i, k) -= surf_fs[k] * h; //Echange_global_impose: h * T_e contribution
364 }
365 }
366 }
367 /* solve Mf.u_fs = Meb.u_eb: DGELSY, just in case */
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 /* substitute into 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: bilinear form */
380 if (essai == 2) break;//not needed for 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 /* symmetrization */
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 /* smallest eigenvalue: 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; //so that "essai" has the correct value on exit
395 }
396 if (first_fgrad_) ctr[essai](s) = 1;
397
398 /* store into 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 /* stencil simplification */
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)); //order of magnitude of the 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); //what threshold to use here?
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 /* counting */
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}
class Cond_lim_base Base class for the hierarchy of classes that represent the different boundary con...
class Conds_lim This class represents a vector of boundary conditions.
Definition Conds_lim.h:32
Classe Dirichlet_homogene This class is the base class of the hierarchy of homogeneous Dirichlet-type...
Dirichlet This class is the base class of the hierarchy of Dirichlet-type boundary conditions.
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
Creates an array with one "row" per mesh vertex.
Definition Domaine.cpp:999
int_t nb_som_tot() const
Returns the total number of vertices of the domain i.e. the number of real and virtual vertices on th...
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
Returns the face/vertex connectivity array.
Definition Domaine_VF.h:590
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
Returns the total number of faces.
Definition Domaine_VF.h:481
DoubleTab xv_
Definition Domaine_VF.h:219
IntTab & elem_faces()
Returns the element/face connectivity array.
Definition Domaine_VF.h:550
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:710
int fbord(int f) const
Definition Domaine_VF.h:146
virtual DoubleTab & face_normales()
Definition Domaine_VF.h:48
IntTab & face_voisins() override
Returns the face-element connectivity array; see above.
Definition Domaine_VF.h:426
int nb_elem_tot() const
const Domaine & domaine() const
int nb_som_tot() const
Classe Echange_externe_impose: This class represents the special case of the class.
Echange_impose_base: This boundary condition is used only for the energy equation.
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
Classe Frottement_externe_impose Base class for Navier-type boundary conditions (v.
Classe Frottement_global_impose Base class for Navier-type boundary conditions (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 This class is the base class of the hierarchy of Neumann-type boundary conditions.
Definition Neumann.h:31
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
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
int_t get_list_size(int_t i_liste) const
Returns the number of elements in list 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