TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Op_Conv_EF_VEF_P1NC_Stab.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_EF_VEF_P1NC_Stab.h>
17#include <Champ_P1NC.h>
18#include <BilanQdmVEF.h>
19#include <Sous_Domaine.h>
20#include <Sous_domaine_dis_base.h>
21#include <Schema_Temps_base.h>
22#include <Debog.h>
23#include <Porosites_champ.h>
24#include <Sous_domaine_VF.h>
25#include <Probleme_base.h>
26#include <ArrOfBit.h>
27#include <TRUSTVects.h>
28#include <SFichier.h>
29#include <TRUSTList.h>
30#include <TRUSTTabs.h>
31#include <Neumann_sortie_libre.h>
32#include <Dirichlet_homogene.h>
33#include <Neumann_homogene.h>
34#include <Periodique.h>
35#include <Symetrie.h>
36#include <Echange_impose_base.h>
37#include <Array_tools.h>
38
39Implemente_instanciable(Op_Conv_EF_VEF_P1NC_Stab,"Op_Conv_EF_Stab_VEF_P1NC",Op_Conv_VEF_Face);
40
41// XD sous_zone_valeur objet_lecture nul NO_BRACE Two words.
42// XD attr sous_zone ref_sous_zone sous_zone REQ sous zone
43// XD attr valeur floattant valeur REQ value
44
45// XD listsous_zone_valeur listobj nul NO_BRACE sous_zone_valeur NO_COMMA List of groups of two words.
46
47// XD convection_ef_stab convection_deriv ef_stab BRACE Keyword for a VEF convective scheme.
48// XD attr alpha floattant alpha OPT To weight the scheme centering with the factor double (between 0 (full centered)
49// XD_CONT and 1 (mix between upwind and centered), by default 1). For scalar equation, it is adviced to use alpha=1 and
50// XD_CONT for the momentum equation, alpha=0.2 is adviced.
51// XD attr test entier test OPT Developer option to compare old and new version of EF_stab
52// XD attr tdivu rien tdivu OPT To have the convective operator calculated as div(TU)-TdivU(=UgradT).
53// XD attr old rien old OPT To use old version of EF_stab scheme (default no).
54// XD attr volumes_etendus rien volumes_etendus OPT Option for the scheme to use the extended volumes (default, yes).
55// XD attr volumes_non_etendus rien volumes_non_etendus OPT Option for the scheme to not use the extended volumes
56// XD_CONT (default, no).
57// XD attr amont_sous_zone ref_sous_zone amont_sous_zone OPT Option to degenerate EF_stab scheme into Amont (upwind)
58// XD_CONT scheme in the sub zone of name sz_name. The sub zone may be located arbitrarily in the domain but the more
59// XD_CONT often this option will be activated in a zone where EF_stab scheme generates instabilities as for free outlet
60// XD_CONT for example.
61// XD attr alpha_sous_zone listsous_zone_valeur alpha_sous_zone OPT Option to change locally the alpha value on N
62// XD_CONT sub-zones named sub_zone_name_I. Generally, it is used to prevent from a local divergence by increasing
63// XD_CONT locally the alpha parameter.
64
66{
67 return s << que_suis_je();
68}
69
71{
72 //Les mots a reconnaitre
73 Motcle motlu, accouverte = "{" , accfermee = "}" ;
74 Motcles les_mots(11);
75 {
76 les_mots[0] = "alpha";
77 les_mots[1] = "test";
78 les_mots[2] = "TdivU";
79 les_mots[3] = "old";
80 les_mots[4] = "volumes_etendus";
81 les_mots[5] = "volumes_non_etendus";
82 les_mots[6] = "amont_sous_domaine";
83 les_mots[7] = "amont_sous_zone";
84 les_mots[8] = "nouvelle_matrice_implicite";
85 les_mots[9] = "alpha_sous_domaine";
86 les_mots[10] = "alpha_sous_zone";
87 }
88
89 s >> motlu;
90 if (motlu!=accouverte)
91 {
92 Cerr << "Error Op_Conv_EF_VEF_P1NC_Stab::readOn()" << finl;
93 Cerr << "Since version 1.5.3, the syntax of the keyword EF_stab has changed." << finl;
94 Cerr << "It must begin with an opening brace {" << finl;
95 Cerr << "and the optional parameters are between the braces:" << finl;
96 Cerr << "Convection { EF_stab } -> Convection { EF_stab { } }" << finl;
98 }
99 s >> motlu;
100
101 while(motlu!=accfermee)
102 {
103 int rang=les_mots.search(motlu);
104
105 switch(rang)
106 {
107 case 0 :
108
109 s >> alpha_;
110 break;
111
112 case 1 :
113
114 test_=1;
115 break;
116
117 case 2 :
118
119 is_compressible_=1;
120 break;
121
122 case 3 :
123
124 old_=1;
125 break;
126
127 case 4 :
128
129 volumes_etendus_=1;
130 break;
131
132 case 5 :
133
134 volumes_etendus_=0;
135 break;
136
137 case 6 :
138 case 7 :
139 sous_domaine=true;
140 s >> nom_sous_domaine;
141 break;
142 case 8 :
143 s >> new_jacobienne_;
144 break;
145 case 9 :
146 case 10 :
147 ssz_alpha=true;
148 s >> nb_ssz_alpha;
149 noms_ssz_alpha.dimensionner(nb_ssz_alpha);
150 alpha_ssz.resize(nb_ssz_alpha);
151 for (int i=0; i<nb_ssz_alpha; i++)
152 {
153 s>>noms_ssz_alpha[i];
154 s>>alpha_ssz(i);
155 }
156 break;
157 default :
158
159 Cerr << "Error Op_Conv_EF_VEF_P1NC_Stab::readOn()" << finl;
160 Cerr << "Keyword " << motlu << " not recognized." << finl;
161 Cerr << "Exiting." << finl;
163
164 }//end switch
165
166 //Continue reading
167 s >> motlu;
168
169 }//end while
170
171 return s ;
172}
173
174
175static KOKKOS_INLINE_FUNCTION double maximum(const double x,
176 const double y)
177{
178 return x<y ? y : x;
179}
180
181static KOKKOS_INLINE_FUNCTION double maximum(const double x,
182 const double y,
183 const double z)
184{
185 return maximum(maximum(x,y),z);
186}
187
188static KOKKOS_INLINE_FUNCTION double minimum(const double x,
189 const double y)
190{
191 return x>y ? y : x;
192}
193
194static KOKKOS_INLINE_FUNCTION double Dij(int elem,
195 int face_loc_i,
196 int face_loc_j,
197 CDoubleTabView3 Kij)
198{
199 const double kij=Kij(elem,face_loc_i,face_loc_j);
200 const double kji=Kij(elem,face_loc_j,face_loc_i);
201 return maximum(-kij,-kji,0);
202}
203
204static inline double Dij(int elem,
205 int face_loc_i,
206 int face_loc_j,
207 const DoubleTab& Kij)
208{
209 const double kij=Kij(elem,face_loc_i,face_loc_j);
210 const double kji=Kij(elem,face_loc_j,face_loc_i);
211 return maximum(-kij,-kji,0);
212}
213
214static KOKKOS_INLINE_FUNCTION double limiteur(double r)
215{
216 return r<=0 ? 0 : Kokkos::fmax(Kokkos::fmin(2,r),Kokkos::fmin(1,2*r));//SuperBee
217}
218
219KOKKOS_INLINE_FUNCTION double formule_Id_2D(int n)
220{
221 return 1./3;
222}
223
224KOKKOS_INLINE_FUNCTION double formule_Id_3D(int n)
225{
226 return 0.25;
227}
228
229KOKKOS_INLINE_FUNCTION double formule_2D(int n)
230{
231 switch(n)
232 {
233 case 0:
234 return 1./3;
235 case 1:
236 return 0.5;
237 case 2:
238 return 1.;
239 default:
240 Process::Kokkos_exit("Erreur Op_Conv_EF_VEF_P1NC_Stab::formule_2D() ");
241 }
242 return 0.;
243}
244
245KOKKOS_INLINE_FUNCTION double formule_3D(int n)
246{
247 switch(n)
248 {
249 case 0:
250 return 0.25;
251 case 1:
252 return 1./3;
253 case 2:
254 return 0.5;
255 case 3:
256 return 1.;
257 default:
258 Process::Kokkos_exit("Erreur Op_Conv_EF_VEF_P1NC_Stab::formule_3D() ");
259 }
260 return 0.;
261}
262
263
264
265////////////////////////////////////////////////////////////////////
266//
267// Implementation of functions
268//
269// of class Op_Conv_EF_VEF_P1NC_Stab
270//
271////////////////////////////////////////////////////////////////////
272
273void Op_Conv_EF_VEF_P1NC_Stab::reinit_conv_pour_Cl(const DoubleTab& transporte,const IntList& faces, const DoubleTabs& valeurs_faces, const DoubleTab& tab_vitesse, DoubleTab& resu) const
274{
275 const Domaine_VEF& domaine_VEF=le_dom_vef.valeur();
276 const Domaine_Cl_VEF& domaine_Cl_VEF=la_zcl_vef.valeur();
277 const DoubleTab& face_normales=domaine_VEF.face_normales();
278 const int nb_bord=domaine_Cl_VEF.nb_cond_lim();
279 const int nb_comp=transporte.line_size();
280 int n_bord=0, num1=0, num2=0, ind_face=0,facei=0, dim=0;
281 double psc=0.;
282
283 const DoubleVect& transporteV= transporte;
284
285 //Loop to dimension the "faces" list
286 for (n_bord=0; n_bord<nb_bord; n_bord++)
287 {
288 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
289 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
290 num1 = 0;
291 num2 = le_bord.nb_faces_tot();
292
293 if (sub_type(Neumann_sortie_libre,la_cl.valeur()))
294 {
295 const Neumann_sortie_libre& la_sortie_libre
296 = ref_cast(Neumann_sortie_libre, la_cl.valeur());
297 ToDo_Kokkos("critical");
298 for (ind_face=num1; ind_face<num2; ind_face++)
299 {
300 facei = le_bord.num_face(ind_face);
301
302 psc=0.;
303 for (dim=0; dim<dimension; dim++)
304 psc-=tab_vitesse(facei,dim)*face_normales(facei,dim);
305
306 if (psc>0)
307 for (dim=0; dim<nb_comp; dim++)
308 resu(facei,dim)+=psc*(la_sortie_libre.val_ext(facei-num1,dim)-transporteV[facei*nb_comp+dim]);
309
310 }
311 }//end if on "Neumann_sortie_libre"
312 }
313}
314
315void Op_Conv_EF_VEF_P1NC_Stab::calculer_coefficients_operateur_centre(DoubleTab& tab_Kij,const int nb_comp, const DoubleTab& tab_vitesse) const
316{
317 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
318 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
319 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
320 const int nb_faces_elem = domaine_VEF.elem_faces().line_size();
321 int dim = Objet_U::dimension;
322
323 assert(tab_Kij.nb_dim()==3);
324 assert(tab_Kij.dimension(0)==nb_elem_tot);
325 assert(tab_Kij.dimension(1)==tab_Kij.dimension(2));
326 assert(tab_Kij.dimension(1)==nb_faces_elem);
327
328 //
329 //Compute the operator coefficients
330 //
331 CDoubleTabView face_normales = domaine_VEF.face_normales().view_ro();
332 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
333 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
334 CDoubleTabView vitesse = tab_vitesse.view_ro();
335 DoubleTabView3 Kij = tab_Kij.view_rw<3>();
336 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
337 range_2D({0,0}, {nb_elem_tot,nb_faces_elem}), KOKKOS_LAMBDA(
338 const int elem, const int face_loci)
339 {
340 int face_i=elem_faces(elem,face_loci);
341
342 double signei=1.0;
343 if(face_voisins(face_i,0)!=elem) signei=-1.0;
344
345 double psci=0;
346 for(int comp=0; comp<dim; comp++)
347 psci+=vitesse(face_i,comp)*face_normales(face_i,comp);
348 psci*=signei;
349
350 //Kij(elem,face_loci,face_loci)=0.;
351 for(int face_locj=face_loci+1; face_locj<nb_faces_elem; face_locj++)
352 {
353 int face_j=elem_faces(elem,face_locj);
354 double signej=1.0;
355 if(face_voisins(face_j,0)!=elem)
356 signej=-1.0;
357
358 double pscj=0;
359 //psci=0;
360 for(int comp=0; comp<dim; comp++)
361 pscj+=vitesse(face_j,comp)*face_normales(face_j,comp);
362 pscj*=signej;
363
364 Kokkos::atomic_add(&Kij(elem,face_loci,face_locj), -1./nb_faces_elem*pscj);
365 Kokkos::atomic_add(&Kij(elem,face_loci,face_loci), +1./nb_faces_elem*pscj);
366 Kokkos::atomic_add(&Kij(elem,face_locj,face_loci), -1./nb_faces_elem*psci);
367 Kokkos::atomic_add(&Kij(elem,face_locj,face_locj), +1./nb_faces_elem*psci);
368 }//end for on "face_locj"
369 });//end for on "elem"
370 end_gpu_timer(__KERNEL_NAME__);
371 //
372 // Correction of Kij for Dirichlet!
373 //
374 {
375 int nb_bord=domaine_Cl_VEF.nb_cond_lim();
376 for (int n_bord=0; n_bord<nb_bord; n_bord++)
377 {
378 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
379
380 if ( (sub_type(Dirichlet,la_cl.valeur()))
381 || (sub_type(Dirichlet_homogene,la_cl.valeur()))
382 )
383 {
384 // GF: removing the test on nb_comp because otherwise in scalar mode we always use extended volume
385 if ( volumes_etendus_ )
386 {
387 CIntTabView num_fac_loc = domaine_VEF.get_num_fac_loc().view_ro();
388 CIntTabView elem_faces_dirichlet_v = elem_faces_dirichlet_.view_ro();
389 CIntArrView elem_nb_faces_dirichlet_v = elem_nb_faces_dirichlet_.view_ro();
390 CIntArrView elem_faces_frontiere_v = elem_faces_frontiere[n_bord].view_ro();
391 const int elem_faces_frontiere_size = elem_faces_frontiere[n_bord].size_array();
392 //
393 //Modification of the matrix coefficients
394 //
395 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
396 Kokkos::RangePolicy<>(0,elem_faces_frontiere_size), KOKKOS_LAMBDA(
397 const int elem_ind)
398 {
399 const int elem=elem_faces_frontiere_v(elem_ind);
400 assert(elem!=-1);
401 const int nb_faces_bord = elem_nb_faces_dirichlet_v(elem);
402
403 //
404 //Compute the weighting coefficient
405 //
406
407 const double coeff = (dim==2) ?
408 nb_faces_bord/2. : nb_faces_bord*nb_faces_bord/6.-nb_faces_bord/3.+1./2;
409
410 //
411 //End of weighting coefficient computation
412 //
413
414 for (int face_loc_i=0; face_loc_i<nb_faces_elem; face_loc_i++)
415 {
416 const int face_i = elem_faces(elem,face_loc_i);
417
418 /* Determine whether "face_i" is a Dirichlet face */
419 bool is_not_on_boundary = true;
420 for (int f_loc=0; f_loc<nb_faces_bord; f_loc++)
421 is_not_on_boundary&=(face_i!=elem_faces_dirichlet_v(elem,f_loc));
422
423 if (is_not_on_boundary) /* if "face_i" is not a Dirichlet face */
424 {
425 for (int face_loc_j=0; face_loc_j<nb_faces_elem; face_loc_j++)
426 {
427 /* Modify the matrix coefficients */
428 /* according to the extended shape functions */
429 for (int f_loc=0; f_loc<nb_faces_bord; f_loc++)
430 {
431 const int face_bord = elem_faces_dirichlet_v(elem,f_loc);
432 const int face_loc_k = num_fac_loc(face_bord,0);
433 assert(face_loc_k>=0);
434 assert(face_loc_k<nb_faces_elem);
435
436 const double kkj = Kij(elem,face_loc_k,face_loc_j);
437 Kij(elem,face_loc_i,face_loc_j) += coeff*kkj;
438 }//end for on "f_loc"
439
440 }//end of for on "face_loc_k"
441
442 }//end of if
443
444 }//end of for on "face_loc_i"
445
446
447 //
448 //Reset to zero the coefficients associated with nodes
449 //that lie on the Dirichlet boundary
450 //
451 {
452 for (int f_loc=0; f_loc<nb_faces_bord; f_loc++)
453 {
454 const int face_bord = elem_faces_dirichlet_v(elem,f_loc);
455 const int face_loc_j = num_fac_loc(face_bord,0);
456 assert(face_loc_j>=0);
457 assert(face_loc_j<nb_faces_elem);
458
459 for (int face_loc_i=0; face_loc_i<nb_faces_elem; face_loc_i++)
460 Kij(elem,face_loc_j,face_loc_i)=0;
461 }//end of for on "f_loc"
462 }
463 //
464 //End of reset to zero
465 //
466
467 //
468 //To recover the LED scheme
469 //
470 {
471 for (int face_loc_i=0; face_loc_i<nb_faces_elem; face_loc_i++)
472 {
473 double sum=0.;
474 for (int face_loc_k=0; face_loc_k<nb_faces_elem; face_loc_k++)
475 {
476 sum+=Kij(elem,face_loc_i,face_loc_k);
477 }
478 //Cerr << "somme apres : " << sum << finl;
479 Kij(elem,face_loc_i,face_loc_i) -= sum;//car div(u)=0!
480 }
481 }
482 //
483 //End of LED scheme
484 //
485
486 });// for face
487
488 end_gpu_timer(__KERNEL_NAME__);
489
490 //
491 //End of matrix coefficient modification
492 //
493
494 }//end of if on "volumes_etendus_"
495
496 }// sub_type Dirichlet
497
498
499 else if (sub_type(Neumann,la_cl.valeur()) || sub_type(Neumann_homogene,la_cl.valeur()) || sub_type(Neumann_val_ext,la_cl.valeur()))
500 {
501 //Do nothing
502 }//end of if on Neumann
503
504 else if (sub_type(Symetrie,la_cl.valeur()))
505 {
506 //Do nothing
507 }//end of if on Symetrie
508
509 else if (sub_type(Periodique,la_cl.valeur()))
510 {
511 //Do nothing
512 }//end of if on Periodique
513
514 else if (sub_type(Echange_impose_base,la_cl.valeur()))
515 {
516 //Do nothing
517 }//end of if on Echange_impose_base
518
519 else
520 {
521 Cerr << "Error Op_Conv_EF_VEF_P1NC_Stab::calculer_coefficients_operateur_centre()" << finl;
522 Cerr << "Boundary condition " << la_cl.que_suis_je() << " not implemented." << finl;
523 Cerr << "Exiting." << finl;
525 }//end of else on other boundary conditions
526
527 }//end of boundary conditions
528 }
529
530 //
531 // End of Kij correction
532 //
533}
535{
536 // CFL computation.
537 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
538 const int nb_faces = domaine_VEF.nb_faces();
539 int nb_comp = Objet_U::dimension;
540 CDoubleTabView face_normales = domaine_VEF.face_normales().view_ro();
541 CDoubleTabView tab_vitesse = vitesse_->valeurs().view_ro();
542 DoubleArrView fluent = fluent_.view_rw();
543 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
544 Kokkos::RangePolicy<>(0, nb_faces), KOKKOS_LAMBDA(
545 const int num_face)
546 {
547 double psc=0.;
548 for (int i=0; i<nb_comp; i++)
549 psc+=tab_vitesse(num_face,i)*face_normales(num_face,i);
550 fluent(num_face)=std::fabs(psc);
551 });
552 end_gpu_timer(__KERNEL_NAME__);
553}
554
555
556DoubleTab& Op_Conv_EF_VEF_P1NC_Stab::ajouter(const DoubleTab& transporte_2,
557 DoubleTab& resu) const
558{
559 DoubleTab sauv(resu);
560 resu=0;
561
562 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
563 const Champ_P1NC& la_vitesse=ref_cast( Champ_P1NC, vitesse_.valeur());
564 const DoubleTab& vitesse_2=la_vitesse.valeurs();
565 const DoubleVect& porosite_face = equation().milieu().porosite_face();
566
567 const IntTab& elem_faces = domaine_VEF.elem_faces();
568
569 const int marq=phi_u_transportant(equation());
570 const int nb_faces_elem=elem_faces.dimension(1);
571 assert(nb_faces_elem==(dimension+1));
572 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
573 int nb_comp=resu.line_size();
574
575 DoubleTab transporte_;
576 DoubleTab vitesse_face_;
577 // either transporte=phi*transporte_ and vitesse=vitesse_
578 // or transporte=transporte_ and vitesse=phi*vitesse_
579 // depending on whether transport uses phi*u or u.
580 const DoubleTab& tab_vitesse=modif_par_porosite_si_flag(vitesse_2,vitesse_face_,marq,porosite_face);
581
582 // either transporte=phi*transporte_ and vitesse=vitesse_
583 // or transporte=transporte_ and vitesse=phi*vitesse_
584 // depending on whether transport uses phi*u or u.
585 const DoubleTab& transporte=modif_par_porosite_si_flag(transporte_2,transporte_,!marq,porosite_face);
586
587 DoubleTrav Kij(nb_elem_tot,nb_faces_elem,nb_faces_elem);
588 //Initialize the flux_bords_ array for pressure drop computation
589 flux_bords_.resize(domaine_VEF.nb_faces_bord(),nb_comp);
590 calculer_flux_bords(Kij,tab_vitesse,transporte);
591
592 if (!old_)
593 {
594 calculer_coefficients_operateur_centre(Kij,nb_comp,tab_vitesse);
595 if (is_compressible_) ajouter_partie_compressible(transporte,resu,tab_vitesse);
596
597 ajouter_operateur_centre(Kij,transporte,resu);
598
599 ajouter_diffusion(Kij,transporte,resu);
600 ajouter_antidiffusion(Kij,transporte,resu);
602
603 }
604 else
605 {
606 assert(old_==1);
607 ajouter_old(transporte,resu,tab_vitesse);
608 }
609
610 //To account for Neumann outflow boundary conditions
611 IntList NeumannFaces;
612 DoubleTabs ValeursNeumannFaces;
613 reinit_conv_pour_Cl(transporte,NeumannFaces,ValeursNeumannFaces,tab_vitesse,resu);
614
615 resu+=sauv;
616
617 if (test_) test(transporte,resu,tab_vitesse);
618 modifier_flux(*this);
619 return resu;
620}
621
622//Porous correction: add the T*div(u) contribution
623//Transported variable: T
624//Transporting variable: u
625//NOTE: the Kij array MUST NOT be used because by
626//construction sum_{j} Kij = 0, which enforces a zero-divergence
627//velocity per element — problematic in compressible flows
628DoubleTab& Op_Conv_EF_VEF_P1NC_Stab::ajouter_partie_compressible(const DoubleTab& transporte,
629 DoubleTab& resu, const DoubleTab& vitesse_2) const
630{
631 const Domaine_VEF& domaine_VEF=le_dom_vef.valeur();
632 const IntTab& elem_faces=domaine_VEF.elem_faces();
633 const IntTab& face_voisins = domaine_VEF.face_voisins();
634 const DoubleTab& face_normales=domaine_VEF.face_normales();
635 const int nb_elem_tot=domaine_VEF.nb_elem_tot();
636 const int nb_faces_elem=elem_faces.line_size();
637
638 //To account for porosity
639 const int marq = phi_u_transportant(equation());
640 const DoubleVect& porosite_elem = equation().milieu().porosite_elem();
641 const DoubleVect& porosite_face = equation().milieu().porosite_face();
642
643 DoubleTab tab_vitesse(vitesse_->valeurs());
644 DoubleTabView tab_vitesse_v = tab_vitesse.view_rw();
645 CDoubleArrView porosite_face_v = porosite_face.view_ro();
646
647 const int vit_size0 = tab_vitesse.dimension(0);
648 const int vit_size1 = tab_vitesse.dimension(1);
649 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
650 Kokkos::MDRangePolicy<Kokkos::Rank<2>>({0, 0}, {vit_size0, vit_size1}), KOKKOS_LAMBDA(
651 const int i, const int j)
652 {
653 tab_vitesse_v(i,j)*=porosite_face_v(i);
654 });
655 end_gpu_timer(__KERNEL_NAME__);
656 const int nb_comp=transporte.line_size();
657 int nb_dim = dimension;
658 int vol_etendus = volumes_etendus_;
659
660 // read only
661 CDoubleTabView face_normales_v = face_normales.view_ro();
662 CIntTabView face_voisins_v = face_voisins.view_ro();
663 CIntTabView elem_faces_v = elem_faces.view_ro();
664 CDoubleArrView transporteV = static_cast<const DoubleVect&>(transporte).view_ro();
665 CIntArrView elem_nb_faces_dirichlet_v = elem_nb_faces_dirichlet_.view_ro();
666 CDoubleArrView porosite_elem_v = porosite_elem.view_ro();
667 // Write only
668 DoubleArrView resuV = static_cast<DoubleVect&>(resu).view_rw();
669
670 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
671 Kokkos::RangePolicy<>(0, nb_elem_tot), KOKKOS_LAMBDA(
672 const int elem)
673 {
674 //Element type: the number of Dirichlet faces
675 //it contains
676 int type_elem=elem_nb_faces_dirichlet_v(elem);
677 double coeff;
678 if (!vol_etendus)
679 coeff = (nb_dim==2) ? formule_Id_2D(type_elem) : formule_Id_3D(type_elem);
680 else
681 coeff = (nb_dim==2) ? formule_2D(type_elem) : formule_3D(type_elem);
682
683 int facei, facei_loc, dim;
684
685 //Compute the divergence per element
686 double div=0.;
687 for (facei_loc=0; facei_loc<nb_faces_elem; facei_loc++)
688 {
689 facei=elem_faces_v(elem,facei_loc);
690 double signe=(face_voisins_v(facei,0)==elem)? 1.:-1.;
691
692 for (dim=0; dim<nb_dim; dim++)
693 div+=signe*face_normales_v(facei,dim)*tab_vitesse_v(facei,dim);
694 }
695 div*=coeff;
696 if (!marq) div/=porosite_elem_v(elem);
697
698 //Compute the compressible part
699 for (facei_loc=0; facei_loc<nb_faces_elem; facei_loc++)
700 {
701 facei=elem_faces_v(elem,facei_loc);
702 for (dim=0; dim<nb_comp; dim++)
703 {
704 int ligne=facei*nb_comp+dim;
705 double delta = div*transporteV[ligne];
706 Kokkos::atomic_sub(&resuV[ligne], delta);
707 }
708 }
709 });
710 end_gpu_timer(__KERNEL_NAME__);
711
712 return resu;
713}
714
715void Op_Conv_EF_VEF_P1NC_Stab::calculer_flux_bords(const DoubleTab& Kij, const DoubleTab& tab_vitesse, const DoubleTab& transporte) const
716{
717 const Domaine_VEF& domaine_VEF=le_dom_vef.valeur();
718 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
719 const int nb_bord = domaine_Cl_VEF.nb_cond_lim();
720 const int nb_comp=transporte.line_size();
721
722 for (int n_bord=0; n_bord<nb_bord; n_bord++)
723 {
724 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
725 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
726 int num1 = 0;
727 int num2 = le_bord.nb_faces();//only loop over real faces here
728
729 if ( sub_type(Dirichlet_homogene,la_cl.valeur()) )
730 {
731 //Do not compute flux at Dirichlet_homogene boundaries
732 }
733 else if ( sub_type(Neumann,la_cl.valeur())
734 || sub_type(Neumann_val_ext,la_cl.valeur())
735 || sub_type(Neumann_homogene,la_cl.valeur())
736 || sub_type(Symetrie,la_cl.valeur())
737 || sub_type(Echange_impose_base,la_cl.valeur())
738 || sub_type(Dirichlet,la_cl.valeur())
739 || sub_type(Periodique,la_cl.valeur()) )
740 {
741 CDoubleTabView face_normales = domaine_VEF.face_normales().view_ro();
742 CIntArrView num_face = le_bord.num_face().view_ro();
743 CDoubleTabView vitesse = tab_vitesse.view_ro();
744 CDoubleArrView transporteV = static_cast<const DoubleVect&>(transporte).view_ro();
745 DoubleTabView flux_bords = flux_bords_.view_wo();
746 const int nb_dim=Objet_U::dimension;
747 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
748 Kokkos::RangePolicy<>(num1, num2), KOKKOS_LAMBDA(
749 const int ind_face)
750 {
751 int facei = num_face(ind_face);
752 double psc=0.;
753 for (int dim=0; dim<nb_dim; dim++) //tempo fix to compile
754 psc-=vitesse(facei,dim)*face_normales(facei,dim);
755
756 for (int dim=0; dim<nb_comp; dim++)
757 flux_bords(facei,dim)=psc*transporteV[facei*nb_comp+dim];
758 });
759 end_gpu_timer(__KERNEL_NAME__);
760
761 }//end of if on "Neumann", "Neumann_homogene", "Symetrie", "Echange_impose_base"
762 else
763 {
764 Cerr << "Error Op_Conv_EF_VEF_P1NC_Stab::calculer_flux_bords()" << finl;
765 Cerr << "Boundary condition " << la_cl.que_suis_je() << " not implemented." << finl;
766 Cerr << "Exiting." << finl;
768 }//end of else on other boundary conditions
769 }
770}
771
772DoubleTab&
773Op_Conv_EF_VEF_P1NC_Stab::ajouter_operateur_centre(const DoubleTab& tab_Kij, const DoubleTab& transporte, DoubleTab& resu) const
774{
775 const Domaine_VEF& domaine_VEF=le_dom_vef.valeur();
776 const int nb_elem_tot=domaine_VEF.nb_elem_tot();
777 const int nb_faces_elem=domaine_VEF.elem_faces().line_size();
778 const int nb_comp=transporte.line_size();
779
780 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
781 CDoubleArrView transporteV = static_cast<const DoubleVect&>(transporte).view_ro();
782 CDoubleTabView3 Kij = tab_Kij.view_ro<3>();
783 DoubleArrView resuV = static_cast<DoubleVect&>(resu).view_rw();
784 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
785 range_2D({0,0}, {nb_elem_tot,nb_faces_elem}), KOKKOS_LAMBDA(
786 const int elem, const int facei_loc)
787 {
788 int facei = elem_faces(elem, facei_loc);
789 for (int facej_loc = facei_loc + 1; facej_loc < nb_faces_elem; facej_loc++)
790 {
791 int facej = elem_faces(elem, facej_loc);
792 double kij = Kij(elem, facei_loc, facej_loc);
793 double kji = Kij(elem, facej_loc, facei_loc);
794
795 for (int dim = 0; dim < nb_comp; dim++)
796 {
797 int ligne = facei * nb_comp + dim;
798 int colonne = facej * nb_comp + dim;
799 double delta = transporteV[colonne] - transporteV[ligne];
800 Kokkos::atomic_add(&resuV[ligne], kij * delta);
801 Kokkos::atomic_sub(&resuV[colonne], kji * delta);
802 }
803 }
804 });
805 end_gpu_timer(__KERNEL_NAME__);
806 return resu;
807}
808
809DoubleTab&
810Op_Conv_EF_VEF_P1NC_Stab::ajouter_diffusion(const DoubleTab& tab_Kij, const DoubleTab& transporte, DoubleTab& resu) const
811{
812 const Domaine_VEF& domaine_VEF=le_dom_vef.valeur();
813 const int nb_elem_tot=domaine_VEF.nb_elem_tot();
814 const int nb_faces_elem=domaine_VEF.elem_faces().line_size();
815 const int nb_comp=transporte.line_size();
816
817 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
818 CDoubleArrView transporteV = static_cast<const DoubleVect&>(transporte).view_ro();
819 CDoubleTabView3 Kij = tab_Kij.view_ro<3>();
820 CDoubleArrView alpha_tab = alpha_tab_.view_ro();
821 DoubleArrView resuV = static_cast<DoubleVect&>(resu).view_rw();
822 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
823 range_2D({0,0}, {nb_elem_tot,nb_faces_elem}), KOKKOS_LAMBDA(
824 const int elem, const int facei_loc)
825 {
826 int facei=elem_faces(elem,facei_loc);
827 for (int facej_loc=facei_loc+1; facej_loc<nb_faces_elem; facej_loc++)
828 {
829 int facej=elem_faces(elem,facej_loc);
830 double dij=Dij(elem,facei_loc,facej_loc,Kij);
831 double coeffij=alpha_tab[facei]*dij;
832 double coeffji=alpha_tab[facej]*dij;
833
834 for (int dim=0; dim<nb_comp; dim++)
835 {
836 int ligne=facei*nb_comp+dim;
837 int colonne=facej*nb_comp+dim;
838 double delta=transporteV[colonne]-transporteV[ligne];
839
840 //NOTE ON SIGN: here we code +div(uT)
841 //NOTE: exploiting the symmetry of the operator
842 Kokkos::atomic_add(&resuV[ligne], coeffij*delta);
843 Kokkos::atomic_sub(&resuV[colonne], coeffji*delta);
844 }
845 }
846 });
847 end_gpu_timer(__KERNEL_NAME__);
848 return resu;
849}
850
851DoubleTab&
852Op_Conv_EF_VEF_P1NC_Stab::ajouter_antidiffusion(const DoubleTab& tab_Kij, const DoubleTab& transporte, DoubleTab& resu) const
853{
854 const Domaine_VEF& domaine_VEF=le_dom_vef.valeur();
855 const int nb_elem_tot=domaine_VEF.nb_elem_tot();
856 const int nb_faces_elem=domaine_VEF.elem_faces().line_size();
857 const int nb_comp=transporte.line_size();
858 if (nb_comp>3) Process::exit("EF_stab is not coded for more than 3 components for array transporte.");
859
860 //For the limiter
861
862 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
863 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
864 CIntTabView num_fac_loc = domaine_VEF.get_num_fac_loc().view_ro();
865 CDoubleArrView transporteV = static_cast<const DoubleVect&>(transporte).view_ro();
866 CDoubleArrView alpha_tab = alpha_tab_.view_ro();
867 CDoubleArrView beta = beta_.view_ro();
868 CDoubleTabView3 Kij = tab_Kij.view_ro<3>();
869 DoubleArrView resuV = static_cast<DoubleVect&>(resu).view_rw();
870 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
871 range_2D({0,0}, {nb_elem_tot,nb_faces_elem}), KOKKOS_LAMBDA(
872 const int elem, const int facei_loc)
873 {
874 double P_plus[3],P_moins[3],Q_plus[3],Q_moins[3];
875 int facei = elem_faces(elem, facei_loc);
876 calculer_senseur(Kij, transporteV, nb_comp, facei, elem_faces, face_voisins, num_fac_loc, P_plus, P_moins,
877 Q_plus, Q_moins);
878
879 for (int facej_loc = 0; facej_loc < nb_faces_elem; facej_loc++)
880 if (facej_loc != facei_loc)
881 {
882 int facej = elem_faces(elem, facej_loc);
883
884 double kij = Kij(elem, facei_loc, facej_loc);
885 double kji = Kij(elem, facej_loc, facei_loc);
886 double dij = Dij(elem, facei_loc, facej_loc, Kij);
887 double lij = kij + dij;
888 double lji = kji + dij;
889 assert(lij >= 0);
890 assert(lji >= 0);
891
892 if (lij <= lji) //facei is upstream
893 {
894 int face_amont = facei;
895 int face_aval = facej;
896
897 //If lij==lji, we iterate twice in the loop
898 //hence the coefficient 1/2
899 double coeff = 1. * (lij < lji) + 0.5 * (lij == lji);
900 assert(coeff == 1. || coeff == 0.5);
901
902 // Registers for performance:
903 double alpha_beta_amont = alpha_tab[face_amont] * beta[face_amont];
904 double alpha_beta_aval = alpha_tab[face_aval] * beta[face_aval];
905
906 for (int dim = 0; dim < nb_comp; dim++)
907 {
908 int ligne = face_aval * nb_comp + dim;
909 int colonne = face_amont * nb_comp + dim;
910
911 double delta = transporteV[colonne] - transporteV[ligne];
912
913 //Slope limiter
914 double R;
915 if (delta >= 0.) R = (Kokkos::fabs(P_plus[dim]) < DMINFLOAT) ? 0. : Q_plus[dim] / P_plus[dim];
916 else R = (Kokkos::fabs(P_moins[dim]) < DMINFLOAT) ? 0. : Q_moins[dim] / P_moins[dim];
917
918 double limit = limiteur(R);
919 //double daij = minimum(limit * dij, lji);
920 double daij = Kokkos::fmin(limit * dij, lji);
921 assert(daij >= 0);
922 assert(daij <= lji);
923
924 double coeffij = alpha_beta_amont * daij * coeff * delta;
925 double coeffji = alpha_beta_aval * daij * coeff * delta;
926
927 //Compute resu
928 Kokkos::atomic_add(&resuV[colonne], + coeffij);
929 Kokkos::atomic_add(&resuV[ligne], - coeffji);
930 }
931 }
932 }
933 });
934 end_gpu_timer(__KERNEL_NAME__);
935 return resu;
936}
937
938//WARNING: assumes that the parameters P_plus, P_moins, Q_plus, Q_moins are zero on entry
939KOKKOS_INLINE_FUNCTION void
940Op_Conv_EF_VEF_P1NC_Stab::calculer_senseur(CDoubleTabView3 Kij, CDoubleArrView transporteV,
941 const int nb_comp, const int face_i,
942 CIntTabView elem_faces, CIntTabView face_voisins, CIntTabView num_fac_loc,
943 double* P_plus, double* P_moins,
944 double* Q_plus, double* Q_moins) const
945{
946 for (int i = 0; i < nb_comp; i++)
947 {
948 P_plus[i] = 0., P_moins[i] = 0.;
949 Q_plus[i] = 0., Q_moins[i] = 0.;
950 }
951 const int nb_faces_elem=(int)elem_faces.extent(1);
952 for (int elem_voisin=0; elem_voisin<2; elem_voisin++)
953 {
954 int elem = face_voisins(face_i,elem_voisin);
955 if (elem!=-1)
956 {
957 int face_i_loc = num_fac_loc(face_i,elem_voisin);
958 //Work on the faces of "elem"
959 for (int face_k_loc=0; face_k_loc<nb_faces_elem; face_k_loc++)
960 {
961 int face_k=elem_faces(elem,face_k_loc);
962 double kik=Kij(elem,face_i_loc,face_k_loc);
963 //
964 //Compute the intermediate variables
965 //
966 for (int dim=0; dim<nb_comp; dim++)
967 {
968 double deltaki = transporteV[face_k*nb_comp+dim]-transporteV[face_i*nb_comp+dim];
969 //Compute P_plus and P_moins
970 //Compute Q_plus and Q_moins
971 /* Initial coding:
972 P_plus(dim)+=minimum(0.,kik)*minimum(0.,deltaki);
973 P_moins(dim)+=minimum(0.,kik)*maximum(0.,deltaki);
974 Q_plus(dim)+=maximum(0.,kik)*maximum(0.,deltaki);
975 Q_moins(dim)+=maximum(0.,kik)*minimum(0.,deltaki);
976 */
977 // Optimized coding:
978 double tmp = kik*deltaki;
979 if (kik>0)
980 {
981 if (tmp>0) Q_plus[dim]+=tmp;
982 else Q_moins[dim]+=tmp;
983 }
984 else
985 {
986 if (tmp>0) P_plus[dim]+=tmp;
987 else P_moins[dim]+=tmp;
988 }
989 }//end of for loop over "dim"
990 //
991 //End of intermediate variable computation
992 //
993 }//end of for loop over "face_k_loc"
994 }//end of if on "elem!=-1"
995 }//end of for loop over "elem_voisin"
996}
997
998//WARNING: assumes that the parameters P_plus, P_moins, Q_plus, Q_moins are zero on entry
999inline void
1000Op_Conv_EF_VEF_P1NC_Stab::calculer_senseur(const DoubleTab& Kij, const DoubleVect& transporteV,
1001 const int nb_comp, const int face_i,
1002 const IntTab& elem_faces, const IntTab& face_voisins, const IntTab& num_fac_loc,
1003 ArrOfDouble& P_plus, ArrOfDouble& P_moins,
1004 ArrOfDouble& Q_plus, ArrOfDouble& Q_moins) const
1005{
1006 assert(P_plus.size_array()==nb_comp);
1007 assert(Q_plus.size_array()==nb_comp);
1008 assert(P_moins.size_array()==nb_comp);
1009 assert(Q_moins.size_array()==nb_comp);
1010 const int nb_faces_elem=elem_faces.dimension(1);
1011 for (int elem_voisin=0; elem_voisin<2; elem_voisin++)
1012 {
1013 int elem = face_voisins(face_i,elem_voisin);
1014 if (elem!=-1)
1015 {
1016 int face_i_loc = num_fac_loc(face_i,elem_voisin);
1017 assert(face_i_loc>=0);
1018 assert(face_i_loc<nb_faces_elem);
1019 //Work on the faces of "elem"
1020 for (int face_k_loc=0; face_k_loc<nb_faces_elem; face_k_loc++)
1021 {
1022 int face_k=elem_faces(elem,face_k_loc);
1023 double kik=Kij(elem,face_i_loc,face_k_loc);
1024 //
1025 //Compute the intermediate variables
1026 //
1027 for (int dim=0; dim<nb_comp; dim++)
1028 {
1029 double deltaki = transporteV[face_k*nb_comp+dim]-transporteV[face_i*nb_comp+dim];
1030 //Compute P_plus and P_moins
1031 //Compute Q_plus and Q_moins
1032 /* Initial coding:
1033 P_plus(dim)+=minimum(0.,kik)*minimum(0.,deltaki);
1034 P_moins(dim)+=minimum(0.,kik)*maximum(0.,deltaki);
1035 Q_plus(dim)+=maximum(0.,kik)*maximum(0.,deltaki);
1036 Q_moins(dim)+=maximum(0.,kik)*minimum(0.,deltaki);
1037 */
1038 // Optimized coding:
1039 double tmp = kik*deltaki;
1040 if (kik>0)
1041 {
1042 if (tmp>0) Q_plus[dim]+=tmp;
1043 else Q_moins[dim]+=tmp;
1044 }
1045 else
1046 {
1047 if (tmp>0) P_plus[dim]+=tmp;
1048 else P_moins[dim]+=tmp;
1049 }
1050 assert(P_plus[dim]>=0);
1051 assert(Q_plus[dim]>=0);
1052 assert(P_moins[dim]<=0);
1053 assert(Q_moins[dim]<=0);
1054 }//end of for loop over "dim"
1055 //
1056 //End of intermediate variable computation
1057 //
1058 }//end of for loop over "face_k_loc"
1059 }//end of if on "elem!=-1"
1060 }//end of for loop over "elem_voisin"
1061}
1062
1063void Op_Conv_EF_VEF_P1NC_Stab::test(const DoubleTab& transporte, const DoubleTab& resu, const DoubleTab& tab_vitesse) const
1064{
1065 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
1066 const IntTab& elem_faces = domaine_VEF.elem_faces();
1067 const int nb_faces_elem=elem_faces.dimension(1);
1068 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
1069
1070 DoubleTab Kij2(nb_elem_tot,nb_faces_elem, nb_faces_elem);
1071 Kij2=0.;
1072
1073 DoubleTab Kij_ancien(nb_elem_tot,nb_faces_elem, nb_faces_elem);
1074 Kij_ancien=0.;
1075
1076 test_difference_Kij(transporte,Kij2,Kij_ancien,tab_vitesse);
1077 test_difference_resu(Kij2,Kij_ancien,transporte,resu,tab_vitesse);
1078}
1079
1080void Op_Conv_EF_VEF_P1NC_Stab::test_difference_Kij(const DoubleTab& transporte, DoubleTab& Kij, DoubleTab& Kij_ancien, const DoubleTab& tab_vitesse ) const
1081{
1082 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
1083 const IntTab& elem_faces = domaine_VEF.elem_faces();
1084 const IntTab& face_voisins = domaine_VEF.face_voisins();
1085 const DoubleTab& face_normales=domaine_VEF.face_normales();
1086 const int nb_faces_elem=elem_faces.dimension(1);
1087 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
1088 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
1089
1090 const int nb_comp = (transporte.nb_dim()!=1) ? transporte.dimension(1) : 1;
1091
1092 calculer_coefficients_operateur_centre(Kij,nb_comp,tab_vitesse);
1093
1094 //
1095 // Compute Kij_ancien:
1096 //
1097 for(int elem0=0; elem0<nb_elem_tot; elem0++)
1098 {
1099 int face_locj=0;
1100 for(int face_loci=0; face_loci<nb_faces_elem; face_loci++)
1101 {
1102 int face_i0=elem_faces(elem0,face_loci);
1103 double signei=1.0;
1104 if(face_voisins(face_i0,0)!=elem0)
1105 signei=-1.0;
1106 double psci=0;
1107 for(int comp=0; comp<dimension; comp++)
1108 psci+=tab_vitesse(face_i0,comp)*face_normales(face_i0,comp);
1109 psci*=signei;
1110 //Kij_ancien(elem,face_loci,face_loci)=0.;
1111 for(face_locj=face_loci+1; face_locj<nb_faces_elem; face_locj++)
1112 {
1113 int face_j0=elem_faces(elem0,face_locj);
1114 double signej=1.0;
1115 if(face_voisins(face_j0,0)!=elem0)
1116 signej=-1.0;
1117
1118 double pscj=0;
1119 //psci=0;
1120 for(int comp=0; comp<dimension; comp++)
1121 pscj+=tab_vitesse(face_j0,comp)*face_normales(face_j0,comp);
1122 pscj*=signej;
1123 Kij_ancien(elem0,face_loci,face_locj)=-1./nb_faces_elem*pscj;
1124 Kij_ancien(elem0,face_loci,face_loci)+=1./nb_faces_elem*pscj;
1125 Kij_ancien(elem0,face_locj,face_loci)=-1./nb_faces_elem*psci;
1126 Kij_ancien(elem0,face_locj,face_locj)+=1./nb_faces_elem*psci;
1127 }
1128 }
1129 }
1130 // Correction of Kij_ancien for Dirichlet!
1131 {
1132 int nb_bord=domaine_Cl_VEF.nb_cond_lim();
1133 double coeff=1./dimension;
1134 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1135 {
1136 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1137 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1138 int nb_faces_tot=le_bord.nb_faces_tot();
1139
1140 if ( (sub_type(Dirichlet,la_cl.valeur()))
1141 || (sub_type(Dirichlet_homogene,la_cl.valeur()))
1142 )
1143 {
1144 if ( volumes_etendus_ )
1145 {
1146 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
1147 {
1148 int face = le_bord.num_face(ind_face);
1149 int elem=face_voisins(face,0);
1150 assert(elem!=-1);
1151 int face_loc_j;
1152 int face_j=-1;
1153 for (face_loc_j=0; (face_loc_j<nb_faces_elem && face_j!=face); face_loc_j++)
1154 {
1155 face_j=elem_faces(elem,face_loc_j);
1156 }
1157 face_loc_j--;
1158 assert(face_loc_j>=0);
1159 assert(face_loc_j<nb_faces_elem);
1160 assert(elem_faces(elem,face_loc_j)==face);
1161 const double kjj=Kij_ancien(elem,face_loc_j,face_loc_j);
1162 for (int face_loc_i=0; face_loc_i<nb_faces_elem; face_loc_i++)
1163 {
1164 int face_i=elem_faces(elem,face_loc_i);
1165 if(face_i!=face)
1166 {
1167 double& kii=Kij_ancien(elem,face_loc_i,face_loc_i);
1168 const double kji=Kij_ancien(elem,face_loc_j,face_loc_i);
1169 kii+=coeff*kji;
1170 double& kij=Kij_ancien(elem,face_loc_i,face_loc_j);
1171 kij+=coeff*kjj;
1172 for (int face_loc_k=(face_loc_i+1); face_loc_k<nb_faces_elem; face_loc_k++)
1173 {
1174 int face_k=elem_faces(elem,face_loc_k);
1175 if(face_k!=face)
1176 {
1177 double& kik=Kij_ancien(elem,face_loc_i,face_loc_k);
1178 const double kjk=Kij_ancien(elem,face_loc_j,face_loc_k);
1179 double& kki=Kij_ancien(elem,face_loc_k,face_loc_i);
1180 kik+=coeff*kjk;
1181 kki+=coeff*kji;
1182 }
1183 }
1184 }
1185 }
1186 {
1187 for (int face_loc_i=0; face_loc_i<nb_faces_elem; face_loc_i++)
1188 Kij_ancien(elem,face_loc_j,face_loc_i)=0;
1189 }
1190 {
1191 for (int face_loc_i=0; face_loc_i<nb_faces_elem; face_loc_i++)
1192 {
1193 double sum=0.;
1194 for (int face_loc_k=0; face_loc_k<nb_faces_elem; face_loc_k++)
1195 {
1196 sum+=Kij_ancien(elem,face_loc_i,face_loc_k);
1197 }
1198 //Cerr << "somme apres : " << sum << finl;
1199 Kij_ancien(elem,face_loc_i,face_loc_i)-=sum;//car div(u)=0!
1200 }
1201 }
1202 }// for face
1203
1204 }//end of if on "volumes_etendus_"
1205
1206 }// sub_type Dirichlet
1207 }
1208 }
1209
1210 Kij-=Kij_ancien;
1211 const double max_kij = local_max_abs_vect(Kij);
1212 if (max_kij > 1.e-15)
1213 {
1214 Cerr << "Error in Kij computation: " << max_kij << finl;
1215 Cerr << "Exiting" << finl;
1216 Process::exit();
1217 }
1218
1219 Kij+=Kij_ancien;
1220}
1221
1222void Op_Conv_EF_VEF_P1NC_Stab::test_difference_resu(const DoubleTab& Kij, const DoubleTab& Kij_ancien,
1223 const DoubleTab& transporte,const DoubleTab& resu, const DoubleTab& tab_vitesse) const
1224{
1225 DoubleTab resu1(resu);
1226 resu1=0;
1227
1228 if (is_compressible_) ajouter_partie_compressible(transporte,resu1,tab_vitesse);
1229 ajouter_operateur_centre(Kij,transporte,resu1);
1230 ajouter_diffusion(Kij,transporte,resu1);
1231 ajouter_antidiffusion(Kij,transporte,resu1);
1233
1234 DoubleTab resu2(resu);
1235 resu2=0;
1236
1237 //
1238 // Compute resu2
1239 //
1240
1241 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
1242
1243 const IntTab& elem_faces = domaine_VEF.elem_faces();
1244 const IntTab& face_voisins = domaine_VEF.face_voisins();
1245 const int nb_faces_elem=elem_faces.line_size();
1246 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
1247 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
1248 const int nb_comp=resu.line_size();
1249 const int nb_faces0 = transporte.dimension(0);
1250
1251 ArrOfDouble pplusi(nb_comp);
1252 ArrOfDouble qplusi(nb_comp);
1253 ArrOfDouble pmoinsi(nb_comp);
1254 ArrOfDouble qmoinsi(nb_comp);
1255
1256 for(int elem=0; elem<nb_elem_tot; elem++)
1257 {
1258 int face_locj=0;
1259
1260 for(int face_loci=0; face_loci<nb_faces_elem; face_loci++)
1261 {
1262 int face_i0=elem_faces(elem,face_loci);
1263 for(int comp0=0; comp0<nb_comp; comp0++)
1264 resu2(face_i0,comp0)+=Kij_ancien(elem,face_loci,face_loci)*transporte(face_i0,comp0);
1265
1266 pplusi=0.;
1267 qplusi=0.;
1268 pmoinsi=0.;
1269 qmoinsi=0.;
1270
1271 int elem1=face_voisins(face_i0,0), elem2=face_voisins(face_i0,1);
1272 int face_loc_i=0, face_loc_j=0;
1273 double dT,min_dT,max_dT, K,min_K,max_K;
1274
1275 //
1276 // in elem1:
1277 //
1278 while((face_loc_i<nb_faces_elem)&&(elem_faces(elem1,face_loc_i)!=face_i0))
1279 face_loc_i++;
1280 if(face_loc_i==nb_faces_elem)
1281 {
1282 //Periodique!!
1283 assert(elem2!=-1);
1284 face_loc_i=0;
1285 while( (face_loc_i<nb_faces_elem) &&
1286 (face_voisins(elem_faces(elem1,face_loc_i),0)!=elem2) &&
1287 (face_voisins(elem_faces(elem1,face_loc_i),1)!=elem2) )
1288 face_loc_i++;
1289 }
1290
1291 assert(face_loc_i<nb_faces_elem);
1292 for(face_loc_j=0; face_loc_j<nb_faces_elem; face_loc_j++)
1293 {
1294 int face_j=elem_faces(elem1,face_loc_j);
1295 if(face_j!=face_i0)
1296 {
1297 K=Kij_ancien(elem1,face_loc_i,face_loc_j);
1298
1299 if(K>0.)
1300 {
1301 max_K=K ;
1302 min_K=0.;
1303 }
1304 else
1305 {
1306 max_K=0.;
1307 min_K=K ;
1308 }
1309
1310 for(int comp0=0; comp0<nb_comp; comp0++)
1311 {
1312 dT =transporte(face_j,comp0);
1313 dT-=transporte(face_i0,comp0);
1314
1315 if(dT>0.)
1316 {
1317 max_dT=dT ;
1318 min_dT=0 ;
1319 }
1320 else
1321 {
1322 max_dT=0. ;
1323 min_dT=dT ;
1324 }
1325
1326 pplusi[comp0] +=min_K*min_dT;
1327 pmoinsi[comp0]+=min_K*max_dT;
1328 qplusi[comp0] +=max_K*max_dT;
1329 qmoinsi[comp0]+=max_K*min_dT;
1330 }
1331 }
1332 }
1333
1334 //
1335 // in elem2:
1336 //
1337
1338 if(elem2!=-1)
1339 {
1340 face_loc_i=0;
1341 while((face_loc_i<nb_faces_elem)&&(elem_faces(elem2,face_loc_i)!=face_i0))
1342 face_loc_i++;
1343 if(face_loc_i==nb_faces_elem)
1344 {
1345 //Periodique!!
1346 face_loc_i=0;
1347 while( (face_loc_i<nb_faces_elem) &&
1348 (face_voisins(elem_faces(elem2,face_loc_i),0)!=elem1) &&
1349 (face_voisins(elem_faces(elem2,face_loc_i),1)!=elem1) )
1350 face_loc_i++;
1351 }
1352 assert(face_loc_i<nb_faces_elem);
1353 for(face_loc_j=0; face_loc_j<nb_faces_elem; face_loc_j++)
1354 {
1355 int face_j=elem_faces(elem2,face_loc_j);
1356 if(face_j!=face_i0)
1357 {
1358 K=Kij_ancien(elem2,face_loc_i,face_loc_j);
1359
1360 if(K>0.)
1361 {
1362 max_K=K ;
1363 min_K=0.;
1364 }
1365 else
1366 {
1367 max_K=0.;
1368 min_K=K ;
1369 }
1370
1371 for(int comp0=0; comp0<nb_comp; comp0++)
1372 {
1373 dT =transporte(face_j,comp0);
1374 dT-=transporte(face_i0,comp0);
1375
1376 if(dT>0.)
1377 {
1378 max_dT=dT ;
1379 min_dT=0 ;
1380 }
1381 else
1382 {
1383 max_dT=0. ;
1384 min_dT=dT ;
1385 }
1386
1387 pplusi[comp0] +=min_K*min_dT;
1388 pmoinsi[comp0]+=min_K*max_dT;
1389 qplusi[comp0] +=max_K*max_dT;
1390 qmoinsi[comp0]+=max_K*min_dT;
1391 }
1392 }
1393 }
1394 }
1395
1396 for(face_locj=0; face_locj<nb_faces_elem; face_locj++)
1397 if(face_locj!=face_loci)
1398 {
1399 int face_j0=elem_faces(elem,face_locj);
1400 const double kij=Kij_ancien(elem,face_loci,face_locj);
1401 const double kji=Kij_ancien(elem,face_locj,face_loci);
1402 double dij=Dij(elem,face_loci,face_locj,Kij_ancien);
1403 double lji=kji+dij;
1404 double lij=kij+dij;
1405 assert(lij>=0);
1406 assert(lji>=0);
1407
1408 for(int comp0=0; comp0<nb_comp; comp0++)
1409 {
1410 const double Ti=transporte(face_i0,comp0);
1411 const double Tj=transporte(face_j0,comp0);
1412 double deltaij=Ti-Tj;
1413 double Fij=0;
1414 if(lij<=lji)
1415 {
1416 double coef=1;
1417 if (lij==lji) coef=.5;
1418 if(deltaij)
1419 {
1420 if(Ti >= Tj)
1421 {
1422 if(pplusi[comp0])
1423 {
1424 double R=qplusi[comp0]/pplusi[comp0];
1425 Fij=minimum(limiteur(R)*dij,lji);
1426 }
1427 }
1428 else if(pmoinsi[comp0])
1429 {
1430 double R=qmoinsi[comp0]/pmoinsi[comp0];
1431 Fij=minimum(limiteur(R)*dij,lji);
1432 }
1433
1434 assert(Fij*dij>=0);
1435 Fij-=dij;
1436 Fij*=deltaij;
1437 }
1438 resu2(face_i0,comp0)+=coef*(kij*Tj+Fij);
1439 resu2(face_j0,comp0)+=coef*(kji*Ti-Fij);
1440 }
1441 }
1442 }
1443 }
1444 }
1445
1446 // For periodicity
1447
1448 int nb_bord=domaine_Cl_VEF.nb_cond_lim();
1449 int face;
1450 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1451 {
1452 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1453 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1454 int num1 = le_bord.num_premiere_face();
1455 int nb_faces_b=le_bord.nb_faces();
1456 int num2 = num1 + nb_faces_b;
1457 if (sub_type(Periodique,la_cl.valeur()))
1458 {
1459 const Periodique& la_cl_perio = ref_cast(Periodique,la_cl.valeur());
1460 int face_associee;
1461 IntVect fait(nb_faces_b);
1462 fait = 0;
1463
1464 for (face=num1; face<num2; face++)
1465 {
1466 if (fait(face-num1) == 0)
1467 {
1468 fait(face-num1) = 1;
1469 face_associee=la_cl_perio.face_associee(face-num1);
1470 fait(face_associee) = 1;
1471 for (int comp=0; comp<nb_comp; comp++)
1472 resu2(face_associee+num1, comp)=(resu2(face,comp)+=resu2(face_associee+num1,comp));
1473 }// if fait
1474 }// for face
1475 }// sub_type Perio
1476 }
1477
1478 resu1-=resu2;
1479
1480 //For Dirichlet faces, our algorithm computes no
1481 //value on those faces since they are overwritten
1482 //by the mass matrix anyway. This is not the case with the old algorithm,
1483 //hence the modification here to avoid seeing only the errors
1484 //made on Dirichlet boundaries, which have no significance
1485 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1486 {
1487 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1488 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1489 int num1 = le_bord.num_premiere_face();
1490 int nb_faces=le_bord.nb_faces();
1491 int num2 = num1 + nb_faces;
1492
1493 if (sub_type(Dirichlet,la_cl.valeur()) || sub_type(Dirichlet_homogene,la_cl.valeur()))
1494 {
1495 for (face=num1; face<num2; face++)
1496 for (int dim=0; dim<nb_comp; dim++)
1497 resu1(face,dim)=0;
1498 }//end of if on Dirichlet
1499 }//end of for on "n_bord"
1500
1501 const double max_abs_resu1 = local_max_abs_vect(resu1);
1502 Journal() << "local_max_abs_vect(resu1) = " << max_abs_resu1
1503 << " " << equation().schema_temps().temps_courant() << finl;
1504
1505 if (max_abs_resu1 > 1.e-15)
1506 {
1507 Cerr << "Error in resu computation: " << max_abs_resu1 << finl;
1508 Cerr << "Displaying boundary faces" << finl;
1509
1510 /**************************************************/
1511 Cerr << "Displaying boundary faces." << finl;
1512
1513 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1514 {
1515 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1516 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1517 int num1 = le_bord.num_premiere_face();
1518 int nb_faces=le_bord.nb_faces();
1519 int num2 = num1 + nb_faces;
1520
1521 if (sub_type(Periodique,la_cl.valeur()))
1522 {
1523 Cerr << "Periodic boundary: ";
1524 for (face=num1; face<num2; face++)
1525 {
1526 Cerr << face << ",";
1527 }// for face
1528 Cerr << finl;
1529 }// sub_type Perio
1530
1531 else if (sub_type(Dirichlet,la_cl.valeur()) || (sub_type(Dirichlet_homogene,la_cl.valeur())) )
1532 {
1533 Cerr << "Dirichlet boundary: ";
1534 for (face=num1; face<num2; face++)
1535 {
1536 Cerr << face << ",";
1537 }// for face
1538 Cerr << finl;
1539 }
1540
1541 }//end of for on "nbord"
1542 /**************************************************/
1543
1544 /**************************************************/
1545 Cerr << "Display of problematic faces: " << finl;
1546 if (nb_comp==1)
1547 {
1548 for (int face_i=0; face_i<nb_faces0; face_i++)
1549 {
1550 if (resu1(face_i)>1.e-15)
1551 Cerr << face_i << "(" << face_voisins(face_i,0) << ","
1552 << face_voisins(face_i,1) << ") ; ";
1553 }//end of for on "face_i"
1554 }
1555 else
1556 {
1557 for (int face_i=0; face_i<nb_faces0; face_i++)
1558 {
1559 Cerr << face_i << "(" << face_voisins(face_i,0) << ","
1560 << face_voisins(face_i,1) << ") ";
1561
1562 for (int dim=0; dim<nb_comp; dim++)
1563 {
1564 Cerr << ", resu1("
1565 << face_i << "," << dim << ")= "
1566 << resu1(face_i,dim);
1567 }
1568 Cerr << finl;
1569 }
1570 }
1571 Cerr << finl;
1572 /**************************************************/
1573
1574 /**************************************************/
1575 resu1+=resu2;
1576
1577 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1578 {
1579 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1580 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1581 int num1 = le_bord.num_premiere_face();
1582 int nb_faces=le_bord.nb_faces();
1583 int num2 = num1 + nb_faces;
1584
1585 if (sub_type(Periodique,la_cl.valeur()))
1586 {
1587 Cerr << "Display of resu values at the periodic boundary" << finl;
1588 for (face=num1; face<num2; face++)
1589 {
1590 Cerr << "resu1(" << face << ") : " << resu1(face) << finl;
1591 Cerr << "resu2(" << face << ") : " << resu2(face) << finl;
1592 }// for face
1593 Cerr << finl;
1594 }// sub_type Perio
1595
1596 }//end of for on "nbord"
1597
1598 /**************************************************/
1599
1600 static int count = 0;
1601 count++;
1602 if (count==2)
1603 {
1604 Cerr << "Exiting" << finl;
1605 Process::exit();
1606 }
1607 }
1608}
1609
1611{
1612 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
1613 const int nb_bord = domaine_Cl_VEF.nb_cond_lim();
1614 const int nb_comp = (resu.nb_dim()==1) ? 1 : resu.dimension(1);
1615
1616 //Boundary faces
1617 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1618 {
1619 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1620 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1621 int num1=0;
1622 int num2=le_bord.nb_faces();
1623
1624 if (sub_type(Periodique,la_cl.valeur()))
1625 {
1626 const Periodique& la_cl_perio = ref_cast(Periodique,la_cl.valeur());
1627 CIntArrView le_bord_num_face = static_cast<const ArrOfInt&>(le_bord.num_face()).view_ro();
1628 CIntArrView face_associee = static_cast<const ArrOfInt&>(la_cl_perio.face_associee()).view_ro();
1629 DoubleArrView resuV = static_cast<ArrOfDouble&>(resu).view_rw();
1630 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(num1, num2), KOKKOS_LAMBDA(const int ind_face)
1631 {
1632 int facei = le_bord_num_face(ind_face);
1633 int ind_face_associee = face_associee(ind_face);
1634 int faceiAss = le_bord_num_face(ind_face_associee);
1635
1636 if (facei<faceiAss)
1637 for (int dim=0; dim<nb_comp; dim++)
1638 {
1639 int ligne=facei*nb_comp+dim;
1640 int ligneAss=faceiAss*nb_comp+dim;
1641
1642 Kokkos::atomic_add(&resuV[ligneAss],resuV[ligne]);
1643 Kokkos::atomic_store(&resuV[ligne],resuV[ligneAss]);
1644 }
1645
1646 });//end of for on "face_i"
1647 end_gpu_timer(__KERNEL_NAME__);
1648 }//end of if on "Periodique"
1649
1650 }//end of for on "n_bord"
1651}
1652
1653void Op_Conv_EF_VEF_P1NC_Stab::ajouter_old(const DoubleTab& transporte, DoubleTab& resu, const DoubleTab& tab_vitesse ) const
1654{
1655 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
1656 // const Champ_P1NC& la_vitesse=ref_cast( Champ_P1NC, vitesse_.valeur());
1657 // const DoubleTab& vitesse=la_vitesse.valeurs();
1658
1659 const IntTab& elem_faces = domaine_VEF.elem_faces();
1660 const IntTab& face_voisins = domaine_VEF.face_voisins();
1661 const DoubleTab& face_normales=domaine_VEF.face_normales();
1662 const int nb_faces_elem=elem_faces.dimension(1);
1663 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
1664 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
1665
1666 assert(nb_faces_elem==(dimension+1));
1667
1668 int nb_comp=resu.line_size();
1669
1670 int face_i0, face_j0, elem0, comp0;
1671 DoubleTab Kij(nb_elem_tot,nb_faces_elem, nb_faces_elem);
1672 //
1673 // Compute Kij:
1674 //
1675 for(elem0=0; elem0<nb_elem_tot; elem0++)
1676 {
1677 int face_loci=0;
1678 int face_locj=0;
1679 for(; face_loci<nb_faces_elem; face_loci++)
1680 {
1681 face_i0=elem_faces(elem0,face_loci);
1682 double signei=1.0;
1683 if(face_voisins(face_i0,0)!=elem0)
1684 signei=-1.0;
1685 double psci=0;
1686 for(comp0=0; comp0<dimension; comp0++)
1687 psci+=tab_vitesse(face_i0,comp0)*face_normales(face_i0,comp0);
1688 psci*=signei;
1689 //Kij(elem,face_loci,face_loci)=0.;
1690 for(face_locj=face_loci+1; face_locj<nb_faces_elem; face_locj++)
1691 {
1692 face_j0=elem_faces(elem0,face_locj);
1693 double signej=1.0;
1694 if(face_voisins(face_j0,0)!=elem0)
1695 signej=-1.0;
1696
1697 double pscj=0;
1698 //psci=0;
1699 for(comp0=0; comp0<dimension; comp0++)
1700 pscj+=tab_vitesse(face_j0,comp0)*face_normales(face_j0,comp0);
1701 pscj*=signej;
1702 Kij(elem0,face_loci,face_locj)=-1./nb_faces_elem*pscj;
1703 Kij(elem0,face_loci,face_loci)+=1./nb_faces_elem*pscj;
1704 Kij(elem0,face_locj,face_loci)=-1./nb_faces_elem*psci;
1705 Kij(elem0,face_locj,face_locj)+=1./nb_faces_elem*psci;
1706 }
1707 }
1708 }
1709 //
1710 // Correction of Kij for Dirichlet!
1711 //
1712 {
1713 int nb_bord=domaine_Cl_VEF.nb_cond_lim();
1714 int face;
1715 double coeff=1./dimension;
1716 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1717 {
1718 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1719 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1720 int nb_faces_tot=le_bord.nb_faces_tot();
1721 if (( (sub_type(Dirichlet,la_cl.valeur())) || (sub_type(Dirichlet_homogene,la_cl.valeur())) )
1722 && ( volumes_etendus_))
1723 {
1724 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
1725 {
1726 face=le_bord.num_face(ind_face);
1727 int elem=face_voisins(face,0);
1728 assert(elem!=-1);
1729 int face_loc_j;
1730 int face_j=-1;
1731 for (face_loc_j=0; (face_loc_j<nb_faces_elem && face_j!=face); face_loc_j++)
1732 {
1733 face_j=elem_faces(elem,face_loc_j);
1734 }
1735 face_loc_j--;
1736 assert(face_loc_j>=0);
1737 assert(face_loc_j<nb_faces_elem);
1738 assert(elem_faces(elem,face_loc_j)==face);
1739 const double kjj=Kij(elem,face_loc_j,face_loc_j);
1740 for (int face_loc_i=0; face_loc_i<nb_faces_elem; face_loc_i++)
1741 {
1742 int face_i=elem_faces(elem,face_loc_i);
1743 if(face_i!=face)
1744 {
1745 double& kii=Kij(elem,face_loc_i,face_loc_i);
1746 const double kji=Kij(elem,face_loc_j,face_loc_i);
1747 kii+=coeff*kji;
1748 double& kij=Kij(elem,face_loc_i,face_loc_j);
1749 kij+=coeff*kjj;
1750 for (int face_loc_k=(face_loc_i+1); face_loc_k<nb_faces_elem; face_loc_k++)
1751 {
1752 int face_k=elem_faces(elem,face_loc_k);
1753 if(face_k!=face)
1754 {
1755 double& kik=Kij(elem,face_loc_i,face_loc_k);
1756 const double kjk=Kij(elem,face_loc_j,face_loc_k);
1757 double& kki=Kij(elem,face_loc_k,face_loc_i);
1758 kik+=coeff*kjk;
1759 kki+=coeff*kji;
1760 }
1761 }
1762 }
1763 }
1764 {
1765 for (int face_loc_i=0; face_loc_i<nb_faces_elem; face_loc_i++)
1766 Kij(elem,face_loc_j,face_loc_i)=0;
1767 }
1768 {
1769 for (int face_loc_i=0; face_loc_i<nb_faces_elem; face_loc_i++)
1770 {
1771 double sum=0.;
1772 for (int face_loc_k=0; face_loc_k<nb_faces_elem; face_loc_k++)
1773 {
1774 sum+=Kij(elem,face_loc_i,face_loc_k);
1775 }
1776 //Cerr << "somme apres : " << sum << finl;
1777 Kij(elem,face_loc_i,face_loc_i)-=sum;//car div(u)=0!
1778 }
1779 }
1780 }// for face
1781 }// sub_type Dirichlet
1782 }
1783 }
1784
1785 //
1786 // Compute resu
1787 //
1788
1789 ArrOfDouble pplusi(nb_comp);
1790 ArrOfDouble qplusi(nb_comp);
1791 ArrOfDouble pmoinsi(nb_comp);
1792 ArrOfDouble qmoinsi(nb_comp);
1793
1794 for(elem0=0; elem0<nb_elem_tot; elem0++)
1795 {
1796 int face_loci=0;
1797 int face_locj=0;
1798
1799 for(; face_loci<nb_faces_elem; face_loci++)
1800 {
1801 face_i0=elem_faces(elem0,face_loci);
1802
1803 for(comp0=0; comp0<nb_comp; comp0++)
1804 resu(face_i0,comp0)+=Kij(elem0,face_loci,face_loci)*transporte(face_i0,comp0);
1805
1806 pplusi=0., qplusi=0., pmoinsi=0., qmoinsi=0.;
1807
1808 int elem1=face_voisins(face_i0,0);
1809 int elem2=face_voisins(face_i0,1);
1810 int face_loc_i=0;
1811 int face_loc_j=0;
1812 double dT,min_dT,max_dT;
1813 double K,min_K,max_K;
1814
1815 //
1816 // in elem1:
1817 //
1818 while((face_loc_i<nb_faces_elem)&&(elem_faces(elem1,face_loc_i)!=face_i0))
1819 face_loc_i++;
1820 if(face_loc_i==nb_faces_elem)
1821 {
1822 //Periodique!!
1823 assert(elem2!=-1);
1824 face_loc_i=0;
1825 while( (face_loc_i<nb_faces_elem) &&
1826 (face_voisins(elem_faces(elem1,face_loc_i),0)!=elem2) &&
1827 (face_voisins(elem_faces(elem1,face_loc_i),1)!=elem2) )
1828 face_loc_i++;
1829 }
1830 assert(face_loc_i<nb_faces_elem);
1831 for(face_loc_j=0; face_loc_j<nb_faces_elem; face_loc_j++)
1832 {
1833 int face_j=elem_faces(elem1,face_loc_j);
1834 if(face_j!=face_i0)
1835 {
1836 K=Kij(elem1,face_loc_i,face_loc_j);
1837
1838 if(K>0.)
1839 {
1840 max_K=K ;
1841 min_K=0.;
1842 }
1843 else
1844 {
1845 max_K=0.;
1846 min_K=K ;
1847 }
1848
1849 for(comp0=0; comp0<nb_comp; comp0++)
1850 {
1851 dT =transporte(face_j,comp0);
1852 dT-=transporte(face_i0,comp0);
1853
1854 if(dT>0.)
1855 {
1856 max_dT=dT ;
1857 min_dT=0 ;
1858 }
1859 else
1860 {
1861 max_dT=0. ;
1862 min_dT=dT ;
1863 }
1864
1865 pplusi[comp0] +=min_K*min_dT;
1866 pmoinsi[comp0]+=min_K*max_dT;
1867 qplusi[comp0] +=max_K*max_dT;
1868 qmoinsi[comp0]+=max_K*min_dT;
1869 }
1870 }
1871 }
1872
1873 //
1874 // in elem2:
1875 //
1876
1877 if(elem2!=-1)
1878 {
1879 face_loc_i=0;
1880 while((face_loc_i<nb_faces_elem)&&(elem_faces(elem2,face_loc_i)!=face_i0))
1881 face_loc_i++;
1882 if(face_loc_i==nb_faces_elem)
1883 {
1884 //Periodique!!
1885 face_loc_i=0;
1886 while( (face_loc_i<nb_faces_elem) &&
1887 (face_voisins(elem_faces(elem2,face_loc_i),0)!=elem1) &&
1888 (face_voisins(elem_faces(elem2,face_loc_i),1)!=elem1) )
1889 face_loc_i++;
1890 }
1891 assert(face_loc_i<nb_faces_elem);
1892 for(face_loc_j=0; face_loc_j<nb_faces_elem; face_loc_j++)
1893 {
1894 int face_j=elem_faces(elem2,face_loc_j);
1895 if(face_j!=face_i0)
1896 {
1897 K=Kij(elem2,face_loc_i,face_loc_j);
1898
1899 if(K>0.)
1900 {
1901 max_K=K ;
1902 min_K=0.;
1903 }
1904 else
1905 {
1906 max_K=0.;
1907 min_K=K ;
1908 }
1909
1910 for(comp0=0; comp0<nb_comp; comp0++)
1911 {
1912 dT =transporte(face_j,comp0);
1913 dT-=transporte(face_i0,comp0);
1914
1915 if(dT>0.)
1916 {
1917 max_dT=dT ;
1918 min_dT=0 ;
1919 }
1920 else
1921 {
1922 max_dT=0. ;
1923 min_dT=dT ;
1924 }
1925
1926 pplusi[comp0] +=min_K*min_dT;
1927 pmoinsi[comp0]+=min_K*max_dT;
1928 qplusi[comp0] +=max_K*max_dT;
1929 qmoinsi[comp0]+=max_K*min_dT;
1930 }
1931 }
1932 }
1933 }
1934
1935
1936
1937 for(face_locj=0; face_locj<nb_faces_elem; face_locj++)
1938 if(face_locj!=face_loci)
1939 {
1940 face_j0=elem_faces(elem0,face_locj);
1941 const double kij=Kij(elem0,face_loci,face_locj);
1942 const double kji=Kij(elem0,face_locj,face_loci);
1943 double dij=Dij(elem0,face_loci,face_locj,Kij);
1944 double lji=kji+dij;
1945 double lij=kij+dij;
1946 assert(lij>=0);
1947 assert(lji>=0);
1948
1949 for(comp0=0; comp0<nb_comp; comp0++)
1950 {
1951 const double Ti=transporte(face_i0,comp0);
1952 const double Tj=transporte(face_j0,comp0);
1953 double deltaij=Ti-Tj;
1954 double Fij=0;
1955 if(lij<=lji)
1956 {
1957 double coef=1;
1958 if (lij==lji) coef=.5;
1959 if(deltaij)
1960 {
1961 if(Ti >= Tj)
1962 {
1963 if(pplusi[comp0])
1964 {
1965 double R=qplusi[comp0]/pplusi[comp0];
1966 Fij=minimum(limiteur(R)*dij,lji);
1967 }
1968 }
1969 else if(pmoinsi[comp0])
1970 {
1971 double R=qmoinsi[comp0]/pmoinsi[comp0];
1972 Fij=minimum(limiteur(R)*dij,lji);
1973 }
1974 assert(Fij*dij>=0);
1975 Fij-=dij;
1976 Fij*=deltaij;
1977 }
1978 resu(face_i0,comp0)+=coef*(kij*Tj+Fij);
1979 resu(face_j0,comp0)+=coef*(kji*Ti-Fij);
1980 }
1981 }
1982 }
1983 }
1984 }
1985 //Apply here the treatment used for Neumann_sortie_libre boundary conditions in Op_Conv_VEF_Face
1986 int nb_bord=domaine_Cl_VEF.nb_cond_lim();
1987 int face;
1988 const int ncomp_ch_transporte = transporte.line_size();
1989
1990 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1991 {
1992 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1993 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1994 int nb_faces_tot=le_bord.nb_faces_tot();
1995
1996 double psc;
1997 int num_face,i;
1998
1999 if (sub_type(Neumann_sortie_libre,la_cl.valeur()))
2000 {
2001 const Neumann_sortie_libre& la_sortie_libre = ref_cast(Neumann_sortie_libre, la_cl.valeur());
2002 //const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2003 int num1 = le_bord.num_premiere_face();
2004 int num2 = num1 + le_bord.nb_faces();
2005
2006 for (num_face=num1; num_face<num2; num_face++)
2007 {
2008 psc =0;
2009 for (i=0; i<dimension; i++)
2010 psc += tab_vitesse(num_face,i)*face_normales(num_face,i);
2011 if (psc>0)
2012 {
2013 for (i=0; i<ncomp_ch_transporte; i++)
2014 resu(num_face,i) -= psc*transporte(num_face,i);
2015 }
2016 else
2017 {
2018 for (i=0; i<ncomp_ch_transporte; i++)
2019 resu(num_face,i) -= psc*la_sortie_libre.val_ext(num_face-num1,i);
2020 fluent_(num_face) -= psc;
2021 }
2022 }
2023 }
2024 // For periodicity
2025 else if (sub_type(Periodique,la_cl.valeur()))
2026 {
2027 const Periodique& la_cl_perio = ref_cast(Periodique,la_cl.valeur());
2028 int face_associee,ind_face_associee;
2029 IntVect fait(nb_faces_tot);
2030 fait = 0;
2031
2032 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
2033 {
2034 face=le_bord.num_face(ind_face);
2035 if (fait(ind_face) == 0)
2036 {
2037 fait(ind_face) = 1;
2038 ind_face_associee=la_cl_perio.face_associee(ind_face);
2039 fait(ind_face_associee) = 1;
2040 face_associee=le_bord.num_face(ind_face_associee);
2041 for (int comp=0; comp<nb_comp; comp++)
2042 resu(face_associee, comp)=(resu(face,comp)+=resu(face_associee,comp));
2043 }// if fait
2044 }// for face
2045 }// sub_type Perio
2046 }
2047 /*
2048 ArrOfDouble bilan(nb_comp);
2049 BilanQdmVEF::bilan_qdm(resu, domaine_Cl_VEF, bilan);
2050 if(nb_comp==1)
2051 Cout << "Scalaire Bilan Convectif : " << bilan[0] << finl;
2052 else
2053 for (int comp=0; comp<nb_comp; comp++)
2054 Cout << "Vecteur Bilan Convectif " << comp << " : " << bilan[comp] << finl;
2055 bilan=0;
2056 BilanQdmVEF::bilan_energie(resu, transporte, domaine_Cl_VEF, bilan);
2057 if(nb_comp==1)
2058 Cout << "Scalaire Bilan Convectif Energie : " << bilan[0] << finl;
2059 else
2060 for (int comp=0; comp<nb_comp; comp++)
2061 Cout << "Vecteur Bilan Convectif Energie " << comp << " : " << bilan[comp] << finl;
2062 if(nb_comp==1)
2063 {
2064 Cout << "min = " << min(transporte);
2065 Cout << " max = " << std::max(transporte) << finl;
2066 }
2067 // else
2068 // for (int comp=0; comp<nb_comp; comp++)
2069 // {
2070 // Cout << "min("<<comp<<") = " << transporte.min(comp);
2071 // Cout << " std::max("<<comp<<") = " << transporte.max(comp) << finl;
2072 // }
2073 Cout << " Ratio Antidiffusion/Diffusion = " << sigma_fija/sigma_fijd << finl;
2074 */
2075}
2076
2077//Function that initializes the attributes "elem_nb_faces_dirichlet_"
2078//and "elem_faces_dirichlet_"
2079//NOTE: "elem_nb_faces_dirichlet_" contains the number of Dirichlet faces
2080//for each element of the mesh
2081//NOTE: "elem_faces_dirichlet_" contains the global indices of Dirichlet faces
2082//belonging to any element of the mesh
2083void Op_Conv_EF_VEF_P1NC_Stab::calculer_data_pour_dirichlet()
2084{
2085 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
2086 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
2087
2088 const IntTab& face_voisins = domaine_VEF.face_voisins();
2089 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
2090 const int nb_bord=domaine_Cl_VEF.nb_cond_lim();
2091
2092 //Sizing and initialization of attributes
2093 //NOTE: an element cannot have more than
2094 //(dimension) Dirichlet faces
2095 elem_nb_faces_dirichlet_.resize(nb_elem_tot);
2096 elem_faces_dirichlet_.resize(nb_elem_tot,Objet_U::dimension);
2097 elem_nb_faces_dirichlet_=0;
2098 elem_faces_dirichlet_=-1;
2099 elem_faces_frontiere.dimensionner(nb_bord);
2100
2101 for (int n_bord=0; n_bord<nb_bord; n_bord++)
2102 {
2103 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
2104 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2105 int face, nb_faces_tot=le_bord.nb_faces_tot();
2106
2107 if ( (sub_type(Dirichlet,la_cl.valeur()))
2108 || (sub_type(Dirichlet_homogene,la_cl.valeur()))
2109 )
2110 {
2111 //
2112 //Filling the arrays
2113 //
2114 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
2115 {
2116 face = le_bord.num_face(ind_face);
2117 const int elem=face_voisins(face,0);
2118 assert(elem!=-1);
2119 elem_faces_frontiere[n_bord].append_array(elem);
2120
2121 elem_nb_faces_dirichlet_(elem)+=1;
2122 assert(elem_nb_faces_dirichlet_(elem)<=Objet_U::dimension);
2123
2124 if (elem_faces_dirichlet_(elem,0)==-1) elem_faces_dirichlet_(elem,0)=face;
2125 else if (elem_faces_dirichlet_(elem,1)==-1) elem_faces_dirichlet_(elem,1)=face;
2126 else if (Objet_U::dimension==3 && elem_faces_dirichlet_(elem,2)==-1) elem_faces_dirichlet_(elem,2)=face;
2127 else
2128 {
2129 Cerr << "Error in Op_Conv_EF_VEF_P1NC_Stab::calculer_data_pour_dirichlet()" << finl;
2130 Cerr << "Element number " << elem << " contains more than "
2131 << Objet_U::dimension << " Dirichlet faces" << finl;
2132 Cerr << "Exiting." << finl;
2133 Process::exit();
2134 }
2135 }//end of for on "face"
2136 //
2137 //End of array filling
2138 //
2139
2140 }//end of if on "Dirichlet"
2141 array_trier_retirer_doublons(elem_faces_frontiere[n_bord]);
2142 }//end of for on "n_bord"
2143}
2144
2146{
2148 calculer_data_pour_dirichlet();
2149
2150 // int nb_comp=1;
2151 // if (equation().inconnue().valeurs().nb_dim()>1)
2152 // nb_comp=equation().inconnue().valeurs().dimension(1);
2153
2154 // limiteurs_.resize(le_dom_vef->nb_faces_tot(),nb_comp);
2155 // limiteurs_=0.;
2156
2157 alpha_tab_.resize_array(le_dom_vef->nb_faces_tot());
2158 alpha_tab_ = alpha_;
2159 beta_.resize_array(le_dom_vef->nb_faces_tot());
2160 beta_=1.;
2161
2162 if (ssz_alpha)
2163 {
2164 for (int i=0; i<nb_ssz_alpha; i++)
2165 {
2166 OBS_PTR(Sous_domaine_VF) la_ssz;
2167 const Sous_Domaine& le_sous_domaine=equation().probleme().domaine().ss_domaine(noms_ssz_alpha[i]);
2168 const Domaine_dis_base& le_domaine_dis=le_dom_vef.valeur();
2169 bool trouve=false;
2170 for (int ssz=0; ssz<le_domaine_dis.nombre_de_sous_domaines_dis(); ssz++)
2171 {
2172 if (le_domaine_dis.sous_domaine_dis(ssz).sous_domaine().est_egal_a(le_sous_domaine))
2173 {
2174 trouve=true;
2175 la_ssz=ref_cast(Sous_domaine_VF,le_domaine_dis.sous_domaine_dis(ssz));
2176 }
2177 }
2178
2179 if(!trouve)
2180 {
2181 Cerr << "Cannot find the discretized sub-domain associated with " << noms_ssz_alpha[i] << finl;
2182 Process::exit();
2183 }
2184 const Sous_domaine_VF& ssz=la_ssz.valeur();
2185 int nb_faces = ssz.les_faces().size();
2186
2187 for (int face=0; face<nb_faces; face++)
2188 {
2189 int la_face=ssz.les_faces()[face];
2190 beta_[la_face] = 1.;
2191 alpha_tab_[la_face] = alpha_ssz(i);
2192 }
2193 }
2194 }
2195
2196
2197
2198
2199 if (sous_domaine)
2200 {
2201 sous_domaine=false;
2202 const Sous_Domaine& le_sous_domaine=equation().probleme().domaine().ss_domaine(nom_sous_domaine);
2203 const Domaine_dis_base& le_domaine_dis=le_dom_vef.valeur();
2204 for (int ssz=0; ssz<le_domaine_dis.nombre_de_sous_domaines_dis(); ssz++)
2205 {
2206 if (le_domaine_dis.sous_domaine_dis(ssz).sous_domaine().est_egal_a(le_sous_domaine))
2207 {
2208 sous_domaine=true;
2209 le_sous_domaine_dis=ref_cast(Sous_domaine_VF,le_domaine_dis.sous_domaine_dis(ssz));
2210 }
2211 }
2212
2213 if(!sous_domaine)
2214 {
2215 Cerr << "Cannot find the discretized sub-domain associated with " << nom_sous_domaine << finl;
2216 Process::exit();
2217 }
2218
2219 const Sous_domaine_VF& ssz=le_sous_domaine_dis.valeur();
2220 int nb_faces = ssz.les_faces().size();
2221
2222 for (int face=0; face<nb_faces; face++)
2223 {
2224 int la_face=ssz.les_faces()[face];
2225 beta_[la_face] = 0.;
2226 alpha_tab_[la_face] = 1.;
2227 }
2228 }
2229
2230}
2231
2232void Op_Conv_EF_VEF_P1NC_Stab::ajouter_contribution(const DoubleTab& transporte_2, Matrice_Morse& matrice) const
2233{
2234 if (new_jacobienne_==0)
2235 {
2236 Op_Conv_VEF_Face::ajouter_contribution(transporte_2, matrice) ;
2237 return;
2238 }
2239 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
2240
2241 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
2242 const int nb_faces_elem = domaine_VEF.domaine().nb_faces_elem();
2243 const int nb_comp=transporte_2.line_size();
2244
2245 DoubleTrav Kij(nb_elem_tot,nb_faces_elem,nb_faces_elem);
2246 Kij=0.;
2247
2248 //
2249 //To account for porosity
2250 //
2251 const Champ_P1NC& la_vitesse=ref_cast( Champ_P1NC, vitesse_.valeur());
2252 const DoubleTab& vitesse_2=la_vitesse.valeurs();
2253 const DoubleVect& porosite_face = equation().milieu().porosite_face();
2254 DoubleTrav transporte_;
2255 DoubleTrav vitesse_face_;
2256
2257 // either transporte=phi*transporte_ and vitesse=vitesse_
2258 // or transporte=transporte_ and vitesse=phi*vitesse_
2259 // depending on whether transport uses phi*u or u.
2260 const int marq=phi_u_transportant(equation());
2261 const DoubleTab& transporte=modif_par_porosite_si_flag(transporte_2,transporte_,!marq,porosite_face);
2262 const DoubleTab& tab_vitesse=modif_par_porosite_si_flag(vitesse_2,vitesse_face_,marq,porosite_face);
2263
2264 calculer_coefficients_operateur_centre(Kij,nb_comp,tab_vitesse);
2265 if (is_compressible_) ajouter_contribution_partie_compressible(transporte,tab_vitesse,matrice);
2266 ajouter_contribution_operateur_centre(Kij,transporte,matrice);
2267 ajouter_contribution_diffusion(Kij,transporte,matrice);
2268
2269 if (test_) test_implicite();
2270}
2271
2272void Op_Conv_EF_VEF_P1NC_Stab::modifier_pour_Cl (Matrice_Morse& matrice, DoubleTab& secmem) const
2273{
2274 Op_Conv_VEF_Face::modifier_pour_Cl(matrice,secmem);
2275}
2276
2277void Op_Conv_EF_VEF_P1NC_Stab::ajouter_contribution_operateur_centre(const DoubleTab& tab_Kij, const DoubleTab& transporte, Matrice_Morse& matrice_morse) const
2278{
2279 const Domaine_VEF& domaine_VEF=le_dom_vef.valeur();
2280 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
2281
2282
2283 const int nb_elem_tot=domaine_VEF.nb_elem_tot();
2284 const int nb_faces_elem=domaine_VEF.elem_faces().dimension(1);
2285 const int nb_bord=domaine_Cl_VEF.nb_cond_lim();
2286
2287 const int nb_comp=transporte.line_size();
2288
2289 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
2290 CDoubleTabView3 Kij = tab_Kij.view_ro<3>();
2291 Matrice_Morse_View matrice;
2292 matrice.set(matrice_morse);
2293 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
2294 range_2D({0,0}, {nb_elem_tot,nb_faces_elem}), KOKKOS_LAMBDA(
2295 const int elem, const int facei_loc)
2296 {
2297 int facei = elem_faces(elem, facei_loc);
2298
2299 for (int facej_loc = facei_loc+1; facej_loc < nb_faces_elem; facej_loc++)
2300 {
2301 int facej = elem_faces(elem, facej_loc);
2302
2303 double kij = Kij(elem, facei_loc, facej_loc);
2304 double kji = Kij(elem, facej_loc, facei_loc);
2305
2306 for (int dim = 0; dim < nb_comp; dim++)
2307 {
2308 int ligne = facei*nb_comp + dim;
2309 int colonne = facej*nb_comp + dim;
2310
2311 //ATTENTION AU SIGNE : ici on code +div(uT)
2312 matrice.atomic_add(ligne, ligne, kij);
2313 matrice.atomic_add(ligne, colonne, -kij);
2314 matrice.atomic_add(colonne, colonne, kji);
2315 matrice.atomic_add(colonne, ligne, -kji);
2316 }
2317 }
2318 });
2319 end_gpu_timer(__KERNEL_NAME__);
2320
2321 //
2322 //For periodicity
2323 //
2324 const IntTab& num_fac_loc = domaine_VEF.get_num_fac_loc();
2325 for (int n_bord=0; n_bord<nb_bord; n_bord++)
2326 {
2327 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
2328 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2329 int num1 = 0;
2330 int num2=le_bord.nb_faces_tot();//and not nb_faces otherwise some coefficients are missed
2331
2332 if (sub_type(Periodique,la_cl.valeur()))
2333 {
2334 const Periodique& la_cl_perio = ref_cast(Periodique,la_cl.valeur());
2335 int faceiAss=0,ind_faceiAss=0;
2336 const IntTab& face_voisins = domaine_VEF.face_voisins();
2337 for (int ind_face=num1; ind_face<num2; ind_face++)
2338 {
2339 ind_faceiAss=la_cl_perio.face_associee(ind_face);
2340
2341 int facei=le_bord.num_face(ind_face);
2342 faceiAss=le_bord.num_face(ind_faceiAss);
2343
2344 //To iterate over periodic faces only once
2345 if (facei<faceiAss)
2346 for (int elem_loc=0; elem_loc<2; elem_loc++)
2347 {
2348 int elem=face_voisins(facei,elem_loc);
2349 assert(elem!=-1);
2350
2351 //Compute the local face index within "elem"
2352 int facei_loc=num_fac_loc(facei,elem_loc);
2353 int faceToComplete;
2354 if (facei_loc!=-1)
2355 faceToComplete=faceiAss;
2356 else
2357 {
2358 faceToComplete=facei;
2359 facei_loc=num_fac_loc(faceiAss,elem_loc);
2360 assert(facei_loc!=-1);
2361 }
2362
2363 //Compute the matrix coefficients due to "elem"
2364 for (int facej_loc=0; facej_loc<nb_faces_elem; facej_loc++)
2365 {
2366 int facej=elem_faces(elem,facej_loc);
2367
2368 if (facej_loc!=facei_loc)
2369 {
2370 double kij=Kij(elem,facei_loc,facej_loc);
2371 //double kji=Kij(elem,facej_loc,facei_loc);
2372
2373 for (int dim=0; dim<nb_comp; dim++)
2374 {
2375 int ligne=faceToComplete*nb_comp+dim;
2376 int colonne=facej*nb_comp+dim;
2377
2378 //ATTENTION AU SIGNE : ici on code +div(uT)
2379 matrice_morse(ligne,ligne)+=kij;
2380 matrice_morse(ligne,colonne)-=kij;
2381 }
2382 }
2383 }
2384 }
2385 }
2386 }
2387 }
2388}
2389
2390void Op_Conv_EF_VEF_P1NC_Stab::ajouter_contribution_diffusion(const DoubleTab& tab_Kij, const DoubleTab& transporte, Matrice_Morse& matrice_morse) const
2391{
2392 const Domaine_VEF& domaine_VEF=le_dom_vef.valeur();
2393 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
2394 const int nb_elem_tot=domaine_VEF.nb_elem_tot();
2395 const int nb_faces_elem=domaine_VEF.elem_faces().line_size();
2396 const int nb_bord=domaine_Cl_VEF.nb_cond_lim();
2397 const int nb_comp=transporte.line_size();
2398
2399 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
2400 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
2401 CDoubleArrView alpha_tab = static_cast<const ArrOfDouble&>(alpha_tab_).view_ro();
2402 CDoubleTabView3 Kij = tab_Kij.view_ro<3>();
2403 Matrice_Morse_View matrice;
2404 matrice.set(matrice_morse);
2405 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
2406 range_2D({0,0}, {nb_elem_tot,nb_faces_elem}), KOKKOS_LAMBDA(
2407 const int elem, const int facei_loc)
2408 {
2409 int facei = elem_faces(elem, facei_loc);
2410
2411 for (int facej_loc = facei_loc+1; facej_loc < nb_faces_elem; facej_loc++)
2412 {
2413 int facej = elem_faces(elem, facej_loc);
2414
2415 double dij = Dij(elem, facei_loc, facej_loc, Kij);
2416
2417 double coeffij = alpha_tab(facei)*dij;
2418 double coeffji = alpha_tab(facej)*dij;
2419
2420 for (int dim = 0; dim < nb_comp; dim++)
2421 {
2422 int ligne = facei*nb_comp + dim;
2423 int colonne = facej*nb_comp + dim;
2424
2425 //NOTE ON SIGN: here we code +div(uT)
2426 //NOTE: exploiting the symmetry of the operator
2427 matrice.atomic_add(ligne, ligne, coeffij);
2428 matrice.atomic_add(ligne, colonne, -coeffij);
2429 matrice.atomic_add(colonne, colonne, coeffji);
2430 matrice.atomic_add(colonne, ligne, -coeffji);
2431 }
2432 }
2433 });
2434 end_gpu_timer(__KERNEL_NAME__);
2435
2436 //
2437 //For periodicity
2438 //
2439 const IntTab& num_fac_loc = domaine_VEF.get_num_fac_loc();
2440 for (int n_bord=0; n_bord<nb_bord; n_bord++)
2441 {
2442 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
2443 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2444 int num1 = 0;
2445 int num2=le_bord.nb_faces_tot();//and not nb_faces() otherwise some coefficients are missed
2446
2447 if (sub_type(Periodique,la_cl.valeur()))
2448 {
2449 const Periodique& la_cl_perio = ref_cast(Periodique,la_cl.valeur());
2450 int faceiAss=0,ind_faceiAss=0;
2451
2452 for (int ind_face=num1; ind_face<num2; ind_face++)
2453 {
2454 int facei=le_bord.num_face(ind_face);
2455 ind_faceiAss=la_cl_perio.face_associee(ind_face);
2456 faceiAss=le_bord.num_face(ind_faceiAss);
2457
2458 //To iterate over periodic faces only once
2459 if (facei<faceiAss)
2460 for (int elem_loc=0; elem_loc<2; elem_loc++)
2461 {
2462 int elem=face_voisins(facei,elem_loc);
2463 assert(elem!=-1);
2464
2465 //Compute the local face index within "elem"
2466 int facei_loc=num_fac_loc(facei,elem_loc);
2467 int faceToComplete;
2468 if (facei_loc!=-1)
2469 faceToComplete=faceiAss;
2470 else
2471 {
2472 faceToComplete=facei;
2473 facei_loc=num_fac_loc(faceiAss,elem_loc);
2474 assert(facei_loc!=-1);
2475 }
2476
2477 //Compute the matrix coefficients due to "elem"
2478 for (int facej_loc=0; facej_loc<nb_faces_elem; facej_loc++)
2479 {
2480 int facej=elem_faces(elem,facej_loc);
2481
2482 if (facej_loc!=facei_loc)
2483 {
2484 double dij=Dij(elem,facei_loc,facej_loc,tab_Kij);
2485 assert(dij>=0);
2486
2487 double coeffij=alpha_tab_[faceToComplete]*dij;
2488 //double coeffji=alpha_tab_[facej]*dij;
2489
2490 for (int dim=0; dim<nb_comp; dim++)
2491 {
2492 int ligne=faceToComplete*nb_comp+dim;
2493 int colonne=facej*nb_comp+dim;
2494
2495 //ATTENTION AU SIGNE : ici on code +div(uT)
2496 matrice_morse(ligne,ligne)+=coeffij;
2497 matrice_morse(ligne,colonne)-=coeffij;
2498 }
2499 }
2500 }
2501 }
2502 }
2503 }
2504 }
2505}
2506
2507//Porous correction: add the T*div(u) contribution
2508//Transported variable: T
2509//Transporting variable: u
2510//NOTE: the Kij array MUST NOT be used because by
2511//construction sum_{j} Kij = 0, which enforces a zero-divergence
2512//velocity per element — problematic in compressible flows
2513void Op_Conv_EF_VEF_P1NC_Stab::ajouter_contribution_partie_compressible(const DoubleTab& transporte, const DoubleTab& vitesse_2,
2514 Matrice_Morse& matrice) const
2515{
2516 const Domaine_VEF& domaine_VEF=le_dom_vef.valeur();
2517 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
2518 const IntTab& elem_faces=domaine_VEF.elem_faces();
2519 const IntTab& face_voisins = domaine_VEF.face_voisins();
2520 const DoubleTab& face_normales=domaine_VEF.face_normales();
2521 const int nb_elem_tot=domaine_VEF.nb_elem_tot();
2522 const int nb_faces_elem=elem_faces.line_size();
2523 const int nb_bord=domaine_Cl_VEF.nb_cond_lim();
2524
2525 //To account for porosity
2526 const int marq = phi_u_transportant(equation());
2527 const DoubleVect& porosite_elem = equation().milieu().porosite_elem();
2528 const DoubleVect& porosite_face = equation().milieu().porosite_face();
2529
2530 DoubleTrav tab_vitesse(vitesse_->valeurs());
2531 for (int i=0; i<tab_vitesse.dimension(0); i++)
2532 for (int j=0; j<tab_vitesse.line_size(); j++)
2533 tab_vitesse(i,j)*=porosite_face(i);
2534
2535 const int nb_comp=transporte.line_size();
2536
2537 double (*formule)(int);
2538
2539 if (!volumes_etendus_)
2540 formule= (dimension==2) ? &formule_Id_2D : &formule_Id_3D;
2541 else
2542 formule= (dimension==2) ? &formule_2D : &formule_3D;
2543
2544 ToDo_Kokkos("critical");
2545 for (int elem=0; elem<nb_elem_tot; elem++)
2546 {
2547 //Element type: the number of Dirichlet faces
2548 //it contains
2549 int type_elem=elem_nb_faces_dirichlet_(elem);
2550 double coeff=formule(type_elem);
2551
2552 //Compute the divergence per element
2553 double div=0.;
2554 for (int facei_loc=0; facei_loc<nb_faces_elem; facei_loc++)
2555 {
2556 int facei=elem_faces(elem,facei_loc);
2557 int signe=(face_voisins(facei,0)==elem)? 1.:-1.;
2558
2559 for (int dim=0; dim<dimension; dim++)
2560 div+=signe*face_normales(facei,dim)*tab_vitesse(facei,dim);
2561 }
2562 div*=coeff;
2563 if (!marq) div/=porosite_elem(elem);
2564
2565 //Compute the compressible part
2566 for (int facei_loc=0; facei_loc<nb_faces_elem; facei_loc++)
2567 {
2568 int facei=elem_faces(elem,facei_loc);
2569
2570 for (int dim=0; dim<nb_comp; dim++)
2571 {
2572 int ligne=facei*nb_comp+dim;
2573 matrice(ligne,ligne)+=div;
2574 }
2575 }
2576 }
2577
2578 //
2579 //For periodicity
2580 //
2581 const IntTab& num_fac_loc = domaine_VEF.get_num_fac_loc();
2582 for (int n_bord=0; n_bord<nb_bord; n_bord++)
2583 {
2584 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
2585 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2586 int num1 = 0;
2587 int num2 = le_bord.nb_faces();//only iterate over real faces
2588
2589 if (sub_type(Periodique,la_cl.valeur()))
2590 {
2591 const Periodique& la_cl_perio = ref_cast(Periodique,la_cl.valeur());
2592
2593 for (int ind_face=num1; ind_face<num2; ind_face++)
2594 {
2595 int facei = le_bord.num_face(ind_face);
2596 int ind_faceiAss = la_cl_perio.face_associee(ind_face);
2597 int faceiAss = le_bord.num_face(ind_faceiAss);
2598
2599 //To iterate over periodic faces only once
2600 if (facei<faceiAss)
2601 for (int elem_loc=0; elem_loc<2; elem_loc++)
2602 {
2603 int elem = face_voisins(facei,elem_loc);
2604 assert(elem!=-1);
2605
2606 //Compute the local face index within "elem"
2607 int facei_loc=num_fac_loc(facei,elem_loc);
2608 int faceToComplete;
2609 if (facei_loc!=-1)
2610 faceToComplete=faceiAss;
2611 else
2612 {
2613 faceToComplete=facei;
2614 facei_loc=num_fac_loc(faceiAss,elem_loc);
2615 assert(facei_loc!=-1);
2616 }
2617
2618 //Element type: the number of Dirichlet faces
2619 //it contains
2620 int type_elem=elem_nb_faces_dirichlet_(elem);
2621 double coeff=formule(type_elem);
2622
2623 //Compute the divergence per element
2624 double div=0.;
2625 for (facei_loc=0; facei_loc<nb_faces_elem; facei_loc++)
2626 {
2627 facei=elem_faces(elem,facei_loc);
2628 int signe=(face_voisins(facei,0)==elem)? 1.:-1.;
2629
2630 for (int dim=0; dim<dimension; dim++)
2631 div+=signe*face_normales(facei,dim)*tab_vitesse(facei,dim);
2632 }
2633 div*=coeff;
2634 if (!marq) div/=porosite_elem(elem);
2635
2636 //Compute the compressible part
2637 for (int dim=0; dim<nb_comp; dim++)
2638 {
2639 int ligne=faceToComplete*nb_comp+dim;
2640 matrice(ligne,ligne)+=div;
2641 }
2642 }
2643 }
2644 }
2645 }
2646}
2647
2648void Op_Conv_EF_VEF_P1NC_Stab::ajouter_contribution_antidiffusion(const DoubleTab& Kij, const DoubleTab& transporte,
2649 Matrice_Morse& matrice) const
2650{
2651 const Domaine_VEF& domaine_VEF=le_dom_vef.valeur();
2652 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
2653 const IntTab& elem_faces=domaine_VEF.elem_faces();
2654 const IntTab& face_voisins = domaine_VEF.face_voisins();
2655 const int nb_elem_tot=domaine_VEF.nb_elem_tot();
2656 const int nb_faces_elem=elem_faces.line_size();
2657 const int nb_bord=domaine_Cl_VEF.nb_cond_lim();
2658 const int nb_comp=transporte.line_size();
2659
2660 int elem=0, elem_loc=0, facei=0,facei_loc=0, faceiAss=0, ind_face=0,ind_faceiAss=0;
2661 int facej=0,facej_loc=0, ligne=0,colonne=0, dim=0, face_amont=0,face_aval=0;
2662 int faceToComplete=0, num1=0,num2=0, n_bord=0;
2663 double kij=0.,kji=0.,dij=0., lij=0.,lji=0., daij=0.;
2664 double delta=0., coeffij=0.,coeffji=0., coeff=0., R=0.;
2665
2666 //For the limiter
2667 ArrOfDouble P_plus(nb_comp),P_moins(nb_comp);
2668 ArrOfDouble Q_plus(nb_comp),Q_moins(nb_comp);
2669 P_plus=0., P_moins=0., Q_plus=0., Q_moins=0.;
2670
2671 const DoubleVect& transporteV = transporte;
2672 const ArrOfDouble& alpha_tab = alpha_tab_;
2673 const IntTab& num_fac_loc = domaine_VEF.get_num_fac_loc();
2674 ToDo_Kokkos("critical");
2675 for (elem=0; elem<nb_elem_tot; elem++)
2676 for (facei_loc=0; facei_loc<nb_faces_elem; facei_loc++)
2677 {
2678 facei=elem_faces(elem,facei_loc);
2679 P_plus=0., P_moins=0., Q_plus=0., Q_moins=0.;
2680 calculer_senseur(Kij,transporteV,nb_comp,facei,elem_faces,face_voisins,num_fac_loc,P_plus,P_moins,Q_plus,Q_moins);
2681 for (facej_loc=0; facej_loc<nb_faces_elem; facej_loc++)
2682 if (facej_loc!=facei_loc)
2683 {
2684 facej=elem_faces(elem,facej_loc);
2685
2686 kij = Kij(elem,facei_loc,facej_loc);
2687 kji = Kij(elem,facej_loc,facei_loc);
2688 dij = Dij(elem,facei_loc,facej_loc,Kij);
2689 lij = kij+dij;
2690 lji = kji+dij;
2691 assert(lij>=0);
2692 assert(lji>=0);
2693
2694 if (lij<=lji) //facei is upstream
2695 {
2696 face_amont = facei;
2697 face_aval = facej;
2698
2699 //If lij==lji, we iterate twice in the loop
2700 //hence the coefficient 1/2
2701 coeff = 1.*(lij<lji)+0.5*(lij==lji);
2702 assert(coeff==1. || coeff==0.5);
2703
2704 for (dim=0; dim<nb_comp; dim++)
2705 {
2706 ligne=face_amont*nb_comp+dim;
2707 colonne=face_aval*nb_comp+dim;
2708
2709 delta=transporteV[ligne]-transporteV[colonne];
2710
2711 //Slope limiter
2712 // if (delta>=0.) R=(P_plus(dim)==0.) ? 0. : Q_plus(dim)/P_plus(dim);
2713 // else R=(P_moins(dim)==0.) ? 0. : Q_moins(dim)/P_moins(dim);
2714
2715 // if (delta>=0.) R=(P_plus(dim)==0.) ? 0. : Q_plus(dim)/(P_plus(dim)+DMINFLOAT);
2716 // else R=(P_moins(dim)==0.) ? 0. : Q_moins(dim)/(P_moins(dim)+DMINFLOAT);
2717
2718 if (delta>=0.) R=(std::fabs(P_plus[dim])<DMINFLOAT) ? 0. : Q_plus[dim]/P_plus[dim];
2719 else R=(std::fabs(P_moins[dim])<DMINFLOAT) ? 0. : Q_moins[dim]/P_moins[dim];
2720
2721
2722 daij=minimum(limiteur(R)*dij,lji);
2723 assert(daij>=0);
2724 assert(daij<=lji);
2725 coeffij=alpha_tab_[face_amont]*beta_[face_amont]*daij;
2726 coeffji=alpha_tab_[face_aval]*beta_[face_aval]*daij;
2727
2728 //Compute the matrix
2729 matrice(ligne,ligne)-=coeffij*coeff;
2730 matrice(ligne,colonne)+=coeffij*coeff;
2731 matrice(colonne,colonne)-=coeffji*coeff;
2732 matrice(colonne,ligne)+=coeffji*coeff;
2733 }
2734 }
2735 }
2736 }
2737
2738 //
2739 //For periodicity
2740 //
2741 for (n_bord=0; n_bord<nb_bord; n_bord++)
2742 {
2743 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
2744 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2745 num1 = 0;
2746 num2=le_bord.nb_faces();//only iterate over real faces
2747
2748 if (sub_type(Periodique,la_cl.valeur()))
2749 {
2750 const Periodique& la_cl_perio = ref_cast(Periodique,la_cl.valeur());
2751
2752 //For the limiter
2753 ArrOfDouble Pj_plus(nb_comp),Pj_moins(nb_comp);
2754 ArrOfDouble Qj_plus(nb_comp),Qj_moins(nb_comp);
2755 Pj_plus=0., Pj_moins=0.;
2756 Qj_plus=0., Qj_moins=0.;
2757
2758 for (ind_face=num1; ind_face<num2; ind_face++)
2759 {
2760 facei=le_bord.num_face(ind_face);
2761 ind_faceiAss=la_cl_perio.face_associee(ind_face);
2762 faceiAss=le_bord.num_face(ind_faceiAss);
2763
2764 //To iterate over periodic faces only once
2765 if (facei<faceiAss)
2766 for (elem_loc=0; elem_loc<2; elem_loc++)
2767 {
2768 elem=face_voisins(facei,elem_loc);
2769 assert(elem!=-1);
2770
2771 //Compute the local face index within "elem"
2772 facei_loc=num_fac_loc(facei,elem_loc);
2773 if (facei_loc!=-1)
2774 faceToComplete=faceiAss;
2775 else
2776 {
2777 faceToComplete=facei;
2778 facei_loc=num_fac_loc(faceiAss,elem_loc);
2779 assert(facei_loc!=-1);
2780 }
2781
2782 //Compute the coefficient to add to the matrix
2783 P_plus=0., P_moins=0.;
2784 Q_plus=0., Q_moins=0.;
2785 calculer_senseur(Kij,transporteV,nb_comp,faceToComplete,elem_faces,face_voisins,num_fac_loc,P_plus,P_moins,Q_plus,Q_moins);
2786
2787 for (facej_loc=0; facej_loc<nb_faces_elem; facej_loc++)
2788 if (facej_loc!=facei_loc)
2789 {
2790 facej=elem_faces(elem,facej_loc);
2791
2792 kij = Kij(elem,facei_loc,facej_loc);
2793 kji = Kij(elem,facej_loc,facei_loc);
2794 dij = Dij(elem,facei_loc,facej_loc,Kij);
2795 lij = kij+dij;
2796 lji = kji+dij;
2797 assert(lij>=0);
2798 assert(lji>=0);
2799
2800 if (lij<=lji) //faceToComplete is upstream
2801 {
2802 face_amont=faceToComplete;
2803 face_aval=facej;
2804
2805 //If lij==lji, we iterate twice in the loop
2806 //hence the coefficient 1/2
2807 coeff = 1.*(lij<lji)+0.5*(lij==lji);
2808 assert(coeff==1. || coeff==0.5);
2809
2810 for (dim=0; dim<nb_comp; dim++)
2811 {
2812 ligne=face_amont*nb_comp+dim;
2813 colonne=face_aval*nb_comp+dim;
2814 delta=transporteV[ligne]-transporteV[colonne];
2815
2816 //Slope limiter
2817 // if (delta>=0.) R=(P_plus(dim)==0.) ? 0. : Q_plus(dim)/P_plus(dim);
2818 // else R=(P_moins(dim)==0.) ? 0. : Q_moins(dim)/P_moins(dim);
2819
2820 // if (delta>=0.) R=(P_plus(dim)==0.) ? 0. : Q_plus(dim)/(P_plus(dim)+DMINFLOAT);
2821 // else R=(P_moins(dim)==0.) ? 0. : Q_moins(dim)/(P_moins(dim)+DMINFLOAT);
2822
2823 if (delta>=0.) R=(std::fabs(P_plus[dim])<DMINFLOAT) ? 0. : Q_plus[dim]/P_plus[dim];
2824 else R=(std::fabs(P_moins[dim])<DMINFLOAT) ? 0. : Q_moins[dim]/P_moins[dim];
2825
2826 daij=minimum(limiteur(R)*dij,lji);
2827 assert(daij>=0);
2828 assert(daij<=lji);
2829 coeffij=alpha_tab[face_amont]*beta_[face_amont]*daij;
2830
2831 //Compute the matrix
2832 matrice(ligne,ligne)-=coeffij*coeff;
2833 matrice(ligne,colonne)+=coeffij*coeff;
2834 }
2835 }
2836 else //faceToComplete is downstream
2837 {
2838 face_aval=faceToComplete;
2839 face_amont=facej;
2840 coeff=1.;
2841 Pj_plus=0., Pj_moins=0., Qj_plus=0., Qj_moins=0.;
2842 calculer_senseur(Kij,transporteV,nb_comp,facej,elem_faces,face_voisins,num_fac_loc,Pj_plus,Pj_moins,Qj_plus,Qj_moins);
2843
2844 for (dim=0; dim<nb_comp; dim++)
2845 {
2846 ligne=face_amont*nb_comp+dim;
2847 colonne=face_aval*nb_comp+dim;
2848
2849 delta=transporteV[ligne]-transporteV[colonne];
2850
2851 //Slope limiter
2852 // if (delta>=0.) R=(Pj_plus(dim)==0.) ? 0. : Qj_plus(dim)/Pj_plus(dim);
2853 // else R=(Pj_moins(dim)==0.) ? 0. : Qj_moins(dim)/Pj_moins(dim);
2854
2855 // if (delta>=0.) R=(Pj_plus(dim)==0.) ? 0. : Qj_plus(dim)/(Pj_plus(dim)+DMINFLOAT);
2856 // else R=(Pj_moins(dim)==0.) ? 0. : Qj_moins(dim)/(Pj_moins(dim)+DMINFLOAT);
2857
2858 if (delta>=0.) R=(std::fabs(Pj_plus[dim])<DMINFLOAT) ? 0. : Qj_plus[dim]/Pj_plus[dim];
2859 else R=(std::fabs(Pj_moins[dim])<DMINFLOAT) ? 0. : Qj_moins[dim]/Pj_moins[dim];
2860
2861 daij=minimum(limiteur(R)*dij,lij);
2862 assert(daij>=0);
2863 assert(daij<=lij);
2864 coeffij=alpha_tab[face_aval]*beta_[face_aval]*daij;
2865
2866 //Compute the matrix
2867 matrice(colonne,colonne)-=coeffij*coeff;
2868 matrice(colonne,ligne)+=coeffij*coeff;
2869 }
2870 }
2871 }
2872 }
2873 }
2874 }
2875 }
2876}
2877
2878void Op_Conv_EF_VEF_P1NC_Stab::test_implicite() const
2879{
2880 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
2881 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
2882
2883 const DoubleTab& unknown=equation().inconnue().valeurs();
2884 const DoubleTab& tab_vitesse=vitesse_->valeurs();
2885
2886 DoubleTab tab_test(unknown);
2887 DoubleVect& test2 = tab_test;
2888 test2 = 0.;
2889
2890 DoubleTab resuExp(unknown);
2891 DoubleVect& resu2Exp = resuExp;
2892 resu2Exp = 0.;
2893
2894 DoubleTab resuImp(unknown);
2895 DoubleVect& resu2Imp = resuImp;
2896 resu2Imp = 0.;
2897
2898 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
2899 const int nb_faces_elem = domaine_VEF.domaine().nb_faces_elem();
2900 const int nb_faces_tot=domaine_VEF.nb_faces_tot();
2901 const int nb_bord=domaine_Cl_VEF.nb_cond_lim();
2902
2903 DoubleTab Kij(nb_elem_tot,nb_faces_elem,nb_faces_elem);
2904 Kij=0.;
2905
2906 const int nb_comp=unknown.line_size();
2907 int size=unknown.dimension(0);
2908 int face=0,face2=0, faceAss=0, ind_face=0,ind_faceAss=0, n_bord=0, num1=0,num2=0;
2909
2910 SFichier testResu("test.txt");
2911 SFichier testMat("matrice.txt");
2912
2913 //
2914 //For periodicity
2915 //
2916 IntTab faces_associees(nb_faces_tot);
2917 for (face=0; face<nb_faces_tot; face++)
2918 faces_associees(face)=face;
2919
2920 for (n_bord=0; n_bord<nb_bord; n_bord++)
2921 {
2922 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
2923 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2924 num1 = 0;
2925 num2=le_bord.nb_faces_tot();//to avoid missing any
2926
2927 if (sub_type(Periodique,la_cl.valeur()))
2928 {
2929 const Periodique& la_cl_perio = ref_cast(Periodique,la_cl.valeur());
2930
2931 for (ind_face=num1; ind_face<num2; ind_face++)
2932 {
2933 face=le_bord.num_face(ind_face);
2934 ind_faceAss=la_cl_perio.face_associee(ind_face);
2935 faceAss=le_bord.num_face(ind_faceAss);
2936
2937 //To iterate over only half the periodic faces
2938 if (face<faceAss)
2939 {
2940 faces_associees(face)=faceAss;
2941 faces_associees(faceAss)=face;
2942 }
2943 }
2944 }
2945 }
2946 //
2947 //End of periodic face treatment
2948 //
2949
2950 calculer_coefficients_operateur_centre(Kij,nb_comp,tab_vitesse);
2951
2952 //
2953 //Build the matrix
2954 //
2955 Matrice_Morse matrice;
2956 dimensionner(matrice);
2957 if (is_compressible_)
2958 ajouter_contribution_partie_compressible(unknown,tab_vitesse,matrice);
2959 ajouter_contribution_operateur_centre(Kij,unknown,matrice);
2960 ajouter_contribution_diffusion(Kij,unknown,matrice);
2961 ajouter_contribution_antidiffusion(Kij,unknown,matrice);
2962 matrice.imprimer_formatte(testMat);
2963 //
2964 //End of matrix construction
2965 //
2966
2967 //
2968 //Compute the explicit operator and comparison
2969 //
2970 for (face=0; face<size; face++)
2971 {
2972 test2[face]=1.;
2973 test2[faces_associees(face)]=1.;
2974
2975 /* Compute the explicit operator */
2976 resuExp=0.;
2977 if (is_compressible_)
2978 ajouter_partie_compressible(tab_test,resuExp,tab_vitesse);
2979 ajouter_operateur_centre(Kij,tab_test,resuExp);
2980 ajouter_diffusion(Kij,tab_test,resuExp);
2981 ajouter_antidiffusion(Kij,tab_test,resuExp);
2983
2984 /* Compute the implicit operator */
2985 resuImp=0.;
2986 matrice.ajouter_multvect_(tab_test,resuImp);
2987
2988 /* Compute the difference */
2989 resuExp+=resuImp;
2990
2991 /* Display of the difference */
2992 testResu<<"*************************"<<finl;
2993 testResu<<"Face test : "<<face<<finl;
2994 for (face2=0; face2<size; face2++)
2995 if (resu2Exp[face2]<=1.e-13)
2996 testResu<<face2<<" OK"<<finl;
2997 else
2998 testResu<<face2<<" residu : "<<resu2Exp[face2]<<finl;
2999 testResu<<"*************************"<<finl;
3000
3001 test2[face]=0.;
3002 test2[faces_associees(face)]=0.;
3003 }
3004 //
3005 //End of explicit operator computation and comparison
3006 //
3007
3008 Process::exit();
3009}
3010
DoubleTab & valeurs() override
Returns the array of field values at the current time.
class Cond_lim Generic class used to represent any class
Definition Cond_lim.h:31
Classe Dirichlet_homogene This class is the base class of the hierarchy of homogeneous Dirichlet-type...
Dirichlet This class is the base class of the hierarchy of Dirichlet-type boundary conditions.
Definition Dirichlet.h:31
const Sous_Domaine_t & ss_domaine(int i) const
Definition Domaine.h:290
int nb_faces_elem(int=0) const
Returns the number of faces of type i of the geometric elements that make up the domain.
Definition Domaine.h:484
int nb_cond_lim() const
Returns the number of boundary conditions.
const Cond_lim & les_conditions_limites(int) const
Returns the i-th boundary condition.
class Domaine_VEF
Definition Domaine_VEF.h:53
int nb_faces() const
Returns the total number of faces.
Definition Domaine_VF.h:471
int nb_faces_tot() const
Returns the total number of faces.
Definition Domaine_VF.h:481
virtual double face_normales(int face, int comp) const
Definition Domaine_VF.h:47
const IntTab & get_num_fac_loc() const
Definition Domaine_VF.h:140
int elem_faces(int i, int j) const
Returns the index of the i-th face of element num_elem; the face numbering convention is.
Definition Domaine_VF.h:542
int face_voisins(int num_face, int i) const
Returns the neighbouring element of num_face in direction i.
Definition Domaine_VF.h:418
int nb_faces_bord() const
Returns the number of faces on which boundary conditions are applied:
Definition Domaine_VF.h:512
class Domaine_dis_base This class is the base of the hierarchy of discretized domains.
int nombre_de_sous_domaines_dis() const
int nb_elem_tot() const
const Sous_domaine_dis_base & sous_domaine_dis(int i) const
const Domaine & domaine() const
Echange_impose_base: This boundary condition is used only for the energy equation.
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual const Milieu_base & milieu() const =0
virtual const Champ_Inc_base & inconnue() const =0
Probleme_base & probleme()
Returns the problem associated with the equation.
Schema_Temps_base & schema_temps()
Returns the time scheme associated with the equation.
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
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
Sortie & imprimer_formatte(Sortie &s) const override
DoubleVect & ajouter_multvect_(const DoubleVect &, DoubleVect &) const override
Operation de multiplication-accumulation (saxpy) matrice vecteur.
DoubleVect & porosite_elem()
Definition Milieu_base.h:58
DoubleVect & porosite_face()
Definition Milieu_base.h:62
const Equation_base & equation() const
Returns the reference to the equation pointed to by MorEqn::mon_equation.
Definition MorEqn.h:62
Classe Neumann_homogene This class is the base class of the hierarchy of homogeneous Neumann-type bou...
double val_ext(int i) const override
Returns the value of the i-th component of the field imposed on the exterior of the boundary.
Classe Neumann_val_ext This class is the base class of the hierarchy of.
Classe Neumann This class is the base class of the hierarchy of Neumann-type boundary conditions.
Definition Neumann.h:31
static int dimension
Definition Objet_U.h:94
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
virtual int est_egal_a(const Objet_U &) const
Returns 1 if x and *this are the same instance (same memory address).
Definition Objet_U.cpp:299
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
class Op_Conv_EF_VEF_P1NC_Stab
DoubleTab & ajouter(const DoubleTab &, DoubleTab &) const override
DoubleTab & ajouter_diffusion(const DoubleTab &, const DoubleTab &, DoubleTab &) const
void completer() override
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its equation.
void ajouter_contribution_diffusion(const DoubleTab &, const DoubleTab &, Matrice_Morse &) const
void calculer_coefficients_operateur_centre(DoubleTab &, const int, const DoubleTab &vitesse) const
public_for_cuda void calculer_flux_bords(const DoubleTab &, const DoubleTab &, const DoubleTab &) const
void ajouter_contribution_operateur_centre(const DoubleTab &, const DoubleTab &, Matrice_Morse &) const
DoubleTab & ajouter_operateur_centre(const DoubleTab &, const DoubleTab &, DoubleTab &) const
DoubleTab & ajouter_partie_compressible(const DoubleTab &, DoubleTab &, const DoubleTab &vitesse) const
DoubleTab & ajouter_antidiffusion(const DoubleTab &, const DoubleTab &, DoubleTab &) const
void modifier_pour_Cl(Matrice_Morse &, DoubleTab &) const override
DOES NOTHING - to override in derived classes.
void mettre_a_jour_pour_periodicite(DoubleTab &) const
void ajouter_contribution(const DoubleTab &, Matrice_Morse &) const override
class Op_Conv_VEF_Face
void dimensionner(Matrice_Morse &) const override
Size the matrix using the dimensionner method of class Op_VEF_Face.
virtual void ajouter_contribution(const DoubleTab &, Matrice_Morse &) const
void modifier_pour_Cl(Matrice_Morse &, DoubleTab &) const override
Modify the right-hand side and the matrix for Dirichlet conditions.
void completer() override
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its equation.
int phi_u_transportant(const Equation_base &eq) const
Defines whether psi is convected with phi*u or with u.
const Champ_Inc_base & vitesse() const
void modifier_flux(const Operateur_base &) const
DoubleTab flux_bords_
DoubleTab & flux_bords()
class Periodique This class represents a periodic boundary condition.
Definition Periodique.h:31
int face_associee(int i) const
Definition Periodique.h:35
const Domaine & domaine() const
Returns the domain associated with the problem.
static KOKKOS_INLINE_FUNCTION void Kokkos_exit(const char *)
Exit routine for TRUST within a Kokkos region.
Definition Process.h:172
static Sortie & Journal(int message_level=0)
Returns a static Sortie object used as an event journal.
Definition Process.cpp:592
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
double temps_courant() const
Returns the current time.
Base class for output streams.
Definition Sortie.h:52
This abstract class contains the geometrical subdomain information common to finite-volume methods (V...
const IntTab & les_faces() const
const Sous_Domaine & sous_domaine() const
Symetrie On symmetry faces, the following properties hold:
Definition Symetrie.h:37
_SIZE_ size_array() const
int nb_dim() const
Definition TRUSTTab.h:199
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
_SIZE_ size() const
Definition TRUSTVect.tpp:45
int line_size() const
Definition TRUSTVect.tpp:67