TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Parcours_interface.cpp
1/****************************************************************************
2* Copyright (c) 2015 - 2016, 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 <Double.h>
17#include <Parcours_interface.h>
18#include <Domaine_VF.h>
19#include <Domaine.h>
20#include <TRUST_Deriv.h>
21#include <Comm_Group.h>
22#include <Connectivite_frontieres.h>
23#include <Param.h>
24#include <Scatter.h>
25#include <Debog.h>
26#include <FTd_tools.h>
27#include <IJK_Navier_Stokes_tools.h>
28
29//#define EXTENSION_TRIANGLE_POUR_CALCUL_INDIC_AVEC_CONSERVATION_FACETTE_COIN
30Implemente_instanciable_sans_constructeur(Parcours_interface,"Parcours_interface",Objet_U);
31
32static int flag_warning_code_missing=1;
33
35{
36 Param param(que_suis_je());
37 param.ajouter_flag("correction_parcours_thomas", &correction_parcours_thomas_);
38 param.ajouter_flag("parcours_sans_tolerance", &parcours_sans_tolerance_);
39 param.ajouter("Erreur_relative_maxi", &Erreur_relative_maxi_);
40 param.lire_avec_accolades_depuis(is);
41
42 if (refdomaine_vf_)
44 return is;
45}
46
48{
49 return os;
50}
51
52// ===================================================================
53// INITIALISATION DE L'OBJET
54// ===================================================================
55
64
65
66// Calcul de la valeur maximale des coordonnees du maillage fixe:
68{
69 const DoubleTab& coord_som = refdomaine_vf_->domaine().coord_sommets();
70 Valeur_max_coordonnees_ = mp_max_abs_vect(coord_som);
72}
73/*! @brief Remplissage des variables persistantes de la classe (refdomaine_vf_, nb_faces_elem_, nb_elements_reels_, type_element_,
74 *
75 * equations_plans_faces_).
76 *
77 */
79{
80 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis);
81 assert(!refdomaine_vf_);
82 refdomaine_vf_ = domaine_vf;
83 nb_faces_elem_ = domaine_vf.domaine().nb_faces_elem();
84 nb_elements_reels_ = domaine_vf.domaine().nb_elem();
85 nb_sommets_par_face_ = domaine_vf.nb_som_face();
90
92
93 // Remplissage du tableau equations_plans_faces_
94 {
95 const int nb_faces = domaine_vf.nb_faces();
96 const int dimension3 = (Objet_U::dimension == 3);
97 int i;
98 double a, b, c = 0., d;
99 double x, y = 0., z = 0.;
100 double inverse_norme;
101 equations_plans_faces_.resize(nb_faces, 4);
102 for (i = 0; i < nb_faces; i++)
103 {
104 x = domaine_vf.xv(i, 0);
105 if (Objet_U::bidim_axi && x == 0.)
106 {
107 // Cas particulier: la normale est nulle sur l'axe (surface nulle)
108 // la normale pointe de gauche a droite en VDF.
109 a = 1.;
110 b = 0.;
111 }
112 else
113 {
114 a = domaine_vf.face_normales(i, 0);
115 b = domaine_vf.face_normales(i, 1);
116 y = domaine_vf.xv(i, 1);
117 if (dimension3)
118 {
119 c = domaine_vf.face_normales(i, 2);
120 z = domaine_vf.xv(i, 2);
121 }
122 inverse_norme = 1. / sqrt(a*a + b*b + c*c);
123 a *= inverse_norme;
124 b *= inverse_norme;
125 c *= inverse_norme;
126 }
127 d = - (a * x + b * y + c * z);
128 equations_plans_faces_(i, 0) = a;
129 equations_plans_faces_(i, 1) = b;
130 equations_plans_faces_(i, 2) = c;
131 equations_plans_faces_(i, 3) = d;
132 }
133 }
134 const Nom& nom_elem = domaine_vf.domaine().type_elem()->que_suis_je();
135 if (nom_elem == "Rectangle")
137 else if (nom_elem == "Rectangle_2D_axi")
139 else if (nom_elem == "Triangle")
141 else if (nom_elem == "Tetraedre")
143 else if (nom_elem == "Hexaedre")
145 else
146 {
147 Cerr << "Parcours_interface::associer_domaine_vf\n";
148 Cerr << " Le type d'element " << nom_elem;
149 Cerr << " n'est pas reconnu !\n";
151 }
152}
153
155{
156 refconnect_front_ = connect;
157}
158
159// ===================================================================
160// METHODE PUBLIQUE : parcours de l'interface
161// ===================================================================
162
163// Boucle sur les facettes :
164// Remplissage de intersections_elem_facettes_
165// Completion du maillage (facettes sur les "processeurs pauvres")
166// (ajout de noeuds virtuels, de facettes virtuelles, et completion
167// des espaces distants et virtuels)
168
170{
171 assert(refdomaine_vf_);
172
173 const Domaine_VF& domaine_vf = refdomaine_vf_.valeur();
174 domaine_elem_ptr = & domaine_vf.domaine().les_elems();
175 domaine_sommets_ptr = & domaine_vf.domaine().les_sommets();
176
177 DoubleTab copie_sommets_maillage;
179 {
180 // Modification pour eliminer les erreurs de calcul de l'indicatrice
181 // Le calcul produit des resultats aleatoires si les sommets du maillage lagrangien
182 // se trouvent exactement sur une face d'un element eulerien (on risque de compter
183 // deux fois des contributions de volume). On deplace donc legerement les sommets
184 // pour les eloigner des faces.
185 //
186 // REMARQUE IMPORTANTE : a la fin de la procedure, on remettre
187 // les sommets du maillage lagrangien dans leur etat initial
188 copie_sommets_maillage = maillage.sommets();
190 }
191
192 // RAZ des intersections elements-facettes
193 {
194 const int nb_elem = domaine_vf.nb_elem();
195 const int nb_facettes = maillage.facettes_.dimension(0);
196 maillage.intersections_elem_facettes_.reset(nb_elem, nb_facettes);
197 }
198
199 // Facettes et elements d'arrivee a envoyer aux processeurs voisins pour l'iteration
200 // suivante:
201 static ArrOfIntFT echange_facettes_numfacette;
202 static ArrOfIntFT echange_facettes_numelement;
203 // Facettes et elements d'arrivee de la liste de facette en cours de traitement
204 // a l'iteration courante:
205 static ArrOfIntFT facettes_a_traiter_numfacette;
206 static ArrOfIntFT facettes_a_traiter_numelement;
207
209 int nb_facettes_echangees = 0;
210 int iteration = 0;
211
212 do
213 {
214 echange_facettes_numfacette.resize_array(0);
215 echange_facettes_numelement.resize_array(0);
216
217 // Au premier passage, la liste des facettes a traiter est vide,
218 // on traite toutes les facettes du domaine
219 if (iteration == 0)
220 {
221 int nb_facettes = maillage.facettes_.dimension(0);
222 for (int i = 0; i < nb_facettes; i++)
223 {
224 // Le parcours commence par l'element qui contient le premier
225 // sommet, si la facette m'appartient (element_depart >= 0)
226 int premier_sommet = maillage.facettes_(i,0);
227 int element_depart = maillage.sommet_elem_[premier_sommet];
228 if (element_depart >= 0)
229 parcours_facette(domaine_vf, maillage,
230 echange_facettes_numfacette,
231 echange_facettes_numelement,
232 i, element_depart);
233 }
234 }
235 else
236 {
237 // Aux passages suivants, on traite uniquement la liste
238 int nb_facettes = facettes_a_traiter_numfacette.size_array();
239 for (int i = 0; i < nb_facettes; i++)
240 {
241 int num_facette = facettes_a_traiter_numfacette[i];
242 int element_depart = facettes_a_traiter_numelement[i];
243 parcours_facette(domaine_vf, maillage,
244 echange_facettes_numfacette,
245 echange_facettes_numelement,
246 num_facette, element_depart);
247 }
248 }
249
250 // Echange des facettes entre processeurs, on recupere
251 // la liste des facettes a traiter et l'element d'arrivee.
252 maillage.echanger_facettes(echange_facettes_numfacette,
253 echange_facettes_numelement,
254 facettes_a_traiter_numfacette,
255 facettes_a_traiter_numelement);
256 // Arret lorsque plus aucun processeur n'a de facettes a traiter.
257 nb_facettes_echangees = Process::check_int_overflow(Process::mp_sum(facettes_a_traiter_numfacette.size_array()));
258 Process::Journal() << " nombre de faces echangees : ";
259 Process::Journal() << facettes_a_traiter_numfacette.size_array() << " (total ";
260 Process::Journal() << nb_facettes_echangees << ")" << finl;
261 iteration++;
262 }
263 while (nb_facettes_echangees > 0);
264
266 {
267 //Modification pour eliminer les erreurs de calcul de l'indicatrice
268 //REMARQUE IMPORTANTE : on remet le maillage dans son etat initial
269 //Ceci est possible car la classe Parcours_interface est une classe
270 //amie de Maillage_FT_Disc
271 // Il y a de nouveaux sommets virtuels dans le maillage (mais pas de changement de proprietaire)
272 // il faut mettre a jour le tableau.
273 const int ni = maillage.sommets_.dimension(0);
274 const int nj = maillage.sommets_.dimension(1);
275 copie_sommets_maillage.resize(ni, nj);
276 maillage.desc_sommets().echange_espace_virtuel(copie_sommets_maillage);
277 maillage.sommets_ = copie_sommets_maillage;
278 }
279
280 Process::Journal() << " comptage erreurs_grossieres=";
282 Process::Journal() << "FIN Parcours_interface::parcourir"<<finl;
283
284}
285
286// ==========================================================================
287// ==========================================================================
288// ==========================================================================
289
290static void effacer_drapeaux_elements_parcourus(
291 ArrOfBit& drapeaux_elements_parcourus,
292 const ArrOfInt& liste_elements_parcourus)
293{
294 // Remise a zero des drapeaux pour la prochaine fois
295 // (efficace : on ne reinitialise que les drapeaux qui sont mis)
296 int n = liste_elements_parcourus.size_array();
297 for (int i = 0; i < n; i++)
298 {
299 const int element = liste_elements_parcourus[i];
300 drapeaux_elements_parcourus.clearbit(element);
301 }
302}
303
304// Calcul de l'equation de plan d'une face d'un element eulerien. Pour un point (x,y,z),
305// la fonction (a*x+b*y+c*z+d) * signe est positive a l'interieur de l'element,
306// negative a l'exterieur. La normale (a,b,c) est unitaire.
307// Parametre: domaine_vf
308// Signification: reference au Domaine_VF. Attention, ce doit etre la meme domaine que celle qui
309// a ete associee au parcours !!!
310// Parametre: num_element
311// Signification: numero d'un element reel du domaine (0 <= num_element < elem_faces().dimension(0))
312// Parametre: num_face_element
313// Signification: numero d'une face de l'element (0 <= num_face_element < elem_faces().dimension(1))
314// Parametre: a,b,c,d
315// Signification: on y met les coefficients du plan: normale (a,b,c) et constante d
316// Valeur de retour : signe (1. ou -1.)
317inline double Parcours_interface::calcul_eq_plan(const Domaine_VF& domaine_vf,
318 const int num_element,
319 const int num_face_element,
320 double& a, double& b, double& c, double& d) const
321{
322 assert((&domaine_vf) == (&(refdomaine_vf_.valeur())));
323 // Numero de la face i
324 const int num_face = domaine_vf.elem_faces(num_element, num_face_element);
325 // Numero du premier element voisin de la face
326 const int elem_voisin = domaine_vf.face_voisins(num_face, 0);
327 // Equation du plan contenant la face
328 a = equations_plans_faces_(num_face, 0);
329 b = equations_plans_faces_(num_face, 1);
330 c = equations_plans_faces_(num_face, 2);
331 d = equations_plans_faces_(num_face, 3);
332
333 if (elem_voisin == num_element)
334 return -1.;
335 else
336 return 1.;
337}
338
339// Parcours des elements euleriens traverses par la facette specifiee,
340// de proche en proche, en commencant par l'element_depart.
341
343 Maillage_FT_Disc& maillage,
344 ArrOfInt& echange_facettes_numfacette,
345 ArrOfInt& echange_facettes_numelement,
346 int num_facette,
347 int element_depart) const
348{
349 const int dimension3 = (Objet_U::dimension == 3);
350
351 Intersections_Elem_Facettes& intersections =
353
354 static ArrOfIntFT liste_elements_parcourus;
355 static ArrOfIntFT elements_a_traiter;
356 static ArrOfIntFT new_elements_a_traiter;
357
358 // Initialisation des drapeaux des elements deja traites pour cette facette
359 // Hypothese : on suppose que drapeaux_elements_parcourus_ est initialise
360 // a zero quand on arrive ici
361 {
362 intersections.get_liste_elements_traverses(num_facette,
363 liste_elements_parcourus);
364 int n = liste_elements_parcourus.size_array();
365 for (int i = 0; i < n; i++)
366 {
367 const int element = liste_elements_parcourus[i];
368 drapeaux_elements_parcourus_.setbit(element);
369 }
370 }
371
372 if (drapeaux_elements_parcourus_[element_depart])
373 {
374 effacer_drapeaux_elements_parcourus(drapeaux_elements_parcourus_,
375 liste_elements_parcourus);
376 return;
377 }
378
379 // Initialisation du "front" d'elements a traiter
380 elements_a_traiter.resize_array(1);
381 elements_a_traiter[0] = element_depart;
382 liste_elements_parcourus.append_array(element_depart);
383 drapeaux_elements_parcourus_.setbit(element_depart);
384
385 // Boucle sur les fronts successifs d'elements traverses par la facette
386 // ********************************************************************
387 do
388 {
389 new_elements_a_traiter.resize_array(0);
390 const int n = elements_a_traiter.size_array();
391
392 // Boucle sur les elements du front
393 // ************************************************
394 for (int i = 0; i < n; i++)
395 {
396 const int element = elements_a_traiter[i];
397
398 // Calcul de l'intersection facette_element
399 int code_retour;
400 if (dimension3)
401 code_retour = calcul_intersection_facelem_3D(domaine_vf, maillage,
402 num_facette, element);
403 else
404 code_retour = calcul_intersection_facelem_2D(domaine_vf, maillage,
405 num_facette, element);
406 // Decryptage du code retour
407 // S'il est negatif, erreur grossiere dans l'algorithme...
408 // En debug, on regarde de pres, en production, on ferme les yeux.
409 if (code_retour < 0)
410 {
411 Journal() << "code_retour<0" << finl;
412 continue;
413 }
414 for (int j = 0; j < nb_faces_elem_; j++)
415 {
416 const int masque = 1 << j;
417
418 // La facette traverse-t-elle la face j ?
419 if ((code_retour & masque) == 0)
420 continue;
421
422 // Numero de l'element voisin
423 const int num_face = domaine_vf.elem_faces(element, j);
424 const int elem_voisin = domaine_vf.face_voisins(num_face, 0)
425 + domaine_vf.face_voisins(num_face, 1)
426 - element;
427
428 // S'il n'y a pas de voisin, on est au bord du domaine
429 if (elem_voisin < 0)
430 continue;
431
432 if (elem_voisin < nb_elements_reels_)
433 {
434 // Si c'est un element reel, et qu'il n'a pas encore ete
435 // parcouru, on l'ajoute a la liste des elements
436 // a parcourir dans le front suivant. On marque l'element
437 // pour ne pas l'ajouter plusieurs fois a la liste.
438 if ( ! drapeaux_elements_parcourus_.testsetbit(elem_voisin))
439 {
440 liste_elements_parcourus.append_array(elem_voisin);
441 new_elements_a_traiter.append_array(elem_voisin);
442 }
443 }
444 else
445 {
446 // Si le voisin est un element virtuel, il faut transmettre
447 // au processeur voisin. On stocke le numero de la facette
448 // et l'element voisin.
449 echange_facettes_numfacette.append_array(num_facette);
450 echange_facettes_numelement.append_array(elem_voisin);
451 }
452 }
453 }
454 // ************************************************
455 // Mise a jour du "front" des elements a traiter
456 elements_a_traiter = new_elements_a_traiter;
457 }
458 while (elements_a_traiter.size_array() > 0);
459 // ********************************************************************
460
461 effacer_drapeaux_elements_parcourus(drapeaux_elements_parcourus_,
462 liste_elements_parcourus);
463}
464
465// ==========================================================================
466// ==========================================================================
467
468// Calcul de l'intersection entre une facette et un element eulerien.
469// Code de retour :
470// -1 si l'intersection est vide (pas normal)
471// >=0 : les bits du code retour indiquent les plans de l'element
472// qui coupent la facette (bit 0 : premiere face de l'element,
473// bit 1 : deuxieme face, etc...)
474
476 const Domaine_VF& domaine_vf,
477 Maillage_FT_Disc& maillage,
478 int num_facette, int num_element) const
479{
480 assert(Objet_U::dimension == 2);
481
482 const int sommet0 = maillage.facettes_(num_facette, 0);
483 const int sommet1 = maillage.facettes_(num_facette, 1);
484 // Extremites du segment.
485 double x0 = maillage.sommets_(sommet0, 0);
486 double y0 = maillage.sommets_(sommet0, 1);
487 double x1 = maillage.sommets_(sommet1, 0);
488 double y1 = maillage.sommets_(sommet1, 1);
489
490 // Extremites du segment tronque (coordonnees barycentriques)
491 double u0 = 1.;
492 double u1 = 0.;
493
494 // Estimation de l'incertitude sur l'evaluation de la fonction plan
495 double Zero = - Erreur_max_coordonnees_;
496 double tolerance_comparaisons = Objet_U::precision_geom;
498 Zero = 0.;
500 tolerance_comparaisons = 0.;
501 // Extension du segment si un sommet au bord
502 {
503 const double dx = x1 - x0;
504 const double dy = y1 - y0;
505 double l = sqrt(dx * dx + dy * dy);
506 if (l > 0.)
507 l = 1. / l;
508 const double ext = 4* Erreur_max_coordonnees_ * l;
509 if (maillage.sommet_ligne_contact(sommet0))
510 {
511 x0 -= ext * dx;
512 y0 -= ext * dy;
513 }
514 else if (maillage.sommet_ligne_contact(sommet1))
515 {
516 x1 += ext * dx;
517 y1 += ext * dy;
518 }
519 }
520
521 // Numero de la face qui genere l'extremite de l'intersection
522 // (-1 -> pas d'intersection avec le bord de l'element)
523 int plan_coupe0 = -1;
524 int plan_coupe1 = -1;
525
526 // *********************************************************************
527 // *********************************************************************
528 // Calcul de l'intersection de la facette avec les plans qui
529 // definissent l'element
530 for (int num_plan = 0; num_plan < nb_faces_elem_; num_plan++)
531 {
532 // Coefficients de la fonction qui definit le plan (c est nul en 2D).
533 double a, b, c, d;
534 double signe = calcul_eq_plan(domaine_vf, num_element, num_plan, a, b, c, d);
535 // Calcul de la fonction f aux deux extremites du segment d'origine
536 const double f_0 = (a * x0 + b * y0 + d) * signe;
537 const double f_1 = (a * x1 + b * y1 + d) * signe;
538 // Calcul de la fonction aux extremites du segment tronque.
539 const double f0 = f_0 * u0 + f_1 * (1. - u0);
540 const double f1 = f_0 * u1 + f_1 * (1. - u1);
541 const int s0_dehors = inf_strict(f0,Zero,tolerance_comparaisons) ? 1 : 0;
542 const int s1_dehors = inf_strict(f1,Zero,tolerance_comparaisons) ? 1 : 0;
543
544 if (s0_dehors + s1_dehors == 1)
545 {
546 // Un point dedans et un dehors, on calcule l'intersection
547 // Coordonnee barycentrique de l'intersection
548 double t = f1 / (f1 - f0);
549 if (t < 0.)
550 t = 0.;
551 else if (t > 1.)
552 t = 1.;
553 if (s0_dehors)
554 {
555 u0 = u0 * t + u1 * (1.-t);
556 plan_coupe0 = num_plan;
557 }
558 else
559 {
560 u1 = u0 * t + u1 * (1.-t);
561 plan_coupe1 = num_plan;
562 }
563 }
564 else if (s0_dehors + s1_dehors == 2)
565 {
566 // Les deux points sont a l'exterieur => pas d'intersection,
567 // c'est un probleme interne de l'algorithme.
569 return -1;
570 }
571 }
572 // *********************************************************************
573 // *********************************************************************
574 // Calcul du centre de gravite de l'intersection et de la contribution
575 // de volume.
576
577 // Coordonnee barycentrique du centre de gravite de l'intersection:
578 double u_centre = (u0 + u1) * 0.5;
579 // Surface d'intersection (fraction entre 0 et 1):
580 double surface = u0 - u1;
581 // En cas d'erreur d'arrondi ...
582 if (inf_strict(surface,0.)) surface = 0.;
583 // Contribution de volume :
584 double volume = 0.;
585 // Contribution d'aire et de barycentre aux faces :
586 double aire_faces[3] = {0., 0., 0.};
587 double barycentre_faces[3][2] = {{0., 0.}, {0., 0.}, {0., 0.}};
588 // Computation of barycenter in phase 1 :
589 double barycentre_phase1[3] = {0.,0.,0.};
590
591 // Si on passe par un coin, on ne veut pas faire de calcul de contribution,
592 // il risque d'etre faux. Une erreur relative a chaque extremite. On ajoute
593 // Un facteur 2.5 pour etre sur.
595 {
596 // Calcul des coordonnees des extremites de l'intersection:
597 double ix0 = x0 * u0 + x1 * (1.-u0);
598 double iy0 = y0 * u0 + y1 * (1.-u0);
599 double ix1 = x0 * u1 + x1 * (1.-u1);
600 double iy1 = y0 * u1 + y1 * (1.-u1);
601 switch(type_element_)
602 {
603 case RECTANGLE:
604 volume = volume_rectangle_barycentre(domaine_vf, num_element,
605 ix0, iy0, ix1, iy1,
607 barycentre_phase1);
608 break;
609 case TRIANGLE:
610 if (flag_warning_code_missing)
611 {
612 Cerr << "WARNING : barycentre_phase1 not filled properly!!" << finl;
613 Cerr << "WARNING : Calculation of barycentre_phase1 not implemented yet." << finl;
614 }
615 volume = volume_triangle(domaine_vf, num_element,
616 ix0, iy0, ix1, iy1,
617 plan_coupe0, plan_coupe1);
618 break;
619 default:
620 Process::exit();// qu'est-ce qu'on fout la ?
621 break;
622 }
623 }
624
625 // Stockage des donnees relatives a cette intersection
627 num_element,
628 surface,
629 volume,
630 barycentre_phase1,
631 aire_faces,
632 barycentre_faces,
633 u_centre,
634 1. - u_centre,
635 0.);
636 // Calcul du code retour
637 int code_retour = 0;
638 if (plan_coupe0 >= 0)
639 code_retour |= 1 << plan_coupe0;
640 if (plan_coupe1 >= 0)
641 code_retour |= 1 << plan_coupe1;
642 return code_retour;
643}
644
645
646
647// TODO (teo boutin) rewrite this as doxygen
648// TODO (teo boutin) make optional the computation of the barycenter.
649
650// Calcul de la contribution de volume d'une facette a la valeur de
651// l'indicatrice dans un element. C'est une fraction du volume de l'element
652// comprise entre Erreur_relative_maxi et 1.-Erreur_relative_maxi
653
654// 4 cas possibles :
655// v=B-A v=A+B v=B-A v=A+B
656// ----1------ ----0------ --0-------- --1-------- <- y_haut
657// | /: | | /: | | :\ | | :\ |
658// | 0 : | | 1 : | | : 1 | | : 0 |
659// | : : | | : : | | : : | | : : |
660// |B :A: | | :A: B | | :A: B | | B:A: |
661// |+ :-: | | :+: + | | :-: + | | +:+: |
662// | : : | | : : | | : : | | : : |
663// ----------- ----------- ----------- ----------- <- y_bas
664// ^ ^
665// x_gauche x_droite
666
667// as a side effects, also computes the barycenter, because this uses the
668
669// Parametres : x0, y0, x1, y1 : coordonnees de l'extremite de l'intersection
670// segment/element
671// plan_coupe0, plan_coupe1 : numeros de la face de l'element sur
672//
673//
675 const int num_element,
676 const double x0, const double y0,
677 const double x1, const double y1,
678 const double epsilon,
679 double bary[3]) const
680{
681 const double angle_bidim_axi = bidim_axi ? Maillage_FT_Disc::angle_bidim_axi() : 0.;
682 constexpr double un_tiers = 1. / 3.;
683
684 // TODO Please define those kinf of global conventions in a more 'global' place
685 // Conventions TRUST VDF :
686 constexpr int NUM_FACE_GAUCHE = 0;
687 constexpr int NUM_FACE_BAS = 1;
688 constexpr int NUM_FACE_HAUT = 3;
689 constexpr int NUM_FACE_DROITE = 2;
690
691 const int face_bas = domaine_vf.elem_faces(num_element, NUM_FACE_BAS);
692 const int face_gauche = domaine_vf.elem_faces(num_element, NUM_FACE_GAUCHE);
693 const int face_droite = domaine_vf.elem_faces(num_element, NUM_FACE_DROITE);
694 const int face_haut = domaine_vf.elem_faces(num_element, NUM_FACE_HAUT);
695 const double y_bas = domaine_vf.xv(face_bas, 1);
696 const double x_gauche = domaine_vf.xv(face_gauche, 0);
697 const double x_droite = domaine_vf.xv(face_droite, 0);
698 const double y_haut = domaine_vf.xv(face_haut, 1);
699
700 // Volume de l'element
701 double v_elem = (x_droite - x_gauche) * (y_haut - y_bas);
702 if (bidim_axi)
703 v_elem *= (x_droite + x_gauche) * 0.5 * angle_bidim_axi;
704
705 // Volume de la partie A (avec signe)
706 double v = (x0 - x1) * ((y0 + y1) * 0.5 - y_bas);
707 bary[0] = (x0 - x1) * ((y0 + y1) * 0.5 - y_bas);
708 bary[1] = (x0 - x1) * ((y0 + y1) * 0.5 - y_bas);
709 // Integral(2pi*r**2 dr) / Integral(2pi*r**2 dr) between r0 and r1
710 if (bidim_axi)
711 {
712 const double s0 = (x1 - x0) * (y0 - y_bas);
713 const double s1 = (x1 - x0) * (y1 - y_bas);
714
715
716 // this test matches only if x1==x0 || y0 + y1 == 2*y_bas.
717 // Either this is used to detect that some elemnts are exactly the same, and then this is the wrong way of doing it.
718 // Or this comparison is simply not working as intended because of float precision
719 assert(s0 + s1 != 0); // I am 100% certain we will never trigger this, this is just for demonstration
720
721 if (s0 + s1 != 0. )
722 {
723 v *= ((x0 + x0 + x1) * s0 + (x0 + x1 + x1) * s1) / (s0 + s1);
724 }
725
726 v *= un_tiers * angle_bidim_axi;
727 const double xx1 = x1*x1;
728 const double xx0 = x0*x0;
729 if (fabs(xx1-xx0)>DMINFLOAT)
730 bary[0] = 2.*un_tiers*(xx1*x1-xx0*x0)/(xx1-xx0);
731 else
732 bary[0] = x0;
733 }
734 else
735 bary[0] = (x0 + x1) *0.5;
736
737 bary[1] = ((y0 + y1) * 0.5 + y_bas) * 0.5;
738
739 // Ajout du volume de B si on touche le bord haut
740 double v2 = 0.;
741 double bary2[2] = {0.,0.};
742 if (y0 > y_haut - epsilon)
743 {
744 v2 = (x_droite - x0) * (y_haut - y_bas);
745 if (bidim_axi)
746 v2 *= (x_droite + x0) * 0.5 * angle_bidim_axi;
747 }
748 else if (y1 > y_haut - epsilon)
749 {
750 v2 = (x1 - x_gauche) * (y_haut - y_bas);
751 if (bidim_axi)
752 v2 *= (x1 + x_gauche) * 0.5 * angle_bidim_axi;
753 }
754 else if (x1 > x0)
755 {
756 v2 = v_elem;
757 }
758
759 if (y0 > y_haut - epsilon)
760 {
761 if (bidim_axi)
762 {
763 double xx1 = x_droite*x_droite;
764 double xx0 = x0*x0;
765 if (fabs(xx1-xx0)>DMINFLOAT)
766 bary2[0] = 2.*un_tiers*(xx1*x_droite-xx0*x0)/(xx1-xx0);
767 }
768 else
769 bary2[0] = (x_droite + x0) * 0.5;
770
771 bary2[1] = (y_haut + y_bas) * 0.5;
772 }
773 else if (y1 > y_haut - epsilon)
774 {
775 if (bidim_axi)
776 {
777 const double xx1 = x1*x1;
778 const double xx0 = x_gauche*x_gauche;
779 if (fabs(xx1-xx0)>DMINFLOAT)
780 bary2[0] = 2.*un_tiers*(xx0*x_gauche-xx1*x1)/(xx0-xx1);
781 }
782 else
783 bary2[0] = (x_gauche + x0) * 0.5;
784
785 bary2[1] = (y_haut + y_bas) * 0.5;
786
787 }
788 else if (x1 > x0)
789 {
790 bary2[0] = (x_gauche + x_droite) * 0.5;
791 if (bidim_axi)
792 if (fabs(x_gauche-x_droite)>DMINFLOAT)
793 {
794 bary2[0] = 2.*un_tiers*(x_droite*x_droite*x_droite-x_gauche*x_gauche*x_gauche)/(x_droite*x_droite-x_gauche*x_gauche);
795 }
796 bary2[1] = (y_haut + y_bas) * 0.5;
797 }
798
799 if ((v+v2)>DMINFLOAT)
800 for (int i=0; i<2; i++)
801 bary[i] = (bary[i]*v + bary2[i]*v2) / (v+v2);
802
803 bary[2] = 0.; // In 2D, nothing on z.
804 v = (v + v2) / v_elem;
805
806 // (teo boutin) est ce qu'on veut vraiment fixer à Erreur_relative_maxi_ ?
807 // ça me semble très bizarre, je ne vois pas de raison de ne pas mettre à 0. et 1.
808 // C'est aussi bizarre d'utiliser Erreur_relative_maxi_ comme une erreur absolue, mais on n'est plus à ça près
809 // On force la valeur entre 0 et 1 strictement.
810 if (v < Erreur_relative_maxi_)
812 else if (v > 1. - Erreur_relative_maxi_)
813 v = 1. - Erreur_relative_maxi_;
814
815 return v;
816}
817
818
819/*! @brief Calcul de la matrice 2x2 de transformation pour passer d'une coordonnee dans le repere (x,y) global a une coordonnee (u,v,1-u-v) barycentrique
820 *
821 * dans un element fini triangulaire.
822 * Le point 0 du triangle aura pour coordonnees (0,0,1)
823 * Le point 1 (1,0,0)
824 * Le point 2 (0,1,0)
825 *
826 */
827inline void Parcours_interface::matrice_triangle(int num_element,
828 FTd_vecteur2& origine,
829 FTd_matrice22& matrice,
830 double& surface) const
831{
832 const int s0 = (*domaine_elem_ptr)(num_element,0);
833 const int s1 = (*domaine_elem_ptr)(num_element,1);
834 const int s2 = (*domaine_elem_ptr)(num_element,2);
835 const double x0 = (*domaine_sommets_ptr)(s0, 0);
836 const double y0 = (*domaine_sommets_ptr)(s0, 1);
837 origine[0] = x0;
838 origine[1] = y0;
839 const double dx1 = (*domaine_sommets_ptr)(s1, 0) - x0;
840 const double dy1 = (*domaine_sommets_ptr)(s1, 1) - y0;
841 const double dx2 = (*domaine_sommets_ptr)(s2, 0) - x0;
842 const double dy2 = (*domaine_sommets_ptr)(s2, 1) - y0;
843
844 // [ dx1 dx2 ](-1) [ matrice[0][0] matrice[0][1] ]
845 // Inversion de la matrice:[ ] = [ ]
846 // [ dy1 dy2 ] [ matrice[1][0] matrice[1][1] ]
847 double det = dx1 * dy2 - dx2 * dy1;
848 surface = det * 0.5;
849 double inv_det = 1. / det;
850 matrice[0][0] = dy2 * inv_det;
851 matrice[0][1] = - dx2 * inv_det;
852 matrice[1][0] = - dy1 * inv_det;
853 matrice[1][1] = dx1 * inv_det;
854}
855
856/*! @brief Applique la transformation calculee par matrice_triangle a une coordonnee (x,y).
857 *
858 * Le resultat est stocke dans (u,v). La troisieme
859 * coordonnee barycentrique est implicitement egale a 1-u-v.
860 *
861 */
862inline void Parcours_interface::transformation_2d(const FTd_vecteur2& origine,
863 const FTd_matrice22& matrice,
864 double x, double y,
865 double& u, double& v) const
866{
867 x -= origine[0];
868 y -= origine[1];
869 u = matrice[0][0] * x + matrice[0][1] * y;
870 v = matrice[1][0] * x + matrice[1][1] * y;
871}
872
873/*! @brief Calcul de la contribution de volume d'une facette a la valeur de l'indicatrice dans un element.
874 *
875 * (x0,y0) et (x1,y1) sont les coordonnees
876 * de l'extremite du segment (obligatoirement a l'interieur du triangle
877 * ou sur un bord). plan_coupe* donne le numero de la face du triangle
878 * sur laquelle se trouve chacun des deux sommets du segment ou -1 si le
879 * sommet est strictement a l'interieur du triangle.
880 * C'est une fraction du volume de l'element comprise entre
881 * Erreur_relative_maxi et 1.-Erreur_relative_maxi
882 *
883 * sommet2
884 * ^ ordonnee=v
885 * |\.
886 * | \.
887 * | \.
888 * | \. face 0 (opposee au sommet 0)
889 * | \.
890 * | 0---1.
891 * | : A :\.
892 * | : :B\.
893 * -------- -> abscisse=u (coordonnees dans le triangle de reference : u,v)
894 * sommet0 sommet1
895 *
896 */
897inline double Parcours_interface::volume_triangle(const Domaine_VF& domaine_vf,
898 int num_element,
899 double x0, double y0,
900 double x1, double y1,
901 int plan_coupe0,
902 int plan_coupe1) const
903{
904 assert(!bidim_axi); // Pas prevu pour l'instant
905
906 static const int FACE_ZERO = 0; // Numero de la face opposee au sommet zero
907 double origine[2];
908 double matrice[2][2];
909 double surface_triangle;
910 double u0, v0, u1, v1;
911 // Calcul des coordonnees de l'intersection dans un repere local au triangle
912 matrice_triangle(num_element, origine, matrice, surface_triangle);
913 transformation_2d(origine, matrice, x0, y0, u0, v0);
914 transformation_2d(origine, matrice, x1, y1, u1, v1);
915
916 // Volume de la partie A (avec signe) sur le triangle de reference
917 double vol = (u0 - u1) * (v0 + v1) * 0.5;
918
919 // Ajout du volume B si on touche la face 0
920 if (plan_coupe0 == FACE_ZERO)
921 vol += (1. - u0) * (1. - u0) * 0.5;
922 else if (plan_coupe1 == FACE_ZERO)
923 vol -= (1. - u1) * (1. - u1) * 0.5;
924
925 if (vol < 0.)
926 vol += 0.5;
927
928 if (vol < Erreur_relative_maxi_)
930 else if (vol > 0.5 - Erreur_relative_maxi_)
931 vol = 0.5 - Erreur_relative_maxi_;
932
933 // le triangle de reference a un volume de 0.5, on ramene vol a une fraction:
934 vol = vol * 2.;
935 return vol;
936}
937
939{
940 double volume;
941 double barycentre[3];
942};
943
945{
946 double area;
947 double barycentre[2];
948};
949
950/*! @brief Cette methode permet de calculer l'intersection entre une facette et un element du maillage eulerien
951 *
952 * Precondition: dimension = 3
953 *
954 * @param (domaine_vf) domaine du calcul
955 * @param (maillage) description du maillage de l'interface
956 * @param (num_facette) indice de la facette intersectant
957 * @param (num_element) indice de l'element intersecte
958 * @return (int) 1 si ok, 0 si ??.
959 */
961 const Domaine_VF& domaine_vf,
962 Maillage_FT_Disc& maillage,
963 int num_facette, int num_element) const
964{
965 assert(Objet_U::dimension == 3);
966 int i,k;
967
968 // Polygone d'intersection entre la facette et l'element.
969 // On l'initialise avec la facette en entier.
970 // Il contient des coordonnees barycentriques.
971 static DoubleTabFT poly_(20,3);
972 static DoubleTabFT new_poly_(20,3);
973 // Polygone d'intersection entre la facette et l'element
974 // contenant les coordonnees reelles de l'element
975 static DoubleTabFT poly_reelles_(20,3);
976
977 poly_.resize(3,3);
978 poly_(0,0) = 1.;
979 poly_(0,1) = 0.;
980 poly_(0,2) = 0.;
981 poly_(1,0) = 0.;
982 poly_(1,1) = 1.;
983 poly_(1,2) = 0.;
984 poly_(2,0) = 0.;
985 poly_(2,1) = 0.;
986 poly_(2,2) = 1.;
987 double coord_som[3][3];
988 const int sommets[3] = { maillage.facettes_(num_facette, 0),
989 maillage.facettes_(num_facette, 1),
990 maillage.facettes_(num_facette, 2)
991 };
992 {
993 for (int ii = 0; ii < 3; ii++)
994 {
995 int s = sommets[ii];
996 for (int j = 0; j < 3; j++)
997 {
998 coord_som[ii][j] = maillage.sommets_(s, j);
999 }
1000 }
1001 }
1002 // Extension du triangle si deux sommets au bord
1003 {
1004 const double fact_mult = 1.;
1005 int isom,isom_s,isom_ss, kk;
1006 for (isom=0 ; isom<3 ; isom++)
1007 {
1008 isom_s = (isom+1)%3;
1009 if (maillage.sommet_ligne_contact(sommets[isom]) && maillage.sommet_ligne_contact(sommets[isom_s]))
1010 {
1011 isom_ss = (isom_s+1)%3;
1012 for (kk=0 ; kk<dimension ; kk++)
1013 {
1014 coord_som[isom][kk] += fact_mult * (coord_som[isom][kk] -coord_som[isom_ss][kk]);
1015 coord_som[isom_s][kk] += fact_mult * (coord_som[isom_s][kk]-coord_som[isom_ss][kk]);
1016 }
1017 break;//sortir au cas ou le 3e sommet soit aussi sur une ligne de contact (ce qui ne devrait normalement pas arriver...)
1018 }
1019 }
1020 }
1021 // Estimation de l'incertitude sur l'evaluation de la fonction plan
1022 double Zero = - Erreur_max_coordonnees_;
1023 double tolerance_comparaisons = Objet_U::precision_geom;
1025 Zero = 0.;
1027 tolerance_comparaisons = 0.;
1028
1029 // polygone_plan_coupe contient pour chaque segment du polygone
1030 // le numero du plan de l'element qui a genere ce segment.
1031 // polygone_plan_coupe_(1) est le plan qui genere le segment poly(0) - poly(1)
1032 // Il contient -1 si c'est un segment de la facette
1033 // d'origine.
1034 static ArrOfIntFT polygone_plan_coupe_(20);
1035 static ArrOfIntFT new_poly_plan_coupe_(20);
1036 polygone_plan_coupe_.resize_array(3);
1037 polygone_plan_coupe_ = -1;
1038
1039 // *********************************************************************
1040 // *********************************************************************
1041 // Calcul de l'intersection du polygone avec les plans qui
1042 // definissent l'element
1043 for (int num_plan = 0; num_plan < nb_faces_elem_; num_plan++)
1044 {
1045 new_poly_.resize(0,3);
1046 new_poly_plan_coupe_.resize_array(0);
1047 int n = 0;
1048 // Coefficients de la fonction qui definit le plan
1049 // "fonction plan" (x,y,z) = a*x + b*y + c*d + d
1050 double a, b, c, d;
1051 double signe = calcul_eq_plan(domaine_vf, num_element, num_plan, a, b, c, d);
1052 // Calcul de la "fonction plan" aux sommets de la facette
1053 const double f0 = (a * coord_som[0][0] + b * coord_som[0][1] + c * coord_som[0][2] + d) * signe;
1054 const double f1 = (a * coord_som[1][0] + b * coord_som[1][1] + c * coord_som[1][2] + d) * signe;
1055 const double f2 = (a * coord_som[2][0] + b * coord_som[2][1] + c * coord_som[2][2] + d) * signe;
1056
1057 // Recherche des points du polygone qui sont dans le demi-espace
1058 const int nb_sommets_poly = poly_.dimension(0);
1059 i = nb_sommets_poly - 1; // Le dernier sommet du polygone
1060 double u = poly_(i,0);
1061 double v = poly_(i,1);
1062 double w = poly_(i,2);
1063 // Calcul de la "fonction plan" au sommet du polygone
1064 double f = f0 * u + f1 * v + f2 * w;
1065 int sommet_dehors = inf_strict(f,Zero,tolerance_comparaisons) ? 1 : 0;
1066
1067 for (i = 0; i < nb_sommets_poly; i++)
1068 {
1069 int sommet_precedent_dehors = sommet_dehors;
1070 double u_prec = u;
1071 double v_prec = v;
1072 double f_prec = f;
1073 u = poly_(i,0);
1074 v = poly_(i,1);
1075 w = poly_(i,2);
1076 // Calcul de la "fonction plan" au sommet du polygone
1077 f = f0 * u + f1 * v + f2 * w;
1078 sommet_dehors = inf_strict(f,Zero,tolerance_comparaisons) ? 1 : 0;
1079 if (sommet_dehors + sommet_precedent_dehors == 1)
1080 {
1081 // Le dernier segment du polygone coupe le plan.
1082 // On calcule le point d'intersection
1083 // Coordonnee barycentrique de l'intersection sur le segment du polygone
1084 double t = f / (f - f_prec);
1085 if (t < 0.)
1086 t = 0.;
1087 else if (t > 1.)
1088 t = 1.;
1089 new_poly_.resize(n+1,3);
1090 // Coordonnee barycentrique de l'intersection sur la facette
1091 double new_u = u_prec * t + u * (1.-t);
1092 double new_v = v_prec * t + v * (1.-t);
1093 double new_w = 1. - new_u - new_v;
1094 new_poly_(n,0) = new_u;
1095 new_poly_(n,1) = new_v;
1096 new_poly_(n,2) = new_w;
1097 n++;
1098 const int num_plan_coupe = sommet_dehors ? polygone_plan_coupe_[i] : num_plan;
1099 new_poly_plan_coupe_.append_array(num_plan_coupe);
1100 }
1101 if (! sommet_dehors)
1102 {
1103 // Le dernier sommet est dedans, je le garde
1104 new_poly_.resize(n+1,3);
1105 new_poly_(n,0) = u;
1106 new_poly_(n,1) = v;
1107 new_poly_(n,2) = w;
1108 n++;
1109 const int num_plan_coupe = polygone_plan_coupe_[i];
1110 new_poly_plan_coupe_.append_array(num_plan_coupe);
1111 }
1112 }
1113 if (new_poly_.dimension(0) == 0)
1114 {
1115 // L'intersection est vide: c'est anormal
1117 return -1;
1118 }
1119 poly_ = new_poly_;
1120 polygone_plan_coupe_ = new_poly_plan_coupe_;
1121 }
1122 // *********************************************************************
1123 const int nb_sommets_poly = poly_.dimension(0);
1124 // Contribution d'aire et de barycentre aux faces :
1125 double aire_faces[3] = {0., 0., 0.};
1126 double barycentre_faces[3][2] = {{0., 0.}, {0., 0.}, {0., 0.}};
1127 // Calcul du centre de gravite et de la surface de l'intersection
1128 double volume = 0.;
1129 double surface = 0.;
1130 double u_centre = 0.;
1131 double v_centre = 0.;
1132 {
1133 i = nb_sommets_poly - 1; // Le dernier sommet du polygone
1134 double u = poly_(i,0);
1135 double v = poly_(i,1);
1136 for (i = 0; i < nb_sommets_poly; i++)
1137 {
1138 double u_prec = u;
1139 double v_prec = v;
1140 u = poly_(i,0);
1141 v = poly_(i,1);
1142 //calcul de la contribution de l'arete a l'aire :
1143 // par la somme algebrique des aires des trapezes (generes par la projection de l'arete sur l'axe u=0)
1144 double contrib_surface = (v - v_prec) * (u + u_prec) * 0.5;
1145 if (contrib_surface!=0.)
1146 {
1147 //calcul du centre de gravite X du trapeze :
1148 // v > |------------\.
1149 // | |\.
1150 // | | \.
1151 // vX > | X | \.
1152 // | | \.
1153 //H v_prec > |------------|----\.
1154 // ^ ^ ^ ^
1155 // 0 uX u u_prec
1156 double B = std::max(u,u_prec); //grande base du trapeze
1157 double b = std::min(u,u_prec); //petite base du trapeze
1158 double h = std::fabs(v - v_prec); //hauteur du trapeze
1159 //le CdG du trapeze : le CdG des CdG du rectangle et du triangle
1160 double Sr = b * h;
1161 double CdGrX = b/2.;
1162 double CdGrY = (v+v_prec)/2.;
1163 double St = (B-b) * h/2.;
1164 double CdGtX = (2.*b+B)/3.;
1165 double CdGtY = v+v_prec;
1166 if (u<u_prec)
1167 {
1168 CdGtY += v_prec;
1169 }
1170 else
1171 {
1172 CdGtY += v;
1173 }
1174 CdGtY /= 3.;
1175
1176 double S = Sr + St;
1177 double uX = (Sr * CdGrX + St * CdGtX) / S;
1178 double vX = (Sr * CdGrY + St * CdGtY) / S;
1179
1180 double contrib_u_centre = uX * contrib_surface;
1181 double contrib_v_centre = vX * contrib_surface;
1182
1183 surface += contrib_surface;
1184 u_centre += contrib_u_centre;
1185 v_centre += contrib_v_centre;
1186 }
1187 }
1188 }
1189
1190 // En cas d'erreur d'arrondi ...
1191 if (surface < 0.) surface = 0.;
1192
1193 // calcul des contributions.
1194 double barycentre_phase1[3] = {0.,0.,0.};
1195 if (correction_parcours_thomas_ || (sqrt(surface) > 5. * Erreur_max_coordonnees_))
1196 {
1197 // normalisation du centre de gravite
1198 if (sup_strict(surface,0.,tolerance_comparaisons))
1199 {
1200 u_centre /= surface;
1201 v_centre /= surface;
1202 }
1203 else
1204 {
1205 u_centre = v_centre = 1./3.;
1206 }
1207 double w_centre = 1. - u_centre - v_centre;
1208 //calcul des coordonnees reelles du centre de gravite
1209 FTd_vecteur3 centre_de_gravite;
1210 {
1211 for (int ii = 0; ii < 3; ii++)
1212 {
1213 centre_de_gravite[ii] =
1214 u_centre * coord_som[0][ii]
1215 + v_centre * coord_som[1][ii]
1216 + w_centre * coord_som[2][ii];
1217 }
1218 }
1219 //calcul des coordonnees reelles du polygone d'intersection
1220 poly_reelles_.resize(nb_sommets_poly,3);
1221 for (i=0 ; i<nb_sommets_poly ; i++)
1222 {
1223 for (k=0 ; k<dimension ; k++)
1224 {
1225 poly_reelles_(i,k) =
1226 poly_(i,0) * coord_som[0][k]
1227 + poly_(i,1) * coord_som[1][k]
1228 + poly_(i,2) * coord_som[2][k];
1229 }
1230 }
1231 FTd_vecteur3 norme;
1232 //calcul des contributions de la facette pour l'indicatrice,
1233 //en fonction du type d'element eulerien
1234 switch(type_element_)
1235 {
1236 case TETRA:
1237 if (flag_warning_code_missing)
1238 {
1239 Cerr << "WARNING : barycentre_phase1 not filled properly!!" << finl;
1240 Cerr << "WARNING : Calculation of barycentre_phase1 not implemented yet for TETRA." << finl;
1241 flag_warning_code_missing=0;
1242 }
1243 volume = volume_tetraedre(domaine_vf, num_element,num_facette,
1244 maillage,
1245 poly_reelles_,
1246 centre_de_gravite,
1248 break;
1249 case HEXA:
1250 maillage.calcul_normale_3D(num_facette,norme);
1251 {
1252 CutCell_Properties cut_cell_properties = volume_barycentre_hexaedre(domaine_vf, num_element,
1253 poly_reelles_,
1254 norme, centre_de_gravite,
1255 polygone_plan_coupe_,
1257 volume = cut_cell_properties.volume;
1258 barycentre_phase1[0] = cut_cell_properties.barycentre[0];
1259 barycentre_phase1[1] = cut_cell_properties.barycentre[1];
1260 barycentre_phase1[2] = cut_cell_properties.barycentre[2];
1261 }
1262
1263 for (int i_face = 0; i_face < 3; i_face++)
1264 {
1265 // 0 = NUM_FACE_GAUCHE;
1266 // 1 = NUM_FACE_BAS;
1267 // 2 = NUM_FACE_ARRIERE;
1268 CutFace_Properties cut_face_properties = coupe_face_rectangulaire(domaine_vf, num_element, i_face,
1269 poly_reelles_,
1270 norme,
1271 polygone_plan_coupe_,
1273 aire_faces[i_face] = cut_face_properties.area;
1274 barycentre_faces[i_face][0] = cut_face_properties.barycentre[0];
1275 barycentre_faces[i_face][1] = cut_face_properties.barycentre[1];
1276 }
1277 break;
1278 default:
1279 // qu'est-ce qu'on fout la ?
1280 Process::exit();
1281 break;
1282 }
1283 // "surface" contient la surface du polygone d'intersection dans le triangle
1284 // de reference. Or ce triangle est de surface 1/2. Pour avoir la fraction
1285 // de surface par rapport au triangle, on multiplie par 2.
1287 num_element,
1288 surface * 2.,
1289 volume,
1290 barycentre_phase1,
1291 aire_faces,
1292 barycentre_faces,
1293 u_centre,
1294 v_centre,
1295 1. - u_centre - v_centre);
1296 }
1297 else
1298 {
1299 // Intersection de surface nulle. On l'enregistre pour ne pas traiter
1300 // cette facette a nouveau lors du parcours.
1302 num_element,
1303 0.,
1304 0.,
1305 barycentre_phase1,
1306 aire_faces,
1307 barycentre_faces,
1308 0., 0., 0.);
1309 }
1310
1311 int code_retour = 0;
1312 {
1313 for (i = 0; i < nb_sommets_poly; i++)
1314 {
1315 const int plan_coupe = polygone_plan_coupe_[i];
1316 if (plan_coupe >= 0)
1317 code_retour |= 1 << plan_coupe;
1318 }
1319 }
1320 return code_retour;
1321}
1322
1323/*! @brief Cette methode (statique) permet d'inverser une matrice 3x3
1324 *
1325 * Precondition: des denominateurs non nuls
1326 *
1327 * @param (matrice) matrice 3x3 a inverser
1328 * @param (matrice_inv) inverse de la matrice 3x3
1329 * @return (rien)
1330 */
1331void Parcours_interface::calcul_inverse_matrice33(const FTd_matrice33& matrice, FTd_matrice33& matrice_inv)
1332{
1333 const double a00 = matrice[0][0];
1334 const double a01 = matrice[0][1];
1335 const double a02 = matrice[0][2];
1336 const double a10 = matrice[1][0];
1337 const double a11 = matrice[1][1];
1338 const double a12 = matrice[1][2];
1339 const double a20 = matrice[2][0];
1340 const double a21 = matrice[2][1];
1341 const double a22 = matrice[2][2];
1342 //calcul de valeurs temporaires pour optimisation
1343 const double t4 = a00*a11;
1344 const double t6 = a00*a12;
1345 const double t8 = a01*a10;
1346 const double t10 = a02*a10;
1347 const double t12 = a01*a20;
1348 const double t14 = a02*a20;
1349 const double t = t4*a22-t6*a21-t8*a22+t10*a21+t12*a12-t14*a11;
1350 if (t==0.)
1351 {
1352 Cerr<<"PB : matrice non inversible : t= "<<t<<finl<<" matrice= "<<finl;
1353 int i,j;
1354 for (i=0 ; i<3 ; i++)
1355 {
1356 for (j=0 ; j<3 ; j++)
1357 {
1358 Cerr<<" "<<matrice[i][j];
1359 }
1360 Cerr<<finl;
1361 }
1362 Process::exit();
1363 }
1364 const double t17 = 1/(t);
1365
1366 //calcul de la matrice inverse
1367 matrice_inv[0][0] = (a11*a22-a12*a21)*t17;
1368 matrice_inv[0][1] = -(a01*a22-a02*a21)*t17;
1369 matrice_inv[0][2] = -(-a01*a12+a02*a11)*t17;
1370 matrice_inv[1][0] = (-a10*a22+a12*a20)*t17;
1371 matrice_inv[1][1] = (a00*a22-t14)*t17;
1372 matrice_inv[1][2] = -(t6-t10)*t17;
1373 matrice_inv[2][0] = -(-a10*a21+a11*a20)*t17;
1374 matrice_inv[2][1] = -(a00*a21-t12)*t17;
1375 matrice_inv[2][2] = (t4-t8)*t17;
1376}
1377
1378/*! @brief Cette methode (statique) permet de calculer le produit d'une matrice 3x3 avec un vecteur 3
1379 *
1380 * @param (matrice) matrice 3x3 a inverser
1381 * @param (vect) vecteur 3 a multiplier
1382 * @param (vect) vecteur 3 resultat
1383 * @return (rien)
1384 */
1385void Parcours_interface::calcul_produit_matrice33_vecteur(const FTd_matrice33& matrice, const FTd_vecteur3& vect, FTd_vecteur3& res)
1386{
1387 int i,j;
1388 for (i=0 ; i<3 ; i++)
1389 {
1390 double x = 0.;
1391 for (j=0 ; j<3 ; j++)
1392 {
1393 x += matrice[i][j] * vect[j];
1394 }
1395 res[i] = x;
1396 }
1397}
1398
1399/*! @brief Calcul de la contribution de volume d'une facette a la valeur de l'indicatrice dans un element.
1400 *
1401 * C'est une fraction du volume de l'element
1402 * comprise entre epsilon et 1.-epsilon
1403 *
1404 * Precondition: dimension = 3
1405 *
1406 * @param (domaine_vf) domaine du calcul
1407 * @param (num_element) indice de l'element intersecte
1408 * @param (poly_reelles) coordonnees (reelles) des sommets definissant une surface contenue dans l'element (en pratique : surface d'intersection entre une facette d'interface et l'element)
1409 * @param (centre_de_gravite) centre de gravite de la surface
1410 * @param (epsilon) erreur relative
1411 * @return (double) contribution du volume engendre par la surface dans l'element
1412 */
1414 int num_element,
1415 int num_facette,
1416 const Maillage_FT_Disc& maillage,
1417 const DoubleTab& poly_reelles,
1418 const FTd_vecteur3& centre_de_gravite,
1419 double epsilon) const
1420{
1421 static const int SOM_Z = 0; // indice du sommet qui servira d'origine
1422 static const int SOM_A = 1; // indice du sommet qui servira pour le premier vecteur
1423 static const int SOM_B = 2; // indice du sommet qui servira pour le second vecteur
1424 static const int SOM_C = 3; // indice du sommet qui servira pour le troisieme vecteur
1425
1426 const int som_Z = (*domaine_elem_ptr)(num_element,SOM_Z);
1427 const int som_A = (*domaine_elem_ptr)(num_element,SOM_A);
1428 const int som_B = (*domaine_elem_ptr)(num_element,SOM_B);
1429 const int som_C = (*domaine_elem_ptr)(num_element,SOM_C);
1430
1431 FTd_matrice33 matrice, matrice_inv;
1432 //on commence par calculer la matrice de transformation de la base (OX,OY,OZ) vers (ZA,ZB,ZC)
1433 //colonne 0 : vecteur OA
1434 matrice[0][0] = (*domaine_sommets_ptr)(som_A, 0) - (*domaine_sommets_ptr)(som_Z, 0); //OA(x)
1435 matrice[1][0] = (*domaine_sommets_ptr)(som_A, 1) - (*domaine_sommets_ptr)(som_Z, 1); //OA(y)
1436 matrice[2][0] = (*domaine_sommets_ptr)(som_A, 2) - (*domaine_sommets_ptr)(som_Z, 2); //OA(z)
1437 //colonne 1 : vecteur OB
1438 matrice[0][1] = (*domaine_sommets_ptr)(som_B, 0) - (*domaine_sommets_ptr)(som_Z, 0); //OB(x)
1439 matrice[1][1] = (*domaine_sommets_ptr)(som_B, 1) - (*domaine_sommets_ptr)(som_Z, 1); //OB(y)
1440 matrice[2][1] = (*domaine_sommets_ptr)(som_B, 2) - (*domaine_sommets_ptr)(som_Z, 2); //OB(z)
1441 //colonne 2 : vecteur OC
1442 matrice[0][2] = (*domaine_sommets_ptr)(som_C, 0) - (*domaine_sommets_ptr)(som_Z, 0); //OC(x)
1443 matrice[1][2] = (*domaine_sommets_ptr)(som_C, 1) - (*domaine_sommets_ptr)(som_Z, 1); //OC(y)
1444 matrice[2][2] = (*domaine_sommets_ptr)(som_C, 2) - (*domaine_sommets_ptr)(som_Z, 2); //OC(z)
1445
1446 //on inverse ensuite la matrice de transformation
1447 calcul_inverse_matrice33(matrice,matrice_inv);
1448
1449 int i,k;
1450
1451 //calcul des coordonnes du polygone dans le repere de reference
1452 const int nb_sommets_poly = poly_reelles.dimension(0);
1453 DoubleTabFT poly_reelles_ref(nb_sommets_poly,3);
1454 FTd_vecteur3 poly, poly_ref;
1455 for (i=0 ; i<nb_sommets_poly ; i++)
1456 {
1457 for (k=0 ; k<3 ; k++)
1458 {
1459 poly[k] = poly_reelles(i,k) - (*domaine_sommets_ptr)(som_Z, k);
1460 }
1461 calcul_produit_matrice33_vecteur(matrice_inv,poly, poly_ref);
1462 for (k=0 ; k<3 ; k++)
1463 {
1464 poly_reelles_ref(i,k) = poly_ref[k];
1465 }
1466 }
1467
1468 //calcul de la normale a la facette dans le repere de reference
1469 FTd_vecteur3 normale_ref;
1470 double AB[3], AC[3], AB_ref[3], AC_ref[3];
1471 const int somA = maillage.facettes_(num_facette, 0);
1472 const int somB = maillage.facettes_(num_facette, 1);
1473 const int somC = maillage.facettes_(num_facette, 2);
1474 for (k=0 ; k<dimension ; k++)
1475 {
1476 AB[k] = maillage.sommets_(somB,k) - maillage.sommets_(somA,k);
1477 AC[k] = maillage.sommets_(somC,k) - maillage.sommets_(somA,k);
1478 }
1479 calcul_produit_matrice33_vecteur(matrice_inv,AB, AB_ref);
1480 calcul_produit_matrice33_vecteur(matrice_inv,AC, AC_ref);
1481 //calcul pdt vect AB_ref x AC_ref
1482 normale_ref[0] = AB_ref[1]*AC_ref[2] - AB_ref[2]*AC_ref[1];
1483 normale_ref[1] = AB_ref[2]*AC_ref[0] - AB_ref[0]*AC_ref[2];
1484 normale_ref[2] = AB_ref[0]*AC_ref[1] - AB_ref[1]*AC_ref[0];
1485
1486 //calcul de la contribution de volume d'une facette a la valeur de l'indicatrice dans l'element de reference
1487 //le calcul est fait en decomposant les polygones en triangles elementaires
1488 FTd_vecteur3 centre_de_gravite_triangle_ref;
1489 static DoubleTabFT triangle_ref(3,3);
1490 double contrib_volume = 0., vol;
1491 for (k=0 ; k<dimension ; k++)
1492 {
1493 triangle_ref(0,k) = poly_reelles_ref(0,k);
1494 }
1495 for (i=1 ; i<nb_sommets_poly-1 ; i++)
1496 {
1497 for (k=0 ; k<dimension ; k++)
1498 {
1499 triangle_ref(1,k) = poly_reelles_ref(i,k);
1500 triangle_ref(2,k) = poly_reelles_ref(i+1,k);
1501 centre_de_gravite_triangle_ref[k] = (triangle_ref(0,k)+triangle_ref(1,k)+triangle_ref(2,k)) /3.;
1502 }
1503 vol = volume_tetraedre_reference(triangle_ref,normale_ref,centre_de_gravite_triangle_ref, epsilon);
1504 contrib_volume += vol;
1505 }
1506
1507 return contrib_volume;
1508}
1509
1510/*! @brief Calcul de la contribution de volume d'une facette a la valeur de l'indicatrice dans le tetraedre de reference.
1511 *
1512 * Dans ce tetraedre, on utilise le plan OXZ comme plan de projection (projection selon OY donc)
1513 *
1514 * Precondition: la surface doit etre un triangle (nb_sommets_poly==3)
1515 *
1516 * @param (poly_reelles_ref) coordonnees (reelles) des sommets l'element de reference
1517 * @param (norme) normale a la surface, dans l'element de reference
1518 * @param (centre_de_gravite, dans l'element de reference) centre de gravite de la surface
1519 * @param (epsilon) erreur relative
1520 * @return (double) contribution du volume engendre par la surface dans l'element
1521 */
1522double Parcours_interface::volume_tetraedre_reference(const DoubleTab& poly_reelles_ref,
1523 const FTd_vecteur3& norme_ref,
1524 const FTd_vecteur3& centre_de_gravite_ref,
1525 double epsilon) const
1526{
1527 //determination des signes pour les differentes composantes :
1528 double signe_princ;
1529 if (norme_ref[1]>0.)
1530 {
1531 signe_princ = -1.;
1532 }
1533 else
1534 {
1535 signe_princ = 1.;
1536 }
1537 // Volume de l'element = base * hauteur /3
1538 // avec base = 0.5, hauteur = 1
1539 double v_elem = 0.5 /3.;
1540 assert(v_elem>0.);
1541
1542 const int nb_sommets_poly = poly_reelles_ref.dimension(0);
1543 int k,i, i_prec = nb_sommets_poly -1;
1544 //on entre dans cette fonction qu'avec des triangles
1545 assert(nb_sommets_poly==3);
1546 //calcul de la normale au triangle dans le repere de reference
1547 FTd_vecteur3 normale_tr;
1548 double AB[3], AC[3];
1549 assert(dimension==3);
1550 for (k=0 ; k<3 ; k++)
1551 {
1552 AB[k] = poly_reelles_ref(1,k) - poly_reelles_ref(0,k);
1553 AC[k] = poly_reelles_ref(2,k) - poly_reelles_ref(0,k);
1554 }
1555 //calcul pdt vect AB_ref x AC_ref
1556 normale_tr[0] = AB[1]*AC[2] - AB[2]*AC[1];
1557 normale_tr[1] = AB[2]*AC[0] - AB[0]*AC[2];
1558 normale_tr[2] = AB[0]*AC[1] - AB[1]*AC[0];
1559 const double aire_tr = normale_tr[0]*normale_tr[0]+normale_tr[1]*normale_tr[1]+normale_tr[2]*normale_tr[2];
1560 if (aire_tr<Erreur_relative_maxi_)
1561 {
1562 return 0;
1563 }
1564 int coupe_face_opp = -1;
1565 int coupe_face_opp_p1 = -1;
1566 //calcule l'aire de la surface projetee sur face_bas
1567 double aire_projetee = 0.;
1568 for (i=0 ; i<nb_sommets_poly ; i++)
1569 {
1570 //teste si l'arete [i_prec,i] est sur la face_opposee
1571 //l'equation de plan de la face opposee est : x+y+z-1=0
1572 double f_prec = poly_reelles_ref(i_prec,0) + poly_reelles_ref(i_prec,1) + poly_reelles_ref(i_prec,2) - 1.;
1573 double f = poly_reelles_ref(i,0) + poly_reelles_ref(i,1) + poly_reelles_ref(i,2) - 1.;
1574 if (f<Erreur_relative_maxi_ && f>-Erreur_relative_maxi_ && f_prec<Erreur_relative_maxi_ && f_prec>-Erreur_relative_maxi_)
1575 {
1576 //les somet i_prec et i sont dans le plan de la face opposee au sommet 0
1577 //comme le polygone est dans le tetraedre, les somets sont dans la face...
1578 coupe_face_opp = i_prec;
1579 coupe_face_opp_p1 = i;
1580 }
1581
1582 //calcul de la contribution de l'arete a l'aire projetee dans le plan (OX,OZ) :
1583 // par la somme algebrique des aires des trapezes (generes par la projection de l'arete sur l'axe x=0)
1584 double contrib_aire_projetee = (poly_reelles_ref(i,2) - poly_reelles_ref(i_prec,2)) * (poly_reelles_ref(i,0) + poly_reelles_ref(i_prec,0)) * 0.5;
1585
1586 aire_projetee += contrib_aire_projetee;
1587 i_prec = i;
1588 }
1589 double v = 0.;
1590
1591 if (aire_projetee!=0.)
1592 {
1593 // Volume de la partie "projection sur la face face_bas (y_bas=0)
1594 v = signe_princ * std::fabs(aire_projetee) * (centre_de_gravite_ref[1]);
1595 }
1596 if (coupe_face_opp!=-1)
1597 {
1598 //la surface possede une arete sur la face opposee au sommet 0 (face 0)
1599 // -> il faut ajouter un volume complementaire
1600 //ce volume est defini par :
1601 // - les sommets coupe_face_opp et coupe_face_opp_p1 (notes som0 et som1)
1602 // - leur projection orthogonale sur la face_bas (ie ces sommets avec y=0) : proj_som0 et proj_som1
1603 // - la projection des sommets coupe_face_opp et coupe_face_opp_p1 sur face_bas, a partir du sommet (0,1,0) : proj2_som0 et proj2_som1
1604 //(cette derniere projection etant d'ailleurs equivalente a la projection de proj_som0 et proj_som1 sur l'arete (1,0,0)(0,0,1) a prtir du sommet (0,0,0)
1605 FTd_vecteur3 som0,som1, proj_som0,proj_som1, proj2_som0,proj2_som1;
1606 //recuperation des sommets sur la face 0
1607 for (k=0 ; k<dimension ; k++)
1608 {
1609 som0[k] = poly_reelles_ref(coupe_face_opp,k);
1610 som1[k] = poly_reelles_ref(coupe_face_opp_p1,k);
1611 }
1612 //calcul de leur projection sur y=0
1613 proj_som0[0] = som0[0];
1614 proj_som1[0] = som1[0];
1615 proj_som0[1] = 0.;
1616 proj_som1[1] = 0.;
1617 proj_som0[2] = som0[2];
1618 proj_som1[2] = som1[2];
1619 //calcul de leur projection sur l'arete (1,0,0)-(0,0,1)
1620 // 0 1 X
1621 // 0 *---------------------------->
1622 // | --- /
1623 // |! --- /
1624 // |! -1- /
1625 // | ! --+
1626 // | ! / ---
1627 // | O /
1628 // | ! /
1629 // | ! /
1630 // | +
1631 // | / !
1632 // 1 | !
1633 // |
1634 // Z V
1635 //on va donc calculer
1636 // -l'intersection des droites : z = z0/x0 . x et z = 1 - x
1637 // -l'intersection des droites : z = z1/x1 . x et z = 1 - x
1638 if (som0[0]<epsilon) //x0==0
1639 {
1640 proj2_som0[0] = 0.;
1641 }
1642 else
1643 {
1644 //x20 = 1 / (1 + z0/x0)
1645 assert((1. + som0[2]/som0[0]) !=0.);
1646 proj2_som0[0] = 1./ (1. + som0[2]/som0[0]);
1647 }
1648 if (som1[0]<epsilon) //x1==0
1649 {
1650 proj2_som1[0] = 0.;
1651 }
1652 else
1653 {
1654 //x21 = 1 / (1 + z1/x1)
1655 assert((1. + som1[2]/som1[0]) !=0.);
1656 proj2_som1[0] = 1./ (1. + som1[2]/som1[0]);
1657 }
1658 proj2_som0[1] = 0.;
1659 proj2_som1[1] = 0.;
1660 proj2_som0[2] = 1. - proj2_som0[0];
1661 proj2_som1[2] = 1. - proj2_som1[0];
1662
1663 //determination du signe des volumes complementaires
1664 FTd_vecteur3 normale_plan_proj;
1665 normale_plan_proj[0] = -(proj_som1[2]-proj_som0[2]);
1666 normale_plan_proj[1] = 0.;
1667 normale_plan_proj[2] = proj_som1[0]-proj_som0[0];
1668 double pdtscal = 0.;
1669 FTd_vecteur3 vect;
1670 for (i=0 ; i<dimension ; i++)
1671 {
1672 vect[i] = proj2_som0[i]- proj_som0[i];
1673 pdtscal += vect[i]*vect[i];
1674 }
1675 if (pdtscal<Erreur_relative_maxi_)
1676 {
1677 for (i=0 ; i<dimension ; i++)
1678 {
1679 vect[i] = proj2_som1[i]- proj_som1[i];
1680 }
1681 }
1682 pdtscal = 0.;
1683 for (i=0 ; i<dimension ; i++)
1684 {
1685 pdtscal += normale_plan_proj[i] * vect[i];
1686 }
1687 double signe_2 = 0.;
1688 if (pdtscal>0.)
1689 {
1690 signe_2 = -1.;
1691 }
1692 else
1693 {
1694 signe_2 = 1.;
1695 }
1696 //une fois les pojetes calcules, il faut calculer le volume correspondant
1697 //ce volume est constitue par les 4 projetes et les 2 sommets opposes
1698 //on decompose alors ce volume en :
1699 // - une pyramide a base quadrangulaire (som0, som1 et leur projete orthogonal qui definissent une base trapezoidale) et le sommet oppose proj2_som0
1700 // - un tetraedre defini par les sommets proj2_som0, som1 et les 2 projetes de som1
1701 //calcul du volume de la pyramide
1702 double l,L,base,h, vol;
1703 // calcul de l'aire de la base de la pyramide
1704 l = sqrt((som1[0]-som0[0])*(som1[0]-som0[0]) + (som1[2]-som0[2])*(som1[2]-som0[2])); //hauteur du trapeze
1705 L = 0.5* (som0[1] + som1[1]); //moyenne des longueurs des bases du trapeze
1706 base = L*l; //base = aire du trapeze (som0,som1,proj_som0,proj_som1)
1707 if (l>=Erreur_relative_maxi_)
1708 {
1709 // calcul de la hauteur de la pyramide
1710 double L2 = (proj2_som0[0]-som0[0])*(proj2_som0[0]-som0[0]) + (proj2_som0[2]-som0[2])*(proj2_som0[2]-som0[2]);
1711 double l2 = ((som1[0]-som0[0])*(proj2_som0[0]-som0[0]) + (som1[2]-som0[2])*(proj2_som0[2]-som0[2])) / l;
1712 h = L2 - l2*l2;
1714 {
1715 h = sqrt(h);
1716 // calcul du volume de la pyramide : base * hauteur / 3.
1717 vol = base * h /3.;
1718 v += signe_2 * vol;
1719 }
1720 }
1721
1722 //calcul du volume du tetraedre
1723 // calcul de l'aire de la base du tetraedre : aire du triangle proj_som1,proj2_som0,proj2_som1
1724 base = (proj_som1[2]-proj2_som0[2]) * (proj2_som1[0]-proj2_som0[0]) - (proj_som1[0]-proj2_som0[0]) * (proj2_som1[2]-proj2_som0[2]);
1725 base = std::fabs(base * 0.5);
1726 // calcul de la hauteur du tetraedre
1727 h = som1[1];
1728 // calcul du volume du tetraedre : base * hauteur / 3.
1729 vol = base * h /3.;
1730 v += signe_2 * vol;
1731 }
1732
1733 //normalisation par le volume de l'element
1734 v /= v_elem;
1735
1736 // On force la valeur entre 0 et 1 strictement.
1737 if (std::fabs(v) < Erreur_relative_maxi_)
1739 else if (v > 1. - Erreur_relative_maxi_)
1740 v = 1. - Erreur_relative_maxi_;
1741 else if (v < -1. + Erreur_relative_maxi_)
1742 v = -1. + Erreur_relative_maxi_;
1743
1744 return v;
1745}
1746
1747/*! @brief Calcul de la contribution de volume d'une facette a la valeur de l'indicatrice dans un element.
1748 *
1749 * C'est une fraction du volume de l'element
1750 * comprise entre epsilon et 1.-epsilon
1751 *
1752 * Precondition: dimension = 3
1753 *
1754 * @param (domaine_vf) domaine du calcul
1755 * @param (num_element) indice de l'element intersecte
1756 * @param (poly_reelles) coordonnees (reelles) des sommets definissant une surface contenue dans l'element (en pratique : surface d'intersection entre une facette d'interface et l'element)
1757 * @param (norme) normale a la facette
1758 * @param (centre_de_gravite) centre de gravite de la surface
1759 * @param (epsilon) erreur relative
1760 * @return (double) contribution du volume engendre par la surface dans l'element
1761 */
1763 int num_element,
1764 const DoubleTab& poly_reelles,
1765 const FTd_vecteur3& norme,
1766 const FTd_vecteur3& centre_de_gravite,
1767 const ArrOfInt& polygone_plan_coupe,
1768 double epsilon) const
1769{
1770 // Conventions TRUST VDF :
1771 constexpr int NUM_FACE_GAUCHE = 0;
1772 constexpr int NUM_FACE_DROITE = 3;
1773 constexpr int NUM_FACE_BAS = 1;
1774 constexpr int NUM_FACE_HAUT = 4;
1775 constexpr int NUM_FACE_ARRIERE = 2;
1776 constexpr int NUM_FACE_AVANT = 5;
1777 int face_bas = domaine_vf.elem_faces(num_element, NUM_FACE_BAS);
1778 int face_haut = domaine_vf.elem_faces(num_element, NUM_FACE_HAUT);
1779 int face_gauche = domaine_vf.elem_faces(num_element, NUM_FACE_GAUCHE);
1780 int face_droite = domaine_vf.elem_faces(num_element, NUM_FACE_DROITE);
1781 int face_arriere = domaine_vf.elem_faces(num_element, NUM_FACE_ARRIERE);
1782 int face_avant = domaine_vf.elem_faces(num_element, NUM_FACE_AVANT);
1783 double y_bas = domaine_vf.xv(face_bas, 1);
1784 double y_haut = domaine_vf.xv(face_haut, 1);
1785 double x_gauche = domaine_vf.xv(face_gauche, 0);
1786 double x_droite = domaine_vf.xv(face_droite, 0);
1787 double z_arriere = domaine_vf.xv(face_arriere, 2);
1788 double z_avant = domaine_vf.xv(face_avant, 2);
1789
1790 //determination des signes pour les differentes composantes :
1791 double signe_princ, signe_compl0,signe_compl1;
1792 if (norme[1]>0.)
1793 {
1794 signe_princ = -1;
1795 }
1796 else if (norme[1]<0.)
1797 {
1798 signe_princ = 1;
1799 }
1800 else
1801 {
1802 signe_princ = 0;
1803 }
1804 if (norme[0]>0.)
1805 {
1806 signe_compl0 = -1;
1807 }
1808 else if (norme[0]<0.)
1809 {
1810 signe_compl0 = +1;
1811 }
1812 else
1813 {
1814 signe_compl0 = 0;
1815 }
1816 if (norme[2]>0.)
1817 {
1818 signe_compl1 = -1;
1819 }
1820 else if (norme[2]<0.)
1821 {
1822 signe_compl1 = 1;
1823 }
1824 else
1825 {
1826 signe_compl1 = 0;
1827 }
1828
1829 // Volume de l'element
1830 double v_elem = (x_droite - x_gauche) * (y_haut - y_bas) * (z_avant - z_arriere);
1831 assert(v_elem>0.);
1832
1833 const int nb_sommets_poly = poly_reelles.dimension(0);
1834 int i, i_prec = nb_sommets_poly -1;
1835 //calcule l'aire de la surface projetee sur face_bas
1836 double aire_projetee = 0.;
1837 for (i=0 ; i<nb_sommets_poly ; i++)
1838 {
1839 //calcul de la contribution de l'arete a l'aire projetee dans le plan (X,Z) :
1840 // par la somme algebrique des aires des trapezes (generes par la projection de l'arete sur l'axe x=0)
1841 double contrib_aire_projetee = (poly_reelles(i,2) - poly_reelles(i_prec,2)) * ((poly_reelles(i,0) + poly_reelles(i_prec,0)) * 0.5);
1842
1843 aire_projetee += contrib_aire_projetee;
1844 i_prec = i;
1845 }
1846
1847 // Volume de la partie "projection sur la face face_bas"
1848 double volume = 0.;
1849
1850 volume += signe_princ * std::fabs(aire_projetee) * (centre_de_gravite[1] - y_bas);
1851
1852 // Barycentre (pondere par le volume) de la partie "projection sur la face face_bas"
1853 double barycentre[3] = {0};
1854 assert(nb_sommets_poly >=2);
1855 int i_min = 0;
1856 for (i = 1; i < nb_sommets_poly; i++)
1857 {
1858 i_min = poly_reelles(i,1) < poly_reelles(i_min,1) ? i : i_min;
1859 }
1860 double y_min = poly_reelles(i_min,1);
1861
1862 // Volume et barycentre de la partie 'prisme'
1863 double volume_prisme = std::fabs(aire_projetee * (y_min - y_bas));
1864 double barycentre_prisme[3] =
1865 {
1866 (centre_de_gravite[0] - x_gauche)/(x_droite - x_gauche),
1867 (0.5*y_min - 0.5*y_bas)/(y_haut - y_bas),
1868 (centre_de_gravite[2] - z_arriere)/(z_avant - z_arriere)
1869 };
1870
1871 assert(volume_prisme >= 0.);
1872
1873 barycentre[0] += signe_princ * volume_prisme*barycentre_prisme[0];
1874 barycentre[1] += signe_princ * volume_prisme*barycentre_prisme[1];
1875 barycentre[2] += signe_princ * volume_prisme*barycentre_prisme[2];
1876
1877 // Volume et barycentre de la partie 'chapeau'
1878 // Le chapeau est un polyedre, union d'un certain nombre de tetraedres (deux par segment)
1879 for (i = 0; i < nb_sommets_poly; i++)
1880 {
1881 const int i_precedent = (i-1) < 0 ? nb_sommets_poly-1 : (i-1);
1882
1883 // On n'inclue pas les tetraedres incluant i_min, car ils ne contribuent pas au volume
1884 if ((i == i_min) || (i_precedent == i_min))
1885 continue;
1886
1887 double tetraedre1_sommet1[3] = {poly_reelles(i,0), poly_reelles(i,1), poly_reelles(i,2)};
1888 double tetraedre1_sommet2[3] = {poly_reelles(i_precedent,0), poly_reelles(i_precedent,1), poly_reelles(i_precedent,2)};
1889 double tetraedre1_sommet3[3] = {poly_reelles(i_precedent,0), y_min, poly_reelles(i_precedent,2)};
1890 double tetraedre1_sommet4[3] = {poly_reelles(i_min,0), poly_reelles(i_min,1), poly_reelles(i_min,2)};
1891 double volume_tetraedre1 = std::fabs(FTd_calculer_volume_tetraedre(tetraedre1_sommet1, tetraedre1_sommet2, tetraedre1_sommet3, tetraedre1_sommet4));
1892 double barycentre_tetraedre1[3] =
1893 {
1894 (0.25*(tetraedre1_sommet1[0] + tetraedre1_sommet2[0] + tetraedre1_sommet3[0]+ tetraedre1_sommet4[0]) - x_gauche)/(x_droite - x_gauche),
1895 (0.25*(tetraedre1_sommet1[1] + tetraedre1_sommet2[1] + tetraedre1_sommet3[1]+ tetraedre1_sommet4[1]) - y_bas)/(y_haut - y_bas),
1896 (0.25*(tetraedre1_sommet1[2] + tetraedre1_sommet2[2] + tetraedre1_sommet3[2]+ tetraedre1_sommet4[2]) - z_arriere)/(z_avant - z_arriere)
1897 };
1898
1899 double tetraedre2_sommet1[3] = {poly_reelles(i,0), poly_reelles(i,1), poly_reelles(i,2)};
1900 double tetraedre2_sommet2[3] = {poly_reelles(i_precedent,0), y_min, poly_reelles(i_precedent,2)};
1901 double tetraedre2_sommet3[3] = {poly_reelles(i,0), y_min, poly_reelles(i,2)};
1902 double tetraedre2_sommet4[3] = {poly_reelles(i_min,0), poly_reelles(i_min,1), poly_reelles(i_min,2)};
1903 double volume_tetraedre2 = std::fabs(FTd_calculer_volume_tetraedre(tetraedre2_sommet1, tetraedre2_sommet2, tetraedre2_sommet3, tetraedre2_sommet4));
1904 double barycentre_tetraedre2[3] =
1905 {
1906 (0.25*(tetraedre2_sommet1[0] + tetraedre2_sommet2[0] + tetraedre2_sommet3[0]+ tetraedre2_sommet4[0]) - x_gauche)/(x_droite - x_gauche),
1907 (0.25*(tetraedre2_sommet1[1] + tetraedre2_sommet2[1] + tetraedre2_sommet3[1]+ tetraedre2_sommet4[1]) - y_bas)/(y_haut - y_bas),
1908 (0.25*(tetraedre2_sommet1[2] + tetraedre2_sommet2[2] + tetraedre2_sommet3[2]+ tetraedre2_sommet4[2]) - z_arriere)/(z_avant - z_arriere)
1909 };
1910
1911 assert(volume_tetraedre1 >= 0.);
1912 assert(volume_tetraedre2 >= 0.);
1913
1914 // Volume et barycentre (pondere par le volume) de la partie 'projection = chapeau + prisme'
1915 barycentre[0] += signe_princ * (volume_tetraedre1*barycentre_tetraedre1[0] + volume_tetraedre2*barycentre_tetraedre2[0]);
1916 barycentre[1] += signe_princ * (volume_tetraedre1*barycentre_tetraedre1[1] + volume_tetraedre2*barycentre_tetraedre2[1]);
1917 barycentre[2] += signe_princ * (volume_tetraedre1*barycentre_tetraedre1[2] + volume_tetraedre2*barycentre_tetraedre2[2]);
1918 }
1919
1920 // Recherche d'un segment coupant la face du haut
1921 for (i = 0; i < nb_sommets_poly; i++)
1922 {
1923 if (polygone_plan_coupe[i] == NUM_FACE_HAUT)
1924 {
1925 const int i_precedent = (i-1) < 0 ? nb_sommets_poly-1 : (i-1);
1926 const int i_suivant = (i+1) >= nb_sommets_poly ? 0 : (i+1);
1927 // Le segment [i-1,i] et sur la face du haut
1928 const int coupe_face_haut = i_precedent;
1929 const int coupe_face_haut_p1 = i;
1930 // Un segment voisin est-il sur la face de droite ?
1931 int coupe_face_droite = -1;
1932 if (polygone_plan_coupe[i_precedent] == NUM_FACE_DROITE)
1933 coupe_face_droite = i_precedent;
1934 else if (polygone_plan_coupe[i_suivant] == NUM_FACE_DROITE)
1935 coupe_face_droite = i;//_suivant;
1936
1937 // Les sommets coupe_haut et coupe_haut_p1 coupent la face face_haut
1938 // -> ajoute la composante de volume associee = moyenne_x * (y_haut-y_bas) * diff_z
1939 double vol_compl0 =
1940 (0.5*(poly_reelles(coupe_face_haut,0) + poly_reelles(coupe_face_haut_p1,0)) - x_gauche)
1941 * (y_haut - y_bas)
1942 * (poly_reelles(coupe_face_haut,2) - poly_reelles(coupe_face_haut_p1,2));
1943
1944 volume += signe_compl0 * std::fabs(vol_compl0);
1945
1946 double min_x_coupe_face_haut;
1947 double max_x_coupe_face_haut;
1948 double z_coupe_face_haut_min_x;
1949 double z_coupe_face_haut_max_x;
1950 if (poly_reelles(coupe_face_haut,0) > poly_reelles(coupe_face_haut_p1,0))
1951 {
1952 min_x_coupe_face_haut = poly_reelles(coupe_face_haut_p1,0);
1953 max_x_coupe_face_haut = poly_reelles(coupe_face_haut,0);
1954 z_coupe_face_haut_min_x = poly_reelles(coupe_face_haut_p1,2);
1955 z_coupe_face_haut_max_x = poly_reelles(coupe_face_haut,2);
1956 }
1957 else
1958 {
1959 min_x_coupe_face_haut = poly_reelles(coupe_face_haut,0);
1960 max_x_coupe_face_haut = poly_reelles(coupe_face_haut_p1,0);
1961 z_coupe_face_haut_min_x = poly_reelles(coupe_face_haut,2);
1962 z_coupe_face_haut_max_x = poly_reelles(coupe_face_haut_p1,2);
1963 }
1964
1965 // Volume et barycentre de la partie 'prisme rectangulaire'
1966 double volume_prectangle = (min_x_coupe_face_haut - x_gauche) * (y_haut - y_bas) * std::fabs(poly_reelles(coupe_face_haut,2) - poly_reelles(coupe_face_haut_p1,2));
1967 double barycentre_prectangle[3] =
1968 {
1969 (0.5*min_x_coupe_face_haut - 0.5*x_gauche)/(x_droite - x_gauche),
1970 0.5,
1971 (0.5*(poly_reelles(coupe_face_haut,2) + poly_reelles(coupe_face_haut_p1,2)) - z_arriere)/(z_avant - z_arriere)
1972 };
1973
1974 // Volume et barycentre de la partie 'prisme triangulaire'
1975 double volume_ptriangle = .5*(max_x_coupe_face_haut - min_x_coupe_face_haut) * (y_haut - y_bas) * std::fabs(poly_reelles(coupe_face_haut,2) - poly_reelles(coupe_face_haut_p1,2));
1976 double barycentre_ptriangle[3] =
1977 {
1978 (min_x_coupe_face_haut + 1./3.*(max_x_coupe_face_haut - min_x_coupe_face_haut) - x_gauche)/(x_droite - x_gauche),
1979 0.5,
1980 (z_coupe_face_haut_max_x + 1./3.*(z_coupe_face_haut_min_x - z_coupe_face_haut_max_x) - z_arriere)/(z_avant - z_arriere)
1981 };
1982
1983 barycentre[0] += signe_compl0 * (volume_prectangle*barycentre_prectangle[0] + volume_ptriangle*barycentre_ptriangle[0]);
1984 barycentre[1] += signe_compl0 * (volume_prectangle*barycentre_prectangle[1] + volume_ptriangle*barycentre_ptriangle[1]);
1985 barycentre[2] += signe_compl0 * (volume_prectangle*barycentre_prectangle[2] + volume_ptriangle*barycentre_ptriangle[2]);
1986
1987 if (coupe_face_droite >= 0)
1988 {
1989 //cette arete coupe aussi la face xmax
1990 //ajoute la composante de volume associee = (x_droite-x_gauche) * (y_haut-y_bas) * (z-z_arriere)
1991 double vol_compl1 =
1992 (x_droite - x_gauche)
1993 * (y_haut - y_bas)
1994 * (poly_reelles(coupe_face_droite,2) - z_arriere);
1995
1996 volume += signe_compl1 * std::fabs(vol_compl1);
1997 barycentre[0] += signe_compl1 * std::fabs(vol_compl1) * .5;
1998 barycentre[1] += signe_compl1 * std::fabs(vol_compl1) * .5;
1999 barycentre[2] += signe_compl1 * std::fabs(vol_compl1) * (.5*poly_reelles(coupe_face_droite,2) - 0.5*z_arriere)/(z_avant - z_arriere);
2000 }
2001 }
2002 }
2003
2004 // Normalisation par le volume de l'element
2005 volume /= v_elem;
2006 barycentre[0] /= v_elem;
2007 barycentre[1] /= v_elem;
2008 barycentre[2] /= v_elem;
2009
2010 assert((volume >= -2) && (volume <= 2));
2011
2012 if (volume == 0.)
2013 {
2014 barycentre[0] = 1./2.;
2015 barycentre[1] = 1./2.;
2016 barycentre[2] = 1./2.;
2017 }
2018 else
2019 {
2020 // Division par le volume pour calcul du barycentre
2021 barycentre[0] /= abs(volume);
2022 barycentre[1] /= abs(volume);
2023 barycentre[2] /= abs(volume);
2024 }
2025
2026 if (std::abs(volume) > 1e-11)
2027 {
2028 assert(barycentre[0] != 0);
2029 assert(barycentre[1] != 0);
2030 assert(barycentre[2] != 0);
2031 assert(barycentre[0] != 1);
2032 assert(barycentre[1] != 1);
2033 assert(barycentre[2] != 1);
2034 }
2035
2036
2037 return {volume, {barycentre[0], barycentre[1], barycentre[2]}};
2038}
2039
2040/*! @brief Calcul de la contribution d'une facette a l'indicatrice surfacique et au barycentre sur une face d'un element.
2041 *
2042 * Precondition: dimension = 3
2043 *
2044 * @param (domaine_vf) domaine du calcul
2045 * @param (num_element) indice de l'element intersecte
2046 * @param (num_face) indice de la face, au sein de l'element
2047 * @param (poly_reelles) coordonnees (reelles) des sommets definissant une surface contenue dans l'element (en pratique : surface d'intersection entre une facette d'interface et l'element)
2048 * @param (norme) normale a la facette
2049 * @param (epsilon) erreur relative
2050 * @return (CutFace_Properties) contribution de la surface engendre par le segment sur la face, et au barycentre de cette surface
2051 */
2053 int num_element,
2054 int num_face,
2055 const DoubleTab& poly_reelles,
2056 const FTd_vecteur3& norme,
2057 const ArrOfInt& polygone_plan_coupe,
2058 double epsilon) const
2059{
2060 // Directions de projection :
2061 // * Si FACE_GAUCHE (plan zy), on projete sur z_arriere
2062 // * Si FACE_DROITE (plan zy), on projete sur z_arriere
2063 // * Si FACE_BAS (plan xz), on projete sur x_gauche
2064 // * Si FACE_HAUT (plan xz), on projete sur x_gauche
2065 // * Si FACE_ARRIERE (plan yx), on projete sur y_bas
2066 // * Si FACE_AVANT (plan yx), on projete sur y_bas
2067 // Pour un plan xy par exemple, la direction dir1 correspond a x et la
2068 // direction dir2 correspond a y.
2069
2070 // Directions du plan de la face
2071 int dir1 = select_dir(num_face, 2, 0, 1);
2072 int dir2 = select_dir(num_face, 1, 2, 0);
2073
2074 // Coordonnees maximale et minimale dans la direction 1
2075 double min1 = domaine_vf.xv(domaine_vf.elem_faces(num_element, dir1), dir1);
2076 double max1 = domaine_vf.xv(domaine_vf.elem_faces(num_element, dir1+3), dir1);
2077
2078 // Coordonnees maximale et minimale dans la direction 2
2079 double min2 = domaine_vf.xv(domaine_vf.elem_faces(num_element, dir2), dir2);
2080 double max2 = domaine_vf.xv(domaine_vf.elem_faces(num_element, dir2+3), dir2);
2081
2082 // Determination des signes pour les differentes composantes :
2083 double signe1, signe2;
2084 if (norme[dir1]>0.)
2085 {
2086 signe1 = -1;
2087 }
2088 else if (norme[dir1]<0.)
2089 {
2090 signe1 = 1;
2091 }
2092 else
2093 {
2094 signe1 = 0;
2095 }
2096 if (norme[dir2]>0.)
2097 {
2098 signe2 = +1;
2099 }
2100 else if (norme[dir2]<0.)
2101 {
2102 signe2 = -1;
2103 }
2104 else
2105 {
2106 signe2 = 0;
2107 }
2108
2109 // Surface de la face
2110 double aire_face = (max1 - min1) * (max2 - min2);
2111 assert(aire_face>0.);
2112
2113 const int nb_sommets_poly = poly_reelles.dimension(0);
2114
2115 double aire = 0.;
2116 double barycentre[2] = {0};
2117 for (int i = 0; i < nb_sommets_poly; i++)
2118 {
2119 // On ne considere que les segments sur la face consideree
2120 // Normalement, il ne peut y en avoir qu'un par facette
2121 if (polygone_plan_coupe[i] == num_face)
2122 {
2123 // Calcul de la contribution de l'arete a l'aire projetee dans le plan (dir1,dir2)
2124 // par la somme algebrique des aires des trapezes generes par la projection de l'arete sur l'axe dir1=min1
2125 // Le signe de l'aire indique la phase correspondante (positive pour la phase disperse).
2126 //
2127 // Representation graphique de la methode :
2128 // / Segment
2129 // + Points du segment
2130 // = Aire associee au segment (partie rectangle)
2131 // . Aire associee au segment (partie triangle)
2132 // - Aire associee au segment (partie coupe_max1)
2133 // : Separation entre le rectangle et le triangle
2134 //
2135 // dir2 dir2
2136 // max2 .------------. max2 .------------.
2137 // | | |------------|
2138 // |====...+B | |------------|
2139 // |====../ | |------------|
2140 // |====./ | |=========...+D
2141 // |====+A | |=========../|
2142 // | | |=========./ |
2143 // min2 '------------' dir1 min2 '========C+--' dir1
2144 // min1 max1 min1 max1
2145 // (a) (b)
2146 //
2147 // dir2 dir2
2148 // max2 .------------.H max2 .======G+----.H
2149 // |------------| |=======.\ |
2150 // |--------F+--| |=======+F+ |
2151 // | :\-| | |
2152 // | : \| | |
2153 // | + +E | |
2154 // | | | |
2155 // min2 '------------' dir1 min2 '------------' dir1
2156 // min1 max1 min1 max1
2157 // (c) (d)
2158 //
2159 // Note : Dans le cas (c), l'aire du triangle et du rectangle
2160 // sont compenses par une partie de l'aire de coupe_max1.
2161 // En sommant algebriquement les surfaces des cas (c) et (d),
2162 // on doit retrouver l'aire du triangle EGH (au signe pres)
2163
2164 const int i_moins_1 = (i == 0) ? (nb_sommets_poly - 1) : (i-1);
2165 const int i_plus_1 = (i == (nb_sommets_poly-1)) ? 0 : (i+1);
2166
2167 int i_long_side = poly_reelles(i,dir1) < poly_reelles(i_moins_1,dir1) ? i_moins_1 : i;
2168 int i_short_side = poly_reelles(i,dir1) < poly_reelles(i_moins_1,dir1) ? i : i_moins_1;
2169
2170 // Aire et barycentre de la partie 'rectangle'
2171 double area_rectangle = abs(poly_reelles(i,dir2) - poly_reelles(i_moins_1,dir2)) * abs(poly_reelles(i_short_side,dir1) - min1);
2172 double barycentre_rectangle[2] =
2173 {
2174 (.5*(poly_reelles(i_short_side,dir1) - min1))/(max1 - min1),
2175 (.5*(poly_reelles(i,dir2) + poly_reelles(i_moins_1,dir2)) - min2)/(max2 - min2)
2176 };
2177
2178 // Aire et barycentre de la partie 'triangle'
2179 double area_triangle = abs(poly_reelles(i,dir2) - poly_reelles(i_moins_1,dir2)) * .5*(poly_reelles(i_long_side,dir1) - poly_reelles(i_short_side,dir1));
2180 double barycentre_triangle[2] =
2181 {
2182 (poly_reelles(i_short_side,dir1) - min1 + 1./3.*(poly_reelles(i_long_side,dir1) - poly_reelles(i_short_side,dir1)))/(max1 - min1),
2183 (poly_reelles(i_long_side,dir2) - min2 + 1./3.*(poly_reelles(i_short_side,dir2) - poly_reelles(i_long_side,dir2)))/(max2 - min2)
2184 };
2185
2186 assert(area_rectangle + area_triangle >= 0.);
2187
2188 // Aire et barycentre (pondere par l'aire) de la partie 'projection = triangle + rectangle'
2189 aire += signe1 * (area_rectangle + area_triangle);
2190 barycentre[0] += signe1 * (area_triangle*barycentre_triangle[0] + area_rectangle*barycentre_rectangle[0]);
2191 barycentre[1] += signe1 * (area_triangle*barycentre_triangle[1] + area_rectangle*barycentre_rectangle[1]);
2192
2193 // Un segment voisin est-il sur dir1=max1
2194 int coupe_max1 = -1;
2195 if (polygone_plan_coupe[i_moins_1] == dir1+3)
2196 coupe_max1 = i_moins_1;
2197 else if (polygone_plan_coupe[i_plus_1] == dir1+3)
2198 coupe_max1 = i;//_suivant;
2199
2200 if (coupe_max1 >= 0)
2201 {
2202 // Aire et barycentre de la partie 'coupe_max1'
2203 double area_coupe_max1 = (max1 - min1) * abs(max2 - poly_reelles(coupe_max1,dir2));
2204 double barycentre_coupe_max1[2] =
2205 {
2206 .5,
2207 (.5*(poly_reelles(coupe_max1,dir2) + max2) - min2)/(max2 - min2)
2208 };
2209
2210 assert(area_coupe_max1 >= 0.);
2211
2212 // Ajout de la contribution de 'coupe_max1' a l'aire et au barycentre (pondere par l'aire)
2213 aire += signe2 * area_coupe_max1;
2214 barycentre[0] += barycentre_coupe_max1[0] * signe2 * area_coupe_max1;
2215 barycentre[1] += barycentre_coupe_max1[1] * signe2 * area_coupe_max1;
2216 }
2217
2218 }
2219 }
2220
2221 // Normalisation par l'aire de la face
2222 aire /= aire_face;
2223 barycentre[0] /= aire_face;
2224 barycentre[1] /= aire_face;
2225
2226
2227 if (aire == 0.)
2228 {
2229 barycentre[0] = 1./2.;
2230 barycentre[1] = 1./2.;
2231 }
2232 else
2233 {
2234 // Division par l'aire pour calcul du barycentre
2235 barycentre[0] /= abs(aire);
2236 barycentre[1] /= abs(aire);
2237 }
2238
2239 return {aire, {barycentre[0], barycentre[1]}};
2240}
2241
2242/*! @brief Pour un point P0 (x0, y0, z0) a l'INTERIEUR de l'element num_element et un autre point P1 (x1, y1, z1), calcule l'intersection du segment (P0,P1)
2243 *
2244 * avec les bords de l'element.
2245 * Si le point P1 est sur un bord de l'element (a epsilon pres), on considere
2246 * qu'il est a l'interieur et on ne reporte aucune intersection.
2247 * Si on trouve une intersection I, on met dans pos_intersection la coordonnee
2248 * barycentrique de l'intersection definie par I = (1-pos) * P0 + pos * P1
2249 * Si on ne trouve pas d'intersection, pos_intersection est inchange.
2250 * Valeur de retour:
2251 * Si une intersection a ete trouvee, numero de la face de sortie dans le domaine_vf
2252 * (peut servir d'index dans face_voisins par exemple).
2253 * Sinon, renvoie -1.
2254 *
2255 */
2257 const int num_element,
2258 double x0, double y0, double z0,
2259 double x1, double y1, double z1,
2260 double& pos_intersection) const
2261{
2262 const int n_faces = nb_faces_elem_;
2263
2264 double t_sortie = 2.;
2265 // Numero de la face de sortie (numero entre 0 et n_faces)
2266 int face_sortie = -1;
2267
2268 for (int face = 0; face < n_faces; face++)
2269 {
2270 double a, b, c, d;
2271 double signe = calcul_eq_plan(domaine_vf, num_element, face, a, b, c, d);
2272
2273 // f est toujours positif si le point est dans l'element,
2274 // sinon il est negatif pour au moins une face de l'element.
2275 double f0 = (a * x0 + b * y0 + c * z0 + d) * signe;
2276 double f1 = (a * x1 + b * y1 + c * z1 + d) * signe;
2277 // Le point x0, y0, z0 doit etre a l'interieur de l'element
2278 assert(f0 > - Erreur_max_coordonnees_ * 2.);
2279 if (f0 < 0.) f0 = 0.;
2280 // On considere que le point d'arrivee est dans l'element s'il est a une
2281 // distance inferieure a Erreur_max_coordonnees.
2282 if (f1 < - Erreur_max_coordonnees_)
2283 {
2284 // Le point d'arrivee est a l'exterieur de l'element.
2285 // Calcul de la coordonnee barycentrique de l'intersection
2286 // telle que x|y|z_intersection = x0|y0|z0 * (1.-t) + x1|y1|z1 * t
2287 // double t = f0 / (f0-f1); // Fixed bug: Arithmetic exception
2288 double t = t_sortie;
2289 if (std::fabs(f0-f1)>=DMINFLOAT) t = f0 / (f0-f1);
2290 if (t < t_sortie)
2291 {
2292 t_sortie = t;
2293 face_sortie = face;
2294 }
2295 }
2296 }
2297 // Conversion du numero de la face de l'element en numero global de face
2298 if (face_sortie >= 0)
2299 {
2300 face_sortie = domaine_vf.elem_faces() (num_element, face_sortie);
2301 pos_intersection = t_sortie;
2302 }
2303
2304 return face_sortie;
2305}
2306
2307/*! @brief Methode outil de Maillage_FT_Disc::deplacer_un_point dans le cas d'un marqueur de la ligne de contact.
2308 *
2309 * P0 est la position initiale du marqueur en contact (sur la face_bord)
2310 * P1 est la position finale visee apres le deplacement
2311 * Pour un point P0(x0,y0,z0) sur la face "face_bord" et un point P1(x1,y1,z1),
2312 * on determine la projection orthogonale p(P1) de P1 sur le plan contenant la
2313 * face, et on calcule l'intersection (x,y,z) du segment [P0,p(P1)] avec
2314 * les bords de la face. S'il n'y a pas d'intersection, (x,y,z)=p(P1) et
2315 * la valeur de retour est -1, sinon la valeur de retour est le numero de
2316 * l'arete de la face qui est coupee par le segment [P0,p(P1)] (aretes
2317 * telles qu'elles sont definies dans la classe Connectivite_frontieres).
2318 *
2319 * @param (domaine_vf) le Domaine_VF a laquelle se rapportent les indices de face et d'element
2320 * @param (face_0) le numero de la face reelle sur laquelle se trouve le point P0
2321 * @param (num_element) un numero d'element voisin de la face face_0
2322 * @param (x0, y0, z0) Coordonnees du point P0 (en 2D, z0 est ignore)
2323 * @param (x1, y1, z1) Coordonnees du point P1 (en 2D, z1 est ignore)
2324 * @param (x, y, z) On met dans (x,y,z) les coordonnees de l'intersection s'il y en a une, sinon on y met les coordonnees de p(P1) qui est sur la face "face_0" Valeur de retour: -1 s'il n'y a pas d'intersection sinon le numero de la face de bord ou passe le sommet
2325 */
2327 const int num_element,
2328 double x0, double y0, double z0,
2329 double x1, double y1, double z1,
2330 double& x, double& y, double& z) const
2331{
2332 // Principe de l'algo :
2333 // * On projete le point d'arrivee sur la face_0
2334 // * On calcule l'intersection du segment avec l'element adjacent
2335 // * On cherche le numero de l'arete correspondant a la face de sortie
2336 {
2337 // Coefficients du plan contenant la face_0 :
2338 const double a = equations_plans_faces_(face_0, 0);
2339 const double b = equations_plans_faces_(face_0, 1);
2340 const double c = equations_plans_faces_(face_0, 2);
2341 const double d = equations_plans_faces_(face_0, 3);
2342
2343 // On projete les points 0 et 1 sur le plan
2344 // En 2D, le coefficient c est nul, donc (z0,z1) peut etre quelconque.
2345 const double f0 = a * x0 + b * y0 + c * z0 + d;
2346 x0 -= f0 * a;
2347 y0 -= f0 * b;
2348 z0 -= f0 * c;
2349 const double f1 = a * x1 + b * y1 + c * z1 + d;
2350 x1 -= f1 * a;
2351 y1 -= f1 * b;
2352 z1 -= f1 * c;
2353 }
2354
2355 // Calcul de l'intersection avec l'element
2356 const Domaine_VF& domaine_vf = refdomaine_vf_.valeur();
2357 // Verifie que num_element est un voisin de face_0:
2358 assert(domaine_vf.face_voisins()(face_0,0) == num_element
2359 || domaine_vf.face_voisins()(face_0,1) == num_element);
2360 double pos_intersection = 1.;
2361 int face_sortie = calculer_face_sortie_element(domaine_vf, num_element,
2362 x0, y0, z0,
2363 x1, y1, z1,
2364 pos_intersection);
2365
2366 // Coordonnees de l'intersection
2367 x = (1. - pos_intersection) * x0 + pos_intersection * x1;
2368 y = (1. - pos_intersection) * y0 + pos_intersection * y1;
2369 z = (1. - pos_intersection) * z0 + pos_intersection * z1;
2370
2371 int face_bord_sortie;
2372
2373 // Le test face_sortie != face_0 permet de gerer des erreurs d'arrondi
2374 // qui font qu'on sort par la mauvaise face (deja vu)
2375 if (face_sortie >= 0 && face_sortie != face_0)
2376 {
2377 const IntTab& face_sommets = domaine_vf.face_sommets();
2378 const int dimension2 = (Objet_U::dimension == 2);
2379 //
2380 // Calcul du numero de l'arete de bord coupee :
2381 // c'est l'arete dont les deux sommets sont des sommets
2382 // de la face "face".
2383 // ----------------------------------------------------
2384 assert(nb_sommets_par_face_ <= 4);
2385 // On met dans face_sortie_sommets les numeros des sommets de la face
2386 // de sortie (indices de sommets dans domaines_vf.domaine().domaine().les_sommets()).
2387 int face_sortie_sommets[4];
2388 int i;
2389 for (i = 0; i < nb_sommets_par_face_; i++)
2390 face_sortie_sommets[i] = face_sommets(face_sortie, i);
2391
2392 // Tableau des numeros des sommets communs a face_0 et a face_sortie,
2393 // tries dans l'ordre croissant (si 2 sommets communs)
2394 // Ce sont des numeros locaux de sommets sur la face_0 :
2395 int sommet_commun[2] = { -1, -1 };
2396 for (i = 0; i < nb_sommets_par_face_; i++)
2397 {
2398 const int face_bord_sommet = face_sommets(face_0, i);
2399 int s = -1;
2400 int j;
2401 for (j = 0; j < nb_sommets_par_face_; j++)
2402 {
2403 s = face_sortie_sommets[j];
2404 if (s == face_bord_sommet)
2405 break;
2406 }
2407 if (s == face_bord_sommet)
2408 {
2409 if (sommet_commun[0] < 0)
2410 {
2411 sommet_commun[0] = i;
2412 if (dimension2)
2413 break; // En dimension 2, il n'y a qu'un sommet commun
2414 }
2415 else
2416 {
2417 sommet_commun[1] = i;
2418 // tri dans l'ordre croissant
2419 if (sommet_commun[0] > sommet_commun[1])
2420 {
2421 sommet_commun[1] = sommet_commun[0];
2422 sommet_commun[0] = i;
2423 }
2424 break; // On a trouve les deux sommets communs
2425 }
2426 }
2427 }
2428
2429 // On doit avoir trouve un sommet commun en 2d, 2 en 3d.
2430 // Test aussi en optimise, sinon ca calcule n'importe-quoi
2431 {
2432 int n;
2433 n = (sommet_commun[0] >= 0) ? 1 : 0;
2434 n += (sommet_commun[1] >= 0) ? 1 : 0;
2435 if (n != Objet_U::dimension - 1)
2436 {
2437 Cerr << "Erreur sur PE " << Process::me()
2438 << " face de sortie non trouvee" << finl;
2439 Process::exit();
2440 }
2441 }
2442 // On cherche a quelle arete correspondent les deux sommets
2443 // communs que l'on vient de trouver :
2444 const Connectivite_frontieres& connect_front = refconnect_front_.valeur();
2445 const IntTab& def_face_arete = connect_front.def_face_aretes();
2446 const int nb_aretes_face = def_face_arete.dimension(0);
2447 for (i = 0; i < nb_aretes_face; i++)
2448 {
2449 // Les deux sommets de l'arete a tester (numeros locaux sur la face_0)
2450 int sommet0 = def_face_arete(i, 0);
2451 int sommet1 = def_face_arete(i, 1);
2452 // ... tries dans l'ordre croissant
2453 if (sommet1 >= 0 && sommet1 < sommet0)
2454 {
2455 int s = sommet1;
2456 sommet1 = sommet0;
2457 sommet0 = s;
2458 }
2459 // Est-ce que c'est la bonne arete ?
2460 if (sommet0 == sommet_commun[0] && sommet1 == sommet_commun[1])
2461 break;
2462 }
2463 // On verifie qu'on a trouve l'arete commune
2464 if (i >= nb_aretes_face)
2465 {
2466 Cerr << "Erreur sur PE " << Process::me()
2467 << " face de sortie non trouvee (2)" << finl;
2468 Process::exit();
2469 }
2470 // Calcul du numero de la face voisine de la face_0 par l'arete i :
2471 face_bord_sortie = connect_front.faces_voisins()(face_0, i);
2472 }
2473 else
2474 {
2475 // On n'a pas trouve d'intersection, (x1,y1,z1) est sur la face_0
2476 face_bord_sortie = -1;
2477 }
2478 return face_bord_sortie;
2479}
2480
2481// Description :
2482// Renvoie la plus grande distance (signee) entre le sommet (x,y,z) et
2483// les plans qui definissent l'element REEL num_element.
2484// Si cette distance est positive, le sommet est a l'exterieur de l'element,
2485// sinon il est a l'interieur. Une majoration de l'erreur sur ce resultat
2486// est donnee par get_erreur_geometrique.
2488 const int num_element,
2489 double x, double y, double z) const
2490{
2491 const int n_faces = nb_faces_elem_;
2492 double f_min = DMAXFLOAT;
2493 for (int face = 0; face < n_faces; face++)
2494 {
2495 double a, b, c, d;
2496 double signe = calcul_eq_plan(domaine_vf, num_element, face, a, b, c, d);
2497 const double f = (a * x + b * y + c * z + d) * signe;
2498 if (f < f_min)
2499 f_min = f;
2500 }
2501 return - f_min;
2502}
2503
2504/*! @brief Renvoie une estimation de l'erreur geometrique (valeur homogene a une distance).
2505 *
2506 * Par exemple si le domaine a une dimension caracteristique de 1e-3
2507 * et si la precision relative des calculs Erreur_relative_maxi_ est fixee a 1E-14
2508 * (valeur fixee dans le code source) alors get_erreur_geometrique renvoie 1E-17.
2509 * Cette valeur est identique sur tous les processeurs et est calculee a partir
2510 * de la taille du domaine.
2511 *
2512 */
2514{
2515 assert(Erreur_max_coordonnees_ > 0.);
2517}
2518
2519/*! @brief Methode outil utilisee pour le traitement des lignes de contact.
2520 *
2521 * Projection du vecteur x_, y_, z_ sur le plan parallele a la face num_face passant
2522 * par l'origine (permet d'obtenir la direction de deplacement d'un sommet sur une
2523 * ligne de contact).
2524 *
2525 */
2527 double& x_,
2528 double& y_,
2529 double& z_) const
2530{
2531 const double x = x_;
2532 const double y = y_;
2533 const double z = z_;
2534 const double nx = equations_plans_faces_(num_face, 0);
2535 const double ny = equations_plans_faces_(num_face, 1);
2536 const double nz = equations_plans_faces_(num_face, 2);
2537 const double a = x * nx + y * ny + z * nz;
2538 x_ = x - a * nx;
2539 y_ = y - a * ny;
2540 z_ = z - a * nz;
2541}
2542
2543// Normale unitaire a la face de bord num_face, au point x,y,z, dirigee vers
2544// l'interieur du domaine.
2545void Parcours_interface::calculer_normale_face_bord(int num_face, double x, double y, double z,
2546 double& nx_, double& ny_, double& nz_) const
2547{
2548 const IntTab& face_voisins = refdomaine_vf_->face_voisins();
2549 double signe;
2550 if (face_voisins(num_face, 0) < 0)
2551 signe = 1.;
2552 else
2553 signe = -1.;
2554 nx_ = equations_plans_faces_(num_face, 0) * signe;
2555 ny_ = equations_plans_faces_(num_face, 1) * signe;
2556 nz_ = equations_plans_faces_(num_face, 2) * signe;
2557}
2558
2559/*! @brief Algorithme base sur une version initiale de Thomas (recode par BM) Ramene le point (x,y,z) a l'interieur de l'element elem du domaine_vf a une
2560 *
2561 * distance >= Erreur_max_coordonnees_ par un algorithme d'Uzawa.
2562 * Valeur de retour: distance finale du sommet aux faces de l'element
2563 * (positive si le sommet est a l'interieur)
2564 *
2565 */
2567 const int elem,
2568 double& x, double& y, double& z) const
2569{
2570 const int nb_faces = domaine_vf.elem_faces().dimension(1);
2571 ArrOfDouble coef_lagrange(nb_faces);
2572 int i;
2573 double somme_m_x = 0., somme_m_y = 0., somme_m_z = 0.;
2574 double norme_infty = 0.;
2575 for (i = 0; i < nb_faces; i++)
2576 {
2577 double a = 0., b = 0., c = 0., d = 0.;
2578 calcul_eq_plan(domaine_vf, elem, i, a, b, c, d);
2579 a = std::fabs(a);
2580 b = std::fabs(b);
2581 c = std::fabs(c);
2582 somme_m_x += a;
2583 somme_m_y += b;
2584 somme_m_z += c;
2585 double somme = a + b + c;
2586 norme_infty = (somme > norme_infty) ? somme : norme_infty;
2587 }
2588 double norme1 = (somme_m_y > somme_m_x) ? somme_m_y : somme_m_x;
2589 norme1 = (somme_m_z > norme1) ? somme_m_z : norme1;
2590 const double rho = 1. / (norme1 * norme_infty);
2591 double solution_x = x;
2592 double solution_y = y;
2593 double solution_z = z;
2594 double dist_min;
2595 const int max_iter = 10;
2596 int niter;
2597 for (niter = 0; niter < max_iter; niter++)
2598 {
2599 dist_min = 1e37;
2600 int finished = 1;
2601 double nsol_x = 0.;
2602 double nsol_y = 0.;
2603 double nsol_z = 0.;
2604 for (i = 0; i < nb_faces; i++)
2605 {
2606 double a = 0., b = 0., c = 0., d = 0.;
2607 double s = calcul_eq_plan(domaine_vf, elem, i, a, b, c, d);
2608 double dist = (a * solution_x + b * solution_y + c * solution_z + d) * s;
2609 // Le nombre suivant est un peu au pif: il ne faut pas prendre une valeur
2610 // qui risque de refaire des erreurs (si on prend 1., ca plante en vdf car
2611 // on a des angles de 45 degres qui font qu'on retombe sur des cas particuliers)
2612 // Il faut un facteur significativement superieur a 1 pour que l'algorithme converge
2613 // en moins de 10 iterations.
2614 double r = 2.0389787 * std::fabs(a) + 3.07687 * std::fabs(b) + 2.528764 * std::fabs(c);
2615 double coef = coef_lagrange[i] - rho * (dist - r * Erreur_max_coordonnees_);
2616 coef = (coef > 0.) ? coef : 0.;
2617 nsol_x += a * s * coef;
2618 nsol_y += b * s * coef;
2619 nsol_z += c * s * coef;
2620 coef_lagrange[i] = coef;
2621 if (dist < Erreur_max_coordonnees_) // Le point est trop pres de parois, on n'a pas converge
2622 finished = 0;
2623 dist_min = (dist < dist_min) ? dist : dist_min;
2624 }
2625 if (finished)
2626 break;
2627 solution_x = nsol_x * 0.5 + x;
2628 solution_y = nsol_y * 0.5 + y;
2629 solution_z = nsol_z * 0.5 + z;
2630 }
2631 if (niter == max_iter)
2632 {
2633 Journal(8) << "Parcours_interface::uzawa2("
2634 << x << " " << y << " " << z << ") non converge. dist_min=" << dist_min << finl;
2635 }
2636 x = solution_x;
2637 y = solution_y;
2638 z = solution_z;
2639 return dist_min;
2640}
2641
2642/*! @brief Pour chaque sommet, s'il est trop pres d'une face eulerienne, deplace le sommet pour l'en eloigner.
2643 *
2644 * Mise a jour de l'espace virtuel des sommets
2645 *
2646 */
2648{
2649 const int nb_sommets = maillage.nb_sommets();
2650 DoubleTab& sommets = maillage.sommets_;
2651 const ArrOfInt& som_elem = maillage.sommet_elem_;
2652 const int dim3 = (sommets.dimension(1) == 3);
2653 const Domaine_VF& domaine_vf = refdomaine_vf_.valeur();
2654 int count = 0;
2655 for (int i = 0; i < nb_sommets; i++)
2656 {
2657 if (maillage.sommet_virtuel(i))
2658 continue;
2659 // Pour les sommets sur les bords du domaine, on les rentre a l'interieur. Avec
2660 // le traitement supplementaire (extension des triangles au dela du domaine,
2661 // cela semble donner un resultat correct. A voir...
2662 //if (maillage.sommet_ligne_contact(i))
2663 // continue;
2664 const int elem = som_elem[i];
2665 double x = sommets(i, 0);
2666 double y = sommets(i, 1);
2667 double z = dim3 ? sommets(i, 2) : 0.;
2668 const double d = distance_sommet_faces(domaine_vf, elem, x, y, z);
2670 {
2671 // On deplace un peu ce sommet:
2672 uzawa2(domaine_vf, elem, x, y, z);
2673 sommets(i, 0) = x;
2674 sommets(i, 1) = y;
2675 if (dim3)
2676 sommets(i, 2) = z;
2677 count++;
2678 }
2679 }
2680 const int nb_som_tot_deplaces = check_int_overflow(mp_sum(count));
2681 if (nb_som_tot_deplaces > 0)
2682 {
2683 if (je_suis_maitre())
2684 Journal(5) << "Parcours_interface::eloigner_sommets_des_faces deplacement " << count << " sommets" << finl;
2685 maillage.desc_sommets().echange_espace_virtuel(sommets);
2686 }
2687 return nb_som_tot_deplaces;
2688}
void clearbit(int_t i) const
Met le bit e a 0.
Definition ArrOfBit.h:100
const IntTab & faces_voisins() const
const IntTab & def_face_aretes() const
void echange_espace_virtuel(ArrOfDouble &tab) const
DoubleTab_t & les_sommets()
Definition Domaine.h:113
IntTab_t & les_elems()
Definition Domaine.h:129
int_t nb_elem() const
Definition Domaine.h:131
int nb_faces_elem(int=0) const
Renvoie le nombre de face de type i des elements geometriques constituants le domaine.
Definition Domaine.h:484
class Domaine_VF
Definition Domaine_VF.h:44
int nb_faces() const
renvoie le nombre global de faces.
Definition Domaine_VF.h:471
virtual double face_normales(int face, int comp) const
Definition Domaine_VF.h:47
double xv(int num_face, int k) const
Definition Domaine_VF.h:76
int face_sommets(int i, int j) const
renvoie le numero du ieme sommet de la face num_face.
Definition Domaine_VF.h:583
int nb_som_face() const
renvoie le nombre de sommets par face.
Definition Domaine_VF.h:494
int elem_faces(int i, int j) const
renvoie le numero de le ieme face de la maille num_elem la facon dont ces faces sont numerotees est
Definition Domaine_VF.h:543
int face_voisins(int num_face, int i) const
renvoie l'element voisin de numface dans la direction i.
Definition Domaine_VF.h:418
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
const Domaine & domaine() const
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
: class Intersections_Elem_Facettes
void ajoute_intersection(int num_facette, int num_element, double surface_intersection, double contrib_volume_phase1, double contrib_barycentre_phase1[3], double contrib_aire_faces_phase1[3], double contrib_barycentre_faces_phase1[3][2], double barycentre_u, double barycentre_v, double barycentre_w)
Ajoute une entree a la liste doublement chainee d'intersections entre la facette d'interface num_face...
void reset(int nb_elements_euleriens=0, int nb_facettes=0)
void get_liste_elements_traverses(int num_facette, ArrOfInt &liste_elements) const
: class Maillage_FT_Disc Cette classe decrit un maillage:
int nb_sommets() const
renvoie le nombre de sommets (reels et virtuels) (egal a sommets().
const DoubleTab & sommets() const
renvoie le tableau des sommets (reels et virtuels) dimension(0) = nombre de sommets,
int sommet_ligne_contact(int i) const
void echanger_facettes(const ArrOfInt &liste_facettes, const ArrOfInt &liste_elem_arrivee, ArrOfInt &facettes_recues_numfacettes, ArrOfInt &facettes_recues_numelement)
Echange des facettes dont les numeros sont fournis dans "liste_facettes" : Pour chaque facette a ajou...
const Desc_Structure_FT & desc_sommets() const
renvoie le descripteur des sommets (espace_distant/virtuel)
double calcul_normale_3D(int num_facette, double norme[3]) const
Intersections_Elem_Facettes intersections_elem_facettes_
int sommet_virtuel(int i) const
static double angle_bidim_axi()
renvoie l'angle solide qui sert a calculer les surfaces et les volumes en bidim_axi
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
classe Objet_U Cette classe est la classe de base des Objets de TRUST
Definition Objet_U.h:73
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
static double precision_geom
Definition Objet_U.h:86
static int bidim_axi
Definition Objet_U.h:102
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
double volume_tetraedre_reference(const DoubleTab &poly_reelles_ref, const FTd_vecteur3 &norme_ref, const FTd_vecteur3 &centre_de_gravite_ref, double epsilon) const
Calcul de la contribution de volume d'une facette a la valeur de l'indicatrice dans le tetraedre de r...
double calcul_eq_plan(const Domaine_VF &domaine_vf, const int num_element, const int num_face_element, double &a, double &b, double &c, double &d) const
void calculer_normale_face_bord(int num_face, double x, double y, double z, double &nx_, double &ny_, double &nz_) const
double volume_tetraedre(const Domaine_VF &domaine_vf, int num_element, int num_facette, const Maillage_FT_Disc &maillage, const DoubleTab &poly_reelles, const FTd_vecteur3 &centre_de_gravite, double epsilon) const
Calcul de la contribution de volume d'une facette a la valeur de l'indicatrice dans un element.
int calcul_intersection_facelem_2D(const Domaine_VF &domaine_vf, Maillage_FT_Disc &maillage, int num_facette, int num_element) const
void parcours_facette(const Domaine_VF &domaine_vf, Maillage_FT_Disc &maillage, ArrOfInt &echange_facettes_numfacette, ArrOfInt &echange_facettes_numelement, int num_facette, int element_depart) const
static void calcul_inverse_matrice33(const FTd_matrice33 &matrice, FTd_matrice33 &matrice_inv)
Cette methode (statique) permet d'inverser une matrice 3x3.
void matrice_triangle(int num_element, FTd_vecteur2 &origine, FTd_matrice22 &matrice, double &surface) const
Calcul de la matrice 2x2 de transformation pour passer d'une coordonnee dans le repere (x,...
int calculer_sortie_face_bord(const int face_0, const int num_element, double x0, double y0, double z0, double x1, double y1, double z1, double &x, double &y, double &z) const
Methode outil de Maillage_FT_Disc::deplacer_un_point dans le cas d'un marqueur de la ligne de contact...
double uzawa2(const Domaine_VF &domaine_vf, const int elem, double &x, double &y, double &z) const
Algorithme base sur une version initiale de Thomas (recode par BM) Ramene le point (x,...
DoubleTabFT equations_plans_faces_
const DoubleTab * domaine_sommets_ptr
enum Parcours_interface::@373266144117317220251337123122267336271346142325 type_element_
void projeter_vecteur_sur_face(const int num_face, double &x_, double &y_, double &z_) const
Methode outil utilisee pour le traitement des lignes de contact.
double get_erreur_geometrique() const
Renvoie une estimation de l'erreur geometrique (valeur homogene a une distance).
double volume_rectangle_barycentre(const Domaine_VF &domaine_vf, int num_element, double x0, double y0, double x1, double y1, double epsilon, double liquid_barycentre[3]) const
void transformation_2d(const FTd_vecteur2 &origine, const FTd_matrice22 &matrice, double x, double y, double &u, double &v) const
Applique la transformation calculee par matrice_triangle a une coordonnee (x,y).
int calculer_face_sortie_element(const Domaine_VF &domaine_vf, const int num_element, double x0, double y0, double z0, double x1, double y1, double z1, double &pos_intersection) const
Pour un point P0 (x0, y0, z0) a l'INTERIEUR de l'element num_element et un autre point P1 (x1,...
static void calcul_produit_matrice33_vecteur(const FTd_matrice33 &matrice, const FTd_vecteur3 &vect, FTd_vecteur3 &res)
Cette methode (statique) permet de calculer le produit d'une matrice 3x3 avec un vecteur 3.
int eloigner_sommets_des_faces(Maillage_FT_Disc &maillage) const
Pour chaque sommet, s'il est trop pres d'une face eulerienne, deplace le sommet pour l'en eloigner.
ArrOfBit drapeaux_elements_parcourus_
double volume_triangle(const Domaine_VF &domaine_vf, int num_element, double x0, double y0, double x1, double y1, int plan_coupe0, int plan_coupe1) const
Calcul de la contribution de volume d'une facette a la valeur de l'indicatrice dans un element.
int calcul_intersection_facelem_3D(const Domaine_VF &domaine_vf, Maillage_FT_Disc &maillage, int num_facette, int num_element) const
Cette methode permet de calculer l'intersection entre une facette et un element du maillage eulerien.
void parcourir(Maillage_FT_Disc &maillage) const
CutCell_Properties volume_barycentre_hexaedre(const Domaine_VF &domaine_vf, int num_element, const DoubleTab &poly_reelles, const FTd_vecteur3 &norme, const FTd_vecteur3 &centre_de_gravite, const ArrOfInt &polygone_plan_coupe, double epsilon) const
Calcul de la contribution de volume d'une facette a la valeur de l'indicatrice dans un element.
const IntTab * domaine_elem_ptr
double distance_sommet_faces(const Domaine_VF &domaine_vf, const int num_element, double x, double y, double z) const
CutFace_Properties coupe_face_rectangulaire(const Domaine_VF &domaine_vf, int num_element, int num_face, const DoubleTab &poly_reelles, const FTd_vecteur3 &norme, const ArrOfInt &polygone_plan_coupe, double epsilon) const
Calcul de la contribution d'une facette a l'indicatrice surfacique et au barycentre sur une face d'un...
void associer_connectivite_frontieres(const Connectivite_frontieres &connect)
void associer_domaine_dis(const Domaine_dis_base &domaine_dis)
Remplissage des variables persistantes de la classe (refdomaine_vf_, nb_faces_elem_,...
static int check_int_overflow(trustIdType)
Definition Process.cpp:428
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
static double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
Classe de base des flux de sortie.
Definition Sortie.h:52
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133