Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
FaceUniqueIdBuilder.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* FaceUniqueIdBuilder.cc (C) 2000-2024 */
9/* */
10/* Construction des identifiants uniques des faces. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/ScopedPtr.h"
16#include "arcane/utils/ITraceMng.h"
17#include "arcane/utils/OStringStream.h"
18#include "arcane/utils/CheckedConvert.h"
19
20#include "arcane/mesh/DynamicMesh.h"
21#include "arcane/mesh/OneMeshItemAdder.h"
22#include "arcane/mesh/GhostLayerBuilder.h"
23#include "arcane/mesh/FaceUniqueIdBuilder.h"
24#include "arcane/mesh/ItemTools.h"
25
26#include "arcane/core/IMeshUniqueIdMng.h"
27#include "arcane/core/IParallelExchanger.h"
28#include "arcane/core/IParallelMng.h"
29#include "arcane/core/ISerializeMessage.h"
30#include "arcane/core/ISerializer.h"
31#include "arcane/core/ParallelMngUtils.h"
32
33#include <unordered_set>
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38namespace Arcane::mesh
39{
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43
44extern "C++" void
45_computeFaceUniqueIdVersion3(DynamicMesh* mesh);
46extern "C++" void
47_computeFaceUniqueIdVersion5(DynamicMesh* mesh);
48extern "C++" void
49arcaneComputeCartesianFaceUniqueId(DynamicMesh* mesh);
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
61
62/*---------------------------------------------------------------------------*/
63/*---------------------------------------------------------------------------*/
64
65void FaceUniqueIdBuilder::
66computeFacesUniqueIds()
67{
68 IParallelMng* pm = m_mesh->parallelMng();
69 Real begin_time = platform::getRealTime();
70 Integer face_version = m_mesh->meshUniqueIdMng()->faceBuilderVersion();
71 bool is_parallel = pm->isParallel();
72 info() << "Using version=" << face_version << " to compute faces unique ids"
73 << " mesh=" << m_mesh->name() << " is_parallel=" << is_parallel;
74
75 if (face_version > 5 || face_version < 0)
76 ARCANE_FATAL("Invalid value '{0}' for compute face unique ids versions: v>=0 && v<=6", face_version);
77
78 if (face_version == 5)
79 _computeFaceUniqueIdVersion5(m_mesh);
80 else if (face_version == 4)
81 arcaneComputeCartesianFaceUniqueId(m_mesh);
82 else if (face_version==3)
83 _computeFaceUniqueIdVersion3(m_mesh);
84 else{
85 if (is_parallel){
86 if (face_version==2){
87 //PAS ENCORE PAR DEFAUT
88 info() << "Use new mesh init in FaceUniqueIdBuilder";
90 }
91 else{
92 // Version par défaut.
94 }
95 }
96 else{
97 if (face_version==0){
98 pwarning() << "No face renumbering";
99 return;
100 }
102 }
103 }
104
105 Real end_time = platform::getRealTime();
106 Real diff = (Real)(end_time - begin_time);
107 info() << "TIME to compute face unique ids=" << diff;
108
109 if (arcaneIsCheck())
111
112 ItemInternalMap& faces_map = m_mesh->facesMap();
113
114 // Il faut ranger à nouveau #m_faces_map car les uniqueId() des
115 // faces ont été modifiés
117
118 bool is_verbose = m_mesh_builder->isVerbose();
119 if (is_verbose){
120 info() << "NEW FACES_MAP after re-indexing";
121 faces_map.eachItem([&](Item face) {
122 info() << "Face uid=" << face.uniqueId() << " lid=" << face.localId();
123 });
124 }
125}
126
127/*---------------------------------------------------------------------------*/
128/*---------------------------------------------------------------------------*/
134{
135 info() << "Check no duplicate face uniqueId";
136 ItemInternalMap& faces_map = m_mesh->facesMap();
137 std::unordered_set<Int64> checked_faces_map;
138 faces_map.eachItem([&](Item face) {
139 ItemUniqueId uid = face.uniqueId();
140 auto p = checked_faces_map.find(uid);
141 if (p!=checked_faces_map.end()){
142 pwarning() << "Duplicate Face UniqueId=" << uid;
143 ARCANE_FATAL("Duplicate Face uniqueId={0}",uid);
144 }
145 checked_faces_map.insert(uid);
146 });
147}
148
149/*---------------------------------------------------------------------------*/
150/*---------------------------------------------------------------------------*/
160{
161 public:
162
163 T_CellFaceInfo(Int64 uid,Integer nb_back_face,Integer nb_true_boundary_face)
164 : m_unique_id(uid), m_nb_back_face(nb_back_face), m_nb_true_boundary_face(nb_true_boundary_face)
165 {
166 }
167
169 : m_unique_id(NULL_ITEM_ID), m_nb_back_face(0), m_nb_true_boundary_face(0)
170 {
171 }
172
173 public:
174
175 bool operator<(const T_CellFaceInfo& ci) const
176 {
177 return m_unique_id<ci.m_unique_id;
178 }
179
180 public:
181
182 Int64 m_unique_id;
183 Int64 m_nb_back_face;
184 Int64 m_nb_true_boundary_face;
185};
186
187/*---------------------------------------------------------------------------*/
188/*---------------------------------------------------------------------------*/
206{
207 IParallelMng* pm = m_mesh->parallelMng();
208 Integer my_rank = pm->commRank();
209 Integer nb_rank = pm->commSize();
210
211 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
212 Integer nb_local_cell = m_mesh_builder->oneMeshItemAdder()->nbCell();
213 bool is_verbose = m_mesh_builder->isVerbose();
214
216 faces_opposite_cell_uid.fill(NULL_ITEM_ID);
219
220 // Pour vérification, s'assure que tous les éléments de ce tableau
221 // sont valides, ce qui signifie que toutes les faces ont bien été
222 // renumérotés
224 faces_new_uid.fill(NULL_ITEM_ID);
225
227
229 faces_infos.reserve(10000);
230 ItemInternalMap& cells_map = m_mesh->cellsMap();
231 ItemInternalMap& faces_map = m_mesh->facesMap();
232 ItemInternalMap& nodes_map = m_mesh->nodesMap();
233
234
235 // NOTE: ce tableau n'est pas utile sur toutes les mailles. Il
236 // suffit qu'il contienne les mailles dont on a besoin, c'est à dire
237 // les notres + celles connectées à une de nos faces. Une table
238 // de hashage sera plus appropriée.
239 HashTableMapT<Int64,Int64> cells_first_face_uid(m_mesh_builder->oneMeshItemAdder()->nbCell()*2,true);
240
241 // Rassemble les données des autres processeurs dans recv_cells;
242 // Pour éviter que les tableaux ne soient trop gros, on procède en plusieurs
243 // étapes.
244 // Chaque sous-domaine construit sa liste de faces frontières, avec pour
245 // chaque face:
246 // - son type
247 // - la liste de ses noeuds,
248 // - le numéro unique de sa maille
249 // - le propriétaire de sa maille
250 // - son indice dans sa maille
251 // Cette liste sera ensuite envoyée à tous les sous-domaines.
252 {
253 ItemTypeMng* itm = m_mesh->itemTypeMng();
254
256
257 faces_map.eachItem([&](Face face) {
258 bool boundary_val = face.isSubDomainBoundary();
259 if (boundary_val)
260 faces_local_id.add(face.localId());
261 });
262
264 Int64 global_nb_boundary_face = pm->reduce(Parallel::ReduceSum,(Int64)nb_sub_domain_boundary_face);
265 debug() << "NB BOUNDARY FACE=" << nb_sub_domain_boundary_face
266 << " NB_FACE=" << nb_local_face
267 << " GLOBAL_NB_BOUNDARY_FACE=" << global_nb_boundary_face;
268
269
272
273 // Calcule la taille d'un bloc d'envoi
274 // La mémoire nécessaire pour une face est égale à nb_node + 4.
275 // Si on suppose qu'on a des quadrangles en général, cela
276 // fait 8 Int64 par face, soit 64 octets par face.
277 // La mémoire nécessaire pour tout envoyer est donc 64 * global_nb_boundary_face.
278 // step_size * nb_proc * 64 octets.
279 // Le step_size par défaut est calculé pour que la mémoire nécessaire
280 // soit de l'ordre de 100 Mo pour chaque message.
281 Int64 step_size = 1500000;
283 FaceInfoListView faces(m_mesh->faceFamily());
284 for( Integer i_phase=0; i_phase<nb_phase; ++i_phase ){
288 if (i_phase+1==nb_phase)
291
292 faces_infos2.clear();
294 Face face(faces[faces_local_id[i_face]]);
297 faces_infos2.add(face.type());
298 for( Node node : face.nodes() )
299 faces_infos2.add(node.uniqueId().asInt64());
300
301 //info() << " ADD FACE lid=" << face->localId();
302
303 Cell cell = face.cell(0);
304 faces_infos2.add(cell.uniqueId().asInt64());
305 faces_infos2.add(cell.owner());
306
307 Integer face_index_in_cell = 0;
308 if (has_back_cell){
309 for( Face current_face_in_cell : cell.faces() ){
310 if (current_face_in_cell==face)
311 break;
312 if (current_face_in_cell.backCell()==cell)
314 }
315 }
316 else
317 face_index_in_cell = NULL_ITEM_ID;
319 }
320 faces_infos2.add(IT_NullType); // Pour dire que la liste s'arête
321
323
324 info() << "Number of face bytes received: " << recv_faces_infos.size()
325 << " phase=" << i_phase << "/" << nb_phase
326 << " first_face=" << first_face_to_send
327 << " last_face=" << last_face_to_send
328 << " nb=" << real_nb_face_to_send;
329
330 Integer recv_faces_infos_index = 0;
331
332 for( Integer i_sub_domain=0; i_sub_domain<nb_rank; ++i_sub_domain ){
333 bool is_end = false;
334 // Il ne faut pas lire les infos qui viennent de moi
335 if (i_sub_domain==my_rank){
337 continue;
338 }
339 // Désérialise les infos de chaque sous-domaine
340 while (!is_end){
343 if (face_type==IT_NullType){
344 is_end = true;
345 break;
346 }
347 ItemTypeInfo* itt = itm->typeFromId(face_type);
348 Integer face_nb_node = itt->nbLocalNode();
350
358
359 Node node = nodes_map.tryFind(faces_nodes_uid[0]);
360 // Si la face n'existe pas dans mon sous-domaine, elle ne m'intéresse pas
361 if (node.null())
362 continue;
364 if (face.null())
365 continue;
367 faces_opposite_cell_uid[face.localId()] = cell_uid;
369 faces_opposite_cell_owner[face.localId()] = cell_owner;
370 cells_first_face_uid.add(cell_uid,-1);
371 }
372 }
373 }
374 info() << "Number of faces on the subdomain interface: "
376 }
377
378 // Cherche le uniqueId max des mailles sur tous les sous-domaines.
379 Int64 max_cell_uid = 0;
380 Int32 max_cell_local_id = 0;
381 cells_map.eachItem([&](Item cell) {
382 Int64 cell_uid = cell.uniqueId().asInt64();
383 Int32 cell_local_id = cell.localId();
384 if (cell_uid>max_cell_uid)
385 max_cell_uid = cell_uid;
388 });
389 Int64 global_max_cell_uid = pm->reduce(Parallel::ReduceMax,max_cell_uid);
390 debug() << "GLOBAL MAX CELL UID=" << global_max_cell_uid;
391
392
396 my_cells_nb_back_face.fill(0);
397
398 cells_map.eachItem([&](Cell cell) {
399 Int64 cell_uid = cell.uniqueId().asInt64();
400 Int32 cell_local_id = cell.localId();
401 Integer nb_back_face = 0;
402 Integer nb_true_boundary_face = 0;
403 for( Face face : cell.faces() ){
404 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
405 if (face.backCell()==cell)
406 ++nb_back_face;
407 else if (face.nbCell()==1 && opposite_cell_uid==NULL_ITEM_ID){
409 }
410 }
413 });
414 std::sort(std::begin(my_cells_faces_info),std::end(my_cells_faces_info));
415
416 {
417 Integer nb_phase = 16;
418 Integer first_cell_index_to_send = 0;
419 Int64 current_face_uid = 0;
420
421 for( Integer i_phase=0; i_phase<nb_phase; ++i_phase ){
425 if (i_phase+1==nb_phase)
427
428 //Integer last_cell_index_to_send = first_cell_index_to_send;
429 Integer nb_cell_to_send = 0;
430 for( Integer zz=first_cell_index_to_send, zs=my_cells_faces_info.size(); zz<zs; ++zz ){
431 if (my_cells_faces_info[zz].m_unique_id<=last_uid_to_send)
433 else
434 break;
435 }
436 debug() << "FIRST TO SEND=" << first_cell_index_to_send
437 << " NB=" << nb_cell_to_send
438 << " first_uid=" << first_uid_to_send
439 << " last_uid=" << last_uid_to_send;
440
442 Int64* begin_array = reinterpret_cast<Int64*>(begin_cell_array);
443 Integer begin_size = nb_cell_to_send*3;
444
446
450
451 info() << "Infos faces (received) nb_int64=" << recv_cells_faces_infos.size();
452 Integer recv_nb_cell = recv_cells_faces_infos.size() / 3;
453
454 // NOTE: comme on connait le uid min et max possible, on peut optimiser en
455 // creant un tableau dimensionne avec comme borne ce min et ce max et
456 // remplir directement les elements de ce tableau. Comme cela, on
457 // n'a pas besoin de tri.
459 for( Integer i=0; i<recv_nb_cell; ++i ){
460 Int64 cell_uid = recv_cells_faces_infos[i*3];
461 global_cells_faces_info[i].m_unique_id = cell_uid;
462 global_cells_faces_info[i].m_nb_back_face = recv_cells_faces_infos[(i*3) +1];
463 global_cells_faces_info[i].m_nb_true_boundary_face = recv_cells_faces_infos[(i*3) +2];
464 }
465 info() << "Sorting the faces nb=" << global_cells_faces_info.size();
466 std::sort(std::begin(global_cells_faces_info),std::end(global_cells_faces_info));
467
468 for( Integer i=0; i<recv_nb_cell; ++i ){
469 Int64 cell_uid = global_cells_faces_info[i].m_unique_id;
470 if (cells_map.hasKey(cell_uid) || cells_first_face_uid.hasKey(cell_uid))
472 current_face_uid += global_cells_faces_info[i].m_nb_back_face + global_cells_faces_info[i].m_nb_true_boundary_face;
473 }
474 }
475 }
476
477 cells_map.eachItem([&](Cell cell) {
478 Int64 cell_uid = cell.uniqueId();
479 Int32 cell_local_id = cell.localId();
480 Integer num_local_face = 0;
481 Integer num_true_boundary_face = 0;
482 for( Face face : cell.faces() ){
483 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
484 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
485 if (face.backCell()==cell){
486 if (!cells_first_face_uid.hasKey(cell_uid))
487 fatal() << "NO KEY 0 for cell_uid=" << cell_uid;
489 face.mutableItemBase().setOwner(my_rank,my_rank);
491 }
492 else if (face.nbCell()==1){
493 if (opposite_cell_uid==NULL_ITEM_UNIQUE_ID){
494 // Il s'agit d'une face frontière du domaine initial
495 if (!cells_first_face_uid.hasKey(cell_uid))
496 fatal() << "NO KEY 1 for cell_uid=" << cell_uid;
499 face.mutableItemBase().setOwner(my_rank,my_rank);
500 }
501 else{
503 fatal() << "NO KEY 1 for cell_uid=" << cell_uid << " opoosite=" << opposite_cell_uid;
505 face.mutableItemBase().setOwner(faces_opposite_cell_owner[face.localId()],my_rank);
506 }
507 }
508 if (face_new_uid!=NULL_ITEM_UNIQUE_ID){
509 faces_new_uid[face.localId()] = face_new_uid;
510 face.mutableItemBase().setUniqueId(face_new_uid);
511 }
512 }
513 });
514
515 // Vérifie que toutes les faces ont été réindéxées
516 {
517 Integer nb_error = 0;
518 for( Integer i=0, is=nb_local_face; i<is; ++i ){
519 if (faces_new_uid[i]==NULL_ITEM_UNIQUE_ID){
520 ++nb_error;
521 if (nb_error<10)
522 error() << "The face lid=" << i << " has not been re-indexed.";
523 }
524 }
525 if (nb_error!=0)
526 ARCANE_FATAL("Some ({0}) faces have not been reindexed",nb_error);
527 }
528
529 if (is_verbose){
531 cells_map.eachItem([&](Cell cell) {
532 Int64 cell_uid = cell.uniqueId().asInt64();
533 Integer face_index = 0;
534 for( Face face : cell.faces() ){
535 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
536 bool shared = false;
537 bool true_boundary = false;
538 bool internal_other = false;
539 if (face.backCell()==cell){
540 }
541 else if (face.nbCell()==1){
542 if (opposite_cell_uid==NULL_ITEM_ID)
543 true_boundary = true;
544 else
545 shared = true;
546 }
547 else{
548 internal_other = true;
549 opposite_cell_uid = face.backCell().uniqueId().asInt64();
550 }
551 ostr() << "NEW UNIQUE ID FOR FACE"
552 << " lid=" << face.localId()
553 << " cell=" << cell_uid
554 << " face=" << face.uniqueId()
555 << " nbcell=" << face.nbCell()
556 << " cellindex=" << face_index << " (";
557 for( Node node : face.nodes() )
558 ostr() << ' ' << node.uniqueId();
559 ostr() << ")";
560 if (internal_other)
561 ostr() << " internal-other";
562 if (true_boundary)
563 ostr() << " true-boundary";
564 if (opposite_cell_uid!=NULL_ITEM_ID){
565 ostr() << " opposite " << opposite_cell_uid;
566 }
567 if (shared)
568 ostr() << " (shared)";
569 ostr() << "\n";
570 ++face_index;
571 }
572 });
573 info() << ostr.str();
574 String file_name("faces_uid.");
576 std::ofstream ofile(file_name.localstr());
577 ofile << ostr.str();
578 }
579}
580
581/*---------------------------------------------------------------------------*/
582/*---------------------------------------------------------------------------*/
589{
591 Int32 sd = i_map.data()->key();
592 exchanger->addSender(sd);
593 }
595 Integer nb_sender = exchanger->nbSender();
596 Integer nb_receiver = exchanger->nbReceiver();
597 info() << "NB_SEND=" << nb_sender << " NB_RECV=" << nb_receiver;
598 Integer total = nb_sender+nb_receiver;
599 Integer global_total = exchanger->parallelMng()->reduce(Parallel::ReduceSum,total);
600 info() << "GLOBAL_NB_MESSAGE=" << global_total;
601
602 {
603 for( Integer i=0, ns=exchanger->nbSender(); i<ns; ++i ){
604 ISerializeMessage* sm = exchanger->messageToSend(i);
605 Int32 rank = sm->destination().value();
606 ISerializer* s = sm->serializer();
608 Integer nb_info = infos.size();
609 s->setMode(ISerializer::ModeReserve);
610 s->reserve(DT_Int64,1); // Pour le nombre d'elements
611 s->reserveSpan(DT_Int64,nb_info); // Pour les elements
612 s->allocateBuffer();
614 s->putInt64(nb_info);
615 s->putSpan(infos);
616 }
617 }
618 exchanger->processExchange();
619 debug() << "END EXCHANGE";
620}
621
622template<typename DataType>
624{
625 public:
626 private:
627
628 class MyInfo
629 {
630 public:
631 MyInfo(const DataType& d,Integer n) : data(d), next_index(n) {}
632 public:
633 DataType data;
634 Integer next_index;
635 };
636
637 public:
638 ItemInfoMultiList() : m_last_index(5000,true) {}
639
640 public:
641
642 void add(Int64 node_uid,const DataType& data)
643 {
644 Integer current_index = m_values.size();
645
646 bool is_add = false;
647 HashTableMapT<Int64,Int32>::Data* d = m_last_index.lookupAdd(node_uid,-1,is_add);
648
649 m_values.add(MyInfo(data,d->value()));
650 d->value() = current_index;
651 }
652
653 public:
654 UniqueArray<MyInfo> m_values;
655 HashTableMapT<Int64,Int32> m_last_index;
656};
657
658/*---------------------------------------------------------------------------*/
659/*---------------------------------------------------------------------------*/
669{
670 IParallelMng* pm = m_mesh->parallelMng();
671 Integer my_rank = pm->commRank();
672 Integer nb_rank = pm->commSize();
673
674 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
675 //Integer nb_local_cell = m_mesh_builder->nbCell();
676 //bool is_verbose = m_mesh_builder->isVerbose();
677
679 faces_opposite_cell_uid.fill(NULL_ITEM_ID);
682
683 // Pour vérification, s'assure que tous les éléments de ce tableau
684 // sont valides, ce qui signifie que toutes les faces ont bien été
685 // renumérotés
687 faces_new_uid.fill(NULL_ITEM_ID);
688
690 faces_infos.reserve(10000);
691 ItemInternalMap& faces_map = m_mesh->facesMap();
692 ItemInternalMap& nodes_map = m_mesh->nodesMap();
693
694
695 // NOTE: ce tableau n'est pas utile sur toutes les mailles. Il
696 // suffit qu'il contienne les mailles dont on a besoin, c'est à dire
697 // les notres + celles connectées à une de nos faces.
698 HashTableMapT<Int32,Int32> cell_first_face_uid(m_mesh_builder->oneMeshItemAdder()->nbCell()*2,true);
699
700 // Rassemble les données des autres processeurs dans recv_cells;
701 // Pour éviter que les tableaux ne soient trop gros, on procède en plusieurs
702 // étapes.
703 // Chaque sous-domaine construit sa liste de faces frontières, avec pour
704 // chaque face:
705 // - son type
706 // - la liste de ses noeuds,
707 // - le numéro unique de sa maille
708 // - le propriétaire de sa maille
709 // - son indice dans sa maille
710 // Cette liste sera ensuite envoyée à tous les sous-domaines.
711 ItemTypeMng* itm = m_mesh->itemTypeMng();
712
713 // Détermine le unique id max des noeuds
714 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
715 nodes_map.eachItem([&](Item node) {
716 Int64 node_uid = node.uniqueId();
717 if (node_uid>my_max_node_uid)
718 my_max_node_uid = node_uid;
719 });
720 Int64 global_max_node_uid = pm->reduce(Parallel::ReduceMax,my_max_node_uid);
721 debug() << "NODE_UID_INFO: MY_MAX_UID=" << my_max_node_uid
722 << " GLOBAL=" << global_max_node_uid;
723
724 //TODO: choisir bonne valeur pour initialiser la table
727 info() << "NB_CORE modulo=" << uid_to_subdomain_converter.modulo();
731
732 // Marque tous les noeuds frontieres car ce sont ceux qu'il faudra envoyer
733 faces_map.eachItem([&](Face face) {
734 Integer face_nb_cell = face.nbCell();
735 if (face_nb_cell==1){
736 for( Node node : face.nodes() )
737 is_boundary_nodes[node.localId()] = true;
738 }
739 });
740
741 // Détermine la liste des faces frontières
742 faces_map.eachItem([&](Face face) {
743 Node first_node = face.node(0);
744 Int64 first_node_uid = first_node.uniqueId();
746 Int32 dest_rank = -1;
747 if (!is_boundary_nodes[first_node.localId()]){
748 v = nodes_info.lookupAdd(first_node_uid)->value();
749 }
750 else{
752 v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
753 }
754 v.add(first_node_uid); // 0
755 v.add(my_rank); // 1
756 v.add(face.uniqueId()); // 2
757 v.add(face.type()); // 3
758 Cell back_cell = face.backCell();
759 Cell front_cell = face.frontCell();
760 if (back_cell.null()) // 4 : only used for debug
761 v.add(NULL_ITEM_UNIQUE_ID);
762 else
763 v.add(back_cell.uniqueId());
764 if (front_cell.null()) // 5 : only used for debug
765 v.add(NULL_ITEM_UNIQUE_ID);
766 else
767 v.add(front_cell.uniqueId());
768 for( Integer z=0, zs=face.nbNode(); z<zs; ++z )
769 v.add(face.node(z).uniqueId());
770 });
771
772 // Positionne la liste des envoies
774 _exchangeData(exchanger.get(),boundary_infos_to_send);
775
776 {
777 Integer nb_receiver = exchanger->nbReceiver();
778 debug() << "NB RECEIVER=" << nb_receiver;
780 for( Integer i=0; i<nb_receiver; ++i ){
781 ISerializeMessage* sm = exchanger->messageToReceive(i);
782 //Int32 orig_rank = sm->destSubDomain();
783 ISerializer* s = sm->serializer();
785 Int64 nb_info = s->getInt64();
786 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
787 received_infos.resize(nb_info);
789 //if ((nb_info % 3)!=0)
790 //fatal() << "info size can not be divided by 3";
791 Integer z =0;
792 while(z<nb_info){
793 Int64 node_uid = received_infos[z+0];
794 Int32 face_type = (Int32)received_infos[z+3];
795 ItemTypeInfo* itt = itm->typeFromId(face_type);
796 Integer face_nb_node = itt->nbLocalNode();
797 Int64Array& a = nodes_info.lookupAdd(node_uid)->value();
799 z += 6;
800 z += face_nb_node;
801 }
802 }
803 Integer my_max_face_node = 0;
804 for( HashTableMapT<Int64,SharedArray<Int64> >::Enumerator inode(nodes_info); ++inode; ){
806 Integer nb_info = a.size();
807 Integer z = 0;
808 Integer node_nb_face = 0;
809 while(z<nb_info){
810 ++node_nb_face;
811 Int32 face_type = (Int32)a[z+3];
812 ItemTypeInfo* itt = itm->typeFromId(face_type);
813 Integer face_nb_node = itt->nbLocalNode();
814 z += 6;
815 z += face_nb_node;
816 }
818 }
819 Integer global_max_face_node = pm->reduce(Parallel::ReduceMax,my_max_face_node);
820 debug() << "GLOBAL MAX FACE NODE=" << global_max_face_node;
821 // OK, maintenant donne comme uid de la face (node_uid * global_max_face_node + index)
822 IntegerUniqueArray indexes;
824
825 for( HashTableMapT<Int64,SharedArray<Int64> >::Enumerator inode(nodes_info); ++inode; ){
827 Integer nb_info = a.size();
828 Integer z = 0;
829 Integer node_nb_face = 0;
830 indexes.clear();
831 while(z<nb_info){
832 Int64 node_uid = a[z+0];
833 Int32 sender_rank = (Int32)a[z+1];
834 Int64 face_uid = a[z+2];
835 Int32 face_type = (Int32)a[z+3];
836 ItemTypeInfo* itt = itm->typeFromId(face_type);
837 Integer face_nb_node = itt->nbLocalNode();
838
839 // Regarde si la face est déjà dans la liste:
840 Integer face_index = node_nb_face;
842 for( Integer y=0; y<node_nb_face; ++y ){
843 if (memcmp(&a[indexes[y]+6],&a[z+6],sizeof(Int64)*face_nb_node)==0){
844 face_index = y;
845 face_new_owner = (Int32)a[indexes[y]+1];
846 }
847 }
848 Int64 face_new_uid = (node_uid * global_max_face_node) + face_index;
849 Int64Array& v = boundary_infos_to_send.lookupAdd(sender_rank)->value();
850 // Indique au propriétaire de cette face son nouvel uid
851 v.add(face_uid);
852 v.add(face_new_uid);
853 v.add(face_new_owner);
854 indexes.add(z);
855 z += 6;
856 z += face_nb_node;
857 ++node_nb_face;
858 }
860 }
861 }
863
864 _exchangeData(exchanger.get(),boundary_infos_to_send);
865 {
866 Integer nb_receiver = exchanger->nbReceiver();
867 debug() << "NB RECEIVER=" << nb_receiver;
869 for( Integer i=0; i<nb_receiver; ++i ){
870 ISerializeMessage* sm = exchanger->messageToReceive(i);
871 ISerializer* s = sm->serializer();
873 Int64 nb_info = s->getInt64();
874 received_infos.resize(nb_info);
876 if ((nb_info % 3)!=0)
877 ARCANE_FATAL("info size can not be divided by 3 v={0}",nb_info);;
878 Int64 nb_item = nb_info / 3;
879 for (Int64 z=0; z<nb_item; ++z ){
880 Int64 old_uid = received_infos[(z*3)];
881 Int64 new_uid = received_infos[(z*3)+1];
882 Int32 new_owner = (Int32)received_infos[(z*3)+2];
884 if (face.null())
885 ARCANE_FATAL("Can not find own face uid={0}", old_uid);
886 face.setUniqueId(new_uid);
888 }
889 }
890 }
891
892 traceMng()->flush();
893 pm->barrier();
894 debug() << "END OF TEST NEW FACE COMPUTE";
895 return;
896}
897
898/*---------------------------------------------------------------------------*/
899/*---------------------------------------------------------------------------*/
907{
908 bool is_verbose = m_mesh_builder->isVerbose();
909
910 ItemInternalMap& cells_map = m_mesh->cellsMap();
911
912 // En séquentiel, les uniqueId() des mailles ne peuvent dépasser la
913 // taille des Integers même en 32bits.
914 Int32 max_uid = 0;
915 cells_map.eachItem([&](Item cell) {
916 Int32 cell_uid = cell.uniqueId().asInt32();
917 if (cell_uid>max_uid)
918 max_uid = cell_uid;
919 });
920 info() << "Max uid=" << max_uid;
921 Integer nb_computed = max_uid + 1;
925
926 cells_map.eachItem([&](Cell cell) {
927 Int32 cell_uid = cell.uniqueId().asInt32();
928 Integer nb_num_back_face = 0;
929 Integer nb_true_boundary_face = 0;
930 for( Face face : cell.faces() ){
931 if (face.backCell()==cell)
933 else if (face.nbCell()==1){
935 }
936 }
939 });
940
941 Integer current_face_uid = 0;
942 for( Integer i=0; i<nb_computed; ++i ){
945 }
946
947 if (is_verbose){
948 cells_map.eachItem([&](Item cell) {
949 Int32 i = cell.uniqueId().asInt32();
950 info() << "Recv: Cell FaceInfo celluid=" << i
951 << " firstfaceuid=" << cell_first_face_uid[i]
952 << " nbback=" << cell_nb_num_back_face[i]
953 << " nbbound=" << cell_true_boundary_face[i];
954 });
955 }
956
957 cells_map.eachItem([&](Cell cell) {
958 Int32 cell_uid = cell.uniqueId().asInt32();
959 Integer nb_num_back_face = 0;
960 Integer nb_true_boundary_face = 0;
961 for( Face face : cell.faces() ){
962 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
963 if (face.backCell()==cell){
966 }
967 else if (face.nbCell()==1){
970 }
971 if (face_new_uid!=NULL_ITEM_UNIQUE_ID){
972 face.mutableItemBase().setUniqueId(face_new_uid);
973 }
974 }
975 });
976
977 if (is_verbose){
979 cells_map.eachItem([&](Cell cell) {
980 Integer face_index = 0;
981 for( Face face : cell.faces() ){
982 Int64 opposite_cell_uid = NULL_ITEM_UNIQUE_ID;
983 bool true_boundary = false;
984 bool internal_other = false;
985 if (face.backCell()==cell){
986 }
987 else if (face.nbCell()==1){
988 true_boundary = true;
989 }
990 else{
991 internal_other = true;
992 opposite_cell_uid = face.backCell().uniqueId().asInt64();
993 }
994 ostr() << "NEW LOCAL ID FOR CELLFACE cell_uid=" << cell.uniqueId() << ' '
995 << face_index << " uid=" << face.uniqueId() << " (";
996 for( Node node : face.nodes() )
997 ostr() << ' ' << node.uniqueId();
998 ostr() << ")";
999 if (internal_other)
1000 ostr() << " internal-other";
1001 if (true_boundary)
1002 ostr() << " true-boundary";
1003 if (opposite_cell_uid!=NULL_ITEM_ID)
1004 ostr() << " opposite " << opposite_cell_uid;
1005 ostr() << '\n';
1006 ++face_index;
1007 }
1008 });
1009 info() << ostr.str();
1010 }
1011}
1012
1013/*---------------------------------------------------------------------------*/
1014/*---------------------------------------------------------------------------*/
1015
1016} // End namespace Arcane::mesh
1017
1018/*---------------------------------------------------------------------------*/
1019/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Tableau d'items de types quelconques.
Maille d'un maillage.
Definition Item.h:1178
FaceConnectedListViewType faces() const
Liste des faces de la maille.
Definition Item.h:1258
Vue sur les informations des faces.
Face d'une maille.
Definition Item.h:932
Cell frontCell() const
Maille devant la face (maille nulle si aucune)
Definition Item.h:1604
Cell cell(Int32 i) const
i-ème maille de la face
Definition Item.h:1617
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2)
Definition Item.h:1006
bool isSubDomainBoundary() const
Indique si la face est au bord du sous-domaine (i.e nbCell()==1)
Definition Item.h:1025
Cell backCell() const
Maille derrière la face (maille nulle si aucune)
Definition Item.h:1598
Table de hachage pour tableaux associatifs.
Data * lookupAdd(KeyTypeConstRef id, const ValueType &value, bool &is_add)
Recherche ou ajoute la valeur correspondant à la clé id.
Interface d'une famille d'entités.
virtual void notifyItemsUniqueIdChanged()=0
Notifie que les numéros uniques des entités ont été modifiées.
virtual Integer faceBuilderVersion() const =0
Version de la numérotation des faces.
Echange d'informations entre processeurs.
virtual void addSender(Int32 rank)=0
Ajoute un processeur à envoyer.
virtual Integer nbSender() const =0
Nombre de processeurs auquel on envoie.
virtual Integer nbReceiver() const =0
Nombre de processeurs dont on va réceptionner les messages.
virtual bool initializeCommunicationsMessages()=0
Calcule les communications.
virtual ISerializeMessage * messageToSend(Integer i)=0
Message destiné au ième processeur.
virtual void processExchange()=0
Effectue l'échange avec les options par défaut de ParallelExchangerOptions.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual void allGatherVariable(ConstArrayView< char > send_buf, Array< char > &recv_buf)=0
Effectue un regroupement sur tous les processeurs.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
virtual void barrier()=0
Effectue une barière.
Int32 flags() const
Flags de l'entité
bool null() const
Vrai si l'entité est l'entité nulle.
@ II_Shared
L'entité est partagée par un autre sous-domaine.
Definition ItemFlags.h:51
@ II_HasBackCell
L'entité a une maille derrière.
Definition ItemFlags.h:45
@ II_SubDomainBoundary
L'entité est à la frontière de deux sous-domaines.
Definition ItemFlags.h:52
Infos sur un type d'entité du maillage.
Gestionnaire des types d'entités de maillage.
Definition ItemTypeMng.h:66
Identifiant unique d'une entité.
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:768
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:771
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:765
Classe de base d'un élément de maillage.
Definition Item.h:83
impl::MutableItemBase mutableItemBase() const
Partie interne modifiable de l'entité.
Definition Item.h:365
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:210
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
Definition Item.h:229
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:216
constexpr bool null() const
true si l'entité est nul (i.e. non connecté au maillage)
Definition Item.h:207
impl::ItemBase itemBase() const
Partie interne de l'entité.
Definition Item.h:354
Int16 type() const
Type de l'entité
Definition Item.h:232
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Méthodes permettant de modifier ItemBase.
void setOwner(Integer suid, Int32 current_sub_domain)
Positionne le numéro du sous-domaine propriétaire de l'entité.
void addFlags(Int32 added_flags)
Ajoute les flags \added_flags à ceux de l'entité
Noeud d'un maillage.
Definition Dom.h:204
Flot de sortie lié à une String.
Construction d'un maillage de manière incrémentale.
IItemFamily * nodeFamily() override
Retourne la famille des noeuds.
IParallelMng * parallelMng() override
Gestionnaire de parallèlisme.
String name() const override
Nom du maillage.
ItemTypeMng * itemTypeMng() const override
Gestionnaire de types d'entités associé
IItemFamily * faceFamily() override
Retourne la famille des faces.
IMeshUniqueIdMng * meshUniqueIdMng() const override
Gestionnare de la numérotation des identifiants uniques.
void _computeFacesUniqueIdsParallelV2()
Calcul les numéros uniques de chaque face en parallèle V2.
void _computeFacesUniqueIdsSequential()
Calcul les numéros uniques de chaque face en séquentiel.
FaceUniqueIdBuilder(DynamicMeshIncrementalBuilder *mesh_builder)
Construit une instance pour le maillage mesh.
void _exchangeData(IParallelExchanger *exchanger, BoundaryInfosMap &boundary_infos_to_send)
void _checkNoDuplicate()
Vérifie qu'on n'a pas deux fois le même uniqueId().
void _computeFacesUniqueIdsParallelV1()
Calcul les numéros uniques de chaque face en parallèle.
Tableau associatif de ItemInternal.
static Face findFaceInNode2(Node node, Integer face_type_id, Int64ConstArrayView face_nodes_uid)
Definition ItemTools.cc:44
Classe d'aide pour la détermination en parallèle des unique_id des faces.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
void clear()
Supprime les éléments du tableau.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
virtual void allocateBuffer()=0
Alloue la mémoire du sérialiseur.
virtual void reserveSpan(eDataType dt, Int64 n)=0
Réserve de la mémoire pour n valeurs de dt.
virtual void putSpan(Span< const Real > values)
Ajoute le tableau values.
virtual void getSpan(Span< Real > values)
Récupère le tableau values.
virtual Int64 getInt64()=0
Récupère une taille.
virtual void reserve(eDataType dt, Int64 n)=0
Réserve de la mémoire pour n objets de type dt.
virtual void setMode(eMode new_mode)=0
Positionne le fonctionnement actuel.
virtual void putInt64(Int64 value)=0
Ajoute l'entier value.
virtual void flush()=0
Flush tous les flots.
Chaîne de caractères unicode.
TraceMessage pwarning() const
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage error() const
Flot pour un message d'erreur.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage fatal() const
Flot pour un message d'erreur fatale.
Vecteur 1D de données avec sémantique par valeur (style STL).
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
Integer toInteger(Real r)
Converti un Int64 en un Integer.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Retourne une interface pour transférer des messages entre rangs.
bool arcaneIsCheck()
Vrai si on est en mode vérification.
Definition Misc.cc:151
@ DT_Int64
Donnée de type entier 64 bits.
Definition DataTypes.h:44
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:638
Int32 Integer
Type représentant un entier.