TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Op_Conv_VEF_Face.cpp
1/****************************************************************************
2* Copyright (c) 2026, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <Op_Conv_VEF_Face.h>
17#include <Champ_P1NC.h>
18#include <Porosites_champ.h>
19#include <Convection_tools.h>
20#include <Dirichlet_homogene.h>
21#include <Periodique.h>
22#include <Symetrie.h>
23#include <Neumann_sortie_libre.h>
24#include <TRUSTVect.h>
25#include <Device.h>
26#include <Tetra_VEF.h>
27#include <Tri_VEF.h>
28#include <Comm_Group_MPI.h>
29
30
31
32//If constexpr can be very useful for performances (see https://rbourgeois33.github.io./posts/post1/#template-away-heavy-branches)
33//But it is not compatible with old compilers. We fallback to plain if when necessary
34#if defined(__cpp_if_constexpr)
35#define TRUST_IFCONSTEXPR if constexpr
36#else
37#define TRUST_IFCONSTEXPR if
38#pragma message("Warning: your C++ std is old and does not enables 'if constexpr', switching to plain 'if'. Think about upgrading to C++ 17.")
39#endif
40
41Implemente_instanciable_sans_constructeur(Op_Conv_VEF_Face,"Op_Conv_Generic_VEF_P1NC",Op_Conv_VEF_base);
42// XD convection_generic convection_deriv generic NO_BRACE Keyword for generic calling of upwind and muscl convective
43// XD_CONT scheme in VEF discretization. For muscl scheme, limiters and order for fluxes calculations have to be
44// XD_CONT specified. The available limiters are : minmod - vanleer -vanalbada - chakravarthy - superbee, and the order
45// XD_CONT of accuracy is 1 or 2. Note that chakravarthy is a non-symmetric limiter and superbee may engender results
46// XD_CONT out of physical limits. By consequence, these two limiters are not recommended. NL2 Examples: NL2 convection
47// XD_CONT { generic amont }NL2 convection { generic muscl minmod 1 }NL2 convection { generic muscl vanleer 2 }NL2 NL2
48// XD_CONT In case of results out of physical limits with muscl scheme (due for instance to strong non-conformal
49// XD_CONT velocity flow field), user can redefine in data file a lower order and a smoother limiter, as : convection {
50// XD_CONT generic muscl minmod 1 }
51// XD attr type chaine(into=["amont","muscl","centre"]) type REQ type of scheme
52// XD attr limiteur chaine(into=["minmod","vanleer","vanalbada","chakravarthy","superbee"]) limiteur OPT type of limiter
53// XD attr ordre entier(into=[1,2,3]) ordre OPT order of accuracy
54// XD attr alpha floattant alpha OPT alpha
55
57{
58 return s << que_suis_je() ;
59}
60
62{
63 Motcle type_op_lu;
64 s >> type_op_lu;
65
66 if (!(type_op_lu=="amont") && !(type_op_lu=="muscl") && !(type_op_lu=="centre"))
67 {
68 Cerr << type_op_lu << " n'est pas compris par " << que_suis_je() << finl;
69 Cerr << " choisir parmi : amont - muscl - centre " << finl;
70 exit();
71 }
72
73 if (type_op_lu=="muscl")
74 {
75 type_op = muscl;
76 s >> type_lim;
77
78 if ( !(type_lim=="minmod") && !(type_lim=="vanleer") && !(type_lim=="vanalbada")
79 && !(type_lim=="chakravarthy") && !(type_lim=="superbee") )
80 {
81 Cerr << type_lim << " n'est pas compris par " << que_suis_je() << finl;
82 Cerr << " choisir parmi : minmod - vanleer - vanalbada - chakravarthy - superbee " << finl;
83 exit();
84 }
85
86 if (type_lim=="minmod")
87 {
88 LIMITEUR=&minmod;
90 }
91 if (type_lim=="vanleer")
92 {
93 LIMITEUR=&vanleer;
95 }
96 if (type_lim=="vanalbada")
97 {
98 LIMITEUR=&vanalbada;
100 }
101 if (type_lim=="chakravarthy")
102 {
103 LIMITEUR=&chakravarthy;
105 }
106 if (type_lim=="superbee")
107 {
108 LIMITEUR=&superbee;
110 }
111 s >> ordre_;
112
113 if (ordre_!=1 && ordre_!=2 && ordre_!=3)
114 {
115 Cerr << "l'ordre apres " << type_lim << " dans " << que_suis_je() << " doit etre soit 1, soit 2, soit 3" << finl;
116 exit();
117 }
118 if (ordre_==3)
119 {
120 // Lecture de alpha_
121 s >> alpha_;
122 }
123 }
124
125 if (type_op_lu=="centre")
126 {
127 type_op = centre;
128 s >> ordre_;
129
130 if (ordre_!=1 && ordre_!=2)
131 {
132 Cerr << "l'ordre apres " << type_op_lu << " dans " << que_suis_je() << " doit etre soit 1, soit 2 " << finl;
133 exit();
134 }
135 }
136
137 if (type_op_lu=="amont")
138 {
139 type_op = amont;
140 ordre_ = 1;
141 }
142
143 return s ;
144}
145
147{
149 // On cherche, pour un elem qui n'est pas de bord (rang==-1),
150 // si un des sommets est sur un bord (tableau des sommets) (C MALOD 17/07/2007)
151 if (type_elem_Cl_.size_array() == 0)
152 {
153 const Domaine_VEF& domaine_VEF = ref_cast(Domaine_VEF, le_dom_vef.valeur());
154 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
155 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
156 const IntVect& rang_elem_non_std = domaine_VEF.rang_elem_non_std();
157 type_elem_Cl_.resize(nb_elem_tot);
158 for (int poly = 0; poly < nb_elem_tot; poly++)
159 {
160 int rang = rang_elem_non_std(poly);
161 type_elem_Cl_[poly] = rang == -1 ? 0 : domaine_Cl_VEF.type_elem_Cl(rang);
162 }
163 }
164}
165
167{
168 // Scalars
173 int nfa7;
175 double alpha;
176 int marq;
181
182 // Views
184 CIntTabView elem_faces_v;
185 CDoubleArrView porosite_face_v;
186 CDoubleArrView porosite_elem_v;
187 CDoubleTabView coord_sommets_v;
188 CIntTabView les_elems_v;
189 CDoubleTabView3 facette_normales_v;
191 CDoubleTabView xp_v;
192 CDoubleTabView xv_v;
193 CIntArrView type_elem_Cl_v;
195 CIntTabView KEL_v;
196 CDoubleTabView3 normales_facettes_Cl_v;
198 CDoubleTabView vitesse_v;
199 CDoubleTabView transporte_face_v;
200 CDoubleTabView3 gradient_v;
201
202 // Outputs
203 DoubleTabView resu_v;
204 DoubleTabView flux_b_v;
205};
206
207template<int ordre, bool isMuscl, bool virtual_only>
208void compute_flux_tetra_kernel(const FluxTetraKernelData& kernel_data)
209{
210
211 //const int dim = Objet_U::dimension;
212 const int dim = 3; // Help compiler: +16% speed-up ! Not the same effect if setting nsom=4 and nfac=4 for a Tetra
213 const int nfac_ = 4;
214 const int nsom_ = 4;
215 const double third = 1.0/3;
216 const double twelvth = 1.0/(3+3*3);
217
218 // Unpack scalars
219 int nb_faces = kernel_data.nb_faces;
220 int nb_faces_bord = kernel_data.nb_faces_bord;
221 //int nfa7 = kernel_data.nfa7;
222 int ncomp_ch_transporte = kernel_data.ncomp_ch_transporte;
223 double alpha = kernel_data.alpha;
224 int marq = kernel_data.marq;
225 bool option_calcul_flux_en_un_point = kernel_data.option_calcul_flux_en_un_point;
226 bool option_appliquer_cl_dirichlet = kernel_data.option_appliquer_cl_dirichlet;
227 bool isAmont = kernel_data.isAmont;
228
229 // Unpack views
230 CIntArrView rang_elem_non_std_v = kernel_data.rang_elem_non_std_v;
231 CIntTabView elem_faces_v = kernel_data.elem_faces_v;
232 CDoubleArrView porosite_face_v = kernel_data.porosite_face_v;
233 CDoubleArrView porosite_elem_v = kernel_data.porosite_elem_v;
234 CDoubleTabView coord_sommets_v = kernel_data.coord_sommets_v;
235 CIntTabView les_elems_v = kernel_data.les_elems_v;
236 CDoubleTabView3 facette_normales_v = kernel_data.facette_normales_v;
237 CIntArrView est_une_face_de_dirichlet_v = kernel_data.est_une_face_de_dirichlet_v;
238 CDoubleTabView xp_v = kernel_data.xp_v;
239 CDoubleTabView xv_v = kernel_data.xv_v;
240 CIntArrView type_elem_Cl_v = kernel_data.type_elem_Cl_v;
241 CIntArrView traitement_pres_bord_v = kernel_data.traitement_pres_bord_v;
242 CIntTabView KEL_v = kernel_data.KEL_v;
243 CDoubleTabView3 normales_facettes_Cl_v = kernel_data.normales_facettes_Cl_v;
244 CDoubleTabView4 vecteur_face_facette_Cl_v= kernel_data.vecteur_face_facette_Cl_v;
245 CDoubleTabView vitesse_v = kernel_data.vitesse_v;
246 CDoubleTabView transporte_face_v = kernel_data.transporte_face_v;
247 CDoubleTabView3 gradient_v = kernel_data.gradient_v;
248
249 // Unpack outputs
250 DoubleTabView resu_v = kernel_data.resu_v;
251 DoubleTabView flux_b_v = kernel_data.flux_b_v;
252
253 //Only virtual elements
254 const int nbeg = virtual_only ? kernel_data.nb_elem : 0;
255 const int nend = virtual_only ? kernel_data.nb_elem_tot : kernel_data.nb_elem;
256
257 //The reel kernel does not start the gpu counter because it is manager by the echange_espace_virtuel_async
258 //Only the virtual one does because it is synchronous, after the comms
259 if (virtual_only)
260 {
261 start_gpu_timer(__KERNEL_NAME__);
262 }
263
264#ifdef TRUST_USE_GPU
265 Kokkos::parallel_for(Kokkos::MDRangePolicy<Kokkos::Rank<2>>({nbeg,0}, {nend, kernel_data.nfa7}), KOKKOS_LAMBDA(const int poly, const int fa7)
266#else
267 Kokkos::parallel_for(Kokkos::RangePolicy<>(nbeg, nend), KOKKOS_LAMBDA(const int poly)
268#endif
269 {
270 int contrib = 0;
271 // calcul des numeros des faces du polyedre
272 int face[4];
273 for (int face_adj = 0; face_adj < nfac_; face_adj++)
274 {
275 int fac = elem_faces_v(poly, face_adj);
276 face[face_adj] = fac;
277 if (fac < nb_faces) contrib = 1; // Une face reelle sur l'element virtuel
278 }
279 //
280 if (contrib)
281 {
282 //prefetch as much as possible
283 bool calcul_flux_en_un_point = (ordre != 3) && (ordre == 1 || traitement_pres_bord_v(poly));
284 bool flux_en_un_point = calcul_flux_en_un_point || option_calcul_flux_en_un_point;
285 double vs[3] = {0.0, 0.0, 0.0};
286 double vsom[12]; // 4 nodes × 3 components
287 double poro[4];
288 double vfa[12];
289 int les_elems_[4] = { les_elems_v(poly,0), les_elems_v(poly,1), les_elems_v(poly,2), les_elems_v(poly,3) };
290 // Gestion de la porosite
291 double coeff = (marq == 0) ? 1. / porosite_elem_v(poly) : 1.0;
292 int itypcl = type_elem_Cl_v(poly);
293 // Determination du type de CL selon le rang
294 int rang = rang_elem_non_std_v(poly);
295 double xc[3];
296 TRUST_IFCONSTEXPR (ordre == 3) // A optimiser! Risque de mauvais resultats en parallel si ordre=3
297 {
298 double xsom[12];
299 for (int i = 0; i < nsom_; i++)
300 for (int j = 0; j < dim; j++)
301 xsom[i * 3 + j] = coord_sommets_v(les_elems_[i], j);
302 int idirichlet, n1, n2, n3;
303 calcul_xg_tetra(xc, xsom, itypcl, idirichlet, n1, n2, n3);
304 }
305
306 double xp[3] = { xp_v(poly,0), xp_v(poly,1), xp_v(poly,2) };
307
308 // Porosity + velocity contributions
309 for (int i = 0; i < nfac_; i++)
310 {
311 poro[i] = porosite_face_v(face[i]);
312
313 for (int j = 0; j < dim; j++)
314 {
315 double vf = vitesse_v(face[i], j);
316 vfa[i*3 + j] = vf;
317 vs[j] += vf * poro[i];
318 }
319 }
320 for (int i = 0; i < nfac_; i++)
321 {
322 for (int j = 0; j < dim; j++)
323 {
324 vsom[i*3 + j] = vs[j] - 3.0 * vfa[i*3 + j] * poro[i];
325 }
326 }
327
328 double vc[3];
329 calcul_vc_tetra(face, vc, vs, vsom, vfa, itypcl, poro);
330 // calcul de xc (a l'intersection des 3 facettes) necessaire pour muscl3
331
332#ifndef TRUST_USE_GPU
333 for (int fa7 = 0; fa7 < kernel_data.nfa7; fa7++)
334#endif
335 {
336 int KEL_v_[4] = {KEL_v(0, fa7), KEL_v(1, fa7),KEL_v(2, fa7),KEL_v(3, fa7)};
337 int les_kel_elems_[2]= {0,0};
338
339 int num10 = -1;
340 int num20 = -1;
341
342 double psc_c = 0, psc_s = 0, psc_s2 = 0;
343
344 // normales aux facettes
345 double cc[3];
346 for (int j = 0; j < 3; j++)
347 {
348 cc[j] = (rang == -1)
349 ? facette_normales_v(poly, fa7, j)
350 : normales_facettes_Cl_v(rang, fa7, j);
351 }
352
353 // Calcul des vitesses en C,S,S2 les 3 extremites de la fa7 et M le centre de la fa7
354 for (int i = 0; i < 3; i++)
355 {
356 psc_c += vc[i] * cc[i];
357 }
358
359 switch (KEL_v_[0])
360 {
361 case 0:
362 num10 = face[0];
363 break;
364 case 1:
365 num10 = face[1];
366 break;
367 case 2:
368 num10 = face[2];
369 break;
370 case 3:
371 num10 = face[3];
372
373 break;
374 default: /* handle error if needed */
375 break;
376 }
377 switch (KEL_v_[1])
378 {
379 case 0:
380 num20 = face[0];
381 break;
382 case 1:
383 num20 = face[1];
384 break;
385 case 2:
386 num20 = face[2];
387 break;
388 case 3:
389 num20 = face[3];
390 break;
391 default: /* handle error if needed */
392 break;
393 }
394 switch (KEL_v_[2])
395 {
396 case 0:
397 psc_s += vsom[0] * cc[0] + vsom[1] * cc[1] + vsom[2] * cc[2];
398 les_kel_elems_[0]=les_elems_[0];
399
400 break;
401 case 1:
402 psc_s += vsom[3] * cc[0] + vsom[4] * cc[1] + vsom[5] * cc[2];
403 les_kel_elems_[0]=les_elems_[1];
404 break;
405 case 2:
406 psc_s += vsom[6] * cc[0] + vsom[7] * cc[1] + vsom[8] * cc[2];
407 les_kel_elems_[0]=les_elems_[2];
408
409 break;
410 case 3:
411 psc_s += vsom[9] * cc[0] + vsom[10] * cc[1] + vsom[11] * cc[2];
412 les_kel_elems_[0]=les_elems_[3];
413
414 break;
415 }
416 switch (KEL_v_[3])
417 {
418 case 0:
419 psc_s2 += vsom[0] * cc[0] + vsom[1] * cc[1] + vsom[2] * cc[2];
420 les_kel_elems_[1]=les_elems_[0];
421 break;
422 case 1:
423 psc_s2 += vsom[3] * cc[0] + vsom[4] * cc[1] + vsom[5] * cc[2];
424 les_kel_elems_[1]=les_elems_[1];
425 break;
426 case 2:
427 psc_s2 += vsom[6] * cc[0] + vsom[7] * cc[1] + vsom[8] * cc[2];
428 les_kel_elems_[1]=les_elems_[2];
429 break;
430 case 3:
431 psc_s2 += vsom[9] * cc[0] + vsom[10] * cc[1] + vsom[11] * cc[2];
432 les_kel_elems_[1]=les_elems_[3];
433 break;
434 }
435
436 int sommet_s = les_kel_elems_[0];
437 int sommet_s2 = les_kel_elems_[1];
438 psc_c *=coeff;
439 psc_s *=coeff;
440 psc_s2 *=coeff;
441 double psc_m = (psc_c + psc_s + psc_s2) *third;
442 // On applique les CL de Dirichlet si num1 ou num2 est une face avec CL de Dirichlet
443 // auquel cas la fa7 coincide avec la face num1 ou num2 -> C est au centre de la face
444
445 int appliquer_cl_dirichlet = 0;
446 if (option_appliquer_cl_dirichlet)
447 if (est_une_face_de_dirichlet_v(num10) || est_une_face_de_dirichlet_v(num20))
448 {
449 appliquer_cl_dirichlet = 1;
450 psc_m = psc_c;
451 }
452
453 // Determination des faces amont pour les points M,C,S,S2
454 int face_amont_m = (psc_m >= 0) ? num10 : num20;
455
456 [[maybe_unused]] int face_amont_c;
457 int face_amont_s, face_amont_s2;
458 TRUST_IFCONSTEXPR (ordre == 3 && isMuscl)
459 {
460 face_amont_c = ((psc_c >= 0) ? num10 : num20);
461 face_amont_s = ((psc_s >= 0) ? num10 : num20) ;
462 face_amont_s2 = ((psc_s2 >= 0) ? num10 : num20) ;
463 }
464 else
465 {
466 face_amont_c= face_amont_m;
467 face_amont_s= face_amont_m;
468 face_amont_s2= face_amont_m;
469 }
470
471 int item_m, item_s, item_s2;
472 [[maybe_unused]] int item_c;
473
474 TRUST_IFCONSTEXPR (isMuscl)
475 {
476 // Use the "face amont" scheme (Muscl)
477 item_m = face_amont_m;
478 item_c = face_amont_c;
479 item_s = face_amont_s;
480 item_s2 = face_amont_s2;
481 }
482 else
483 {
484 // Use the center-of-element scheme (non-Muscl)
485 item_m = poly;
486 item_c = poly;
487 item_s = poly;
488 item_s2 = poly;
489 }
490
491 int dir = (psc_m >= 0) ? 0 : 1;
492 int kel = (psc_m >= 0) ? KEL_v_[0] : KEL_v_[1];
493 int num_face=0;
494 switch (kel)
495 {
496 case 0:
497 num_face = face[0];
498 break;
499 case 1:
500 num_face = face[1];
501 break;
502 case 2:
503 num_face = face[2];
504 break;
505 case 3:
506 num_face = face[3];
507 break;
508 }
509
510 double centre_fa7[3];
511 if (rang == -1)
512 {
513 int isom_glob_0 = les_kel_elems_[0];//2
514 int isom_glob_1 = les_kel_elems_[1];//3
515
516 for (int j = 0; j < 3; j++)
517 {
518 centre_fa7[j] = xp[j]
519 + coord_sommets_v(isom_glob_0, j)
520 + coord_sommets_v(isom_glob_1, j);
521 centre_fa7[j] *= third;
522 }
523 }
524 bool flux_avec_m = isAmont || appliquer_cl_dirichlet;
525
526 double xv_m_arr[3];
527 double xv_s_arr[3];
528 double xv_s2_arr[3];
529 double cs_s_arr[3];
530 double cs_s2_arr[3];
531
532 for (int j = 0; j < 3; j++)
533 {
534 xv_m_arr[j] = xv_v(num_face, j);
535 xv_s_arr[j] = xv_v(face_amont_s, j);
536 xv_s2_arr[j] = xv_v(face_amont_s2, j);
537 cs_s_arr[j] = coord_sommets_v(sommet_s, j);
538 cs_s2_arr[j] = coord_sommets_v(sommet_s2, j);
539 }
540
541 for (int comp0 = 0; comp0 < ncomp_ch_transporte; comp0++)
542 {
543 double inco_m = transporte_face_v(face_amont_m, comp0);
544 double flux;
545 if (flux_avec_m) // amont
546 flux = inco_m * psc_m;
547 else // muscl ou centre
548 {
549 // PL: data locality matters ! Try to access arrays one by one and store into registers
550 double inco_s = transporte_face_v(face_amont_s, comp0);
551 double inco_s2 = transporte_face_v(face_amont_s2, comp0) ;
552 for (int j = 0; j < dim; j++)
553 {
554 double gm = gradient_v(item_m, comp0, j);
555 double gs = gradient_v(item_s, comp0, j);
556 double gs2 = gradient_v(item_s2, comp0, j);
557
558 // Calcul de l'inconnue au centre M de la fa7
559
560 inco_m += gm * (rang == -1 ? centre_fa7[j] - xv_m_arr[j]
561 : vecteur_face_facette_Cl_v(rang, fa7, j, dir));
562 inco_s += gs * (cs_s_arr[j] - xv_s_arr[j]);
563 inco_s2+= gs2 * (cs_s2_arr[j] - xv_s2_arr[j]);
564 }
565 // Calcul de l'inconnue a C, une autre extremite de la fa7, intersection avec les autres fa7
566 // du polyedre. C=G centre du polyedre si volume non etendu
567 // xc donne par elemvef.calcul_xg()
568 double inco_c;
569 TRUST_IFCONSTEXPR (ordre == 3)
570 {
571 inco_c = transporte_face_v(face_amont_c, comp0);
572 for (int j = 0; j < dim; j++)
573 inco_c += gradient_v(item_c, comp0, j) * (-xv_v(face_amont_c, j) + xc[j]);
574 }
575 else
576 inco_c = dim * inco_m - inco_s - inco_s2;
577
578 if (flux_en_un_point)
579 // Calcul du flux sur 1 point
580 flux = inco_m * psc_m;
581 else
582 // Calcul du flux sur 3 points
583 flux = (inco_c * psc_c + inco_s * psc_s + inco_s2 * psc_s2 + 9 * inco_m * psc_m)*twelvth;
584 }
585
586 // Ponderation par coefficient alpha
587 flux *= alpha;
588
589 int compo = ncomp_ch_transporte == 1 ? 0 : comp0;
590 Kokkos::atomic_sub(&resu_v(num10, compo), flux);
591 Kokkos::atomic_add(&resu_v(num20, compo), flux);
592 if (num10 < nb_faces_bord)
593 Kokkos::atomic_add(&flux_b_v(num10, compo), flux);
594 if (num20 < nb_faces_bord)
595 Kokkos::atomic_sub(&flux_b_v(num20, compo), flux);
596
597 }// boucle sur comp
598 } // fin de la boucle sur les facettes
599 } // fin de la boucle
600 });
601 if (virtual_only) end_gpu_timer(__KERNEL_NAME__);
602}
603
604//Wrapper to hide the async logic
605//Same name as the actual kernel function to appear as the same on the profiler
606template<int ordre, bool isMuscl>
607void compute_flux_tetra_kernel(const FluxTetraKernelData& kernel_data, DoubleTab& tab_gradient)
608{
609 //Packing, isend, irecv but no wait and no unpacking
610 //If GPU, the isend/irdc are cudaMemcpyAsync P2P, on a given stream, no blocking !
611 tab_gradient.start_echange_espace_virtuel_async(__KERNEL_NAME__);
612 //Only operate on reel elements
613 compute_flux_tetra_kernel<ordre, /*muscl*/ isMuscl, /* virtual poly only */ false>(kernel_data);
614 //Wait and unpack virtual elements
615 tab_gradient.finish_echange_espace_virtuel_async(__KERNEL_NAME__);
616 //Only operates on virtual elements
617 compute_flux_tetra_kernel<ordre, /*muscl*/ isMuscl, /* virtual poly only */ true>(kernel_data);
618}
619//
620// Fonctions de la classe Op_Conv_VEF_Face
621//
622////////////////////////////////////////////////////////////////////
623//
624// Implementation des fonctions
625//
626// de la classe Op_Conv_VEF_Face
627//
628////////////////////////////////////////////////////////////////////
629
630DoubleTab& Op_Conv_VEF_Face::ajouter(const DoubleTab& transporte, DoubleTab& resu) const
631{
632 const Champ_Inc_base& la_vitesse_aux_faces = vitesse();
633 return ajouter_gen(transporte, la_vitesse_aux_faces, resu);
634}
635
636DoubleTab& Op_Conv_VEF_Face::ajouter_gen(const DoubleTab& transporte, const Champ_Inc_base& la_vitesse, DoubleTab& resu) const
637{
638
639 assert((type_op==amont) || (type_op==muscl) || (type_op==centre));
640 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
641 const Domaine_VEF& domaine_VEF = ref_cast(Domaine_VEF, le_dom_vef.valeur());
642 const DoubleTab& velocity_tab=la_vitesse.valeurs();
643 const DoubleVect& porosite_face = equation().milieu().porosite_face();
644
645 int marq=phi_u_transportant(equation());
646 DoubleTab transporte_face_;
647 DoubleTab vitesse_face_;
648 // soit on a transporte_face=phi*transporte et vitesse_face=vitesse
649 // soit on a transporte_face=transporte et vitesse_face=phi*vitesse
650 // cela depend si on transporte avec phi*u ou avec u.
651 const DoubleTab& transporte_face = modif_par_porosite_si_flag(transporte,transporte_face_,!marq,porosite_face);
652 const DoubleTab& vitesse_face = modif_par_porosite_si_flag(la_vitesse.valeurs(),vitesse_face_,marq,porosite_face);
653
654 const IntTab& elem_faces = domaine_VEF.elem_faces();
655 const auto& facette_normales = domaine_VEF.facette_normales();
656 const Domaine& domaine = domaine_VEF.domaine();
657 const int nfa7 = domaine_VEF.type_elem().nb_facette();
658 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
659 const int nb_elem = domaine_VEF.nb_elem();
660 const IntVect& rang_elem_non_std = domaine_VEF.rang_elem_non_std();
661 const DoubleTab& normales_facettes_Cl = domaine_Cl_VEF.normales_facettes_Cl();
662 int premiere_face_int = domaine_VEF.premiere_face_int();
663 int nb_faces = domaine_VEF.nb_faces();
664 int nfac = domaine.nb_faces_elem();
665 int nsom = domaine.nb_som_elem();
666 const DoubleTab& vecteur_face_facette_Cl = domaine_Cl_VEF.vecteur_face_facette_Cl();
667 int nb_bord = domaine_VEF.nb_front_Cl();
668 const IntTab& les_elems=domaine.les_elems();
669
670 // Permet d'avoir un flux_bord coherent avec les CLs (mais parfois diverge?)
671 // Active uniquement pour ordre 3
672 int option_appliquer_cl_dirichlet = (ordre_==3 ? 1 : 0);
673 int option_calcul_flux_en_un_point = 0;//(ordre==3 ? 1 : 0);
674 // Definition d'un tableau pour un traitement special des schemas pres des bords
675 if (traitement_pres_bord_.size_array()!=nb_elem_tot)
676 {
677 traitement_pres_bord_.resize_array(nb_elem_tot);
679 // Pour muscl3 on applique le minmod sur les elements ayant une face de Dirichlet
680 if (ordre_==3)
681 {
682 for (int n_bord=0; n_bord<nb_bord; n_bord++)
683 {
684 const Cond_lim_base& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
685 if ( sub_type(Dirichlet,la_cl) || sub_type(Dirichlet_homogene,la_cl) )
686 {
687 const Front_VF& le_bord = ref_cast(Front_VF,la_cl.frontiere_dis());
688 int nb_faces_tot = le_bord.nb_faces_tot();
689 const IntTab& face_voisins = domaine_VEF.face_voisins();
690 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
691 {
692 int num_face = le_bord.num_face(ind_face);
693 int elem = face_voisins(num_face,0);
694 traitement_pres_bord_[elem]=1;
695 }
696 }
697 }
698 }
699 else
700 {
701 // Pour le muscl/centre actuels on utilise un calcul de flux a l'ordre 1
702 // aux mailles de bord ou aux mailles ayant un sommet de Dirichlet
703 ArrOfInt est_un_sommet_de_bord_(domaine_VEF.nb_som_tot());
704 for (int n_bord=0; n_bord<nb_bord; n_bord++)
705 {
706 const Cond_lim_base& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
707 if ( sub_type(Dirichlet,la_cl) || sub_type(Dirichlet_homogene,la_cl) )
708 {
709 const Front_VF& le_bord = ref_cast(Front_VF,la_cl.frontiere_dis());
710 int nb_faces_tot = le_bord.nb_faces_tot();
711 int size = domaine_VEF.face_sommets().dimension(1);
712 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
713 for (int som=0; som<size; som++)
714 {
715 int face = le_bord.num_face(ind_face);
716 est_un_sommet_de_bord_[domaine_VEF.face_sommets(face,som)]=1;
717 }
718 }
719 }
720 for (int elem=0; elem<nb_elem_tot; elem++)
721 {
722 if (rang_elem_non_std(elem)!=-1)
723 traitement_pres_bord_[elem]=1;
724 else
725 {
726 for (int n_som=0; n_som<nsom; n_som++)
727 if (est_un_sommet_de_bord_[les_elems(elem,n_som)])
728 traitement_pres_bord_[elem]=1;
729 }
730 }
731 }
732 // Construction du tableau est_une_face_de_dirichlet_
733 est_une_face_de_dirichlet_.resize_array(domaine_VEF.nb_faces_tot());
735 for (int n_bord=0; n_bord<nb_bord; n_bord++)
736 {
737 const Cond_lim_base& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
738 if ( sub_type(Dirichlet,la_cl) || sub_type(Dirichlet_homogene,la_cl) )
739 {
740 const Front_VF& le_bord = ref_cast(Front_VF,la_cl.frontiere_dis());
741 int nb_faces_tot = le_bord.nb_faces_tot();
742 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
743 {
744 int num_face = le_bord.num_face(ind_face);
745 est_une_face_de_dirichlet_[num_face] = 1;
746 }
747 }
748 }
749 }
750
751 // Pour le traitement de la convection on distingue les polyedres
752 // standard qui ne "voient" pas les conditions aux limites et les
753 // polyedres non standard qui ont au moins une face sur le bord.
754 // Un polyedre standard a n facettes sur lesquelles on applique le
755 // schema de convection.
756 // Pour un polyedre non standard qui porte des conditions aux limites
757 // de Dirichlet, une partie des facettes sont portees par les faces.
758 // En bref pour un polyedre le traitement de la convection depend
759 // du type (triangle, tetraedre ...) et du nombre de faces de Dirichlet.
760
761 const Elem_VEF_base& type_elemvef= domaine_VEF.type_elem();
762 int istetra=0;
763 Nom nom_elem=type_elemvef.que_suis_je();
764 if ((nom_elem=="Tetra_VEF")||(nom_elem=="Tri_VEF"))
765 istetra=1;
766
767 const DoubleVect& porosite_elem = equation().milieu().porosite_elem();
768 int ncomp_ch_transporte=(transporte_face.nb_dim() == 1?1:transporte_face.dimension(1));
769
770 // Traitement particulier pour les faces de periodicite
771 DoubleTrav resu_perio;
772 int nb_faces_perio = 0;
773 for (int n_bord=0; n_bord<nb_bord; n_bord++)
774 {
775 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
776 if (sub_type(Periodique,la_cl.valeur()))
777 {
778 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
779 nb_faces_perio+=le_bord.nb_faces();
780 }
781 }
782 if (nb_faces_perio>0)
783 {
784 resu_perio.resize(nb_faces_perio,ncomp_ch_transporte);
785 nb_faces_perio=0;
786 for (int n_bord=0; n_bord<nb_bord; n_bord++)
787 {
788 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
789 if (sub_type(Periodique,la_cl.valeur()))
790 {
791 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
792 int num1 = le_bord.num_premiere_face();
793 int num2 = num1 + le_bord.nb_faces();
794 CDoubleTabView resu_v = resu.view_ro();
795 DoubleTabView resu_perio_v = resu_perio.view_wo();
796 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(num1, num2), KOKKOS_LAMBDA(const int num_face)
797 {
798 int ind_face = nb_faces_perio + num_face - num1;
799 for (int comp = 0; comp < ncomp_ch_transporte; comp++)
800 resu_perio_v(ind_face, comp) = resu_v(num_face, comp);
801 });
802 end_gpu_timer(__KERNEL_NAME__);
803 nb_faces_perio+=num2-num1;
804 }
805 }
806 }
807
808 DoubleTab tab_gradient; // Peut pointer vers gradient_elem ou gradient_face selon schema
809 if(type_op==centre || type_op==muscl)
810 {
811 // Tableau gradient base sur gradient_elem selon schema
812 if (gradient_elem_.size_array() == 0) gradient_elem_.resize(nb_elem_tot, ncomp_ch_transporte, dimension); // (du/dx du/dy dv/dx dv/dy) pour un poly
813 Champ_P1NC::calcul_gradient(transporte_face, gradient_elem_, domaine_Cl_VEF);
814
815 if (type_op == centre)
816 {
817 tab_gradient.ref(gradient_elem_);
818 }
819 else if (type_op == muscl)
820 {
821 int cas = 1;
822 if (type_lim_int == type_lim_minmod) cas = 1;
823 if (type_lim_int == type_lim_vanleer) cas = 2;
824 if (type_lim_int == type_lim_vanalbada) cas = 3;
825 if (type_lim_int == type_lim_chakravarthy) cas = 4;
826 if (type_lim_int == type_lim_superbee) cas = 5;
827 // application du limiteur
828 if (!gradient_face_.get_md_vector())
829 {
830 gradient_face_.resize(0, ncomp_ch_transporte, dimension); // (du/dx du/dy dv/dx dv/dy) pour une face
832 }
833 for (int n_bord = 0; n_bord < nb_bord; n_bord++)
834 {
835 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
836 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
837 int num1 = le_bord.num_premiere_face();
838 int num2 = num1 + le_bord.nb_faces();
839 if (sub_type(Symetrie, la_cl.valeur()))
840 {
841 int ordre = ordre_;
842 int dim = dimension;
843 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
844 CDoubleTabView face_normale = domaine_VEF.face_normales().view_ro();
845 CDoubleTabView3 gradient_elem = gradient_elem_.view_ro<3>();
846 DoubleTabView3 gradient_face = gradient_face_.view_wo<3>();
847 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(num1, num2), KOKKOS_LAMBDA(const int fac)
848 {
849 int elem1 = face_voisins(fac, 0);
850 for (int comp0 = 0; comp0 < ncomp_ch_transporte; comp0++)
851 for (int i = 0; i < dim; i++)
852 gradient_face(fac, comp0, i) = gradient_elem(elem1, comp0, i);
853
854 if (ordre == 3)
855 {
856 // On enleve la composante normale (on pourrait le faire pour les autres schemas...)
857 // mais pour le moment, on ne veut pas changer le comportement par defaut du muscl...
858 for (int comp0 = 0; comp0 < ncomp_ch_transporte; comp0++)
859 for (int i = 0; i < dim; i++)
860 {
861 double carre_surface = 0;
862 double tmp = 0;
863 for (int j = 0; j < dim; j++)
864 {
865 double ndS = face_normale(fac, j);
866 carre_surface += ndS * ndS;
867 tmp += gradient_face(fac, comp0, j) * ndS;
868 }
869 gradient_face(fac, comp0, i) -= tmp * face_normale(fac, i) / carre_surface;
870 }
871 }
872 });
873 end_gpu_timer(__KERNEL_NAME__);
874 }
875 }
876 tab_gradient.ref(gradient_face_);
877 int dim = dimension;
878 int ordre = ordre_;
879 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
880 CIntArrView traitement_pres_bord = traitement_pres_bord_.view_ro();
881 CIntArrView faces_doubles = domaine_VEF.faces_doubles().view_ro();
882 CDoubleTabView3 gradient_elem = gradient_elem_.view_ro<3>();
883 DoubleTabView3 gradient = tab_gradient.view_wo<3>();
884#ifdef TRUST_USE_GPU
885 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_2D({0,0}, {nb_faces, ncomp_ch_transporte}), KOKKOS_LAMBDA(const int fac, const int comp0)
886#else
887 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, nb_faces), KOKKOS_LAMBDA(const int fac)
888#endif
889 {
890 if (faces_doubles[fac] /* face perio */ || fac>=premiere_face_int /* face interne */)
891 {
892 int elem1 = face_voisins(fac, 0);
893 int elem2 = face_voisins(fac, 1);
894 int limiteur = cas;
895 if (ordre == 3 && (traitement_pres_bord[elem1] || traitement_pres_bord[elem2]))
896 limiteur = 1;
897#ifndef TRUST_USE_GPU
898 for (int comp0 = 0; comp0 < ncomp_ch_transporte; comp0++)
899#endif
900 for (int i = 0; i < dim; i++)
901 {
902 double grad1 = gradient_elem(elem1, comp0, i);
903 double grad2 = gradient_elem(elem2, comp0, i);
904 gradient(fac, comp0, i) = FCT_LIMITEUR(grad1, grad2, limiteur);
905 }
906 }
907 });
908 end_gpu_timer(__KERNEL_NAME__);
909 if(nom_elem=="Tetra_VEF")
910 {
911 /* no echange espace virtuel here, it will be done later in a async way for tetra kernel*/
912 }
913 else
914 {
915 tab_gradient.echange_espace_virtuel();// Pas possible de supprimer. Garder le Kernel sur le CPU n'apporte pas.
916 }
917 }// fin if(type_op==muscl)
918 }
919
920 // Dimensionnement du tableau des flux convectifs au bord du domaine de calcul
921 DoubleTab& flux_b = flux_bords_;
922 int nb_faces_bord=domaine_VEF.nb_faces_bord();
923 flux_b.resize(nb_faces_bord,ncomp_ch_transporte);
924 // No, lock with DomainFlow test case:
925 //if (flux_b.dimension(0)!=nb_faces_bord) flux_b.resize(nb_faces_bord,ncomp_ch_transporte);
926 flux_b = 0.;
927
928 const IntTab& KEL=type_elemvef.KEL();
929 const DoubleTab& xv=domaine_VEF.xv();
930 const DoubleTab& coord_sommets=domaine.coord_sommets();
931
932
933 // Boucle ou non selon la valeur de alpha (uniquement a l'ordre 3 pour le moment)
934 // Si alpha=1, la boucle se limite a une simple passe avec le schema choisi (muscl, amont, centre)
935 // Si alpha<1, la boucle se compose de 2 passes:
936 // -la premiere avec le schema choisi et une ponderation de alpha
937 // -la seconde avec le schema centre et une ponderation de 1-alpha
938 double alpha = alpha_;
939 int nombre_passes = (alpha==1 ? 1 : 2);
940 for (int passe=1; passe<=nombre_passes; passe++)
941 {
942 type_operateur type_op_boucle = type_op;
943 if (passe==2)
944 {
945 type_op_boucle = centre;
946 tab_gradient.ref(gradient_elem_);
947 }
948 // Les polyedres non standard sont ranges en 2 groupes dans le Domaine_VEF:
949 // - polyedres bords et joints
950 // - polyedres bords et non joints
951 // On traite les polyedres en suivant l'ordre dans lequel ils figurent
952 // dans le domaine
953 // boucle sur les polys
954 if(nom_elem=="Tetra_VEF")
955 {
956
957 FluxTetraKernelData kernel_data;
958
959 // Scalars
960 kernel_data.nb_elem = nb_elem;
961 kernel_data.nb_elem_tot = nb_elem_tot;
962 kernel_data.nb_faces = nb_faces;
963 kernel_data.nb_faces_bord = nb_faces_bord;
964 kernel_data.nfa7 = nfa7;
965 kernel_data.ncomp_ch_transporte = ncomp_ch_transporte;
966 kernel_data.alpha = alpha;
967 kernel_data.marq = marq;
968 kernel_data.option_calcul_flux_en_un_point = option_calcul_flux_en_un_point;
969 kernel_data.option_appliquer_cl_dirichlet = option_appliquer_cl_dirichlet;
970 kernel_data.isMuscl = (type_op_boucle == muscl);
971 kernel_data.isAmont = (type_op_boucle == amont);
972 // Views
973 kernel_data.rang_elem_non_std_v = rang_elem_non_std.view_ro();
974 kernel_data.elem_faces_v = elem_faces.view_ro();
975 kernel_data.porosite_face_v = porosite_face.view_ro();
976 kernel_data.porosite_elem_v = porosite_elem.view_ro();
977 kernel_data.coord_sommets_v = coord_sommets.view_ro();
978 kernel_data.les_elems_v = les_elems.view_ro();
979 kernel_data.facette_normales_v = facette_normales.view_ro<3>();
981 kernel_data.xp_v = domaine_VEF.xp().view_ro();
982 kernel_data.xv_v = xv.view_ro();
983 kernel_data.type_elem_Cl_v = type_elem_Cl_.view_ro();
984 kernel_data.traitement_pres_bord_v = traitement_pres_bord_.view_ro();
985 kernel_data.KEL_v = type_elemvef.KEL().view_ro();
986 kernel_data.normales_facettes_Cl_v = normales_facettes_Cl.view_ro<3>();
987 kernel_data.vecteur_face_facette_Cl_v = vecteur_face_facette_Cl.view_ro<4>();
988 kernel_data.vitesse_v = la_vitesse.valeurs().view_ro();
989 kernel_data.transporte_face_v = transporte_face.view_ro();
990 kernel_data.gradient_v = tab_gradient.view_ro<3>();
991 // Outputs
992 kernel_data.resu_v = resu.view_rw();
993 kernel_data.flux_b_v = flux_b.view_rw();
994
995 if (type_op_boucle == muscl)
996 {
997 if (ordre_==1)
998 {
999 //Wrapper to hide the async complexity
1000 compute_flux_tetra_kernel</* ordre */ 1, /*muscl*/ true>(kernel_data, tab_gradient);
1001 }
1002
1003 else if (ordre_==2)
1004 {
1005 compute_flux_tetra_kernel</* ordre */ 2, /*muscl*/ true>(kernel_data, tab_gradient);
1006 }
1007 else if (ordre_==3)
1008 {
1009 compute_flux_tetra_kernel</* ordre */ 3, /*muscl*/ true>(kernel_data, tab_gradient);
1010 }
1011 }
1012 else
1013 {
1014 if (ordre_==1)
1015 {
1016 compute_flux_tetra_kernel</* ordre */ 1, /*muscl*/ false>(kernel_data, tab_gradient);
1017 }
1018 else if (ordre_==2)
1019 {
1020 compute_flux_tetra_kernel</* ordre */ 2, /*muscl*/ false>(kernel_data, tab_gradient);
1021 }
1022 else if (ordre_==3)
1023 {
1024 compute_flux_tetra_kernel</* ordre */ 3, /*muscl*/ false>(kernel_data, tab_gradient);
1025 }
1026 }
1027 }
1028 else
1029 {
1030 // Non tetra (tri, quad, hexa)
1031 const DoubleTab& vecteur_face_facette = ref_cast_non_const(Domaine_VEF,domaine_VEF).vecteur_face_facette();
1032 ArrOfInt face(nfac);
1033 ArrOfDouble vs(dimension);
1034 ArrOfDouble vc(dimension);
1035 ArrOfDouble cc(dimension);
1036 DoubleVect xc(dimension);
1037 DoubleTab vsom(nsom,dimension);
1038 DoubleTab xsom(nsom,dimension);
1039 for (int poly=0; poly<nb_elem_tot; poly++)
1040 {
1041 int contrib = 0;
1042 // calcul des numeros des faces du polyedre
1043 for (int face_adj=0; face_adj<nfac; face_adj++)
1044 {
1045 int face_ = elem_faces(poly,face_adj);
1046 face(face_adj)= face_;
1047 if (face_<nb_faces) contrib=1; // Une face reelle sur l'element virtuel
1048 }
1049 //
1050 if (contrib)
1051 {
1052 int calcul_flux_en_un_point = (ordre_ != 3) && (ordre_==1 || traitement_pres_bord_(poly));
1053 for (int j=0; j<dimension; j++)
1054 {
1055 vs(j) = velocity_tab(face(0),j)*porosite_face(face(0));
1056 for (int i=1; i<nfac; i++)
1057 vs(j)+= velocity_tab(face(i),j)*porosite_face(face(i));
1058 }
1059 // calcul de la vitesse aux sommets des polyedres
1060 // On va utliser les fonctions de forme implementees dans la classe Champs_P1_impl ou Champs_Q1_impl
1061 if (istetra==1)
1062 {
1063 for (int i=0; i<nsom; i++)
1064 for (int j=0; j<dimension; j++)
1065 vsom(i,j) = (vs(j) - dimension*velocity_tab(face(i),j)*porosite_face(face(i)));
1066 }
1067 else
1068 {
1069 // pour que cela soit valide avec les hexa (c'est + lent a calculer...)
1070 for (int j=0; j<nsom; j++)
1071 {
1072 int num_som = les_elems(poly,j);
1073 for (int ncomp=0; ncomp<dimension; ncomp++)
1074 vsom(j,ncomp) = la_vitesse.valeur_a_sommet_compo(num_som,poly,ncomp);
1075 }
1076 }
1077
1078 // Determination du type de CL selon le rang
1079 int rang = rang_elem_non_std(poly);
1080 int itypcl = (rang==-1 ? 0 : domaine_Cl_VEF.type_elem_Cl(rang));
1081
1082 // calcul de vc (a l'intersection des 3 facettes) vc vs vsom proportionnelles a la porosite
1083 type_elemvef.calcul_vc(face, vc, vs, vsom, la_vitesse, itypcl, porosite_face);
1084
1085 // calcul de xc (a l'intersection des 3 facettes) necessaire pour muscl3
1086 if (ordre_==3)
1087 {
1088 int idirichlet;
1089 int n1,n2,n3;
1090 for (int i=0; i<nsom; i++)
1091 for (int j=0; j<dimension; j++)
1092 xsom(i,j) = coord_sommets(les_elems(poly,i),j);
1093 type_elemvef.calcul_xg(xc,xsom,itypcl,idirichlet,n1,n2,n3);
1094 }
1095
1096 // Gestion de la porosite
1097 if (marq==0)
1098 {
1099 double coeff=1./porosite_elem(poly);
1100 vsom*=coeff;
1101 vc*=coeff;
1102 }
1103 // Boucle sur les facettes du polyedre non standard:
1104 for (int fa7=0; fa7<nfa7; fa7++)
1105 {
1106 int num10 = face(KEL(0,fa7));
1107 int num20 = face(KEL(1,fa7));
1108 // normales aux facettes
1109 if (rang==-1)
1110 for (int i=0; i<dimension; i++)
1111 cc[i] = facette_normales(poly, fa7, i);
1112 else
1113 for (int i=0; i<dimension; i++)
1114 cc[i] = normales_facettes_Cl(rang,fa7,i);
1115
1116 // Calcul des vitesses en C,S,S2 les 3 extremites de la fa7 et M le centre de la fa7
1117 double psc_c=0,psc_s=0,psc_m,psc_s2=0;
1118 if (dimension==2)
1119 {
1120 for (int i=0; i<2; i++)
1121 {
1122 psc_c+=vc[i]*cc[i];
1123 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
1124 }
1125 psc_m=(psc_c+psc_s)/2.;
1126 }
1127 else
1128 {
1129 for (int i=0; i<3; i++)
1130 {
1131 psc_c+=vc[i]*cc[i];
1132 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
1133 psc_s2+=vsom(KEL(3,fa7),i)*cc[i];
1134 }
1135 psc_m=(psc_c+psc_s+psc_s2)/3.;
1136 }
1137 // On applique les CL de Dirichlet si num1 ou num2 est une face avec CL de Dirichlet
1138 // auquel cas la fa7 coincide avec la face num1 ou num2 -> C est au centre de la face
1139 int appliquer_cl_dirichlet=0;
1140 if (option_appliquer_cl_dirichlet)
1142 {
1143 appliquer_cl_dirichlet = 1;
1144 psc_m = psc_c;
1145 }
1146
1147 // Determination de la face amont pour M
1148 int face_amont_m,dir;
1149 if (psc_m >= 0)
1150 {
1151 face_amont_m = num10;
1152 dir=0;
1153 }
1154 else
1155 {
1156 face_amont_m = num20;
1157 dir=1;
1158 }
1159 // Determination des faces amont pour les points C,S,S2
1160 int face_amont_c=face_amont_m;
1161 int face_amont_s=face_amont_m;
1162 int face_amont_s2=face_amont_m;
1163 if (type_op_boucle==muscl && ordre_==3)
1164 {
1165 face_amont_c = (psc_c >= 0) ? num10 : num20;
1166 face_amont_s = (psc_s >= 0) ? num10 : num20;
1167 face_amont_s2 = (psc_s2 >= 0) ? num10 : num20;
1168 }
1169 // gradient aux items element (schema centre) ou aux items face (schemas muscl)
1170 int item_m=poly;
1171 int item_c=poly;
1172 int item_s=poly;
1173 int item_s2=poly;
1174 if (type_op_boucle==muscl)
1175 {
1176 item_m = face_amont_m;
1177 item_c = face_amont_c;
1178 item_s = face_amont_s;
1179 item_s2 = face_amont_s2;
1180 }
1181
1182 for (int comp0=0; comp0<ncomp_ch_transporte; comp0++)
1183 {
1184 double flux;
1185 double inco_m = (ncomp_ch_transporte==1?transporte_face(face_amont_m):transporte_face(face_amont_m,comp0));
1186 if (type_op_boucle==amont || appliquer_cl_dirichlet)
1187 {
1188 flux = inco_m*psc_m;
1189 }
1190 else // muscl ou centre
1191 {
1192 // Calcul de l'inconnue au centre M de la fa7
1193 if (rang==-1)
1194 for (int j=0; j<dimension; j++)
1195 inco_m+= tab_gradient(item_m,comp0,j)*vecteur_face_facette(poly,fa7,j,dir);
1196 else
1197 for (int j=0; j<dimension; j++)
1198 inco_m+= tab_gradient(item_m,comp0,j)*vecteur_face_facette_Cl(rang,fa7,j,dir);
1199
1200 // Calcul de l'inconnue au sommet S, une premiere extremite de la fa7
1201 double inco_s = (ncomp_ch_transporte==1?transporte_face(face_amont_s):transporte_face(face_amont_s,comp0));
1202 int sommet_s = les_elems(poly,KEL(2,fa7));
1203 for (int j=0; j<dimension; j++)
1204 inco_s+= tab_gradient(item_s,comp0,j)*(-xv(face_amont_s,j)+coord_sommets(sommet_s,j));
1205
1206 // Calcul de l'inconnue au sommet S2, la derniere extremite de la fa7 en 3D
1207 double inco_s2=0;
1208 if (dimension==3)
1209 {
1210 inco_s2 = (ncomp_ch_transporte==1?transporte_face(face_amont_s2):transporte_face(face_amont_s2,comp0));
1211 int sommet_s2 = les_elems(poly,KEL(3,fa7));
1212 for (int j=0; j<dimension; j++)
1213 inco_s2+= tab_gradient(item_s2,comp0,j)*(-xv(face_amont_s2,j)+coord_sommets(sommet_s2,j));
1214 }
1215
1216 // Calcul de l'inconnue a C, une autre extremite de la fa7, intersection avec les autres fa7
1217 // du polyedre. C=G centre du polyedre si volume non etendu
1218 // xc donne par elemvef.calcul_xg()
1219 double inco_c;
1220 if (ordre_==3)
1221 {
1222 inco_c = (ncomp_ch_transporte==1?transporte_face(face_amont_c):transporte_face(face_amont_c,comp0));
1223 for (int j=0; j<dimension; j++)
1224 inco_c+= tab_gradient(item_c,comp0,j)*(-xv(face_amont_c,j)+xc(j));
1225 }
1226 else
1227 {
1228 inco_c = dimension*inco_m-inco_s-inco_s2;
1229 }
1230
1231 // Calcul du flux sur 1 point
1232 if (calcul_flux_en_un_point || option_calcul_flux_en_un_point)
1233 {
1234 flux = inco_m*psc_m;
1235 }
1236 else
1237 {
1238 // Calcul du flux sur 3 points
1239 flux = (dimension==2) ? (inco_c*psc_c + inco_s*psc_s + 4*inco_m*psc_m)/6
1240 : (inco_c*psc_c + inco_s*psc_s + inco_s2*psc_s2 + 9*inco_m*psc_m)/12;
1241 }
1242 }
1243
1244 // Ponderation par coefficient alpha
1245 flux*=alpha;
1246
1247 if (ncomp_ch_transporte == 1)
1248 {
1249 resu(num10) -= flux;
1250 resu(num20) += flux;
1251 if (num10<nb_faces_bord) flux_b(num10,0) += flux;
1252 if (num20<nb_faces_bord) flux_b(num20,0) -= flux;
1253 }
1254 else
1255 {
1256 resu(num10,comp0) -= flux;
1257 resu(num20,comp0) += flux;
1258 if (num10<nb_faces_bord) flux_b(num10,comp0) += flux;
1259 if (num20<nb_faces_bord) flux_b(num20,comp0) -= flux;
1260 }
1261
1262 }// boucle sur comp
1263 } // fin de la boucle sur les facettes
1264 }
1265 } // fin de la boucle
1266 }
1267 alpha = 1 - alpha;
1268 } // fin de la boucle
1269
1270 nb_faces_perio = 0;
1271 // Boucle sur les bords pour traiter les conditions aux limites
1272 // il y a prise en compte d'un terme de convection pour les
1273 // conditions aux limites de Neumann_sortie_libre seulement
1274 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1275 {
1276 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1277
1278 if (sub_type(Neumann_sortie_libre,la_cl.valeur()))
1279 {
1280 const Neumann_sortie_libre& la_sortie_libre = ref_cast(Neumann_sortie_libre, la_cl.valeur());
1281 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1282 int num1 = le_bord.num_premiere_face();
1283 int num2 = num1 + le_bord.nb_faces();
1284 int dim = Objet_U::dimension;
1285 CDoubleTabView face_normale = domaine_VEF.face_normales().view_ro();
1286 CDoubleTabView val_ext = la_sortie_libre.val_ext().view_ro();
1287 CDoubleTabView transporte_face_v = transporte_face.view_ro();
1288 CDoubleTabView vitesse_face_v = vitesse_face.view_ro();
1289 DoubleTabView flux_b_v = flux_b.view_wo();
1290 DoubleTabView resu_v = resu.view_rw();
1291 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(num1, num2), KOKKOS_LAMBDA(const int num_face)
1292 {
1293 double psc =0;
1294 for (int i=0; i<dim; i++)
1295 psc += vitesse_face_v(num_face,i)*face_normale(num_face,i);
1296 for (int i=0; i<ncomp_ch_transporte; i++)
1297 {
1298 double val = psc > 0 ? transporte_face_v(num_face,i) : val_ext(num_face-num1,i);
1299 resu_v(num_face,i) -= psc*val;
1300 flux_b_v(num_face,i) = -psc*val;
1301 }
1302 });
1303 end_gpu_timer(__KERNEL_NAME__);
1304 }
1305 else if (sub_type(Periodique,la_cl.valeur()))
1306 {
1307 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl.valeur());
1308 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1309 int num1 = le_bord.num_premiere_face();
1310 int num2 = num1 + le_bord.nb_faces();
1311 CIntArrView face_associee = la_cl_perio.face_associee().view_ro();
1312 CDoubleTabView resu_perio_v = resu_perio.view_ro();
1313 DoubleTabView resu_v = resu.view_rw();
1314 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(num1, num1+le_bord.nb_faces()/2), KOKKOS_LAMBDA(const int num_face)
1315 {
1316 int ind_face = num_face - num1;
1317 int voisine = face_associee(ind_face) + num1;
1318 for (int comp=0; comp<ncomp_ch_transporte; comp++)
1319 {
1320 double diff1 = resu_v(num_face,comp) - resu_perio_v(nb_faces_perio+ind_face,comp);
1321 double diff2 = resu_v(voisine,comp) - resu_perio_v(nb_faces_perio+ind_face+voisine-num_face,comp);
1322 resu_v(voisine,comp) += diff1;
1323 resu_v(num_face,comp) += diff2;
1324 /* On ne doit pas ajouter a flux_b, c'est deja calcule au dessus
1325 flux_b(voisine,comp) += diff1;
1326 flux_b(num_face,comp) += diff2; */
1327 }
1328 });
1329 end_gpu_timer(__KERNEL_NAME__);
1330 nb_faces_perio+=num2-num1;
1331 }
1332 }
1333 modifier_flux(*this);
1334 return resu;
1335}
1336
1337// methodes recuperes de l'ancien OpVEFFaAmont
1338KOKKOS_INLINE_FUNCTION void convbisimplicite_dec(const double psc_, const int num1, const int num2,
1339 CDoubleTabView transporte, const int ncomp,
1340 Matrice_Morse_View matrice,
1341 CDoubleArrView porosite_face, int phi_u_transportant)
1342{
1343 double psc=psc_;
1344 if (!phi_u_transportant)
1345 psc*=porosite_face(psc_>=0 ? num1 : num2);
1346 for (int comp=0; comp<ncomp; comp++)
1347 {
1348 int n1=num1*ncomp+comp;
1349 int n2=num2*ncomp+comp;
1350 int n = psc_>=0 ? n1 : n2;
1351 matrice.atomic_add(n1,n,psc);
1352 matrice.atomic_add(n2,n,-psc);
1353 }
1354}
1355
1356void Op_Conv_VEF_Face::ajouter_contribution(const DoubleTab& tab_transporte, Matrice_Morse& matrice_morse) const
1357{
1358 const Champ_Inc_base& v = vitesse();
1359 ajouter_contribution_gen(tab_transporte, v, matrice_morse);
1360}
1361
1362void Op_Conv_VEF_Face::ajouter_contribution_gen(const DoubleTab& tab_transporte, const Champ_Inc_base& la_vitesse, Matrice_Morse& matrice_morse) const
1363{
1365 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
1366 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
1367
1368 const Domaine& domaine = domaine_VEF.domaine();
1369 const Elem_VEF_base& type_elem = domaine_VEF.type_elem();
1370 const int nfa7 = type_elem.nb_facette();
1371 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
1372
1373 int nfac = domaine.nb_faces_elem();
1374 int nsom = domaine.nb_som_elem();
1375
1376 // Pour le traitement de la convection on distingue les polyedres
1377 // standard qui ne "voient" pas les conditions aux limites et les
1378 // polyedres non standard qui ont au moins une face sur le bord.
1379 // Un polyedre standard a n facettes sur lesquelles on applique le
1380 // schema de convection.
1381 // Pour un polyedre non standard qui porte des conditions aux limites
1382 // de Dirichlet, une partie des facettes sont portees par les faces.
1383 // En bref pour un polyedre le traitement de la convection depend
1384 // du type (triangle, tetraedre ...) et du nombre de faces de Dirichlet.
1385
1386 int ncomp_ch_transporte = tab_transporte.nb_dim() == 1 ? 1 : tab_transporte.dimension(1);
1387
1388 int marq=phi_u_transportant(equation());
1389
1390 DoubleTab vitesse_face_;
1391 // soit on a transporte=phi*transporte_ et vitesse_face=vitesse_
1392 // soit transporte=transporte_ et vitesse_face=phi*vitesse_
1393 // cela depend si on transporte avec phi u ou avec u.
1394 const DoubleTab& tab_velocity_tab = la_vitesse.valeurs();
1395 const DoubleVect& tab_porosite_face = equation().milieu().porosite_face();
1396 const DoubleTab& tab_vitesse_face=modif_par_porosite_si_flag(tab_velocity_tab,vitesse_face_,marq,tab_porosite_face);
1397 const Elem_VEF_base& type_elemvef = domaine_VEF.type_elem();
1398 int istetra=0;
1399 Nom nom_elem=type_elemvef.que_suis_je();
1400 if ((nom_elem=="Tetra_VEF")||(nom_elem=="Tri_VEF"))
1401 istetra=1;
1402
1403 // Les polyedres non standard sont ranges en 2 groupes dans le Domaine_VEF:
1404 // - polyedres bords et joints
1405 // - polyedres bords et non joints
1406 // On traite les polyedres en suivant l'ordre dans lequel ils figurent
1407 // dans le domaine
1408
1409 // boucle sur les polys
1410 int phi_u_transportant_yes=phi_u_transportant(equation());
1411 int dim = Objet_U::dimension;
1412 CIntTabView KEL = type_elemvef.KEL().view_ro();
1413 CIntArrView rang_elem_non_std = domaine_VEF.rang_elem_non_std().view_ro();
1414 CIntArrView type_elem_Cl = domaine_Cl_VEF.type_elem_Cl().view_ro();
1415 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
1416 CDoubleTabView3 normales_facettes_Cl = domaine_Cl_VEF.normales_facettes_Cl().view_ro<3>();
1417 CDoubleTabView3 facette_normales = domaine_VEF.facette_normales().view_ro<3>();
1418 CDoubleArrView porosite_face = tab_porosite_face.view_ro();
1419 CDoubleArrView porosite_elem = equation().milieu().porosite_elem().view_ro();
1420 CDoubleTabView vitesse = la_vitesse.valeurs().view_ro();
1421 CDoubleTabView velocity_tab = tab_velocity_tab.view_ro();
1422 CDoubleTabView transporte = tab_transporte.view_ro();
1423 Matrice_Morse_View matrice;
1424 matrice.set(matrice_morse);
1425 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, nb_elem_tot), KOKKOS_LAMBDA(const int poly)
1426 {
1427 int rang = rang_elem_non_std(poly);
1428 int itypcl= rang==-1 ? 0 : type_elem_Cl(rang);
1429
1430 // calcul des numeros des faces du polyedre
1431 int face[4];
1432 for (int face_adj=0; face_adj<nfac; face_adj++)
1433 face[face_adj] = elem_faces(poly,face_adj);
1434
1435 double vs[3];
1436 for (int j=0; j<dim; j++)
1437 {
1438 vs[j] = velocity_tab(face[0],j)*porosite_face[face[0]];
1439 for (int i=1; i<nfac; i++)
1440 vs[j] += velocity_tab(face[i],j)*porosite_face[face[i]];
1441 }
1442 // calcul de la vitesse aux sommets des polyedres
1443 // On va utliser les fonctions de forme implementees dans la classe Champs_P1_impl ou Champs_Q1_impl
1444 double vsom[12];
1445 if (istetra==1)
1446 {
1447 for (int i=0; i<nsom; i++)
1448 for (int j=0; j<dim; j++)
1449 vsom[i * dim + j] = (vs[j] - dim*velocity_tab(face[i],j)*porosite_face[face[i]]);
1450 }
1451 else
1452 {
1453 // pour que cela soit valide avec les hexa (c'est + lent a calculer...)
1454 Process::Kokkos_exit("Implicit scheme for VEF hexa ? Not coded. Even not tested.");
1455 /*
1456 for (int i=0; i<nsom; i++)
1457 {
1458 int num_som = les_elems(poly,i);
1459 for (int j=0; j<dim; j++)
1460 vsom(i,j) = la_vitesse.valeur_a_sommet_compo(num_som,poly,j);
1461 } */
1462 }
1463
1464 // calcul de vc (a l'intersection des 3 facettes) vc vs vsom proportionnelles a la prosite
1465 double vc[3];
1466 if (dim==3)
1467 calcul_vc_tetra_views(face,vc,vs,vsom,vitesse,itypcl,porosite_face);
1468 else
1469 calcul_vc_tri_views(face,vc,vs,vsom,vitesse,itypcl,porosite_face);
1470 if (marq==0)
1471 {
1472 const double porosite_poly=porosite_elem(poly);
1473 for (int j=0; j<dim; j++)
1474 {
1475 vs[j]/=porosite_poly;
1476 vc[j]/=porosite_poly;
1477 for (int i=0; i<nsom; i++)
1478 vsom[i * dim + j]/=porosite_poly;
1479 }
1480 }
1481 // Boucle sur les facettes du polyedre non standard:
1482 double cc[3] = { 0., 0., 0. };
1483 for (int fa7=0; fa7<nfa7; fa7++)
1484 {
1485 // normales aux facettes
1486 for (int i=0; i<dim; i++)
1487 cc[i] = rang==-1 ? facette_normales(poly,fa7,i) : normales_facettes_Cl(rang,fa7,i);
1488
1489 // On applique le schema de convection a chaque sommet de la facette
1490 double psc_c=0,psc_s=0,psc_s2=0;
1491 for (int i=0; i<dim; i++)
1492 {
1493 psc_c += vc[i]*cc[i];
1494 psc_s += vsom[KEL(2,fa7) * dim + i]*cc[i];
1495 psc_s2 += dim==3 ? vsom[KEL(3,fa7) * dim + i]*cc[i] : 0;
1496 }
1497 double psc_m=(psc_c+psc_s+psc_s2)/dim;
1498 int num10 = face[KEL(0,fa7)];
1499 int num20 = face[KEL(1,fa7)];
1500 convbisimplicite_dec(psc_m,num10,num20,transporte,ncomp_ch_transporte,matrice,porosite_face,phi_u_transportant_yes);
1501 } // fin de boucle sur les facettes.
1502
1503 }); // fin de boucle sur les polyedres.
1504 end_gpu_timer(__KERNEL_NAME__);
1505
1506 // Boucle sur les bords pour traiter les conditions aux limites
1507 // il y a prise en compte d'un terme de convection pour les
1508 // conditions aux limites de Neumann_sortie_libre seulement
1509 int nb_bord = domaine_VEF.nb_front_Cl();
1510 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1511 {
1512 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1513 if (sub_type(Neumann_sortie_libre,la_cl.valeur()))
1514 {
1515 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1516 int num1 = le_bord.num_premiere_face();
1517 int num2 = num1 + le_bord.nb_faces();
1518 CDoubleTabView face_normales = domaine_VEF.face_normales().view_ro();
1519 CDoubleTabView vitesse_face = tab_vitesse_face.view_ro();
1520 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(num1, num2), KOKKOS_LAMBDA(const int num_face)
1521 {
1522 double psc=0;
1523 for (int i=0; i<dim; i++)
1524 psc += vitesse_face(num_face,i)*face_normales(num_face,i);
1525 if (!phi_u_transportant_yes)
1526 psc*=porosite_face(num_face);
1527 if (psc>0)
1528 {
1529 for (int j=0; j<ncomp_ch_transporte; j++)
1530 {
1531 int n0=num_face*ncomp_ch_transporte+j;
1532 matrice.atomic_add(n0,n0,psc);
1533 }
1534 }
1535 });
1536 end_gpu_timer(__KERNEL_NAME__);
1537 }
1538 }
1540}
1541
1543{
1544 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
1545 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
1546 const Champ_Inc_base& la_vitesse=vitesse();
1547 const DoubleTab& face_normales = domaine_VEF.face_normales();
1548 //const Domaine& domaine = domaine_VEF.domaine();
1549 //int nfac = domaine.nb_faces_elem();
1550
1551 double psc;
1552 int i,n_bord;
1553 int num_face;
1554 int ncomp;
1555 if (resu.nb_dim() == 1)
1556 ncomp=1;
1557 else
1558 ncomp= resu.dimension(1);
1559
1560 //ArrOfInt face(nfac);
1561
1562
1563 // Traitement particulier pour les faces de periodicite
1564
1565 int nb_faces_perio = 0;
1566 int voisine;
1567 double diff1,diff2;
1568
1569 // Boucle pour compter le nombre de faces de periodicite
1570 for (n_bord=0; n_bord<domaine_VEF.nb_front_Cl(); n_bord++)
1571 {
1572 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1573 if (sub_type(Periodique,la_cl.valeur()))
1574 {
1575 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1576 nb_faces_perio += le_bord.nb_faces();
1577 }
1578 }
1579
1580 DoubleTab tab;
1581 if (ncomp == 1)
1582 tab.resize(nb_faces_perio);
1583 else
1584 tab.resize(nb_faces_perio,ncomp);
1585
1586 // Boucle pour remplir tab
1587 nb_faces_perio=0;
1588 for (n_bord=0; n_bord<domaine_VEF.nb_front_Cl(); n_bord++)
1589 {
1590 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1591 if (sub_type(Periodique,la_cl.valeur()))
1592 {
1593 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1594 int num1 = le_bord.num_premiere_face();
1595 int num2 = num1 + le_bord.nb_faces();
1596 for (num_face=num1; num_face<num2; num_face++)
1597 {
1598 if (ncomp == 1)
1599 tab(nb_faces_perio) = resu(num_face);
1600 else
1601 for (int comp=0; comp<ncomp; comp++)
1602 tab(nb_faces_perio,comp) = resu(num_face,comp);
1603 nb_faces_perio++;
1604 }
1605 }
1606 }
1607 // Boucle sur les bords pour traiter les conditions aux limites
1608 // il y a prise en compte d'un terme de convection pour les
1609 // conditions aux limites de Neumann_sortie_libre seulement
1610 nb_faces_perio=0;
1611 for (n_bord=0; n_bord<domaine_VEF.nb_front_Cl(); n_bord++)
1612 {
1613
1614 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1615
1616 if (sub_type(Neumann_sortie_libre,la_cl.valeur()))
1617 {
1618 const Neumann_sortie_libre& la_sortie_libre = ref_cast(Neumann_sortie_libre, la_cl.valeur());
1619 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1620 int num1 = le_bord.num_premiere_face();
1621 int num2 = num1 + le_bord.nb_faces();
1622 for (num_face=num1; num_face<num2; num_face++)
1623 {
1624 psc =0;
1625 for (i=0; i<dimension; i++)
1626 psc += la_vitesse.valeurs()(num_face,i)*face_normales(num_face,i);
1627 if (psc>0)
1628 if (ncomp == 1)
1629 resu(num_face) += 0;
1630 else
1631 for (i=0; i<ncomp; i++)
1632 resu(num_face,i) += 0;
1633 else
1634 {
1635 if (ncomp == 1)
1636 resu(num_face) -= psc*la_sortie_libre.val_ext(num_face-num1);
1637 else
1638 for (i=0; i<ncomp; i++)
1639 resu(num_face,i) -= psc*la_sortie_libre.val_ext(num_face-num1,i);
1640 }
1641 }
1642 }
1643 else if (sub_type(Periodique,la_cl.valeur()))
1644 {
1645 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl.valeur());
1646 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1647 int num1 = le_bord.num_premiere_face();
1648 int num2 = num1 + le_bord.nb_faces();
1649 ArrOfInt fait(le_bord.nb_faces());
1650 fait = 0;
1651 for (num_face=num1; num_face<num2; num_face++)
1652 {
1653 if (fait[num_face-num1] == 0)
1654 {
1655 voisine = la_cl_perio.face_associee(num_face-num1) + num1;
1656
1657 if (ncomp == 1)
1658 {
1659 diff1 = resu(num_face)-tab(nb_faces_perio);
1660 diff2 = resu(voisine)-tab(nb_faces_perio+voisine-num_face);
1661 resu(voisine) += diff1;
1662 resu(num_face) += diff2;
1663 }
1664 else
1665 for (int comp=0; comp<ncomp; comp++)
1666 {
1667 diff1 = resu(num_face,comp)-tab(nb_faces_perio,comp);
1668 diff2 = resu(voisine,comp)-tab(nb_faces_perio+voisine-num_face,comp);
1669 resu(voisine,comp) += diff1;
1670 resu(num_face,comp) += diff2;
1671 }
1672
1673 fait[num_face-num1]= 1;
1674 fait[voisine-num1] = 1;
1675 }
1676 nb_faces_perio++;
1677 }
1678 }
1679 }
1680}
1681
1683{
1684 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
1685 const Domaine_VEF& domaine_VEF = ref_cast(Domaine_VEF, le_dom_vef.valeur());
1686 int marq=phi_u_transportant(equation());
1687 // on force a calculer un pas de temps sans "porosite"
1688 marq=0;
1689 const Domaine& domaine = domaine_VEF.domaine();
1690 int nfac = domaine.nb_faces_elem();
1691 int nsom = domaine.nb_som_elem();
1692 const int nfa7 = domaine_VEF.type_elem().nb_facette();
1693 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
1694
1695 // On definit le tableau des sommets:(C MALOD 17/07/2007)
1696
1697 // Pour le traitement de la convection on distingue les polyedres
1698 // standard qui ne "voient" pas les conditions aux limites et les
1699 // polyedres non standard qui ont au moins une face sur le bord.
1700 // Un polyedre standard a n facettes sur lesquelles on applique le
1701 // schema de convection.
1702 // Pour un polyedre non standard qui porte des conditions aux limites
1703 // de Dirichlet, une partie des facettes sont portees par les faces.
1704 // En bref pour un polyedre le traitement de la convection depend
1705 // du type (triangle, tetraedre ...) et du nombre de faces de Dirichlet.
1706
1707 const Elem_VEF_base& type_elemvef= domaine_VEF.type_elem();
1708 int istetra=0;
1709 Nom nom_elem=type_elemvef.que_suis_je();
1710 if ((nom_elem=="Tetra_VEF")||(nom_elem=="Tri_VEF"))
1711 istetra=1;
1712
1713 // On remet a zero le tableau qui sert pour
1714 // le calcul du pas de temps de stabilite
1715 fluent_ = 0;
1716
1717 // Les polyedres non standard sont ranges en 2 groupes dans le Domaine_VEF:
1718 // - polyedres bords et joints
1719 // - polyedres bords et non joints
1720 // On traite les polyedres en suivant l'ordre dans lequel ils figurent
1721 // dans le domaine
1722 if (nom_elem=="Tetra_VEF")
1723 {
1724 assert(dimension==3);
1725 int dim = 3;
1726 CIntArrView rang_elem_non_std = domaine_VEF.rang_elem_non_std().view_ro();
1727 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
1728 CDoubleTabView3 facette_normales = domaine_VEF.facette_normales().view_ro<3>();
1729 CDoubleTabView3 normales_facettes_Cl = domaine_Cl_VEF.normales_facettes_Cl().view_ro<3>();
1730 CIntTabView KEL = type_elemvef.KEL().view_ro();
1731 CDoubleArrView porosite_face = equation().milieu().porosite_face().view_ro();
1732 CDoubleArrView porosite_elem = equation().milieu().porosite_elem().view_ro();
1733 CDoubleTabView vitesse_face = vitesse().valeurs().view_ro();
1734 CIntArrView type_elem_Cl = type_elem_Cl_.view_ro();
1735 DoubleArrView fluent = fluent_.view_rw();
1736 // boucle sur les polys
1737 auto kernel = KOKKOS_LAMBDA(const int poly)
1738 {
1739 // calcul des numeros des faces du polyedre
1740 int face[4];
1741 for (int face_adj = 0; face_adj < nfac; face_adj++)
1742 face[face_adj] = elem_faces(poly, face_adj);
1743
1744 double vs[3];
1745 for (int j = 0; j < dim; j++)
1746 {
1747 vs[j] = 0;
1748 for (int i = 0; i < nfac; i++)
1749 vs[j] += vitesse_face(face[i], j) * porosite_face(face[i]);
1750 }
1751
1752 // calcul de la vitesse aux sommets des tetradres
1753 double vsom[12];
1754 for (int i = 0; i < 4; i++)
1755 for (int j = 0; j < 3; j++)
1756 vsom[i * 3 + j] = (vs[j] - 3 * vitesse_face(face[i], j) * porosite_face(face[i]));
1757
1758 int itypcl = type_elem_Cl(poly);
1759 // calcul de vc (a l'intersection des 3 facettes) vc vs vsom proportionnelles a la prosite
1760 double vc[3];
1761 calcul_vc_tetra_views(face, vc, vs, vsom, vitesse_face, itypcl, porosite_face);
1762 if (marq == 0)
1763 {
1764 double inv_porosite_poly = 1.0 / porosite_elem(poly);
1765 for (int j = 0; j < dim; j++)
1766 {
1767 vs[j] *= inv_porosite_poly;
1768 vc[j] *= inv_porosite_poly;
1769 for (int i = 0; i < nsom; i++)
1770 vsom[i * dim + j] *= inv_porosite_poly;
1771 }
1772 }
1773 int rang = rang_elem_non_std(poly);
1774 // Boucle sur les facettes du polyedre non standard:
1775 for (int fa7 = 0; fa7 < nfa7; fa7++)
1776 {
1777 int num1 = face[KEL(0, fa7)];
1778 int num2 = face[KEL(1, fa7)];
1779 // On applique le schema de convection a chaque sommet de la facette
1780 double psc_c = 0, psc_s = 0, psc_s2 = 0;
1781 for (int i = 0; i < dim; i++)
1782 {
1783 double cc = rang == -1 ? facette_normales(poly, fa7, i) : normales_facettes_Cl(rang, fa7, i);
1784 psc_c += vc[i] * cc;
1785 psc_s += vsom[KEL(2, fa7) * dim + i] * cc;
1786 psc_s2 += vsom[KEL(3, fa7) * dim + i] * cc;
1787 }
1788 double psc_m = (psc_c + psc_s + psc_s2) / dim;
1789
1790 int num = (psc_m >= 0 ? num2 : num1);
1791 Kokkos::atomic_add(&fluent[num], std::abs(psc_m));
1792 } // fin de la boucle sur les facettes
1793 };
1794 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nb_elem_tot, kernel);
1795 end_gpu_timer(__KERNEL_NAME__);
1796 }
1797 else
1798 {
1799 const DoubleVect& porosite_elem = equation().milieu().porosite_elem();
1800 const IntTab& KEL = type_elemvef.KEL();
1801 const DoubleVect& porosite_face = equation().milieu().porosite_face();
1802 const IntTab& elem_faces = domaine_VEF.elem_faces();
1803 const auto& facette_normales = domaine_VEF.facette_normales();
1804 const IntTab& les_elems = domaine.les_elems();
1805 const IntVect& rang_elem_non_std = domaine_VEF.rang_elem_non_std();
1806 const DoubleTab& normales_facettes_Cl = domaine_Cl_VEF.normales_facettes_Cl();
1807 ArrOfInt face(nfac);
1808 ArrOfDouble vs(dimension);
1809 ArrOfDouble vc(dimension);
1810 DoubleTab vsom(nsom,dimension);
1811 ArrOfDouble cc(dimension);
1812 const DoubleTab& vitesse_face = vitesse().valeurs();
1813 // boucle sur les polys
1814 for (int poly=0; poly<nb_elem_tot; poly++)
1815 {
1816 int rang = rang_elem_non_std(poly);
1817 // On cherche, pour un elem qui n'est pas de bord (rang==-1),
1818 // si un des sommets est sur un bord (tableau des sommets) (C MALOD 17/07/2007)
1819 int itypcl;
1820 if (rang==-1)
1821 itypcl=0;
1822 else
1823 itypcl=domaine_Cl_VEF.type_elem_Cl(rang);
1824
1825 // calcul des numeros des faces du polyedre
1826 for (int face_adj=0; face_adj<nfac; face_adj++)
1827 face[face_adj]= elem_faces(poly,face_adj);
1828
1829 for (int j=0; j<dimension; j++)
1830 {
1831 vs[j] = vitesse_face(face[0],j)*porosite_face[face[0]];
1832 for (int i=1; i<nfac; i++)
1833 vs[j]+= vitesse_face(face[i],j)*porosite_face[face[i]];
1834 }
1835 // calcul de la vitesse aux sommets des polyedres
1836 // On va utliser les fonctions de forme implementees dans la classe Champs_P1_impl ou Champs_Q1_impl
1837 if (istetra==1)
1838 {
1839 for (int i=0; i<nsom; i++)
1840 for (int j=0; j<dimension; j++)
1841 vsom(i,j) = (vs[j] - dimension*vitesse_face(face[i],j)*porosite_face[face[i]]);
1842 }
1843 else
1844 {
1845 // pour que cela soit valide avec les hexa (c'est + lent a calculer...)
1846 int ncomp;
1847 for (int j=0; j<nsom; j++)
1848 {
1849 int num_som = les_elems(poly,j);
1850 for (ncomp=0; ncomp<dimension; ncomp++)
1851 vsom(j,ncomp) = vitesse().valeur_a_sommet_compo(num_som,poly,ncomp);
1852 }
1853 }
1854
1855 // calcul de vc (a l'intersection des 3 facettes) vc vs vsom proportionnelles a la prosite
1856 type_elemvef.calcul_vc(face,vc,vs,vsom,vitesse(),itypcl,porosite_face);
1857 if (marq==0)
1858 {
1859 double porosite_poly=porosite_elem(poly);
1860 for (int i=0; i<nsom; i++)
1861 for (int j=0; j<dimension; j++)
1862 vsom(i,j)/=porosite_poly;
1863 for (int j=0; j<dimension; j++)
1864 {
1865 vs[j]/= porosite_poly;
1866 vc[j]/=porosite_poly;
1867 }
1868 }
1869 // Boucle sur les facettes du polyedre non standard:
1870 for (int fa7=0; fa7<nfa7; fa7++)
1871 {
1872 int num1 = face[KEL(0,fa7)];
1873 int num2 = face[KEL(1,fa7)];
1874 // normales aux facettes
1875 if (rang==-1)
1876 {
1877 for (int i=0; i<dimension; i++)
1878 cc[i] = facette_normales(poly, fa7, i);
1879 }
1880 else
1881 {
1882 for (int i=0; i<dimension; i++)
1883 cc[i] = normales_facettes_Cl(rang,fa7,i);
1884 }
1885 // On applique le schema de convection a chaque sommet de la facette
1886
1887 double psc_c=0,psc_s=0,psc_m,psc_s2=0;
1888 if (dimension==2)
1889 {
1890 for (int i=0; i<dimension; i++)
1891 {
1892 psc_c+=vc[i]*cc[i];
1893 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
1894 }
1895 psc_m=(psc_c+psc_s)/2.;
1896 }
1897 else
1898 {
1899 for (int i=0; i<dimension; i++)
1900 {
1901 psc_c+=vc[i]*cc[i];
1902 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
1903 psc_s2+=vsom(KEL(3,fa7),i)*cc[i];
1904 }
1905 psc_m=(psc_c+psc_s+psc_s2)/3.;
1906 }
1907
1908 // int amont,dir;
1909 if (psc_m >= 0)
1910 {
1911 // amont = num1;
1912 fluent_(num2) += psc_m;
1913 //dir=0;
1914 }
1915 else
1916 {
1917 //amont = num2;
1918 fluent_(num1) -= psc_m;
1919 //dir=1;
1920 }
1921
1922 } // fin de la boucle sur les facettes
1923 } // fin de la boucle
1924 }
1925
1926 // Boucle sur les bords pour traiter les conditions aux limites
1927 // il y a prise en compte d'un terme de convection pour les
1928 // conditions aux limites de Neumann_sortie_libre seulement
1929 int nb_bord = domaine_VEF.nb_front_Cl();
1930 int nb_comp = Objet_U::dimension;
1931 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1932 {
1933 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1934 if (sub_type(Neumann_sortie_libre,la_cl.valeur()))
1935 {
1936 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1937 int num1b = le_bord.num_premiere_face();
1938 int num2b = num1b + le_bord.nb_faces();
1939 CDoubleTabView face_normales = domaine_VEF.face_normales().view_ro();
1940 CDoubleTabView vitesse_face = vitesse().valeurs().view_ro();
1941 DoubleArrView fluent = fluent_.view_rw();
1942 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
1943 Kokkos::RangePolicy<>(num1b, num2b), KOKKOS_LAMBDA(
1944 const int num_face)
1945 {
1946 double psc = 0;
1947 for (int i=0; i<nb_comp; i++)
1948 psc += vitesse_face(num_face,i)*face_normales(num_face,i);
1949 if (psc>0) { /* Do nothing */}
1950 else
1951 fluent(num_face) -= psc;
1952 });
1953 end_gpu_timer(__KERNEL_NAME__);
1954 }
1955 }
1956}
1957
1959{
1960 ord=ordre_;
1961}
1963{
1964 typelim=type_lim;
1965}
1966void Op_Conv_VEF_Face::get_alpha(double& alp) const
1967{
1968 alp=alpha_;
1969}
1970
1971void Op_Conv_VEF_Face::get_type_op(int& typeop) const
1972{
1973 typeop=type_op;
1974}
Classe Champ_Inc_base.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
static DoubleTab & calcul_gradient(const DoubleTab &, DoubleTab &, const Domaine_Cl_VEF &)
virtual double valeur_a_sommet_compo(int, int, int) const
renvoi la compo eme corrdonne des valeurs a l'element le_poly au sommet sommet
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
virtual Frontiere_dis_base & frontiere_dis()
Renvoie la frontiere discretisee a laquelle les conditions aux limites s'appliquent.
classe Cond_lim Classe generique servant a representer n'importe quelle classe
Definition Cond_lim.h:31
Classe Dirichlet_homogene Cette classe est la classe de base de la hierarchie des conditions aux limi...
classe Dirichlet Cette classe est la classe de base de la hierarchie des conditions aux limites de ty...
Definition Dirichlet.h:31
int nb_faces_elem(int=0) const
Renvoie le nombre de face de type i des elements geometriques constituants le domaine.
Definition Domaine.h:484
int type_elem_Cl(int i) const
DoubleTab & vecteur_face_facette_Cl()
DoubleTab & normales_facettes_Cl()
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
class Domaine_VEF
Definition Domaine_VEF.h:54
IntVect & rang_elem_non_std()
Definition Domaine_VEF.h:86
const Elem_VEF_base & type_elem() const
Definition Domaine_VEF.h:75
auto & facette_normales()
Definition Domaine_VEF.h:84
int nb_faces() const
renvoie le nombre global de faces.
Definition Domaine_VF.h:471
int nb_faces_tot() const
renvoie le nombre total de faces.
Definition Domaine_VF.h:481
void creer_tableau_faces(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
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
ArrOfInt & faces_doubles()
renvoie 1 pour les faces appartenant a un bord perio ou un item commun, 0 par defaut
Definition Domaine_VF.h:567
int face_sommets(int i, int j) const
renvoie le numero du ieme sommet de la face num_face.
Definition Domaine_VF.h:583
int elem_faces(int i, int j) const
renvoie le numero de le ieme face de la maille num_elem la facon dont ces faces sont numerotees est
Definition Domaine_VF.h:543
double xp(int num_elem, int k) const
Definition Domaine_VF.h:77
int premiere_face_int() const
une face est interne ssi elle separe deux elements.
Definition Domaine_VF.h:463
int face_voisins(int num_face, int i) const
renvoie l'element voisin de numface dans la direction i.
Definition Domaine_VF.h:418
int nb_faces_bord() const
renvoie le nombre de faces sur lesquelles sont appliquees les conditions limites :
Definition Domaine_VF.h:513
int nb_elem_tot() const
int nb_front_Cl() const
const Domaine & domaine() const
int nb_som_tot() const
virtual void calcul_xg(DoubleVect &, const DoubleTab &, const int, int &, int &, int &, int &) const =0
virtual void calcul_vc(const ArrOfInt &, ArrOfDouble &, const ArrOfDouble &, const DoubleTab &, const Champ_Inc_base &, int, const DoubleVect &) const =0
const IntTab & KEL() const
virtual int nb_facette() const =0
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
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
int nb_faces_tot() const
Definition Front_VF.h:58
int num_face(const int) const
Definition Front_VF.h:68
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
DoubleVect & porosite_elem()
Definition Milieu_base.h:58
DoubleVect & porosite_face()
Definition Milieu_base.h:62
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
Une chaine de caractere (Nom) en majuscules.
Definition Motcle.h:26
classe Neumann_sortie_libre Cette classe represente une frontiere ouverte sans vitesse imposee
double val_ext(int i) const override
Renvoie la valeur de la i-eme composante du champ impose a l'exterieur de la frontiere.
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
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
class Op_Conv_VEF_Face
void ajouter_contribution_gen(const DoubleTab &transporte, const Champ_Inc_base &la_vitesse, Matrice_Morse &matrice) const
ArrOfInt est_une_face_de_dirichlet_
void contribue_au_second_membre(DoubleTab &) const
ArrOfInt traitement_pres_bord_
void get_type_op(int &) const
void get_type_lim(Motcle &) const
void remplir_fluent() const override
DoubleTab & ajouter_gen(const DoubleTab &transporte, const Champ_Inc_base &la_vitesse, DoubleTab &resu) const
type_lim_type type_lim_int
double(* LIMITEUR)(double, double)
type_operateur type_op
void get_ordre(int &) const
void get_alpha(double &) const
DoubleTab & ajouter(const DoubleTab &, DoubleTab &) const override
virtual void ajouter_contribution(const DoubleTab &, Matrice_Morse &) const
void completer() override
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
class Op_Conv_VEF_base
int phi_u_transportant(const Equation_base &eq) const
definit si l'on convecte psi avec phi*u ou avec u
const Champ_Inc_base & vitesse() const
void modifier_matrice_pour_periodique_apres_contribuer(Matrice_Morse &matrice, const Equation_base &) const
Somme les 2 lignes des faces periodiques associees permet de calculer dans le code sans se poser de q...
void modifier_matrice_pour_periodique_avant_contribuer(Matrice_Morse &matrice, const Equation_base &) const
divise les coefficients sur les ligne des faces periodiques par 2 en prevision de l'application modif...
void modifier_flux(const Operateur_base &) const
DoubleTab flux_bords_
virtual void completer()
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
classe Periodique Cette classe represente une condition aux limites periodique.
Definition Periodique.h:31
int face_associee(int i) const
Definition Periodique.h:35
static KOKKOS_INLINE_FUNCTION void Kokkos_exit(const char *)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.h:173
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
classe Symetrie Sur les faces de symetrie on a les proprietes suivantes:
Definition Symetrie.h:37
virtual void ref(const TRUSTTab &)
Definition TRUSTTab.tpp:308
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, View< _TYPE_, _SHAPE_ > > view_wo()
Definition TRUSTTab.h:276
int nb_dim() const
Definition TRUSTTab.h:199
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, ConstView< _TYPE_, _SHAPE_ > > view_ro() const
Definition TRUSTTab.h:261
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, View< _TYPE_, _SHAPE_ > > view_rw()
Definition TRUSTTab.h:291
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
virtual void finish_echange_espace_virtuel_async(const std::string kernel_name)
virtual void start_echange_espace_virtuel_async(const std::string kernel_name)
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")
CDoubleTabView4 vecteur_face_facette_Cl_v
CIntArrView traitement_pres_bord_v
CDoubleArrView porosite_elem_v
CDoubleTabView3 normales_facettes_Cl_v
CDoubleTabView3 facette_normales_v
CDoubleArrView porosite_face_v
CDoubleTabView transporte_face_v
CIntArrView est_une_face_de_dirichlet_v
CDoubleTabView3 gradient_v
CDoubleTabView coord_sommets_v