TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Champ_Face_PolyMAC_CDO.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 <Linear_algebra_tools_impl.h>
17#include <Connectivite_som_elem.h>
18#include <Dirichlet_homogene.h>
19#include <Domaine_Cl_PolyMAC_family.h>
20#include <Champ_Fonc_reprise.h>
21#include <Champ_Face_PolyMAC_CDO.h>
22#include <Schema_Temps_base.h>
23#include <Champ_Uniforme.h>
24#include <Domaine_PolyMAC_CDO.h>
25
26#include <TRUSTTab_parts.h>
27#include <Probleme_base.h>
28#include <Equation_base.h>
29#include <Matrix_tools.h>
30#include <Domaine_VF.h>
31#include <Dirichlet.h>
32#include <Symetrie.h>
33#include <EChaine.h>
34#include <Domaine.h>
35#include <array>
36#include <cmath>
37
38Implemente_instanciable(Champ_Face_PolyMAC_CDO, "Champ_Face_PolyMAC_CDO|Champ_Face_PolyMAC", Champ_Face_base);
39
40Sortie& Champ_Face_PolyMAC_CDO::printOn(Sortie& os) const { return os << que_suis_je() << " " << le_nom(); }
41
43
45{
46 // use the same kind of code as in Champ_Fonc_P0_base, but retrieve the number of faces instead of the number of elements
47 // note: the code used in Champ_Fonc_P0_base::fixer_nb_valeurs_nodales() to retrieve the discrete domain is somewhat surprising...
48
49 const Champ_Inc_base& self = ref_cast(Champ_Inc_base, *this);
51
52 assert(n == domaine.nb_faces() + (dimension < 3 ? domaine.nb_som() : domaine.domaine().nb_aretes()));
53
54 // Problem: nb_comp equals 2 but we only want one dimension !!!
55 // HACK:
56 int old_nb_compo = nb_compo_;
57 nb_compo_ = 1;
58 creer_tableau_distribue(domaine.mdv_faces_aretes);
59 nb_compo_ = old_nb_compo;
60 return n;
61}
62
64{
65 const DoubleTab& v = ch.valeurs();
66 DoubleTab_parts parts(valeurs());
67 DoubleTab& val = parts[0]; //velocity part
68 const Domaine_VF& domaine_PolyMAC_CDO = ref_cast( Domaine_VF,le_dom_VF.valeur());
69 int nb_faces = domaine_PolyMAC_CDO.nb_faces();
70 const DoubleVect& surface = domaine_PolyMAC_CDO.face_surfaces();
71 const DoubleTab& normales = domaine_PolyMAC_CDO.face_normales();
72
73 if (sub_type(Champ_Uniforme,ch))
74 {
75 for (int num_face=0; num_face<nb_faces; num_face++)
76 {
77 double vn=0;
78 for (int dir=0; dir<dimension; dir++)
79 vn+=v(0,dir)*normales(num_face,dir);
80
81 vn/=surface(num_face);
82 val(num_face) = vn;
83 }
84 }
85 else if (sub_type(Champ_Fonc_reprise, ch))
86 for (int f = 0; f < nb_faces; f++)
87 val(f) = ch.valeurs()(f);
88 else
89 {
90 // int ndeb_int = domaine_PolyMAC_CDO.premiere_face_int();
91 // const IntTab& face_voisins = domaine_PolyMAC_CDO.face_voisins();
92 const DoubleTab& xv=domaine_PolyMAC_CDO.xv();
93 DoubleTab eval(val.dimension_tot(0),dimension);
94 ch.valeur_aux(xv,eval);
95 for (int num_face=0; num_face<nb_faces; num_face++)
96 {
97 double vn=0;
98 for (int dir=0; dir<dimension; dir++)
99 vn+=eval(num_face,dir)*normales(num_face,dir);
100
101 vn/=surface(num_face);
102 val(num_face) = vn;
103 }
104 }
105 return *this;
106}
107
108DoubleVect& Champ_Face_PolyMAC_CDO::valeur_a_elem(const DoubleVect& position, DoubleVect& result, int poly) const
109{
110 Cerr << "Champ_Face_PolyMAC_CDO::" <<__func__ << " is not coded !" << finl;
111 throw;
112}
113
114double Champ_Face_PolyMAC_CDO::valeur_a_elem_compo(const DoubleVect& position, int poly, int ncomp) const
115{
116 Cerr << "Champ_Face_PolyMAC_CDO::" <<__func__ << " is not coded !" << finl;
117 throw;
118}
119
120//interpolation of the integral of v around a dual edge, multiplied by the edge length
122{
124 const IntTab& a_f = domaine.arete_faces(), &e_f = domaine.elem_faces(), &f_e = domaine.face_voisins();
125 const DoubleTab& nf = domaine.face_normales(), &ta = domaine.ta(), &xs = domaine.domaine().coord_sommets(), &xa = dimension < 3 ? xs : domaine.xa(), &xv = domaine.xv();
126 const DoubleVect& fs = domaine.face_surfaces(), &ve = domaine.volumes();
127 int i, j, k, l, r, e, f, fb, a, idx;
128
129 if (radeb.dimension(0)) return;
130 init_fcl(), domaine.init_m2(), init_va();
131 radeb.resize(1, 2), racf.resize(0, 3);
132
133
134 std::map<int, double> rami;
135 std::map<int, std::array<double, 3> > ramf;
136 for (a = 0; a < xa.dimension_tot(0); radeb.append_line(raji.dimension(0), rajf.dimension(0)), rami.clear(), ramf.clear(), a++)
137 {
138 //contribution from each face surrounding the edge
139 for (i = 0; i < a_f.dimension(1) && (f = a_f(a, i)) >= 0; i++)
140 {
141 //orientation relative to the edge
142 std::array<double, 3> taz = {{ 0, 0, 1 }}, vec; //tangent vector to the edge and its cross product with xv - xa
143 vec = domaine.cross(3, dimension, dimension < 3 ? &taz[0] : &ta(a, 0), &xv(f, 0), nullptr, dimension < 3 ? &xs(a, 0): &xa(a, 0));
144 int sgn = domaine.dot(&vec[0], &nf(f, 0)) > 0 ? 1 : -1;
145
146 //m2 contribution
147 for (j = 0; j < 2 && (e = f_e(f, j)) >= 0; j++)
148 for (k = domaine.m2d(e), idx = 0; k < domaine.m2d(e + 1); k++, idx++)
149 for (l = domaine.m2i(k); f == e_f(e, idx) && l < domaine.m2i(k + 1); l++)
150 if (fcl_(fb = e_f(e, domaine.m2j(l)), 0) < 2) rami[fb] += sgn * (e == f_e(f, 0) ? 1 : -1) * (e == f_e(fb, 0) ? 1 : -1) * ve(e) * domaine.m2c(l) / fs(f);
151 else if (fcl_(fb, 0) == 3)
152 for (r = 0; r < dimension; r++)
153 ramf[fb][r] += sgn * (e == f_e(f, 0) ? 1 : -1) * (e == f_e(fb, 0) ? 1 : -1) * ve(e) * domaine.m2c(l) / fs(f) * nf(fb, r) / fs(fb);
154 //boundary part -> with va if Neumann or Symetrie, with val_imp if Dirichlet_homogene
155 if (fcl_(f, 0) == 1 || fcl_(f, 0) == 2)
156 {
157 for (k = vadeb(a, 0); k < vadeb(a + 1, 0); k++) rami[vaji(k)] += sgn * domaine.dot(&xa(a, 0), &vaci(k, 0), &xv(f, 0));
158 for (k = vadeb(a, 1); k < vadeb(a + 1, 1); k++) ramf[vajf(k, 0)][vajf(k, 1)] += sgn * domaine.dot(&xa(a, 0), &vacf(k, 0), &xv(f, 0));
159 }
160 else if (fcl_(f, 0) == 3)
161 for (k = 0; k < dimension; k++)
162 ramf[f][k] += sgn * (xa(a, k) - xv(f, k));
163 }
164 //filling
165 double la = dimension < 3 ? 1 : domaine.longueur_aretes()(a);
166 for (auto &&kv : rami)
167 if (std::fabs(kv.second) > 1e-8 * la)
168 raji.append_line(kv.first), raci.append_line(kv.second * la);
169 for (auto &&kv : ramf)
170 if (domaine.dot(&kv.second[0], &kv.second[0]) > 1e-16 * la * la)
171 rajf.append_line(kv.first), racf.append_line(kv.second[0] * la, kv.second[1] * la, kv.second[2] * la);
172 }
173 CRIMP(radeb), CRIMP(raji), CRIMP(rajf), CRIMP(raci), CRIMP(racf);
174}
175
176//interpolation of velocity at edges (in the plane normal to each edge)
178{
180 const IntTab& f_e = domaine.face_voisins(), &a_f = domaine.arete_faces();
181 const DoubleTab& xv = domaine.xv(), &ta = domaine.ta(), &xs = domaine.domaine().coord_sommets(),
182 &xa = dimension < 3 ? xs : domaine.xa(), &nf = domaine.face_normales(), &xp = domaine.xp();
183 const DoubleVect& fs = domaine.face_surfaces(), &pf = equation().milieu().porosite_face(), &pe = equation().milieu().porosite_elem();
184
185 int i, j, k, l, m, e, f, fb, a;
186
187 if (vadeb.dimension(0)) return;
188 domaine.init_m1(), domaine.init_ve();
189 std::map<int, std::array<double, 3>> vami;
190 std::map<std::array<int, 2>, std::array<double, 3>> vamf;
191 vadeb.resize(1, 2), vajf.resize(0, 2), vaci.resize(0, 3), vacf.resize(0, 3);
192
193
194 Matrice33 M, iM;
195 for (a = 0; a < xa.dimension_tot(0); vadeb.append_line(vaji.dimension(0), vajf.dimension(0)), vami.clear(), vamf.clear(), a++)
196 {
197 /* list of faces ordered in trigonometric (counter-clockwise) order */
198 //local basis
199 std::array<double, 3> taz = {{ 0, 0, 1 }}, v0 = domaine.cross(3, dimension, dimension < 3 ? &taz[0] : &ta(a, 0), &xv(a_f(a, 0), 0), nullptr, &xa(a, 0)),
200 v1 = domaine.cross(3, 3, dimension < 3 ? &taz[0] : &ta(a, 0), &v0[0]);
201 // list of faces, ordered by rotating in the local basis
202 std::map<double, int> fmap;
203 for (i = 0; i < a_f.dimension(1) && (f = a_f(a, i)) >= 0; i++) fmap[atan2(domaine.dot(&xv(f, 0), &v1[0], &xa(a, 0)), domaine.dot(&xv(f, 0), &v0[0], &xa(a, 0)))] = f;
204 std::vector<int> fas, sgn;
205 for (auto && kv : fmap) fas.push_back(kv.second);
206 //face orientations
207 /* compute the interpolation */
208 DoubleTrav xe((int)fas.size(), dimension), surf((int)fas.size(), 2), nsurf((int)fas.size(), 2, 3); //intermediate points between xv, surfaces and normals of the dual edge triangles
209 double surf_tot = 0, xg[3] = { 0, 0, 0 }; //total surface, center of gravity, normal to the edge
210 //orientations of faces relative to the contour
211 for (i = 0; i < (int) fas.size(); i++)
212 {
213 std::array <double, 3> vec = domaine.cross(3, dimension, dimension < 3 ? &taz[0] : &ta(a, 0), &xv(fas[i], 0), nullptr, &xa(a, 0));
214 sgn.push_back(domaine.dot(&vec[0], &nf(fas[i], 0)) > 0 ? 1 : -1);
215 }
216 for (i = 0; i < (int) fas.size(); i++)
217 {
218 //intermediate points between faces (not necessarily xp)
219 int fa[2] = { f = fas[i], fb = fas[(i + 1) * (i + 1 < (int) fas.size())] }, sgfa[2] = { sgn[i], sgn[(i + 1) * (i + 1 < (int) fas.size())] };
220 if (domaine.dot(&xv(fb, 0), &nf(f, 0), &xv(f, 0)) * sgn[i] < 0) //angle > 180 -> go through xa
221 for (k = 0; k < dimension; k++) xe(i, k) = xa(a, k);
222 else if (domaine.dot(&xv(f, 0), &xv(fb, 0), &xa(a, 0), &xa(a, 0)) - (dimension < 3 ? 0 : domaine.dot(&xv(f, 0), &ta(a, 0), &xa(a, 0)) * domaine.dot(&xv(fb, 0), &ta(a, 0), &xa(a, 0))) <= 0) //angle obtus -> parallelogramme
223 for (k = 0; k < dimension; k++) xe(i, k) = xv(f, k) + xv(fb, k) - xa(a, k);
224 else //acute angle -> intersection of face normals. Solve (xe - xv).(xv - xa) = 0 for both faces, and xe.ta = ta.(xf + xfb) / 2 in 3D
225 {
226 double s[3];
227 for (j = 0; j < 2; j++)
228 for (k = 0, s[j] = domaine.dot(&xv(fa[j], 0), &xv(fa[j], 0), &xa(a, 0), &xa(a, 0)); k < 3; k++)
229 M(j, k) = k < dimension ? xv(fa[j], k) - xa(a, k) : 0;
230 for (k = 0, s[2] = dimension < 3 ? 0 : (domaine.dot(&xv(f, 0), &ta(a, 0), &xa(a, 0)) + domaine.dot(&xv(fb, 0), &ta(a, 0), &xa(a, 0))) / 2; k < 3; k++)
231 M(2, k) = dimension < 3 ? (k == 2) : ta(a, k);
232 double eps = Matrice33::inverse(M, iM, 0);
233 for (j = 0; eps != 0 && j < dimension; j++)
234 for (k = 0, xe(i, j) = xa(a, j); k < dimension; k++) xe(i, j) += iM(j, k) * s[k];
235 //if xe ends up on the wrong side of a face, use xp (if the element exists) or xf + xfb / 2 (otherwise)
236 if (eps == 0 || domaine.dot(&xe(i, 0), &nf(f, 0), &xv(f, 0)) * sgfa[0] < 0 || domaine.dot(&xe(i, 0), &nf(fb, 0), &xv(fb, 0)) * sgfa[1] > 0)
237 {
238 if ((e = f_e(f, sgfa[0] > 0)) >= 0)
239 for (k = 0; k < dimension; k++) xe(i, k) = xp(e, k);
240 else for (k = 0; k < dimension; k++) xe(i, k) = (xv(f, k) + xv(fb, k)) / 2;
241 }
242 }
243
244 //surfaces and center of gravity
245 for (j = 0; j < 2; j++)
246 {
247 std::array<double, 3> vsurf3 = domaine.cross(dimension, dimension, &xe(i, 0), &xv(fa[j], 0), &xa(a, 0), &xa(a, 0));
248 //orientation relative to ta
249 for (k = 0, l = (dimension < 3 ? vsurf3[2] < 0 : domaine.dot(&ta(a, 0), &vsurf3[0]) < 0); k < 3; k++) vsurf3[k] *= (l ? -1. : 1.) / 2;
250 surf(i, j) = dimension < 3 ? std::fabs(vsurf3[2]) : sqrt(domaine.dot(&vsurf3[0], &vsurf3[0]));
251 surf_tot += surf(i, j);
252 for (k = 0; surf(i, j) > 1e-16 && k < 3; k++) nsurf(i, j, k) = vsurf3[k] / surf(i, j);
253 for (k = 0; k < dimension; k++) xg[k] += surf(i, j) * (xv(fa[j], k) + xe(i, k) - 2 * xa(a, k)) / 3;
254 }
255 }
256 for (k = 0; k < dimension; k++) xg[k] = xa(a, k) + (surf_tot ==0 ? 0. : xg[k] / surf_tot);
257
258 if (!surf_tot) continue;
259 M = Matrice33(surf_tot, 0, 0, 0, surf_tot, 0, 0, 0, surf_tot);
260 /* loops over the triangles of the dual edge */
261 std::array<double, 3> vec;
262 for (i = 0; i < (int) fas.size(); i++)
263 for (j = 0; j < 2; j++)
264 if (surf(i, j) > 1e-16)
265 {
266 f = fas[(i + j) * (i + j < (int) fas.size())], e = f_e(f, sgn[i] > 0); //face, element (if it exists)
267 double x[2][3] = { { 0, }, }; //boundary points: xv(fa[i]) -> xe(i) (j = 0) or xe(i) -> xv(fa[i + 1]) (j = 1)
268 for (k = 0; k < 2; k++)
269 for (l = 0; l < dimension; l++) x[k][l] = j == k ? xv(f, l) : xe(i, l);
270
271 //edge-point segments: using va
272 for (k = 0; k < 2; k++)
273 {
274 for (l = 0; l < dimension; l++) vec[l] = (xa(a, l) + x[k][l]) / 2 - xg[l];
275 vec = domaine.cross(3, dimension, &nsurf(i, j, 0), &vec[0]);
276 for (l = 0; l < 3; l++)
277 for (m = 0; m < dimension; m++) M(l, m) -= (k ? -1 : 1) * (x[k][m] - xa(a, m)) * vec[l];
278 }
279
280 //segment x[0] -> x[1]
281 for (k = 0; k < dimension; k++) vec[k] = (x[0][k] + x[1][k]) / 2 - xg[k];
282 vec = domaine.cross(3, dimension, &nsurf(i, j, 0), &vec[0]);
283 //vf part
284 if (fcl_(f, 0) < 2)
285 for (k = 0; k < dimension; k++)
286 vami[f][k] += domaine.dot(x[1], &nf(f, 0), x[0]) / fs(f) * vec[k];
287 else if (fcl_(f, 0) == 3)
288 for (k = 0; k < dimension; k++)
289 for (l = 0; l < dimension; l++)
290 vamf[ {{ f, l }}][l] += domaine.dot(x[1], &nf(f, 0), x[0]) / fs(f) * vec[k] * nf(f, l) / fs(f);
291 //complement: using ve (e >= 0) / imposed value (Dirichlet) / va (Neumann/Symmetry)
292 if (e >= 0)
293 for (k = domaine.vedeb(e); k < domaine.vedeb(e + 1); k++) //ve
294 {
295 if (fcl_(fb = domaine.veji(k), 0) < 2)
296 for (l = 0; l < dimension; l++)
297 vami[fb][l] += (domaine.dot(x[1], &domaine.veci(k, 0), x[0]) - domaine.dot(x[1], &nf(f, 0), x[0]) * domaine.dot(&domaine.veci(k, 0), &nf(f, 0)) / (fs(f) * fs(f))) * vec[l] * pf(fb) / pe(e);
298 else if (fcl_(fb, 0) == 3)
299 for (l = 0; l < dimension; l++)
300 for (m = 0; m < dimension; m++)
301 vamf[ {{ fb, m }}][l] += (domaine.dot(x[1], &domaine.veci(k, 0), x[0]) - domaine.dot(x[1], &nf(f, 0), x[0]) * domaine.dot(&domaine.veci(k, 0), &nf(f, 0)) / (fs(f) * fs(f)))
302 * vec[l] * nf(fb, m) / fs(f) * pf(fb) / pe(e);
303 }
304 else if (fcl_(f, 0) == 3)
305 for (k = 0; k < dimension; k++)
306 for (l = 0; l < dimension; l++) //imposed value
307 vamf[ {{ f, k }}][l] += (x[1][k] - x[0][k] - domaine.dot(x[1], &nf(f, 0), x[0]) * nf(f, k) / (fs(f) * fs(f))) * vec[l];
308 else if (fcl_(f, 0) == 1 || fcl_(f, 0) == 2)
309 for (k = 0; k < dimension; k++)
310 for (l = 0; l < dimension; l++) //va
311 M(k, l) -= (x[1][l] - x[0][l] - domaine.dot(x[1], &nf(f, 0), x[0]) * nf(f, l) / (fs(f) * fs(f))) * vec[k];
312
313 //normal part of the triangle (3D only): also using vf/ve/imposed value
314 if (dimension < 3) continue;
315 else if (e >= 0)
316 for (k = domaine.vedeb(e); k < domaine.vedeb(e + 1); k++) //ve
317 {
318 if (fcl_(fb = domaine.veji(k), 0) < 2)
319 for (l = 0; l < dimension; l++)
320 vami[fb][l] += surf(i, j) * domaine.dot(&nsurf(i, j, 0), &domaine.veci(k, 0)) * nsurf(i, j, l) * pf(fb) / pe(e);
321 else if (fcl_(fb, 0) == 3)
322 for (l = 0; l < dimension; l++)
323 for (m = 0; m < dimension; m++)
324 vamf[ {{ fb, m }}][l] += surf(i, j) * domaine.dot(&nsurf(i, j, 0), &domaine.veci(k, 0)) * nsurf(i, j, l) * nf(fb, m) / fs(f) * pf(fb) / pe(e);
325 }
326 else if (fcl_(f, 0) == 3)
327 for (k = 0; k < dimension; k++)
328 for (l = 0; l < dimension; l++) //imposed value
329 vamf[ {{ f, k }}][l] += surf(i, j) * nsurf(i, j, k) * nsurf(i, j, l);
330 else if (fcl_(f, 0) == 1 || fcl_(f, 0) == 2)
331 for (k = 0; k < dimension; k++)
332 for (l = 0; l < dimension; l++) //va
333 M(k, l) -= surf(i, j) * nsurf(i, j, k) * nsurf(i, j, l);
334 }
335
336 //inversion of M and filling
337 double eps = Matrice33::inverse(M, iM, 0);
338 if (std::fabs(eps) < 1e-24) continue;
339 for (auto && kv : vami)
340 {
341 double inc[3] = { 0, 0, 0 };
342 for (k = 0; k < dimension; k++)
343 for (l = 0; l < dimension; l++) inc[k] += iM(k, l) * kv.second[l];
344 if (domaine.dot(inc, inc) > 1e-16) vaji.append_line(kv.first), vaci.append_line(inc[0], inc[1], inc[2]);
345 }
346 for (auto && kv : vamf)
347 {
348 double inc[3] = { 0, 0, 0 };
349 for (k = 0; k < dimension; k++)
350 for (l = 0; l < dimension; l++) inc[k] += iM(k, l) * kv.second[l];
351 if (domaine.dot(inc, inc) > 1e-16) vajf.append_line(kv.first[0], kv.first[1]), vacf.append_line(inc[0], inc[1], inc[2]);
352 }
353 }
354 CRIMP(vadeb), CRIMP(vaji), CRIMP(vajf), CRIMP(vaci), CRIMP(vacf);
355}
356
357/* velocity at elements */
358void Champ_Face_PolyMAC_CDO::interp_ve(const DoubleTab& inco, DoubleTab& val, bool is_vit) const
359{
361 int e, f, j, k, r;
362
363 domaine.init_ve();
364 val = 0;
365
366 if (polymac_flica5)
367 {
368 const DoubleVect& pf = equation().milieu().porosite_face(), &pe = equation().milieu().porosite_elem();
369 for (e = 0; e < val.dimension(0); e++)
370 for (j = domaine.vedeb(e); j < domaine.vedeb(e + 1); j++)
371 {
372 f = domaine.veji(j);
373 const double coef = is_vit ? pf(f) / pe(e) : 1.0;
374 for (r = 0; r < dimension; r++) val(e, r) += domaine.veci(j, r) * inco(f) * coef;
375 }
376 }
377 else
378 {
380 const DoubleTab& nf = domaine.face_normales();
381 const DoubleVect& fs = domaine.face_surfaces(), *pf = mon_equation_non_nul() ? &equation().milieu().porosite_face() : nullptr, *pe = pf ? &equation().milieu().porosite_elem() : nullptr;
382
383 for (e = 0; e < val.dimension(0); e++)
384 for (j = domaine.vedeb(e); j < domaine.vedeb(e + 1); j++)
385 if (fcl_(f = domaine.veji(j), 0) < 2) //computed velocity
386 {
387 const double coef = is_vit && pf ? (*pf)(f) / (*pe)(e) : 1.0;
388 for (r = 0; r < dimension; r++) val(e, r) += domaine.veci(j, r) * inco(f) * coef;
389 }
390 else if (fcl_(f, 0) == 3)
391 for (k = 0; k < dimension; k++)
392 for (r = 0; r < dimension; r++) //Dirichlet
393 {
394 const double coef = is_vit && pf ? (*pf)(f) / (*pe)(e) : 1.0;
395 val(e, r) += domaine.veci(j, r) * ref_cast(Dirichlet, cls[fcl_(f, 1)].valeur()).val_imp(fcl_(f, 2), k) * nf(f, k) / fs(f) * coef;
396 }
397 }
398}
399
400/* velocity at elements over a list of elements */
401void Champ_Face_PolyMAC_CDO::interp_ve(const DoubleTab& inco, const IntVect& les_polys, DoubleTab& val, bool is_vit) const
402{
404 int e, f, j, r;
405
406 domaine.init_ve();
407
408 const DoubleVect *pf = mon_equation_non_nul() ? &equation().milieu().porosite_face() : nullptr, *pe = pf ? &equation().milieu().porosite_elem() : nullptr;
409 for (int poly = 0; poly < les_polys.size(); poly++)
410 {
411 e = les_polys(poly);
412 if (e!=-1)
413 {
414 for (r = 0; r < dimension; r++) val(e, r) = 0;
415 for (j = domaine.vedeb(e); j < domaine.vedeb(e + 1); j++)
416 {
417 f = domaine.veji(j);
418 const double coef = is_vit && pf ? (*pf)(f) / (*pe)(e) : 1.0;
419 for (r = 0; r < dimension; r++) val(e, r) += domaine.veci(j, r) * inco(f) * coef;
420 }
421 }
422 }
423}
424
425/* gradient d_j v_i at elements */
426void Champ_Face_PolyMAC_CDO::interp_gve(const DoubleTab& inco, DoubleTab& vals) const
427{
430 const IntTab& f_e = domaine.face_voisins();
431 const DoubleTab& nf = domaine.face_normales();
432 const DoubleVect& fs = domaine.face_surfaces();
433 int i, j, k, f, e;
434 double scal;
435
436 domaine.init_m2solv();
437 //velocities at elements, gradient of each component at faces
438 DoubleTrav ve1(0, dimension);
439 domaine.domaine().creer_tableau_elements(ve1);
440 interp_ve(inco, ve1);
441
442 //gradient at dual faces, field (nf.grad)v (obtained by inverting m2)
443 DoubleTrav gv(domaine.nb_faces_tot(), dimension), cgv, ngv;
444 domaine.creer_tableau_faces(cgv), domaine.creer_tableau_faces(ngv);
445 for (f = 0; f < domaine.nb_faces_tot(); f++)
446 if (fcl_(f, 0) != 1) //gve = 0 if Neumann
447 {
448 for (i = 0; i < 2; i++)
449 if ((e = f_e(f, i)) >= 0)
450 for (k = 0; k < dimension; k++) gv(f, k) += (i ? 1 : -1) * fs(f) * ve1(e, k); //internal element -> using ve1
451 else if (fcl_(f, 0) == 3)
452 for (k = 0; k < dimension; k++) //Dirichlet boundary -> using imposed value
453 gv(f, k) += (i ? 1 : -1) * fs(f) * ref_cast(Dirichlet, cls[fcl_(f, 1)].valeur()).val_imp(fcl_(f, 2), k);
454 //if Symmetry -> keep only the normal component at the face
455 if (fcl_(f, 0) == 2)
456 for (k = 0, scal = domaine.dot(&nf(f, 0), &gv(f, 0)) / fs(f); k < dimension; k++) gv(f, k) = scal * nf(f, k) / fs(f);
457 }
458
459 //for each component:
460 for (k = 0; k < dimension; k++)
461 {
462 /* invert m2 -> to obtain (nf.grad) v_k */
463 for (f = 0; f < domaine.nb_faces_tot(); f++) cgv(f) = gv(f, k);
464 domaine.m2solv.resoudre_systeme(domaine.m2mat, cgv, ngv);
465 /* re-interpolation at elements -> grad v_k */
466 for (e = 0; e < domaine.nb_elem(); e++)
467 for (i = domaine.vedeb(e); i < domaine.vedeb(e + 1); i++)
468 for (j = 0; j < dimension; j++)
469 vals.addr()[(e * dimension + k) * dimension + j] += domaine.veci(i, j) * ngv(domaine.veji(i));
470 }
471
473}
474
475DoubleTab& Champ_Face_PolyMAC_CDO::valeur_aux_elems_(const DoubleTab& val_face, const DoubleTab& positions, const IntVect& les_polys, DoubleTab& val_elem) const
476{
477 const Champ_base& cha = le_champ();
478 int nb_compo = cha.nb_comp(), N = val_face.line_size(), D = dimension;
479 assert(val_elem.line_size() == nb_compo * N);
480 assert((positions.dimension(0) == les_polys.size()) || (positions.dimension_tot(0) == les_polys.size()));
481
482 if (val_elem.nb_dim() > 2)
483 Process::exit("TRUST error in Champ_Face_PolyMAC_CDO::valeur_aux_elems_ : The DoubleTab val has more than 2 entries !");
484
485 if (nb_compo == 1)
486 Process::exit("TRUST error in Champ_Face_PolyMAC_CDO::valeur_aux_elems_ : A scalar field cannot be of Champ_Face type !");
487
488 // only if Champ_Face_PolyMAC_CDO because interp_ve needs mon_dom_cl_dis ...
489 if (!mon_dom_cl_dis && que_suis_je() == "Champ_Face_PolyMAC_CDO")
490 return val_elem; //nothing can be done until the boundary conditions are known
491
492 //interpolate ve over all elements, then restrict to les_polys
493 DoubleTrav ve(0, N * D);
494 const Domaine_VF& domdom = ref_cast(Domaine_VF, domaine_vf());
495 domdom.domaine().creer_tableau_elements(ve);
496
497 if (polymac_flica5 && que_suis_je() == "Champ_Face_PolyMAC_CDO")
498 {
499 bool is_vit = false && cha.le_nom().debute_par("vitesse");
500 interp_ve(val_face, les_polys, ve, is_vit);
501 }
502 else
503 {
504 bool is_vit = cha.le_nom().debute_par("vitesse") && !cha.le_nom().debute_par("vitesse_debitante");
505 interp_ve(val_face, ve, is_vit);
506 }
507
508 for (int p = 0; p < les_polys.size(); p++)
509 for (int r = 0, e = les_polys(p); e < domdom.nb_elem() && r < N * D; r++)
510 val_elem(p, r) = (e == -1) ? 0. : ve(e, r);
511 return val_elem;
512}
513
514DoubleTab& Champ_Face_PolyMAC_CDO::valeur_aux_elems(const DoubleTab& positions, const IntVect& les_polys, DoubleTab& val_elem) const
515{
516 return valeur_aux_elems_(le_champ().valeurs(), positions, les_polys, val_elem);
517}
518
519DoubleTab& Champ_Face_PolyMAC_CDO::valeur_aux_elems_passe(const DoubleTab& positions, const IntVect& les_polys, DoubleTab& val_elem) const
520{
521 return valeur_aux_elems_(le_champ().passe(), positions, les_polys, val_elem);
522}
523
524DoubleVect& Champ_Face_PolyMAC_CDO::valeur_aux_elems_compo(const DoubleTab& positions, const IntVect& les_polys, DoubleVect& val, int ncomp) const
525{
526 if (!polymac_flica5 || que_suis_je() != "Champ_Face_PolyMAC_CDO") fcl();
527 const Champ_base& cha=le_champ();
528 assert(val.size_totale() >= les_polys.size());
529
530 // only if Champ_Face_PolyMAC_CDO because interp_ve needs mon_dom_cl_dis ...
531 if (!mon_dom_cl_dis && que_suis_je() == "Champ_Face_PolyMAC_CDO")
532 return val; //nothing can be done until the boundary conditions are known
533
534 //interpolate ve over all elements, then restrict to les_polys
535 DoubleTrav ve(0, dimension * cha.valeurs().line_size());
536 ref_cast(Domaine_VF,domaine_vf()).domaine().creer_tableau_elements(ve);
537 if (polymac_flica5 && que_suis_je() == "Champ_Face_PolyMAC_CDO")
538 {
539 bool is_vit = false && cha.le_nom().debute_par("vitesse");
540 interp_ve(cha.valeurs(), les_polys, ve, is_vit);
541 }
542 else
543 interp_ve(cha.valeurs(), ve);
544
545 for (int p = 0; p < les_polys.size(); p++) val(p) = (les_polys(p) == -1) ? 0. : ve(les_polys(p), ncomp);
546
547 return val;
548}
549
550DoubleTab& Champ_Face_PolyMAC_CDO::remplir_coord_noeuds(DoubleTab& positions) const
551{
552 Cerr << "Champ_Face_PolyMAC_CDO::" <<__func__ << " is not coded !" << finl;
553 throw;
554}
555
556int Champ_Face_PolyMAC_CDO::remplir_coord_noeuds_et_polys(DoubleTab& positions, IntVect& polys) const
557{
558 Cerr << "Champ_Face_PolyMAC_CDO::" <<__func__ << " is not coded !" << finl;
559 throw;
560}
561
562DoubleTab& Champ_Face_PolyMAC_CDO::valeur_aux_faces(DoubleTab& val) const
563{
564 const Champ_base& cha=le_champ();
565 int nb_compo=cha.nb_comp();
566
567 if (nb_compo == 1)
568 Process::exit("Champ_Face_PolyMAC_CDO::valeur_aux_faces : A scalar field cannot be of Champ_Face type !");
569
571 val.resize(domaine.nb_faces(), dimension), val = 0;
572
573 for (int f = 0; f < domaine.nb_faces(); f++)
574 for (int r = 0; r < dimension; r++) val(f, r) = cha.valeurs()(f) * domaine.face_normales(f, r) / domaine.face_surfaces(f);
575 return val;
576}
577
578DoubleVect& Champ_Face_PolyMAC_CDO::calcul_S_barre_sans_contrib_paroi(const DoubleTab& vitesse, DoubleVect& SMA_barre) const
579{
580 // with boundary contribution for now...
581 abort();
582 return calcul_S_barre(vitesse, SMA_barre);
583}
584
585DoubleVect& Champ_Face_PolyMAC_CDO::calcul_S_barre(const DoubleTab& vitesse, DoubleVect& SMA_barre) const
586{
588 DoubleTab duidxj(0, dimension, dimension);
589 domaine.domaine().creer_tableau_elements(duidxj);
590 interp_gve(vitesse, duidxj);
591
592 for (int elem = 0; elem < domaine.domaine().nb_elem(); elem++)
593 {
594 double temp = 0.;
595 for (int i = 0; i < dimension; i++)
596 for (int j = 0; j < dimension; j++)
597 {
598 double Sij = 0.5 * (duidxj(elem, i, j) + duidxj(elem, j, i));
599 temp += Sij * Sij;
600 }
601 SMA_barre(elem) = 2. * temp;
602 }
603
604 return SMA_barre;
605
606}
607
608DoubleTab& Champ_Face_PolyMAC_CDO::trace(const Frontiere_dis_base& fr, DoubleTab& x, double t, int distant) const
609{
610 assert(distant==0);
611 init_fcl();
612 const bool vectoriel = (le_champ().nb_comp() > 1);
613 const int dim = vectoriel ? dimension : 1;
614 const Front_VF& fr_vf = ref_cast(Front_VF, fr);
616 const IntTab& face_voisins = domaine.face_voisins();
617 const DoubleTab& val = valeurs(t);
618 DoubleTrav ve(0, dimension);
619 if (vectoriel)
620 {
621 domaine.domaine().creer_tableau_elements(ve);
622 interp_ve(val, ve);
623 }
624
625 for (int i = 0; i < fr_vf.nb_faces(); i++)
626 {
627 const int face = fr_vf.num_premiere_face() + i;
628 for (int dir = 0; dir < 2; dir++)
629 {
630 const int elem = face_voisins(face, dir);
631 if (elem != -1)
632 {
633 for (int d = 0; d < dim; d++) x(i, d) = vectoriel ? ve(elem, d) : val[face];
634 }
635 }
636 }
637
638 return x;
639}
640
642{
643 ConstDoubleTab_parts val_part(valeurs());
644 return val_part[0].dimension(0) + val_part[1].dimension(0);
645}
DoubleTab & remplir_coord_noeuds(DoubleTab &positions) const override
int fixer_nb_valeurs_nodales(int n) override
Champ_base & affecter_(const Champ_base &) override
virtual void interp_ve(const DoubleTab &inco, DoubleTab &val, bool is_vit=true) const
virtual void interp_gve(const DoubleTab &inco, DoubleTab &vals) const final
double valeur_a_elem_compo(const DoubleVect &position, int poly, int ncomp) const override
Causes an error! Must be overridden by derived classes.
int remplir_coord_noeuds_et_polys(DoubleTab &positions, IntVect &polys) const override
DOES NOTHING. Method to override.
DoubleVect & valeur_a_elem(const DoubleVect &position, DoubleVect &result, int poly) const override
Causes an error! Must be overridden by derived classes.
DoubleVect & calcul_S_barre_sans_contrib_paroi(const DoubleTab &vitesse, DoubleVect &SMA_barre) const
DoubleTab & valeur_aux_faces(DoubleTab &result) const override
Returns the field value at the faces.
virtual DoubleTab & valeur_aux_elems_(const DoubleTab &val_face, const DoubleTab &positions, const IntVect &les_polys, DoubleTab &valeurs) const
DoubleTab & valeur_aux_elems(const DoubleTab &positions, const IntVect &polys, DoubleTab &result) const override
Causes an error! Must be overridden by derived classes.
DoubleVect & valeur_aux_elems_compo(const DoubleTab &positions, const IntVect &polys, DoubleVect &result, int ncomp) const override
Causes an error! Must be overridden by derived classes.
int nb_valeurs_nodales() const override
virtual Champ_base & le_champ()
DoubleTab & trace(const Frontiere_dis_base &, DoubleTab &, double, int distant) const override
Computes the trace of a field on a boundary at time tps.
DoubleVect & calcul_S_barre(const DoubleTab &vitesse, DoubleVect &SMA_barre) const
DoubleTab & valeur_aux_elems_passe(const DoubleTab &positions, const IntVect &polys, DoubleTab &result) const override
void init_fcl() const
const IntTab & fcl() const
Champ_Fonc_reprise This class allows reading back a field saved in an xyz file.
const Domaine & domaine() const
virtual void creer_tableau_distribue(const MD_Vector &, RESIZE_OPTIONS=RESIZE_OPTIONS::COPY_INIT)
DoubleTab & passe(int i=1) override
Returns field values at instant t-i.
const Domaine_Cl_dis_base & domaine_Cl_dis() const
const Domaine_dis_base & domaine_dis_base() const override
DoubleTab & valeurs() override
Returns the array of field values at the current time.
const Domaine_VF & domaine_vf() const
virtual DoubleTab & valeurs()=0
Champ_Uniforme Represents a field that is constant in space and time.
Champ_base()
Default constructor of a Champ_base.
virtual DoubleTab & valeur_aux(const DoubleTab &positions, DoubleTab &valeurs) const
Causes an error! Must be overridden by derived classes.
class Conds_lim This class represents a vector of boundary conditions.
Definition Conds_lim.h:32
Dirichlet This class is the base class of the hierarchy of Dirichlet-type boundary conditions.
Definition Dirichlet.h:31
virtual void creer_tableau_elements(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
Creates a parallel array of values at elements.
Definition Domaine.cpp:850
const Cond_lim & les_conditions_limites(int) const
Returns the i-th boundary condition.
class Domaine_VF
Definition Domaine_VF.h:44
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
int nb_faces() const
Returns the total number of faces.
Definition Domaine_VF.h:471
virtual double face_normales(int face, int comp) const
Definition Domaine_VF.h:47
double xv(int num_face, int k) const
Definition Domaine_VF.h:76
const Domaine & domaine() const
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
const Nom & le_nom() const override
Returns the name of the field.
virtual int nb_comp() const
Definition Field_base.h:56
int nb_compo_
Definition Field_base.h:95
class Front_VF
Definition Front_VF.h:36
int nb_faces() const
Definition Front_VF.h:53
int num_premiere_face() const
Definition Front_VF.h:63
class Frontiere_dis_base Class representing a discretized boundary.
A 3x3 matrix.
Definition Matrice33.h:28
static double inverse(const Matrice33 &m, Matrice33 &resu, int exit_on_error=1)
Computes the inverse.
DoubleVect & porosite_elem()
Definition Milieu_base.h:58
DoubleVect & porosite_face()
Definition Milieu_base.h:62
int mon_equation_non_nul() const
Definition MorEqn.h:85
const Equation_base & equation() const
Returns the reference to the equation pointed to by MorEqn::mon_equation.
Definition MorEqn.h:62
virtual int debute_par(const char *const n) const
Definition Nom.cpp:314
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
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
_TYPE_ * addr()
int nb_dim() const
Definition TRUSTTab.h:199
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
int line_size() const
Definition TRUSTVect.tpp:67
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")