TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Marching_Cubes.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 <Marching_Cubes.h>
17#include <TRUST_Deriv.h>
18#include <Marching_Cubes_data.h>
19#include <ArrOfBit.h>
20#include <TRUSTVect.h>
21#include <Domaine_VF.h>
22#include <Domaine.h>
23#include <Rectangle.h>
24#include <Rectangle_2D_axi.h>
25#include <Triangle.h>
26#include <Tetraedre.h>
27#include <Hexaedre.h>
28#include <Parser.h>
29#include <Comm_Group.h>
30#include <communications.h>
31#include <Array_tools.h>
32
33Implemente_instanciable_sans_constructeur(Marching_Cubes,"Marching_Cubes",Objet_U);
34
35
37{
38 Cerr << "Erreur : Marching_Cubes::readOn n'est pas code." << finl;
40 return is;
41}
42
44{
45 Cerr << "Erreur : Marching_Cubes::printOn n'est pas code." << finl;
47 return os;
48}
49
51{
52 const Domaine& domaine = domaine_vf.domaine();
53 ref_domaine_vf_ = domaine_vf;
56}
57
58/*! @brief Construction d'un maillage en segments ou en triangles comme l'isovaleur d'une fonction discretisee aux sommets du maillage eulerien (associer_domaine_vf).
59 *
60 * L'algorithme est un "marching cubes" generalise pour travailler avec un
61 * maillage vf en triangles, rectangles, cubes ou tetraedres.
62 * En cas d'erreur, le maillage est remis a zero (reset()).
63 *
64 * @param (valeurs_sommets) Un vecteur distribue de valeurs aux sommets du maillage vf dont on va construire l'isovaleur. L'espace virtuel doit etre a jour.
65 * @param (isovaleur) L'isovaleur a construire
66 * @param (maillage) L'objet maillage a construire. On efface completement son contenu et on le remplace par l'isovaleur.
67 * @param (indicatrice_approchee) On y stocke 0 si valeurs_sommets[i] < isovaleur pour tous les sommets de la maille et si valeurs_sommets[i] > isovaleur Certaines mailles (traversees par l'interface) ont une valeur differente qu'on ne calcule pas (on met 0.5). Si phase != AJOUTE_TOUTES_PHASES, on suppose que indicatrice_approchee contient une approximation de l'indicatrice des interfaces existantes avant l'entree dans cette fonction (elle doit contenir 0 ou 1 dans les mailles non traversees par une interface, et une valeur intermediaire dans les mailles traversees). Ce tableau est ecrase quoi qu'il arrive (y compris en cas de valeur de retour=0) (faire une copie du tableau avant d'appeler la fonction si on veut revenir en arriere !)
68 * @param (phase) Indique comment mettre a jour indicatrice_approchee. Ce parametre est utilise pour construire une interface en plusieurs etapes (reunion de plusieurs bulles, soustraction d'une phase, ...) phase == AJOUTE_TOUTES_PHASES : la valeur de l'indicatrice approchee est calculee partout phase == 0 : on met a 0 l'indicatrice si valeur<isovaleur, l'indicatrice est inchangee si valeur>isovaleur phase == 1 : on met a 1 l'indicatrice si valeur>isovaleur, l'indicatrice l'indicatrice est inchangee si valeur<isovaleur Valeur de retour: 1: construction reussie. 0: erreur: l'interface qu'on vient de construire entre en collision avec une interface existante (teste base sur la valeur de "indicatrice_approchee" a l'entree de la fonction)
69 */
70int Marching_Cubes::construire_iso(const DoubleVect& valeurs_sommets,
71 double isovaleur,
72 Maillage_FT_Disc& maillage,
73 DoubleVect& indicatrice_approchee,
75 int ignorer_collision) const
76{
77 // Note sur le parallelisme:
78 // La difficulte de l'algorithme consiste a creer un sommet unique aux
79 // sommets des triangles (pour retrouver la connectivite du maillage
80 // qui est ignoree dans la methode de Juric d'origine)
81 // Les sommets du maillage cree se trouvent obligatoirement
82 // sur des aretes du maillage VF, et il y en a au plus un par arete (aretes
83 // sur lesquelles valeurs_sommets-isovaleur change de signe).
84 // Donc un sommet du maillage lagrangien est repere de facon unique par
85 // le couple des sommets de l'arete VF sur laquelle il se trouve
86 // (couples ranges dans le tableau def_noeud).
87 // Dans un premier temps, on cree toutes les facettes de l'isovaleur
88 // et on duplique tous les sommets (on cree 3 sommets par facette).
89 // ("construire_noeuds_et_facettes").
90 // Afin de savoir quels sommets sont sur un bord du domaine, on cree des
91 // sommets supplementaires sur les faces de bord, marques de facon
92 // particuliere ("construire_noeuds_joints").
93 // Puis on va trier tous ces sommets par ordre lexicographique et supprimer
94 // les doublons ("trier_les_noeuds", et "construire_noeuds_uniques")
95 // Or il faut faire le lien logique entre les sommets de joints situes
96 // aux frontieres entre deux processeurs (le noeud i du PE 1 est identique
97 // au noeud j du PE 2) : "correspondance_espaces_distant_virtuel".
98 //
99 // On parcourt aussi les elements virtuels et on cree des sommets
100 // supplementaires marques par le numero du processeur. Apres avoir
101 // trie les sommets, on connait pour chaque sommet les processeurs voisins
102 // qui ont cree le meme sommet.
103 //
104 // Donc pour que l'algorithme fonctionne, il faut que tous les elements
105 // virtuels voisins d'un element reel par une arete soient connus.
106 // Dans la version actuelle, c'est ok: on connait tous les elements voisins
107 // par au moins un sommet.
108
109 if (!ref_domaine_vf_)
110 {
111 Cerr << "Marching_Cubes::construire_iso : Erreur :" << finl;
112 Cerr << " Aucun domaine n'a ete associe a Marching_Cubes" << finl;
113 assert(0);
115 }
116
117 ArrOfBit signe; // Taille : nombre de sommets euleriens
118 // Estimation de la taille necessaire du tableau
119 // Jusqu'a "construire_noeuds_uniques" la signification de def_noeud
120 // est la suivante:
121 // def_noeud(i,0) = numero du premier sommet du segment qui porte le noeud
122 // def_noeud(i,1) = numero du deuxieme sommet
123 // (les sommets sont tries: def_noeud(i,1) > def_noeud(i,0))
124 // Pour un sommet interne (construit a partir d'un element reel)
125 // def_noeud(i,2) = me()
126 // def_noeud(i,3) = i
127 // def_noeud(i,4) = numero de l'element qui a servi a construire le noeud
128 // Pour un sommet sur une face de joint avec PE_voisin
129 // def_noeud(i,2) = PE_voisin
130 // def_noeud(i,3) = i
131 // def_noeud(i,4) = -1
132 // Pour un sommet sur une face de bord
133 // def_noeud(i,2) = nproc()
134 // def_noeud(i,3) = i
135 // def_noeud(i,4) = numero de la face de bord dans le domaine
136 // Un meme sommet (ie, meme segment) peut figurer plusieurs fois comme sommet
137 // interne, sommet de bord et/ou sommet de joint.
138 IntTab def_noeud;
139 def_noeud.resize(last_def_noeud_size * 2, 4, RESIZE_OPTIONS::NOCOPY_NOINIT);
140
141 maillage.reset();
142
143 IntTab& facettes = maillage.facettes_;
144 DoubleTab& coord_noeuds = maillage.sommets_;
145
146 calculer_signe(valeurs_sommets, isovaleur, signe);
147
148 const int resultat_ok = construire_noeuds_et_facettes(signe, def_noeud, facettes,
149 indicatrice_approchee, phase);
150
151 if (resultat_ok || ignorer_collision)
152 {
153 construire_noeuds_joints(signe, def_noeud);
154
155 trier_les_noeuds(def_noeud);
156
157 construire_noeuds_uniques(def_noeud, maillage);
158 // Ici def_noeud a change de definition:
159 // def_noeud(i,0) = numero du premier sommet du segment qui porte le noeud
160 // def_noeud(i,1) = numero du deuxieme sommet
161 // (les sommets sont tries: def_noeud(i,1) > def_noeud(i,0))
162 // def_noeud(i,2) = PE proprietaire du noeud pour les noeuds crees en parcourant
163 // les elements du domaine.
164 // Si le noeud est un duplicata cree sur les faces de bord,
165 // alors def_noeud(i,2) == nb_procs.
166 // def_noeud(i,3) = numero de l'element (-1 si noeud virtuel)
167 // def_noeud(i,4) = numero de la face de bord (-1 si noeud virtuel)
168
170
171 calculer_coord_noeuds(valeurs_sommets, isovaleur,
172 def_noeud, maillage);
173
174 {
175 int nb_sommets = maillage.sommets_.dimension(0);
176 maillage.sommet_PE_owner_. resize_array(nb_sommets);
177 maillage.sommet_num_owner_.resize_array(nb_sommets);
178 maillage.sommet_elem_. resize_array(nb_sommets);
179 maillage.sommet_face_bord_.resize_array(nb_sommets);
180 maillage.drapeaux_sommets_.resize_array(nb_sommets);
181
183 // Le descripteur des facettes est vide, mais on calcule quand meme
184 // le schema de comm pour qu'il soit valide
188
189 const int moi = Process::me();
190
191 for (int i = 0; i < nb_sommets; i++)
192 {
193 maillage.sommet_num_owner_[i] = i;
194 const int pe_owner = maillage.sommet_PE_owner_[i];
195 const int elem = (pe_owner == moi) ? def_noeud(i, 3) : -1;
196 const int face = def_noeud(i, 4);
197 maillage.sommet_elem_[i] = elem;
198 maillage.sommet_face_bord_[i] = face;
199 maillage.drapeaux_sommets_[i] = 0;
200 }
203 }
204
205 // il faut mettre le statut minimal pour corriger_proprietaire_facettes
208
209 // On conserve la taille du tableau temporaire pour la prochaine execution.
210 last_def_noeud_size = def_noeud.dimension(0);
211
212 Journal() << "Marching_Cubes::construire_iso" << finl;
213 Journal() << " " << facettes.dimension(0) << " facettes, ";
214 Journal() << coord_noeuds.dimension(0) << " noeuds, ";
215
217 }
218 else
219 {
220 Journal() << "Marching_Cubes::construire_iso erreur: collision avec une interface existante" << finl;
221 maillage.reset();
222 }
223 return resultat_ok;
224}
225
226// Construction d'une interface comme l'isovaleur zero d'une fonction
227// dont l'expression est donnee en parametre. L'expression est evaluee
228// aux sommets du maillage eulerien et l'interface est construite par
229// l'algorithme des marching cubes.
230// Le maillage est reinitialise au debut de l'operation.
231//
232// Parametre: expression
233// Signification: une expression mathematique f(x,y,z) comprise par le parser
234// exemple : "x+2*y+z*z"
235// Parametre: isovaleur
236// Signification: on va construire le maillage de la surface definie par
237// f(x,y,z)=isovaleur
238// Parametre: maillage
239// Signification: l'objet Maillage dans lequel on va stocker le resultat
240// Parametre: indicatrice_approchee
241// Signification: voir Marching_Cubes::construire_iso
242// Parametre: phase
243// Signification: voir Marching_Cubes::construire_iso
244// Parametre: eval_expression_sommets
245// Signification: un tableau a une dimension de taille nb_sommets (euleriens),
246// et dont les items communs sont correctement initialises
247// pour pouvoir faire un echange_espace_virtuel de valeurs aux
248// sommets.
249// Valeur de retour: voir Marching_Cubes::construire_iso
250int Marching_Cubes::construire_iso(const Nom& expression, double isovaleur,
251 Maillage_FT_Disc& maillage,
252 DoubleVect& indicatrice_approchee,
254 DoubleTab& eval_expression_sommets,
255 int ignorer_collision) const
256{
257 const int dimension3 = (dimension == 3);
258
259 if (!ref_domaine_vf_)
260 {
261 Cerr << "Marching_Cubes::construire_iso : Erreur :" << finl;
262 Cerr << " Aucun domaine n'a ete associe a Marching_Cubes" << finl;
263 assert(0);
265 }
266
267 std::string expr_chaine(expression);
268 Parser parser(expr_chaine, dimension);
269 parser.addVar("x");
270 parser.addVar("y");
271 if (dimension3)
272 parser.addVar("z");
273 parser.parseString();
274
275 // Construction d'un tableau de valeurs aux sommets euleriens
276 const Domaine& domaine = ref_domaine_vf_->domaine();
277 const int nb_sommets = domaine.nb_som();
278
279 for (int i = 0; i < nb_sommets; i++)
280 {
281 double x, y, z = 0.;
282 x = domaine.coord(i, 0);
283 y = domaine.coord(i, 1);
284 if (dimension3)
285 z = domaine.coord(i, 2);
286 parser.setVar("x", x);
287 parser.setVar("y", y);
288 if (dimension3)
289 parser.setVar("z", z);
290 double valeur = parser.eval();
291 eval_expression_sommets(i) = valeur;
292 }
293 eval_expression_sommets.echange_espace_virtuel();
294
295 // Construction de l'interface
296 const int ok = construire_iso(eval_expression_sommets, isovaleur, maillage, indicatrice_approchee, phase,
297 ignorer_collision);
298 // l'appel a maillage_modifie() est fait dans construire_iso(valeurs_sommets, ...)
299 return ok;
300}
301
302// **********************************************************************
303// Methodes protegees
304
305// Structures de donnees de l'algorithme marching cubes
306// (en gros, description des facettes a creer en fonction
307// du type d'element eulerien et du signe de la fonction aux
308// sommets de l'element, voir Marching_Cubes_data.h).
310{
311 // Detection du type d'element eulerien
312 const Elem_geom_base& elem_geom = domaine.type_elem().valeur();
313
314 const int (*def_aretes)[2]=0; // Pointeur sur un tableau de 2 entiers
315 const int (*def_aretes_faces)[2]=0;
316 const int *nb_facettes=0;
317 const int *facettes=0;
318
319 int nb_cas_marching_cubes=0;
320
321 // Selection des tableaux a copier...
322 // Pour ajouter de nouveaux elements euleriens, il "suffit" d'ajouter
323 // un test if ci-dessous et de definir les tableaux mcubes_*
324 // dans Marching_Cubes_data.h
325 if (sub_type(Rectangle, elem_geom))
326 {
327
330 nb_aretes_faces = 1;
333 nb_cas_marching_cubes = 16;
334
335 def_aretes = mcubes_def_aretes_vdf_2d;
336 def_aretes_faces = mcubes_def_aretes_faces_vdf_2d;
337 nb_facettes = mcubes_nb_facettes_vdf_2d;
338 facettes = mcubes_facettes_vdf_2d;
339
340 }
341 else if (sub_type(Triangle, elem_geom))
342 {
343
346 nb_aretes_faces = 1;
349 nb_cas_marching_cubes = 8;
350
351 def_aretes = mcubes_def_aretes_vef_2d;
352 def_aretes_faces = mcubes_def_aretes_faces_vef_2d;
353 nb_facettes = mcubes_nb_facettes_vef_2d;
354 facettes = mcubes_facettes_vef_2d;
355
356 }
357 else if (sub_type(Tetraedre, elem_geom))
358 {
359
362 nb_aretes_faces = 3;
365 nb_cas_marching_cubes = 16;
366
367 def_aretes = mcubes_def_aretes_vef_3d;
368 def_aretes_faces = mcubes_def_aretes_faces_vef_3d;
369 nb_facettes = mcubes_nb_facettes_vef_3d;
370 facettes = mcubes_facettes_vef_3d;
371
372 }
373 else if (sub_type(Hexaedre, elem_geom))
374 {
375
378 nb_aretes_faces = 4;
381 nb_cas_marching_cubes = 256;
382
383 def_aretes = mcubes_def_aretes_vdf_3d;
384 def_aretes_faces = mcubes_def_aretes_faces_vdf_3d;
385 nb_facettes = mcubes_nb_facettes_vdf_3d;
386 facettes = mcubes_facettes_vdf_3d;
387
388 }
389 else
390 {
391 Cerr << "Erreur dans Marching_Cubes::remplir_data_marching_cubes :" << finl;
392 Cerr << " l'element geometrique " << elem_geom.que_suis_je();
393 Cerr << " n'est pas pris en charge." << finl;
395 }
396
397 int i;
398
399 // Creation des tables de donnees
400 // Definition des aretes de l'element geometrique eulerien
402 for (i = 0; i < nb_aretes_element; i++)
403 {
404 mcubes_def_aretes(i, 0) = def_aretes[i][0];
405 mcubes_def_aretes(i, 1) = def_aretes[i][1];
406 }
407 // Definition des aretes d'une face de l'element geometrique
409 for (i = 0; i < nb_aretes_faces; i++)
410 {
411 mcubes_def_aretes_faces(i, 0) = def_aretes_faces[i][0];
412 mcubes_def_aretes_faces(i, 1) = def_aretes_faces[i][1];
413 }
414
415 // Remplissage de l'index des facettes
416 mcubes_index_facettes.resize_array(nb_cas_marching_cubes + 1);
417 mcubes_nb_facettes.resize_array(nb_cas_marching_cubes);
418 int index = 0;
419 for (i = 0; i < nb_cas_marching_cubes ; i++)
420 {
421 mcubes_index_facettes[i] = index;
422 int n = nb_facettes[i];
423 mcubes_nb_facettes[i] = n;
424 index += n * nb_sommets_facette;
425 }
426 mcubes_index_facettes[i] = index;
427
428 // Remplissage du tableau de description des facettes dans les
429 // differents cas marching_cubes
430 mcubes_facettes.resize_array(index);
431 for (i = 0; i < index; i++)
432 mcubes_facettes[i] = facettes[i];
433 assert(facettes[i] == -1); // Signature de fin de tableau...
434}
435
436// Pour chaque joint, on construit un tableau de correspondance :
437// Pour i=0..nombre de sommets de joint,
438// renum_virt_loc(joint)(i,0) = numero distant d'un sommet eulerien de joint
439// renum_virt_loc(joint)(i,1) = numero local du meme sommet
440// La difference avec le tableau dans Joint est la suivante:
441// Propriete : le tableau est trie par ordre croissant des numeros distants
442// (pour recherche binaire rapide dans renum_sommets_dist_loc).
443void Marching_Cubes::remplir_renum_virt_loc(const Domaine& domaine)
444{
445 const int nb_joints = domaine.nb_joints();
446 renum_virt_loc_.dimensionner(nb_joints);
447 indice_joint_.resize_array(nproc());
448 indice_joint_ = -1;
449
450 for (int num_joint = 0; num_joint < nb_joints; num_joint++)
451 {
452
453 // renum_unsorted contient :
454 // renum_unsorted(i,0) = numero de sommet sur le PE voisin
455 // renum_unsorted(i,1) = numero local du sommet
456
457 const Joint& joint = domaine.joint(num_joint);
458 const IntTab& renum_unsorted = joint.renum_virt_loc();
459 IntTab& renum_sorted = renum_virt_loc_[num_joint];
460 const int nb_sommets_joint = renum_unsorted.dimension(0);
461
462 // On copie le tableau, puis on le trie par ordre croissant
463 // de la premiere colonne.
464 renum_sorted = renum_unsorted;
465 assert(renum_sorted.dimension_tot(1) == 2);
466 using pair = std::array<int, 2>;
467 pair* ptr = reinterpret_cast<pair*>(renum_sorted.addr());
468 std::sort(ptr, ptr+nb_sommets_joint, [&](const pair& p1, const pair& p2)
469 {
470 return (p1[0]<p2[0]);
471 });
472
473 const int PE_voisin = joint.PEvoisin();
474 indice_joint_[PE_voisin] = num_joint;
475 }
476}
477
478// Cette fonction convertit les numeros de sommets euleriens distants stockes
479// dans le tableau en numeros locaux. Les numeros doivent correspondre
480// a des sommets du joint avec le pe_voisin.
481// entree : num_sommet contient des numeros de sommets euleriens du joint
482// avec le pe_voisin. Ce sont les numeros des sommets sur le pe_voisin
483// sortie : on remplace les numeros distants par les numeros locaux.
484// Comportement indefini si le sommet n'est pas dans le joint.
485
487 ArrOfInt& num_sommets) const
488{
489 // Recherche de l'indice du joint avec pe_voisin
490 const int indice_joint = indice_joint_[pe_voisin];
491 assert(indice_joint >= 0);
492 // Tableau de correspondance numero distant-numero local
493 const IntTab& renum_virt_loc = renum_virt_loc_[indice_joint];
494 const int dernier_sommet_joint = renum_virt_loc.dimension(0) - 1;
495 const int nb_sommets = num_sommets.size_array();
496
497 for(int i = 0; i < nb_sommets; i++)
498 {
499 const int numero_distant = num_sommets[i];
500 // Recherche binaire du sommet dans renum_virt_loc
501 int min = 0;
502 int max = dernier_sommet_joint;
503 int valeur = -1;
504 int milieu;
505 while (min < max)
506 {
507 milieu = (min + max) >> 1; // (min + max) / 2
508 valeur = renum_virt_loc(milieu, 0);
509 if (numero_distant > valeur)
510 min = milieu + 1;
511 else if (numero_distant < valeur)
512 max = milieu - 1;
513 else
514 min = max = milieu;
515 }
516 // Teste si le sommet a ete trouve
517 assert(renum_virt_loc(min, 0) == numero_distant);
518 const int numero_local = renum_virt_loc(min, 1);
519 num_sommets[i] = numero_local;
520 }
521}
522
523// #########################################################################
524// Premiere etape : determination du signe de la fonction (valeur-isovaleur)
525// en chaque sommet (reel)
526// Complexite : N (N=nombre de sommets du maillage eulerien)
527
528void Marching_Cubes::calculer_signe(const DoubleVect& valeurs_sommets,
529 const double isovaleur,
530 ArrOfBit& signe) const
531{
532 int i;
533
534 const int nb_sommets = ref_domaine_vf_->nb_som();
535 assert(valeurs_sommets.size() == nb_sommets);
536 signe.resize_array(nb_sommets);
537 signe = 0;
538 // signe vaut 1 si valeur - isovaleur > 0, 0 sinon.
539 for(i = 0; i < nb_sommets; i++)
540 if (valeurs_sommets[i] - isovaleur > 0.)
541 signe.setbit(i);
542}
543
544// #########################################################################
545// Deuxieme etape : Parcours des elements reels, construction des facettes et
546// des noeuds de l'isovaleur. Les noeuds sont situes sur des aretes du maillage
547// eulerien et caracterises par les numeros des deux sommets de l'arete.
548// Les noeuds sont dupliques (pour chaque arete,
549// il y a autant de noeuds identiques que d'elements voisins de l'arete).
550// Complexite : N (N=nombre d'elements du maillage eulerien)
551// Valeur de retour: 1=>construction reussie
552// 0=>Rate:l'interface qui vient d'etre creee entre en collision avec une
553// interface existante. def_noeud et facettes est tout de meme rempli
554// et indicatrice_approchee mis a jour (il faut donc en creer une copie
555// avant d'appeler cette methode pour restaurer la valeur initiale en cas
556// de probleme).
558 IntTab& def_noeud,
559 IntTab& facettes,
560 DoubleVect& indicatrice_approchee,
561 const Maillage_FT_Disc::AjoutPhase phase) const
562{
563 int resultat_ok = 1; // Valeur de retour de la fonction
564 int arete, elem, sommet;
565
566 const Domaine& domaine = ref_domaine_vf_->domaine();
567 // Pour chaque element virtuel, numero du PE proprietaire :
568 const IntTab& elem_virt_pe_num = domaine.elem_virt_pe_num();
569 // Raccourci vers les numeros des sommets des elements
570 const IntTab& elem_sommets = domaine.les_elems();
571 const int nb_elements_reels = domaine.nb_elem();
572 const int nb_elem_tot = domaine.nb_elem_tot();
573 const int nb_sommets_reels = domaine.nb_som();
574 // Mon numero de PE
575 const int mon_PE = Process::me();
576
577 // Tableaux de travail :
578 // Numero attribue au noeud cree sur l'arete i de l'element
579 // On initialise a -1 pour assert...
580 ArrOfInt numero_noeud_arete(nb_aretes_element);
581 numero_noeud_arete = -1;
582 // Numero de chaque sommet de l'element en cours de traitement
583 ArrOfInt numero_sommet(nb_sommets_element);
584 // Signe de la fonction sur chaque sommet de l'element
585 ArrOfInt signe_sommet(nb_sommets_element);
586
587 def_noeud.resize(0, 4);
588 facettes.resize(0, nb_sommets_facette);
589 int nb_facettes = 0;
590 int nb_noeuds = 0;
591 const int numero_dernier_cas = (1 << nb_sommets_element) - 1;
592
593 // Boucle sur les elements du maillage.
594 // Pour les elements reels, on cree des noeuds sur les aretes et on
595 // cree les faces.
596 // Pour les elements virtuels, on cree seulement les noeuds sur les
597 // aretes reelles, et on enregistre ces noeuds comme appartenant
598 // au processeur voisin.
599
600 for (elem = 0; elem < nb_elem_tot; elem++)
601 {
602
603 int cas_marching_cubes = 0;
604 int facteur = 1;
605 // On recupere les numeros des sommets et le signe en local
606 for (sommet = 0; sommet < nb_sommets_element; sommet++)
607 {
608 const int n = elem_sommets(elem, sommet);
609 numero_sommet[sommet] = n;
610 int s;
611 if (n < nb_sommets_reels) /* Est-ce un sommet reel ? */
612 {
613 s = signe[n];
614 // Calcul du numero du "cas marching_cubes"
615 // C'est une suite de bits 0 ou 1 selon le signe de la fonction
616 cas_marching_cubes += s * facteur;
617 facteur *= 2;
618 }
619 else
620 {
621 // facteur negatif => le cas marching_cubes sera negatif a la fin.
622 cas_marching_cubes = -1;
623 facteur = -1;
624 s = -1;
625 }
626 signe_sommet[sommet] = s;
627 }
628
629 if (elem < nb_elements_reels)
630 {
631 assert(cas_marching_cubes >= 0);
632 double indic;
633 if (cas_marching_cubes == 0)
634 indic = 0.;
635 else if (cas_marching_cubes == numero_dernier_cas)
636 indic = 1.;
637 else
638 indic = 0.5;
639
641 {
642 // On ecrase toutes les interfaces existantes (ce n'est pas un ajout d'une interface)
643 indicatrice_approchee[elem] = indic;
644 }
645 else
646 {
647 // PL: clang :error: arithmetic between floating-point type 'double' and enumeration type 'const Maillage_FT_Disc::AjoutPhase' is deprecated [-Werror,-Wdeprecated-enum-float-conversion]
648 if (indic == (1. - (double)phase))
649 {
650 // Ne rien faire
651 }
652 else if (indicatrice_approchee[elem] != (1. - (double)phase))
653 {
654 // Collision !
655 resultat_ok = 0;
656 }
657 else
658 {
659 // Je mets une nouvelle interface
660 indicatrice_approchee[elem] = indic;
661 }
662 }
663 }
664 else
665 {
666 cas_marching_cubes = -1;
667 }
668
669 // Early quit : si l'element ne contient pas de facette, c'est a dire
670 // si tous les sommets ont le meme signe, on se casse
671 if (cas_marching_cubes == 0 || cas_marching_cubes == numero_dernier_cas)
672 continue;
673
674 int numero_element_a_stocker = elem;
675 int PE_element = mon_PE;
676 if (elem >= nb_elements_reels)
677 {
678 // C'est un element virtuel
679 numero_element_a_stocker = -1;
680 PE_element = elem_virt_pe_num(elem - nb_elements_reels,
681 0 /* colonne 0=numero du PE */);
682 }
683
684 // Creation des noeuds sur les segments de l'element dont les sommets
685 // sont reels et de signe different.
686
687 // (Idee pour ameliorer : precalculer la liste des noeuds a creer
688 // en fonction du cas marching cubes comme pour les facettes)
689 // Boucle sur les aretes de l'element, creation des noeuds
690 for (arete = 0; arete < nb_aretes_element; arete++)
691 {
692 numero_noeud_arete[arete] = -1;
693 const int s1 = mcubes_def_aretes(arete, 0);
694 const int s2 = mcubes_def_aretes(arete, 1);
695 const int signe1 = signe_sommet[s1];
696 const int signe2 = signe_sommet[s2];
697 // Si on est sur une arete virtuelle (un des deux sommets est virtuel)
698 // alors on n'ajoute pas de sommet
699 // Un noeud est present si la fonction change de signe
700 if (signe1 != signe2 && signe1 >= 0 && signe2 >= 0)
701 {
702 numero_noeud_arete[arete] = nb_noeuds;
703 int n1 = numero_sommet[s1];
704 int n2 = numero_sommet[s2];
705 if (n1 > n2)
706 {
707 int n = n1;
708 n1 = n2;
709 n2 = n;
710 }
711 // Le noeud est caracterise par les numeros des deux sommets
712 // de l'arete qui le porte.
713 def_noeud.resize(nb_noeuds+1, 5);
714 def_noeud(nb_noeuds, 0) = n1;
715 def_noeud(nb_noeuds, 1) = n2;
716 def_noeud(nb_noeuds, 2) = PE_element;
717 def_noeud(nb_noeuds, 3) = nb_noeuds;
718 def_noeud(nb_noeuds, 4) = numero_element_a_stocker;
719 nb_noeuds++;
720 }
721 }
722
723 // Creation des facettes si l'element est reel :
724 if (elem < nb_elements_reels)
725 {
726 // Index dans le tableau de description des facettes a creer
727 int index = mcubes_index_facettes[cas_marching_cubes];
728 const int index_fin = mcubes_index_facettes[cas_marching_cubes+1];
729 const int newsize = nb_facettes + mcubes_nb_facettes[cas_marching_cubes];
730 facettes.resize(newsize, nb_sommets_facette);
731
732 const int dim = Objet_U::dimension;
733
734 for (; index < index_fin; index += nb_sommets_facette)
735 {
736 int j;
737 for (j = 0; j < dim; j++)
738 {
739 const int larete = mcubes_facettes[index+j];
740 const int numero_noeud = numero_noeud_arete[larete];
741 assert(numero_noeud >= 0);
742 facettes(nb_facettes, j) = numero_noeud;
743 }
744 nb_facettes++;
745 }
746 }
747 }
748 // S'il y a une erreur sur un processeur, tout le monde renvoie 0
749 resultat_ok = Process::mp_min(resultat_ok);
750 return resultat_ok;
751}
752
753/*! @brief Ajout des sommets situes sur des faces (bords ou joints) dans le tableau def_noeud.
754 *
755 * Soit faces_sommets est une liste de faces d'un joint, dans ce cas, numero_PE
756 * est le PE_voisin du joint.
757 * Soit faces_sommets est la liste des faces du domaine et nb_faces_a_traiter
758 * est le nombre de faces de bord. Dans ce cas, numero_PE = nproc().
759 *
760 */
762 const IntTab& faces_sommets,
763 const int nb_faces_a_traiter,
764 const int numero_PE,
765 IntTab& def_noeud) const
766{
767 // ATTENTION : static : il faut resizer explicitement au cas ou la
768 // classe est utilisee avec des discretisations differentes.
769 // Numero attribue au noeud cree sur l'arete i de la face
770 // On initialise a -1 pour assert...
771 static ArrOfInt numero_noeud_arete;
772 numero_noeud_arete.resize_array(nb_aretes_element);
773 numero_noeud_arete = -1;
774 // Numero de chaque sommet de la face
775 static ArrOfInt numero_sommet;
776 numero_sommet.resize_array(nb_sommets_par_face);
777 // Signe de la fonction sur chaque sommet de la face
778 static ArrOfInt signe_sommet;
779 signe_sommet.resize_array(nb_sommets_par_face);
780
781 const int nb_procs = Process::nproc();
782
783 for (int face = 0; face < nb_faces_a_traiter; face++)
784 {
785
786 int somme_signe = 0;
787 for (int sommet = 0; sommet < nb_sommets_par_face; sommet++)
788 {
789 const int n = faces_sommets(face, sommet);
790 const int s = signe[n];
791 numero_sommet[sommet] = n;
792 signe_sommet[sommet] = s;
793 somme_signe += s;
794 }
795
796 // Si tous les sommets ont le meme signe, on arrete pour cette face
797 if (somme_signe == 0 || somme_signe == nb_sommets_par_face)
798 continue;
799
800 // Boucle sur les aretes, creation des noeuds
801
802 for (int arete = 0; arete < nb_aretes_faces; arete++)
803 {
804 const int s1 = mcubes_def_aretes_faces(arete, 0);
805 const int s2 = mcubes_def_aretes_faces(arete, 1);
806 const int signe1 = signe_sommet[s1];
807 const int signe2 = signe_sommet[s2];
808 if (signe1 != signe2)
809 {
810 const int nb_noeuds = def_noeud.dimension(0);
811 numero_noeud_arete[arete] = nb_noeuds;
812 int n1 = numero_sommet[s1];
813 int n2 = numero_sommet[s2];
814 if (n1 > n2)
815 {
816 int n = n1;
817 n1 = n2;
818 n2 = n;
819 }
820 // Le noeud est caracterise par les numeros des deux sommets
821 // de l'arete qui le porte, le premier numero etant tjs le + petit.
822 def_noeud.resize(nb_noeuds+1, 5);
823 def_noeud(nb_noeuds, 0) = n1;
824 def_noeud(nb_noeuds, 1) = n2;
825 def_noeud(nb_noeuds, 2) = numero_PE;
826 def_noeud(nb_noeuds, 3) = nb_noeuds;
827 if (numero_PE == nb_procs)
828 // On balaie les faces de bord
829 def_noeud(nb_noeuds, 4) = face;
830 else
831 // On balaie les faces de joint
832 def_noeud(nb_noeuds, 4) = -1;
833 }
834 } // Fin de la boucle sur les aretes
835 } // Fin de la boucle sur les faces
836}
837
839 IntTab& def_noeud) const
840{
841 const Domaine_VF& domaine_vf = ref_domaine_vf_.valeur();
842 // Creation des sommets situes sur les faces de bord
843 {
844 // Les faces de bord sont les premieres faces du domaine
845
846 const IntTab& faces_sommets = domaine_vf.face_sommets();
847 const int numero_PE = Process::nproc();
848 const int nb_faces_bord = domaine_vf.nb_faces_bord();
849
851 faces_sommets,
852 nb_faces_bord,
853 numero_PE,
854 def_noeud);
855 }
856}
857
858// #########################################################################
859// Quatrieme etape
860// Tri lexicographique des noeuds crees. Le critere est le suivant:
861// - ordre croissant du numero du premier sommet,
862// - si 1er sommet identique, ordre croissant du deuxieme sommet,
863// - si 2eme sommet identique, ordre croissant du PE associe
864// Complexite : N * log(N) (N=nombre de noeuds dupliques du maillage lagrangien)
865
866void Marching_Cubes::trier_les_noeuds(IntTab& def_noeud) const
867{
868 if(def_noeud.dimension(1) == 4)
869 tri_lexicographique_tableau(def_noeud);
870 else if(def_noeud.dimension(1) == 5)
871 {
872 int nb_noeuds = def_noeud.dimension(0);
873 using quintuplet = std::array<int, 5>;
874 quintuplet* ptr = reinterpret_cast<quintuplet*>(def_noeud.addr());
875 std::sort(ptr, ptr+nb_noeuds);
876 }
877 else
878 {
879 Cerr << "Marching_Cubes::trier_les_noeuds wrong dimension" << finl;
881 }
882}
883
884// #########################################################################
885// Cinquieme etape :
886// Reduction de la liste des noeuds a une liste ou chaque noeud est unique,
887// creation de la structure de descripteur noeuds distants/virtuels,
888// et mise a jour des facettes avec les numeros definitifs des noeuds.
889// A la fin, def_noeud contient une liste unique d'aretes.
890
891// On suppose que la liste de noeuds est triee (voir ci-dessus).
892// Ainsi, les noeuds identiques se suivent et le PE proprietaire apparait
893// en premier.
894// Les noeuds distants et virtuels sont crees dans l'ordre
895// croissant du numero local du noeud.
896
898 Maillage_FT_Disc& maillage) const
899{
900 const int mon_PE = Process::me();
901 const int nb_procs = Process::nproc();
902 const Domaine_VF& domaine_vf = ref_domaine_vf_.valeur();
903 const IntTab& face_voisins = domaine_vf.face_voisins();
904 const int nb_noeuds = def_noeud.dimension(0);
905 ArrOfInt renumerotation(nb_noeuds);
906 IntTab& facettes = maillage.facettes_;
907 Descripteur_FT& espace_distant = maillage.desc_sommets_.espace_distant();
908 Descripteur_FT& espace_virtuel = maillage.desc_sommets_.espace_virtuel();
909
910 // L'initialisation ne sert que pour le test assert car
911 // normalement le tableau est entierement rempli.
912 renumerotation = -1;
913
914 // Indice du dernier noeud unique ajoute au tableau
915 int dernier = -1;
916 // Numeros des sommets du dernier noeud ajoute
917 int dernier_som0 = -1;
918 int dernier_som1 = -1;
919 int dernier_PEvoisin_ajoute = -1;
920
921 int noeud;
922 enum {NOEUD_REEL, NOEUD_VIRTUEL} type_noeud = NOEUD_REEL;
923
924 // Certains sommets sont crees sur les elements virtuels alors qu'ils n'existent
925 // pas sur les elements reels (element virtuel qui possede une arete virtuelle
926 // dont les deux sommets sont reels). Il faut supprimer ces sommets car le processeur
927 // voisin ne trouvera pas de noeud correspondant dans son espace virtuel.
928 // On met donc keep_last_node a 1 des qu'on trouve me() dans le numero du processeur.
929 int keep_last_node = 1;
930
931 for (noeud = 0; noeud < nb_noeuds; noeud++)
932 {
933 const int noeud_som0 = def_noeud(noeud, 0);
934 const int noeud_som1 = def_noeud(noeud, 1);
935 const int noeud_PE = def_noeud(noeud, 2);
936 const int noeud_ancien_numero = def_noeud(noeud, 3);
937 const int noeud_ligne_contact = (noeud_PE == nb_procs);
938 const int noeud_elem_ou_face = def_noeud(noeud, 4);
939 // Numero de la face ou se trouve le noeud
940 const int noeud_face = noeud_ligne_contact ? noeud_elem_ou_face : -1;
941 // Numero de l'element ou se trouve le noeud
942 int noeud_element;
943 if (noeud_ligne_contact)
944 {
945 // Le noeud est sur une face de bord => un des deux voisins est -1.
946 assert(face_voisins(noeud_face, 0) == -1
947 || face_voisins(noeud_face, 1) == -1);
948 noeud_element =
949 face_voisins(noeud_face, 0) + face_voisins(noeud_face, 1) + 1;
950 }
951 else
952 {
953 noeud_element = noeud_elem_ou_face;
954 }
955
956 // Le noeud est-il different du precedent ?
957 if (noeud_som0 != dernier_som0 || noeud_som1 != dernier_som1)
958 {
959 // Oui, on cree un nouveau noeud. Si le noeud precedent doit etre
960 // ignore, on le supprime:
961 if (keep_last_node)
962 {
963 if (dernier >= 0 && type_noeud == NOEUD_VIRTUEL)
964 {
965 // Quel est le proprietaire du noeud ?
966 const int pe_owner = def_noeud(dernier, 2);
967 // On ajoute le noeud a l'espace virtuel
968 espace_virtuel.ajoute_element(pe_owner, dernier);
969 }
970 dernier++;
971 keep_last_node = 0;
972 }
973 // On ajoute le nouveau noeud a la liste des noeuds uniques
974 def_noeud(dernier, 0) = dernier_som0 = noeud_som0;
975 def_noeud(dernier, 1) = dernier_som1 = noeud_som1;
976 def_noeud(dernier, 2) = noeud_PE;
977 def_noeud(dernier, 3) = noeud_element;
978 def_noeud(dernier, 4) = noeud_face;
979
980 if (noeud_PE != mon_PE)
981 {
982 // Le plus petit PE qui possede le noeud n'est pas moi.
983 // Donc le noeud est virtuel.
984 type_noeud = NOEUD_VIRTUEL;
985 }
986 else
987 {
988 // Le plus petit PE qui possede le noeud est moi.
989 // Le noeud est reel (ou distant si on trouve d'autres PEs
990 // par la suite).
991 type_noeud = NOEUD_REEL;
992 dernier_PEvoisin_ajoute = noeud_PE;
993 }
994 }
995 else
996 {
997 // C'est le meme noeud que le precedent.
998 // On cherche si le noeud est sur des faces de bord et/ou
999 // sur des faces de joint.
1000 if (type_noeud == NOEUD_REEL)
1001 {
1002 if (noeud_PE == nb_procs)
1003 {
1004 // Le noeud est sur une face de bord. On connait maintenant
1005 // la face de bord et on met le noeud dansl'element adjacent
1006 def_noeud(dernier, 3) = noeud_element;
1007 def_noeud(dernier, 4) = noeud_face;
1008 }
1009 else if (noeud_PE != dernier_PEvoisin_ajoute)
1010 {
1011 // Le noeud appartient a une face de joint avec noeud_PE :
1012 // il y a un nouveau voisin a ajouter a l'espace distant
1013 espace_distant.ajoute_element(noeud_PE, dernier);
1014 dernier_PEvoisin_ajoute = noeud_PE;
1015 }
1016 }
1017 }
1018 // Si le noeud existe sur le processeur local, on peut le garder :
1019 if (noeud_PE == mon_PE)
1020 keep_last_node = 1;
1021
1022 renumerotation[noeud_ancien_numero] = dernier;
1023 }
1024 if (keep_last_node)
1025 {
1026 if (dernier >= 0 && type_noeud == NOEUD_VIRTUEL)
1027 {
1028 // Quel est le proprietaire du noeud ?
1029 const int pe_owner = def_noeud(dernier, 2);
1030 // On ajoute le noeud a l'espace virtuel
1031 espace_virtuel.ajoute_element(pe_owner, dernier);
1032 }
1033 dernier++;
1034 }
1035
1036 espace_distant.calcul_liste_pe_voisins();
1037 espace_virtuel.calcul_liste_pe_voisins();
1038 maillage.desc_sommets_.calcul_schema_comm(dernier);
1039
1040 def_noeud.resize(dernier, 5);
1041
1042 // #########################################################################
1043 // Sixieme etape :
1044 // On remplace les numeros des noeuds des facettes par les nouveaux
1045 // numeros uniques.
1046 // Complexite : N (N=nombre de facettes du maillage lagrangien)
1047
1048 {
1049 ArrOfInt& tab = facettes; // tableau vu comme unidimensionnel
1050 int i;
1051 // Nb total de numeros de sommets = nb de facettes * nb sommets par facette
1052 const int nb_sommets = tab.size_array();
1053 for (i = 0; i < nb_sommets; i++)
1054 {
1055 int num_sommet = tab[i];
1056 num_sommet = renumerotation[num_sommet];
1057 assert(num_sommet > -1);
1058 tab[i] = num_sommet;
1059 }
1060 }
1061}
1062
1063// #########################################################################
1064// Septieme etape :
1065// Tri des listes d'elements virtuels de sorte que les sommets partages
1066// apparaissent dans le meme ordre dans la liste des elements distants d'un PE
1067// et dans la liste des elements virtuels du PE voisin.
1068// Les noeuds virtuels sont toujours sur des aretes de joint.
1069// A l'entree dans cette fonction, le descripteur contient les bons elements pour
1070// chaque PE voisins (distant et virtuel), mais ils sont a priori dans le desordre.
1071// Exemple:
1072// * le processeur 1 a les noeuds 0:A, 1:B, 2:C, 3:D, 4:E, 5:F, 6:G.
1073// * le processeur 2 a les noeuds 0:a, 1:b, 2:c, 3:d, 4:e, 5:f.
1074// * les noeuds communs sont A=d, C=b, F=c, G=f
1075// * au depart:
1076// le tableau des elements distants de 1 est (0,2,5,6) (indices des noeuds communs)
1077// le tableau des elements virtuels de 2 est (1,2,3,5) (indices des noeuds communs)
1078// * Quand le processeur 1 envoie son espace distant, il envoie (A,C,F,G) dans cet
1079// ordre. Le but est que le processeur 2 associe les donnees recues a (d,b,c,f)
1080// dans cet ordre. Le tableau des elements virtuels du processeur 2 doit etre
1081// (3,1,2,5). On doit reordonner les elements virtuels.
1082//
1083// Pour faire ca, 2 recoit les noeuds de 1 (une cle qui decrit le noeud de
1084// facon unique). Il recoit (A,C,F,G). Il traduit cette cle sous la forme locale:
1085// (d,b,c,f). Puis il cherche les numeros des noeuds correspondant : (3,1,2,5),
1086// c'est son espace virtuel.
1087
1089 Desc_Structure_FT& desc) const
1090{
1091 // Pour chaque espace distant, on construit un tableau contenant une cle qui decrit
1092 // les noeuds d'interface de facon unique: la cle est constituee des numeros
1093 // des deux sommets euleriens de l'arete qui porte le noeud.
1094 // On aurait aussi pu utiliser les coordonnees x,y,z comme cle mais c'est moins sur...
1095 // En pratique, il s'agit simplement des deux premieres colonnes du tableau def_noeud.
1096
1097 // Copie du tableau
1098 IntTab cles(def_noeud);
1099
1100 // On echange ce tableau : pour chaque noeud virtuel, on recupere la cle distante.
1101 desc.echange_espace_virtuel(cles);
1102
1103 // Boucle sur les PEs voisins de l'espace virtuel
1104 Descripteur_FT& esp_virtuel = desc.espace_virtuel();
1105 const ArrOfInt& pe_voisins = esp_virtuel.pe_voisins();
1106 const int nb_pe_voisins = pe_voisins.size_array();
1107 int index_pe;
1108 IntTabFT cles_pe; // Les cles des noeuds virtuels d'un voisin particulier
1109 IntTabFT temp_renum; // Tableau temporaire pour l'envoi a la fonction de renumerotation
1110 // Elements de l'espace virtuel tries dans le bon ordre
1111 ArrOfIntFT nouvel_espace_virtuel;
1112
1113 for(index_pe = 0; index_pe < nb_pe_voisins; index_pe++)
1114 {
1115
1116 const int pe_voisin = pe_voisins[index_pe];
1117 const ArrOfInt& elements = esp_virtuel.elements(pe_voisin);
1118 const int nb_elements = elements.size_array();
1119
1120 cles_pe.resize(nb_elements, 3);
1121 temp_renum.resize(nb_elements, 2);
1122 nouvel_espace_virtuel.resize_array(nb_elements);
1123
1124 // On copie les cles, on ajoute un numero d'ordre et on remplace le numero
1125 // des sommets euleriens de l'arete (qui est actuellement un numero sur
1126 // le processeur distant) par le numero local.
1127 // Copie des cles de l'espace virtuel
1128 for (int i = 0; i < nb_elements; i++)
1129 {
1130 const int n = elements[i];
1131 temp_renum(i, 0) = cles(n, 0);
1132 temp_renum(i, 1) = cles(n, 1);
1133 }
1134 // Transformation des numeros de sommets euleriens distants de chaque cle
1135 // en numeros de sommets locaux.
1136 renum_sommets_dist_loc(pe_voisin, temp_renum);
1137 // Creation d'un tableau de cles avec une colonne supplementaire contenant
1138 // le numero d'ordre de la cle.
1139 for (int i = 0; i < nb_elements; i++)
1140 {
1141 // On corrige la cle : sommet de plus petit numero en premier
1142 int s0 = temp_renum(i, 0);
1143 int s1 = temp_renum(i, 1);
1144 if (s0 < s1)
1145 {
1146 cles_pe(i, 0) = s0;
1147 cles_pe(i, 1) = s1;
1148 }
1149 else
1150 {
1151 cles_pe(i, 0) = s1;
1152 cles_pe(i, 1) = s0;
1153 }
1154 cles_pe(i, 2) = i;
1155 }
1156 // Par exemple, on aurait : cles_pe = { (d,0), (b,1), (c,2), (f,3) }
1157
1158 // Maintenant, on trie ces cles par ordre lexicographique (meme tri que
1159 // le tableau def_noeud)
1160 tri_lexicographique_tableau(cles_pe);
1161 // Les cles apparaissent maintenant dans le meme ordre que dans le
1162 // tableau def_noeud, donc dans le meme ordre que dans l'espace virtuel, soit:
1163 // (exemple : cles_pe = { (b,1), (c,2), (d,0), (f,3) })
1164 assert(cles_pe.dimension(0) == elements.size_array());
1165 for (int i = 0; i < nb_elements; i++)
1166 {
1167 const int element = elements[i];
1168 // Si les espaces distants et virtuels sont coherents, les cles
1169 // sont identiques.
1170 assert(cles_pe(i, 0) == def_noeud(element, 0));
1171 assert(cles_pe(i, 1) == def_noeud(element, 1));
1172 // Mettre ce noeud au bon endroit dans l'espace virtuel :
1173 // le noeud b en 1, le noeud c en 2, le noeud d en 0, le noeud f en 3.
1174 int position = cles_pe(i, 2);
1175 nouvel_espace_virtuel[position] = element;
1176 }
1177 // On remplace l'espace virtuel par le nouvel espace trie.
1178 esp_virtuel.set_elements(pe_voisin, nouvel_espace_virtuel);
1179 }
1180
1181 // Les espaces virtuels et distants sont maintenant coherents, on
1182 // peut calculer le schema de comm :
1184 desc.calcul_schema_comm(def_noeud.dimension(0));
1185}
1186
1187// #########################################################################
1188// Huitieme etape :
1189// Calcul des coordonnees des noeuds sur les aretes.
1190// Complexite : N (N=nombre de noeuds uniques du maillage lagrangien)
1191
1192void Marching_Cubes::calculer_coord_noeuds(const DoubleVect& valeurs_sommets,
1193 const double isovaleur,
1194 const IntTab& def_noeud,
1195 Maillage_FT_Disc& maillage) const
1196{
1197 // Raccourci vers les coordonnees des sommets du maillage eulerien
1198 const DoubleTab& coord_ = ref_domaine_vf_->domaine().coord_sommets();
1199 const int nb_noeuds = def_noeud.dimension(0);
1200 DoubleTab& coord_noeuds = maillage.sommets_;
1201 coord_noeuds.resize(nb_noeuds, dimension);
1202 int noeud;
1203 int dimension3 = (dimension == 3);
1204
1205 for (noeud = 0; noeud < nb_noeuds; noeud++)
1206 {
1207
1208 int s0 = def_noeud(noeud, 0);
1209 int s1 = def_noeud(noeud, 1);
1210 double valeur0 = valeurs_sommets(s0);
1211 double valeur1 = valeurs_sommets(s1);
1212 // valeur1-valeur0 est forcement non nul, sinon les signes seraient les memes
1213 double alpha = (isovaleur - valeur0) / (valeur1 - valeur0);
1214 // Sanity checking
1215 if (alpha < 0.) alpha = 0.;
1216 if (alpha > 1.) alpha = 1.;
1217 // Coordonnees (on deroule, c'est plus efficace ...?)
1218 coord_noeuds(noeud, 0) = coord_(s0,0)*(1.-alpha)+coord_(s1,0)*alpha;
1219 coord_noeuds(noeud, 1) = coord_(s0,1)*(1.-alpha)+coord_(s1,1)*alpha;
1220 if (dimension3)
1221 coord_noeuds(noeud, 2) = coord_(s0,2)*(1.-alpha)+coord_(s1,2)*alpha;
1222 }
1223
1224 const Desc_Structure_FT& desc = maillage.desc_sommets_;
1225 desc.echange_espace_virtuel(coord_noeuds);
1226}
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
: class Desc_Structure_FT
void echange_espace_virtuel(ArrOfDouble &tab) const
Descripteur_FT & espace_virtuel()
Renvoie une reference non-const a l'espace virtuel.
Descripteur_FT & espace_distant()
Renvoie une reference non-const a l'espace distant.
void calcul_schema_comm(const int nb_items_tot)
void remplir_element_pe(ArrOfInt &element_pe) const
remplit le tableau qui donne pour chaque element le numero du pe proprietaire.
: class Descripteur_FT Descripteur_FT stocke pour chaque PE une liste de numeros d'elements.
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...
class Domaine_VF
Definition Domaine_VF.h:44
int face_sommets(int i, int j) const
renvoie le numero du ieme sommet de la face num_face.
Definition Domaine_VF.h:583
int 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
const Domaine & domaine() const
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
const IntTab_t & renum_virt_loc() const
Definition Joint.h:57
int PEvoisin() const
Definition Joint.h:49
: class Maillage_FT_Disc Cette classe decrit un maillage:
void corriger_proprietaires_facettes()
Sans changer les sommets existants ni la numerotation des facettes, on change le proprietaire des fac...
ArrOfIntFT sommet_PE_owner_
Desc_Structure_FT desc_facettes_
ArrOfIntFT sommet_face_bord_
Desc_Structure_FT desc_sommets_
void maillage_modifie(Statut_Maillage nouveau_statut)
Cette methode change le statut du maillage et invalide le cache de valeurs calculees (surface,...
ArrOfIntFT sommet_num_owner_
ArrOfIntFT drapeaux_sommets_
Statut_Maillage statut_
void reset()
vide toutes les structures du maillage, le statut passe a RESET.
int construire_noeuds_et_facettes(const ArrOfBit &signe, IntTab &def_noeud, IntTab &facettes, DoubleVect &indicatrice_approchee, const Maillage_FT_Disc::AjoutPhase phase) const
void construire_noeuds_uniques(IntTab &def_noeud, Maillage_FT_Disc &maillage) const
ArrOfIntFT mcubes_nb_facettes
void remplir_data_marching_cubes(const Domaine &domaine)
void calculer_coord_noeuds(const DoubleVect &valeurs_sommets, const double isovaleur, const IntTab &def_noeud, Maillage_FT_Disc &maillage) const
ArrOfInt indice_joint_
void correspondance_espaces_distant_virtuel(const IntTab &def_noeud, Desc_Structure_FT &desc) const
void remplir_renum_virt_loc(const Domaine &domaine)
void trier_les_noeuds(IntTab &def_noeud) const
int construire_iso(const DoubleVect &valeurs_sommets, double isovaleur, Maillage_FT_Disc &maillage, DoubleVect &indicatrice_approchee, const Maillage_FT_Disc::AjoutPhase phase, int ignorer_collision=0) const
Construction d'un maillage en segments ou en triangles comme l'isovaleur d'une fonction discretisee a...
void renum_sommets_dist_loc(const int pe_voisin, ArrOfInt &num_sommets) const
void construire_noeuds_joints(const ArrOfBit &signe, IntTab &def_noeud) const
void construire_noeuds_liste_faces(const ArrOfBit &signe, const IntTab &faces_sommets, const int nb_faces_a_traiter, const int numero_PE, IntTab &def_noeud) const
Ajout des sommets situes sur des faces (bords ou joints) dans le tableau def_noeud.
void calculer_signe(const DoubleVect &valeurs_sommets, const double isovaleur, ArrOfBit &signe) const
IntTabFT mcubes_def_aretes_faces
ArrOfIntFT mcubes_facettes
void associer_domaine_vf(const Domaine_VF &domaine_vf)
ArrOfIntFT mcubes_index_facettes
IntTabFT mcubes_def_aretes
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
classe Objet_U Cette classe est la classe de base des Objets de TRUST
Definition Objet_U.h:73
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
Representation des donnees de la classe Parser.
Definition Parser.h:39
void addVar(const char *)
Definition Parser.cpp:565
void setVar(const char *sv, double val)
Definition Parser.h:73
double eval()
Definition Parser.h:68
virtual void parseString()
Definition Parser.cpp:124
static double mp_min(double)
Definition Process.cpp:386
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 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
Classe de base des flux de sortie.
Definition Sortie.h:52
_SIZE_ size_array() const
_TYPE_ * addr()
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")