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