TRUST 1.9.8
HPC thermohydraulic platform
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 // j'utilise le meme genre de code que dans Champ_Fonc_P0_base sauf que je recupere le nombre de faces au lieu du nombre d'elements
47 // je suis tout de meme etonne du code utilise dans Champ_Fonc_P0_base::fixer_nb_valeurs_nodales() pour recuperer le domaine discrete...
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 // Probleme: nb_comp vaut 2 mais on ne veut qu'une 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]; //partie vitesses
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 de l'integrale de v autour d'une arete duale, multipliee par la longueur de l'arete
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 de chaque face entourant l'arete
139 for (i = 0; i < a_f.dimension(1) && (f = a_f(a, i)) >= 0; i++)
140 {
141 //sens par rapport a l'arete
142 std::array<double, 3> taz = {{ 0, 0, 1 }}, vec; //vecteur tangent a l'arete et produit vectoriel de celui-ci avec 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 //partie m2
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 //partie "bord" -> avec va si Neumann ou Symetrie, avec val_imp si 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 //remplissage
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 aux aretes de la vitesse (dans le plan normal a chaque arete)
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 /* liste des faces ordonnee dans le sens trigo */
198 //base locale
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 // liste des faces, ordonnee en tournant dans la base locale
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 //orientation des faces
207 /* calcul de l'interpolation */
208 DoubleTrav xe((int)fas.size(), dimension), surf((int)fas.size(), 2), nsurf((int)fas.size(), 2, 3); //points intermediaires entre les xv, surfaces et normales des triangles de l'arete duale
209 double surf_tot = 0, xg[3] = { 0, 0, 0 }; //surface totale, centre de gravite, normale a l'arete
210 //orientations des faces par rapport au 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 //points intermediaires entre faces (pas forcement 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 -> on passe par 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 //angle aigu -> intersection des normales aux faces. On resout (xe - xv).(xv - xa) = 0 pour les deux faces, et xe.ta = ta.(xf + xfb) / 2 en 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 //si xe se retrouve du mauvais cote d'une des faces, on prend xp (si l'element existe) ou xf + xfb / 2 (sinon)
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 et centre de gravite
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 par rapport a 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 /* boucles sur les triangles de l'arete duale */
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 (si il existe)
267 double x[2][3] = { { 0, }, }; //points sur le contour : xv(fa[i]) -> xe(i) (j = 0) ou 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 //segments arete-points : avec 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 //partie vf
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 : avec ve (e >= 0) / val_imp (Dirichlet) / va (Neumann/Symetrie)
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++) //val_imp
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 //partie normale au triangle (3D seulement): avec vf/ve/val_imp egalement
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++) //val_imp
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 de M et remplissage
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/* vitesse aux 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) //vitesse calculee
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/* vitesse aux elements sur une liste d'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 aux 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 //vitesses aux elements, gradient de chaque composante aux faces
438 DoubleTrav ve1(0, dimension);
439 domaine.domaine().creer_tableau_elements(ve1);
440 interp_ve(inco, ve1);
441
442 //gradient aux faces duales, champ (nf.grad)v (obtenu en inversant 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 si 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); //element interne -> avec ve1
451 else if (fcl_(f, 0) == 3)
452 for (k = 0; k < dimension; k++) //bord de Dirichlet -> avec val_imp
453 gv(f, k) += (i ? 1 : -1) * fs(f) * ref_cast(Dirichlet, cls[fcl_(f, 1)].valeur()).val_imp(fcl_(f, 2), k);
454 //si Symetrie -> on ne garde que la composante normale a la 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 //pour chaque composante :
460 for (k = 0; k < dimension; k++)
461 {
462 /* inversion de m2 -> pour obtenir (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 /* reinterpolation aux 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 // seulement si Champ_Face_PolyMAC_CDO car interp_ve est besoin de mon_dom_cl_dis ...
489 if (!mon_dom_cl_dis && que_suis_je() == "Champ_Face_PolyMAC_CDO")
490 return val_elem; //on ne peut rien faire tant qu'on ne connait pas les CLs
491
492 //on interpole ve sur tous les elements, puis on se restreint a 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 // seulement si Champ_Face_PolyMAC_CDO car interp_ve est besoin de mon_dom_cl_dis ...
531 if (!mon_dom_cl_dis && que_suis_je() == "Champ_Face_PolyMAC_CDO")
532 return val; //on ne peut rien faire tant qu'on ne connait pas les CLs
533
534 //on interpole ve sur tous les elements, puis on se restreint a 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 // avec contrib au bord pour l'instant...
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
provoque une erreur ! doit etre surchargee par les classes derivees
int remplir_coord_noeuds_et_polys(DoubleTab &positions, IntVect &polys) const override
NE FAIT RIEN Methode a surcharger.
DoubleVect & valeur_a_elem(const DoubleVect &position, DoubleVect &result, int poly) const override
provoque une erreur ! doit etre surchargee par les classes derivees
DoubleVect & calcul_S_barre_sans_contrib_paroi(const DoubleTab &vitesse, DoubleVect &SMA_barre) const
DoubleTab & valeur_aux_faces(DoubleTab &result) const override
renvoie la valeur du champ aux 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
provoque une erreur ! doit etre surchargee par les classes derivees
DoubleVect & valeur_aux_elems_compo(const DoubleTab &positions, const IntVect &polys, DoubleVect &result, int ncomp) const override
provoque une erreur ! doit etre surchargee par les classes derivees
int nb_valeurs_nodales() const override
virtual Champ_base & le_champ()
DoubleTab & trace(const Frontiere_dis_base &, DoubleTab &, double, int distant) const override
Calcule la trace d'un champ sur une frontiere au temps 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
classe Champ_Fonc_reprise Cette classe permet de relire un champ sauvegarde dans un fichier xyz
const Domaine & domaine() const
virtual void creer_tableau_distribue(const MD_Vector &, RESIZE_OPTIONS=RESIZE_OPTIONS::COPY_INIT)
DoubleTab & passe(int i=1) override
Renvoie les valeurs du champs a l'instant t-i.
const Domaine_Cl_dis_base & domaine_Cl_dis() const
const Domaine_dis_base & domaine_dis_base() const override
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
const Domaine_VF & domaine_vf() const
virtual DoubleTab & valeurs()=0
classe Champ_Uniforme Represente un champ constant dans l'espace et dans le temps.
Champ_base()
Constructeur par defaut d'un Champ_base.
virtual DoubleTab & valeur_aux(const DoubleTab &positions, DoubleTab &valeurs) const
Provoque une erreur ! Doit etre surchargee par les classes derivees.
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
classe Dirichlet Cette classe est la classe de base de la hierarchie des conditions aux limites de ty...
Definition Dirichlet.h:31
virtual void creer_tableau_elements(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
creation d'un tableau parallele de valeurs aux elements.
Definition Domaine.cpp:851
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
class Domaine_VF
Definition Domaine_VF.h:44
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
int nb_faces() const
renvoie le nombre global de 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
Renvoie le nom du champ.
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
classe Frontiere_dis_base Classe representant une frontiere discretisee.
une matrice 3x3.
Definition Matrice33.h:28
static double inverse(const Matrice33 &m, Matrice33 &resu, int exit_on_error=1)
calcul de l'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
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
virtual int debute_par(const char *const n) const
Definition Nom.cpp:319
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
static void abort()
Routine de sortie de Trio-U sur une erreur abort().
Definition Process.cpp:570
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Classe de base des flux de sortie.
Definition Sortie.h:52
_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")