Arcane  v3.15.2.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-2025 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-2025 */
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/core/IMeshUniqueIdMng.h"
21#include "arcane/core/IParallelExchanger.h"
22#include "arcane/core/IParallelMng.h"
23#include "arcane/core/ISerializeMessage.h"
24#include "arcane/core/ISerializer.h"
25#include "arcane/core/ParallelMngUtils.h"
26
27#include "arcane/mesh/DynamicMesh.h"
28#include "arcane/mesh/OneMeshItemAdder.h"
29#include "arcane/mesh/GhostLayerBuilder.h"
30#include "arcane/mesh/FaceUniqueIdBuilder.h"
31#include "arcane/mesh/ItemTools.h"
32#include "arcane/mesh/ItemsOwnerBuilder.h"
33
34#include <unordered_set>
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39namespace Arcane::mesh
40{
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45extern "C++" void
46_computeFaceUniqueIdVersion3(DynamicMesh* mesh);
47extern "C++" void
48_computeFaceUniqueIdVersion5(DynamicMesh* mesh);
49extern "C++" void
50arcaneComputeCartesianFaceUniqueId(DynamicMesh* mesh);
51
52/*---------------------------------------------------------------------------*/
53/*---------------------------------------------------------------------------*/
54
62
63/*---------------------------------------------------------------------------*/
64/*---------------------------------------------------------------------------*/
65
66void FaceUniqueIdBuilder::
67computeFacesUniqueIds()
68{
69 IParallelMng* pm = m_mesh->parallelMng();
70 Real begin_time = platform::getRealTime();
71 Integer face_version = m_mesh->meshUniqueIdMng()->faceBuilderVersion();
72 bool is_parallel = pm->isParallel();
73 info() << "Using version=" << face_version << " to compute faces unique ids"
74 << " mesh=" << m_mesh->name() << " is_parallel=" << is_parallel;
75
76 if (face_version > 5 || face_version < 0)
77 ARCANE_FATAL("Invalid value '{0}' for compute face unique ids versions: v>=0 && v<=6", face_version);
78
79 if (face_version == 5)
80 _computeFaceUniqueIdVersion5(m_mesh);
81 else if (face_version == 4)
82 arcaneComputeCartesianFaceUniqueId(m_mesh);
83 else if (face_version == 3)
84 _computeFaceUniqueIdVersion3(m_mesh);
85 else if (face_version == 0) {
86 info() << "No face renumbering";
87 }
88 else {
89 // Version 1 ou 2
90 if (is_parallel) {
91 if (face_version == 2) {
92 //PAS ENCORE PAR DEFAUT
93 info() << "Use new mesh init in FaceUniqueIdBuilder";
95 }
96 else {
97 // Version par défaut.
99 }
100 }
101 else {
103 }
104 }
105
106 Real end_time = platform::getRealTime();
107 Real diff = (Real)(end_time - begin_time);
108 info() << "TIME to compute face unique ids=" << diff;
109
110 if (arcaneIsCheck())
112
113 ItemInternalMap& faces_map = m_mesh->facesMap();
114
115 // Il faut ranger à nouveau #m_faces_map car les uniqueId() des
116 // faces ont été modifiés
117 if (face_version != 0)
119
120 bool is_verbose = m_mesh_builder->isVerbose();
121 if (is_verbose) {
122 info() << "NEW FACES_MAP after re-indexing";
123 faces_map.eachItem([&](Item face) {
124 info() << "Face uid=" << face.uniqueId() << " lid=" << face.localId();
125 });
126 }
127 // Avec la version 0 ou 5, les propriétaires ne sont pas positionnées
128 // Il faut le faire maintenant
129 if (face_version == 0 || face_version == 5) {
130 ItemsOwnerBuilder owner_builder(m_mesh);
131 owner_builder.computeFacesOwner();
132 }
133}
134
135/*---------------------------------------------------------------------------*/
136/*---------------------------------------------------------------------------*/
142{
143 info() << "Check no duplicate face uniqueId";
144 ItemInternalMap& faces_map = m_mesh->facesMap();
145 std::unordered_set<Int64> checked_faces_map;
146 faces_map.eachItem([&](Item face) {
147 ItemUniqueId uid = face.uniqueId();
148 auto p = checked_faces_map.find(uid);
149 if (p!=checked_faces_map.end()){
150 pwarning() << "Duplicate Face UniqueId=" << uid;
151 ARCANE_FATAL("Duplicate Face uniqueId={0}",uid);
152 }
153 checked_faces_map.insert(uid);
154 });
155}
156
157/*---------------------------------------------------------------------------*/
158/*---------------------------------------------------------------------------*/
168{
169 public:
170
171 T_CellFaceInfo(Int64 uid,Integer nb_back_face,Integer nb_true_boundary_face)
172 : m_unique_id(uid), m_nb_back_face(nb_back_face), m_nb_true_boundary_face(nb_true_boundary_face)
173 {
174 }
175
177 : m_unique_id(NULL_ITEM_ID), m_nb_back_face(0), m_nb_true_boundary_face(0)
178 {
179 }
180
181 public:
182
183 bool operator<(const T_CellFaceInfo& ci) const
184 {
185 return m_unique_id<ci.m_unique_id;
186 }
187
188 public:
189
190 Int64 m_unique_id;
191 Int64 m_nb_back_face;
192 Int64 m_nb_true_boundary_face;
193};
194
195/*---------------------------------------------------------------------------*/
196/*---------------------------------------------------------------------------*/
214{
215 IParallelMng* pm = m_mesh->parallelMng();
216 Integer my_rank = pm->commRank();
217 Integer nb_rank = pm->commSize();
218
219 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
220 Integer nb_local_cell = m_mesh_builder->oneMeshItemAdder()->nbCell();
221 bool is_verbose = m_mesh_builder->isVerbose();
222
224 faces_opposite_cell_uid.fill(NULL_ITEM_ID);
227
228 // Pour vérification, s'assure que tous les éléments de ce tableau
229 // sont valides, ce qui signifie que toutes les faces ont bien été
230 // renumérotés
232 faces_new_uid.fill(NULL_ITEM_ID);
233
235
236 Int64UniqueArray faces_infos;
237 faces_infos.reserve(10000);
238 ItemInternalMap& cells_map = m_mesh->cellsMap();
239 ItemInternalMap& faces_map = m_mesh->facesMap();
240 ItemInternalMap& nodes_map = m_mesh->nodesMap();
241
242
243 // NOTE: ce tableau n'est pas utile sur toutes les mailles. Il
244 // suffit qu'il contienne les mailles dont on a besoin, c'est à dire
245 // les notres + celles connectées à une de nos faces. Une table
246 // de hashage sera plus appropriée.
247 HashTableMapT<Int64,Int64> cells_first_face_uid(m_mesh_builder->oneMeshItemAdder()->nbCell()*2,true);
248
249 // Rassemble les données des autres processeurs dans recv_cells;
250 // Pour éviter que les tableaux ne soient trop gros, on procède en plusieurs
251 // étapes.
252 // Chaque sous-domaine construit sa liste de faces frontières, avec pour
253 // chaque face:
254 // - son type
255 // - la liste de ses noeuds,
256 // - le numéro unique de sa maille
257 // - le propriétaire de sa maille
258 // - son indice dans sa maille
259 // Cette liste sera ensuite envoyée à tous les sous-domaines.
260 {
261 ItemTypeMng* itm = m_mesh->itemTypeMng();
262
264
265 faces_map.eachItem([&](Face face) {
266 bool boundary_val = face.isSubDomainBoundary();
267 if (boundary_val)
268 faces_local_id.add(face.localId());
269 });
270
272 Int64 global_nb_boundary_face = pm->reduce(Parallel::ReduceSum,(Int64)nb_sub_domain_boundary_face);
273 debug() << "NB BOUNDARY FACE=" << nb_sub_domain_boundary_face
274 << " NB_FACE=" << nb_local_face
275 << " GLOBAL_NB_BOUNDARY_FACE=" << global_nb_boundary_face;
276
277
280
281 // Calcule la taille d'un bloc d'envoi
282 // La mémoire nécessaire pour une face est égale à nb_node + 4.
283 // Si on suppose qu'on a des quadrangles en général, cela
284 // fait 8 Int64 par face, soit 64 octets par face.
285 // La mémoire nécessaire pour tout envoyer est donc 64 * global_nb_boundary_face.
286 // step_size * nb_proc * 64 octets.
287 // Le step_size par défaut est calculé pour que la mémoire nécessaire
288 // soit de l'ordre de 100 Mo pour chaque message.
289 Int64 step_size = 1500000;
291 FaceInfoListView faces(m_mesh->faceFamily());
292 for( Integer i_phase=0; i_phase<nb_phase; ++i_phase ){
296 if (i_phase+1==nb_phase)
299
300 faces_infos2.clear();
302 Face face(faces[faces_local_id[i_face]]);
305 faces_infos2.add(face.type());
306 for( Node node : face.nodes() )
307 faces_infos2.add(node.uniqueId().asInt64());
308
309 //info() << " ADD FACE lid=" << face->localId();
310
311 Cell cell = face.cell(0);
312 faces_infos2.add(cell.uniqueId().asInt64());
313 faces_infos2.add(cell.owner());
314
315 Integer face_index_in_cell = 0;
316 if (has_back_cell){
317 for( Face current_face_in_cell : cell.faces() ){
318 if (current_face_in_cell==face)
319 break;
320 if (current_face_in_cell.backCell()==cell)
322 }
323 }
324 else
325 face_index_in_cell = NULL_ITEM_ID;
327 }
328 faces_infos2.add(IT_NullType); // Pour dire que la liste s'arête
329
331
332 info() << "Number of face bytes received: " << recv_faces_infos.size()
333 << " phase=" << i_phase << "/" << nb_phase
334 << " first_face=" << first_face_to_send
335 << " last_face=" << last_face_to_send
336 << " nb=" << real_nb_face_to_send;
337
338 Integer recv_faces_infos_index = 0;
339
340 for( Integer i_sub_domain=0; i_sub_domain<nb_rank; ++i_sub_domain ){
341 bool is_end = false;
342 // Il ne faut pas lire les infos qui viennent de moi
343 if (i_sub_domain==my_rank){
345 continue;
346 }
347 // Désérialise les infos de chaque sous-domaine
348 while (!is_end){
351 if (face_type==IT_NullType){
352 is_end = true;
353 break;
354 }
355 ItemTypeInfo* itt = itm->typeFromId(face_type);
356 Integer face_nb_node = itt->nbLocalNode();
358
366
367 Node node = nodes_map.tryFind(faces_nodes_uid[0]);
368 // Si la face n'existe pas dans mon sous-domaine, elle ne m'intéresse pas
369 if (node.null())
370 continue;
371 Face face = ItemTools::findFaceInNode2(node, face_type, faces_nodes_uid);
372 if (face.null())
373 continue;
375 faces_opposite_cell_uid[face.localId()] = cell_uid;
377 faces_opposite_cell_owner[face.localId()] = cell_owner;
378 cells_first_face_uid.add(cell_uid,-1);
379 }
380 }
381 }
382 info() << "Number of faces on the subdomain interface: "
384 }
385
386 // Cherche le uniqueId max des mailles sur tous les sous-domaines.
387 Int64 max_cell_uid = 0;
388 Int32 max_cell_local_id = 0;
389 cells_map.eachItem([&](Item cell) {
390 Int64 cell_uid = cell.uniqueId().asInt64();
391 Int32 cell_local_id = cell.localId();
392 if (cell_uid>max_cell_uid)
393 max_cell_uid = cell_uid;
396 });
397 Int64 global_max_cell_uid = pm->reduce(Parallel::ReduceMax,max_cell_uid);
398 debug() << "GLOBAL MAX CELL UID=" << global_max_cell_uid;
399
400
404 my_cells_nb_back_face.fill(0);
405
406 cells_map.eachItem([&](Cell cell) {
407 Int64 cell_uid = cell.uniqueId().asInt64();
408 Int32 cell_local_id = cell.localId();
409 Integer nb_back_face = 0;
410 Integer nb_true_boundary_face = 0;
411 for( Face face : cell.faces() ){
412 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
413 if (face.backCell()==cell)
414 ++nb_back_face;
415 else if (face.nbCell()==1 && opposite_cell_uid==NULL_ITEM_ID){
417 }
418 }
421 });
422 std::sort(std::begin(my_cells_faces_info),std::end(my_cells_faces_info));
423
424 {
425 Integer nb_phase = 16;
426 Integer first_cell_index_to_send = 0;
427 Int64 current_face_uid = 0;
428
429 for( Integer i_phase=0; i_phase<nb_phase; ++i_phase ){
433 if (i_phase+1==nb_phase)
435
436 //Integer last_cell_index_to_send = first_cell_index_to_send;
437 Integer nb_cell_to_send = 0;
438 for( Integer zz=first_cell_index_to_send, zs=my_cells_faces_info.size(); zz<zs; ++zz ){
439 if (my_cells_faces_info[zz].m_unique_id<=last_uid_to_send)
441 else
442 break;
443 }
444 debug() << "FIRST TO SEND=" << first_cell_index_to_send
445 << " NB=" << nb_cell_to_send
446 << " first_uid=" << first_uid_to_send
447 << " last_uid=" << last_uid_to_send;
448
450 Int64* begin_array = reinterpret_cast<Int64*>(begin_cell_array);
451 Integer begin_size = nb_cell_to_send*3;
452
454
458
459 info() << "Infos faces (received) nb_int64=" << recv_cells_faces_infos.size();
460 Integer recv_nb_cell = recv_cells_faces_infos.size() / 3;
461
462 // NOTE: comme on connait le uid min et max possible, on peut optimiser en
463 // creant un tableau dimensionne avec comme borne ce min et ce max et
464 // remplir directement les elements de ce tableau. Comme cela, on
465 // n'a pas besoin de tri.
467 for( Integer i=0; i<recv_nb_cell; ++i ){
468 Int64 cell_uid = recv_cells_faces_infos[i*3];
469 global_cells_faces_info[i].m_unique_id = cell_uid;
470 global_cells_faces_info[i].m_nb_back_face = recv_cells_faces_infos[(i*3) +1];
471 global_cells_faces_info[i].m_nb_true_boundary_face = recv_cells_faces_infos[(i*3) +2];
472 }
473 info() << "Sorting the faces nb=" << global_cells_faces_info.size();
474 std::sort(std::begin(global_cells_faces_info),std::end(global_cells_faces_info));
475
476 for( Integer i=0; i<recv_nb_cell; ++i ){
477 Int64 cell_uid = global_cells_faces_info[i].m_unique_id;
478 if (cells_map.hasKey(cell_uid) || cells_first_face_uid.hasKey(cell_uid))
480 current_face_uid += global_cells_faces_info[i].m_nb_back_face + global_cells_faces_info[i].m_nb_true_boundary_face;
481 }
482 }
483 }
484
485 cells_map.eachItem([&](Cell cell) {
486 Int64 cell_uid = cell.uniqueId();
487 Int32 cell_local_id = cell.localId();
488 Integer num_local_face = 0;
489 Integer num_true_boundary_face = 0;
490 for( Face face : cell.faces() ){
491 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
492 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
493 if (face.backCell()==cell){
494 if (!cells_first_face_uid.hasKey(cell_uid))
495 fatal() << "NO KEY 0 for cell_uid=" << cell_uid;
497 face.mutableItemBase().setOwner(my_rank,my_rank);
499 }
500 else if (face.nbCell()==1){
501 if (opposite_cell_uid==NULL_ITEM_UNIQUE_ID){
502 // Il s'agit d'une face frontière du domaine initial
503 if (!cells_first_face_uid.hasKey(cell_uid))
504 fatal() << "NO KEY 1 for cell_uid=" << cell_uid;
507 face.mutableItemBase().setOwner(my_rank,my_rank);
508 }
509 else{
511 fatal() << "NO KEY 1 for cell_uid=" << cell_uid << " opoosite=" << opposite_cell_uid;
513 face.mutableItemBase().setOwner(faces_opposite_cell_owner[face.localId()],my_rank);
514 }
515 }
516 if (face_new_uid!=NULL_ITEM_UNIQUE_ID){
517 faces_new_uid[face.localId()] = face_new_uid;
518 face.mutableItemBase().setUniqueId(face_new_uid);
519 }
520 }
521 });
522
523 // Vérifie que toutes les faces ont été réindéxées
524 {
525 Integer nb_error = 0;
526 for( Integer i=0, is=nb_local_face; i<is; ++i ){
527 if (faces_new_uid[i]==NULL_ITEM_UNIQUE_ID){
528 ++nb_error;
529 if (nb_error<10)
530 error() << "The face lid=" << i << " has not been re-indexed.";
531 }
532 }
533 if (nb_error!=0)
534 ARCANE_FATAL("Some ({0}) faces have not been reindexed",nb_error);
535 }
536
537 if (is_verbose){
539 cells_map.eachItem([&](Cell cell) {
540 Int64 cell_uid = cell.uniqueId().asInt64();
541 Integer face_index = 0;
542 for( Face face : cell.faces() ){
543 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
544 bool shared = false;
545 bool true_boundary = false;
546 bool internal_other = false;
547 if (face.backCell()==cell){
548 }
549 else if (face.nbCell()==1){
550 if (opposite_cell_uid==NULL_ITEM_ID)
551 true_boundary = true;
552 else
553 shared = true;
554 }
555 else{
556 internal_other = true;
557 opposite_cell_uid = face.backCell().uniqueId().asInt64();
558 }
559 ostr() << "NEW UNIQUE ID FOR FACE"
560 << " lid=" << face.localId()
561 << " cell=" << cell_uid
562 << " face=" << face.uniqueId()
563 << " nbcell=" << face.nbCell()
564 << " cellindex=" << face_index << " (";
565 for( Node node : face.nodes() )
566 ostr() << ' ' << node.uniqueId();
567 ostr() << ")";
568 if (internal_other)
569 ostr() << " internal-other";
570 if (true_boundary)
571 ostr() << " true-boundary";
572 if (opposite_cell_uid!=NULL_ITEM_ID){
573 ostr() << " opposite " << opposite_cell_uid;
574 }
575 if (shared)
576 ostr() << " (shared)";
577 ostr() << "\n";
578 ++face_index;
579 }
580 });
581 info() << ostr.str();
582 String file_name("faces_uid.");
584 std::ofstream ofile(file_name.localstr());
585 ofile << ostr.str();
586 }
587}
588
589/*---------------------------------------------------------------------------*/
590/*---------------------------------------------------------------------------*/
597{
599 Int32 sd = i_map.data()->key();
600 exchanger->addSender(sd);
601 }
603 Integer nb_sender = exchanger->nbSender();
604 Integer nb_receiver = exchanger->nbReceiver();
605 info() << "NB_SEND=" << nb_sender << " NB_RECV=" << nb_receiver;
606 Integer total = nb_sender+nb_receiver;
607 Integer global_total = exchanger->parallelMng()->reduce(Parallel::ReduceSum,total);
608 info() << "GLOBAL_NB_MESSAGE=" << global_total;
609
610 {
611 for( Integer i=0, ns=exchanger->nbSender(); i<ns; ++i ){
612 ISerializeMessage* sm = exchanger->messageToSend(i);
613 Int32 rank = sm->destination().value();
614 ISerializer* s = sm->serializer();
616 Integer nb_info = infos.size();
617 s->setMode(ISerializer::ModeReserve);
618 s->reserveInt64(1); // Pour le nombre d'elements
619 s->reserveSpan(eBasicDataType::Int64,nb_info); // Pour les elements
620 s->allocateBuffer();
622 s->putInt64(nb_info);
623 s->putSpan(infos);
624 }
625 }
626 exchanger->processExchange();
627 debug() << "END EXCHANGE";
628}
629
630template<typename DataType>
632{
633 public:
634 private:
635
636 class MyInfo
637 {
638 public:
639 MyInfo(const DataType& d,Integer n) : data(d), next_index(n) {}
640 public:
641 DataType data;
642 Integer next_index;
643 };
644
645 public:
646 ItemInfoMultiList() : m_last_index(5000,true) {}
647
648 public:
649
650 void add(Int64 node_uid,const DataType& data)
651 {
652 Integer current_index = m_values.size();
653
654 bool is_add = false;
655 HashTableMapT<Int64,Int32>::Data* d = m_last_index.lookupAdd(node_uid,-1,is_add);
656
657 m_values.add(MyInfo(data,d->value()));
658 d->value() = current_index;
659 }
660
661 public:
662 UniqueArray<MyInfo> m_values;
663 HashTableMapT<Int64,Int32> m_last_index;
664};
665
666/*---------------------------------------------------------------------------*/
667/*---------------------------------------------------------------------------*/
677{
678 IParallelMng* pm = m_mesh->parallelMng();
679 Integer my_rank = pm->commRank();
680 Integer nb_rank = pm->commSize();
681
682 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
683 //Integer nb_local_cell = m_mesh_builder->nbCell();
684 //bool is_verbose = m_mesh_builder->isVerbose();
685
687 faces_opposite_cell_uid.fill(NULL_ITEM_ID);
690
691 // Pour vérification, s'assure que tous les éléments de ce tableau
692 // sont valides, ce qui signifie que toutes les faces ont bien été
693 // renumérotés
695 faces_new_uid.fill(NULL_ITEM_ID);
696
697 Int64UniqueArray faces_infos;
698 faces_infos.reserve(10000);
699 ItemInternalMap& faces_map = m_mesh->facesMap();
700 ItemInternalMap& nodes_map = m_mesh->nodesMap();
701
702
703 // NOTE: ce tableau n'est pas utile sur toutes les mailles. Il
704 // suffit qu'il contienne les mailles dont on a besoin, c'est à dire
705 // les notres + celles connectées à une de nos faces.
706 HashTableMapT<Int32,Int32> cell_first_face_uid(m_mesh_builder->oneMeshItemAdder()->nbCell()*2,true);
707
708 // Rassemble les données des autres processeurs dans recv_cells;
709 // Pour éviter que les tableaux ne soient trop gros, on procède en plusieurs
710 // étapes.
711 // Chaque sous-domaine construit sa liste de faces frontières, avec pour
712 // chaque face:
713 // - son type
714 // - la liste de ses noeuds,
715 // - le numéro unique de sa maille
716 // - le propriétaire de sa maille
717 // - son indice dans sa maille
718 // Cette liste sera ensuite envoyée à tous les sous-domaines.
719 ItemTypeMng* itm = m_mesh->itemTypeMng();
720
721 // Détermine le unique id max des noeuds
722 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
723 nodes_map.eachItem([&](Item node) {
724 Int64 node_uid = node.uniqueId();
725 if (node_uid>my_max_node_uid)
726 my_max_node_uid = node_uid;
727 });
728 Int64 global_max_node_uid = pm->reduce(Parallel::ReduceMax,my_max_node_uid);
729 debug() << "NODE_UID_INFO: MY_MAX_UID=" << my_max_node_uid
730 << " GLOBAL=" << global_max_node_uid;
731
732 //TODO: choisir bonne valeur pour initialiser la table
735 info() << "NB_CORE modulo=" << uid_to_subdomain_converter.modulo();
739
740 // Marque tous les noeuds frontieres car ce sont ceux qu'il faudra envoyer
741 faces_map.eachItem([&](Face face) {
742 Integer face_nb_cell = face.nbCell();
743 if (face_nb_cell==1){
744 for( Node node : face.nodes() )
745 is_boundary_nodes[node.localId()] = true;
746 }
747 });
748
749 // Détermine la liste des faces frontières
750 faces_map.eachItem([&](Face face) {
751 Node first_node = face.node(0);
752 Int64 first_node_uid = first_node.uniqueId();
754 Int32 dest_rank = -1;
755 if (!is_boundary_nodes[first_node.localId()]){
756 v = nodes_info.lookupAdd(first_node_uid)->value();
757 }
758 else{
760 v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
761 }
762 v.add(first_node_uid); // 0
763 v.add(my_rank); // 1
764 v.add(face.uniqueId()); // 2
765 v.add(face.type()); // 3
766 Cell back_cell = face.backCell();
767 Cell front_cell = face.frontCell();
768 if (back_cell.null()) // 4 : only used for debug
769 v.add(NULL_ITEM_UNIQUE_ID);
770 else
771 v.add(back_cell.uniqueId());
772 if (front_cell.null()) // 5 : only used for debug
773 v.add(NULL_ITEM_UNIQUE_ID);
774 else
775 v.add(front_cell.uniqueId());
776 for( Integer z=0, zs=face.nbNode(); z<zs; ++z )
777 v.add(face.node(z).uniqueId());
778 });
779
780 // Positionne la liste des envoies
782 _exchangeData(exchanger.get(),boundary_infos_to_send);
783
784 {
785 Integer nb_receiver = exchanger->nbReceiver();
786 debug() << "NB RECEIVER=" << nb_receiver;
788 for( Integer i=0; i<nb_receiver; ++i ){
789 ISerializeMessage* sm = exchanger->messageToReceive(i);
790 //Int32 orig_rank = sm->destSubDomain();
791 ISerializer* s = sm->serializer();
793 Int64 nb_info = s->getInt64();
794 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
795 received_infos.resize(nb_info);
797 //if ((nb_info % 3)!=0)
798 //fatal() << "info size can not be divided by 3";
799 Integer z =0;
800 while(z<nb_info){
801 Int64 node_uid = received_infos[z+0];
802 Int32 face_type = (Int32)received_infos[z+3];
803 ItemTypeInfo* itt = itm->typeFromId(face_type);
804 Integer face_nb_node = itt->nbLocalNode();
805 Int64Array& a = nodes_info.lookupAdd(node_uid)->value();
807 z += 6;
808 z += face_nb_node;
809 }
810 }
811 Integer my_max_face_node = 0;
812 for( HashTableMapT<Int64,SharedArray<Int64> >::Enumerator inode(nodes_info); ++inode; ){
814 Integer nb_info = a.size();
815 Integer z = 0;
816 Integer node_nb_face = 0;
817 while(z<nb_info){
818 ++node_nb_face;
819 Int32 face_type = (Int32)a[z+3];
820 ItemTypeInfo* itt = itm->typeFromId(face_type);
821 Integer face_nb_node = itt->nbLocalNode();
822 z += 6;
823 z += face_nb_node;
824 }
826 }
827 Integer global_max_face_node = pm->reduce(Parallel::ReduceMax,my_max_face_node);
828 debug() << "GLOBAL MAX FACE NODE=" << global_max_face_node;
829 // OK, maintenant donne comme uid de la face (node_uid * global_max_face_node + index)
830 IntegerUniqueArray indexes;
832
833 for( HashTableMapT<Int64,SharedArray<Int64> >::Enumerator inode(nodes_info); ++inode; ){
835 Integer nb_info = a.size();
836 Integer z = 0;
837 Integer node_nb_face = 0;
838 indexes.clear();
839 while(z<nb_info){
840 Int64 node_uid = a[z+0];
841 Int32 sender_rank = (Int32)a[z+1];
842 Int64 face_uid = a[z+2];
843 Int32 face_type = (Int32)a[z+3];
844 ItemTypeInfo* itt = itm->typeFromId(face_type);
845 Integer face_nb_node = itt->nbLocalNode();
846
847 // Regarde si la face est déjà dans la liste:
848 Integer face_index = node_nb_face;
850 for( Integer y=0; y<node_nb_face; ++y ){
851 if (memcmp(&a[indexes[y]+6],&a[z+6],sizeof(Int64)*face_nb_node)==0){
852 face_index = y;
853 face_new_owner = (Int32)a[indexes[y]+1];
854 }
855 }
856 Int64 face_new_uid = (node_uid * global_max_face_node) + face_index;
857 Int64Array& v = boundary_infos_to_send.lookupAdd(sender_rank)->value();
858 // Indique au propriétaire de cette face son nouvel uid
859 v.add(face_uid);
860 v.add(face_new_uid);
861 v.add(face_new_owner);
862 indexes.add(z);
863 z += 6;
864 z += face_nb_node;
865 ++node_nb_face;
866 }
868 }
869 }
871
872 _exchangeData(exchanger.get(),boundary_infos_to_send);
873 {
874 Integer nb_receiver = exchanger->nbReceiver();
875 debug() << "NB RECEIVER=" << nb_receiver;
877 for( Integer i=0; i<nb_receiver; ++i ){
878 ISerializeMessage* sm = exchanger->messageToReceive(i);
879 ISerializer* s = sm->serializer();
881 Int64 nb_info = s->getInt64();
882 received_infos.resize(nb_info);
884 if ((nb_info % 3)!=0)
885 ARCANE_FATAL("info size can not be divided by 3 v={0}",nb_info);;
886 Int64 nb_item = nb_info / 3;
887 for (Int64 z=0; z<nb_item; ++z ){
888 Int64 old_uid = received_infos[(z*3)];
889 Int64 new_uid = received_infos[(z*3)+1];
890 Int32 new_owner = (Int32)received_infos[(z*3)+2];
892 if (face.null())
893 ARCANE_FATAL("Can not find own face uid={0}", old_uid);
894 face.setUniqueId(new_uid);
896 }
897 }
898 }
899
900 traceMng()->flush();
901 pm->barrier();
902 debug() << "END OF TEST NEW FACE COMPUTE";
903 return;
904}
905
906/*---------------------------------------------------------------------------*/
907/*---------------------------------------------------------------------------*/
915{
916 bool is_verbose = m_mesh_builder->isVerbose();
917
918 ItemInternalMap& cells_map = m_mesh->cellsMap();
919
920 // En séquentiel, les uniqueId() des mailles ne peuvent dépasser la
921 // taille des Integers même en 32bits.
922 Int32 max_uid = 0;
923 cells_map.eachItem([&](Item cell) {
924 Int32 cell_uid = cell.uniqueId().asInt32();
925 if (cell_uid>max_uid)
926 max_uid = cell_uid;
927 });
928 info() << "Max uid=" << max_uid;
929 Integer nb_computed = max_uid + 1;
933
934 cells_map.eachItem([&](Cell cell) {
935 Int32 cell_uid = cell.uniqueId().asInt32();
936 Integer nb_num_back_face = 0;
937 Integer nb_true_boundary_face = 0;
938 for( Face face : cell.faces() ){
939 if (face.backCell()==cell)
941 else if (face.nbCell()==1){
943 }
944 }
947 });
948
949 Integer current_face_uid = 0;
950 for( Integer i=0; i<nb_computed; ++i ){
953 }
954
955 if (is_verbose){
956 cells_map.eachItem([&](Item cell) {
957 Int32 i = cell.uniqueId().asInt32();
958 info() << "Recv: Cell FaceInfo celluid=" << i
959 << " firstfaceuid=" << cell_first_face_uid[i]
960 << " nbback=" << cell_nb_num_back_face[i]
961 << " nbbound=" << cell_true_boundary_face[i];
962 });
963 }
964
965 cells_map.eachItem([&](Cell cell) {
966 Int32 cell_uid = cell.uniqueId().asInt32();
967 Integer nb_num_back_face = 0;
968 Integer nb_true_boundary_face = 0;
969 for( Face face : cell.faces() ){
970 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
971 if (face.backCell()==cell){
974 }
975 else if (face.nbCell()==1){
978 }
979 if (face_new_uid!=NULL_ITEM_UNIQUE_ID){
980 face.mutableItemBase().setUniqueId(face_new_uid);
981 }
982 }
983 });
984
985 if (is_verbose){
987 cells_map.eachItem([&](Cell cell) {
988 Integer face_index = 0;
989 for( Face face : cell.faces() ){
990 Int64 opposite_cell_uid = NULL_ITEM_UNIQUE_ID;
991 bool true_boundary = false;
992 bool internal_other = false;
993 if (face.backCell()==cell){
994 }
995 else if (face.nbCell()==1){
996 true_boundary = true;
997 }
998 else{
999 internal_other = true;
1000 opposite_cell_uid = face.backCell().uniqueId().asInt64();
1001 }
1002 ostr() << "NEW LOCAL ID FOR CELLFACE cell_uid=" << cell.uniqueId() << ' '
1003 << face_index << " uid=" << face.uniqueId() << " (";
1004 for( Node node : face.nodes() )
1005 ostr() << ' ' << node.uniqueId();
1006 ostr() << ")";
1007 if (internal_other)
1008 ostr() << " internal-other";
1009 if (true_boundary)
1010 ostr() << " true-boundary";
1011 if (opposite_cell_uid!=NULL_ITEM_ID)
1012 ostr() << " opposite " << opposite_cell_uid;
1013 ostr() << '\n';
1014 ++face_index;
1015 }
1016 });
1017 info() << ostr.str();
1018 }
1019}
1020
1021/*---------------------------------------------------------------------------*/
1022/*---------------------------------------------------------------------------*/
1023
1024} // End namespace Arcane::mesh
1025
1026/*---------------------------------------------------------------------------*/
1027/*---------------------------------------------------------------------------*/
#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:149
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 Item.h:564
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 reserve(Int64 new_capacity)
Réserve le mémoire pour new_capacity éléments.
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 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.
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:68
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:691
Int32 Integer
Type représentant un entier.