TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Maillage_FT_Disc.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 <Maillage_FT_Disc.h>
17#include <TRUST_Deriv.h>
18#include <TRUSTVect.h>
19#include <Domaine.h>
20#include <Domaine_VF.h>
21#include <Transport_Interfaces_FT_Disc.h>
22#include <Motcle.h>
23#include <EcritureLectureSpecial.h>
24#include <Champ_base.h>
25#include <Paroi_FT_disc.h>
26#include <Sauvegarde_Reprise_Maillage_FT.h>
27#include <communications.h>
28#include <Comm_Group.h>
29#include <SFichier.h>
30#include <LecFicDistribue.h>
31#include <Probleme_FT_Disc_gen.h>
32#include <Dirichlet_entree_fluide_leaves.h>
33#include <Dirichlet_homogene.h>
34#include <Debog.h>
35#include <Array_tools.h>
36#include <Param.h>
37
38#include <TRUST_2_PDI.h>
39
40//#define PATCH_HYSTERESIS_V2
41//#define PATCH_HYSTERESIS_V3
42#include<ArrOfBit.h>
43// //#define DEBUG_HYSTERESIS_V2
44/*
45 * define permettant de post-traiter les triangles et leurs elements miroirs autour d'un point sommet s0.
46 * Pour les tracer :
47\rm xsplit_*
48sed -e '/Postraitement_ft_lata/d' -e '/^First postprocessing/,/First postprocessing/{//!b};d' err > bb
49sed -i -e '/^Cas de 3 sommets/,/of exiting...$/d' \
50 -e '/^Misma/,/of exiting$/d' -e '/^$/d' -e '/^3[ \t]*$/d' -e 's/TAG/# TAG/' bb
51split -d -l 5 bb xsplit_
52gnuplot -p << EOF
53list=system("ls xsplit_*"); splot for [file in list] file w lp t file
54EOF
55 *
56 */
57
58Implemente_instanciable_sans_constructeur(Maillage_FT_Disc_Data_Cache,"Maillage_FT_Disc_Data_Cache",Objet_U);
60{
61 assert(0);
63 return is;
64}
66{
67 assert(0);
69 return os;
70}
71Maillage_FT_Disc_Data_Cache::Maillage_FT_Disc_Data_Cache()
72{
73 clear();
74}
76{
77 tag_surface_ = -1;
78 tag_normale_ = -1;
79 tag_courbure_ = -1;
80 surface_facettes_.resize_array(0);
81 normale_facettes_.resize(0,0);
82 courbure_sommets_.resize_array(0);
83}
84
85/////////////////////////////////////////////////////////////////////////
86
87Implemente_instanciable_sans_constructeur(Maillage_FT_Disc,"Maillage_FT_Disc",Ensemble_Lagrange_base);
88
89
90/*! @brief Pour chaque sommet du maillage, s'il est sur un bord, on calcule costheta min et max (hysteresis) correspondant a la condition aux limites ou
91 *
92 * se trouve le sommet.
93 * L'angle est constant par face de bord... possibilite de faire mieux
94 * pour un champ xyz
95 *
96 */
97void Maillage_FT_Disc::calculer_costheta_minmax(DoubleTab& costheta) const
98{
100 const Domaine_Cl_dis_base& domaine_cl = eq.domaine_Cl_dis();
101 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF,eq.domaine_dis());
102
103 const int nb_som = nb_sommets();
104 costheta.resize(nb_som, 2);
105 costheta=0;
106 const double deg_to_rad = M_PI / 180.;
107
108 DoubleVect tmp;
109
110 for (int i = 0; i < nb_som; i++)
111 {
112 // Indice de la face de bord dans le domaine_VF
113 const int num_face = sommet_face_bord_[i];
114 if ((num_face < 0) || (num_face>=domaine_vf.nb_faces_bord()))
115 continue;
116 const Cond_lim& cl = domaine_cl.la_cl_de_la_face(num_face);
117 const Cond_lim_base& cl_base = cl.valeur();
118
119 double theta1 = 0., theta2 = 0.;
120 if (sub_type(Paroi_FT_disc, cl_base))
121 {
122 const Paroi_FT_disc& cl_ft = ref_cast(Paroi_FT_disc, cl_base);
123 // Indice de la face sur la frontiere
124 const Frontiere& front = cl_ft.frontiere_dis().frontiere();
125 const int num_premiere_face = front.num_premiere_face();
126 const int num_face_frontiere = num_face - num_premiere_face;
127 // Valeur d'angle imposee sur la face
128 const Paroi_FT_disc::Type_modele type_cl = cl_ft.get_type_modele();
129 switch(type_cl)
130 {
132 {
133 const Champ_front_base& champ_frontiere = cl_ft.champ_front();
134 champ_frontiere.valeurs_face(num_face_frontiere, tmp);
135 theta1 = tmp[0];
136 theta2 = theta1;
137 break;
138 }
140 {
141 const Champ_front_base& champ_frontiere = cl_ft.champ_front();
142 champ_frontiere.valeurs_face(num_face_frontiere, tmp);
143 theta1 = tmp[0];
144 theta2 = tmp[1];
145 break;
146 }
148 {
149 theta1 = 90.;
150 theta2 = 90.;
151 break;
152 }
153 default:
154 Cerr << "Erreur dans Maillage_FT_Disc::calculer_costheta_minmax: condition aux limites non implementee"
155 << finl;
157 }
158 }
159 else
160 {
161 Cerr << "Error in Maillage_FT_Disc::calculer_costheta_minmax:\n "
162 << cl_base.que_suis_je() << " is not a valid boundary condition type."
163 << finl;
165 }
166
167 if (refequation_transport_)
168 {
169 const Transport_Interfaces_FT_Disc& eq_interfaces = refequation_transport_.valeur();
170 const Probleme_base& pb = eq_interfaces.get_probleme_base();
171 Probleme_FT_Disc_gen& pb_ft = ref_cast_non_const(Probleme_FT_Disc_gen, pb);
172 Triple_Line_Model_FT_Disc& tcl = pb_ft.tcl();
173 // change theta to theta_app only when tcl is activated and read_via_file()
174 // read_via_file() to avoid change theta to 0. for TCL used but not activated case
175 if (tcl.is_activated() && tcl.is_read_via_file())
176 {
177 const double theta_app = tcl.get_theta_app();
178 theta1 = theta_app;
179 theta2 = theta_app;
180 }
181 }
182
183 costheta(i, 0) = cos(theta1 * deg_to_rad);
184 costheta(i, 1) = cos(theta2 * deg_to_rad);
185 }
186 desc_sommets_.echange_espace_virtuel(costheta);
187}
188
189/*! @brief renvoie l'angle solide qui sert a calculer les surfaces et les volumes en bidim_axi
190 *
191 */
193{
194 return M_PI * 2.;
195}
196
197/*! @brief constructeur par defaut.
198 *
199 */
201 statut_(RESET),
203 temps_physique_(0.),
204 niveau_plot_(-1),
209 weight_CL_(0.5)
210{
211 mesh_data_cache_.typer("Maillage_FT_Disc_Data_Cache");
212}
213
214/*! @brief renvoie une ref non const au cache de valeurs calculees sur le maillage (courbure, surface, normale, .
215 *
216 * ..)
217 * On fait un cast de l'objet en non const (voir commentaire sur
218 * mesh_data_cache_ dans Maillage_FT_Disc.h)
219 *
220 */
222{
223 const Maillage_FT_Disc_Data_Cache *ptr = &mesh_data_cache_.valeur();
224 // Cast en non const ici !!!
225 return *(Maillage_FT_Disc_Data_Cache *) ptr;
226}
227
228/*! @brief Cette methode change le statut du maillage et invalide le cache de valeurs calculees (surface, courbure, .
229 *
230 * ..)
231 * Il faut l'appeler chaque fois que le maillage est modifie
232 * et avant le prochain appel a get_update_xxx.
233 * Cette methode est appelee par les methode publiques non constantes
234 * de Maillage_FT_Disc et par les methodes de Remaillage, ...
235 *
236 */
238{
239 //Process::Journal()<<"maillage_modifie de "<<statut_<<" a "<<nouveau_statut<<finl;
240 if (nouveau_statut < PARCOURU && statut_ >= PARCOURU)
242 statut_ = nouveau_statut;
244}
245
246/*! @brief La construction par copie est interdite !
247 *
248 */
254
255/*! @brief L'operateur = est interdit !
256 *
257 */
259{
260 assert(0);
262 return *this;
263}
264
265//Lecture des informations necessaires a l initialisation des coordonnees
266//des points qui constituent un ensemble Lagrangien
267// - soit lecture dans un fichier (remplissage direct de sommets_)
268// - soit lecture des informations concernant la distribution dans les sous domaines :
269// nombre de sous domaines a considerer
270// Pour chaque sous domaine :
271// lecture de son nom
272// si repartition aleatoire des points
273// lecture du nombre de marqueurs
274// si repartition uniforme des points
275// lecture du nombre de marqueurs dans chaque direction
276
278{
279 Motcles les_mots(3);
280 {
281 les_mots[0] = "fichier";
282 les_mots[1] = "sous_domaines";
283 les_mots[2] = "sous_zones";
284 }
285
286 Motcle motlu, accolade_fermee="}", accolade_ouverte="{";
287 is >> motlu;
288 if(motlu!=accolade_ouverte)
289 {
290 Cerr << "On attendait une { a la lecture d'une " << que_suis_je() << finl;
291 Cerr << "et non : " << motlu << finl;
293 }
294 is >> motlu;
295
296 while (motlu != accolade_fermee)
297 {
298 int rang=les_mots.search(motlu);
299 switch(rang)
300 {
301 case 0 :
302 {
303 Nom nomfic;
304 is >> nomfic;
305
306 EFichier fic;
307 Cerr << "Lecture de l ensemble des sommets du Maillage_FT_Disc dans le fichier " << nomfic << finl;
308 if (!fic.ouvrir(nomfic))
309 {
310 Cerr << " Erreur a l'ouverture du fichier." << finl;
312 }
313 fic >> sommets_lu_;
314
315 break;
316 }
317 case 1 :
318 case 2 :
319 {
320 int nb_sz;
321 is>>nb_sz;
322 nom_sz.dimensionner(nb_sz);
323 nb_marqs_sz.resize(nb_sz);
324 int dim = Objet_U::dimension;
325 nb_marqs_par_dir.resize(nb_sz,dim);
326
327 for (int i=0; i<nb_sz; i++)
328 {
329 is>>nom_sz[i];
330 is>>motlu;
331 if (motlu=="aleatoire")
332 is>>nb_marqs_sz(i);
333 else if (motlu=="uniforme")
334 {
335 nb_marqs_sz(i) = 1;
336 for (int k=0; k<dim; k++)
337 {
338 is >> nb_marqs_par_dir(i,k);
339 if (nb_marqs_par_dir(i,k)<=0)
340 {
341 if (je_suis_maitre())
342 Cerr<<"Le nombre de marqueurs specifies dans chacune des "<<dim<<" directions doit etre strictement positif"<<finl;
344 }
345 nb_marqs_sz(i) *= nb_marqs_par_dir(i,k);
346 }
347 }
348 else
349 {
350 Cerr<<"Les seules options disponibles pour la distribution de marqueurs sont aleatoire et uniforme"<<finl;
351 Cerr<<motlu<<" n est pas reconnu"<<finl;
353 }
354
355 }
356
357 break;
358 }
359 default :
360 {
361 if (je_suis_maitre())
362 {
363 Cerr << "On ne comprend pas le mot : " << motlu << " dans " << que_suis_je() << finl;
364 Cerr << "Les mots compris sont : " << finl;
365 for (int i=0; i<les_mots.size(); i++)
366 Cerr<<les_mots[i]<<finl;
367 }
369 }
370 }
371 is >> motlu;
372 }
373
374 return is;
375}
376
378{
379 Cerr << "Erreur : ::printOn n'est pas code." << finl;
380 assert(0);
381 return os;
382}
383
384
385Sortie& Maillage_FT_Disc::printFa7(int fa7,int affsom, Sortie& os) const
386{
387 const ArrOfDouble& surface_facette_ = get_update_surface_facettes();
388 const DoubleTab& normale_facette_ = get_update_normale_facettes();
389 int isom,som,nbsom = facettes_.dimension(1);
390 os<<"#fa7="<<fa7<<" soms= ";
391 for (isom=0 ; isom<nbsom ; isom++)
392 {
393 som = facettes_(fa7,isom);
394 os<<" "<<som<<"("<<sommet_PE_owner_[som]<<"-"<<sommet_num_owner_[som]<<")";
395 }
396 if (surface_facette_.size_array()==facettes_.dimension(1))
397 {
398 os<<" surf= "<<surface_facette_[fa7]<<" normale= "<<normale_facette_(fa7,0)<<" "<<normale_facette_(fa7,1);
399 if (dimension==3)
400 {
401 os<<" "<<normale_facette_(fa7,2);
402 }
403 }
404 os<<finl;
405 if (affsom==1 && nbsom>2)
406 {
407 for (isom=0 ; isom<nbsom ; isom++)
408 {
409 som = facettes_(fa7,isom);
410 printSom(som,os);
411 }
412 som = facettes_(fa7,0);
413 printSom(som,os);
414 os<<finl;
415 }
416
417 return os;
418}
420{
421 os<<"sommet "<<som;
422 if (som>=0)
423 {
424 os<<" pe-Som="<<sommet_PE_owner_[som]<<"-"<<sommet_num_owner_[som]<<" coords= "<<sommets_(som,0)<<" "<<sommets_(som,1);
425 if (dimension==3)
426 {
427 os<<" "<<sommets_(som,2);
428 }
429 os<<" elem="<<sommet_elem_[som]<<" faceB="<<sommet_face_bord_[som];
430 os<<finl;
431 }
432
433 return os;
434}
435
436void Maillage_FT_Disc::ecrire_plot(const Nom& nom,double un_temps, int niveau_requete) const
437{
438 if (niveau_requete>niveau_plot_)
439 return;
440
441 static int compteur_plot = 0;
442 Nom nom_fic=Objet_U::nom_du_cas();
443 nom_fic += "_";
444 char str[14];
445#if INT_is_64_ == 1
446 snprintf(str,14,"%03ld",compteur_plot++);
447#else
448 snprintf(str,14,"%03d",compteur_plot++);
449#endif
450 nom_fic += Nom(str);
451 nom_fic += "_";
452 if (nom!="")
453 {
454 nom_fic += nom;
455 nom_fic += "_";
456 }
457 if (Process::nproc()>1)
458 {
459#if INT_is_64_ == 1
460 if (Process::nproc()<=1000)
461 snprintf(str,14,"%03ld_",me());
462 else if (Process::nproc()<=10000)
463 snprintf(str,14,"%04ld_",me());
464 else if (Process::nproc()<=100000)
465 snprintf(str,14,"%05ld_",me());
466#else
467 if (Process::nproc()<=1000)
468 snprintf(str,14,"%03d_",me());
469 else if (Process::nproc()<=10000)
470 snprintf(str,14,"%04d_",me());
471 else if (Process::nproc()<=100000)
472 snprintf(str,14,"%05d_",me());
473#endif
474 else
475 {
476 Cerr << "Error in Maillage_FT_Disc::ecrire_plot." << finl;
477 Cerr << "Contact TRUST support." << finl;
479 }
480 nom_fic += Nom(str);
481 }
482 nom_fic += (Nom(un_temps));
483 nom_fic += ".plot";
484 SFichier fic(nom_fic);
485 fic.setf(std::ios::scientific);
486 fic.precision(5);
487 Process::Journal() << "ecriture de " << nom_fic << " au temps " << un_temps << finl;
488
489 //balyage des facettes
490 int fa7,isom,som, k;
491 const int nbfacettes = facettes_.dimension(0);
492 const int nb_som_par_facette = facettes_.dimension(1);
493 FTd_vecteur3 cdg;
494 const double coeff = 0.1;
495 for (fa7=0 ; fa7<nbfacettes ; fa7++)
496 {
497 if (! facette_virtuelle(fa7))
498 {
499 fic << "# ";
500 printFa7(fa7,0,fic);
501 //calcul du cdg de la fa7
502 for (k=0 ; k<dimension ; k++)
503 {
504 cdg[k] = 0.;
505 }
506 for (isom=0 ; isom<nb_som_par_facette ; isom++)
507 {
508 som = facettes_(fa7,isom);
509 for (k=0 ; k<dimension ; k++)
510 {
511 cdg[k] += sommets_(som,k);
512 }
513 }
514 for (k=0 ; k<dimension ; k++)
515 {
516 cdg[k] /= nb_som_par_facette;
517 }
518 //impression des sommets de la facette, avec leger decalage vers le cdg
519 for (isom=0 ; isom<nb_som_par_facette ; isom++)
520 {
521 som = facettes_(fa7,isom);
522 for (k=0 ; k<dimension ; k++)
523 {
524 fic << " "<< sommets_(som,k);
525 }
526 for (k=0 ; k<dimension ; k++)
527 {
528 fic << " "<< sommets_(som,k) - coeff*(sommets_(som,k) - cdg[k]);
529 }
530 fic<<finl;
531 }
532 if (nb_som_par_facette>2)
533 {
534 isom = 0;
535 som = facettes_(fa7,isom);
536 for (k=0 ; k<dimension ; k++)
537 {
538 fic << " "<< sommets_(som,k);
539 }
540 for (k=0 ; k<dimension ; k++)
541 {
542 fic << " "<< sommets_(som,k) - coeff*(sommets_(som,k) - cdg[k]);
543 }
544 fic<<finl;
545 }
546 fic<<finl<<finl;
547 //impression du cdg
548 for (k=0 ; k<dimension ; k++)
549 {
550 fic << " "<< cdg[k];
551 }
552 fic<<finl<<finl;
553 }
554 }
555
556 fic.close();
557}
558
559/*! @brief Cette fonction permet de lire les parametres pour le maillage des interfaces
560 *
561 * @param (is) flot d'entree
562 * @return (Entree) le flot d'entree
563 */
565{
566 Cerr<<"Lecture des parametres de remaillage (Remaillage_FT::lire_param_remaillage)"<<finl;
567
568 Param param("Maillage_FT_Disc::lire_param_maillage");
569 param.ajouter("niveau_plot",&niveau_plot_);
570 param.ajouter("correction_contact_courbure_coeff",&correction_contact_courbure_coeff_);
571 param.ajouter("niter_pre_lissage",&niter_pre_lissage_);
572 param.ajouter("calcul_courbure_iterations",&calcul_courbure_iterations_);
573 param.ajouter("methode_calcul_courbure_contact_line", &methode_calcul_courbure_contact_line_);
574 param.dictionnaire("standard", (int)STANDARD);
575 param.dictionnaire("mirror", (int)MIRROR);
576 param.dictionnaire("improved", (int)IMPROVED);
577 param.dictionnaire("none", (int)NONE);
578 param.dictionnaire("weighted", (int)WEIGHTED);
579 param.dictionnaire("hysteresis", (int)HYSTERESIS);
580 param.ajouter("weight_CL",&weight_CL_);
581 param.lire_avec_accolades(is);
582
583 return is;
584}
585
586/*! @brief on remplit refequation_transport_, schema_comm_domaine_ desc_sommets_.comm_group_ et desc_facettes_.comm_group_
587 *
588 * Precondition: le domaine_dis de l'equation doit etre complete (joints)
589 */
591{
592 const Transport_Interfaces_FT_Disc& eq = ref_cast(Transport_Interfaces_FT_Disc,equation);
593 refequation_transport_ = eq;
594
595 const Domaine_dis_base& domaine_dis = eq.domaine_dis();
596 const Parcours_interface& parcours_interface = eq.parcours_interface();
597 associer_domaine_dis_parcours(domaine_dis, parcours_interface);
598}
599
601{
602 refdomaine_dis_ = domaine_dis;
603 refparcours_interface_ = parcours;
604
605 // On recupere la liste des PE voisins
606 ArrOfIntFT pe_list;
607 for (const auto& itr : domaine_dis.domaine().faces_joint())
608 {
609 const Joint& joint = itr;
610 const int pe_voisin = joint.PEvoisin();
611 pe_list.append_array(pe_voisin);
612 }
613 // La liste des processeurs avec qui on communique dans ce schema sont tous
614 // les voisins du maillage eulerien. Communications symetriques (on envoie
615 // et on recoit a tous les processeurs voisins).
616 schema_comm_domaine_.set_send_recv_pe_list(pe_list, pe_list);
617}
618
619/*! @brief vide toutes les structures du maillage, le statut passe a RESET.
620 *
621 */
623{
624 sommets_.resize(0,dimension);
625 facettes_.resize(0,dimension);
626 voisins_.resize(0,dimension);
627 sommet_elem_.resize_array(0);
628 sommet_face_bord_.resize_array(0);
629 sommet_PE_owner_.resize_array(0);
630 sommet_num_owner_.resize_array(0);
631 desc_sommets_.reset();
632 desc_facettes_.reset();
633 drapeaux_sommets_.resize_array(0);
636
638}
639
640/*! @brief Recopie une partie du maillage source dans *this.
641 *
642 * Si niveau_copie == MINIMAL, seuls les membres de l'etat minimal sont copies.
643 *
644 */
646{
647 reset();
648 if (niveau_copie == RESET)
649 return; // C'est sans interet, mais en toute rigueur on traite le cas...
650
651 // Copie des membres qui definissent l'etat minimal:
652 refequation_transport_ = source.refequation_transport_;
653 refdomaine_dis_ = source.refdomaine_dis_;
654 refparcours_interface_ = source.refparcours_interface_;
657 sommets_ = source.sommets_;
658 facettes_ = source.facettes_;
659 voisins_ = source.voisins_;
660 sommet_elem_ = source.sommet_elem_;
668
669 if (niveau_copie > MINIMAL)
670 {
671 // Attention : le niveau de copie > MINIMAL est partiellement implemente.
672 // Toutes les donnees du Maillage_FT_Disc source ne sont pas copiees.
673
675
679
683 }
684
685 maillage_modifie(niveau_copie);
686}
687
688//Cette methode ajoute le maillage de l'interface passe en parametre
689//Amene l'etat du maillage a MINIMAL
690//skip_facettes = 1 dans le cas d une injection de particules
691void Maillage_FT_Disc::ajouter_maillage(const Maillage_FT_Disc& maillage_tmp,int skip_facettes)
692{
693 assert(maillage_tmp.statut_ >= MINIMAL);
694 assert(&maillage_tmp != this);
695 maillage_tmp.check_mesh(1,0,skip_facettes);
696
697 const int nb_sommets_tmp = maillage_tmp.nb_sommets();
698 const int nb_facettes_tmp = maillage_tmp.nb_facettes();
699 const DoubleTab& sommets_tmp = maillage_tmp.sommets();
700 const IntTab& facettes_tmp = maillage_tmp.facettes();
701 const ArrOfInt& sommet_elem_tmp = maillage_tmp.sommet_elem_;
702 const ArrOfInt& sommet_face_bord_tmp = maillage_tmp.sommet_face_bord_;
703 const ArrOfInt& sommet_PE_owner_tmp = maillage_tmp.sommet_PE_owner();
704 //const ArrOfInt & sommet_num_owner_tmp = maillage_tmp.sommet_num_owner();
705 const ArrOfInt& drapeaux_sommets_tmp = maillage_tmp.drapeaux_sommets_;
706
707 const int nb_sommets_ = nb_sommets();
708 const int nb_facettes_ = nb_facettes();
709 const int nb_sommets_tot = nb_sommets_ + nb_sommets_tmp;
710 const int nb_facettes_tot = nb_facettes_ + nb_facettes_tmp;
711 const int nb_som_par_facette = facettes_tmp.dimension(1);
712
713 //on redimensionne les tableaux
714 sommets_.resize(nb_sommets_tot,dimension);
715 facettes_.resize(nb_facettes_tot,nb_som_par_facette);
716 sommet_elem_.resize_array(nb_sommets_tot);
717 sommet_face_bord_.resize_array(nb_sommets_tot);
718 sommet_PE_owner_.resize_array(nb_sommets_tot);
719 sommet_num_owner_.resize_array(nb_sommets_tot);
720 drapeaux_sommets_.resize_array(nb_sommets_tot);
721 facette_num_owner_.resize_array(nb_facettes_tot);
722
723 //on ajoute les facettes au maillage
724 int fa7, fa7_tmp, isom,som,som_tmp, k;
725 for (fa7_tmp=0 ; fa7_tmp<nb_facettes_tmp ; fa7_tmp++)
726 {
727 fa7 = fa7_tmp + nb_facettes_;
728 for (isom=0 ; isom<nb_som_par_facette ; isom++)
729 {
730 facettes_(fa7,isom) = facettes_tmp(fa7_tmp,isom) + nb_sommets_;
731 }
732 facette_num_owner_[fa7] = fa7; // Puis echange esp.virt. a la fin
733 }
734
735 //on ajoute les sommets au maillage + leurs parametres
736 for (som_tmp=0 ; som_tmp<nb_sommets_tmp ; som_tmp++)
737 {
738 som = som_tmp + nb_sommets_;
739 for (k=0 ; k<dimension ; k++)
740 {
741 sommets_(som,k) = sommets_tmp(som_tmp,k);
742 }
743 sommet_elem_[som] = sommet_elem_tmp[som_tmp];
744 sommet_face_bord_[som] = sommet_face_bord_tmp[som_tmp];
745 sommet_PE_owner_[som] = sommet_PE_owner_tmp[som_tmp];
746 sommet_num_owner_[som] = som; // Puis echange esp.virt. a la fin
747 drapeaux_sommets_[som] = drapeaux_sommets_tmp[som_tmp];
748 }
749
750 // Il faut maintenant mettre a jour les descripteurs
751 // avec renumerotation des elements
752 ArrOfInt elements_tmp;
753 {
754 //descripteurs des sommets : espace distant
755 const Desc_Structure_FT& desc_sommets_tmp = maillage_tmp.desc_sommets();
756 const Descripteur_FT& espace_tmp = desc_sommets_tmp.espace_distant();
757 Descripteur_FT& espace_ = desc_sommets_.espace_distant();
758 const ArrOfInt& pe_voisins_tmp = espace_tmp.pe_voisins();
759 int ipe_tmp, pe_tmp, nb_pe_tmp = pe_voisins_tmp.size_array();
760 for (ipe_tmp=0 ; ipe_tmp<nb_pe_tmp ; ipe_tmp++)
761 {
762 pe_tmp = pe_voisins_tmp[ipe_tmp];
763 elements_tmp = espace_tmp.elements(pe_tmp);
764 elements_tmp += nb_sommets_;
765 espace_.ajoute_elements(pe_tmp,elements_tmp);
766 }
767 espace_.calcul_liste_pe_voisins();
768 }
769 {
770 //descripteurs des sommets : espace virtuel
771 const Desc_Structure_FT& desc_sommets_tmp = maillage_tmp.desc_sommets();
772 const Descripteur_FT& espace_tmp = desc_sommets_tmp.espace_virtuel();
773 Descripteur_FT& espace_ = desc_sommets_.espace_virtuel();
774 const ArrOfInt& pe_voisins_tmp = espace_tmp.pe_voisins();
775 int ipe_tmp,pe_tmp, nb_pe_tmp = pe_voisins_tmp.size_array();
776 for (ipe_tmp=0 ; ipe_tmp<nb_pe_tmp ; ipe_tmp++)
777 {
778 pe_tmp = pe_voisins_tmp[ipe_tmp];
779 elements_tmp = espace_tmp.elements(pe_tmp);
780 elements_tmp += nb_sommets_;
781 espace_.ajoute_elements(pe_tmp,elements_tmp);
782 }
783 espace_.calcul_liste_pe_voisins();
784 }
785 {
786 //descripteurs des facettes : espace distant
787 const Desc_Structure_FT& desc_facettes_tmp = maillage_tmp.desc_facettes();
788 const Descripteur_FT& espace_tmp = desc_facettes_tmp.espace_distant();
789 Descripteur_FT& espace_ = desc_facettes_.espace_distant();
790 const ArrOfInt& pe_voisins_tmp = espace_tmp.pe_voisins();
791 int ipe_tmp,pe_tmp, nb_pe_tmp = pe_voisins_tmp.size_array();
792 for (ipe_tmp=0 ; ipe_tmp<nb_pe_tmp ; ipe_tmp++)
793 {
794 pe_tmp = pe_voisins_tmp[ipe_tmp];
795 elements_tmp = espace_tmp.elements(pe_tmp);
796 elements_tmp += nb_facettes_;
797 espace_.ajoute_elements(pe_tmp,elements_tmp);
798 }
799 espace_.calcul_liste_pe_voisins();
800 }
801 {
802 //descripteurs des facettes : espace virtuel
803 const Desc_Structure_FT& desc_facettes_tmp = maillage_tmp.desc_facettes();
804 const Descripteur_FT& espace_tmp = desc_facettes_tmp.espace_virtuel();
805 Descripteur_FT& espace_ = desc_facettes_.espace_virtuel();
806 const ArrOfInt& pe_voisins_tmp = espace_tmp.pe_voisins();
807 int ipe_tmp,pe_tmp, nb_pe_tmp = pe_voisins_tmp.size_array();
808 for (ipe_tmp=0 ; ipe_tmp<nb_pe_tmp ; ipe_tmp++)
809 {
810 pe_tmp = pe_voisins_tmp[ipe_tmp];
811 elements_tmp = espace_tmp.elements(pe_tmp);
812 elements_tmp += nb_facettes_;
813 espace_.ajoute_elements(pe_tmp,elements_tmp);
814 }
815 espace_.calcul_liste_pe_voisins();
816 }
817 //puis enfin mettre a jour leur schema de comm
818 desc_sommets_.calcul_schema_comm(nb_sommets_tot);
819 desc_facettes_.calcul_schema_comm(nb_facettes_tot);
820
821 desc_sommets_.echange_espace_virtuel(sommet_num_owner_);
822 desc_facettes_.echange_espace_virtuel(facette_num_owner_);
823
825
826 check_mesh();
827}
828/*! @brief Remplit la structure intersections_elem_facettes_.
829 *
830 * Le statut passe a PARCOURU.
831 *
832 * Precondition: statut >= MINIMAL
833 */
835{
836 if (statut_==RESET)
837 {
838 Cerr << "Error! Maillage_FT_Disc is empty. Contact TRUST support." << finl;
840 }
841 if (statut_ >= PARCOURU)
842 return;
843 // Remplit la structure intersections_elem_facettes et
844 // ajoute des facettes sur les processeurs "pauvres"
845 const Parcours_interface& p = refparcours_interface_.valeur();
846 statistics().create_custom_counter("Parcours de l'interface",2,"FrontTracking");
847 statistics().begin_count("Parcours de l'interface", statistics().get_last_opened_counter_level()+1);
848 p.parcourir(*this);
849 statistics().end_count("Parcours de l'interface");
851
852}
853
854/*! @brief Complete les structures de donnees du maillage.
855 *
856 * Le statut passe a COMPLET.
857 *
858 * Precondition: statut >= MINIMAL
859 */
861{
862 assert(statut_ != RESET);
864 if (statut_ >= COMPLET)
865 return;
866 // Force le calcul de la normale et la surface des elements
872}
873
874
875/*! @brief Calcul de la fonction indicatrice (on suppose que "indicatrice" a la structure d'un tableau de valeurs aux elements, on ne remplit
876 *
877 * que les elements reels).
878 * La fraction volumique de la phase 1 dans les elements traverses par
879 * une interface est determinee a partir des donnees du parcours dans
880 * "intersections_elem_facettes_".
881 * Les autres elements sont remplis par une methode heuristique utilisant
882 * l'indicatrice_precedente.
883 *
884 * Precondition: statut >= PARCOURU
885 * Attention, l'algorithme est concu de sorte que l'on puisse utiliser le
886 * meme tableau "indicatrice" et "indicatrice_precedente".
887 */
888void Maillage_FT_Disc::calcul_indicatrice(DoubleVect& indicatrice,
889 const DoubleVect& indicatrice_precedente) const
890{
891 assert(statut_ >= PARCOURU);
892
893 statistics().create_custom_counter("Calculer_Indicatrice",2,"FrontTracking");
894 statistics().begin_count("Calculer_Indicatrice",statistics().get_last_opened_counter_level()+1);
895
896 const Domaine_dis_base& domaine_dis = refdomaine_dis_.valeur();
897 const Domaine& ladomaine = domaine_dis.domaine();
898 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis);
899 const int nb_elem = ladomaine.nb_elem();
900 const int nb_elem_tot = ladomaine.nb_elem_tot();
901 const IntTab& elem_faces = domaine_vf.elem_faces();
902 const IntTab& face_voisins = domaine_vf.face_voisins();
903
904 static ArrOfBit elements_calcules;
905 elements_calcules.resize_array(nb_elem_tot);
906 // On ne recalcule pas l'indicatrice sur la majorite du domaine,
907 // uniquement les elements qui ne sont pas traverses et qui ont
908 // une indicatrice qui n'est pas egale a 0 ou 1.
909 elements_calcules = 1;
910
911 indicatrice = indicatrice_precedente;
912 // Mettre a zero les elements traverses, les elements voisins et les elements dont
913 // l'indicatrice n'est ni a zero ni a un.
914 {
915 const int nb_elem_voisins = elem_faces.dimension(1);
916
917 // Boucle sur les elements
918 const ArrOfInt& index_elem = intersections_elem_facettes_.index_elem();
919 assert(indicatrice.size() == nb_elem);
920 int i;
921 DoubleVect check(indicatrice);
922 for (i = 0; i < nb_elem_tot; i++)
923 {
924 const double x = indicatrice_precedente[i];
925 // int check_voisins = ((x != 0.) && (x != 1.));
926 int check_voisins = (!est_egal(x, 0.) && !est_egal(x, 1.));
927 if (i < nb_elem)
928 {
929 int index = index_elem[i];
930 check_voisins |= (index >= 0);
931 check(i) = check_voisins;
932 }
933 }
934 check.echange_espace_virtuel();
935 Debog::verifier("Maillage_FT_Disc::calcul_indicatrice check=",check);
936 for (i = 0; i < nb_elem_tot; i++)
937 {
938 if (check(i))
939 {
940 elements_calcules.clearbit(i);
941 // Boucle sur les voisins
942 int j;
943 for (j = 0; j < nb_elem_voisins; j++)
944 {
945 const int face = elem_faces(i, j);
946 const int elem = face_voisins(face, 0) + face_voisins(face, 1) - i;
947 if (elem >= 0 && elem < nb_elem_tot)
948 elements_calcules.clearbit(elem); // Voisin d'une interf => considere comme non calcule.
949 }
950 }
951 }
952 }
953
954 // Ajout des contributions de volume
955 // Les elements traverses par l'interface deviennent des elements_calcules
956 {
957 const ArrOfInt& index_elem =
958 intersections_elem_facettes_.index_elem();
959 assert(indicatrice.size() == nb_elem);
960
961 // Boucle sur les elements
962 for (int i = 0; i < nb_elem; i++)
963 {
964
965 int index = index_elem[i];
966 double somme_contrib = 0.;
967 // Boucle sur les facettes qui traversent cet element
968 while (index >= 0)
969 {
970 const Intersections_Elem_Facettes_Data& data = intersections_elem_facettes_.data_intersection(index);
971 somme_contrib += data.contrib_volume_phase1_;
972 index = data.index_facette_suivante_;
973 };
974 while (somme_contrib > 1.)
975 somme_contrib -= 1.;
976 while (somme_contrib < 0.)
977 somme_contrib += 1.;
978 if (somme_contrib > 0.) // Pour ne pas faire les elements pures
979 {
980 indicatrice[i] = somme_contrib;
981 elements_calcules.setbit(i);
982 }
983 }
984 }
985
986 const Transport_Interfaces_FT_Disc& eq_interfaces = refequation_transport_.valeur();
987 const int nb_particles_tot=eq_interfaces.get_nb_particles_tot();
988 // Calcul de l'indicatrice au voisinage de l'interface a l'aide
989 // de la fonction distance.
990 // Il reste dans elements_calcules[i] == 0 les voisins de l'interface
991 // in the case of solid particles, the distance to the interface is corrupted
992 // in cells where two particles overlap. Thus, it cannot be used to correct
993 // the phase indicator.
994 if (!is_solid_particle_ || (is_solid_particle_ && nb_particles_tot==1))
995 {
996 const DoubleTab& distance = equation_transport().get_distance_interface().valeurs();
997 int i;
998 int error_count = 0;
999
1000 for (i = 0; i < nb_elem; i++)
1001 {
1002
1003 if (elements_calcules[i] == 0)
1004 {
1005 double x = distance(i);
1006 // La distance a-t-elle ete calculee pour cet element ?
1007 if (x > -1e10)
1008 {
1009 double v = (x > 0.) ? 1. : 0.;
1010 indicatrice[i] = v;
1011 }
1012 else
1013 {
1014 // Probleme : un element a une indicatrice suspecte et
1015 // on ne peut pas l'evaluer avec la fonction distance
1016 // (augmenter le nombre d'iterations du calcul de distance ?)
1017 error_count++;
1018 }
1019 }
1020 }
1021 if (error_count)
1022 {
1023 Cerr << "[" << me() << "] calcul_indicatrice : error_count = " << error_count << finl;
1024 }
1025 }
1026 indicatrice.echange_espace_virtuel();
1027
1028 // Certains elements ont une indicatrice erronee (error_count).
1029 // Deuxieme correction pour tuer les elements isoles qui seraient faux.
1030 // Pour chaque element monophasique (non traverse par une interface)
1031 // calculer la moyenne de l'indicatrice sur les elements monophasiques voisins,
1032 // si moyenne >0.5, mettre a 1 sinon mettre a 0
1033 {
1034 // Pour que l'algo soit parallele, on met a jour a la fin et non au fur et a mesure
1035 // sinon le resultat depend de l'ordre de parcours des elements
1036 // Liste des elements a mettre a changer (colonne 0) et valeur a mettre (colonne 1)
1037 IntTab elems_to_change(0,2);
1038 const int nb_faces_elem = elem_faces.line_size();
1039 const ArrOfInt& index_elem = intersections_elem_facettes_.index_elem();
1040 for (int elem = 0; elem < nb_elem; elem++)
1041 {
1042 // element non traverse par une interface ?
1043 if (index_elem[elem] >= 0)
1044 continue;
1045
1046 double somme = 0.; //somme des indicatrices des elements monophasiques voisins
1047 int count = 0; //nombre d'elements monophasiques voisins
1048 for (int ivoisin = 0; ivoisin < nb_faces_elem; ivoisin++)
1049 {
1050 const int face = elem_faces(elem, ivoisin);
1051 const int elem_voisin = face_voisins(face, 0) + face_voisins(face, 1) - elem;
1052 // element au bord du domaine ?
1053 if (elem_voisin < 0)
1054 continue;
1055 // element voisin non monophasique ?
1056 if (indicatrice[elem_voisin] != 0. && indicatrice[elem_voisin] != 1.)
1057 continue;
1058 // L'element voisin est monophasique
1059 somme += indicatrice[elem_voisin];
1060 count++;
1061 }
1062 // Bug fix Salim Hamidi 2019/25/02
1063 // Si count==1 l'algo etait considere non pertinent... pas toujours correction du bug
1064 // Correction testee en VDF mais deux cas test VEF ont fait des ecarts
1065 if(count == 1)
1066 {
1067 // TODO: A investiguer
1068 // Elem est une maille diphasique.
1069 // Pourquoi lui met-on la valeur de somme qui vaut ici indicatrice[elem_voisin]
1070 // qui est pure (indicatrice[elem_voisin] vaut 0 ou 1)
1071 elems_to_change.append_line(elem, (int)std::lrint(somme));
1072 }
1073 if (count > 1)
1074 {
1075 int indic;
1076 if (indicatrice[elem] == 1.)
1077 indic = 1;
1078 else if (indicatrice[elem] == 0.)
1079 indic = 0;
1080 else
1081 indic = -1;
1082 int new_indic = ((somme * 2) > count) ? 1 : 0;
1083 // on compare somme/count avec l'indicatrice
1084 if (indic != new_indic)
1085 {
1086 // L'indicatrice de cet element doit etre corrigee
1087 elems_to_change.append_line(elem, new_indic);
1088 }
1089 }
1090 }
1091 // Correction du tableau
1092 const int n = elems_to_change.dimension(0);
1093 for (int i = 0; i < n; i++)
1094 {
1095 const int elem = elems_to_change(i, 0);
1096 indicatrice[elem] = elems_to_change(i, 1);
1097 }
1098 if (n > 0)
1099 Journal() << "Calcul indicatrice: correction par voisinage de " << n << " elements" << finl;
1100 }
1101 indicatrice.echange_espace_virtuel();
1102
1103 Debog::verifier("Maillage_FT_Disc::calcul_indicatrice indicatrice=",indicatrice);
1104 elements_calcules.resize_array(0);
1105 statistics().end_count("Calculer_Indicatrice");
1106}
1107
1108/*! @brief Deplace les sommets de l'interface d'un vecteur "deplacement" fourni, Change eventuellement les sommets de processeur, cree eventuellement
1109 *
1110 * des lignes de contact et detecte les collisions.
1111 *
1112 * @param (deplacement) un tableau de taille (nb_sommets(), Objet_U::dimension) contenant le vecteur deplacement de chaque sommet. Les deplacements des sommets virtuels sont ignores.
1113 */
1114void Maillage_FT_Disc::transporter(const DoubleTab& deplacement)
1115{
1116 statistics().create_custom_counter("Transporter_maillage",2,"FrontTracking");
1117 statistics().begin_count("Transporter_maillage",statistics().get_last_opened_counter_level()+1);
1118
1119 assert(deplacement.dimension(0) == sommets_.dimension(0));
1120 assert(deplacement.dimension(1) == sommets_.dimension(1));
1121
1122 int i;
1123 const int dim = Objet_U::dimension;
1124 const int nb_som = nb_sommets();
1125 // La taille est surestimee
1126 ArrOfInt liste_sommets;
1127 liste_sommets.resize_array(nb_som, RESIZE_OPTIONS::NOCOPY_NOINIT);
1128 // Le tableau de deplacement des sommets reels
1129 DoubleTab vecteur;
1130 vecteur.resize(nb_som, dim, RESIZE_OPTIONS::NOCOPY_NOINIT);
1131 ArrOfIntFT liste_sommets_sortis;
1132 ArrOfIntFT numero_face_sortie;
1133
1134 int n = 0;
1135 for (i = 0; i < nb_som; i++)
1136 {
1137 if (! sommet_virtuel(i))
1138 {
1139 liste_sommets[n] = i;
1140 for (int j = 0; j < dim; j++)
1141 vecteur(n, j) = deplacement(i, j);
1142 n++;
1143 }
1144 }
1145 // Taille finale
1146 liste_sommets.resize_array(n);
1147 vecteur.resize_dim0(n);
1148
1149 // Cette methode s'occupe simplement des sommets :
1150 deplacer_sommets(liste_sommets,
1151 vecteur,
1152 liste_sommets_sortis,
1153 numero_face_sortie);
1154
1155 // Lorsque le premier sommet d'une facette est recu ou envoyer,
1156 // il faut changer son proprietaire.
1158
1160 statistics().end_count("Transporter_maillage");
1161}
1162
1163//-Remplit un tableau temporaire sommets_tmp de positions
1164//(voir Ensemble_Lagrange_base::remplir_sommets_tmp)
1165//-Genere la structure complete a partir de ce tableau de positions
1166//(voir remplir_structure())
1168{
1169 DoubleTab sommets_tmp;
1170 remplir_sommets_tmp(sommets_tmp);
1171 remplir_structure(sommets_tmp);
1172}
1173
1174//On remplit la structure de l ensemble Lagrangien
1175// -sommets_ -sommet_elem_ -sommet_face_bord_
1176// -sommet_PE_owner_ -sommet_num_owner_ -drapeaux_sommets_
1177
1178// Demarche similaire a celle appliquee dans Marching_Cubes::construire_iso
1179// -constrution de def_noeud
1180// -on remplit la structure de l ensemble Lagrangien :
1181// sommets_ sommet_elem_ sommet_face_bord_
1182// sommet_PE_owner_ sommet_num_owner_ drapeaux_sommets_
1183
1184//som_init_util_ est rempli (=1 si le sommet i appartient au processeur, 0 sinon)
1185
1186void Maillage_FT_Disc::remplir_structure(const DoubleTab& soms)
1187{
1188
1189 // Au depart la signification de def_noeud est la suivante:
1190 // def_noeud(i,0) = 0 //pas de sens ici
1191 // def_noeud(i,1) = 0 //pas de sens ici
1192 // def_noeud(i,2) = numero_PE (-1 sinon)
1193 // def_noeud(i,3) = numero de sommet
1194 // def_noeud(i,4) = numero de l element qui contient le sommet (-1 sinon)
1195
1196 IntTab def_noeud(0, 4);
1197
1198 reset();
1199 construire_noeuds(def_noeud,soms);
1200
1201 Descripteur_FT& espace_distant = desc_sommets_.espace_distant();
1202 Descripteur_FT& espace_virtuel = desc_sommets_.espace_virtuel();
1203
1204 int nb_noeuds = def_noeud.dimension(0);
1205 for (int noeud=0; noeud<nb_noeuds; noeud++)
1206 {
1207 def_noeud(noeud,3) = def_noeud(noeud,4);
1208 def_noeud(noeud,4) = -1;
1209 }
1210 espace_distant.calcul_liste_pe_voisins();
1211 espace_virtuel.calcul_liste_pe_voisins();
1212 desc_sommets_.calcul_schema_comm(nb_noeuds);
1213
1214 // Ici def_noeud a change de definition:
1215 // def_noeud(i,0) = 0 //pas de sens ici
1216 // def_noeud(i,1) = 0 //pas de sens ici
1217 // def_noeud(i,2) = numero_PE (-1 sinon)
1218 // def_noeud(i,3) = numero de l'element (-1 sinon)
1219 // def_noeud(i,4) = -1 //Pas de noeaud considere sur une face de bord au depart
1220
1221 //Construction de som_init_util pour la structure construite
1222 som_init_util_.resize_array(nb_noeuds);
1223 som_init_util_ = 0;
1224 for (int noeud=0; noeud<nb_noeuds; noeud++)
1225 if (def_noeud(noeud,3)!=-1)
1226 som_init_util_[noeud] = 1;
1227
1228 //On remplit sommets_
1229 //renum donne la correspondance entre un numero de sommet retenu
1230 //et son indice dans def_noeud
1231 IntTab renum;
1232 calculer_coord_noeuds(def_noeud,soms,renum);
1233
1234 {
1235 int nbsommets = sommets_.dimension(0);
1236 sommet_PE_owner_. resize_array(nbsommets);
1237 sommet_num_owner_.resize_array(nbsommets);
1238 sommet_elem_. resize_array(nbsommets);
1239 sommet_face_bord_.resize_array(nbsommets);
1240 drapeaux_sommets_.resize_array(nbsommets);
1241 desc_sommets_.calcul_schema_comm(nbsommets);
1242 desc_sommets_.remplir_element_pe(sommet_PE_owner_);
1243 // Le descripteur des facettes est vide, mais on calcule quand meme
1244 // le schema de comm pour qu'il soit valide
1245
1246 for (int i = 0; i < nbsommets; i++)
1247 {
1248 sommet_num_owner_[i] = i;
1249 const int elem = def_noeud(renum(i), 3);
1250 const int face = def_noeud(renum(i), 4);
1251 sommet_elem_[i] = elem;
1252 sommet_face_bord_[i] = face;
1253 drapeaux_sommets_[i] = 0;
1254 }
1255 desc_sommets_.echange_espace_virtuel(sommet_num_owner_);
1256 desc_sommets_.echange_espace_virtuel(sommet_face_bord_);
1257 }
1258
1259
1261
1262 Journal() << "Maillage_FT_Disc::construire_points" << finl;
1263 Journal() << sommets_.dimension(0) << " noeuds, ";
1264
1266}
1267
1268
1269//On applique une procedure pour determiner
1270// -le processeur a qui appartient un sommet
1271// -le numero d element qui contient ce sommet
1272//On remplit ensuite def_noeud
1273
1274void Maillage_FT_Disc::construire_noeuds(IntTab& def_noeud,const DoubleTab& soms)
1275{
1276 int som;
1277 const Domaine& madomaine = mon_dom_.valeur();
1278 const int nb_elements_reels = madomaine.nb_elem();
1279 const int nb_sommets_tot = soms.dimension(0);
1280
1281 //Procedure pour determiner a quel processeur appartiennent les sommets (tmp3)
1282 //et quel element les contiennent (tmp2)
1283 ///////////////////////////////////////////////////////////////////////////
1284
1285 int nb_som_tot;
1286 const int dim = Objet_U::dimension;
1287 const int moi = Process::me();
1288 const int nbproc = Process::nproc();
1289 const int chunk_size = 65536*nbproc ; // Lire les sommets par blocs
1290
1291 // Lecture des indices des elements contenant le sommet
1292 // int erreur_sommets_exterieurs = 0;
1293
1294 DoubleTab tmp;
1295 // tmp2 : pour chaque sommet, -1 si je ne le garde pas, sinon numero de l'element qui contient le sommet
1296 ArrOfInt tmp2;
1297 // tmp3 : -1 ou numero du processeur qui garde le sommet.
1298 ArrOfInt tmp3;
1299 int i = 0;
1300
1301 nb_som_tot = soms.dimension(0);
1302 if (nb_som_tot>chunk_size)
1303 {
1304 Cerr << "The maximum of particules that you can use in your datafile is equal to " << chunk_size/nbproc << " / processor" << finl;
1305 Cerr << "If you want to exceed this limitation, you must parallelize your calculation with an apropriate number of processor" << finl;
1306 Process::exit();
1307 }
1308
1309 while (i < nb_som_tot)
1310 {
1311 const int n_to_read = std::min(chunk_size, nb_som_tot - i);
1312 tmp.resize(n_to_read, dim);
1313 tmp2.resize_array(n_to_read);
1314 tmp3.resize_array(n_to_read);
1315
1316 for (int j = 0; j < n_to_read; j++)
1317 for (int k = 0; k < dim; k++)
1318 tmp(j, k) = soms(i+j, k);
1319
1320 madomaine.chercher_elements(tmp, tmp2);
1321 // Ne pas tenir compte des sommets dans les elements virtuels
1322 for (int j = 0; j < n_to_read; j++)
1323 if (tmp2[j] >= nb_elements_reels)
1324 tmp2[j] = -1;
1325 // Verifier qu'un processeur et un seul prend la main.
1326 // Le premier processeur initialise tmp3 en mettant son numero
1327 // pour les sommets qu'il possede et -1 pour les autres.
1328 // Puis la liste est passee au processeur suivant qui la complete.
1329 if (moi == 0)
1330 {
1331 // Preparer la premiere liste
1332 for (int j = 0; j < n_to_read; j++)
1333 if (tmp2[j] >= 0)
1334 tmp3[j] = moi;
1335 else
1336 tmp3[j] = -1;
1337 }
1338 else
1339 {
1340 // Recevoir une liste d'attribution du processeur precedent
1341 // et la completer
1342 recevoir(tmp3, moi - 1, moi, 0 /* canal */);
1343 for (int j = 0; j < n_to_read; j++)
1344 if (tmp3[j] >= 0) // Le sommet a ete pris par un autre processeur
1345 tmp2[j] = -1;
1346 else if (tmp2[j] >= 0) // Le sommet n'a pas ete pris et est chez moi
1347 tmp3[j] = moi;
1348 }
1349 if (moi < nbproc - 1)
1350 {
1351 envoyer(tmp3, moi, moi + 1, 0 /* canal */);
1352 }
1353 else
1354 {
1355 // Le dernier processeur prend les sommets qui restent
1356 for (int j = 0; j < n_to_read; j++)
1357 if (tmp3[j] < 0)
1358 {
1359 tmp3[j] = moi;
1360 // Pour l'instant on ne sait pas traiter des maillages qui depassent du
1361 // domaine:
1362 // erreur_sommets_exterieurs=1;
1363 }
1364 }
1365
1366 i += n_to_read;
1367 }
1368
1369 ////////////////////////////////////////////////////////////////////////////
1370 def_noeud.resize(nb_sommets_tot, 5);
1371 int nb_noeuds = 0;
1372
1373 for (som = 0; som < nb_sommets_tot; som++)
1374 {
1375 // Remplissage de def_noeud pour chaque point traites
1376 nb_noeuds=som;
1377 int PE_element;
1378 int numero_element_a_stocker;
1379 PE_element = tmp3[som];
1380 numero_element_a_stocker = tmp2[som];
1381 def_noeud(nb_noeuds, 0) = 0;
1382 def_noeud(nb_noeuds, 1) = 0;
1383 def_noeud(nb_noeuds, 2) = PE_element;
1384 def_noeud(nb_noeuds, 3) = nb_noeuds;
1385 def_noeud(nb_noeuds, 4) = numero_element_a_stocker;
1386
1387 }
1388
1389}
1390
1391//On remplit sommets_ (coordonnees des points a suivre)
1392//On cree renum pour connaitre la correspondance
1393//entre nouveau numero de sommet et ancien dans def_noeud
1394
1395void Maillage_FT_Disc::calculer_coord_noeuds(const IntTab& def_noeud,const DoubleTab& soms,IntTab& renum)
1396{
1397 // Raccourci vers les coordonnees des sommets du maillage eulerien
1398 const int nb_noeuds = def_noeud.dimension(0);
1399 DoubleTab& coord_noeuds = sommets_;
1400 coord_noeuds.resize(nb_noeuds, dimension);
1401 int noeud;
1402 int dimension3 = (dimension == 3);
1403
1404 int indice=0;
1405 renum.resize(0);
1406 for (noeud = 0; noeud < nb_noeuds; noeud++)
1407 {
1408 if (def_noeud(noeud,3) != -1)
1409 {
1410 coord_noeuds(indice, 0) = soms(noeud,0);
1411 coord_noeuds(indice, 1) = soms(noeud,1);
1412 if (dimension3)
1413 coord_noeuds(indice, 2) = soms(noeud,2);
1414 renum.resize(indice+1);
1415 renum(indice)=noeud;
1416 indice++;
1417 }
1418 }
1419
1420 if (!dimension3)
1421 coord_noeuds.resize(indice,2);
1422 else
1423 coord_noeuds.resize(indice,3);
1424
1425}
1426
1427//Methode qui assure le deplacement des sommets (particules)
1428//sans considerations sur les facettes
1429//Une fois le deplacement effectue on applique une procedure de suppression des
1430//sommets virtuels et des sommets se trouvant sur une frontiere ouverte
1431void Maillage_FT_Disc::transporter_simple(const DoubleTab& deplacement)
1432{
1433 assert(deplacement.dimension(0) == sommets_.dimension(0));
1434 assert(deplacement.dimension(1) == sommets_.dimension(1));
1435
1436 int i;
1437 const int dim = Objet_U::dimension;
1438 const int nb_som = nb_sommets();
1439 // La taille est surestimee
1440 ArrOfIntFT liste_sommets(nb_som);
1441 // Le tableau de deplacement des sommets reels
1442 DoubleTabFT vecteur(nb_som, dim);
1443 ArrOfIntFT liste_sommets_sortis;
1444 ArrOfIntFT numero_face_sortie;
1445
1446 int n = 0;
1447 for (i = 0; i < nb_som; i++)
1448 {
1449 if (! sommet_virtuel(i))
1450 {
1451 liste_sommets[n] = i;
1452 for (int j = 0; j < dim; j++)
1453 vecteur(n, j) = deplacement(i, j);
1454 n++;
1455 }
1456 }
1457 // Taille finale
1458 liste_sommets.resize_array(n);
1459 vecteur.resize(n, dim);
1460
1461 int skip_facettes = 1;
1462 deplacer_sommets(liste_sommets,
1463 vecteur,
1464 liste_sommets_sortis,
1465 numero_face_sortie,
1466 skip_facettes);
1467
1469}
1470
1471//Description :
1472// Cette methode calcule les equations des plans passant par les aretes de la facette fa7
1473// et perpendiculaires a la facette.
1474// Les 3 premiers coefficients (a,b,c) designent la normale a ce plan, orientee vers l'interieur de la facette.
1476 int fa7, int isom,
1477 double& a, double& b, double& c, double& d) const
1478{
1479 int res = 1;
1480 const int nb_faces = facettes_.dimension(1);
1481 const DoubleTab& normale_facettes = get_update_normale_facettes();
1482
1483 int som0,som1;
1484 double x0, y0, z0, x1, y1, z1;
1485 double inverse_norme;
1486 //recuperation des sommets de l'arete
1487 som0 = facettes_(fa7,isom);
1488 som1 = facettes_(fa7,(isom+1)%nb_faces);
1489 //recuperation des coordonnees de l'arete
1490 x0 = sommets_(som0,0);
1491 y0 = sommets_(som0,1);
1492 z0 = sommets_(som0,2);
1493 x1 = sommets_(som1,0);
1494 y1 = sommets_(som1,1);
1495 z1 = sommets_(som1,2);
1496 //calcul de la normale a l'arete (dans le plan de la facette)
1497 a = (y1-y0) * normale_facettes(fa7,2) - (z1-z0) * normale_facettes(fa7,1);
1498 b = (z1-z0) * normale_facettes(fa7,0) - (x1-x0) * normale_facettes(fa7,2);
1499 c = (x1-x0) * normale_facettes(fa7,1) - (y1-y0) * normale_facettes(fa7,0);
1500 inverse_norme = 1. / sqrt(a*a + b*b + c*c);
1501 a *= -inverse_norme;
1502 b *= -inverse_norme;
1503 c *= -inverse_norme;
1504 d = - (a * x0 + b * y0 + c * z0);
1505
1506 return res;
1507}
1508
1509
1510//cette fonction calcule la normale unitaire a la facette, a partir des coordonnees de ses sommets.
1511//elle renvoie la surface de la facette.
1512double Maillage_FT_Disc::calcul_normale_3D(int num_facette, double norme[3]) const
1513{
1514 double l = -1.;
1515 int s0 = facettes_(num_facette,0);
1516 int s1 = facettes_(num_facette,1);
1517 int s2 = facettes_(num_facette,2);
1518 double x0 = sommets_(s0,0);
1519 double y0 = sommets_(s0,1);
1520 double z0 = sommets_(s0,2);
1521 double dx1 = sommets_(s1,0) - x0;
1522 double dy1 = sommets_(s1,1) - y0;
1523 double dz1 = sommets_(s1,2) - z0;
1524 double dx2 = sommets_(s2,0) - x0;
1525 double dy2 = sommets_(s2,1) - y0;
1526 double dz2 = sommets_(s2,2) - z0;
1527
1528 //calcul normale : pdt vectoriel
1529 norme[0] = dy1 * dz2 - dy2 * dz1;
1530 norme[1] = dz1 * dx2 - dz2 * dx1;
1531 norme[2] = dx1 * dy2 - dx2 * dy1;
1532 l = sqrt(norme[0] * norme[0] + norme[1] * norme[1] + norme[2] * norme[2]);
1533#ifdef _AFFDEBUG
1534 {
1535 Process::Journal()<<"Maillage_FT_Disc::calcul_normale_3D fa7= "<<num_facette<<finl;
1536 Process::Journal()<<" som 0 coords= "<<x0<<" "<<y0<<" "<<z0<<finl;
1537 Process::Journal()<<" som 1 coords= "<<sommets_(s1,0)<<" "<<sommets_(s1,1)<<" "<<sommets_(s1,2)<<finl;
1538 Process::Journal()<<" som 2 coords= "<<sommets_(s2,0)<<" "<<sommets_(s2,1)<<" "<<sommets_(s2,2)<<finl;
1539 Process::Journal()<<" som 0 coords= "<<x0<<" "<<y0<<" "<<z0<<finl;
1540 Process::Journal()<<" ->normale= "<<norme[0]<<" "<<norme[1]<<" "<<norme[2]<<" norme= "<<l<<finl;
1541 }
1542#endif
1543 if (l != 0.)
1544 {
1545 double inv_l = 1. / l;
1546 norme[0] *= inv_l;
1547 norme[1] *= inv_l;
1548 norme[2] *= inv_l;
1549 }
1550
1551 return l*0.5;
1552}
1553
1554/*! @brief Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le resultat.
1555 *
1556 * Si le maillage
1557 * n'a pas change depuis le dernier calcul (mesh_tag identique)
1558 * alors on ne recalcule pas la valeur.
1559 * Attention, cette methode doit etre appelee simultanement sur
1560 * tous les processeurs.
1561 *
1562 */
1564{
1566 const int tag = get_mesh_tag();
1567 if (data_cache.tag_surface_ != tag)
1568 {
1569 data_cache.tag_surface_ = tag;
1570 data_cache.tag_normale_ = tag;
1572 data_cache.normale_facettes_);
1573 }
1574 return data_cache.surface_facettes_;
1575}
1576
1577/*! @brief Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le resultat.
1578 *
1579 * Si le maillage
1580 * n'a pas change depuis le dernier calcul (mesh_tag identique)
1581 * alors on ne recalcule pas la valeur.
1582 * Attention, cette methode doit etre appelee simultanement sur
1583 * tous les processeurs.
1584 *
1585 */
1587{
1589 const int tag = get_mesh_tag();
1590 if (data_cache.tag_normale_ != tag)
1591 {
1592 data_cache.tag_surface_ = tag;
1593 data_cache.tag_normale_ = tag;
1595 data_cache.normale_facettes_);
1596 }
1597 return data_cache.normale_facettes_;
1598}
1599
1600double Maillage_FT_Disc::compute_surface_and_normale_element(const int elem, const bool normalize, double surface, double normale[3]) const
1601{
1602 const ArrOfDouble& surface_facettes = get_update_surface_facettes();
1603 const DoubleTab& normale_facettes = get_update_normale_facettes();
1605 const ArrOfInt& index_elem = intersections.index_elem();
1606 normale[0]=0.;
1607 normale[1]=0.;
1608 normale[2]=0.;// = {0.,0.,0.}; // Normale sortante de I=0 vers I=1
1609 surface = 0.;
1610 {
1611 int index = index_elem[elem];
1612 if (index<0)
1613 return surface;
1614 // Boucle sur les faces qui traversent l'element:
1615 while (index >= 0)
1616 {
1617 const Intersections_Elem_Facettes_Data& data = intersections.data_intersection(index);
1618 const double fraction_surf = data.fraction_surface_intersection_ * surface_facettes[data.numero_facette_];
1619 for (int dir= 0; dir<Objet_U::dimension; dir++)
1620 normale[dir] += fraction_surf * normale_facettes(data.numero_facette_, dir);
1621 surface += fraction_surf;
1622 index = data.index_facette_suivante_;
1623 }
1624 }
1625
1626 if (normalize)
1627 {
1628 const double norm = sqrt(normale[0]*normale[0]+normale[1]*normale[1]+normale[2]*normale[2]);
1629 if (norm> Objet_U::precision_geom * Objet_U::precision_geom) // c'est a peu pres une surface pour le moment donc norm tres petit.
1630 {
1631 for (int dir= 0; dir<Objet_U::dimension; dir++)
1632 normale[dir] /= norm;
1633 }
1634 }
1635 return surface;
1636}
1637
1638double Maillage_FT_Disc::compute_normale_element(const int elem, const bool normalize, ArrOfDouble& normale) const
1639{
1640 const ArrOfDouble& surface_facettes = get_update_surface_facettes();
1641 const DoubleTab& normale_facettes = get_update_normale_facettes();
1643 const ArrOfInt& index_elem = intersections.index_elem();
1644 normale=0.;// Normale sortante de I=0 vers I=1
1645 {
1646 int index = index_elem[elem];
1647 if (index<0)
1648 return 0.;
1649 // Boucle sur les faces qui traversent l'element:
1650 while (index >= 0)
1651 {
1652 const Intersections_Elem_Facettes_Data& data = intersections.data_intersection(index);
1653 const double fraction_surf = data.fraction_surface_intersection_ * surface_facettes[data.numero_facette_];
1654 for (int dir= 0; dir<Objet_U::dimension; dir++)
1655 normale[dir] += fraction_surf * normale_facettes(data.numero_facette_, dir);
1656 //surface_totale += fraction_surf;
1657 index = data.index_facette_suivante_;
1658 }
1659 //Cerr << "Surface dans l'elem : " << surface_totale << finl;
1660 }
1661
1662 const double norm = norme_array(normale);
1663 if (normalize)
1664 {
1665 if (norm> Objet_U::precision_geom * Objet_U::precision_geom) // c'est a peu pres une surface pour le moment donc norm tres petit.
1666 {
1667 for (int dir= 0; dir<Objet_U::dimension; dir++)
1668 normale[dir] /= norm;
1669 }
1670 }
1671 return norm;
1672}
1673
1675{
1676 const Maillage_FT_Disc_Data_Cache& data_cache = mesh_data_cache();
1677 return data_cache.surface_facettes_;
1678}
1679
1681{
1682 const Maillage_FT_Disc_Data_Cache& data_cache = mesh_data_cache();
1683 return data_cache.normale_facettes_;
1684}
1685
1687{
1688 Vecteur3 coords_fa7(0.,0.,0.);
1689 for (int dir = 0; dir < 3; dir++)
1690 {
1691 for (int som = 0; som < 3; som++)
1692 {
1693 coords_fa7[dir] += sommets_(facettes_(fa7, som), dir);
1694 }
1695 }
1696
1697 for (int dir = 0; dir < 3; dir++)
1698 {
1699 coords_fa7[dir] /= 3.;
1700 }
1701 return coords_fa7;
1702}
1703
1704/*! @brief Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le resultat.
1705 *
1706 * Si le maillage
1707 * n'a pas change depuis le dernier calcul (mesh_tag identique)
1708 * alors on ne recalcule pas la valeur.
1709 * Attention, cette methode doit etre appelee simultanement sur
1710 * tous les processeurs.
1711 *
1712 */
1714{
1716 const int tag = get_mesh_tag();
1717 if (data_cache.tag_courbure_ != tag)
1718 {
1719 data_cache.tag_courbure_ = tag;
1720 calcul_courbure_sommets(data_cache.courbure_sommets_, 1 /*1st call*/);
1721#if (defined(PATCH_HYSTERESIS_V2) || defined(PATCH_HYSTERESIS_V3) )
1722 // pour evaluer correctement l'angle de la ligne de contact...
1723 int ncalls = calcul_courbure_iterations_; // 2;
1724 for (int i=2; i<=ncalls; i++)
1725 calcul_courbure_sommets(data_cache.courbure_sommets_, i /*ith call*/);
1726#endif
1727 }
1728 return data_cache.courbure_sommets_;
1729}
1730
1731/*! @brief Calcul de la surface et de la normale aux facettes du maillage.
1732 *
1733 * Stocke le resultat dans les tableaux en parametres.
1734 *
1735 */
1736void Maillage_FT_Disc::calcul_surface_normale(ArrOfDouble& surface, DoubleTab& normale) const
1737{
1738 assert(statut_ >= MINIMAL);
1739 int i;
1740 int nfacettes_nulles = 0;
1741 const int nbfacettes = facettes_.dimension(0);
1742 surface.resize_array(nbfacettes);
1743 normale.resize(nbfacettes, dimension);
1744 if (dimension == 2)
1745 {
1746 for (i = 0; i < nbfacettes; i++)
1747 {
1748 int s0 = facettes_(i,0);
1749 int s1 = facettes_(i,1);
1750 double dx = sommets_(s1,0) - sommets_(s0,0);
1751 double dy = sommets_(s1,1) - sommets_(s0,1);
1752 double l = sqrt(dx * dx + dy * dy);
1753 double inv_l;
1754 if (l == 0.)
1755 inv_l = 1.;
1756 else
1757 inv_l = 1. / l;
1758
1759 if (bidim_axi)
1760 l *= angle_bidim_axi()*(sommets_(s1,0) + sommets_(s0,0))*0.5;
1761
1762 surface[i] = l;
1763 if (l == 0.)
1764 {
1765 l = 1.;
1766 dy = -1.;
1767 nfacettes_nulles++;
1768 }
1769 // GB. 2020/17/06. In order to create a unit "normale",
1770 // it is necessary to have inv_l as 1./sqrt(dx * dx + dy * dy)
1771 // and not as : 1. / l after the correction!
1772 // That is why 'inv_l' is calculated before 'if (bidim_axi)'
1773 // double inv_l = 1. / l;
1774 normale(i, 0) = - dy * inv_l;
1775 normale(i, 1) = dx * inv_l;
1776 }
1777 }
1778 else
1779 {
1780 double norme[3], s;
1781 for (i = 0; i < nbfacettes; i++)
1782 {
1783 s = calcul_normale_3D(i,norme);
1784 surface[i] = s;
1785 if (s == 0.)
1786 {
1787 s = 1.;
1788 nfacettes_nulles++;
1789#ifdef _AFFDEBUG
1790 Objet_U::Journal() <<"Fa7 de surf nulle ";
1792#endif
1793 }
1794 normale(i, 0) = norme[0];
1795 normale(i, 1) = norme[1];
1796 normale(i, 2) = norme[2];
1797 }
1798 }
1799 if (nfacettes_nulles > 0)
1800 Objet_U::Journal() << "Facettes de surface nulle : " << nfacettes_nulles << finl;
1801}
1802
1804{
1805 assert(statut_ >= MINIMAL);
1806 Cerr<<"ATTENTION : Maillage_FT_Disc::calculer_voisins non implementee !!!"<<finl;
1807 //assert(0);
1808}
1809
1810/*! @brief renvoie le tableau des sommets (reels et virtuels) dimension(0) = nombre de sommets,
1811 *
1812 * dimension(1) = dimension du probleme (2 ou 3)
1813 * contenu = coordonnees des sommets
1814 *
1815 */
1816const DoubleTab& Maillage_FT_Disc::sommets() const
1817{
1818 assert(statut_ >= MINIMAL);
1819 return sommets_;
1820}
1821
1822/*! @brief renvoie le nombre de sommets (reels et virtuels) (egal a sommets().
1823 *
1824 * dimension(0))
1825 *
1826 */
1828{
1829 if (statut_< MINIMAL)
1830 return 0;
1831
1832 return sommets_.dimension(0);
1833}
1834
1835/*! @brief renvoie le tableau des facettes (reelles et virtuelles) dimension(0) = nombre de facettes,
1836 *
1837 * dimension(1) = nombre de sommets par facette (2 en 2D, 3 en 3D)
1838 * contenu = numero des sommets de chaque facette dans le tableau des sommets
1839 *
1840 */
1841const IntTab& Maillage_FT_Disc::facettes() const
1842{
1843 assert(statut_ >= MINIMAL);
1844 return facettes_;
1845}
1846
1847/*! @brief renvoie le nombre de facettes (reelles et virtuelles) (egal a facettes().
1848 *
1849 * dimension(0))
1850 *
1851 */
1853{
1854 if (statut_< MINIMAL)
1855 return 0;
1856
1857 return facettes_.dimension(0);
1858}
1860{
1861 if (statut_< MINIMAL)
1862 return 0;
1863 int compt = 0 ;
1864 for (int ifa=0 ; ifa<facettes_.dimension(0) ; ifa++)
1865 {
1866 if (! facette_virtuelle(ifa))
1867 {
1868 compt++;
1869 }
1870 }
1871 return compt;
1872}
1873
1875{
1876 if (statut_< MINIMAL)
1877 return 0;
1878 int compt = 0 ;
1879 for (int ifa=0 ; ifa<facettes_.dimension(0) ; ifa++)
1880 {
1881 if (! facette_virtuelle(ifa))
1882 {
1883 compt++;
1884 }
1885 }
1887 return compt;
1888}
1889
1891{
1892 if (statut_< MINIMAL)
1893 return 0;
1894 int compt = 0 ;
1895 for (int ifa=0 ; ifa<facettes_.dimension(0) ; ifa++)
1896 {
1897 compt++;
1898 }
1900 return compt;
1901}
1902/*! @brief Cette methode teste si les facettes sont voisines : Des facettes sont voisines si :
1903 *
1904 * -elles ont 1 sommet commun en 2D
1905 * -elles ont 2 sommets communs en 3D
1906 * La methode renvoie -1 si les facettes ne sont pas voisines.
1907 * Elle renvoie l'indice (local) de l'arete (dans fa70) par laquelle les facettes sont voisines
1908 * A OPTIMISER eventuellement
1909 *
1910 */
1912 int& iarete0, int& iarete1) const
1913{
1914 int isom0,isom1, som0,som1;
1915 int res = 0;
1916 iarete1 = iarete0 = -1;
1917 const int nb_som_par_fa7 = facettes_.dimension(1);
1918 int compteur = 0, trouve;
1919
1920 //on marque aussi les sommets communs
1921 int somsCommuns0[3];
1922 int somsCommuns1[3];
1923 somsCommuns0[0] = somsCommuns0[1] = somsCommuns0[2] = 0;
1924 somsCommuns1[0] = somsCommuns1[1] = somsCommuns1[2] = 0;
1925
1926 for (isom0=0 ; isom0<nb_som_par_fa7 ; isom0++)
1927 {
1928 som0 = facettes_(fa70,isom0);
1929 trouve = 0;
1930 for (isom1=0 ; isom1<nb_som_par_fa7 && trouve==0 ; isom1++)
1931 {
1932 som1 = facettes_(fa71,isom1);
1933 if (som1==som0)
1934 {
1935 compteur++;
1936 trouve = 1;
1937 somsCommuns0[isom0]++;
1938 somsCommuns1[isom1]++;
1939 }
1940 }
1941 }
1942
1943 //s'assure que le nb de sommets communs est correct
1944 if (compteur==(nb_som_par_fa7-1))
1945 {
1946 //les facettes sont donc bien voisines
1947 //et recupere les indices des aretes de voisinage dans les facettes
1948 res = 1;
1949 if (dimension==2)
1950 {
1951 iarete0 = (somsCommuns0[0]==1) ? (0) : (1);
1952 iarete1 = (somsCommuns1[0]==1) ? (0) : (1);
1953 assert(facettes_(fa70,iarete0) == facettes_(fa71,iarete1));
1954 }
1955 else
1956 {
1957 //on determine les aretes communes, en fonction des sommets communs
1958 if (somsCommuns0[0]==1)
1959 {
1960 if (somsCommuns0[1]==1)
1961 {
1962 iarete0 = 0;
1963 }
1964 else
1965 {
1966 iarete0 = 2;
1967 }
1968 }
1969 else
1970 {
1971 iarete0 = 1;
1972 }
1973 if (somsCommuns1[0]==1)
1974 {
1975 if (somsCommuns1[1]==1)
1976 {
1977 iarete1 = 0;
1978 }
1979 else
1980 {
1981 iarete1 = 2;
1982 }
1983 }
1984 else
1985 {
1986 iarete1 = 1;
1987 }
1988#ifdef _AFFDEBUG
1989 {
1990 Process::Journal()<<"test facettes_voisines compteur="<<compteur<<finl;
1991 Process::Journal()<<" ";
1992 printFa7(fa70,0,Process::Journal());
1993 Process::Journal()<<" ";
1994 printFa7(fa71,0,Process::Journal());
1995 Process::Journal()<<" somsCommuns0="<<somsCommuns0[0]<<" "<<somsCommuns0[1]<<" "<<somsCommuns0[2]<<finl;
1996 Process::Journal()<<" somsCommuns1="<<somsCommuns1[0]<<" "<<somsCommuns1[1]<<" "<<somsCommuns1[2]<<finl;
1997 Process::Journal()<<" aretes voisines iarete0="<<iarete0<<" iarete1="<<iarete1<<finl;
1998 Process::Journal()<<" test = "<<(facettes_(fa70,iarete0)==facettes_(fa71,iarete1)?1:0)<<" res="<<res<<finl;
1999 }
2000#endif
2001 //attention : il faut aussi que le sens de parcours de l'arete soit opposse
2002 if (facettes_(fa70,iarete0)==facettes_(fa71,iarete1))
2003 {
2004 //les 2 facettes parcourenet l'arete dans le meme sens : elles ne sont pas voisines
2005 //(ou voisines mais pas compatibles au sens du maillage)
2006 res = 0;
2007 }
2008 else
2009 {
2010 if (! (facettes_(fa70,iarete0) == facettes_(fa71,(iarete1+1)%nb_som_par_fa7)) ||
2011 ! (facettes_(fa71,iarete1) == facettes_(fa70,(iarete0+1)%nb_som_par_fa7)) )
2012 {
2013 Process::Journal()<<"PB dans facettes_voisines : fa7 voisines iarete0="<<iarete0<<" iarete1="<<iarete1<<finl;
2014 Process::Journal()<<" ";
2015 printFa7(fa70,0,Process::Journal());
2016 Process::Journal()<<" ";
2017 printFa7(fa71,0,Process::Journal());
2018 Process::Journal()<<" somsCommuns0="<<somsCommuns0[0]<<" "<<somsCommuns0[1]<<" "<<somsCommuns0[2]<<finl;
2019 Process::Journal()<<" somsCommuns1="<<somsCommuns1[0]<<" "<<somsCommuns1[1]<<" "<<somsCommuns1[2]<<finl;
2020 Process::Journal()<<" aretes voisines iarete0="<<iarete0<<" iarete1="<<iarete1<<finl;
2021 Process::Journal()<<" test = "<< (int) (facettes_(fa70,iarete0)==facettes_(fa71,iarete1)?1:0)<<" res="<<res<<finl;
2022 }
2023 assert( facettes_(fa70,iarete0) == facettes_(fa71,(iarete1+1)%nb_som_par_fa7) );
2024 assert( facettes_(fa71,iarete1) == facettes_(fa70,(iarete0+1)%nb_som_par_fa7) );
2025 }
2026 }
2027 }
2028
2029 return res;
2030}
2031
2032//Description :
2033// Cette calcule les voisinages des facettes, en parcourant les intersections avec les elements
2034// Le maillage doit etre en etat PARCOURU.
2035//A OPTIMISER
2037 const Intersections_Elem_Facettes* ief) const
2038{
2039 Process::Journal()<<"Maillage_FT_Disc::calculer_voisinage_facettes"<<finl;
2040 int res = 1;
2041 if (ief==nullptr)
2042 {
2044 assert(statut_ >= PARCOURU);
2045 }
2046 fa7Voisines.resize(nb_facettes(),facettes_.dimension(1));
2047 fa7Voisines = -1;
2048
2049 ArrOfIntFT fa7s_elem;
2050 int i, nb_fa7, ifa70,ifa71,fa70,fa71, iarete0,iarete1;
2051 const Domaine_dis_base& domaine_dis = refdomaine_dis_.valeur();
2052 const Domaine& ladomaine = domaine_dis.domaine();
2053 const int nb_elem = ladomaine.nb_elem(); // Nombre d'elements reels
2054 for (i=0 ; i<nb_elem ; i++)
2055 {
2056 ief->get_liste_facettes_traversantes(i,fa7s_elem);
2057 nb_fa7 = fa7s_elem.size_array();
2058 //on va ensuite tester tous les couples de fa7 posssibles
2059 for (ifa70=0 ; ifa70<nb_fa7 ; ifa70++)
2060 {
2061 fa70 = fa7s_elem[ifa70];
2062 for (ifa71=ifa70+1 ; ifa71<nb_fa7 ; ifa71++)
2063 {
2064 fa71 = fa7s_elem[ifa71];
2065 //on teste d'abord si les facettes sont voisines
2066 if (facettes_voisines(fa70,fa71,iarete0,iarete1))
2067 {
2068 //les facettes sont bien voisines : on memorise ca dans le tableau de voisinage
2069 fa7Voisines(fa70,iarete0) = fa71;
2070 fa7Voisines(fa71,iarete1) = fa70;
2071 }
2072 }
2073 }
2074 }//fin du balayage des elements
2075
2076 return res;
2077}
2078
2079/*! @brief Pour postraitement uniquement : la signification precise des drapeaux est de la cuisine interne a la classe.
2080 *
2081 * ..
2082 *
2083 */
2085{
2086 assert(statut_ >= MINIMAL);
2087 return drapeaux_sommets_;
2088}
2089
2090/*! @brief renvoie le descripteur des sommets (espace_distant/virtuel)
2091 *
2092 */
2094{
2095 assert(statut_ >= MINIMAL);
2096 return desc_sommets_;
2097}
2098/*! @brief renvoie le descripteur des facettes (espace_distant/virtuel)
2099 *
2100 */
2102{
2103 assert(statut_ >= MINIMAL);
2104 return desc_facettes_;
2105}
2106
2107/*! @brief pour postraitement, renvoie le numero du PE proprietaire des sommets
2108 *
2109 */
2111{
2112 assert(statut_ >= MINIMAL);
2113 return sommet_PE_owner_;
2114}
2115/*! @brief pour postraitement, renvoie le numero des sommets sur le PE proprietaire des sommets
2116 *
2117 */
2119{
2120 assert(statut_ >= MINIMAL);
2121 return sommet_num_owner_;
2122}
2123
2124/*! @brief pour postraitement, remplit le tableau en parametre avec le numero du PE proprietaire de chaque facette.
2125 *
2126 */
2127void Maillage_FT_Disc::facette_PE_owner(ArrOfInt& facette_pe) const
2128{
2129 assert(statut_ >= MINIMAL);
2130 facette_pe.resize_array(facettes_.dimension(0));
2131 desc_facettes_.remplir_element_pe(facette_pe);
2132}
2133
2134/*! @brief pour postraitement, renvoie sommet_elem_
2135 *
2136 */
2137const ArrOfInt& Maillage_FT_Disc::sommet_elem() const
2138{
2139 assert(statut_ >= MINIMAL);
2140 return sommet_elem_;
2141}
2142
2143/*! @brief pour postraitement, renvoie sommet_face_bord_
2144 *
2145 */
2147{
2148 assert(statut_ >= MINIMAL);
2149 return sommet_face_bord_;
2150}
2151
2152/*! @brief return temps_physique_ (temps_physique_ ne sert a rien en interne.
2153 *
2154 * ..)
2155 *
2156 */
2158{
2159 return temps_physique_;
2160}
2161
2162/*! @brief return temps_physique_ = t
2163 *
2164 */
2166{
2167 temps_physique_ = t;
2168 return t;
2169}
2170
2171/*! @brief return som_init_util_
2172 *
2173 */
2174const ArrOfInt& Maillage_FT_Disc::som_init_util() const
2175{
2176 return som_init_util_;
2177}
2178
2180{
2181 int special, afaire;
2182 const int format_xyz = EcritureLectureSpecial::is_ecriture_special(special, afaire);
2183 if (format_xyz)
2184 {
2185 const Domaine_dis_base& domaine_dis = refdomaine_dis_.valeur();
2186 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis);
2187 Sauvegarde_Reprise_Maillage_FT::ecrire_xyz(*this, domaine_vf, os);
2188 return 0;
2189 }
2191 {
2192 Cerr << "Maillage_FT_Disc::sauvegarder Format PDI not supported yet" << finl;
2193 Process::exit();
2194 return 0;
2195 }
2196 else
2197 {
2198 int bytes = 0;
2199 os << que_suis_je() << finl;
2200 os << mesh_state_tag_ << finl;
2201 os << temps_physique_ << finl;
2202 // On augmente la precision d'ecriture du maillage Front Tracking
2203 // au moment de l'ecriture et on restaure l'ancienne apres
2204 // Probleme rencontre sur la FA819
2205 int old_precision = (int)os.get_ostream().precision(14);
2206 os << sommets_;
2207 bytes += 8 * sommets_.size_array();
2208 os.precision(old_precision);
2209 os << facettes_;
2210 bytes += 4 * facettes_.size_array();
2211 os << voisins_;
2212 bytes += 4 * voisins_.size_array();
2213 os << sommet_elem_;
2214 bytes += 4 * sommet_elem_.size_array();
2215 os << sommet_face_bord_;
2216 bytes += 4 * sommet_face_bord_.size_array();
2217 os << sommet_PE_owner_;
2218 bytes += 4 * sommet_PE_owner_.size_array();
2219 os << sommet_num_owner_;
2220 bytes += 4 * sommet_num_owner_.size_array();
2221 os << facette_num_owner_;
2222 bytes += 4 * facette_num_owner_.size_array();
2223 os << desc_sommets_;
2224 os << desc_facettes_;
2225 os << drapeaux_sommets_;
2226 bytes += 4 * drapeaux_sommets_.size_array();
2227 return bytes;
2228 }
2229}
2230
2232{
2233 reset();
2234 const int format_xyz =
2236 if (format_xyz)
2237 {
2238 if (refdomaine_dis_)
2239 {
2240 const Domaine_dis_base& domaine_dis = refdomaine_dis_.valeur();
2241 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis);
2242 Sauvegarde_Reprise_Maillage_FT::lire_xyz(*this, &domaine_vf, &is, 0);
2243 }
2244 else
2245 {
2246 // On est dans "avancer", equation non associee
2248 }
2249 }
2251 {
2252 Cerr << "Maillage_FT_Disc::reprendre Format PDI not supported yet" << finl;
2253 Process::exit();
2254 return 0;
2255 }
2256 else
2257 {
2258 Nom motlu;
2259 is >> motlu;
2260 if (motlu != que_suis_je())
2261 {
2262 Cerr << "Erreur dans Maillage_FT_Disc::reprendre\n";
2263 Cerr << " On attendait le motcle " << que_suis_je();
2264 Cerr << "\n On a trouve " << motlu << finl;
2265 Process::exit();
2266 }
2267 is >> mesh_state_tag_;
2268 is >> temps_physique_;
2269 is >> sommets_;
2270 is >> facettes_;
2271 is >> voisins_;
2272 is >> sommet_elem_;
2273 is >> sommet_face_bord_;
2274 is >> sommet_PE_owner_;
2275 is >> sommet_num_owner_;
2276 is >> facette_num_owner_;
2277 is >> desc_sommets_;
2278 is >> desc_facettes_;
2279 is >> drapeaux_sommets_;
2281 if (refdomaine_dis_)
2282 {
2283 // L'equation de transport a ete associee : on reprend le vrai
2284 // maillage (c'est pas une lecture bidon pour passer au bloc suivant
2285 // dans avancer_fichier...)
2286 desc_sommets_.calcul_schema_comm(sommets_.dimension(0));
2287 desc_facettes_.calcul_schema_comm(facettes_.dimension(0));
2288 check_mesh();
2289 }
2290 }
2291 return 1;
2292}
2293
2294/*! @brief fonction qui cree un nouveau sommet par copie d'une existant utilise dans Remailleur_Collision_FT_Collision_Seq
2295 *
2296 */
2298{
2300 if (me()!=sommet_PE_owner_[som])
2301 {
2302 //si je ne suis pas le proprietaire du sommet de reference : on abandonne
2303 return -1;
2304 }
2305
2306 int NVsom = nb_sommets();
2307 int nb_sommets_tot = NVsom+1;
2308 //on redimensionne les tableaux
2309 sommets_.resize(nb_sommets_tot,dimension);
2310 sommet_elem_.resize_array(nb_sommets_tot);
2311 sommet_face_bord_.resize_array(nb_sommets_tot);
2312 sommet_PE_owner_.resize_array(nb_sommets_tot);
2313 sommet_num_owner_.resize_array(nb_sommets_tot);
2314 drapeaux_sommets_.resize_array(nb_sommets_tot);
2315
2316 //copie des donnes dui sommet som dans NVsom
2317 int k;
2318 for (k=0 ; k<dimension ; k++)
2319 {
2320 sommets_(NVsom,k) = sommets_(som,k);
2321 }
2322 sommet_elem_[NVsom] = sommet_elem_[som];
2324 sommet_PE_owner_[NVsom] = sommet_PE_owner_[som];
2325 sommet_num_owner_[NVsom] = NVsom;
2327
2328 return NVsom;
2329}
2330
2331//idem ci-dessus, mais rend le sommet interne (sommet_face_bord_=-1)
2333{
2334 int NVsom = copier_sommet(som);
2335
2336 if (NVsom>=0)
2337 {
2338 //rend le sommet interne
2339 sommet_face_bord_[som] = -1;
2340 }
2341
2342 return NVsom;
2343}
2344
2345
2346/*! @brief Envoi des sommets dont le numero est donne dans liste_sommets au processeur dont le numero est donne dans liste_pe (on cree un
2347 *
2348 * sommet virtuel sur ce processeur). Parmi les sommets de la liste_sommets,
2349 * seuls ceux qui ne sont pas encore dans l'espace virtuel sont crees.
2350 *
2351 * Precondition: Les membres suivants doivent etre valides:
2352 * * sommets_,
2353 * * desc_sommets_,
2354 * * drapeaux_sommets_,
2355 * * sommet_elem_,
2356 * * sommet_PE_owner_,
2357 * * sommet_num_owner_
2358 *
2359 * Postcondition: Les memes tableaux sont valides a la sortie de la fonction.
2360 *
2361 * @param (liste_sommets) une liste de numeros de sommets REELS qui peut contenir des doublons.
2362 * @param (liste_pe) une liste de meme taille que liste_sommets contenant le numero du processeur sur lequel il faut creer un noeud virtuel. Le processeur ne doit pas etre moi.
2363 * @param (comm) un schema de comm valide, dans lequel send_pe_list contient au moins les processeurs cites dans liste_pe.
2364 */
2365void Maillage_FT_Disc::creer_sommets_virtuels(const ArrOfInt& liste_sommets,
2366 const ArrOfInt& liste_pe,
2367 const Schema_Comm& comm)
2368{
2370
2371 const int dimension3 = (dimension == 3);
2372 int i;
2373 const int n = liste_sommets.size_array();
2374 Descripteur_FT& espace_distant = desc_sommets_.espace_distant();
2375
2376 comm.begin_comm();
2377
2378 for (i = 0; i < n; i++)
2379 {
2380 int pe_destination = liste_pe[i];
2381 assert(pe_destination != me());
2382 int numero_sommet = liste_sommets[i];
2383 // Si le sommet est deja connu par le destinataire, on ne l'envoie pas.
2384 if (espace_distant.contient_element(pe_destination, numero_sommet))
2385 continue;
2386
2387 // Ajout du sommet a l'espace distant
2388 espace_distant.ajoute_element(pe_destination, numero_sommet);
2389
2390 // Envoi a l'autre processeur
2391 Sortie& send_buffer = comm.send_buffer(pe_destination);
2392 // On verifie que le sommet est bien reel
2393 assert(! sommet_virtuel(numero_sommet));
2394 int drapeau = drapeaux_sommets_[numero_sommet];
2395 int face_bord = sommet_face_bord_[numero_sommet];
2396 double x = sommets_(numero_sommet,0);
2397 double y = sommets_(numero_sommet,1);
2398 double z = dimension3 ? sommets_(numero_sommet, 2) : 0.;
2399 send_buffer << numero_sommet << drapeau << face_bord << x << y << z;
2400 }
2401
2403
2404 Descripteur_FT& espace_virtuel = desc_sommets_.espace_virtuel();
2405 // Liste des processeurs de qui on a recu des messages
2406 const ArrOfInt& recv_pe_list = comm.get_recv_pe_list();
2407 const int recv_pe_size = recv_pe_list.size_array();
2408 int indice_pe;
2409 for (indice_pe = 0; indice_pe < recv_pe_size; indice_pe++)
2410 {
2411 const int pe_source = recv_pe_list[indice_pe];
2412 Entree& recv_buffer = comm.recv_buffer(pe_source);
2413
2414 do
2415 {
2416 // Numero du sommet sur le PE proprietaire :
2417 int numero_sur_pe_source, drapeau, face_bord;
2418 double x, y, z;
2419 recv_buffer >> numero_sur_pe_source >> drapeau >> face_bord >> x >> y >> z;
2420 if (recv_buffer.eof())
2421 break;
2422
2423 // Creation du sommet
2424 int nsom = sommets_.dimension(0);
2425 if (dimension3)
2426 sommets_.append_line(x, y, z);
2427 else
2428 sommets_.append_line(x, y);
2429 espace_virtuel.ajoute_element(pe_source, nsom);
2430 sommet_elem_.append_array(-1); // C'est un sommet virtuel => -1
2431 sommet_face_bord_.append_array(face_bord);
2432 sommet_PE_owner_.append_array(pe_source);
2433 sommet_num_owner_.append_array(numero_sur_pe_source);
2434 drapeaux_sommets_.append_array(drapeau);
2435 }
2436 while (1);
2437 }
2438 comm.end_comm();
2439
2440 // Recalcul des listes de voisins et du schema de comm
2441 espace_distant.calcul_liste_pe_voisins();
2442 espace_virtuel.calcul_liste_pe_voisins();
2443 desc_sommets_.calcul_schema_comm(sommets_.dimension(0));
2444
2446}
2447
2448/*! @brief Cree chez moi les sommets virtuels specifies par le couple (pe,num) si le sommet n'existe pas encore.
2449 *
2450 * Le sommet est suppose etre reel sur "pe" et le sommet virtuel est cree sur "me()".
2451 * (c'est l'inverse de "creer_sommets_virtuels" qui cree des sommets virtuels chez
2452 * chez le pe demande).
2453 * Fait appel a creer_sommets_virtuels, donc meme preconditions.
2454 *
2455 * @param (request_sommets_pe) une liste de numeros de processeurs DIFFERENTS de me()
2456 * @param (request_sommets_num) une liste de numeros de sommets. Chaque couple pe[i],num[i] designe un sommet reel d'indice "num" sur le processeur "pe". Pour chaque sommet, on cree un sommet virtuel sur me() s'il n'existe pas deja.
2457 */
2458void Maillage_FT_Disc::creer_sommets_virtuels_numowner(const ArrOfInt& request_sommets_pe,
2459 const ArrOfInt& request_sommets_num)
2460{
2461 const int nbproc = Process::nproc();
2462 // Liste des processeurs a qui on envoyer des requetes
2463 // et de qui on va recevoir des noeuds:
2464 ArrOfIntFT send_pe_list;
2465 // Liste des processeurs de qui on va recevoir des requetes
2466 // et a qui on va envoyer des noeuds:
2467 ArrOfIntFT recv_pe_list;
2468 // Pour chaque processeur, est-il dans send_pe_list ?
2469 ArrOfIntFT pe_markers(nbproc);
2470 pe_markers = 0;
2471 {
2472 int i;
2473 const int n = request_sommets_pe.size_array();
2474 assert(n == request_sommets_num.size_array());
2475 for (i = 0; i < n; i++)
2476 {
2477 const int pe = request_sommets_pe[i];
2478 assert(pe != Process::me());
2479 if (pe_markers[pe] == 0)
2480 {
2481 pe_markers[pe] = 1;
2482 send_pe_list.append_array(pe);
2483 }
2484 }
2485 }
2486 // Calcule la send_pe_list en fonction de la recv_pe_list.
2487 // C'est long (communication all_to_all) mais c'est le plus simple
2488 // car les processeurs de la recv_pe_list ne savent pas a priori
2489 // de quels processeurs ils vont recevoir des messages.
2490 {
2491 int sz = send_pe_list.size_array();
2492 ArrOfInt s(sz);
2493 ArrOfInt r;
2494 int i;
2495 for (i = 0; i < sz; i++) s[i] = send_pe_list[i];
2496 reverse_send_recv_pe_list(s, r);
2497 sz = r.size_array();
2498 recv_pe_list.resize_array(sz);
2499 for (i = 0; i < sz; i++) recv_pe_list[i] = r[i];
2500 }
2501
2502 // Envoi des requetes de creation de noeuds aux proprietaires des noeuds.
2503 {
2504 Schema_Comm schema;
2505 schema.set_send_recv_pe_list(send_pe_list, recv_pe_list);
2506 schema.begin_comm();
2507 {
2508 int i;
2509 const int n = request_sommets_pe.size_array();
2510 for (i = 0; i < n; i++)
2511 {
2512 const int pe = request_sommets_pe[i];
2513 const int som = request_sommets_num[i];
2514 schema.send_buffer(pe) << som;
2515 }
2516 }
2518
2519 // Liste des requetes de creation de noeuds recues:
2520 ArrOfIntFT liste_sommets_pe; // Sur quel proc faut-il creer un noeud virt ?
2521 ArrOfIntFT liste_sommets_num; // Numero local du noeud a envoyer
2522 {
2523 int i_pe;
2524 const int n_pe = recv_pe_list.size_array();
2525 for (i_pe = 0; i_pe < n_pe; i_pe++)
2526 {
2527 const int pe = recv_pe_list[i_pe];
2528 Entree& buffer = schema.recv_buffer(pe);
2529 int num_sommet;
2530 while (1)
2531 {
2532 buffer >> num_sommet;
2533 if (buffer.eof())
2534 break;
2535 assert(num_sommet >= 0 && num_sommet < nb_sommets());
2536 liste_sommets_pe.append_array(pe);
2537 liste_sommets_num.append_array(num_sommet);
2538 }
2539 }
2540 }
2541 schema.end_comm();
2542 // Envoi des sommets virtuels requis
2543 // On intervertit les listes "envoi" et "reception"
2544 schema.set_send_recv_pe_list(recv_pe_list, send_pe_list);
2545 creer_sommets_virtuels(liste_sommets_num,
2546 liste_sommets_pe,
2547 schema);
2548 }
2549}
2550
2551/*! @brief Realise l'ensemble des echanges de noeuds specifies dans liste_sommets, liste_elem_virtuel_arrivee et deplacement.
2552 *
2553 * Met a jour les sommets, facettes, espaces distants
2554 * et virtuels. Le maillage retourne a l'etat minimal. Le buffer d'echange est
2555 * reinitialise.
2556 * On stocke dans liste_nouveaux_sommets la liste des numeros des sommets reels
2557 * fraichement arrives sur le domaine, ainsi que le deplacement restant pour
2558 * chacun de ces sommets (tableau a 3 colonnes (meme en dimension 2 !), de taille
2559 * le nombre de nouveaux sommets).
2560 *
2561 * Precondition:
2562 * Les membres suivants doivent etre valides a l'entree de la fonction:
2563 * (Meme liste que pour creer_sommets_virtuels(...) )
2564 * Postcondition:
2565 * Les memes membres sont valides a la sortie.
2566 * Attention: on ne met PAS a jour les facettes, la regle de propriete des
2567 * facettes n'est donc pas verifiee au retour de la fonction.
2568 * Il faut appeler corriger_proprietaire_facettes.
2569 *
2570 */
2571void Maillage_FT_Disc::echanger_sommets_PE(const ArrOfInt& liste_sommets,
2572 const ArrOfInt& liste_elem_virtuel_arrivee,
2573 const ArrOfInt& liste_face_virtuelle_arrivee,
2574 const DoubleTab& deplacement,
2575 ArrOfInt& liste_nouveaux_sommets,
2576 DoubleTab& deplacement_restant,
2577 int skip_facettes)
2578{
2579
2580 if (Comm_Group::check_enabled()) check_mesh(1 /* error is fatal */,
2581 1 /* do not test facette_owner */,
2582 skip_facettes);
2583 assert(statut_ >= MINIMAL);
2584
2585 int i;
2586 // Nombre de sommets a echanger
2587 const int nechange = liste_sommets.size_array();
2588
2589 // Numeros des processeurs a qui on envoie les noeuds
2590 ArrOfIntFT liste_pe(nechange);
2591 // Numeros des elements ou arrivent les noeuds (numero local sur ce proc)
2592 ArrOfIntFT liste_elem_arrivee(nechange);
2593 // Numeros des faces ou arrivent les noeuds "ligne de contact"
2594 ArrOfIntFT liste_face_arrivee(nechange);
2595
2596 // Creation des noeuds virtuels sur le processeur d'arrivee s'ils n'existent
2597 // pas encore.
2598 const Domaine_dis_base& domaine_dis = refdomaine_dis_.valeur();
2599 const Domaine& ladomaine = domaine_dis.domaine();
2600 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis);
2601 const IntTab& elem_virt_pe_num = ladomaine.elem_virt_pe_num();
2602 const IntTab& face_virt_pe_num = domaine_vf.face_virt_pe_num();
2603 const int nb_elements_reels = ladomaine.nb_elem();
2604 const int nb_faces_reelles = domaine_vf.nb_faces();
2605
2606 for (i = 0; i < nechange; i++)
2607 {
2608 // Numero de l'element virtuel ou arrive le sommet
2609 const int numero_element = liste_elem_virtuel_arrivee[i];
2610 // Numero du pe qui possede l'element eulerien
2611 // (si l'index est negatif, c'est que l'element d'arrivee n'est pas virtuel !)
2612 const int index = numero_element - nb_elements_reels;
2613 const int pe_destination = elem_virt_pe_num(index, 0);
2614 // Numero de l'element ou arrive le sommet sur l'autre pe
2615 const int element_d_arrivee = elem_virt_pe_num(index, 1);
2616
2617 // Numero de la face de bord d'arrivee sur l'autre pe
2618 // si le sommet est sur une ligne de contact.
2619 const int numero_face = liste_face_virtuelle_arrivee[i];
2620 // On verifie qu'on connait la face d'arrivee pour les sommets de bord
2621 assert( ((sommet_ligne_contact(liste_sommets[i]) != 0) && (numero_face >= 0))
2622 || ((sommet_ligne_contact(liste_sommets[i]) == 0) && (numero_face < 0)));
2623 int face_d_arrivee = -1;
2624 if (numero_face >= 0)
2625 {
2626 // Calcul du numero local de la face d'arrivee sur le processeur voisin :
2627 const int index_face = numero_face - nb_faces_reelles;
2628 face_d_arrivee = face_virt_pe_num(index_face, 1);
2629 }
2630
2631 liste_pe[i] = pe_destination;
2632 liste_elem_arrivee[i] = element_d_arrivee;
2633 liste_face_arrivee[i] = face_d_arrivee;
2634 }
2635
2636 // Les echanges de sommets se font entre voisins par des joints du maillage
2637 // fixe. On prend donc le schema de communication de la zone.
2638 // Envoi des sommets aux destinataires (pour l'instant, creation de sommets
2639 // virtuels sur le processeur destination).
2640 creer_sommets_virtuels(liste_sommets, liste_pe, schema_comm_domaine_);
2641
2642 // Mise a jour du nouveau PE proprietaire, de l'element contenant le sommet et de la
2643 // face de bord :
2644 // * Remplissage du tableau sommet_PE_owner avec le nouveau proprietaire
2645 // et -1 si le sommet ne change pas de main,
2646 // * Remplissage de sommet_elem_ avec le numero de l'element d'arrivee,
2647 // * Remplissage de sommet_face_bord_ avec le numero de la face,
2648 // * Appel a la methode echanger_elements qui transforme
2649 // les espaces distants et virtuels en fonction du nouveau proprietaire.
2650 sommet_PE_owner_ = -1;
2651 for (i = 0; i < nechange; i++)
2652 {
2653 const int sommet = liste_sommets[i];
2654 const int pe_destination = liste_pe[i];
2655 const int element_d_arrivee = liste_elem_arrivee[i];
2656 const int face_d_arrivee = liste_face_arrivee[i];
2657 // Verifie que le meme sommet ne figure pas deux fois dans la liste :
2658 assert(sommet_PE_owner_[sommet] < 0);
2659 assert(pe_destination != Process::me());
2660 sommet_PE_owner_[sommet] = pe_destination;
2661 // element_d_arrivee est un numero d'element eulerien reel sur le pe_destination
2662 sommet_elem_[sommet] = element_d_arrivee;
2663 sommet_face_bord_[sommet] = face_d_arrivee;
2664 }
2665 desc_sommets_.echange_espace_virtuel(sommet_PE_owner_);
2666 // Envoi du numero d'element contenant les sommets a tous les processeurs
2667 desc_sommets_.echange_espace_virtuel(sommet_elem_);
2668 desc_sommets_.echange_espace_virtuel(sommet_face_bord_);
2669 // Mise a jour des espaces distants et virtuels (c'est la qu'on change
2670 // reelement de proprietaire)
2671 desc_sommets_.echanger_elements(sommet_PE_owner_);
2672 // Recalcul de sommet_PE_owner a partir des descripteurs (on l'avait ecrase
2673 // avec -1 partout sauf pour les sommets qui changent de procs).
2674 desc_sommets_.remplir_element_pe(sommet_PE_owner_);
2675 // On remet a -1 le numero d'element si le sommet n'est pas a moi
2676 const int nbsommets = sommets_.dimension(0);
2677 const int moi = me();
2678 for (i = 0; i < nbsommets; i++)
2679 {
2680 if (sommet_PE_owner_[i] != moi)
2681 sommet_elem_[i] = -1;
2682 else
2683 assert(sommet_elem_[i] >= 0 && sommet_elem_[i] < nb_elements_reels);
2684 }
2685 // Recalcul de sommet_num_owner
2686 for (i = 0; i < nbsommets; i++)
2687 sommet_num_owner_[i] = i;
2688 desc_sommets_.echange_espace_virtuel(sommet_num_owner_);
2689
2690 // Envoi du numero du sommet et du deplacement restant
2691 {
2692 liste_nouveaux_sommets.resize_array(0);
2693 deplacement_restant.resize(0, Objet_U::dimension);
2694 // Choix d'un schema de communication:
2695 // Apres l'echange des sommets, le sommet a envoyer est virtuel sur l'expediteur
2696 // et reel sur le destinataire : on prend le schema
2697 // "les procs ayant des sommets virtuels parlent aux procs ayant des sommets reels"
2698 // (on pourrait reduire cet ensemble).
2699 const Schema_Comm& comm = desc_sommets_.schema_comm_inverse();
2700
2701 comm.begin_comm();
2702 // Remplissage des buffers
2703 for (i = 0; i < nechange; i++)
2704 {
2705 const int pe_destination = liste_pe[i];
2706 const int sommet = liste_sommets[i];
2707 const int num_owner = sommet_num_owner_[sommet];
2708 const double x = deplacement(i, 0);
2709 const double y = deplacement(i, 1);
2710 const double z = deplacement(i, 2);
2711 Sortie& send_buffer = comm.send_buffer(pe_destination);
2712 send_buffer << num_owner << x << y << z;
2713 }
2715 // Recuperation des donnees
2716 const ArrOfInt& recv_pe_list = comm.get_recv_pe_list();
2717 const int recv_pe_size = recv_pe_list.size_array();
2718 int n_recus = 0;
2719 const int dim = Objet_U::dimension;
2720 for (int indice_pe = 0; indice_pe < recv_pe_size; indice_pe++)
2721 {
2722 const int pe_source = recv_pe_list[indice_pe];
2723 Entree& recv_buffer = comm.recv_buffer(pe_source);
2724 while (1)
2725 {
2726 int sommet;
2727 double x, y, z;
2728 recv_buffer >> sommet >> x >> y >> z;
2729 if (recv_buffer.eof())
2730 break;
2731 liste_nouveaux_sommets.append_array(sommet);
2732 deplacement_restant.resize(n_recus+1, dim);
2733 deplacement_restant(n_recus, 0) = x;
2734 deplacement_restant(n_recus, 1) = y;
2735 if (dim==3)
2736 deplacement_restant(n_recus, 2) = z;
2737 n_recus++;
2738 }
2739 }
2740 comm.end_comm();
2741 }
2742
2743 statut_ = MINIMAL;
2744
2745 if (Comm_Group::check_enabled()) check_mesh(1 /* error is fatal */,
2746 1 /* do not test facette_owner */,
2747 skip_facettes);
2748}
2749
2750static void ordonner_sommets_facettes(IntTab& facettes,
2751 const ArrOfInt& sommet_PE_owner,
2752 const ArrOfInt& sommet_num_owner)
2753{
2754 assert(facettes.dimension(1) == 3);
2755 const int nb_facettes = facettes.dimension(0);
2756 int i;
2757 for (i = 0; i < nb_facettes; i++)
2758 {
2759 int s0,s1,s2;
2760 s0 = facettes(i,0);
2761 s1 = facettes(i,1);
2762 s2 = facettes(i,2);
2763 if (s0 == s1) // Facette invalide a effacer
2764 s2 = s0; // il faut qu'elle reste invalide apres permutation
2765 int pe0,pe1,pe2;
2766 pe0 = sommet_PE_owner[s0];
2767 pe1 = sommet_PE_owner[s1];
2768 pe2 = sommet_PE_owner[s2];
2769 int num0,num1,num2;
2770 num0 = sommet_num_owner[s0];
2771 num1 = sommet_num_owner[s1];
2772 num2 = sommet_num_owner[s2];
2773 while (pe1 < pe0 || (pe1 == pe0 && num1 < num0)
2774 || pe2 < pe0 || (pe2 == pe0 && num2 < num0))
2775 {
2776 int tmp;
2777 tmp = s0;
2778 s0 = s1;
2779 s1 = s2;
2780 s2 = tmp;
2781 tmp = pe0;
2782 pe0 = pe1;
2783 pe1 = pe2;
2784 pe2 = tmp;
2785 tmp = num0;
2786 num0 = num1;
2787 num1 = num2;
2788 num2 = tmp;
2789 }
2790 facettes(i,0) = s0;
2791 facettes(i,1) = s1;
2792 facettes(i,2) = s2;
2793 }
2794}
2795
2796/*! @brief Sans changer les sommets existants ni la numerotation des facettes, on change le proprietaire des facettes de sorte que ce soit aussi le proprietaire
2797 *
2798 * du premier sommet de la facette. Pour cela on doit eventuellement creer des
2799 * sommets virtuels supplementaire et des facettes.
2800 * Aucune facette n'est supprimee.
2801 * Certaines facettes reelles sont creees,
2802 * Certaines facettes reelles deviennent virtuelles.
2803 * Le maillage retourne a l'etat minimal.
2804 * Cette methode est utilisee lors de l'algorithme Marching-Cubes, du transport
2805 * et du remaillage pour amener le maillage dans son etat conforme aux conventions.
2806 *
2807 * Precondition:
2808 * Les membres suivants doivent etre valides :
2809 * - Memes membres que creer_facettes_virtuelles
2810 * - desc_facettes_ (remarque)
2811 *(remarque) desc_facettes_ doit etre un descripteur valide (correspondance entre
2812 * elements distants et elements virtuels). En revanche, on suppose que
2813 * la facette peut etre reelle sur n'importe quel processeur (pas forcement
2814 * le proprietaire du premier sommet).
2815 * Postcondition:
2816 * - Toutes les conditions qui definissent l'etat MINIMAL sont remplies.
2817 */
2819{
2820 //Process::Journal()<<"Maillage_FT_Disc::corriger_proprietaires_facettes nb_som="<<nb_sommets()<<finl;
2822 check_mesh(1, 1 /* ne pas tester proprietaire facette */);
2823 assert(statut_ >= MINIMAL);
2824
2825 static ArrOfIntFT facette_pe;
2826 static ArrOfIntFT liste_facettes;
2827 static ArrOfIntFT liste_PE;
2828
2829 if (Objet_U::dimension == 3)
2830 {
2831 ordonner_sommets_facettes(facettes_,
2834 }
2835 int i;
2836 const int moi = me();
2837 {
2838 const int nbfacettes = facettes_.dimension(0);
2839 // Quel est le proprietaire actuel des facettes ?
2840 // (d'apres le descripteur des facettes)
2841 facette_pe.resize_array(nbfacettes);
2842 desc_facettes_.remplir_element_pe(facette_pe);
2843
2844 // A qui devraient etre les facettes ? (d'apres le numero du proprietaire
2845 // du premier sommet).
2846 // On construit facette_pe = -1 si le proprietaire est legitime
2847 // facette_pe = numero du proprietaire legitime sinon.
2848 liste_facettes.resize_array(0);
2849 liste_PE.resize_array(0);
2850 for (i = 0; i < nbfacettes; i++)
2851 {
2852 int pe_actuel = facette_pe[i];
2853 int premier_sommet = facettes_(i, 0);
2854 int pe_legitime = sommet_PE_owner_[premier_sommet];
2855 if (pe_actuel == moi && pe_actuel != pe_legitime)
2856 {
2857 liste_facettes.append_array(i);
2858 liste_PE.append_array(pe_legitime);
2859 facette_pe[i] = pe_legitime;
2860 }
2861 else
2862 {
2863 facette_pe[i] = -1;
2864 }
2865 }
2866 }
2867
2868 // Creation des facettes virtuelles sur le vrai proprietaire.
2869 // Le schema de comm est "les procs ayant des sommets virtuels
2870 // parlent aux procs ayant les sommets reels" (en effet,
2871 // si je suis le proprietaire illegitime d'une facette,
2872 // le sommet 0 est virtuel pour moi et reel pour le proprietaire
2873 // de la facette).
2874 {
2875 const Schema_Comm& comm = desc_sommets_.schema_comm_inverse();
2876 creer_facettes_virtuelles(liste_facettes, liste_PE,
2877 comm.get_send_pe_list(),
2878 comm.get_recv_pe_list());
2879 }
2880 {
2881 // Simple resize, on n'a fait qu'ajouter des elements virtuels qui seront
2882 // ecrases par echange_espace_virtuel
2883 const int nbfacettes = facettes_.dimension(0);
2884 facette_pe.resize_array(nbfacettes);
2885 desc_facettes_.echange_espace_virtuel(facette_pe);
2886 // Mise a jour des espaces distants et virtuels (c'est la qu'on change
2887 // reelement de proprietaire)
2888 desc_facettes_.echanger_elements(facette_pe);
2889 // Mise a jour de facette_num_owner_
2890 facette_num_owner_.resize_array(nbfacettes);
2891 for (i = 0; i < nbfacettes; i++)
2892 facette_num_owner_[i] = i;
2893 desc_facettes_.echange_espace_virtuel(facette_num_owner_);
2894 }
2895
2897 //Process::Journal()<<"FIN Maillage_FT_Disc::corriger_proprietaires_facettes nb_som="<<nb_sommets()<<finl;
2898}
2899
2900/*! @brief Creation de facettes virtuelles sur le pe specifie.
2901 *
2902 * liste_facettes = liste de numeros de facettes reelles a envoyer sur le
2903 * processeur distant (la liste peut comporter des doublons)
2904 * Le processeur distant ne doit pas etre moi !
2905 * liste_pe = numero du pe a qui il faut envoyer chaque facette
2906 * comm = un schema ou send_pe_list contient les PEs mentionnes dans la liste.
2907 *
2908 * Algo: Il faut d'abord creer les sommets des facettes, s'ils n'existent
2909 * pas encore, puis creer les facettes.
2910 * Cas general, le processeur A possede la facette (au sens du descripteur des
2911 * facettes), le processeur B possede un sommet 's' de la facette, on veut envoyer
2912 * la facette au processeur C. Il faut:
2913 * A envoie a B le numero du sommet 's' et le numero du processeur C
2914 * B cree sur C le sommet virtuel 's'
2915 * A envoie a C les numeros des sommets 's' de la facette, C peut maintenant creer la facette.
2916 *
2917 */
2918void Maillage_FT_Disc::creer_facettes_virtuelles(const ArrOfInt& liste_facettes,
2919 const ArrOfInt& liste_facettes_pe,
2920 const ArrOfInt& facettes_send_pe_list,
2921 const ArrOfInt& facettes_recv_pe_list)
2922{
2923 // Lorsque l'on arrive par Maillage_FT_IJK::creer_facettes_virtuelles
2924 // le tableau des compo_connexes doit etre a jour. On peut donc utiliser
2925 // le check_mesh == Maillage_FT_IJK::check_mesh.
2927 check_mesh(1, 1 /* ne pas tester le proprietaire de la facette */);
2928 assert(statut_ >= MINIMAL);
2929
2930 // On envoie des paquets contenant deux types de messages :
2931 // Messages envoyes au destinataire de la facette (pe0)
2932 // token DATA_FACETTE
2933 // numero du PE possedant le sommet0 (pe1)
2934 // numero du sommet 0 de la facette sur le pe0
2935 // numero du PE possedant le sommet1 (pe1)
2936 // numero du sommet 1 de la facette sur pe1
2937 //[ numero du PE possedant le sommet2 (pe2)
2938 // numero du sommet 2 de la facette sur pe2 ] (en dimension 3)
2939 //
2940 // Messages envoyes au pe1 et pe2
2941 // pour leur dire de creer ces sommets sur le pe0
2942 // token DATA_NOEUD
2943 // numero du sommet
2944 // numero du pe0
2945 static const int DATA_FACETTE = 0;
2946 static const int DATA_NOEUD = 1;
2947 int data_facette[8];
2948 int data_noeud[3];
2949 data_facette[0] = DATA_FACETTE;
2950 data_noeud[0] = DATA_NOEUD;
2951
2952 const int n_proc = nproc();
2953 ArrOfIntFT liste_sommets; // liste des sommets a envoyer
2954 ArrOfIntFT liste_sommets_pe;// pour chaque sommet, numero du pe a qui envoyer
2955 ArrOfIntFT recv_pe_flags; // pour chaque pe, recoit-t-il des sommets ?
2956 ArrOfIntFT recv_pe_list; // liste des pe qui recoivent des sommets
2957 ArrOfIntFT send_pe_flags; // pour chaque pe, envoie-t-il des sommets ?
2958 ArrOfIntFT send_pe_list; // liste des pe qui envoient des sommets
2959
2960 int i;
2961 const int moi = me();
2962
2963 liste_sommets.resize_array(0);
2964 liste_sommets_pe.resize_array(0);
2965 recv_pe_flags.resize_array(n_proc);
2966 recv_pe_flags = 0;
2967 send_pe_flags.resize_array(n_proc);
2968 send_pe_flags = 0;
2969
2970 static Schema_Comm comm;
2971 {
2972 // Construction d'un schema de comm contenant a la fois les destinataires
2973 // des facettes (liste_facettes_pe) et les proprietaires des sommets
2974 // des facettes.
2975 const Schema_Comm& comm_sommets = desc_sommets_.schema_comm_inverse();
2976 send_pe_list = comm_sommets.get_send_pe_list();
2977 append_array_to_array(send_pe_list, facettes_send_pe_list);
2978 array_trier_retirer_doublons(send_pe_list);
2979 recv_pe_list = comm_sommets.get_recv_pe_list();
2980 append_array_to_array(recv_pe_list, facettes_recv_pe_list);
2981 array_trier_retirer_doublons(recv_pe_list);
2982 comm.set_send_recv_pe_list(send_pe_list, recv_pe_list);
2983 }
2984 comm.begin_comm();
2985 {
2986 const int nbfacettes = liste_facettes.size_array();
2987 Descripteur_FT& espace_distant = desc_facettes_.espace_distant();
2988
2989 for (i = 0; i < nbfacettes; i++)
2990 {
2991 const int facette = liste_facettes[i];
2992 const int pe_destination = liste_facettes_pe[i];
2993 assert(pe_destination != moi);
2994
2995 // Si la facette est deja virtuelle sur le pe_destination, inutile
2996 // de l'envoyer.
2997 if (espace_distant.contient_element(pe_destination, facette))
2998 continue;
2999
3000 // Ajout de la facette a l'espace distant
3001 espace_distant.ajoute_element(pe_destination, facette);
3002
3003 int n_data = 1;
3004 data_facette[n_data++] = facette; // Numero de la facette chez le proprietaire
3005
3006 for (int j = 0; j < dimension; j++)
3007 {
3008 const int sommet = facettes_(facette, j);
3009 const int le_sommet_num_owner = sommet_num_owner_[sommet];
3010 const int sommet_pe = sommet_PE_owner_[sommet];
3011
3012 // Donnees de la facette pour le destinataire de la facette
3013 data_facette[n_data++] = le_sommet_num_owner;
3014 data_facette[n_data++] = sommet_pe;
3015 // Demande d'envoi du sommet au proprietaire du sommet
3016 if (sommet_pe != pe_destination)
3017 {
3018 if (sommet_pe == moi)
3019 {
3020 // Si le sommet est a moi, j'empile tout de suite le sommet a envoyer
3021 liste_sommets.append_array(le_sommet_num_owner);
3022 liste_sommets_pe.append_array(pe_destination);
3023 send_pe_flags[pe_destination] = 1;
3024 }
3025 else
3026 {
3027 // Sinon, j'envoie la demande au pe qui possede le sommet
3028 data_noeud[1] = le_sommet_num_owner;
3029 data_noeud[2] = pe_destination;
3030 comm.send_buffer(sommet_pe).put(data_noeud, 3);
3031 }
3032 }
3033 }
3034 comm.send_buffer(pe_destination).put(data_facette, n_data);
3035 }
3036 }
3038
3039 static ArrOfIntFT liste_facettes_pe_source;
3040 static ArrOfIntFT liste_facettes_num_owner;
3041 static ArrOfIntFT liste_facettes_sommets;
3042 static ArrOfIntFT liste_facettes_sommets_pe;
3043 liste_facettes_pe_source.resize_array(0);
3044 liste_facettes_num_owner.resize_array(0);
3045 liste_facettes_sommets.resize_array(0);
3046 liste_facettes_sommets_pe.resize_array(0);
3047
3048 // Reception des donnees : liste des sommets a envoyer, liste
3049 // des facettes et des sommets a recevoir. On construit send/recv_pe_flags,
3050 // qui indiquent si on recoit ou si on envoie des sommets a chaque proc.
3051 // Cela servira a construire le schema de comm pour l'envoi des sommets
3052 // virtuels.
3053 {
3054 const ArrOfInt& pe_voisins = comm.get_recv_pe_list();
3055 const int nb_voisins = pe_voisins.size_array();
3056 for (i = 0; i < nb_voisins; i++)
3057 {
3058 const int pe_source = pe_voisins[i];
3059 Entree& buffer = comm.recv_buffer(pe_source);
3060 while (1)
3061 {
3062 int token;
3063 buffer.get(& token, 1);
3064 if (buffer.eof())
3065 break;
3066
3067 switch(token)
3068 {
3069 case DATA_FACETTE:
3070 {
3071 buffer.get(data_facette, 2*dimension+1);
3072 liste_facettes_pe_source.append_array(pe_source); // pe proprietaire de la facette
3073 const int num_facette = data_facette[0];
3074 liste_facettes_num_owner.append_array(num_facette);
3075 for (int j = 0; j < dimension; j++)
3076 {
3077 // Numero du sommet sur le pe proprietaire
3078 int sommet_num = data_facette[j*2+1];
3079 // Numero du pe proprietaire du sommet
3080 int sommet_pe = data_facette[j*2+2];
3081 if (sommet_pe != moi)
3082 recv_pe_flags[sommet_pe] = 1;
3083 liste_facettes_sommets.append_array(sommet_num);
3084 liste_facettes_sommets_pe.append_array(sommet_pe);
3085 }
3086 break;
3087 }
3088 case DATA_NOEUD:
3089 {
3090 buffer.get(data_noeud, 2);
3091 liste_sommets.append_array(data_noeud[0]); // numero du sommet a envoyer
3092 liste_sommets_pe.append_array(data_noeud[1]); // numero du pe destinataire
3093 send_pe_flags[data_noeud[1]] = 1;
3094 break;
3095 }
3096 default:
3097 assert(0);
3098 }
3099 }
3100 }
3101 }
3102 comm.end_comm();
3103
3104 // Creation des sommets virtuels requis
3105 {
3106 // Construction du schema de comm. a partir de la liste des processeurs
3107 // a qui on envoie des donnees et de qui on recoit.
3108 static Schema_Comm comm2;
3109 send_pe_list.resize_array(0);
3110 for (i = 0; i < n_proc; i++)
3111 if (send_pe_flags[i])
3112 send_pe_list.append_array(i);
3113 recv_pe_list.resize_array(0);
3114 for (i = 0; i < n_proc; i++)
3115 if (recv_pe_flags[i])
3116 recv_pe_list.append_array(i);
3117 comm2.set_send_recv_pe_list(send_pe_list, recv_pe_list);
3118 creer_sommets_virtuels(liste_sommets, liste_sommets_pe, comm2);
3119 }
3120
3121 // Creation des facettes virtuelles
3122 {
3123 const int dimension3 = (dimension == 3);
3124 // Conversion des numeros distants des sommets en numeros locaux,
3125 // le resultat remplace le contenu de liste_facettes_sommets.
3127 liste_facettes_sommets,
3128 liste_facettes_sommets_pe,
3129 liste_facettes_sommets);
3130 const int nb_new_facettes = liste_facettes_pe_source.size_array();
3131 int nbfacettes = facettes_.dimension(0);
3132 facettes_.resize(nbfacettes + nb_new_facettes, dimension);
3133 facette_num_owner_.resize_array(nbfacettes + nb_new_facettes);
3134 for (i = 0; i < nb_new_facettes; i++)
3135 {
3136 facettes_(nbfacettes, 0) = liste_facettes_sommets[i*dimension];
3137 facettes_(nbfacettes, 1) = liste_facettes_sommets[i*dimension+1];
3138 if (dimension3)
3139 facettes_(nbfacettes, 2) = liste_facettes_sommets[i*dimension+2];
3140 desc_facettes_.espace_virtuel().ajoute_element(liste_facettes_pe_source[i],
3141 nbfacettes);
3142 facette_num_owner_[nbfacettes] = liste_facettes_num_owner[i];
3143 nbfacettes++;
3144 }
3145 }
3146 desc_facettes_.espace_virtuel().calcul_liste_pe_voisins();
3147 desc_facettes_.espace_distant().calcul_liste_pe_voisins();
3148 desc_facettes_.calcul_schema_comm(facettes_.dimension(0));
3149
3150 statut_ = MINIMAL;
3151
3152 // Si cette methode est appelee par Maillage_FT_IJK::creer_facettes_virtuelles,
3153 // a ce stade, on a cree des facettes sans mettre a jour le tableau compo_connexe.
3154 // Le check_mesh a appeler ne doit donc pas verifier les compo_connexes.
3155 // La verification des compo_connexes est prevue a la fin de
3156 // Maillage_FT_IJK::creer_facettes_virtuelles
3158 Maillage_FT_Disc::check_mesh(1, 1 /* ne pas tester le proprietaire de la facette */);
3159}
3160
3161/*! @brief Echange des facettes dont les numeros sont fournis dans "liste_facettes" : Pour chaque facette a ajouter,
3162 *
3163 * * On determine le processeur destinataire de la facette (c'est le
3164 * processeur qui possede l'element_arrivee)
3165 * * On ajoute la facette sur ce processeur si elle n'existe pas encore
3166 * (creation d'une facette virtuelle et des sommets de la facette).
3167 * * On envoie a ce processeur le numero de l'element_arrivee. Le numero est
3168 * converti en numero local d'un element reel sur ce processeur.
3169 * Cette methode est essentiellement utilisee dans le parcours de l'interface.
3170 *
3171 * Precondition: Le maillage doit etre dans l'etat minimal (en particulier,
3172 * il doit respecter la convention "proprietaire facette=proprietaire 1er sommet").
3173 *
3174 * Trois categories de processeurs vont se parler:
3175 * le processeur A qui connait le numero de la facette a envoyer,
3176 * le processeur B qui possede la facette,
3177 * le processeur C a qui on veut envoyer la facette.
3178 *
3179 * @param (liste_facettes) un tableau contenant des numeros de facettes reelles ou virtuelles, eventuellement avec doublons.
3180 * @param (liste_elem_arrivee) tableau de taille identique a liste_facettes, contenant pour chacune un numero d'element virtuel.
3181 * @param (facettes_recues_numfacettes) tableau rempli lors de l'echange avec la liste des facettes qui ont ete recues (meme si elles existaient deja et avec les doublons eventuels). Le contenu initial du tableau est efface. Aliasing ave liste_facettes autorise.
3182 * @param (facettes_recues_numelement) tableau rempli lors de l'echange: pour chaque facette recue, numero de l'element d'arrivee (c'est la traduction du numero d'element virtuel "liste_elem_arrivee" en numero d'element reel sur le processeur qui a recu la facette. Aliasing avec liste_elem_arrivee autorise.
3183 */
3184void Maillage_FT_Disc::echanger_facettes(const ArrOfInt& liste_facettes,
3185 const ArrOfInt& liste_elem_arrivee,
3186 ArrOfInt& facettes_recues_numfacettes,
3187 ArrOfInt& facettes_recues_numelement)
3188{
3190 const int moi = me();
3191 int i;
3192 const int nb_facettes_envoi = liste_facettes.size_array();
3193
3194 // Numeros des elements euleriens associes a chaque facette (numero local
3195 // de l'element sur le pe qui possede cet element)
3196 static ArrOfIntFT liste_elem_arrivee_local;
3197 // Pour chaque element d'arrivee, determination du PE destination
3198 // et conversion du numero de l'element virtuel en numero local sur ce pe.
3199 static ArrOfIntFT liste_pe_dest;
3200
3201 const Domaine_dis_base& domaine_dis = refdomaine_dis_.valeur();
3202 const Domaine& le_dom = domaine_dis.domaine();
3203 const int nb_elem = le_dom.nb_elem(); // Nombre d'elements reels
3204 {
3205 liste_pe_dest.resize_array(nb_facettes_envoi);
3206 liste_elem_arrivee_local.resize_array(nb_facettes_envoi);
3207
3208 const IntTab& elem_virt_pe_num = le_dom.elem_virt_pe_num();
3209
3210 for (i = 0; i < nb_facettes_envoi; i++)
3211 {
3212 const int elem_voisin = liste_elem_arrivee[i];
3213 // Calcul de l'index de l'element dans elem_virt_pe_num (l'indice 0
3214 // correspond au premier element virtuel, soit l'element nb_elem)
3215 const int index = elem_voisin - nb_elem;
3216 // Numero du pe qui possede l'element voisin
3217 const int pe = elem_virt_pe_num(index, 0);
3218 // Numero local de l'element sur ce pe.
3219 const int elem_local = elem_virt_pe_num(index, 1);
3220 liste_pe_dest[i] = pe;
3221 liste_elem_arrivee_local[i] = elem_local;
3222 }
3223 }
3224 // =======================================================================
3225 // Communication A -> B
3226 //
3227 // Envoi de la liste des facettes a transmettre au processeur proprietaire de la
3228 // facette (A envoie les numeros de facettes a B)
3229 // On remplit facettes_to_send (liste des facettes que B doit envoyer a C)
3230 // facettes_pe_dest (numero du processeur C a qui il faut envoyer)
3231 // BtoC_send_pe_flags (drapeaux des processeurs a qui on envoie)
3232 // Attention : si B=C, on n'envoie pas la facette.
3233 static ArrOfIntFT facettes_to_send;
3234 static ArrOfIntFT facettes_pe_dest;
3235 // Lors de la communication finale entre les procs B et les procs C,
3236 // ces drapeaux indiquent si on recoit des donnees et si on en envoie
3237 // a chacun des processeurs.
3238 static int nbproc = Process::nproc();
3239 static ArrOfIntFT BtoC_send_pe_flags(nbproc);
3240 static ArrOfIntFT BtoC_recv_pe_flags(nbproc);
3241 BtoC_send_pe_flags = 0;
3242 facettes_to_send.resize_array(0);
3243 facettes_pe_dest.resize_array(0);
3244 {
3245 // A et B sont voisins au sens des espaces distants/virtuels des facettes
3246 // (un processeur chez qui la facette est virtuelle envoie des donnees au
3247 // processeur chez qui elle est reelle => schema_comm_inverse)
3248 const Schema_Comm& comm = desc_facettes_.schema_comm_inverse();
3249 comm.begin_comm();
3250 for (i = 0; i < nb_facettes_envoi; i++)
3251 {
3252 const int facette = liste_facettes[i];
3253 const int PE_destinataire = liste_pe_dest[i];
3254 const int premier_sommet = facettes_(facette, 0);
3255 const int PE_proprietaire = sommet_PE_owner_[premier_sommet];
3256 const int facette_num_owner = facette_num_owner_[facette];
3257 if (PE_proprietaire == moi)
3258 {
3259 facettes_to_send.append_array(facette_num_owner);
3260 facettes_pe_dest.append_array(PE_destinataire);
3261 BtoC_send_pe_flags[PE_destinataire] = 1;
3262 }
3263 else
3264 {
3265 if (PE_destinataire != PE_proprietaire)
3266 comm.send_buffer(PE_proprietaire) << facette_num_owner << PE_destinataire;
3267 }
3268 }
3270 const ArrOfInt& recv_pe_list = comm.get_recv_pe_list();
3271 const int nb_recv_pe = recv_pe_list.size_array();
3272 for (i = 0; i < nb_recv_pe; i++)
3273 {
3274 const int pe_source = recv_pe_list[i];
3275 Entree& buffer = comm.recv_buffer(pe_source);
3276 while (1)
3277 {
3278 int facette, PE_destinataire;
3279 buffer >> facette >> PE_destinataire;
3280 if (buffer.eof())
3281 break;
3282 facettes_to_send.append_array(facette);
3283 facettes_pe_dest.append_array(PE_destinataire);
3284 BtoC_send_pe_flags[PE_destinataire] = 1;
3285 }
3286 }
3287 comm.end_comm();
3288 }
3289
3290 // =======================================================================
3291 // Communication A -> C
3292 //
3293 // A envoie a C la liste la liste des facettes, l'expediteur et le numero
3294 // de l'element d'entree.
3295 // On remplit facettes_recues_numfacettes (numerotation temporaire)
3296 // facettes_recues_numelement
3297 // BtoC_recv_pe_flags (drapeaux des procs de qui on recoit des facettes).
3298 // Attention : si B=C on ne recoit pas de donnees de B
3299
3300 // Pour chaque facette recue, numero du PE proprietaire de la facette:
3301 static ArrOfIntFT nouvelles_facettes_pe_proprietaire;
3302 {
3303 nouvelles_facettes_pe_proprietaire.resize_array(0);
3304 BtoC_recv_pe_flags = 0;
3305
3306 // A et C sont voisins au sens du maillage eulerien
3307 const Schema_Comm& comm = schema_comm_domaine_;
3308 comm.begin_comm();
3309 for (i = 0; i < nb_facettes_envoi; i++)
3310 {
3311 const int facette = liste_facettes[i];
3312 const int PE_destinataire = liste_pe_dest[i];
3313 const int element_arrivee = liste_elem_arrivee_local[i];
3314 const int premier_sommet = facettes_(facette, 0);
3315 const int PE_proprietaire = sommet_PE_owner_[premier_sommet];
3316 const int facette_num_owner = facette_num_owner_[facette];
3317 assert (PE_destinataire != moi);
3318 comm.send_buffer(PE_destinataire) << facette_num_owner
3319 << PE_proprietaire
3320 << element_arrivee;
3321 }
3323 // On efface facettes_recues_numfacettes et numelement.
3324 // Pour le cas ou il y aurait aliasing des parametres, il ne faut plus
3325 // utiliser liste_facettes et liste_elem_arrivee.
3326 facettes_recues_numfacettes.resize_array(0);
3327 facettes_recues_numelement.resize_array(0);
3328 const ArrOfInt& recv_pe_list = comm.get_recv_pe_list();
3329 const int nb_recv_pe = recv_pe_list.size_array();
3330 for (i = 0; i < nb_recv_pe; i++)
3331 {
3332 const int pe_source = recv_pe_list[i];
3333 Entree& buffer = comm.recv_buffer(pe_source);
3334 while (1)
3335 {
3336 int facette = -1, PE_proprietaire = -1, element_arrivee = -1;
3337 buffer >> facette >> PE_proprietaire >> element_arrivee;
3338 if (buffer.eof())
3339 break;
3340 assert(facette >= 0 && PE_proprietaire >= 0 && element_arrivee >= 0);
3341 assert(element_arrivee < nb_elem); // Ce doit etre un element reel
3342 // Enregistre le numero de la nouvelle facette et l'element d'arrivee.
3343 // Pour l'instant c'est le numero de la facette sur le proprietaire.
3344 facettes_recues_numfacettes.append_array(facette);
3345 nouvelles_facettes_pe_proprietaire.append_array(PE_proprietaire);
3346 facettes_recues_numelement.append_array(element_arrivee);
3347 // Enregistre que l'on va recevoir des donnees du PE_proprietaire lors
3348 // de la derniere communication B->C
3349 if (PE_proprietaire != moi)
3350 BtoC_recv_pe_flags[PE_proprietaire] = 1;
3351 }
3352 }
3353 comm.end_comm();
3354 }
3355
3356 // =======================================================================
3357 // Communication B -> C
3358 //
3359 // Construction du schema de communication pour envoyer les facettes reelles
3360 // au destinataire (B envoie les facettes a C) : il faut determiner
3361 // a qui j'envoie et de qui de recois.
3362 {
3363 static ArrOfIntFT send_pe_list;
3364 static ArrOfIntFT recv_pe_list;
3365 send_pe_list.resize_array(0);
3366 recv_pe_list.resize_array(0);
3367 for (i = 0; i < nbproc; i++)
3368 if (BtoC_send_pe_flags[i])
3369 send_pe_list.append_array(i);
3370 for (i = 0; i < nbproc; i++)
3371 if (BtoC_recv_pe_flags[i])
3372 recv_pe_list.append_array(i);
3373 // Envoi des facettes
3374 creer_facettes_virtuelles(facettes_to_send, facettes_pe_dest,
3375 send_pe_list, recv_pe_list);
3376 }
3377 // Conversion du numero de la facette en numero local dans facettes_recues_numfacettes
3380 facettes_recues_numfacettes,
3381 nouvelles_facettes_pe_proprietaire,
3382 facettes_recues_numfacettes);
3384}
3385
3386/*! @brief Conversion des couples (numeros_distants, pe) en numeros_locaux.
3387 *
3388 * Parametres:
3389 * descripteur = soit desc_sommets_, soit desc_facettes_, ou un autre
3390 * element_num_owner = soit sommets_num_owner_, soit facettes_num_owner_, ou equivalent
3391 * numeros_distants = une liste de numeros de facettes ou sommets qui appartiennent au pe_distant
3392 * et qui sont virtuels chez moi. Le numero est le numero
3393 * de la facette ou du sommet sur le pe_distant
3394 * pe_distant = pour chaque numero de facette ou sommet, le pe proprietaire
3395 *
3396 * @param (numeros_locaux) tableau rempli par cette methode. Le contenu initial est efface. La taille est identique a celle de numeros_distants. On y met le numero local des elements (ce sont des numeros d'elements virtuels). Attention: numeros_locaux et numeros_distants peuvent referencer le meme tableau
3397 */
3399 const ArrOfInt& element_num_owner,
3400 const ArrOfInt& numeros_distants,
3401 const ArrOfInt& pe_distant,
3402 ArrOfInt& numeros_locaux) const
3403{
3404 const Descripteur_FT& espace_virtuel = descripteur.espace_virtuel();
3405 const int nb_numeros = numeros_distants.size_array();
3406 numeros_locaux.resize_array(nb_numeros);
3407 const int moi = me();
3408
3409 for (int index = 0; index < nb_numeros; index++)
3410 {
3411 const int numero_distant = numeros_distants[index];
3412 const int pe = pe_distant[index];
3413 int numero_local = -1;
3414
3415 if (pe == moi)
3416 {
3417 numero_local = numero_distant;
3418 }
3419 else
3420 {
3421 // Recherche parmi les sommets virtuels du pe:
3422 const ArrOfInt& elements_virtuels = espace_virtuel.elements(pe);
3423 const int n = elements_virtuels.size_array();
3424 // Elem est un numero de facette ou de sommet
3425 int i;
3426 for (i = 0; i < n; i++)
3427 {
3428 const int elem = elements_virtuels[i];
3429 const int numero_distant_de_elem = element_num_owner[elem];
3430 if (numero_distant == numero_distant_de_elem)
3431 {
3432 numero_local = elem;
3433 break;
3434 }
3435 }
3436 assert(numero_local >= 0);
3437 }
3438 numeros_locaux[index] = numero_local;
3439 }
3440}
3442 const ArrOfInt& element_num_owner,
3443 const int numero_distant,
3444 const int pe_distant,
3445 int& numero_local) const
3446{
3447 const Descripteur_FT& espace_virtuel = descripteur.espace_virtuel();
3448 const int moi = me();
3449
3450 numero_local = -1;
3451
3452 if (pe_distant == moi)
3453 {
3454 numero_local = numero_distant;
3455 }
3456 else
3457 {
3458 // Recherche parmi les sommets virtuels du pe:
3459 const ArrOfInt& elements_virtuels = espace_virtuel.elements(pe_distant);
3460 const int n = elements_virtuels.size_array();
3461 // Elem est un numero de facette ou de sommet
3462 int i;
3463 for (i = 0; i < n; i++)
3464 {
3465 const int elem = elements_virtuels[i];
3466 const int numero_distant_de_elem = element_num_owner[elem];
3467 if (numero_distant == numero_distant_de_elem)
3468 {
3469 numero_local = elem;
3470 break;
3471 }
3472 }
3473 //assert(numero_local >= 0);
3474 }
3475}
3476
3477// Description :
3478// Methode outil utilisee dans "deplacer_sommets".
3479// (pour decouper le code en petits bouts...).
3480// On modifie x, y, z, element, face_bord et eventuellement sommets_envoyes...
3481// x,y,z: position initiale en entree, position finale en sortie
3482// (le sommet est deplace en direction de la destination jusqu'a
3483// ce qu'il sorte de l'"element")
3484// x1,y1,z1: destination
3485// element : en entree, numero de l'element ou se trouve le sommet,
3486// en sortie, numero de l'element ou arrive le sommet,
3487// face_bord: idem pour la face de bord si le sommet est sur un bord,
3488// -1 sinon.
3489// sommets_envoyes, ... : donnees pour les echanges entre processeurs si
3490// le sommet traverse un joint.
3491// valeur de retour : 0 si x1,y1,z1 est dans l'"element" initial (on a fini le deplacement)
3492// 1 sinon (la destination n'a pas encore ete atteinte).
3493
3494//RQ : Fonction scindee en 2 :
3495// - deplacement du point (deplacer_un_point)
3496// - deplacement du sommet (deplacer_un_sommet) : appel a deplacer_un_point + gestion des transferts entre processeurs
3497//fonctions statiques (pour ne pas utiliser des membres propres au maillage
3498int Maillage_FT_Disc::deplacer_un_point(double& x, double& y, double& z,
3499 double x1, double y1, double z1,
3500 int& element,
3501 int& face_bord,
3502 const Parcours_interface& parcours,
3503 const Domaine_VF& domaine_vf,
3504 const IntTab& face_voisins,
3505 int skip_facettes)
3506{
3507 // Valeur de retour de la fonction :
3508 int continuer = -2;
3509 // Rappel : face_bord < -1 <=> le sommet est sur une ligne de contact
3510 // La face de bord ou passe le sommet (si ligne contact) :
3511 int face_suivante = -2;
3512 // L'element ou passe le sommet :
3513 int element_suivant = -2;
3514
3515 if (face_bord < 0)
3516 {
3517 // Le noeud n'est pas une ligne de contact
3518 // Si on ne trouve pas d'intersection, on recupere pos_intersection=1.
3519 double pos_intersection = 1.;
3520 const int face_sortie =
3521 parcours.calculer_face_sortie_element(domaine_vf, element,
3522 x, y, z,
3523 x1, y1, z1,
3524 pos_intersection);
3525 // Mettre a jour la position x,y,z
3526 x = x * (1. - pos_intersection) + x1 * pos_intersection;
3527 y = y * (1. - pos_intersection) + y1 * pos_intersection;
3528 z = z * (1. - pos_intersection) + z1 * pos_intersection;
3529 if (face_sortie >= 0)
3530 {
3531 // Le sommet sort de l'element, quel est l'element voisin ?
3532 const int elem0 = face_voisins(face_sortie, 0);
3533 const int elem1 = face_voisins(face_sortie, 1);
3534 element_suivant = elem0 + elem1 - element;
3535 if (element_suivant < 0)
3536 {
3537 // Le sommet touche un bord => il devient ligne de contact
3538 element_suivant = element;
3539 face_suivante = face_sortie;
3540 continuer = 1;
3541 }
3542 else
3543 {
3544 // Le sommet passe dans un autre element
3545 face_suivante = -1;
3546 continuer = 1;
3547 }
3548 }
3549 else
3550 {
3551 // Le sommet ne change pas d'element
3552 element_suivant = element;
3553 face_suivante = -1;
3554 continuer = 0;
3555 }
3556 }
3557 else
3558 {
3559 //On ne modifie pas face_bord et elem dans le cas des marqueurss (skip_facettes)
3560 if (!skip_facettes)
3561 {
3562 // Le sommet est sur un bord => ligne de contact
3563 // Le sommet se deplace sur la face de bord. Par ou sort-il ?
3564 const int nouvelle_face_bord =
3565 parcours.calculer_sortie_face_bord(face_bord, element,
3566 x, y, z,
3567 x1, y1, z1,
3568 x, y, z); // Nouvelle position
3569 if (nouvelle_face_bord >= 0)
3570 {
3571 // Le sommet change de face de bord :
3572 // Numero de la face suivante :
3573 face_suivante = nouvelle_face_bord;
3574 // Numero de l'element adjacent a cette face
3575 const int elem0 = face_voisins(face_suivante, 0);
3576 const int elem1 = face_voisins(face_suivante, 1);
3577 element_suivant = elem0 + elem1 + 1;
3578 assert((elem0 == -1 || elem1 == -1)
3579 && (elem0 >= 0 || elem1 >= 0));
3580 continuer = 1;
3581 }
3582 else
3583 {
3584 // Le sommet reste sur la meme face de bord
3585 face_suivante = face_bord;
3586 element_suivant = element;
3587 continuer = 0;
3588 }
3589 } //fin !skip_facettes
3590 else
3591 {
3592 element_suivant = element;
3593 face_suivante = face_bord;
3594 continuer = 0;
3595 }
3596 }
3597
3598 element = element_suivant;
3599 face_bord = face_suivante;
3600
3601
3602
3603 return continuer;
3604}
3605
3606int Maillage_FT_Disc::deplacer_un_sommet(double& x, double& y, double& z,
3607 double x1, double y1, double z1,
3608 int& element,
3609 int& face_bord,
3610 const int num_sommet,
3611 const Parcours_interface& parcours,
3612 const Domaine_VF& domaine_vf,
3613 const IntTab& face_voisins,
3614 ArrOfInt& sommets_envoyes,
3615 ArrOfInt& element_virtuel_arrivee,
3616 ArrOfInt& face_virtuelle_arrivee,
3617 DoubleTab& deplacement_restant,
3618 int skip_facettes)
3619
3620{
3621 // Valeur de retour de la fonction :
3622 int continuer = -2;
3623 // Rappel : face_bord < -1 <=> le sommet est sur une ligne de contact
3624 // La face de bord ou passe le sommet (si ligne contact) :
3625 int face_suivante = -2;
3626 // L'element ou passe le sommet :
3627 int element_suivant = -2;
3628
3629 // -------------------------------------------------------------
3630 // PREMIERE ETAPE : calcul de "face_suivante", "element_suivant" et "continuer" :
3631 // -------------------------------------------------------------
3632
3633 element_suivant = element;
3634 face_suivante = face_bord;
3635 continuer = Maillage_FT_Disc::deplacer_un_point(x,y,z, x1,y1,z1,
3636 element_suivant, face_suivante,
3637 parcours, domaine_vf, face_voisins,
3638 skip_facettes);
3639
3640 // On n'a rien oublie ?
3641 assert(continuer > -2 && face_suivante > -2 && element_suivant > -2);
3642
3643 // -------------------------------------------------------------
3644 // DEUXIEME ETAPE : traitement des traversees de joints entre processeurs
3645 // -------------------------------------------------------------
3646 if (continuer)
3647 {
3648 const int nb_elem_reels = domaine_vf.nb_elem();
3649 if (element_suivant >= nb_elem_reels)
3650 {
3651 if (num_sommet>=0)
3652 {
3653 //cas general
3654 // L'element voisin est virtuel, on traverse un joint.
3655 // On empile les valeurs a transmettre.
3656 sommets_envoyes.append_array(num_sommet);
3657 element_virtuel_arrivee.append_array(element_suivant);
3658 face_virtuelle_arrivee.append_array(face_suivante);
3659 const int n = deplacement_restant.dimension(0);
3660 deplacement_restant.resize(n+1, 3);
3661 deplacement_restant(n,0) = x1 - x;
3662 deplacement_restant(n,1) = y1 - y;
3663 deplacement_restant(n,2) = z1 - z;
3664 // Le sommet reste pour l'instant dans l'element reel courant.
3665 // Il sera mis a jour dans "echanger_sommets_PE".
3666 // On arrete les iterations pour ce sommet, la suite sera
3667 // traitee par un autre processeur:
3668 continuer = 0;
3669 }
3670 else
3671 {
3672 //cas ou on deplace un point, pas un sommet
3673 continuer = -1;
3674 }
3675 }
3676 else
3677 {
3678 // Mise a jour de element et face_bord
3679 element = element_suivant;
3680 face_bord = face_suivante;
3681 }
3682 }
3683 return continuer;
3684}
3685
3686
3687/*! @brief Applique un vecteur deplacement aux noeuds dont le numero est dans "liste_noeud", puis echange les espaces virtuels.
3688 *
3689 * Si un noeud traverse un joint, il change de proprietaire.
3690 * Si un noeud rencontre une paroi, il s'arrete sur la paroi et on le
3691 * transforme en noeud "ligne de contact".
3692 * Si un noeud est sur une paroi (noeud "ligne de contact"), il longe
3693 * la paroi (on deplace le noeud de face de bord en face de bord en
3694 * minimisant la distance entre le noeud et le deplacement demande.
3695 *
3696 * @param (liste_sommets_initiale) une liste non redondante de noeuds REELS a deplacer
3697 * @param (deplacement_initial) le vecteur deplacement des noeuds de "liste_noeuds" ( dimension(0)==liste_noeuds.size_array() et dimension(1)==dimension )
3698 */
3699void Maillage_FT_Disc::deplacer_sommets(const ArrOfInt& liste_sommets_initiale,
3700 const DoubleTab& deplacement_initial,
3701 ArrOfInt& liste_sommets_sortis,
3702 ArrOfInt& numero_face_sortie,
3703 int skip_facettes)
3704
3705{
3706 assert(deplacement_initial.dimension(0) == liste_sommets_initiale.size_array());
3707 assert(deplacement_initial.dimension(1) == Objet_U::dimension);
3708
3709 if (Comm_Group::check_enabled()) check_mesh(1,0,skip_facettes);
3710
3711 const int dimension3 = (Objet_U::dimension == 3);
3712 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, refdomaine_dis_.valeur());
3713 const Parcours_interface& parcours = refparcours_interface_.valeur();
3714 const IntTab& face_voisins = domaine_vf.face_voisins();
3715
3716 //
3717 // ALGORITHME :
3718 // On deplace tous les noeuds jusqu'a ce qu'ils rencontrent un joint.
3719 // Puis on change les noeuds de processeurs et on continue le deplacement
3720 // des noeuds qui viennent d'arriver.
3721 //
3722
3723 // Liste de sommets et deplacement a l'iteration courante
3724 static ArrOfIntFT liste_sommets;
3725 static DoubleTabFT deplacement;
3726 // Liste des sommets qui atteignent un joint et donnees a envoyer
3727 static ArrOfIntFT sommets_envoyes;
3728 static ArrOfIntFT element_virtuel_arrivee;
3729 static ArrOfIntFT face_virtuelle_arrivee;
3730 static DoubleTabFT deplacement_restant;
3731
3732 //On reinitialise sommet_face_bord_ a -1 dans le cas des marqueurs (skip_facettes)
3733 if (get_is_solid_particle() || skip_facettes ) sommet_face_bord_ = -1; // for fpi module, facets at the wall should never be deleted
3734
3735 liste_sommets = liste_sommets_initiale;
3736 {
3737 // Remplissage du tableau "deplacement" qui a toujours 3 colonnes.
3738 const int n = deplacement_initial.dimension(0);
3739 deplacement.resize(n, 3);
3740 for (int i = 0; i < n; i++)
3741 {
3742 deplacement(i, 0) = deplacement_initial(i, 0);
3743 deplacement(i, 1) = deplacement_initial(i, 1);
3744 deplacement(i, 2) = (dimension3) ? deplacement_initial(i, 2) : 0.;
3745 }
3746 }
3747
3748 // Boucle : "tant qu'il reste des noeuds a deplacer sur l'un des processeurs"
3749 int somme_nb_sommets_envoyes = 0;
3750 const int max_iterations_echange = 50;
3751 int nb_iterations_echange = 0;
3752
3753 do
3754 {
3755 const int nbsommets = liste_sommets.size_array();
3756 sommets_envoyes.resize_array(0);
3757 element_virtuel_arrivee.resize_array(0);
3758 face_virtuelle_arrivee.resize_array(0);
3759 deplacement_restant.resize(0, 3);
3760
3761 for (int i_sommet = 0; i_sommet < nbsommets; i_sommet++)
3762 {
3763 const int num_sommet = liste_sommets[i_sommet];
3764 // Coordonnee courante du sommet (on la deplace d'element en element)
3765 double x0 = sommets_(num_sommet, 0);
3766 double y0 = sommets_(num_sommet, 1);
3767 double z0 = (dimension3 ? sommets_(num_sommet, 2) : 0.);
3768 // Position du point d'arrivee
3769 const double x1 = x0 + deplacement(i_sommet, 0);
3770 const double y1 = y0 + deplacement(i_sommet, 1);
3771 const double z1 = (dimension3) ? (z0 + deplacement(i_sommet, 2)) : 0.;
3772 // Numero de l'element ou se trouve le sommet
3773 int element = sommet_elem_[num_sommet];
3774 // Numero de la face de bord ou se trouve le sommet (si ligne de contact)
3775 int face_bord = sommet_face_bord_[num_sommet];
3776
3777 assert(element >= 0); // Pas de sommet virtuel dans la liste !
3778 int continuer = 0;
3779 int face_bord_m2, face_bord_m1 = -10;
3780 // Boucle de deplacement du sommet d'element en element
3781
3782 do
3783 {
3784 face_bord_m2 = face_bord_m1;
3785 face_bord_m1 = face_bord;
3786 continuer = Maillage_FT_Disc::deplacer_un_sommet(x0, y0, z0,
3787 x1, y1, z1,
3788 element,
3789 face_bord,
3790 num_sommet,
3791 parcours,
3792 domaine_vf,
3793 face_voisins,
3794 sommets_envoyes,
3795 element_virtuel_arrivee,
3796 face_virtuelle_arrivee,
3797 deplacement_restant,
3798 skip_facettes);
3799
3800 //ajout test pour limiter les allers-retours antre plsieurs faces de bord
3801 //pb des coins
3802 if (face_bord!=-1 && face_bord==face_bord_m2)
3803 {
3804 //Process::Journal()<<"face_bord==face_bord_m2 : fin deplacement"<<finl;
3805 continuer = 0;
3806 }
3807 }
3808 while (continuer);
3809
3810 sommets_(num_sommet, 0) = x0;
3811 sommets_(num_sommet, 1) = y0;
3812 if (dimension3)
3813 sommets_(num_sommet, 2) = z0;
3814 sommet_elem_[num_sommet] = element;
3815 sommet_face_bord_[num_sommet] = face_bord;
3816 }
3817
3818 // Mise a jour des espaces virtuels des coordonnees des sommets
3819 desc_sommets_.echange_espace_virtuel(sommets_);
3820 // Mise a jour des espaces virtuels des face_bord (si le sommet est ligne
3821 // de contact, sommet_face_bord_ doit etre >= 0 meme si c'est un sommet virtuel)
3822 desc_sommets_.echange_espace_virtuel(sommet_face_bord_);
3823
3824 const int nb_sommets_envoyes = sommets_envoyes.size_array();
3825 somme_nb_sommets_envoyes = Process::check_int_overflow(mp_sum(nb_sommets_envoyes));
3826 if (somme_nb_sommets_envoyes > 0)
3827 {
3828 // Echange des sommets et des deplacements restants
3829 // On recupere une nouvelle "liste_sommets" et un nouveau "deplacement"
3830
3831 echanger_sommets_PE(sommets_envoyes,
3832 element_virtuel_arrivee,
3833 face_virtuelle_arrivee,
3834 deplacement_restant,
3835 liste_sommets,
3836 deplacement,
3837 skip_facettes);
3838 }
3839 nb_iterations_echange++;
3840 }
3841 while (somme_nb_sommets_envoyes > 0 && nb_iterations_echange < max_iterations_echange);
3842 if (nb_iterations_echange == max_iterations_echange)
3843 {
3844 if (je_suis_maitre())
3845 Cerr << "Maillage_FT_Disc.cpp::deplacer_sommets max_iterations_echange atteint." << finl;
3846 }
3847
3849
3850 liste_sommets.resize_array(0);
3851 deplacement.resize(0);
3852 sommets_envoyes.resize_array(0);
3853 element_virtuel_arrivee.resize_array(0);
3854 face_virtuelle_arrivee.resize_array(0);
3855 deplacement_restant.resize(0);
3856}
3857
3858// Description :
3859// Verification de la coherence de la structure de donnees des sommets.
3860int Maillage_FT_Disc::check_sommets(int error_is_fatal) const
3861{
3862 const double invalid_value = DMAXFLOAT*0.9;
3863 const int dimension3 = (Objet_U::dimension == 3);
3864 const int moi = Process::me();
3865 const Domaine_dis_base& domaine_dis = refdomaine_dis_.valeur();
3866 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis);
3867 const int nb_elements_reels = domaine_vf.nb_elem();
3868 int i, j;
3869
3870 if (statut_ == RESET)
3871 {
3872 int ok = (nb_sommets() == 0);
3873 ok = ok && (sommet_elem_.size_array() == 0);
3874 ok = ok && (sommet_face_bord_.size_array() == 0);
3875 ok = ok && (sommet_PE_owner_.size_array() == 0);
3876 ok = ok && (sommet_num_owner_.size_array() == 0);
3877 ok = ok && (desc_sommets_.espace_virtuel().pe_voisins().size_array() == 0);
3878 ok = ok && (desc_sommets_.espace_distant().pe_voisins().size_array() == 0);
3879 if (!ok && error_is_fatal)
3880 {
3881 Journal() << "Erreur Maillage_FT_Disc::check_sommets : maillage RESET invalide" << finl;
3882 assert(0);
3883 Process::exit();
3884 }
3885 return !ok;
3886 }
3887 //Journal() << "Entree dans Maillage_FT_Disc::check_sommets" << finl;
3888 // Verification que les espaces distants et virtuels sont coherents:
3889 desc_sommets_.check();
3890 // Verification des tailles des tableaux:
3891 const int nbsommets = sommets_.dimension(0);
3892 if (sommets_.dimension(1) != Objet_U::dimension)
3893 Journal() << "Erreur sommets_.dimension(1) != Objet_U::dimension" << finl;
3894 // Verification de sommet_PE_owner_ : on le recalcule et on compare
3895 {
3896 if (sommet_PE_owner_.size_array() != nbsommets)
3897 {
3898 if (error_is_fatal)
3899 {
3900 assert(0);
3901 Process::exit();
3902 }
3903 Cerr << "" << finl;
3904 }
3905
3906 ArrOfIntFT pe_owner(nbsommets);
3907 desc_sommets_.remplir_element_pe(pe_owner);
3908 for (i = 0; i < nbsommets; i++)
3909 {
3910 if (sommet_PE_owner_[i] != pe_owner[i])
3911 {
3912 if (error_is_fatal)
3913 {
3914 assert(0);
3915 Process::exit();
3916 }
3917 break;
3918 }
3919 }
3920 if (i < nbsommets)
3921 Cerr << "Erreur Verification de sommet_PE_owner_" << finl;
3922 }
3923 // Verification de sommet_num_owner_ : on le recalcule et on compare
3924 {
3925 if (sommet_num_owner_.size_array() != nbsommets)
3926 {
3927 Journal() << "Erreur sommet_num_owner_.size_array() != nb_sommets" << finl;
3928 if (error_is_fatal)
3929 {
3930 assert(0);
3931 Process::exit();
3932 }
3933 }
3934 ArrOfIntFT num_owner(nbsommets);
3935 for (i = 0; i < nbsommets; i++)
3936 num_owner[i] = i;
3937 desc_sommets_.echange_espace_virtuel(num_owner);
3938 for (i = 0; i < nbsommets; i++)
3939 {
3940 if (num_owner[i] != sommet_num_owner_[i])
3941 {
3942 Journal() << "Erreur num_owner[" << i << "] = " << num_owner[i];
3943 Journal() << " sommet_num_owner_ = " << sommet_num_owner_[i] << finl;
3944 if (error_is_fatal)
3945 {
3946 assert(0);
3947 Process::exit();
3948 }
3949 }
3950 }
3951 }
3952
3953 // Verification des coordonnees des sommets virtuels : comparaison avec une copie echangee
3954 {
3955 DoubleTabFT copie_sommets = sommets_;
3956 // On invalide les elements virtuels. Cela permet de detecter le cas
3957 // ou un element se trouverait a la fois dans l'espace distant et dans
3958 // l'espace virtuel.
3959 const Descripteur_FT& espace_virtuel = desc_sommets_.espace_virtuel();
3960 const ArrOfInt& pe_voisins = espace_virtuel.pe_voisins();
3961 const int nb_pe_voisins = pe_voisins.size_array();
3962 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
3963 {
3964 const int pe = pe_voisins[indice_pe];
3965 const ArrOfInt& elements = espace_virtuel.elements(pe);
3966 const int n = elements.size_array();
3967 for (i = 0; i < n; i++)
3968 {
3969 const int num_sommet = elements[i];
3970 copie_sommets(num_sommet, 0) = invalid_value;
3971 copie_sommets(num_sommet, 1) = invalid_value;
3972 if (dimension3)
3973 copie_sommets(num_sommet, 2) = invalid_value;
3974 }
3975 }
3976 // Echange espace virtuel sur la copie
3977 desc_sommets_.echange_espace_virtuel(copie_sommets);
3978 // Comparaison de la copie et du tableau des sommets.
3979 for (i = 0; i < nbsommets; i++)
3980 {
3981 for (j = 0; j < Objet_U::dimension; j++)
3982 {
3983 if (copie_sommets(i,j) == invalid_value)
3984 {
3985 Journal() << "Erreur copie_sommets(" << i << ",";
3986 Journal() << j << ") == DMAX_FLOAT" << finl;
3987 if (error_is_fatal)
3988 {
3989 assert(0);
3990 Process::exit();
3991 }
3992 }
3993 if (copie_sommets(i,j) != sommets_(i,j))
3994 {
3995 Journal() << "Erreur copie_sommets(" << i << ",";
3996 Journal() << j << ") = " << copie_sommets(i,j);
3997 Journal() << " sommets_ = " << sommets_(i,j) << finl;
3998 if (error_is_fatal)
3999 {
4000 assert(0);
4001 Process::exit();
4002 }
4003 }
4004 }
4005 }
4006 }
4007
4008 // Verification de sommet_elem_ :
4009 {
4010 if (sommet_elem_.size_array() != nbsommets)
4011 {
4012 Journal() << "Erreur sommet_elem_.size_array() != nb_sommets" << finl;
4013 if (error_is_fatal)
4014 {
4015 assert(0);
4016 Process::exit();
4017 }
4018 }
4019 const Parcours_interface& parcours =refparcours_interface_.valeur();
4020 const double epsilon = parcours.get_erreur_geometrique();
4021
4022 for (i = 0; i < nbsommets; i++)
4023 {
4024 const int num_element = sommet_elem_[i];
4025 const int pe = sommet_PE_owner_[i];
4026 if (pe != moi && num_element >= 0)
4027 {
4028 Journal() << "Erreur sommet_num_owner_[" << i;
4029 Journal() << "] && sommet_elem_ >= 0" << finl;
4030 if (error_is_fatal)
4031 {
4032 assert(0);
4033 Process::exit();
4034 }
4035 }
4036 if (pe == moi)
4037 {
4038 if (num_element > nb_elements_reels)
4039 {
4040 Journal() << "Erreur i=" << i;
4041 Journal() << " sommet_elem_[i]>nb_elements_reels" << finl;
4042 if (error_is_fatal)
4043 {
4044 assert(0);
4045 Process::exit();
4046 }
4047 }
4048 else
4049 {
4050 // On verifie que le sommet est dans l'element a epsilon pres.
4051 // Le transport assure une distance < epsilon. On laisse un peu de marge,
4052 // on teste si distance < 2. * epsilon.
4053 double x, y, z = 0.;
4054 x = sommets_(i, 0);
4055 y = sommets_(i, 1);
4056 if (dimension3)
4057 z = sommets_(i, 2);
4058 const double distance = parcours.distance_sommet_faces(domaine_vf, num_element,
4059 x, y, z);
4060 if (distance > 2. * epsilon)
4061 {
4062 Journal() << "Erreur i=" << i << " num_element=" << num_element;
4063 Journal() << " distance_sommet_faces=" << distance << finl;
4064 if (error_is_fatal)
4065 {
4066 Cerr << "Trouble when checking mesh in Maillage_FT_Disc::check_sommets." << finl;
4067 Cerr << "FT sommet is not in element (according to precision set)." << finl;
4068 Cerr << "*******************************************************************************************" << finl;
4069 Cerr << " HINT ==> try to define the parameter Erreur_relative_maxi in the Parcours_interface bloc " << finl;
4070 Cerr << " which should be defined the BEGING OF THE EQUATION bloc & before conditions_initiales. " << finl;
4071 Cerr << "*******************************************************************************************" << finl;
4072 Process::exit();
4073 }
4074 }
4075 }
4076 }
4077 }
4078 // Verification de sommet_face_bord_ :
4079 {
4080 if (sommet_face_bord_.size_array() != nbsommets)
4081 {
4082 Journal() << "Erreur sommet_face_bord_.size_array() != nb_sommets" << finl;
4083 if (error_is_fatal)
4084 {
4085 assert(0);
4086 Process::exit();
4087 }
4088 }
4089 const IntTab& face_voisins = domaine_vf.face_voisins();
4090 for (i = 0; i < nbsommets; i++)
4091 {
4092 const int face = sommet_face_bord_[i];
4093 const int element = sommet_elem_[i];
4094 if (face >= 0 && !sommet_virtuel(i))
4095 {
4096 const int voisin0 = face_voisins(face, 0);
4097 const int voisin1 = face_voisins(face, 1);
4098 if (voisin0 >= 0 && voisin1 >= 0)
4099 {
4100 Journal() << "Erreur sommet_face_bord_[" << i;
4101 Journal() << "]=" << face << " (la face n'est pas au bord)." << finl;
4102 if (error_is_fatal)
4103 {
4104 assert(0);
4105 Process::exit();
4106 }
4107 }
4108 if (voisin0 != element && voisin1 != element)
4109 {
4110 Journal() << "Erreur sommet_face_bord_[" << i;
4111 Journal() << "]=" << face;
4112 Journal() << "\n (la face n'est pas voisine de l'element ";
4113 Journal() << element << finl;
4114 if (error_is_fatal)
4115 {
4116 assert(0);
4117 Process::exit();
4118 }
4119 }
4120 }
4121 }
4122 }
4123 }
4124 return 0;
4125}
4126
4127// Description
4128// Verifie la coherence des structures de donnees de l'interface (notamment
4129// la distribution des donnees sur les differents processeurs, espaces
4130// virtuels, etc). On verifie que toutes les conditions imposees pour avoir
4131// un maillage dans l'etat MINIMAL sont remplies.
4132//
4133// Si skip_facette_pe != 0, on ne verifie pas la condition "proprietaire facette
4134// == proprietaire premier sommet".
4135// Si skip_facettes != 0 on ne considere que check_sommets()
4136
4137int Maillage_FT_Disc::check_mesh(int error_is_fatal, int skip_facette_pe, int skip_facettes) const
4138{
4139 statistics().create_custom_counter("Check_mesh",2,"FrontTracking");
4140
4141 const double invalid_value = DMAXFLOAT*0.9;
4142 int i, j;
4143 int return_code = -1;
4144
4145 return_code = check_sommets(error_is_fatal);
4146 if (return_code == 0)
4147 return_code = -1;
4148
4149 if (skip_facettes)
4150 return return_code;
4151
4152 statistics().begin_count("Check_mesh",statistics().get_last_opened_counter_level()+1);
4153 if (return_code < 0 && statut_ == RESET)
4154 {
4155 int ok = (nb_facettes() == 0);
4156 ok = ok && (facette_num_owner_.size_array() == 0);
4157 ok = ok && (desc_facettes_.espace_virtuel().pe_voisins().size_array() == 0);
4158 ok = ok && (desc_facettes_.espace_distant().pe_voisins().size_array() == 0);
4159 if (!ok && error_is_fatal)
4160 {
4161 Journal() << "Erreur Maillage_FT_Disc::check_mesh : maillage RESET invalide" << finl;
4162 assert(0);
4163 Process::exit();
4164 }
4165 return_code = !ok;
4166 }
4167
4168 if (return_code < 0)
4169 {
4170 desc_facettes_.check();
4171 // Verification des tailles des tableaux:
4172 const int nbsommets = sommets_.dimension(0);
4173 const int nbfacettes = facettes_.dimension(0);
4174 if (facettes_.dimension(1) != Objet_U::dimension)
4175 Journal() << "Erreur facettes_.dimension(1) != Objet_U::dimension" << finl;
4176
4177 // Verification des facettes :
4178
4179 // Les numeros de sommets existent-t-ils ?
4180 // Les espaces virtuels sont-ils coherents ?
4181 // On verifie que les coordonnees des sommets sont les memes sur tous les procs.
4182 // Pour ca, on cree un tableau contenant les coordonnees des sommets des facettes,
4183 // on echange l'espace virtuel du tableau et on compare au tableau facettes_ et sommets_
4184 const int dim_carre = Objet_U::dimension * Objet_U::dimension;
4185 DoubleTabFT coord_facettes(nbfacettes, dim_carre);
4186
4187 for (i = 0; i < nbfacettes; i++)
4188 {
4189 int n = 0;
4190 for (j = 0; j < Objet_U::dimension; j++)
4191 {
4192 const int som = facettes_(i, j);
4193 if (som >= nbsommets)
4194 {
4195 Journal() << "Erreur facettes_(" << i << "," << j;
4196 Journal() << ") >= nb_sommets" << finl;
4197 printFa7(i,1,Journal());
4198 if (error_is_fatal)
4199 {
4200 assert(0);
4201 Process::exit();
4202 }
4203 return_code = 0;
4204 }
4205 for (int k = 0; k < Objet_U::dimension; k++)
4206 coord_facettes(i, n++) = sommets_(som, k);
4207 }
4208 }
4209 // On invalide les espaces virtuels:
4210 const Descripteur_FT& espace_virtuel = desc_facettes_.espace_virtuel();
4211 const ArrOfInt& pe_voisins = espace_virtuel.pe_voisins();
4212 const int nb_pe_voisins = pe_voisins.size_array();
4213 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
4214 {
4215 const int pe = pe_voisins[indice_pe];
4216 const ArrOfInt& elements = espace_virtuel.elements(pe);
4217 const int n = elements.size_array();
4218 for (i = 0; i < n; i++)
4219 {
4220 const int num_facette = elements[i];
4221 for (j = 0; j < dim_carre; j++)
4222 coord_facettes(num_facette, j) = invalid_value;
4223 }
4224 }
4225 desc_facettes_.echange_espace_virtuel(coord_facettes);
4226 // Verification des coordonnees
4227 for (i = 0; i < nbfacettes; i++)
4228 {
4229 int n = 0;
4230 for (j = 0; j < Objet_U::dimension; j++)
4231 {
4232 const int som = facettes_(i, j);
4233 for (int k = 0; k < Objet_U::dimension; k++)
4234 {
4235 double original = sommets_(som, k);
4236 double copie = coord_facettes(i, n++);
4237 if (original != copie)
4238 {
4239 Journal() << "Erreur facette " << i << " sommet " << j << " direction " << k;
4240 Journal() << " " << original << " != " << copie << finl;
4241 printFa7(i,1,Journal());
4242 Journal() <<" Fa7 orig ="<<finl;
4243 if (Objet_U::dimension ==3)
4244 {
4245 Journal() << " som0= " << sommets_(i, 0) << " " << sommets_(i, 1) << " " << sommets_(i, 2) << finl;
4246 Journal() << " som1= " << sommets_(i, 3) << " " << sommets_(i, 4) << " " << sommets_(i, 5) << finl;
4247 Journal() << " som2= " << sommets_(i, 6) << " " << sommets_(i, 7) << " " << sommets_(i, 8) << finl;
4248 }
4249 else
4250 {
4251 Journal() << " som0= " << sommets_(i, 0) << " " << sommets_(i, 1) <<finl;
4252 Journal() << " som1= " << sommets_(i, 2) << " " << sommets_(i, 3) << finl;
4253 }
4254 Journal() <<" Fa7 copie ="<<finl;
4255 if (Objet_U::dimension ==3)
4256 {
4257 Journal() << " som0= " << coord_facettes(i, 0) << " " << coord_facettes(i, 1) << " " << coord_facettes(i, 2) << finl;
4258 Journal() << " som1= " << coord_facettes(i, 3) << " " << coord_facettes(i, 4) << " " << coord_facettes(i, 5) << finl;
4259 Journal() << " som2= " << coord_facettes(i, 6) << " " << coord_facettes(i, 7) << " " << coord_facettes(i, 8) << finl;
4260 }
4261 else
4262 {
4263 Journal() << " som0= " << coord_facettes(i, 0) << " " << coord_facettes(i, 1) <<finl;
4264 Journal() << " som1= " << coord_facettes(i, 2) << " " << coord_facettes(i, 3) << finl;
4265 }
4266 if (error_is_fatal)
4267 {
4268 Process::exit();
4269 }
4270 return_code = 0;
4271 }
4272 }
4273 }
4274 }
4275
4276 // Verification qu'il n'existe pas deux fois la meme facette
4277 {
4278 const int nb_facettes = facettes_.dimension(0);
4279 assert(Objet_U::dimension == facettes_.dimension(1));
4280
4281 // tri du tableau + suppression doublons
4282 IntTabFT copie_facettes = facettes_;
4283 tableau_trier_retirer_doublons(copie_facettes);
4284 int count = nb_facettes - copie_facettes.dimension(0);
4285 if (count > 0)
4286 Cerr << "Erreur facette : " << count << " facettes identiques sur PE " << me() << finl;
4287 }
4288
4289 // Verification du proprietaire de la facette.
4290 // On reconstruit le tableau des proprietaires d'apres l'espace virtuel,
4291 // on verifie que c'est bien le proprietaire du premier sommet de la facette.
4292 // (code identique au debut de "corriger_proprietaire_facette").
4293 if (! skip_facette_pe)
4294 {
4295 // Quel est le proprietaire actuel des facettes ?
4296 // (d'apres le descripteur des facettes)
4297 ArrOfIntFT facette_pe(nbfacettes);
4298 desc_facettes_.remplir_element_pe(facette_pe);
4299 // On verifie:
4300 for (i = 0; i < nbfacettes; i++)
4301 {
4302 int pe_actuel = facette_pe[i];
4303 int premier_sommet = facettes_(i, 0);
4304 int pe_legitime = sommet_PE_owner_[premier_sommet];
4305 if (pe_actuel != pe_legitime)
4306 {
4307 Journal() << "Erreur facette " << i;
4308 Journal() << " : owner(d'apres descripteur)=" << pe_actuel;
4309 Journal() << " owner(d'apres 1er sommet)=" << pe_legitime << finl;
4310 printFa7(i,1,Journal());
4311 if (error_is_fatal)
4312 {
4313 assert(0);
4314 Process::exit();
4315 }
4316 return_code = 0;
4317 }
4318 }
4319 // Verification de facette_num_owner_
4320 ArrOfIntFT num_owner(nbfacettes);
4321 for (i = 0; i < nbfacettes; i++)
4322 num_owner[i] = i;
4324 for (i = 0; i < nbfacettes; i++)
4325 if (num_owner[i] != facette_num_owner_[i])
4326 {
4327 Journal() << "Erreur facette " << i;
4328 Journal() << " : facette_num_owner[i]=" << facette_num_owner_[i];
4329 Journal() << " devrait valoir " << num_owner[i] << finl;
4330 if (error_is_fatal)
4331 {
4332 assert(0);
4333 Process::exit();
4334 }
4335 return_code = 0;
4336 }
4337 }
4338 }
4339 statistics().end_count("Check_mesh");
4340
4341 return return_code;
4342}
4343
4344/*! @brief Retire toutes les facettes virtuelles et tous les sommets qui ne sont pas utilises.
4345 *
4346 */
4348{
4349 //lance le nettoyage
4351 // maillage_modifie() est fait dans nettoyer_maillage
4352}
4353
4354/*! @brief Retire toutes les facettes virtuelles, toutes les facettes invalides (sommet0 == sommet1) et tous les sommets qui ne sont pas utilises.
4355 *
4356 */
4358{
4359 assert(statut_ >= MINIMAL);
4360 // Lorsque l'on arrive par Maillage_FT_IJK::nettoyer_maillage et qu'il y a
4361 // eu un nettoyage preliminaire de compo_connexe_facettes_, l'appel :
4362 // if (Comm_Group::check_enabled()) check_mesh(1,0,1);
4363 // va pointer vers Maillage_FT_IJK::check_mesh et va tester la taille du tableau
4364 // compo_connexe. A ce moment, le tableau compo_connexe_facettes_ a ete nettoye
4365 // de ces facettes virtuel alors que le maillage ne va l'etre que par la suite.
4366 // On force donc ici l'appel a Maillage_FT_Disc::check_mesh.
4367 // La verification par un Maillage_FT_IJK::check_mesh aura lieu a la fin de cette routine.
4369
4370 const int dimension3 = (Objet_U::dimension==3);
4371 ArrOfIntFT new_elements;
4372
4373 // On decale toutes les facettes reelles pour remplir les trous
4374 // dans les tableaux :
4375 // * facettes_
4376 // * facette_num_owner_
4377 {
4378 const int nbfacettes = facettes_.dimension(0);
4379 int n = 0;
4380 int i;
4381 for (i = 0; i < nbfacettes; i++)
4382 {
4383 const int invalide = (facettes_(i,0) == facettes_(i,1));
4384 const int virtuelle = facette_virtuelle(i);
4385 if (!invalide && !virtuelle)
4386 {
4387 facettes_(n, 0) = facettes_(i, 0);
4388 facettes_(n, 1) = facettes_(i, 1);
4389 if (dimension3)
4390 facettes_(n, 2) = facettes_(i, 2);
4391 n++;
4392 }
4393 }
4394 facettes_.resize(n, Objet_U::dimension);
4395
4396 facette_num_owner_.resize_array(n);
4397 for (i = 0; i < n; i++)
4398 facette_num_owner_[i] = i;
4399 // Inutile d'echanger les espaces virtuels de facette_num_owner_:
4400 // il n'y a plus d'espaces virtuels.
4401 }
4402
4403 // Il n'y a plus aucune facette virtuelle, on vide les espaces distants et
4404 // virtuels:
4405 desc_facettes_.reset();
4406 desc_facettes_.calcul_schema_comm(facettes_.dimension(0));
4407
4408 // Marquage des sommets utilises:
4409 ArrOfIntFT sommets_utilises(nb_sommets());
4410 {
4411 ArrOfInt& tab = facettes_; // vu comme unidimensionnel
4412 const int nb_sommets_facettes = tab.size_array();
4413 sommets_utilises = 0;
4414 // Boucle sur tous les sommets de toutes les facettes
4415 for (int i = 0; i < nb_sommets_facettes; i++)
4416 {
4417 const int sommet = tab[i];
4418 sommets_utilises[sommet]++;
4419 }
4420 }
4421
4422 // Suppression des sommets virtuels inutilises
4423 // Pour cela, on parcours l'espace virtuel des sommets,
4424 // et si un sommet n'est pas utilise on le retire de l'espace virtuel
4425 // et de l'espace distant correspondant (on envoie au proprietaire
4426 // du sommet le rang du sommet a supprimer dans le tableau des elements
4427 // distants).
4428 // Le schema de comm a utiliser est "les proprietaires d'elements virtuels
4429 // parlent aux proprietaires des elements reels" :
4430 {
4431 const Schema_Comm& comm = desc_sommets_.schema_comm_inverse();
4432 comm.begin_comm();
4433 // Boucle sur les espaces virtuels de sommets
4434 {
4435 Descripteur_FT& espace_virtuel = desc_sommets_.espace_virtuel();
4436 const ArrOfInt& pe_voisins = espace_virtuel.pe_voisins();
4437 const int nb_pe_voisins = pe_voisins.size_array();
4438 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
4439 {
4440 const int pe = pe_voisins[indice_pe];
4441 const ArrOfInt& elements = espace_virtuel.elements(pe);
4442 const int nb_elements = elements.size_array();
4443 Sortie& buffer = comm.send_buffer(pe);
4444 new_elements.resize_array(0);
4445 for (int i = 0; i < nb_elements; i++)
4446 {
4447 const int sommet = elements[i];
4448 if (sommets_utilises[sommet])
4449 {
4450 // Le sommet est utilise, on le laisse dans la liste
4451 new_elements.append_array(sommet);
4452 }
4453 else
4454 {
4455 // Le sommet n'est pas utilise, on envoie le rang du sommet a supprimer
4456 // au proprietaire
4457 buffer << i;
4458 }
4459 }
4460 // Mise a jour des elements virtuels
4461 espace_virtuel.set_elements(pe, new_elements);
4462 }
4463 espace_virtuel.calcul_liste_pe_voisins();
4464 }
4466 // On retire les elements des listes d'elements distants
4467 {
4468 Descripteur_FT& espace_distant = desc_sommets_.espace_distant();
4469 const ArrOfInt& pe_voisins = comm.get_recv_pe_list();
4470 const int nb_pe_voisins = pe_voisins.size_array();
4471 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
4472 {
4473 const int pe = pe_voisins[indice_pe];
4474 const ArrOfInt& elements = espace_distant.elements(pe);
4475 const int nb_elements = elements.size_array();
4476 Entree& buffer = comm.recv_buffer(pe);
4477 int element_courant = 0;
4478 new_elements.resize_array(0);
4479 do
4480 {
4481 // rang du prochain sommet a supprimer dans "elements"
4482 int rang_sommet;
4483 buffer >> rang_sommet;
4484 if (buffer.eof())
4485 rang_sommet = nb_elements;
4486 else
4487 assert(rang_sommet < nb_elements);
4488 // On conserve les sommets jusqu'a rang_sommet exclu
4489 for (; element_courant < rang_sommet; element_courant++)
4490 {
4491 const int sommet = elements[element_courant];
4492 new_elements.append_array(sommet);
4493 // On marque du sommet car il est utilise
4494 // dans un espace distant
4495 sommets_utilises[sommet]++;
4496 }
4497 // On passe le sommet a retirer
4498 element_courant++;
4499 }
4500 while (element_courant < nb_elements);
4501 // Mise a jour des elements distants
4502 espace_distant.set_elements(pe, new_elements);
4503 }
4504 espace_distant.calcul_liste_pe_voisins();
4505 }
4506 comm.end_comm();
4507 }
4508 // Suppression des sommets reels inutilises :
4509 // Mise a jour de :
4510 // * sommets_
4511 // * sommet_elem_
4512 // * sommet_face_bord_
4513 // * sommet_PE_owner_
4514 // * drapeaux_sommets_
4515 // On construit en meme temps le tableau renum_sommets:
4516 // si i est l'indice actuel d'un sommet, renum_sommets[i]
4517 // est l'indice du sommet apres suppression des sommets
4518 // inutilises.
4519 ArrOfIntFT renum_sommets(sommets_.dimension(0));
4520 {
4521 const int nbsommets = sommets_.dimension(0);
4522 // Compteur de sommets apres suppression
4523 int n = 0;
4524 for (int i = 0; i < nbsommets; i++)
4525 {
4526 if (sommets_utilises[i])
4527 {
4528 renum_sommets[i] = n;
4529 sommets_(n, 0) = sommets_(i, 0);
4530 sommets_(n, 1) = sommets_(i, 1);
4531 if (dimension3)
4532 sommets_(n, 2) = sommets_(i, 2);
4533 sommet_elem_[n] = sommet_elem_[i];
4537 n++;
4538 }
4539 else
4540 {
4541 renum_sommets[i] = -1; // Le sommet i est supprime
4542 }
4543 }
4544 sommets_ .resize(n, Objet_U::dimension);
4545 sommet_elem_ .resize_array(n);
4546 sommet_face_bord_.resize_array(n);
4547 sommet_PE_owner_ .resize_array(n);
4548 drapeaux_sommets_.resize_array(n);
4549 }
4550
4551 // Renumerotation des sommets dans desc_sommets
4552 {
4553 // Boucle sur les deux espaces : distant et virtuel
4554 for (int num_espace = 0; num_espace < 2; num_espace++)
4555 {
4556 // Espace_dv est soit l'ESPACE_D(istant), soit l'ESPACE_V(irtuel).
4557 Descripteur_FT& espace_dv =
4558 (num_espace == 0)
4559 ? desc_sommets_.espace_distant()
4560 : desc_sommets_.espace_virtuel();
4561
4562 const ArrOfInt& pe_voisins = espace_dv.pe_voisins();
4563 const int nb_pe_voisins = pe_voisins.size_array();
4564 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
4565 {
4566 const int pe = pe_voisins[indice_pe];
4567 const ArrOfInt& elements = espace_dv.elements(pe);
4568 const int nb_elements = elements.size_array();
4569 new_elements.resize_array(nb_elements);
4570 for (int i = 0; i < nb_elements; i++)
4571 {
4572 const int num_sommet = elements[i];
4573 const int new_num = renum_sommets[num_sommet];
4574 assert(new_num >= 0);
4575 new_elements[i] = new_num;
4576 }
4577 espace_dv.set_elements(pe, new_elements);
4578 }
4579 // Mise a jour du descripteur:
4580 espace_dv.calcul_liste_pe_voisins();
4581 }
4582 desc_sommets_.calcul_schema_comm(sommets_.dimension(0));
4583 }
4584
4585 // Mise a jour de sommet_num_owner_:
4586 {
4587 const int nbsommets = sommets_.dimension(0);
4588 sommet_num_owner_.resize_array(nbsommets);
4589 for (int i = 0; i < nbsommets; i++)
4590 sommet_num_owner_[i] = i;
4591 desc_sommets_.echange_espace_virtuel(sommet_num_owner_);
4592 }
4593
4594 // Renumerotation des sommets dans facettes_
4595 {
4596 ArrOfInt& tab = facettes_; // vu comme unidimensionnel
4597 const int nb_sommets_facettes = tab.size_array();
4598 // Boucle sur tous les sommets de toutes les facettes
4599 for (int i = 0; i < nb_sommets_facettes; i++)
4600 {
4601 const int sommet = tab[i];
4602 const int new_num = renum_sommets[sommet];
4603 tab[i] = new_num;
4604 }
4605 }
4606
4608
4610}
4611
4612/*! @brief Supprime les facettes dont les indices locaux sont donnes en parametre.
4613 *
4614 * Le maillage est nettoye et retourne a l'etat MINIMAL.
4615 *
4616 */
4617void Maillage_FT_Disc::supprimer_facettes(const ArrOfInt& liste_facettes)
4618{
4619 const int n = liste_facettes.size_array();
4620 for (int i = 0; i < n; i++)
4621 {
4622 int j = liste_facettes[i];
4623 // On rend la facette j "invalide" pour nettoyer_maillage()
4624 facettes_(j, 1) = facettes_(j, 0);
4625 }
4627}
4628
4629//Procedure de nettoyage des sommets que l on ne veut pas considerer
4630//a l etape suivante: sommets virtuels et sur des frontieres ouvertes
4632{
4633 assert(statut_ >= MINIMAL);
4634
4636 const int dimension3 = (Objet_U::dimension==3);
4637 ArrOfIntFT new_elements;
4638 ArrOfIntFT sommets_utilises(nb_sommets());
4639 sommets_utilises=0;
4640
4641 //On detecte les sommets utilises
4642 //On ne retient pas les sommets virtuels et ceux situes sur des faces de frontiere ouverte
4643 for (int som=0; som<nb_sommets(); som++)
4644 {
4646 int face_loc;
4647 int face_bord = sommet_face_bord_[som];
4648 int face_fr_ouverte = 0;
4649 if ((face_bord!=-1))
4650 {
4651 const Cond_lim_base& type_cl = zcl.condition_limite_de_la_face_reelle(face_bord,face_loc);
4652 if (((!sub_type(Dirichlet,type_cl)) && (!sub_type(Dirichlet_homogene,type_cl)) && (!sub_type(Symetrie,type_cl)))
4653 || (sub_type(Dirichlet_entree_fluide,type_cl)))
4654 face_fr_ouverte = 1;
4655 }
4656
4657 if ((!sommet_virtuel(som)) && (!face_fr_ouverte))
4658 sommets_utilises[som] ++;
4659 }
4660
4661
4662 // Suppression des sommets virtuels inutilises
4663 // Pour cela, on parcours l'espace virtuel des sommets,
4664 // et si un sommet n'est pas utilise on le retire de l'espace virtuel
4665 // et de l'espace distant correspondant (on envoie au proprietaire
4666 // du sommet le rang du sommet a supprimer dans le tableau des elements
4667 // distants).
4668 // Le schema de comm a utiliser est "les proprietaires d'elements virtuels
4669 // parlent aux proprietaires des elements reels" :
4670 {
4671 const Schema_Comm& comm = desc_sommets_.schema_comm_inverse();
4672 comm.begin_comm();
4673 // Boucle sur les espaces virtuels de sommets
4674 {
4675 Descripteur_FT& espace_virtuel = desc_sommets_.espace_virtuel();
4676 const ArrOfInt& pe_voisins = espace_virtuel.pe_voisins();
4677 const int nb_pe_voisins = pe_voisins.size_array();
4678 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
4679 {
4680 const int pe = pe_voisins[indice_pe];
4681 const ArrOfInt& elements = espace_virtuel.elements(pe);
4682 const int nb_elements = elements.size_array();
4683 Sortie& buffer = comm.send_buffer(pe);
4684 new_elements.resize_array(0);
4685 for (int i = 0; i < nb_elements; i++)
4686 {
4687 const int sommet = elements[i];
4688 if (sommets_utilises[sommet])
4689 {
4690 // Le sommet est utilise, on le laisse dans la liste
4691 new_elements.append_array(sommet);
4692 }
4693 else
4694 {
4695 // Le sommet n'est pas utilise, on envoie le rang du sommet a supprimer
4696 // au proprietaire
4697 buffer << i;
4698 }
4699 }
4700 // Mise a jour des elements virtuels
4701 espace_virtuel.set_elements(pe, new_elements);
4702 }
4703 espace_virtuel.calcul_liste_pe_voisins();
4704 }
4706 // On retire les elements des listes d'elements distants
4707 {
4708 Descripteur_FT& espace_distant = desc_sommets_.espace_distant();
4709 const ArrOfInt& pe_voisins = comm.get_recv_pe_list();
4710 const int nb_pe_voisins = pe_voisins.size_array();
4711 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
4712 {
4713 const int pe = pe_voisins[indice_pe];
4714 const ArrOfInt& elements = espace_distant.elements(pe);
4715 const int nb_elements = elements.size_array();
4716 Entree& buffer = comm.recv_buffer(pe);
4717 int element_courant = 0;
4718 new_elements.resize_array(0);
4719 do
4720 {
4721 // rang du prochain sommet a supprimer dans "elements"
4722 int rang_sommet;
4723 buffer >> rang_sommet;
4724 if (buffer.eof())
4725 rang_sommet = nb_elements;
4726 else
4727 assert(rang_sommet < nb_elements);
4728 // On conserve les sommets jusqu'a rang_sommet exclu
4729 for (; element_courant < rang_sommet; element_courant++)
4730 {
4731 const int sommet = elements[element_courant];
4732 new_elements.append_array(sommet);
4733 // On marque du sommet car il est utilise
4734 // dans un espace distant
4735 sommets_utilises[sommet]++;
4736 }
4737 // On passe le sommet a retirer
4738 element_courant++;
4739 }
4740 while (element_courant < nb_elements);
4741 // Mise a jour des elements distants
4742 espace_distant.set_elements(pe, new_elements);
4743 }
4744 espace_distant.calcul_liste_pe_voisins();
4745 }
4746 comm.end_comm();
4747 }
4748
4749 // Suppression des sommets reels inutilises
4750 // (dans notre cas ceux sont des sommets sur des faces de frontieres ouvertes):
4751 // Mise a jour de :
4752 // * sommets_
4753 // * sommet_elem_
4754 // * sommet_face_bord_
4755 // * sommet_PE_owner_
4756 // * drapeaux_sommets_
4757 // On construit en meme temps le tableau renum_sommets:
4758 // si i est l'indice actuel d'un sommet, renum_sommets[i]
4759 // est l'indice du sommet apres suppression des sommets
4760 // inutilises.
4761 ArrOfIntFT renum_sommets(sommets_.dimension(0));
4762 {
4763 const int nbsommets = sommets_.dimension(0);
4764 // Compteur de sommets apres suppression
4765 int n = 0;
4766 for (int i = 0; i < nbsommets; i++)
4767 {
4768 if (sommets_utilises[i])
4769 {
4770 renum_sommets[i] = n;
4771 sommets_(n, 0) = sommets_(i, 0);
4772 sommets_(n, 1) = sommets_(i, 1);
4773 if (dimension3)
4774 sommets_(n, 2) = sommets_(i, 2);
4775 sommet_elem_[n] = sommet_elem_[i];
4779 n++;
4780 }
4781 else
4782 {
4783 renum_sommets[i] = -1; // Le sommet i est supprime
4784 }
4785 }
4786 sommets_ .resize(n, Objet_U::dimension);
4787 sommet_elem_ .resize_array(n);
4788 sommet_face_bord_.resize_array(n);
4789 sommet_PE_owner_ .resize_array(n);
4790 drapeaux_sommets_.resize_array(n);
4791
4793
4794 }
4795
4796 //On supprime ce qui est lie aux espaces distants et virtuel
4797
4798 // Renumerotation des sommets dans desc_sommets
4799 {
4800 // Boucle sur les deux espaces : distant et virtuel
4801 for (int num_espace = 0; num_espace < 2; num_espace++)
4802 {
4803 // Espace_dv est soit l'ESPACE_D(istant), soit l'ESPACE_V(irtuel).
4804 Descripteur_FT& espace_dv =
4805 (num_espace == 0)
4806 ? desc_sommets_.espace_distant()
4807 : desc_sommets_.espace_virtuel();
4808
4809 const ArrOfInt& pe_voisins = espace_dv.pe_voisins();
4810 const int nb_pe_voisins = pe_voisins.size_array();
4811 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
4812 {
4813 const int pe = pe_voisins[indice_pe];
4814 const ArrOfInt& elements = espace_dv.elements(pe);
4815 const int nb_elements = elements.size_array();
4816 new_elements.resize_array(nb_elements);
4817 for (int i = 0; i < nb_elements; i++)
4818 {
4819 const int num_sommet = elements[i];
4820 const int new_num = renum_sommets[num_sommet];
4821 assert(new_num >= 0);
4822 new_elements[i] = new_num;
4823 }
4824 espace_dv.set_elements(pe, new_elements);
4825 }
4826 // Mise a jour du descripteur:
4827 espace_dv.calcul_liste_pe_voisins();
4828 }
4829 desc_sommets_.calcul_schema_comm(sommets_.dimension(0));
4830 }
4831
4832 // Mise a jour de sommet_num_owner_:
4833 {
4834 const int nbsommets = sommets_.dimension(0);
4835 sommet_num_owner_.resize_array(nbsommets);
4836 for (int i = 0; i < nbsommets; i++)
4837 sommet_num_owner_[i] = i;
4838 desc_sommets_.echange_espace_virtuel(sommet_num_owner_);
4839 }
4840
4843}
4844
4845void Maillage_FT_Disc::nettoyer_phase(const Nom& nom_eq, const int phase)
4846{
4847 assert(statut_ >= MINIMAL);
4848
4850 const int dimension3 = (Objet_U::dimension==3);
4851 ArrOfIntFT new_elements;
4852 ArrOfIntFT sommets_utilises(nb_sommets());
4853 sommets_utilises=0;
4855 Transport_Interfaces_FT_Disc& eq_interf = ref_cast_non_const(Transport_Interfaces_FT_Disc,eq);
4856 const DoubleTab& indic = eq_interf.inconnue().valeurs();
4857 double phase_reelle = double(phase);
4858 int elem;
4859
4860 //Les sommets utilises sont ceux places dans la phase marquee
4861 for (int som=0; som<nb_sommets(); som++)
4862 {
4863 elem = sommet_elem_[som];
4864 if (est_egal(indic(elem),phase_reelle))
4865 sommets_utilises[som] ++;
4866 }
4867
4868
4869 // Suppression des sommets virtuels inutilises
4870 // Pour cela, on parcours l'espace virtuel des sommets,
4871 // et si un sommet n'est pas utilise on le retire de l'espace virtuel
4872 // et de l'espace distant correspondant (on envoie au proprietaire
4873 // du sommet le rang du sommet a supprimer dans le tableau des elements
4874 // distants).
4875 // Le schema de comm a utiliser est "les proprietaires d'elements virtuels
4876 // parlent aux proprietaires des elements reels" :
4877 {
4878 const Schema_Comm& comm = desc_sommets_.schema_comm_inverse();
4879 comm.begin_comm();
4880 // Boucle sur les espaces virtuels de sommets
4881 {
4882 Descripteur_FT& espace_virtuel = desc_sommets_.espace_virtuel();
4883 const ArrOfInt& pe_voisins = espace_virtuel.pe_voisins();
4884 const int nb_pe_voisins = pe_voisins.size_array();
4885 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
4886 {
4887 const int pe = pe_voisins[indice_pe];
4888 const ArrOfInt& elements = espace_virtuel.elements(pe);
4889 const int nb_elements = elements.size_array();
4890 Sortie& buffer = comm.send_buffer(pe);
4891 new_elements.resize_array(0);
4892 for (int i = 0; i < nb_elements; i++)
4893 {
4894 const int sommet = elements[i];
4895 if (sommets_utilises[sommet])
4896 {
4897 // Le sommet est utilise, on le laisse dans la liste
4898 new_elements.append_array(sommet);
4899 }
4900 else
4901 {
4902 // Le sommet n'est pas utilise, on envoie le rang du sommet a supprimer
4903 // au proprietaire
4904 buffer << i;
4905 }
4906 }
4907 // Mise a jour des elements virtuels
4908 espace_virtuel.set_elements(pe, new_elements);
4909 }
4910 espace_virtuel.calcul_liste_pe_voisins();
4911 }
4913 // On retire les elements des listes d'elements distants
4914 {
4915 Descripteur_FT& espace_distant = desc_sommets_.espace_distant();
4916 const ArrOfInt& pe_voisins = comm.get_recv_pe_list();
4917 const int nb_pe_voisins = pe_voisins.size_array();
4918 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
4919 {
4920 const int pe = pe_voisins[indice_pe];
4921 const ArrOfInt& elements = espace_distant.elements(pe);
4922 const int nb_elements = elements.size_array();
4923 Entree& buffer = comm.recv_buffer(pe);
4924 int element_courant = 0;
4925 new_elements.resize_array(0);
4926 do
4927 {
4928 // rang du prochain sommet a supprimer dans "elements"
4929 int rang_sommet;
4930 buffer >> rang_sommet;
4931 if (buffer.eof())
4932 rang_sommet = nb_elements;
4933 else
4934 assert(rang_sommet < nb_elements);
4935 // On conserve les sommets jusqu'a rang_sommet exclu
4936 for (; element_courant < rang_sommet; element_courant++)
4937 {
4938 const int sommet = elements[element_courant];
4939 new_elements.append_array(sommet);
4940 // On marque du sommet car il est utilise
4941 // dans un espace distant
4942 sommets_utilises[sommet]++;
4943 }
4944 // On passe le sommet a retirer
4945 element_courant++;
4946 }
4947 while (element_courant < nb_elements);
4948 // Mise a jour des elements distants
4949 espace_distant.set_elements(pe, new_elements);
4950 }
4951 espace_distant.calcul_liste_pe_voisins();
4952 }
4953 comm.end_comm();
4954 }
4955
4956 // Suppression des sommets reels inutilises
4957 // (dans notre cas ceux sont des sommets sur des faces de frontieres ouvertes):
4958 // Mise a jour de :
4959 // * sommets_
4960 // * sommet_elem_
4961 // * sommet_face_bord_
4962 // * sommet_PE_owner_
4963 // * drapeaux_sommets_
4964 // On construit en meme temps le tableau renum_sommets:
4965 // si i est l'indice actuel d'un sommet, renum_sommets[i]
4966 // est l'indice du sommet apres suppression des sommets
4967 // inutilises.
4968 ArrOfIntFT renum_sommets(sommets_.dimension(0));
4969 {
4970 const int nbsommets = sommets_.dimension(0);
4971 // Compteur de sommets apres suppression
4972 int n = 0;
4973 for (int i = 0; i < nbsommets; i++)
4974 {
4975 if (sommets_utilises[i])
4976 {
4977 renum_sommets[i] = n;
4978 sommets_(n, 0) = sommets_(i, 0);
4979 sommets_(n, 1) = sommets_(i, 1);
4980 if (dimension3)
4981 sommets_(n, 2) = sommets_(i, 2);
4982 sommet_elem_[n] = sommet_elem_[i];
4986 n++;
4987 }
4988 else
4989 {
4990 renum_sommets[i] = -1; // Le sommet i est supprime
4991 }
4992 }
4993 sommets_ .resize(n, Objet_U::dimension);
4994 sommet_elem_ .resize_array(n);
4995 sommet_face_bord_.resize_array(n);
4996 sommet_PE_owner_ .resize_array(n);
4997 drapeaux_sommets_.resize_array(n);
4998
5000
5001 }
5002
5003 //On supprime ce qui est lie aux espaces distants et virtuel
5004
5005 // Renumerotation des sommets dans desc_sommets
5006 {
5007 // Boucle sur les deux espaces : distant et virtuel
5008 for (int num_espace = 0; num_espace < 2; num_espace++)
5009 {
5010 // Espace_dv est soit l'ESPACE_D(istant), soit l'ESPACE_V(irtuel).
5011 Descripteur_FT& espace_dv =
5012 (num_espace == 0)
5013 ? desc_sommets_.espace_distant()
5014 : desc_sommets_.espace_virtuel();
5015
5016 const ArrOfInt& pe_voisins = espace_dv.pe_voisins();
5017 const int nb_pe_voisins = pe_voisins.size_array();
5018 for (int indice_pe = 0; indice_pe < nb_pe_voisins; indice_pe++)
5019 {
5020 const int pe = pe_voisins[indice_pe];
5021 const ArrOfInt& elements = espace_dv.elements(pe);
5022 const int nb_elements = elements.size_array();
5023 new_elements.resize_array(nb_elements);
5024 for (int i = 0; i < nb_elements; i++)
5025 {
5026 const int num_sommet = elements[i];
5027 const int new_num = renum_sommets[num_sommet];
5028 assert(new_num >= 0);
5029 new_elements[i] = new_num;
5030 }
5031 espace_dv.set_elements(pe, new_elements);
5032 }
5033 // Mise a jour du descripteur:
5034 espace_dv.calcul_liste_pe_voisins();
5035 }
5036 desc_sommets_.calcul_schema_comm(sommets_.dimension(0));
5037 }
5038
5039 // Mise a jour de sommet_num_owner_:
5040 {
5041 const int nbsommets = sommets_.dimension(0);
5042 sommet_num_owner_.resize_array(nbsommets);
5043 for (int i = 0; i < nbsommets; i++)
5044 sommet_num_owner_[i] = i;
5045 desc_sommets_.echange_espace_virtuel(sommet_num_owner_);
5046 }
5047
5050}
5051
5052#if (defined(PATCH_HYSTERESIS_V2) || defined(PATCH_HYSTERESIS_V3))
5053// From Remaillage_FT : FTd_vecteur3 to ArrOfDouble...
5054inline double produit_scalaire(const ArrOfDouble& a, const ArrOfDouble& b)
5055{
5056 assert(a.size_array()==3);
5057 assert(b.size_array()==3);
5058 return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
5059}
5060
5061inline void produit_vectoriel(const ArrOfDouble& a, const ArrOfDouble& b, ArrOfDouble& resu)
5062{
5063 assert(a.size_array()==3);
5064 assert(b.size_array()==3);
5065 assert(resu.size_array()==3);
5066 resu[0] = a[1]*b[2] - a[2]*b[1];
5067 resu[1] = a[2]*b[0] - a[0]*b[2];
5068 resu[2] = a[0]*b[1] - a[1]*b[0];
5069}
5070
5071void Maillage_FT_Disc::pre_lissage_courbure(ArrOfDouble& store_courbure_sommets, const int nitera) const
5072{
5073 // Un peu de lissage :
5074 const int nsom = nb_sommets();
5075 const ArrOfDouble& surface = get_update_surface_facettes();
5076 ArrOfDouble tmp_courbure_sommets(store_courbure_sommets);
5077 ArrOfDouble surface_autour_sommets(store_courbure_sommets);
5078
5079 int i_facette;
5080 for (int iter = 0; iter < nitera; iter++)
5081 {
5082 tmp_courbure_sommets = store_courbure_sommets;
5083 store_courbure_sommets = 0.;
5084 surface_autour_sommets = 0.;
5085 for (i_facette = 0; i_facette < nb_facettes(); i_facette++)
5086 {
5087 // Ne pas calculer de flux pour les facettes virtuelles:
5088 if (facette_virtuelle(i_facette))
5089 continue;
5090
5091 //const int s0 = facettes_(i_facette, 0);
5092 double moy = 0.;
5093 int count =0;
5094 for (int i = 0; i < 3; i++)
5095 {
5096 const int si = facettes_(i_facette, i);
5097 if (!sommet_ligne_contact(si))
5098 {
5099 moy += tmp_courbure_sommets[si];
5100 count++;
5101 }
5102 }
5103 if (count>0)
5104 moy /= count;
5105 for (int i = 0; i < 3; i++)
5106 {
5107 const int s = facettes_(i_facette, i);
5108 const double surf = surface(i_facette);
5109 store_courbure_sommets[s] += moy*surf;
5110 surface_autour_sommets[s] +=surf;
5111 }
5112 }
5113 for (int isom = 0; isom < nsom; isom++)
5114 if (surface_autour_sommets[isom]>0)
5115 store_courbure_sommets[isom] /=surface_autour_sommets[isom];
5116 }
5117}
5118
5119// Correction a la contact line pour prendre en compte que la tangente au cercle n'est pas rigoureusement donnee par la facette
5120// Il faut faire une petite correction (d'angle eps) pour evaluer l'angle de contact au sommet...
5121// Pour evaluer cette correction, on a besoin de connaitre la courbure normale kappa_n=1/r...
5122// Il faut donc une methode iterative (a 2 passe au moins).
5123// 1ere pass : On ne connait pas la courbure, on ne fait pas de correction.
5124// 2eme pass (et potentiellement les suivantes) : On utilise l'approximation de la courbure
5125// locale issue de la passe precedente.
5126void Maillage_FT_Disc::correction_costheta(const double c, const int s0, const int facette,
5127 /* const ArrOfDouble& s0s1, const ArrOfDouble& s0s2, */
5128 double ps) const
5129{
5130 // Soit l=norme(s0G) ou G est le cdg de la facette.
5131 // s0G = 1./3. * (s0s1+s0s2)
5132 double l2=0, r=0;
5133 /* for (int j = 0; j < Objet_U::dimension; j++)
5134 {
5135 double tmp= (s0s1[j]+s0s2[j]);
5136 l2 += tmp*tmp;
5137 }
5138 l2 *= 1./3.;
5139 */
5140 // Un estimation de la taille de la facette est donnee par sa surface :
5141 //const ArrOfDouble& surface = get_update_surface_facettes();
5142 //l2 = surface(facette);
5143#if 1
5144 int ii=0;
5145 for (ii=0; ii<3; ii++)
5146 {
5147 if (facettes_(facette,ii) == s0)
5148 {
5149 break;
5150 }
5151
5152 }
5153 assert(facettes_(facette,ii)==s0);
5154 const int s1 = facettes_(facette,(ii+1)%3);
5155 const int s2 = facettes_(facette,(ii+2)%3);
5156
5157 ArrOfDouble som0(3),som1(3),som2(3), s0s1(3), s0s2(3);
5158 for (int j=0; j<Objet_U::dimension; j++)
5159 {
5160 som0[j] = sommets_(s0,j);
5161 som1[j] = sommets_(s1,j);
5162 som2[j] = sommets_(s2,j);
5163 s0s1[j] = som1[j] - som0[j];
5164 s0s2[j] = som2[j] - som0[j];
5165 }
5166
5167 /*
5168 double tmp1=0,tmp2=0;
5169 for (int j = 0; j < Objet_U::dimension; j++)
5170 {
5171 tmp1 += (s0s1[j]*s0s1[j]);
5172 tmp2 += (s0s2[j]*s0s2[j]);
5173 }
5174 l2 = 0.5*(tmp1+tmp2);
5175 */
5176 for (int j = 0; j < Objet_U::dimension; j++)
5177 {
5178 double tmp= (s0s1[j]+s0s2[j]);
5179 l2 += tmp*tmp;
5180 }
5181 l2 *= 1./3.;
5182#endif
5183
5184 // Pour r, on utilise la courbure... Donc iteratif...
5185 if (c!=0.)
5186 {
5188 //r = 2./c; // Hypothese : localement isotrope : kappa_n=kappa_t=0.5kappa
5189 //r = 0.; // Hypothese : kappa_n=0
5190 //r = 1./c; // Hypothese : courbure uniquement normale : kappa_n=kappa
5191 double r2 = r*r;
5192 if (l2>=r2)
5193 {
5194 Cerr << "Probleme lors du calcul de la courbure a la ligne de contact. "<< finl;
5195 Cerr << "Il semblerait que la courbure au sommet " << s0 << " sur le process "
5196 << Process::me() << " soit tres grande (ie un rayon de courbure plus petit"
5197 << " que la longueur caracteristique de l'element du Front. " << finl;
5198 Cerr << "Une erreur possible est un angle de contact initialement trop loin de la "
5199 << "gamme d'angles de contacts fournis dans le jeu de donnees. " << finl;
5200 Cerr << "Verifiez votre JDD puis contactez TRUST support." << finl;
5201 Process::exit();
5202 }
5203 //assert(l2<r2);
5204 // theta_reel = theta_apparent + eps // x=theta_apparent; eps+alpha= pi/2
5205 // alpha est l'angle entre le plan de la facette et la normale au cercle (vers l'interieur).
5206 // cos(x+eps) = cos(x)*cos(eps)-sin(x)sin(eps)
5207 // avec :
5208 // o cos(x) = ps
5209 // o sin(x) = sqrt(1-ps^2)
5210 // o cos(eps) = sin(alpha)=sin(pi/2-eps) = sqrt((r^2-l^2)/r^2)
5211 // o sin(eps) = cos(alpha)=cos(pi/2-eps)=l/r
5212 ps = ps*sqrt((r2-l2)/r2) - sqrt((1.-ps*ps)*l2/r2);
5213 }
5214}
5215
5216// Methode permettant de calculer lors d'une hysterisis l'angle de contact
5217// dans la plage des angles autorises qui soit le plus proche de l'angle de
5218// contact reel. C'est la premiere fois qu'on a besoin d'un angle de contact
5219// reelement mesure sur le maillage (et pas fourni en CL)
5220double Maillage_FT_Disc::calculer_costheta_objectif(const int s0, const int facette, const int call, const double c,
5221 const DoubleTabFT& tab_cos_theta, ArrOfBit& drapeau_angle_in_range) const
5222{
5223 const Parcours_interface& parcours = refparcours_interface_.valeur();
5224 const DoubleTab& normale = get_update_normale_facettes();
5225 const int numface0 = sommet_face_bord_[s0];
5226 int j; /*
5227 ArrOfDouble som0(3),som1(3),som2(3), s0s1(3), s0s2(3);
5228 for (j=0; j<Objet_U::dimension; j++)
5229 {
5230 som0[j] = sommets_(s0,j);
5231 som1[j] = sommets_(s1,j);
5232 som2[j] = sommets_(s2,j);
5233 s0s1[j] = som1[j] - som0[j];
5234 s0s2[j] = som2[j] - som0[j];
5235 } */
5236 ArrOfDouble nprime(3), vect_base(3), ntheta(3);
5237 // Si on prend ntheta egale a nfacette
5238 // au lieu d'essayer de determiner le vrai ntheta (qui correspond a l'objectif fixee)
5239 // ntheta[0] = normale(facette, 0) ;
5240 // ntheta[1] = normale(facette, 1) ;
5241 // ntheta[2] = normale(facette, 2) ;
5242 // Avec cette approximation, on ne tient pas compte de la CL et
5243 // C'est comme si la courbure (dans la direction normale au bord) etait nulle!
5244 // Dans le cas d'un cylindre comme la courbure tangeante est nulle, on obtient
5245 // Une courbure totale evaluee a 0 et donc un equilibre impossible quel que soit la CL...
5246 //
5247 // Ce que l'on veut plutot faire, c'est que ntheta forme un angle theta avec la normale au bord.
5248 // (ou theta doit etre calcule pour etre la projection de la valeur theta reele sur
5249 // l'intervalle d'angles authorises)
5250 //
5251 // Pour calculer la contribution en s0, on a besoin de connaitre l'angle de contact en s0
5252 // Au lieu de l'angle reel, on veut connaitre l'angle objectif, cad celui qui
5253 // doit etre atteint (si on est hors equilibbre) pour satisfaire la ligne de contact.
5254
5255 // Pour cela, il faut ici calculer l'angle de contact reel a la paroi et soit :
5256 // 1. il est dans la gamme d'angles de contact souhaitee : C'est alors cet angle qu'on utilise
5257 // pour le calcul de la courbure.
5258 // 2. il n'est pas dans la gamme des angles authorises : Il faut alors rechercher la borne de
5259 // l'intervalle la plus proche de l'angle reel et utiliser celle-ci pour calculer la courbure.
5260 // Dans ce second cas, cela aura pour effet de creer une courbure locale (aux sommets de la ligne de contact)
5261 // qui n'est pas homogene a celle a l'interieure du dom, ce qui va creer un terme source a divergence non nulle
5262 // pour la qdm, qui, via navier stokes va mettre le fluide en mouvement, qui, une fois la vitesse interpolee,
5263 // va deplacer le noeud en paroi dans la bonne direction.
5264 // C'est donc dans le cas 2 une methode tres indirecte d'imposer l'angle de contact.
5265 // Mais qui marche? Voir fiche hysterisis...
5266
5267 const double costheta0 = tab_cos_theta(s0, 0);
5268 const double costheta1 = tab_cos_theta(s0, 1);
5269 /* if (std::fabs(costheta0-costheta1)<1e-5) {
5270 // Pas besoin de se casser la tete s'il n'y a pas d'hysterisis...
5271 return costheta0;
5272 }
5273 */
5274
5275 // Normale unitaire a la face de bord (vers l'interieur)
5276 double nf0[3] = {0., 0., 0.};
5277 parcours.calculer_normale_face_bord(numface0,
5278 sommets_(s0,0), sommets_(s0,1), sommets_(s0,2),
5279 nf0[0], nf0[1], nf0[2]);
5280
5281 // Calcul du produit scalaire entre la normale au bord et la normale unitaire a la facette
5282 // On a besoin ici de celle orientee vers la vapeur pour etre coherent avec la definition de
5283 // l'angle de contact (qui est pris du cote liquide). Donc il faut -normale dans le ps :
5284 double ps = 0;
5285 for (j = 0; j < Objet_U::dimension; j++)
5286 ps -= nf0[j]* normale(facette, j);
5287 // Le produit scalaire entre les deux normales, c'est comme celui entre les 2 tangentes...
5288 // On a donc ps=cos(theta)
5289
5290 // Correction de l'angle de contact (prise en compte de la tangente au cercle
5291 // qui n'est pas rigoureusement donnee par la facette
5292 if ((call> 1) && (correction_contact_courbure_coeff_!=0.))
5293 correction_costheta(c, s0, facette, ps);
5294
5295 double costheta=0.;
5296 if ((ps-costheta0)*(ps-costheta1) <=0 )
5297 {
5298 // L'angle reel est dans l'intervalle authorise. On l'utilise pour le calcul de la courbure.
5299 costheta = ps;
5300 }
5301 else
5302 {
5303 drapeau_angle_in_range.clearbit(s0);
5304 // L'angle reel est en dehors de l'intervalle. On retient donc la borne de l'intervalle la
5305 // plus proche comme valeur pour utiliser dans le calcul de la courbure.
5306 if (std::fabs(ps-costheta0) <std::fabs(ps-costheta1))
5307 {
5308 // On est proche de la borne costheta0. C'est elle qu'on va utiliser.
5309 costheta = costheta0;
5310 }
5311 else
5312 {
5313 costheta = costheta1;
5314 }
5315 }
5316 return costheta;
5317}
5318#endif
5319
5320#ifdef PATCH_HYSTERESIS_V2
5321// A: Le point a reflechir.
5322// nprime: une normale au plan quelconque! -> devient unitaire en sortie!
5323// Ar: La reflexion de A
5324static void miroir(const ArrOfDouble& A, ArrOfDouble& nprime,const ArrOfDouble& O, ArrOfDouble& Ar)
5325{
5326 // Rendre la normale unitaire :
5327 const double l = sqrt(nprime[0] * nprime[0] + nprime[1] * nprime[1] + nprime[2] * nprime[2]);
5328 if (l != 0.)
5329 {
5330 double inv_l = 1. / l;
5331 nprime[0] *= inv_l;
5332 nprime[1] *= inv_l;
5333 nprime[2] *= inv_l;
5334 }
5335
5336 const int m=A.size_array();
5337 assert(m==3);
5338 ArrOfDouble OA(A);
5339 OA-=O;// OA=A-O;
5340 double ps=produit_scalaire(OA,nprime);
5341 //OAr=Ar-O=OA-2.*ps*n => Ar=A-2.*ps*n
5342 for (int i=0; i<m; i++)
5343 {
5344 Ar[i] =A[i]-2.*ps*nprime[i];
5345 }
5346}
5347
5348static void normalize(ArrOfDouble& nprime)
5349{
5350 // Rendre la normale unitaire :
5351 const double l = sqrt(nprime[0] * nprime[0] + nprime[1] * nprime[1] + nprime[2] * nprime[2]);
5352 if (l != 0.)
5353 {
5354 double inv_l = 1. / l;
5355 nprime[0] *= inv_l;
5356 nprime[1] *= inv_l;
5357 nprime[2] *= inv_l;
5358 }
5359}
5360#endif
5361
5362/*! @brief Calcul de la courbure discrete du maillage aux sommets.
5363 *
5364 * Methode de calcul : voir these B. Mathieu paragraphe 3.3.3 page 97
5365 * La courbure est egale a la differentielle de la surface d'interface par rapport
5366 * au deplacement des sommets, divisee par la differentielle du volume.
5367 *
5368 *
5369 * @param (courbure_sommets) Tableau dans lequel on veut stocker la courbure aux sommets. La valeur initiale du tableau est perdue. L'espace virtuel du tableau resultat est a jour.
5370 */
5371void Maillage_FT_Disc::calcul_courbure_sommets(ArrOfDouble& courbure_sommets, const int call) const
5372{
5373 const DoubleTab& normale = get_update_normale_facettes();
5374 const ArrOfDouble& surface = get_update_surface_facettes();
5375
5376 const int nsom = nb_sommets();
5377 const int dim = Objet_U::dimension;
5378 const int nfaces = nb_facettes();
5379
5380#if (defined(PATCH_HYSTERESIS_V2) || defined(PATCH_HYSTERESIS_V3))
5381 ArrOfBit drapeau_angle_in_range;
5382 drapeau_angle_in_range.resize_array(nsom);
5383 drapeau_angle_in_range=1; // par defaut on presume que oui. Si pour une seule facette on est en dehors,
5384 // on le met a 0 pour le sommet en question.
5385 // coef default value is 2.
5386 Cerr << "Your choice of parameters : correction coefficient " << correction_contact_courbure_coeff_
5387 << " and iter pre-lissage : " << niter_pre_lissage_ << finl;
5388 ArrOfDouble store_courbure_sommets(courbure_sommets);
5389 if (call> 1)
5390 {
5391 if (courbure_sommets.size_array() != nsom)
5392 {
5393 Cerr << "Erreur dans la seconde passe du calcul de la courbure... Dimensions des tableaux differentes!" << finl;
5394 Process::exit();
5395 }
5396 pre_lissage_courbure(store_courbure_sommets, niter_pre_lissage_);
5397 }
5398 else
5399 {
5400 // Lors du premier passage, il faut dimensionner correctement le tableau de courbure...
5401 courbure_sommets.resize_array(nsom);
5402 store_courbure_sommets.resize_array(nsom); // aaa
5403 }
5404#else
5405 courbure_sommets.resize_array(nsom);
5406#endif
5407
5408 // Differentielle de la surface d'interface par rapport au deplacement de chaque sommet
5409 DoubleTab d_surface(nsom, dim);
5410 // Differentielle du volume de la phase 1 par rapport au deplacement de chaque sommet
5411 DoubleTab d_volume(nsom, dim);
5412
5413 double n_s[3] = {0.,0.,0.};
5414 const double inverse_dimension = 1. / (double) dimension;
5415 const double un_tiers = 1. / 3.;
5416 const double un_sixieme = 1. / 6.;
5417
5418 // This is based on the angle given in the data file (that is the micros/Young contact angle)
5419 DoubleTabFT tab_cos_theta;
5420 calculer_costheta_minmax(tab_cos_theta);
5421
5422 int i, j, facette;
5423
5424 // Cette classe sert pour promener les sommets sur le bord du domaine.
5425 const Parcours_interface& parcours = refparcours_interface_.valeur();
5426
5427 for (facette = 0; facette < nfaces; facette++)
5428 {
5429 // Si la facette est reelle, on ajoute la contribution a la differentielle
5430 // des deux ou trois sommets
5431 if (! facette_virtuelle(facette))
5432 {
5433 if (!bidim_axi)
5434 {
5435 int ii;
5436 const double surface_sur_dim = surface[facette] * inverse_dimension;
5437 for (ii = 0; ii < dim; ii++)
5438 {
5439 // La differentielle de volume par rapport a un deplacement v est
5440 // (v scalaire n) * surface_facette / dimension
5441 // avec n la normale a la facette dirigee vers la phase 1.
5442 n_s[ii] = normale(facette, ii) * surface_sur_dim;
5443 }
5444 for (ii = 0; ii < dim; ii++)
5445 {
5446 const int sommet = facettes_(facette, ii);
5447 for (j = 0; j < dim; j++)
5448 d_volume(sommet, j) += n_s[j];
5449 }
5450 // Calcul de la differentielle de surface :
5451 if (dim == 2)
5452 {
5453 int som[2];
5454 som[0] = facettes_(facette, 0);
5455 som[1] = facettes_(facette, 1);
5456 double n[2];
5457 n[0] = normale(facette, 0);
5458 n[1] = normale(facette, 1);
5459 // La differentielle est orthogonale a la normale :
5460 d_surface(som[0], 0) -= n[1];
5461 d_surface(som[0], 1) += n[0];
5462 d_surface(som[1], 0) += n[1];
5463 d_surface(som[1], 1) -= n[0];
5464
5465 // Traitement des lignes de contact: ajout d'une contribution
5466 // cos(theta) * differentielle de la surface de bord mouillee par
5467 // la phase 0
5468 for (int i2 = 0; i2 < 2; i2++)
5469 {
5470 const int isom2 = som[i2];
5471 const int face = sommet_face_bord_[isom2];
5472 if (face < 0) // pas une face de bord
5473 continue;
5474
5475#ifndef PATCH_HYSTERESIS_V2
5476 const double costheta = tab_cos_theta(isom2, 0);
5477#else
5478 const double costheta0 = tab_cos_theta(som[i2], 0);
5479 const double costheta1 = tab_cos_theta(som[i2], 1);
5480 // Normale unitaire a la face de bord (vers l'interieur)
5481 double nf1[3] = {0., 0., 0.};
5482 parcours.calculer_normale_face_bord(face, som[i2], som[i2], 0,
5483 nf1[0], nf1[1], nf1[2]);
5484
5485 // Calcul du produit scalaire entre la normale unitaire a la facette
5486 double ps = 0;
5487 for (j = 0; j < dim; j++)
5488 {
5489 ps += nf1[j]* n[j];
5490 }
5491 // Le produit scalaire entre les deux normales, c'est comme celui entre les 2 tangentes...
5492 // On a donc cos(theta)
5493 // A priori, si l'hysterisis fonctionne bien, il est dans l'intervalle
5494 Nom st;
5495 st = (ps-costheta0)*(ps-costheta1) <=0 ? "YES":"NO";
5496 Cerr << "GB_CALCUL_COURBURE 2D PLAN : ps "
5497 << ps << " in costheta ["<< costheta0 << " ; " << costheta1 << "]? " << st << finl;
5498 const double costheta = ps;
5499 Cerr << "Quelle est le sommet a choisir? Est-ce que i2 " << i2 << "est bien le sommet du bord?" << finl;
5500 Cerr << "GB_CALCUL_COURBURE 2D PLAN: "
5501 << "A valider depuis hysterisis. Le developpement fait en 3D n'a pas ete applique ici!" << finl;
5502 Process::exit();
5503#endif
5504
5505 // Normale unitaire au bord
5506 double nx, ny, nz;
5507 parcours.calculer_normale_face_bord(face,
5508 sommets_(som[i2],0), sommets_(som[i2],1), 0.,
5509 nx, ny, nz);
5510 // Ajout de la contribution de la surface:
5511 double signe = (i2==0) ? -1. : 1.;
5512 d_surface(som[i2], 0) += signe * ny * costheta;
5513 d_surface(som[i2], 1) -= signe * nx * costheta;
5514 }
5515
5516 }
5517 else
5518 {
5519 int sommets_loc[3];
5520 sommets_loc[0] = facettes_(facette, 0);
5521 sommets_loc[1] = facettes_(facette, 1);
5522 sommets_loc[2] = facettes_(facette, 2);
5523 ArrOfDouble n(3);// GB mod double[3] to ArrOfDouble
5524 n[0] = normale(facette, 0) * 0.5;
5525 n[1] = normale(facette, 1) * 0.5;
5526 n[2] = normale(facette, 2) * 0.5;
5527 for (ii = 0; ii < 3; ii++)
5528 {
5529 // La differentielle de surface pour un deplacement du sommet i
5530 // est le produit vectoriel de la normale par le vecteur
5531 // s2s1 = (sommet[(i+1)%3] - sommet[(i+2)%3]) * 0.5
5532 // (vecteur de norme "base du triangle * 0.5" et de direction
5533 // la hauteur du triangle)
5534 const int s0 = sommets_loc[ii];
5535 const int s1 = sommets_loc[ (ii+1)%3 ];
5536 const int s2 = sommets_loc[ (ii+2)%3 ];
5537 ArrOfDouble s2s1(3); // GB mod double[3] to ArrOfDouble
5538 s2s1[0] = sommets_(s1,0) - sommets_(s2,0);
5539 s2s1[1] = sommets_(s1,1) - sommets_(s2,1);
5540 s2s1[2] = sommets_(s1,2) - sommets_(s2,2);
5541 // On calcule la courbure partout de la meme maniere
5542 // meme si on est sur une ligne de contact (ie dans un premier temps, sans tenir compte de
5543 // l'effet de la ligne de contact). On corrige l'effet de la ligne de contact par la suite...
5544 d_surface(s0,0) += s2s1[1] * n[2] - s2s1[2] * n[1];
5545 d_surface(s0,1) += s2s1[2] * n[0] - s2s1[0] * n[2];
5546 d_surface(s0,2) += s2s1[0] * n[1] - s2s1[1] * n[0];
5547#ifdef PATCH_HYSTERESIS_V2
5549 {
5550 const int numface0 = sommet_face_bord_[s0];
5551 if (numface0>=0)
5552 {
5553 // Le sommet s0 est sur une ligne de contact.
5554
5555 // Voila la suite :
5556 ArrOfDouble som0(3),som1(3),som2(3), s0s1(3), s0s2(3);
5557 for (j=0; j<dim; j++)
5558 {
5559 som0[j] = sommets_(s0,j);
5560 som1[j] = sommets_(s1,j);
5561 som2[j] = sommets_(s2,j);
5562 s0s1[j] = som1[j] - som0[j];
5563 s0s2[j] = som2[j] - som0[j];
5564 }
5565 ArrOfDouble nprime(3), vect_base(3), ntheta(3);
5566 // Si on prend ntheta egale a nfacette
5567 // au lieu d'essayer de determiner le vrai ntheta (qui correspond a l'objectif fixee)
5568 // ntheta[0] = normale(facette, 0) ;
5569 // ntheta[1] = normale(facette, 1) ;
5570 // ntheta[2] = normale(facette, 2) ;
5571 // Avec cette approximation, on ne tient pas compte de la CL et
5572 // C'est comme si la courbure (dans la direction normale au bord) etait nulle!
5573 // Dans le cas d'un cylindre comme la courbure tangeante est nulle, on obtient
5574 // Une courbure totale evaluee a 0 et donc un equilibre impossible quel que soit la CL...
5575 //
5576 // Ce que l'on veut plutot faire, c'est que ntheta forme un angle theta avec la normale au bord.
5577 // (ou theta doit etre calcule pour etre la projection de la valeur theta reele sur
5578 // l'intervalle d'angles authorises)
5579 //
5580 // Pour calculer la contribution en s0, on a besoin de connaitre l'angle de contact en s0
5581 // Au lieu de l'angle reel, on veut connaitre l'angle objectif, cad celui qui
5582 // doit etre atteint (si on est hors equilibbre) pour satisfaire la ligne de contact.
5583
5584 // Pour cela, il faut ici calculer l'angle de contact reel a la paroi et soit :
5585 // 1. il est dans la gamme d'angles de contact souhaitee : C'est alors cet angle qu'on utilise
5586 // pour le calcul de la courbure.
5587 // 2. il n'est pas dans la gamme des angles authorises : Il faut alors rechercher la borne de
5588 // l'intervalle la plus proche de l'angle reel et utiliser celle-ci pour calculer la courbure.
5589 // Dans ce second cas, cela aura pour effet de creer une courbure locale (aux sommets de la ligne de contact)
5590 // qui n'est pas homogene a celle a l'interieure du dom, ce qui va creer un terme source a divergence non nulle
5591 // pour la qdm, qui, via navier stokes va mettre le fluide en mouvement, qui, une fois la vitesse interpolee,
5592 // va deplacer le noeud en paroi dans la bonne direction.
5593 // C'est donc dans le cas 2 une methode tres indirecte d'imposer l'angle de contact.
5594 // Mais qui marche? Voir fiche hysterisis...
5595
5596 const double costheta0 = tab_cos_theta(s0, 0);
5597 const double costheta1 = tab_cos_theta(s0, 1);
5598
5599 // Normale unitaire a la face de bord (vers l'interieur)
5600 double nf0[3] = {0., 0., 0.};
5601 parcours.calculer_normale_face_bord(numface0,
5602 sommets_(s0,0), sommets_(s0,1), sommets_(s0,2),
5603 nf0[0], nf0[1], nf0[2]);
5604
5605 // Calcul du produit scalaire entre la normale au bord et la normale unitaire a la facette
5606 // On a besoin ici de celle orientee vers la vapeur pour etre coherent avec la definition de
5607 // l'angle de contact (qui est pris du cote liquide). Donc il faut -normale dans le ps :
5608 double ps = 0;
5609 for (j = 0; j < dim; j++)
5610 ps -= nf0[j]* normale(facette, j);
5611 // Le produit scalaire entre les deux normales, c'est comme celui entre les 2 tangentes...
5612 // On a donc ps=cos(theta)
5613
5614 // Correction de l'angle de contact (prise en compte de la tangente au cercle
5615 // qui n'est pas rigoureusement donnee par la facette
5616 if ((call> 1) && (correction_contact_courbure_coeff_!=0.))
5617 //correction_costheta(store_courbure_sommets[s0], s0, s0s1, s0s2, ps);
5618 correction_costheta(store_courbure_sommets[s0], s0, facette, ps);
5619
5620 double costheta=0.;
5621 if ((ps-costheta0)*(ps-costheta1) <=0 )
5622 {
5623 // L'angle reel est dans l'intervalle authorise. On l'utilise pour le calcul de la courbure.
5624 costheta = ps;
5625 }
5626 else
5627 {
5628 // L'angle reel est en dehors de l'intervalle. On retient donc la borne de l'intervalle la
5629 // plus proche comme valeur pour utiliser dans le calcul de la courbure.
5630 if (std::fabs(ps-costheta0) <std::fabs(ps-costheta1))
5631 {
5632 // On est proche de la borne costheta0. C'est elle qu'on va utiliser.
5633 costheta = costheta0;
5634 }
5635 else
5636 {
5637 costheta = costheta1;
5638 }
5639 }
5640 {
5641 // Pour remplacer une bonne part du bloc precedent :
5642 const double costheta_bis = calculer_costheta_objectif(s0, facette, call, store_courbure_sommets[s0],
5643 tab_cos_theta, drapeau_angle_in_range);
5644 if (std::fabs(costheta-costheta_bis)>1e-8)
5645 {
5646 Cerr << "Oh oh... les 2 methodes different... " << finl;
5647 Process::exit();
5648 }
5649 }
5650
5651 // On cherche quel type de contact on a (ponctuel ou lineique).
5652 const int numface1 = sommet_face_bord_[s1];
5653 const int numface2 = sommet_face_bord_[s2];
5654
5655#ifdef DEBUG_HYSTERESIS_V2
5656 const int inode = 6 ;
5657// if (facette == 11)
5658 if ( (ii==0) && ((s0 == inode) || (s1 == inode) || (s2 == inode))
5659 && (!(numface1 >= 0 && numface2 >= 0))) /* pour ne pas afficher les facettes avec 3 som bords*/
5660 {
5661 Cerr << "TAG FACETTE "<< facette << " : " << s0 << " " << s1 << " " << s2 << finl;
5662 Cerr << som0 << finl;
5663 Cerr << som1 << finl;
5664 Cerr << som2 << finl;
5665 Cerr << som0 << finl;
5666 }
5667#endif
5668
5669 if (numface1 < 0 && numface2 < 0)
5670 {
5671 // Le contact est ponctuel au sommet s0
5672
5673 // Construction du vecteur tb :
5674 ArrOfDouble v(3), nb(3), tb(3);
5675 // Pour cela, on a besoin d'un segment de la facette (v)
5676 for (j=0; j<dim; j++)
5677 v[j] = som2[j] - som1[j]; // s1s2
5678 // et de la normale au bord (nb):
5679 parcours.calculer_normale_face_bord(numface0,
5680 sommets_(s0,0), sommets_(s0,1), sommets_(s0,2),
5681 nb[0], nb[1], nb[2]);
5682 // pour en deduire le vecteur du plan de la face de bord normale a la facette :
5683 produit_vectoriel(v,nb,tb); // tb non-unitaire
5684 normalize(tb);
5685 // D'apres la rotation, le vecteur ntheta se construit comme :
5686 // (attention, ici, theta est bien l'angle objectif souhaitee en accord avec la CL),
5687 // Hors equilibre, c'est different de l'angle de contact reel.
5688 const double sintheta = sqrt(1.-costheta*costheta);
5689 for (j=0; j<dim; j++)
5690 ntheta[j] = sintheta*tb[j] + costheta*nb[j];
5691
5692 // on cree un miroir de s1 et de s2 par rapport au plan parallel a ntheta et s2s1 et contenant s0.
5693 ArrOfDouble nplan(3); // la normale au plan.
5694
5695 // Seul la direction de nplan compte. Pas son signe ou sa valeur.
5696 parcours.projeter_vecteur_sur_face(numface0,v[0], v[1],v[2]);
5697 produit_vectoriel(ntheta,v,nplan);
5698
5699 ArrOfDouble reflexion_som1(dim),reflexion_som2(dim);
5700 miroir(som1,nplan/* normale_au_plan*/,som0/*pt_du_plan*/, reflexion_som1);
5701 miroir(som2,nplan/* normale_au_plan*/,som0/*pt_du_plan*/, reflexion_som2);
5702
5703 // remise de points dans l'ordre pour que le miroir tourne dans le meme sens...
5704 // Il faut donc utiliser les sommets dans l'ordre inverse pour construire
5705 // la normale de la partie reflechie...
5706 ArrOfDouble s0s2p(3), s0s1p(3), s1ps2p(3);
5707 for (j=0; j<dim; j++)
5708 {
5709 s0s2p[j] = reflexion_som2[j]-som0[j];
5710 s0s1p[j] = reflexion_som1[j]-som0[j];
5711 s1ps2p[j] = reflexion_som2[j]-reflexion_som1[j];
5712 }
5713
5714 // Calcul de la nouvelle normale... (non-unitaire)
5715 produit_vectoriel(s0s2p,s0s1p,nprime);
5716
5717 // Le vecteur de base pour calcul de la surface est :
5718 vect_base=s1ps2p;
5719#ifdef DEBUG_HYSTERESIS_V2
5720 if ( (s0 == inode) || (s1 == inode) || (s2 == inode) )
5721 {
5722 Cerr << "TAG REFLEXION s1s2 FACETTE "<< facette << " : " << s0 << " " << s1 << " " << s2 << finl;
5723 Cerr << som0 << finl;
5724 Cerr << reflexion_som1 << finl;
5725 Cerr << reflexion_som2 << finl;
5726 Cerr << som0 << finl;
5727 }
5728#endif
5729 }
5730 else if (numface1 >= 0 && numface2 >= 0
5731 && !((s0==s1) && (s0==s2)))
5732 {
5733 // les 3 sommets sont sur des bords...
5734 // et la facette n'est pas degeneree (ie 3 sommets identiques...)
5735 Cerr << "Cas de 3 sommets de la facette " << facette
5736 << " (" << s0 << " " << s1 << " " << s2 << " )"
5737 << " sur process "
5738 << Process::me() << " pas prevu pour l'instant!" << finl;
5739 Cerr << "som0 " << som0 << finl;
5740 Cerr << "som1 " << som1 << finl;
5741 Cerr << "som2 " << som2 << finl;
5742 Cerr << "Do nothing instead of exiting... " << finl;
5743 nprime *=0.;
5744 vect_base *=0.;
5745 //Cerr << "Exiting... " << finl;
5746 //Process::exit();
5747 }
5748 else if (numface1 >= 0)
5749 {
5750 // Le segment s0s1 est une ligne de contact:
5751
5752 // Construction du vecteur tb :
5753 ArrOfDouble v(3), nb(3), tb(3);
5754 // Pour cela, on a besoin d'un segment de la facette (v)
5755 for (j=0; j<dim; j++)
5756 v[j] = som0[j] - som1[j]; // s1s0 // Pour des questions d'orientation..
5757 // et de la normale au bord (nb):
5758 parcours.calculer_normale_face_bord(numface0,
5759 sommets_(s0,0), sommets_(s0,1), sommets_(s0,2),
5760 nb[0], nb[1], nb[2]);
5761 {
5762 ArrOfDouble nb1(3);
5763 parcours.calculer_normale_face_bord(numface1,
5764 sommets_(s1,0), sommets_(s1,1), sommets_(s1,2),
5765 nb1[0], nb1[1], nb1[2]);
5766 if (std::fabs(nb[0]*nb1[0]+nb[1]*nb1[1]+nb[2]*nb1[2]-1.) > 0.05)
5767 {
5768 nb+=nb1;
5769 normalize(nb);
5770 Cerr << "Mismatching normals... " << finl;
5771 Cerr << "nb: " << nb[0] << " " << nb[1] << " " << nb[2] << finl;
5772 Cerr << "nb1: " << nb1[0] << " " << nb1[1] << " " << nb1[2] << finl;
5773 Cerr << "Le probleme sera resolu quand on aura conserve les facettes de coins" << finl;
5774 Cerr << "Skipping for the time being instead of exiting" << finl;
5775 //Process::exit();
5776 }
5777
5778 }
5779
5780 // pour en deduire le vecteur du plan de la face de bord normale a la facette :
5781 produit_vectoriel(v,nb,tb); // tb non-unitaire
5782 normalize(tb);
5783 // D'apres la rotation, le vecteur ntheta se construit comme :
5784 // (attention, ici, theta est bien l'angle objectif souhaitee en accord avec la CL,
5785 // Hors equilibre, c'est different de l'angle de contact reel.
5786 const double sintheta = sqrt(1.-costheta*costheta);
5787 for (j=0; j<dim; j++)
5788 ntheta[j] = sintheta*tb[j] + costheta*nb[j];
5789
5790 // on cree un miroir de s2 par rapport au plan parallel a ntheta et s0s1 et contenant s0.
5791 ArrOfDouble nplan(3); // la normale au plan.
5792 produit_vectoriel(s0s1,ntheta,nplan);
5793 ArrOfDouble reflexion_som2(dim);
5794 miroir(som2,nplan/* normale_au_plan*/,som0/*pt_du_plan*/, reflexion_som2);
5795
5796 // remise de points dans l'ordre pour que le miroir tourne dans le meme sens...
5797 // Il faut donc utiliser les sommets dans l'ordre inverse pour la partie reflechie...
5798 ArrOfDouble s0s2p(3), s2ps1(3);
5799 for (j=0; j<dim; j++)
5800 {
5801 s0s2p[j] = reflexion_som2[j]-som0[j];
5802 s2ps1[j] = som1[j]-reflexion_som2[j];
5803 }
5804
5805 // Calcul de la nouvelle normale...(non-unitaire)
5806 produit_vectoriel(s0s2p,s0s1,nprime);
5807
5808 // Le vecteur de base pour calcul de la surface est :
5809 vect_base=s2ps1;
5810#ifdef DEBUG_HYSTERESIS_V2
5811 if ( (s0 == inode) || (s1 == inode) || (s2 == inode) )
5812 {
5813 Cerr << "TAG REFLEXION s0s1 "<< facette << " : " << s0 << " " << s1 << " " << s2 << finl;
5814 Cerr << som0 << finl;
5815 Cerr << som1 << finl;
5816 Cerr << reflexion_som2 << finl;
5817 Cerr << som0 << finl;
5818 }
5819#endif
5820 }
5821 else if (numface2 >= 0)
5822 {
5823 // Le segment s0s2 est une ligne de contact:
5824
5825 // Construction du vecteur tb :
5826 ArrOfDouble v(3), nb(3), tb(3);
5827 // Pour cela, on a besoin d'un segment de la facette (v)
5828 for (j=0; j<dim; j++)
5829 v[j] = som2[j] - som0[j]; // s0s2 // Pour des questions d'orientation..
5830 // et de la normale au bord (nb):
5831 parcours.calculer_normale_face_bord(numface0,
5832 sommets_(s0,0), sommets_(s0,1), sommets_(s0,2),
5833 nb[0], nb[1], nb[2]);
5834 {
5835 ArrOfDouble nb2(3);
5836 parcours.calculer_normale_face_bord(numface2,
5837 sommets_(s1,0), sommets_(s1,1), sommets_(s1,2),
5838 nb2[0], nb2[1], nb2[2]);
5839 if (std::fabs(nb[0]*nb2[0]+nb[1]*nb2[1]+nb[2]*nb2[2]-1.) > 0.05)
5840 {
5841 nb+=nb2;
5842 normalize(nb);
5843 Cerr << "Mismatching normals... " << finl;
5844 Cerr << "nb: " << nb[0] << " " << nb[1] << " " << nb[2] << finl;
5845 Cerr << "nb2: " << nb2[0] << " " << nb2[1] << " " << nb2[2] << finl;
5846 Cerr << "Le probleme sera resolu quand on aura conserve les facettes de coins" << finl;
5847 Cerr << "Skipping for the time being instead of exiting" << finl;
5848 //Process::exit();
5849 }
5850 }
5851
5852 // pour en deduire le vecteur du plan de la face de bord normale a la facette :
5853 produit_vectoriel(v,nb,tb); // tb non-unitaire
5854 normalize(tb);
5855 // D'apres la rotation, le vecteur ntheta se construit comme :
5856 // (attention, ici, theta est bien l'angle objectif souhaitee en accord avec la CL,
5857 // Hors equilibre, c'est different de l'angle de contact reel.
5858 const double sintheta = sqrt(1.-costheta*costheta);
5859 for (j=0; j<dim; j++)
5860 ntheta[j] = sintheta*tb[j] + costheta*nb[j];
5861
5862 // on cree un miroir de s1 par rapport au plan parallel a ntheta et s0s2 et contenant s0.
5863 ArrOfDouble nplan(3); // la normale au plan.
5864 produit_vectoriel(s0s2,ntheta,nplan);
5865 ArrOfDouble reflexion_som1(dim);
5866 miroir(som1,nplan/* normale_au_plan*/,som0/*pt_du_plan*/, reflexion_som1);
5867
5868 // remise de points dans l'ordre pour que le miroir tourne dans le meme sens...
5869 // Il faut donc utiliser les sommets dans l'ordre inverse pour la partie reflechie...
5870 ArrOfDouble s0s1p(3), s2s1p(3);
5871 for (j=0; j<dim; j++)
5872 {
5873 s0s1p[j] = reflexion_som1[j]-som0[j];
5874 s2s1p[j] = reflexion_som1[j]-som2[j];
5875 }
5876
5877 // Calcul de la nouvelle normale...(non-unitaire)
5878 produit_vectoriel(s0s2,s0s1,nprime);
5879
5880 // Le vecteur de base pour calcul de la surface est :
5881 vect_base=s2s1p;
5882#ifdef DEBUG_HYSTERESIS_V2
5883 if ( (s0 == inode) || (s1 == inode) || (s2 == inode) )
5884 //if (facette == 11)
5885 {
5886 Cerr << "TAG REFLEXION s0s2 "<< facette << " : " << s0 << " " << s1 << " " << s2 << finl;
5887 Cerr << som0 << finl;
5888 Cerr << reflexion_som1 << finl;
5889 Cerr << som2 << finl;
5890 Cerr << som0 << finl;
5891 }
5892#endif
5893 }
5894 else
5895 {
5896 Cerr << "Cas impossible... WTF!" << finl;
5897 Process::exit();
5898 }
5899
5900 // Rendre la normale unitaire :
5901 normalize(nprime);
5902
5903 //Calculer contribution du miroir a d_surface +=
5904 d_surface(s0,0) += (vect_base[1] * nprime[2] - vect_base[2] * nprime[1])*0.5;
5905 d_surface(s0,1) += (vect_base[2] * nprime[0] - vect_base[0] * nprime[2])*0.5;
5906 d_surface(s0,2) += (vect_base[0] * nprime[1] - vect_base[1] * nprime[0])*0.5;
5907
5908 //Calculer contribution du miroir a d_volume +=
5909 for (j = 0;
5910 j < dim;
5911 j++)
5912 d_volume(s0, j) += nprime[j] * surface_sur_dim;
5913 }
5914 }
5915#endif
5916#if defined(PATCH_HYSTERESIS_V3)
5919 {
5920 // Traitement des lignes de contact: ajout d'une contribution
5921 // cos(theta) * differentielle de la surface de bord mouillee par
5922 // la phase 0
5923 const int numface1 = sommet_face_bord_[s1];
5924 const int numface2 = sommet_face_bord_[s2];
5925 // Le segment s1s2 est une ligne de contact:
5926 if (numface1 >= 0 && numface2 >= 0)
5927 {
5928 // On prend l'angle de contact au milieu du segment,
5929 // a partir des valeurs cibles de l'angle de contact a chaque sommet.
5930 const double costheta_s1 = calculer_costheta_objectif(s1,facette,call,store_courbure_sommets[s1],
5931 tab_cos_theta, drapeau_angle_in_range);
5932 const double costheta_s2 = calculer_costheta_objectif(s2,facette,call,store_courbure_sommets[s2],
5933 tab_cos_theta, drapeau_angle_in_range);
5934 //Cerr << "Som0 " << s0 << " cos(theta) en s1 " << costheta_s1 << " et s2 " << costheta_s2 << finl;
5935 const double costheta = (costheta_s1+costheta_s2) * 0.5;
5936 // Normale unitaire au bord
5937 double nx, ny, nz;
5938 parcours.calculer_normale_face_bord(numface1,
5939 sommets_(s1,0), sommets_(s1,1), sommets_(s1,2),
5940 nx, ny, nz);
5941 // produit vectoriel s1s2 vectoriel n
5942 d_surface(s1,0) -= (s2s1[1] * nz - s2s1[2] * ny) * costheta * 0.5;
5943 d_surface(s1,1) -= (s2s1[2] * nx - s2s1[0] * nz) * costheta * 0.5;
5944 d_surface(s1,2) -= (s2s1[0] * ny - s2s1[1] * nx) * costheta * 0.5;
5945
5946 parcours.calculer_normale_face_bord(numface2,
5947 sommets_(s2,0), sommets_(s2,1), sommets_(s2,2),
5948 nx, ny, nz);
5949 // produit vectoriel s1s2 vectoriel n
5950 d_surface(s2,0) -= (s2s1[1] * nz - s2s1[2] * ny) * costheta * 0.5;
5951 d_surface(s2,1) -= (s2s1[2] * nx - s2s1[0] * nz) * costheta * 0.5;
5952 d_surface(s2,2) -= (s2s1[0] * ny - s2s1[1] * nx) * costheta * 0.5;
5953 }
5954 }
5955#endif
5957 {
5958 // Traitement des lignes de contact: ajout d'une contribution
5959 // cos(theta) * differentielle de la surface de bord mouillee par
5960 // la phase 0
5961 const int numface1 = sommet_face_bord_[s1];
5962 const int numface2 = sommet_face_bord_[s2];
5963 // Le segment s1s2 est une ligne de contact:
5964 if (numface1 >= 0 && numface2 >= 0)
5965 {
5966 // On prend l'angle de contact au milieu du segment:
5967 const double costheta = (tab_cos_theta(s1, 0) + tab_cos_theta(s2, 0)) * 0.5;
5968 // Normale unitaire au bord
5969 double nx, ny, nz;
5970 parcours.calculer_normale_face_bord(numface1,
5971 sommets_(s1,0), sommets_(s1,1), sommets_(s1,2),
5972 nx, ny, nz);
5973 // produit vectoriel s1s2 vectoriel n
5974 d_surface(s1,0) -= (s2s1[1] * nz - s2s1[2] * ny) * costheta * 0.5;
5975 d_surface(s1,1) -= (s2s1[2] * nx - s2s1[0] * nz) * costheta * 0.5;
5976 d_surface(s1,2) -= (s2s1[0] * ny - s2s1[1] * nx) * costheta * 0.5;
5977
5978 parcours.calculer_normale_face_bord(numface2,
5979 sommets_(s2,0), sommets_(s2,1), sommets_(s2,2),
5980 nx, ny, nz);
5981 // produit vectoriel s1s2 vectoriel n
5982 d_surface(s2,0) -= (s2s1[1] * nz - s2s1[2] * ny) * costheta * 0.5;
5983 d_surface(s2,1) -= (s2s1[2] * nx - s2s1[0] * nz) * costheta * 0.5;
5984 d_surface(s2,2) -= (s2s1[0] * ny - s2s1[1] * nx) * costheta * 0.5;
5985 }
5986 }
5987 }
5988 }
5989 }
5990 else
5991 {
5992 // Case bidim_axi (calculation for a 1radian angle,
5993 // As it is a ratio surface/volume, the angle as no effect.
5994 // Volume differential:
5995
5996 const int s1 = facettes_(facette, 0);
5997 const int s2 = facettes_(facette, 1);
5998 const double r1 = sommets_(s1, 0);
5999 const double y1 = sommets_(s1, 1);
6000 const double r2 = sommets_(s2, 0);
6001 const double y2 = sommets_(s2, 1);
6002 const double L2 = (r2-r1)*(r2-r1) + (y2-y1)*(y2-y1);
6003 const double L = sqrt(L2);
6004 const double nx = normale(facette, 0);
6005 const double ny = normale(facette, 1);
6006 const double dv_dn1 = L * (r1 * un_tiers + r2 * un_sixieme);
6007 const double dv_dn2 = L * (r2 * un_tiers + r1 * un_sixieme);
6008 d_volume(s1, 0) += nx * dv_dn1;
6009 d_volume(s1, 1) += ny * dv_dn1;
6010 d_volume(s2, 0) += nx * dv_dn2;
6011 d_volume(s2, 1) += ny * dv_dn2;
6012 // Differentielle de surface
6013 d_surface(s1, 0) += 0.5 * L + 0.5 * (r1 + r2) * (-ny);
6014 d_surface(s1, 1) += 0.5 * (r1 + r2) * (nx);
6015 d_surface(s2, 0) += 0.5 * L + 0.5 * (r1 + r2) * (ny);
6016 d_surface(s2, 1) += 0.5 * (r1 + r2) * (-nx);
6017
6018 // GB 09/01/2018. Correction to account for the surface differencial
6019 // from the boundary face wetted by phase 0
6020 int som[2];
6021 double r[2];
6022 som[0] = facettes_(facette, 0);
6023 som[1] = facettes_(facette, 1);
6024 r[0] = sommets_(s1, 0);
6025 r[1] = sommets_(s2, 0);
6026 for (int i2 = 0; i2 < 2; i2++)
6027 {
6028 const int face = sommet_face_bord_[som[i2]];
6029 if (face < 0) // pas une face de bord
6030 continue;
6031
6032 double costheta = tab_cos_theta(som[i2], 0);
6033 // Normale unitaire au bord
6034 double nfx = 0.0;
6035 double nfy = 0.0;
6036 double nfz = 0.0;
6037 // if som[i2] est virtuel; the "face=sommet_face_bord_[som[i2]]" are also virtual,
6038 // can not directly used in calculer_normale_face_bord
6039 // because sommet_face_bord_ is not well filled for virtual sommets...
6040 if(sommet_elem_[som[i2]]<0)
6041 {
6042 const Domaine_dis_base& domaine_dis = refdomaine_dis_;
6043 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis);
6044
6045 const Equation_base& eq = equation_transport();
6046 const Domaine_Cl_dis_base& domaine_cl = eq.domaine_Cl_dis();
6047
6048 for (int ii=0; ii<domaine_cl.nb_cond_lim(); ii++)
6049 {
6050
6051 const Frontiere& fr=domaine_cl.les_conditions_limites(ii)->frontiere_dis().frontiere();
6052 const int nb_first_face = fr.num_premiere_face();
6053 const int nb_face = fr.nb_faces();
6054 if(nb_face >1)
6055 {
6056 // coords of first face
6057 const double xf1 =domaine_vf.xv(nb_first_face, 0);
6058 const double yf1 =domaine_vf.xv(nb_first_face, 1);
6059 // coords of last face
6060 const double xf2 =domaine_vf.xv(nb_first_face+nb_face-1, 0);
6061 const double yf2 =domaine_vf.xv(nb_first_face+nb_face-1, 1);
6062 const double xf3 = sommets_(som[i2],0);
6063 const double yf3 =sommets_(som[i2],1);
6064
6065 // check if three points are aligned
6066 // Calculate the determinant (twice the area of the triangle)
6067 const double area = xf1 * (yf2 - yf3) + xf2 * (yf3 - yf1) + xf3 * (yf1 - yf2);
6068
6069 int elem_voisin = domaine_vf.face_voisins(nb_first_face, 0) + domaine_vf.face_voisins(nb_first_face, 1) +1;
6070 const double cell_height = 2.*std::fabs(domaine_vf.dist_face_elem0(nb_first_face,elem_voisin));
6071
6072 if (std::fabs(area) < cell_height*cell_height/2.)
6073 {
6074 parcours.calculer_normale_face_bord(nb_first_face,
6075 sommets_(som[i2],0), sommets_(som[i2],1), 0.,
6076 nfx, nfy, nfz);
6077 break;
6078 }
6079 }
6080 }
6081 }
6082 else
6083 {
6084 parcours.calculer_normale_face_bord(face,
6085 sommets_(som[i2],0), sommets_(som[i2],1), 0.,
6086 nfx, nfy, nfz);
6087
6088 }
6089 // Ajout de la contribution de la surface:
6090 double signe = (i2==0) ? -1. : 1.;
6091 d_surface(som[i2], 0) += r[i2] * signe * nfy * costheta;
6092 d_surface(som[i2], 1) += r[i2] * signe * nfx * costheta;
6093 }
6094 }
6095 }
6096 }
6097
6098 // On a calcule la contribution de chaque facette reelle aux differents sommets.
6099 // Certaines contributions ont ete ajoutees a des sommets virtuels, il
6100 // faut recuperer ces contributions sur le sommet reel.
6103
6104 // Calcul de la courbure :
6105 // d_surface * d_volume / norme(d_volume)^2
6106 double dx[3] = { 0., 0., 0. };
6107#if (defined(PATCH_HYSTERESIS_V2) || defined(PATCH_HYSTERESIS_V3) )
6108 double norm_L2=0.;
6109 double norm_Linf=0.;
6110 int count=0;
6111 int isom_max_courb=-123456;
6112#endif
6113
6114 for (i = 0; i < nsom; i++)
6115 {
6116 double c = 0.;
6117 if (!sommet_virtuel(i))
6118 {
6119#if (defined(PATCH_HYSTERESIS_V2) || defined(PATCH_HYSTERESIS_V3) )
6123 {
6124#endif
6125 // Calcul du vecteur deplacement :
6126 // Si ce n'est pas une ligne de contact, c'est le vecteur normal,
6127 // sinon c'est la projection du vecteur normal sur le bord du domaine.
6128 dx[0] = d_volume(i, 0);
6129 dx[1] = d_volume(i, 1);
6130 if (dim == 3)
6131 dx[2] = d_volume(i, 2);
6132
6133 const int face_bord = sommet_face_bord_[i];
6134 if (face_bord >= 0)
6135 parcours.projeter_vecteur_sur_face(face_bord, dx[0], dx[1], dx[2]);
6136
6137 double ds_dx = 0.;
6138 double dv_dx = 0.;
6139 for (j = 0; j < dim; j++)
6140 {
6141 const double ds = d_surface(i, j);
6142 const double dv = d_volume(i, j);
6143 ds_dx += ds * dx[j];
6144 dv_dx += dv * dx[j];
6145 }
6146 if (dv_dx != 0.)
6147 {
6148 c = - ds_dx / dv_dx;
6149 }
6150#if (defined(PATCH_HYSTERESIS_V2) || defined(PATCH_HYSTERESIS_V3) )
6151 }
6153 {
6154
6155 double ds_dv = 0.;
6156 double dv_dv = 0.;
6157 for (j = 0; j < dim; j++)
6158 {
6159 const double ds = d_surface(i, j);
6160 const double dv = d_volume(i, j);
6161 ds_dv += ds * dv;
6162 dv_dv += dv * dv;
6163 }
6164 if (dv_dv != 0.)
6165 {
6166 c = - ds_dv / dv_dv;
6167 }
6168
6169 }
6170 // Quelle que soit la methode, on print si on a plus d'une passe :
6171 if ((call>1) && (sommet_face_bord_[i]>=0))
6172 {
6173 double delta=std::fabs(courbure_sommets[i] - c);
6174 norm_L2 += delta*delta;
6175 count++;
6176 if (delta>norm_Linf)
6177 {
6178 norm_Linf = delta;
6179 isom_max_courb = i;
6180 }
6181 }
6182#endif
6183 }
6184#if (defined(PATCH_HYSTERESIS_V2) || defined(PATCH_HYSTERESIS_V3) )
6185#else
6186 ArrOfDouble& store_courbure_sommets(courbure_sommets);
6187 ArrOfBit drapeau_angle_in_range(courbure_sommets.size_array());
6188 drapeau_angle_in_range = 1;
6189#endif
6190 courbure_sommets[i] = c;
6192 {
6193 if ((call>1) && (sommet_face_bord_[i]>=0))
6194 //if (call>1)
6195 courbure_sommets[i] = store_courbure_sommets[i];
6196 }
6198 {
6199 if ((call>1) && (sommet_face_bord_[i]>=0))
6200 {
6201 //if (call>1)
6202 const double c_in = store_courbure_sommets[i];
6203 const double c_bord = c;
6204 courbure_sommets[i] = (1-weight_CL_)*c_in+ weight_CL_*c_bord;
6205 }
6206 }
6208 {
6209 if ((call>1) && (sommet_face_bord_[i]>=0))
6210 {
6211 // Au second passage, la courbure des noeuds de la ligne de contact est :
6212 const int contact_angle_inside_range = drapeau_angle_in_range.testsetbit(i);
6213 if (contact_angle_inside_range)
6214 {
6215 // o Soit fournie par une valeur lissee issue de l'interieur du domaine
6216 // si le cos(theta) est dans la gamme autorisee.
6217 // Ainsi, la courbure sera assez reguliere au voisinage de la ligne de contact
6218 // et il n'y aura pas de force generee pour la faire bouger.
6219 const double c_in = store_courbure_sommets[i];
6220 courbure_sommets[i] = c_in;
6221 }
6222 else
6223 {
6224 // o Soit calculee sur le bord avec la valeur limite de cos(theta) la plus proche du domaine authorise
6225 // si l'angle est sur un bord de la gamme.
6226 // Dans ce cas, une inomogeneite de courbure peut conduire a la creation d'un gradient de la
6227 // force de tension de surface et par suite a la mise en mouvement de la ligne de contact.
6228 const double c_bord = c;
6229 courbure_sommets[i] = c_bord;
6230 }
6231 }
6232 }
6233 }
6234#if (defined(PATCH_HYSTERESIS_V2) || defined(PATCH_HYSTERESIS_V3) )
6235 if ((call>1) && ((methode_calcul_courbure_contact_line_ == MIRROR)
6238 {
6239 norm_Linf = mp_max(norm_Linf);
6240 count=mp_sum(count);
6241 if (count>0)
6242 norm_L2=sqrt(mp_sum(norm_L2))/count;
6243 Cerr << "Evaluation de la convergence de la courbure. call= " << call << " norm_Linf= " << norm_Linf
6244 << " norm_L2= " << norm_L2 << " nsom_contact= " << count << finl;
6245 Journal() << "max_courb on " << isom_max_courb << " value " << norm_Linf << finl;
6246 }
6247#endif
6248 desc_sommets().echange_espace_virtuel(courbure_sommets);
6249}
6250
6251/*! @brief Prepare un tableau de donnees aux sommets ou aux facettes pour conserver les valeurs apres transport.
6252 *
6253 * Le transport modifie le descripteur et augmente
6254 * le nombre de sommets ou de facettes. En general les tableaux qui contiennent
6255 * des valeurs aux sommets ou aux facettes ne sont donc plus valables apres
6256 * le transport. On peut les rendre valables comme suit
6257 * (exemple avec le tableau courbure aux sommets) :
6258 * preparer_tableau_avant_transport(courbure, desc_sommets());
6259 * transporter(deplacement);
6260 * update_tableau_apres_transport(courbure, desc_sommets());
6261 * Attention, le tableau ne devient valable qu'apres avoir appele
6262 * update_tableau_apres_transport.
6263 *
6264 */
6266 const Desc_Structure_FT& descripteur) const
6267{
6268 // Preparation de "collecter_espace_virtuel" : on annule la valeur pour tous
6269 // les elements virtuels:
6270 int voisin, i;
6271 const Descripteur_FT& esp_virt = descripteur.espace_virtuel();
6272 const ArrOfInt& liste_pe_voisins = esp_virt.pe_voisins();
6273 const int n_voisins = liste_pe_voisins.size_array();
6274 for (voisin = 0; voisin < n_voisins; voisin++)
6275 {
6276 const int pe_voisin = liste_pe_voisins[voisin];
6277 const ArrOfInt& elements = esp_virt.elements(pe_voisin);
6278 const int n = elements.size_array();
6279 for (i = 0; i < n; i++)
6280 {
6281 const int elem = elements[i];
6282 tableau[elem] = 0.;
6283 }
6284 }
6285}
6287 const Desc_Structure_FT& descripteur) const
6288{
6289 // Preparation de "collecter_espace_virtuel" : on annule la valeur pour tous
6290 // les elements virtuels:
6291 int voisin, i;
6292 const Descripteur_FT& esp_virt = descripteur.espace_virtuel();
6293 const ArrOfInt& liste_pe_voisins = esp_virt.pe_voisins();
6294 const int n_voisins = liste_pe_voisins.size_array();
6295 for (voisin = 0; voisin < n_voisins; voisin++)
6296 {
6297 const int pe_voisin = liste_pe_voisins[voisin];
6298 const ArrOfInt& elements = esp_virt.elements(pe_voisin);
6299 const int n = elements.size_array();
6300 for (i = 0; i < n; i++)
6301 {
6302 const int elem = elements[i];
6303 tableau[elem] = 0;
6304 }
6305 }
6306}
6307
6308/*! @brief Voir preparer_tableau_avant_transport
6309 *
6310 */
6312 const Desc_Structure_FT& descripteur) const
6313{
6314 const int dim = tableau.dimension(1);
6315 int voisin, i, j;
6316 const Descripteur_FT& esp_virt = descripteur.espace_virtuel();
6317 const ArrOfInt& liste_pe_voisins = esp_virt.pe_voisins();
6318 const int n_voisins = liste_pe_voisins.size_array();
6319 for (voisin = 0; voisin < n_voisins; voisin++)
6320 {
6321 const int pe_voisin = liste_pe_voisins[voisin];
6322 const ArrOfInt& elements = esp_virt.elements(pe_voisin);
6323 const int n = elements.size_array();
6324 for (i = 0; i < n; i++)
6325 {
6326 const int elem = elements[i];
6327 for (j = 0; j < dim; j++)
6328 tableau(elem,j) = 0.;
6329 }
6330 }
6331}
6332
6333/*! @brief Voir preparer_tableau_avant_transport
6334 *
6335 */
6337 int new_size,
6338 const Desc_Structure_FT& descripteur) const
6339{
6340 // Le transport des interfaces cree de nouveaux sommets/facettes en fin de tableau.
6341 // On doit donc augmenter la taille du tableau et determiner la valeur
6342 // de ces nouveaux elements.
6343 const int old_size = tableau.size_array();
6344 tableau.resize_array(new_size);
6345 int i;
6346 for (i = old_size; i < new_size; i++)
6347 tableau[i] = 0.;
6348 // Somme sur tous les processeurs de la valeur stockee pour chaque element.
6349 // La valeur est non nulle uniquement sur le processeur qui possedait
6350 // l'element avant le transport (voir preparer_tableau_avant_transport).
6351 // Le nouveau proprietaire recupere ainsi la valeur avant transport.
6353 descripteur.echange_espace_virtuel(tableau);
6354}
6355
6357 int new_size,
6358 const Desc_Structure_FT& descripteur) const
6359{
6360 // Le transport des interfaces cree de nouveaux sommets/facettes en fin de tableau.
6361 // On doit donc augmenter la taille du tableau et determiner la valeur
6362 // de ces nouveaux elements.
6363 const int old_size = tableau.size_array();
6364 tableau.resize_array(new_size);
6365 int i;
6366 for (i = old_size; i < new_size; i++)
6367 tableau[i] = 0;
6368 // Somme sur tous les processeurs de la valeur stockee pour chaque element.
6369 // La valeur est non nulle uniquement sur le processeur qui possedait
6370 // l'element avant le transport (voir preparer_tableau_avant_transport).
6371 // Le nouveau proprietaire recupere ainsi la valeur avant transport.
6373 descripteur.echange_espace_virtuel(tableau);
6374}
6375
6376/*! @brief Voir preparer_tableau_avant_transport
6377 *
6378 */
6380 int new_size,
6381 const Desc_Structure_FT& descripteur) const
6382{
6383 const int old_size = tableau.dimension(0);
6384 const int dim = tableau.dimension(1);
6385 tableau.resize(new_size, dim);
6386 int i, j;
6387 for (i = old_size; i < new_size; i++)
6388 for (j = 0; j < dim; j++)
6389 tableau(i,j) = 0.;
6391 descripteur.echange_espace_virtuel(tableau);
6392}
6393
6399
6401{
6402 return refequation_transport_.valeur();
6403}
6404
6406{
6407 return refequation_transport_.valeur();
6408}
6409
6414
6416{
6417 if (statut_==RESET)
6418 return 0;
6419 else if (statut_==MINIMAL)
6420 return 1;
6421 else if (statut_==PARCOURU)
6422 return 2;
6423 else if (statut_==COMPLET)
6424 return 3;
6425 else
6426 {
6427 Cerr<<"Le type de statut n est pas fixe"<<finl;
6428 Process::exit();
6429 }
6430 return -1;
6431}
6432
6433/*! @brief creation d'un tableau aux sommets du maillage Meme principe que Domaine::creer_tableau_sommets()
6434 *
6435 */
6436void Maillage_FT_Disc::creer_tableau_sommets(Array_base& x, RESIZE_OPTIONS opt) const
6437{
6438 const MD_Vector& md = desc_sommets().get_md_vector();
6440}
6441
6442/*! @brief creation d'un tableau aux sommets du maillage Meme principe que Domaine::creer_tableau_elements()
6443 *
6444 */
6446{
6447 const MD_Vector& md = desc_facettes().get_md_vector();
6449}
6450
6452{
6453 const int nb_fa7=nb_facettes();
6454 gravity_center_fa7_.resize(nb_fa7,dimension);
6455 for (int fa7=0; fa7<nb_fa7; fa7++)
6456 {
6457 int s0 = facettes_(fa7,0);
6458 int s1 = facettes_(fa7,1);
6459 int s2=-1;
6460 double x2=1e15,y2=1e15;
6461 double z0=1e15,z1=1e15,z2=1e15;
6462 if (dimension==3) s2 = facettes_(fa7,2);
6463 double x0 = sommets_(s0,0);
6464 double y0 = sommets_(s0,1);
6465 if (dimension==3) z0 = sommets_(s0,2);
6466 double x1 = sommets_(s1,0);
6467 double y1 = sommets_(s1,1);
6468 if (dimension==3) z1 = sommets_(s1,2);
6469 if (dimension==3) x2 = sommets_(s2,0);
6470 if (dimension==3) y2 = sommets_(s2,1);
6471 if (dimension==3) z2 = sommets_(s2,2);
6472 gravity_center_fa7_(fa7,0)=(x0+x1+x2)/dimension;
6473 gravity_center_fa7_(fa7,1)=(y0+y1+y2)/dimension;
6474 if (dimension==3) gravity_center_fa7_(fa7,2)=(z0+z1+z2)/dimension;
6475 }
6476}
int testsetbit(int_t i) const
Renvoie la valeur du bit e, puis met le bit e a 1.
Definition ArrOfBit.h:85
ArrOfBit_32_64 & resize_array(int_t n)
Change la taille du tableau et copie les donnees existantes.
Definition ArrOfBit.cpp:71
void setbit(int_t i) const
Met le bit e a 1.
Definition ArrOfBit.h:73
void clearbit(int_t i) const
Met le bit e a 0.
Definition ArrOfBit.h:100
Empty class used as a base for all the arrays.
Definition Array_base.h:41
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
virtual DoubleTab & valeurs()=0
classe Champ_front_base Classe de base pour la hierarchie des champs aux frontieres.
virtual void valeurs_face(int, DoubleVect &) const
Renvoie le vecteur des valeurs du champ pour la face donnee.
static int check_enabled()
Definition Comm_Group.h:159
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
virtual Frontiere_dis_base & frontiere_dis()
Renvoie la frontiere discretisee a laquelle les conditions aux limites s'appliquent.
Champ_front_base & champ_front()
classe Cond_lim Classe generique servant a representer n'importe quelle classe
Definition Cond_lim.h:31
static void verifier(const char *const msg, double)
Definition Debog.cpp:21
: class Desc_Structure_FT
void collecter_espace_virtuel(ArrOfDouble &tab, MD_Vector_tools::Operations_echange op) const
void echange_espace_virtuel(ArrOfDouble &tab) const
Descripteur_FT & espace_virtuel()
Renvoie une reference non-const a l'espace virtuel.
const MD_Vector & get_md_vector() const
Descripteur_FT & espace_distant()
Renvoie une reference non-const a l'espace distant.
: class Descripteur_FT Descripteur_FT stocke pour chaque PE une liste de numeros d'elements.
int contient_element(int pe, int element) const
Renvoie "pas zero" si l'element est deja dans le descripteur pour le pe donne, 0 sinon.
void set_elements(int PE_voisin, const ArrOfInt &elements)
Remplace la liste des elements par celle en parametre.
int ajoute_element(int PE_voisin, int element)
Ajoute l'element au tableau du PE_voisin.
const ArrOfInt & elements(int pe_voisin) const
Renvoie la liste des elements distants/virtuels du pe en parametre.
const ArrOfInt & pe_voisins() const
Renvoie la liste des PE pour lesquels la liste d'elements est non vide, dans l'ordre croissant des nu...
void calcul_liste_pe_voisins()
Calcule la liste des PEs dont la liste d'elements est non vide, tries dans l'ordre croissant de numer...
int ajoute_elements(int PE_voisin, const ArrOfInt &elements)
Ajoute l'element au tableau du PE_voisin.
classe Dirichlet_entree_fluide Cette classe represente une condition aux limite imposant une grandeur
Classe Dirichlet_homogene Cette classe est la classe de base de la hierarchie des conditions aux limi...
classe Dirichlet Cette classe est la classe de base de la hierarchie des conditions aux limites de ty...
Definition Dirichlet.h:31
int_t nb_elem_tot() const
Definition Domaine.h:132
SmallArrOfTID_t & chercher_elements(const DoubleTab &pos, SmallArrOfTID_t &elem, int reel=0) const
Recherche des elements contenant les points dont les coordonnees sont specifiees.
Definition Domaine.cpp:405
int_t nb_elem() const
Definition Domaine.h:131
Joints_t & faces_joint()
Definition Domaine.h:265
const IntTab_t & elem_virt_pe_num() const
Definition Domaine.h:365
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
int nb_cond_lim() const
Renvoie le nombre de conditions aux limites.
virtual const Cond_lim & la_cl_de_la_face(int num_face) const
A partir d'un indice de face de bord dans le Domaine_VF, renvoie la condition aux limites a laquelle ...
const Cond_lim_base & condition_limite_de_la_face_reelle(int face_globale, int &face_locale) const
Renvoie la condition limite associee a une face reelle donnee.
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
class Domaine_VF
Definition Domaine_VF.h:44
int nb_faces() const
renvoie le nombre global de faces.
Definition Domaine_VF.h:471
double xv(int num_face, int k) const
Definition Domaine_VF.h:76
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
const IntTab & face_virt_pe_num() const
int face_voisins(int num_face, int i) const
renvoie l'element voisin de numface dans la direction i.
Definition Domaine_VF.h:418
int nb_faces_bord() const
renvoie le nombre de faces sur lesquelles sont appliquees les conditions limites :
Definition Domaine_VF.h:513
virtual double dist_face_elem0(int, int) const
Definition Domaine_VF.h:182
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
const Domaine & domaine() const
static int is_ecriture_special(int &special, int &a_faire)
indique si le format special a ete demande en lecture active par sauvegarde xyz .
static int is_lecture_special()
indique si le format special a ete demande en lecture active par reprise xyz .
classe Ensemble_Lagrange_base Classe de base des classes representant une structure geometrique const...
void remplir_sommets_tmp(DoubleTab &soms_tmp)
virtual int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::in)
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual int get(int *ob, std::streamsize n)
Definition Entree.cpp:222
virtual int eof()
Definition Entree.cpp:256
classe Equation_base Le role d'une equation est le calcul d'un ou plusieurs champs....
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Renvoie le domaine des conditions aux limite discretisee associee a l'equation.
Probleme_base & probleme()
Renvoie le probleme associe a l'equation.
Domaine_dis_base & domaine_dis()
Renvoie le domaine discretise associe a l'equation.
int_t num_premiere_face() const
Definition Frontiere.h:67
int_t nb_faces() const
Renvoie le nombre de faces de la frontiere.
Definition Frontiere.h:59
const Frontiere & frontiere() const
Renvoie la frontiere geometrique associee.
: class Intersections_Elem_Facettes
const ArrOfInt & index_elem() const
Renvoie un tableau de taille domaine.
const Intersections_Elem_Facettes_Data & data_intersection(int index) const
Renvoie les donnees de l'intersection stockee a l'indice "index" dans le tableau "data" ( 0 <= index ...
void get_liste_facettes_traversantes(int num_element, ArrOfInt &liste_facettes) const
int PEvoisin() const
Definition Joint.h:49
static void creer_tableau_distribue(const MD_Vector &, Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
transforme v en un tableau parallele ayant la structure md.
: Cette classe est un OWN_PTR mais l'objet pointe est partage entre plusieurs
Definition MD_Vector.h:48
: class Maillage_FT_Disc Cette classe decrit un maillage:
void creer_tableau_elements(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
creation d'un tableau aux sommets du maillage Meme principe que Domaine::creer_tableau_elements()
Transport_Interfaces_FT_Disc & equation_transport()
void transporter_simple(const DoubleTab &deplacement)
virtual void creer_facettes_virtuelles(const ArrOfInt &liste_facettes, const ArrOfInt &liste_pe, const ArrOfInt &facettes_send_pe_list, const ArrOfInt &facettes_recv_pe_list)
Creation de facettes virtuelles sur le pe specifie.
DoubleTab gravity_center_fa7_
void nettoyer_noeuds_virtuels_et_frontieres()
virtual Entree & lire_param_maillage(Entree &is)
Cette fonction permet de lire les parametres pour le maillage des interfaces.
int get_mesh_tag() const
return mesh_state_tag_
void preparer_tableau_avant_transport(ArrOfDouble &tableau, const Desc_Structure_FT &descripteur) const
Prepare un tableau de donnees aux sommets ou aux facettes pour conserver les valeurs apres transport.
virtual void calculer_costheta_minmax(DoubleTab &costheta) const
Pour chaque sommet du maillage, s'il est sur un bord, on calcule costheta min et max (hysteresis) cor...
const ArrOfInt & sommet_num_owner() const
pour postraitement, renvoie le numero des sommets sur le PE proprietaire des sommets
int methode_calcul_courbure_contact_line_
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,
Sortie & printSom(int som, Sortie &os) const
void corriger_proprietaires_facettes()
Sans changer les sommets existants ni la numerotation des facettes, on change le proprietaire des fac...
void associer_equation_transport(const Equation_base &equation) override
on remplit refequation_transport_, schema_comm_domaine_ desc_sommets_.comm_group_ et desc_facettes_....
void update_tableau_apres_transport(ArrOfDouble &tableau, int nb_elements, const Desc_Structure_FT &descripteur) const
Voir preparer_tableau_avant_transport.
void supprimer_facettes(const ArrOfInt &liste_facettes)
Supprime les facettes dont les indices locaux sont donnes en parametre.
const ArrOfInt & drapeaux_sommets() const
Pour postraitement uniquement : la signification precise des drapeaux est de la cuisine interne a la ...
ArrOfIntFT sommet_PE_owner_
Desc_Structure_FT desc_facettes_
void pre_lissage_courbure(ArrOfDouble &store_courbure_sommets, const int niter) const
virtual const ArrOfDouble & get_surface_facettes() const
virtual double compute_surface_and_normale_element(const int elem, const bool normalize, double surface, double normal[3]) const
void creer_sommets_virtuels(const ArrOfInt &liste_sommets, const ArrOfInt &liste_pe, const Schema_Comm &comm)
Envoi des sommets dont le numero est donne dans liste_sommets au processeur dont le numero est donne ...
virtual int check_sommets(int error_is_fatal=1) const
int nb_facettes() const
renvoie le nombre de facettes (reelles et virtuelles) (egal a facettes().
ArrOfIntFT sommet_face_bord_
int sommet_ligne_contact(int i) const
double correction_contact_courbure_coeff_
ArrOfIntFT facette_num_owner_
int facettes_voisines(int fa70, int fa71, int &iarete0, int &iarete1) const
Cette methode teste si les facettes sont voisines : Des facettes sont voisines si :
int calculer_voisinage_facettes(IntTab &fa7Voisines, const Intersections_Elem_Facettes *ief=nullptr) const
void calcul_courbure_sommets(ArrOfDouble &courbure, const int call_number) const
Calcul de la courbure discrete du maillage aux sommets.
void correction_costheta(const double c, const int s0, const int facette, double ps) const
virtual void nettoyer_maillage()
Retire toutes les facettes virtuelles, toutes les facettes invalides (sommet0 == sommet1) et tous les...
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...
Desc_Structure_FT desc_sommets_
void associer_domaine_dis_parcours(const Domaine_dis_base &domaine_dis, const Parcours_interface &parcours)
const Maillage_FT_Disc & operator=(const Maillage_FT_Disc &)
L'operateur = est interdit !
static int deplacer_un_point(double &x, double &y, double &z, double x1, double y1, double z1, int &element_suivant, int &face_suivante, const Parcours_interface &parcours, const Domaine_VF &domaine_vf, const IntTab &face_voisins, int skip_facettes=0)
int sauvegarder(Sortie &) const override
Sauvegarde d'un Objet_U sur un flot de sortie Methode a surcharger.
int facette_virtuelle(int i) const
Renvoie 0 si la facette m'appartient, 1 sinon.
void calculer_coord_noeuds(const IntTab &def_noeud, const DoubleTab &soms, IntTab &renum)
const Equation_base & equation_associee() const override
double temps() const
return temps_physique_ (temps_physique_ ne sert a rien en interne.
void maillage_modifie(Statut_Maillage nouveau_statut)
Cette methode change le statut du maillage et invalide le cache de valeurs calculees (surface,...
const Desc_Structure_FT & desc_sommets() const
renvoie le descripteur des sommets (espace_distant/virtuel)
void completer_maillage()
Complete les structures de donnees du maillage.
int nb_facettes_totale() const
virtual int check_mesh(int error_is_fatal=1, int skip_facette_owner=0, int skip_facettes=0) const
ArrOfIntFT sommet_num_owner_
virtual void ajouter_maillage(const Maillage_FT_Disc &maillage_tmp, int skip_facettes=0)
double calcul_normale_3D(int num_facette, double norme[3]) const
double changer_temps(double t)
return temps_physique_ = t
void creer_sommets_virtuels_numowner(const ArrOfInt &request_sommets_pe, const ArrOfInt &request_sommets_num)
Cree chez moi les sommets virtuels specifies par le couple (pe,num) si le sommet n'existe pas encore.
int copier_sommet_interne(int som)
virtual const DoubleTab & get_update_normale_facettes() const
Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le re...
void construire_noeuds(IntTab &def_noeud, const DoubleTab &soms)
const ArrOfInt & som_init_util() const
return som_init_util_
virtual double compute_normale_element(const int elem, const bool normalize, ArrOfDouble &normale) const
Schema_Comm schema_comm_domaine_
void convertir_numero_distant_local(const Desc_Structure_FT &descripteur, const ArrOfInt &element_num_owner, const ArrOfInt &numeros_distants, const ArrOfInt &pe_distant, ArrOfInt &numeros_locaux) const
Conversion des couples (numeros_distants, pe) en numeros_locaux.
const Desc_Structure_FT & desc_facettes() const
renvoie le descripteur des facettes (espace_distant/virtuel)
ArrOfIntFT drapeaux_sommets_
Maillage_FT_Disc_Data_Cache & mesh_data_cache() const
renvoie une ref non const au cache de valeurs calculees sur le maillage (courbure,...
void facette_PE_owner(ArrOfInt &facette_pe) const
pour postraitement, remplit le tableau en parametre avec le numero du PE proprietaire de chaque facet...
int calcule_equation_plan_areteFa7(int fa7, int iarete, double &a, double &b, double &c, double &d) const
Intersections_Elem_Facettes intersections_elem_facettes_
void parcourir_maillage()
Remplit la structure intersections_elem_facettes_.
int sommet_virtuel(int i) const
const ArrOfInt & sommet_PE_owner() const
pour postraitement, renvoie le numero du PE proprietaire des sommets
virtual void recopie(const Maillage_FT_Disc &maillage_source, Statut_Maillage niveau_copie)
Recopie une partie du maillage source dans *this.
Maillage_FT_Disc()
constructeur par defaut.
virtual void deplacer_sommets(const ArrOfInt &liste_sommets_initiale, const DoubleTab &deplacement_initial, ArrOfInt &liste_sommets_sortis, ArrOfInt &numero_face_sortie, int skip_facettes=0)
Applique un vecteur deplacement aux noeuds dont le numero est dans "liste_noeud", puis echange les es...
void calcul_indicatrice(DoubleVect &indicatrice, const DoubleVect &indicatrice_precedente) const
Calcul de la fonction indicatrice (on suppose que "indicatrice" a la structure d'un tableau de valeur...
ArrOfIntFT som_init_util_
virtual void transporter(const DoubleTab &deplacement)
Deplace les sommets de l'interface d'un vecteur "deplacement" fourni, Change eventuellement les somme...
void ecrire_plot(const Nom &nom, double temps, int niveau_requete) const
const Intersections_Elem_Facettes & intersections_elem_facettes() const
friend class Parcours_interface
virtual const DoubleTab & get_normale_facettes() const
void nettoyer_elements_virtuels()
Retire toutes les facettes virtuelles et tous les sommets qui ne sont pas utilises.
void calcul_surface_normale(ArrOfDouble &surface, DoubleTab &normale) const
Calcul de la surface et de la normale aux facettes du maillage.
int copier_sommet(int som)
fonction qui cree un nouveau sommet par copie d'une existant utilise dans Remailleur_Collision_FT_Col...
void echanger_sommets_PE(const ArrOfInt &liste_sommets, const ArrOfInt &liste_elem_virtuel_arrivee, const ArrOfInt &liste_face_virtuelle_arrivee, const DoubleTab &deplacement, ArrOfInt &liste_nouveaux_sommets, DoubleTab &deplacement_restant, int skip_facettes=0)
Realise l'ensemble des echanges de noeuds specifies dans liste_sommets, liste_elem_virtuel_arrivee et...
static int deplacer_un_sommet(double &x, double &y, double &z, double x1, double y1, double z1, int &element, int &face_bord, const int num_sommet, const Parcours_interface &parcours, const Domaine_VF &domaine_vf, const IntTab &face_voisins, ArrOfInt &sommets_envoyes, ArrOfInt &element_virtuel_arrivee, ArrOfInt &face_virtuelle_arrivee, DoubleTab &deplacement_restant, int skip_facettes=0)
int reprendre(Entree &) override
Reprise d'un Objet_U sur un flot d'entree Methode a surcharger.
int nb_facettes_reelles() const
Statut_Maillage statut_
virtual const ArrOfDouble & get_update_surface_facettes() const
Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le re...
void nettoyer_phase(const Nom &nom_eq, const int phase)
virtual const ArrOfDouble & get_update_courbure_sommets() const
Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le re...
void reset()
vide toutes les structures du maillage, le statut passe a RESET.
void creer_tableau_sommets(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
creation d'un tableau aux sommets du maillage Meme principe que Domaine::creer_tableau_sommets()
const ArrOfInt & sommet_face_bord() const
pour postraitement, renvoie sommet_face_bord_
Sortie & printFa7(int fa7, int affsom, Sortie &os) const
static double angle_bidim_axi()
renvoie l'angle solide qui sert a calculer les surfaces et les volumes en bidim_axi
int nb_facettes_reelle_totale() const
const IntTab & facettes() const
renvoie le tableau des facettes (reelles et virtuelles) dimension(0) = nombre de facettes,
Vecteur3 coords_fa7(int fa7) const
const bool & get_is_solid_particle() const
const ArrOfInt & sommet_elem() const
pour postraitement, renvoie sommet_elem_
void remplir_structure(const DoubleTab &soms)
double calculer_costheta_objectif(const int som, const int facette, const int call, const double c, const DoubleTabFT &tab_cos_theta, ArrOfBit &drapeau_angle_in_range) const
Un tableau d'objets de la classe Motcle.
Definition Motcle.h:63
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
friend class Entree
Definition Objet_U.h:76
static int dimension
Definition Objet_U.h:99
friend class Sortie
Definition Objet_U.h:75
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 const Nom & nom_du_cas()
Renvoie une reference constante vers le nom du cas.
Definition Objet_U.cpp:146
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
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void dictionnaire(const char *option_name, int value)
Add an (option name, integer value) entry to the dictionary attached to a previously registered integ...
Definition Param.cpp:293
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
int lire_avec_accolades(Entree &is)
Alias of lire_avec_accolades_depuis.
Definition Param.h:577
void calculer_normale_face_bord(int num_face, double x, double y, double z, double &nx_, double &ny_, double &nz_) const
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...
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).
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,...
void parcourir(Maillage_FT_Disc &maillage) const
double distance_sommet_faces(const Domaine_VF &domaine_vf, const int num_element, double x, double y, double z) const
classe Paroi_FT_disc Condition aux limites d'angle de contact pour l'equation
Type_modele get_type_modele() const
const Triple_Line_Model_FT_Disc & tcl() const
classe Probleme_base C'est un Probleme_U qui n'est pas un couplage.
virtual const Equation_base & equation(int) const =0
virtual const Equation_base & get_equation_by_name(const Nom &) const
(B. Math): Methode virtuelle ajoutee pour les problemes ayant plusieurs equations de meme type (Probl...
static int check_int_overflow(trustIdType)
Definition Process.cpp:428
static double mp_max(double)
Definition Process.cpp:376
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 int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
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
Cette classe est a la classe C++ ofstream ce que la classe Sortie est a la classe C++ ostream Elle re...
Definition SFichier.h:27
static void lire_xyz(Maillage_FT_Disc &mesh, const Domaine_VF *domaine_vf, Entree *fichier, const Domaine *domaine_src)
Remplissage du maillage mesh a partir d'un fichier de sauvegarde xyz (fichier) ou d'un domaine source...
static void ecrire_xyz(const Maillage_FT_Disc &mesh, const Domaine_VF &domaine_vf, Sortie &fichier)
void echange_taille_et_messages() const
Cette methode lance l'echange de donnees entre tous les processeurs.
Sortie & send_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y entasser des donnees a envoyer.
void end_comm() const
Vide les buffers et libere les ressources: on a fini de lire les donnees recues dans les buffers.
Entree & recv_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y lire les donnees recues.
const ArrOfInt & get_recv_pe_list() const
void begin_comm() const
Reserve les buffers de comm pour une nouvelle communication.
const ArrOfInt & get_send_pe_list() const
void set_send_recv_pe_list(const ArrOfInt &send_pe_list, const ArrOfInt &recv_pe_list, const int me_to_me=0)
Definit la liste des processeurs a qui on va envoyer et de qui on va recevoir des donnees.
void precision(int pre) override
void setf(IOS_FORMAT code) override
Classe de base des flux de sortie.
Definition Sortie.h:52
ostream & get_ostream()
Definition Sortie.h:64
virtual int put(const unsigned *ob, std::streamsize n, std::streamsize nb_colonnes=1)
Definition Sortie.cpp:101
virtual void precision(int)
Definition Sortie.cpp:40
classe Symetrie Sur les faces de symetrie on a les proprietes suivantes:
Definition Symetrie.h:37
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
void append_line(_TYPE_)
Definition TRUSTTab.tpp:213
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
int line_size() const
Definition TRUSTVect.tpp:67
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")
static int is_PDI_checkpoint()
static int is_PDI_restart()
void nettoyer_proprietes_particules(const ArrOfInt &som_utilises)
virtual const Parcours_interface & parcours_interface() const
const Champ_Inc_base & inconnue() const override
const Probleme_base & get_probleme_base() const
virtual const Champ_base & get_distance_interface() const
double get_theta_app(const int num_face)