Arcane  v3.16.2.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
EdgeUniqueIdBuilder.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/* EdgeUniqueIdBuilder.cc (C) 2000-2025 */
9/* */
10/* Construction des identifiants uniques des arêtes. */
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
19#include "arcane/mesh/DynamicMesh.h"
20#include "arcane/mesh/EdgeUniqueIdBuilder.h"
21#include "arcane/mesh/GhostLayerBuilder.h"
22#include "arcane/mesh/OneMeshItemAdder.h"
23#include "arcane/mesh/ItemsOwnerBuilder.h"
24
25#include "arcane/core/IParallelExchanger.h"
26#include "arcane/core/IParallelMng.h"
27#include "arcane/core/ISerializeMessage.h"
28#include "arcane/core/ISerializer.h"
29#include "arcane/core/ParallelMngUtils.h"
30#include "arcane/core/IMeshUniqueIdMng.h"
31
32#include <functional>
33
34/*---------------------------------------------------------------------------*/
35/*---------------------------------------------------------------------------*/
36
37namespace Arcane::mesh
38{
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
42
45: TraceAccessor(mesh_builder->mesh()->traceMng())
46, m_mesh(mesh_builder->mesh())
47, m_mesh_builder(mesh_builder)
48{
49}
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
54/*---------------------------------------------------------------------------*/
55/*---------------------------------------------------------------------------*/
56
57void EdgeUniqueIdBuilder::
58computeEdgesUniqueIds()
59{
60 double begin_time = platform::getRealTime();
61
62 Int32 edge_version = m_mesh->meshUniqueIdMng()->edgeBuilderVersion();
63
64 info() << "Using version=" << edge_version << " to compute edges unique ids"
65 << " mesh=" << m_mesh->name();
66 bool has_renumbering = true;
67 if (edge_version == 1)
68 _computeEdgesUniqueIdsParallel3();
69 else if (edge_version == 2)
70 _computeEdgesUniqueIdsParallelV2();
71 else if (edge_version == 3)
72 _computeEdgesUniqueIdsParallel64bit();
73 else if (edge_version == 0) {
74 has_renumbering = false;
75 info() << "No renumbering for edges";
76 }
77 else
78 ARCANE_FATAL("Invalid valid version '{0}'. Valid values are 0, 1, 2 or 3");
79
80 double end_time = platform::getRealTime();
81 Real diff = static_cast<Real>(end_time - begin_time);
82 info() << "TIME to compute edge unique ids=" << diff;
83
84 ItemInternalMap& edges_map = m_mesh->edgesMap();
85
86 // Il faut ranger à nouveau #m_edges_map si les uniqueId() des
87 // edges ont été modifiés.
88 if (has_renumbering)
89 edges_map.notifyUniqueIdsChanged();
90
91 if (m_mesh_builder->isVerbose()) {
92 info() << "NEW EDGES_MAP after re-indexing";
93 edges_map.eachItem([&](Item edge) {
94 info() << "Edge uid=" << edge.uniqueId() << " lid=" << edge.localId();
95 });
96 }
97
98 // S'il n'y a pas de renumérotation, il n'y a pas non de
99 // calcul des propriétaires. Il faut donc le faire maintenant
100 if (!has_renumbering) {
101 ItemsOwnerBuilder owner_builder(m_mesh);
102 owner_builder.computeEdgesOwner();
103 }
104}
105
106/*---------------------------------------------------------------------------*/
107/*---------------------------------------------------------------------------*/
116class T_CellEdgeInfo
117{
118 public:
119
120 T_CellEdgeInfo(Int64 uid, Integer nb_back_edge, Integer nb_true_boundary_edge)
121 : m_unique_id(uid)
122 , m_nb_back_edge(nb_back_edge)
123 , m_nb_true_boundary_edge(nb_true_boundary_edge)
124 {
125 }
126
127 T_CellEdgeInfo()
128 : m_unique_id(NULL_ITEM_ID)
129 , m_nb_back_edge(0)
130 , m_nb_true_boundary_edge(0)
131 {
132 }
133
134 public:
135
136 bool operator<(const T_CellEdgeInfo& ci) const
137 {
138 return m_unique_id < ci.m_unique_id;
139 }
140
141 public:
142
143 Int64 m_unique_id;
144 Int64 m_nb_back_edge;
145 Int64 m_nb_true_boundary_edge;
146};
147
148template <typename DataType>
149class ItemInfoMultiList
150{
151 public:
152 private:
153
154 class MyInfo
155 {
156 public:
157
158 MyInfo(const DataType& d, Integer n)
159 : data(d)
160 , next_index(n)
161 {}
162
163 public:
164
165 DataType data;
166 Integer next_index;
167 };
168
169 public:
170
171 ItemInfoMultiList()
172 : m_last_index(5000, true)
173 {}
174
175 public:
176
177 void add(Int64 node_uid, const DataType& data)
178 {
179 Integer current_index = m_values.size();
180
181 bool is_add = false;
182 HashTableMapT<Int64, Int32>::Data* d = m_last_index.lookupAdd(node_uid, -1, is_add);
183
184 m_values.add(MyInfo(data, d->value()));
185 d->value() = current_index;
186 }
187
188 public:
189
190 UniqueArray<MyInfo> m_values;
191 HashTableMapT<Int64, Int32> m_last_index;
192};
193
194/*---------------------------------------------------------------------------*/
195/*---------------------------------------------------------------------------*/
196
197class Parallel3EdgeUniqueIdBuilder
198: public TraceAccessor
199{
200 using BoundaryInfosMap = std::unordered_map<Int32, SharedArray<Int64>>;
201
202 public:
203
204 Parallel3EdgeUniqueIdBuilder(ITraceMng* tm, DynamicMeshIncrementalBuilder* mesh_builder,
205 Int64 max_node_uid);
206
207 public:
208
209 void compute();
210
211 private:
212
213 DynamicMesh* m_mesh = nullptr;
214 DynamicMeshIncrementalBuilder* m_mesh_builder = nullptr;
215 IParallelMng* m_parallel_mng = nullptr;
216 const Int32 m_my_rank = A_NULL_RANK;
217 const Int32 m_nb_rank = A_NULL_RANK;
218 BoundaryInfosMap m_boundary_infos_to_send;
219 NodeUidToSubDomain m_uid_to_subdomain_converter;
220 std::unordered_map<Int64, SharedArray<Int64>> m_nodes_info;
221 UniqueArray<bool> m_is_boundary_nodes;
222 bool m_is_verbose = false;
223
224 private:
225
226 void _exchangeData(IParallelExchanger* exchanger);
227 void _addEdgeBoundaryInfo(Edge edge);
228 void _computeEdgesUniqueId();
229 void _sendInfosToOtherRanks();
230};
231
232/*---------------------------------------------------------------------------*/
233/*---------------------------------------------------------------------------*/
234
235Parallel3EdgeUniqueIdBuilder::
236Parallel3EdgeUniqueIdBuilder(ITraceMng* tm, DynamicMeshIncrementalBuilder* mesh_builder, Int64 max_node_uid)
237: TraceAccessor(tm)
238, m_mesh(mesh_builder->mesh())
239, m_mesh_builder(mesh_builder)
240, m_parallel_mng(m_mesh->parallelMng())
241, m_my_rank(m_parallel_mng->commRank())
242, m_nb_rank(m_parallel_mng->commSize())
243, m_uid_to_subdomain_converter(max_node_uid, m_nb_rank)
244, m_is_verbose(m_mesh_builder->isVerbose())
245{
246}
247
248/*---------------------------------------------------------------------------*/
249/*---------------------------------------------------------------------------*/
256{
257 for (const auto& [key, value] : m_boundary_infos_to_send) {
258 exchanger->addSender(key);
259 }
261 {
262 for (Integer i = 0, ns = exchanger->nbSender(); i < ns; ++i) {
263 ISerializeMessage* sm = exchanger->messageToSend(i);
264 Int32 rank = sm->destination().value();
265 ISerializer* s = sm->serializer();
266 ConstArrayView<Int64> infos = m_boundary_infos_to_send[rank];
267 Integer nb_info = infos.size();
268 s->setMode(ISerializer::ModeReserve);
269 s->reserveInt64(1); // Pour le nombre d'éléments
270 s->reserveSpan(eBasicDataType::Int64, nb_info); // Pour les elements
271 s->allocateBuffer();
273 //info() << " SEND1 rank=" << rank << " nb_info=" << nb_info;
274 s->putInt64(nb_info);
275 s->putSpan(infos);
276 }
277 }
278 exchanger->processExchange();
279 debug() << "END EXCHANGE";
280}
281
282/*---------------------------------------------------------------------------*/
283/*---------------------------------------------------------------------------*/
284
285void Parallel3EdgeUniqueIdBuilder::
286_addEdgeBoundaryInfo(Edge edge)
287{
288 Node first_node = edge.node(0);
289 Int64 first_node_uid = first_node.uniqueId();
291 Int32 dest_rank = -1;
292 if (!m_is_boundary_nodes[first_node.localId()]) {
293 v = m_nodes_info[first_node_uid];
294 }
295 else {
296 dest_rank = m_uid_to_subdomain_converter.uidToRank(first_node_uid);
297 v = m_boundary_infos_to_send[dest_rank];
298 }
299 v.add(first_node_uid); // 0
300 v.add(m_my_rank); // 1
301 v.add(edge.uniqueId()); // 2
302 v.add(edge.type()); // 3
303 v.add(NULL_ITEM_UNIQUE_ID); // 4 : only used for debug
304 v.add(NULL_ITEM_UNIQUE_ID); // 5 : only used for debug
305 if (m_is_verbose)
306 info() << "Edge uid=" << edge.uniqueId() << " n0,n1=" << edge.node(0).uniqueId() << "," << edge.node(1).uniqueId()
307 << " n0=" << ItemPrinter(edge.node(0)) << " n1=" << ItemPrinter(edge.node(1)) << " dest_rank=" << dest_rank;
308 for (Node edge_node : edge.nodes())
309 v.add(edge_node.uniqueId());
310}
311
312/*---------------------------------------------------------------------------*/
313/*---------------------------------------------------------------------------*/
329compute()
330{
331 IParallelMng* pm = m_mesh->parallelMng();
332
333 Integer nb_local_edge = m_mesh_builder->oneMeshItemAdder()->nbEdge();
334 info() << "ComputeEdgesUniqueIdsParallel3 nb_edge=" << nb_local_edge;
335
336 UniqueArray<Int64> edges_opposite_cell_uid(nb_local_edge);
337 edges_opposite_cell_uid.fill(NULL_ITEM_ID);
338 UniqueArray<Int32> edges_opposite_cell_index(nb_local_edge);
339 UniqueArray<Int32> edges_opposite_cell_owner(nb_local_edge);
340
341 // Pour vérification, s'assure que tous les éléments de ce tableau
342 // sont valides, ce qui signifie que toutes les edges ont bien été
343 // renumérotés.
344 UniqueArray<Int64> edges_new_uid(nb_local_edge);
345 edges_new_uid.fill(NULL_ITEM_UNIQUE_ID);
346
347 UniqueArray<Int64> edges_infos;
348 edges_infos.reserve(10000);
349 ItemInternalMap& edges_map = m_mesh->edgesMap();
350 ItemInternalMap& faces_map = m_mesh->facesMap(); // utilisé pour détecter le bord
351
352 // NOTE : ce tableau n'est pas utile sur toutes les mailles. Il
353 // suffit qu'il contienne les mailles dont on a besoin, c'est-à-dire
354 // les nôtres + celles connectées à une de nos edges.
355 HashTableMapT<Int32, Int32> cell_first_edge_uid(m_mesh_builder->oneMeshItemAdder()->nbCell() * 2, true);
356
357 // Rassemble les données des autres processeurs dans recv_cells;
358 // Pour éviter que les tableaux ne soient trop gros, on procède en plusieurs
359 // étapes.
360 // Chaque sous-domaine construit sa liste des arêtes frontières, avec pour
361 // chaque arête :
362 // - son type,
363 // - la liste de ses noeuds,
364 // - le numéro unique de sa maille,
365 // - le propriétaire de sa maille,
366 // - son indice dans sa maille,
367 // Cette liste sera ensuite envoyée à tous les sous-domaines.
368
369 IItemFamily* node_family = m_mesh->nodeFamily();
370 m_is_boundary_nodes.resize(node_family->maxLocalId(), false);
371
372 // Marque tous les noeuds frontières, car ce sont ceux qu'il faudra envoyer
373 // Un noeud est considéré comme frontière s'il appartient à une face qui n'a qu'une
374 // maille connectée.
375 faces_map.eachItem([&](Face face) {
376 Integer face_nb_cell = face.nbCell();
377 if (face_nb_cell == 1) {
378 for (Int32 ilid : face.nodeIds())
379 m_is_boundary_nodes[ilid] = true;
380 }
381 });
382
383 // Détermine la liste des arêtes frontières.
384 // L'ordre de cette liste dépend de l'implémentation de la table de hashage.
385 // Afin d'avoir la même numérotation que la version historique (qui utilise HashTableMapT),
386 // on utilise une instance temporaire de cette classe pour ce calcul si
387 // l'implémentation utilisée est différente. C'est le cas à partir d'octobre 2024.
388 // A terme, il faudrait utiliser une autre version du calcul des uniqueId() des
389 // arêtes.
390 // TODO: Ce mécanisme est en test. A vérifier que cela donne ensuite
391 // la même numérotation.
392 const bool is_new_item_map_impl = ItemInternalMap::UseNewImpl;
393 if (is_new_item_map_impl) {
394 info() << "Edge: ItemInternalMap is using new implementation";
395 HashTableMapT<Int64, Edge> old_edges_map(5000, false);
396 edges_map.eachItem([&](Edge edge) {
397 old_edges_map.add(edge.uniqueId(), edge);
398 });
399 old_edges_map.eachValue([&](Edge edge) {
400 _addEdgeBoundaryInfo(edge);
401 });
402 }
403 else {
404 edges_map.eachItem([&](Edge edge) {
405 _addEdgeBoundaryInfo(edge);
406 });
407 }
408
409 _computeEdgesUniqueId();
410 _sendInfosToOtherRanks();
411
412 traceMng()->flush();
413 pm->barrier();
414 info() << "END OF TEST NEW EDGE COMPUTE";
415}
416
417/*---------------------------------------------------------------------------*/
418/*---------------------------------------------------------------------------*/
419
420void Parallel3EdgeUniqueIdBuilder::
421_computeEdgesUniqueId()
422{
423 ItemTypeMng* itm = m_mesh->itemTypeMng();
424 IParallelMng* pm = m_parallel_mng;
426 _exchangeData(exchanger.get());
427
428 Integer nb_receiver = exchanger->nbReceiver();
429 debug() << "NB RECEIVER=" << nb_receiver;
430 SharedArray<Int64> received_infos;
431 for (Integer i = 0; i < nb_receiver; ++i) {
432 ISerializeMessage* sm = exchanger->messageToReceive(i);
433 //Int32 orig_rank = sm->destSubDomain();
434 ISerializer* s = sm->serializer();
436 Int64 nb_info = s->getInt64();
437 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
438 received_infos.resize(nb_info);
439 s->getSpan(received_infos);
440 //if ((nb_info % 3)!=0)
441 //fatal() << "info size can not be divided by 3";
442 Integer z = 0;
443 while (z < nb_info) {
444 Int64 node_uid = received_infos[z + 0];
445 //Int64 sender_rank = received_infos[z+1];
446 //Int64 edge_uid = received_infos[z+2];
447 Int32 edge_type = (Int32)received_infos[z + 3];
448 // received_infos[z+4];
449 // received_infos[z+5];
450 ItemTypeInfo* itt = itm->typeFromId(edge_type);
451 Integer edge_nb_node = itt->nbLocalNode();
452 Int64Array& a = m_nodes_info[node_uid];
453 a.addRange(Int64ConstArrayView(6 + edge_nb_node, &received_infos[z]));
454 z += 6;
455 z += edge_nb_node;
456 //info() << "NODE UID=" << node_uid << " sender=" << sender_rank
457 // << " edge_uid=" << edge_uid;
458 //node_cell_list.add(node_uid,cell_uid,cell_owner);
459 //HashTableMapT<Int64,Int32>::Data* v = nodes_nb_cell.lookupAdd(node_uid);
460 //++v->value();
461 }
462 }
463
464 Integer my_max_edge_node = 0;
465 for (const auto& [key, value] : m_nodes_info) {
466 //Int64 key = inode.data()->key();
467 Int64ConstArrayView a = value;
468 //info() << "A key=" << key << " size=" << a.size();
469 Integer nb_info = a.size();
470 Integer z = 0;
471 Integer node_nb_edge = 0;
472 while (z < nb_info) {
473 ++node_nb_edge;
474 //Int64 node_uid = a[z+0];
475 //Int64 sender_rank = a[z+1];
476 //Int64 edge_uid = a[z+2];
477 Int32 edge_type = (Int32)a[z + 3];
478 // a[z+4];
479 // a[z+5];
480 ItemTypeInfo* itt = itm->typeFromId(edge_type);
481 Integer edge_nb_node = itt->nbLocalNode();
482 /*info() << "NODE2 UID=" << node_uid << " sender=" << sender_rank
483 << " edge_uid=" << edge_uid */
484 //for( Integer y=0; y<edge_nb_node; ++y )
485 //info() << "Nodes = i="<< y << " " << a[z+6+y];
486 z += 6;
487 z += edge_nb_node;
488 }
489 my_max_edge_node = math::max(node_nb_edge, my_max_edge_node);
490 }
491 Integer global_max_edge_node = pm->reduce(Parallel::ReduceMax, my_max_edge_node);
492 debug() << "GLOBAL MAX EDGE NODE=" << global_max_edge_node;
493 // OK, maintenant donne comme uid de la edge (node_uid * global_max_edge_node + index)
494 IntegerUniqueArray indexes;
495 m_boundary_infos_to_send.clear();
496
497 for (const auto& [key, value] : m_nodes_info) {
498 Int64ConstArrayView a = value;
499 Integer nb_info = a.size();
500 Integer z = 0;
501 Integer node_nb_edge = 0;
502 indexes.clear();
503 while (z < nb_info) {
504 Int64 node_uid = a[z + 0];
505 Int32 sender_rank = (Int32)a[z + 1];
506 Int64 edge_uid = a[z + 2];
507 Int32 edge_type = (Int32)a[z + 3];
508 // a[z+4];
509 // a[z+5];
510 ItemTypeInfo* itt = itm->typeFromId(edge_type);
511 Integer edge_nb_node = itt->nbLocalNode();
512
513 // Regarde si la edge est déjà dans la liste:
514 Integer edge_index = node_nb_edge;
515 Int32 edge_new_owner = sender_rank;
516 for (Integer y = 0; y < node_nb_edge; ++y) {
517 if (memcmp(&a[indexes[y] + 6], &a[z + 6], sizeof(Int64) * edge_nb_node) == 0) {
518 edge_index = y;
519 edge_new_owner = (Int32)a[indexes[y] + 1];
520 }
521 }
522 Int64 edge_new_uid = (node_uid * global_max_edge_node) + edge_index;
523 Int64Array& v = m_boundary_infos_to_send[sender_rank];
524 // Indique au propriétaire de cette arête son nouvel uid
525 v.add(edge_uid);
526 v.add(edge_new_uid);
527 v.add(edge_new_owner);
528 indexes.add(z);
529 z += 6;
530 z += edge_nb_node;
531 /* info() << "NODE3 UID=" << node_uid << " sender=" << sender_rank
532 << " edge_uid=" << edge_uid
533 << " edge_index=" << edge_index
534 << " edge_new_uid=" << edge_new_uid; */
535 ++node_nb_edge;
536 }
537 my_max_edge_node = math::max(node_nb_edge, my_max_edge_node);
538 }
539}
540
541/*---------------------------------------------------------------------------*/
542/*---------------------------------------------------------------------------*/
543
544void Parallel3EdgeUniqueIdBuilder::
545_sendInfosToOtherRanks()
546{
547 const bool is_verbose = m_mesh_builder->isVerbose();
548 IParallelMng* pm = m_parallel_mng;
549 Ref<IParallelExchanger> exchanger = ParallelMngUtils::createExchangerRef(pm);
550
551 _exchangeData(exchanger.get());
552
553 ItemInternalMap& edges_map = m_mesh->edgesMap();
554 Integer nb_receiver = exchanger->nbReceiver();
555 debug() << "NB RECEIVER=" << nb_receiver;
556 Int64UniqueArray received_infos;
557 for (Integer i = 0; i < nb_receiver; ++i) {
558 ISerializeMessage* sm = exchanger->messageToReceive(i);
559 auto orig_rank = sm->destination();
560 ISerializer* s = sm->serializer();
562 Int64 nb_info = s->getInt64();
563 if (is_verbose)
564 info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
565 received_infos.resize(nb_info);
566 s->getSpan(received_infos);
567 if ((nb_info % 3) != 0)
568 ARCANE_FATAL("info size can not be divided by 3 x={0}", nb_info);
569 Int64 nb_item = nb_info / 3;
570 for (Int64 z = 0; z < nb_item; ++z) {
571 Int64 old_uid = received_infos[(z * 3)];
572 Int64 new_uid = received_infos[(z * 3) + 1];
573 Int32 new_owner = static_cast<Int32>(received_infos[(z * 3) + 2]);
574 //info() << "EDGE old_uid=" << old_uid << " new_uid=" << new_uid;
575 impl::MutableItemBase iedge(edges_map.tryFind(old_uid));
576 if (iedge.null())
577 ARCANE_FATAL("Can not find own edge uid={0}", old_uid);
578 iedge.setUniqueId(new_uid);
579 iedge.setOwner(new_owner, m_my_rank);
580 Edge edge{ iedge };
581 if (is_verbose)
582 info() << "SetEdgeOwner uid=" << new_uid << " owner=" << new_owner
583 << " n0,n1=" << edge.node(0).uniqueId() << "," << edge.node(1).uniqueId()
584 << " n0=" << ItemPrinter(edge.node(0)) << " n1=" << ItemPrinter(edge.node(1));
585 }
586 }
587}
588
589/*---------------------------------------------------------------------------*/
590/*---------------------------------------------------------------------------*/
598{
599 bool is_verbose = m_mesh_builder->isVerbose();
600 Integer nb_cell = m_mesh_builder->oneMeshItemAdder()->nbCell();
601
602 ItemInternalMap& cells_map = m_mesh->cellsMap();
603
604 // En séquentiel, les uniqueId() des mailles ne peuvent dépasser la
605 // taille des Integers même en 32bits.
606 Int32 max_uid = 0;
607 cells_map.eachItem([&](Item cell) {
608 Int32 cell_uid = cell.uniqueId().asInt32();
609 if (cell_uid>max_uid)
610 max_uid = cell_uid;
611 });
612 info() << "Max uid=" << max_uid;
613 Int32UniqueArray cell_first_edge_uid(max_uid+1);
614 Int32UniqueArray cell_nb_num_back_edge(max_uid+1);
615 Int32UniqueArray cell_true_boundary_edge(max_uid+1);
616
617 cells_map.eachItem([&](Cell cell) {
618 Int32 cell_uid = cell.uniqueId().asInt32();
619 Integer nb_num_back_edge = 0;
620 Integer nb_true_boundary_edge = 0;
621 for( Edge edge : cell.edges()){
622 if (edge.itemBase().backCell()==cell)
623 ++nb_num_back_edge;
624 else if (edge.nbCell()==1){
625 ++nb_true_boundary_edge;
626 }
627 }
628 cell_nb_num_back_edge[cell_uid] = nb_num_back_edge;
629 cell_true_boundary_edge[cell_uid] = nb_true_boundary_edge;
630 });
631
632 Integer current_edge_uid = 0;
633 for( Integer i=0; i<nb_cell; ++i ){
634 cell_first_edge_uid[i] = current_edge_uid;
635 current_edge_uid += cell_nb_num_back_edge[i] + cell_true_boundary_edge[i];
636 }
637
638 if (is_verbose){
639 for( Integer i=0; i<nb_cell; ++i ){
640 info() << "Recv: Cell EdgeInfo celluid=" << i
641 << " firstedgeuid=" << cell_first_edge_uid[i]
642 << " nbback=" << cell_nb_num_back_edge[i]
643 << " nbbound=" << cell_true_boundary_edge[i];
644 }
645 }
646
647 cells_map.eachItem([&](Cell cell) {
648 Int32 cell_uid = cell.uniqueId().asInt32();
649 Integer nb_num_back_edge = 0;
650 Integer nb_true_boundary_edge = 0;
651 for( Edge edge : cell.edges() ){
652 Int64 edge_new_uid = NULL_ITEM_UNIQUE_ID;
653 //info() << "CHECK CELLUID=" << cell_uid << " EDGELID=" << edge->localId();
654 if (edge.itemBase().backCell()==cell){
655 edge_new_uid = cell_first_edge_uid[cell_uid] + nb_num_back_edge;
656 ++nb_num_back_edge;
657 }
658 else if (edge.nbCell()==1){
659 edge_new_uid = cell_first_edge_uid[cell_uid] + cell_nb_num_back_edge[cell_uid] + nb_true_boundary_edge;
660 ++nb_true_boundary_edge;
661 }
662 if (edge_new_uid!=NULL_ITEM_UNIQUE_ID){
663 //info() << "NEW EDGE UID: LID=" << edge->localId() << " OLDUID=" << edge->uniqueId()
664 //<< " NEWUID=" << edge_new_uid << " THIS=" << edge;
665 edge.mutableItemBase().setUniqueId(edge_new_uid);
666 }
667 }
668 });
669
670 if (is_verbose){
671 OStringStream ostr;
672 cells_map.eachItem([&](Cell cell) {
673 Int32 cell_uid = cell.uniqueId().asInt32();
674 Integer index = 0;
675 for( Edge edge : cell.edges() ){
676 Int64 opposite_cell_uid = NULL_ITEM_UNIQUE_ID;
677 bool true_boundary = false;
678 bool internal_other = false;
679 if (edge.itemBase().backCell()==cell){
680 }
681 else if (edge.nbCell()==1){
682 true_boundary = true;
683 }
684 else{
685 internal_other = true;
686 opposite_cell_uid = edge.itemBase().backCell().uniqueId().asInt64();
687 }
688 ostr() << "NEW LOCAL ID FOR CELLEDGE " << cell_uid << ' '
689 << index << ' ' << edge.uniqueId() << " (";
690 for( Node node : edge.nodes() ){
691 ostr() << ' ' << node.uniqueId();
692 }
693 ostr() << ")";
694 if (internal_other)
695 ostr() << " internal-other";
696 if (true_boundary)
697 ostr() << " true-boundary";
698 if (opposite_cell_uid!=NULL_ITEM_ID)
699 ostr() << " opposite " << opposite_cell_uid;
700 ostr() << '\n';
701 ++index;
702 }
703 });
704 info() << ostr.str();
705 }
706}
707
708/*---------------------------------------------------------------------------*/
709/*---------------------------------------------------------------------------*/
710
711void EdgeUniqueIdBuilder::
712_computeEdgesUniqueIdsParallelV2()
713{
714 // Positionne les uniqueId() des arêtes de manière très simple.
715 // Si le maximum des uniqueId() des noeuds est MAX_NODE_UID, alors
716 // le uniqueId() d'une arête est :
717 //
718 // node(0).uniqueId() * MAX_NODE_UID + node(1).uniqueId()
719 //
720 // Cela ne fonctionne que si MAX_NODE_UID est inférieur à 2^31.
721
722 IParallelMng* pm = m_mesh->parallelMng();
723
724 ItemInternalMap& nodes_map = m_mesh->nodesMap();
725 ItemInternalMap& edges_map = m_mesh->edgesMap();
726
727 Int64 max_uid = 0;
728 nodes_map.eachItem([&](Item node) {
729 if (node.uniqueId() > max_uid)
730 max_uid = node.uniqueId();
731 });
732 Int64 total_max_uid = pm->reduce(Parallel::ReduceMax,max_uid);
733 if (total_max_uid>INT32_MAX)
734 ARCANE_FATAL("Max uniqueId() for node is too big v={0} max_allowed={1}",total_max_uid,INT32_MAX);
735
736 edges_map.eachItem([&](Edge edge) {
737 Node node0{edge.node(0)};
738 Node node1{edge.node(1)};
739 Int64 new_uid = (node0.uniqueId().asInt64() * total_max_uid) + node1.uniqueId().asInt64();
740 edge.mutableItemBase().setUniqueId(new_uid);
741 });
742}
743
744/*---------------------------------------------------------------------------*/
745/*---------------------------------------------------------------------------*/
746
747void EdgeUniqueIdBuilder::
748_computeEdgesUniqueIdsParallel3()
749{
750 IParallelMng* pm = m_mesh->parallelMng();
751 ItemInternalMap& nodes_map = m_mesh->nodesMap();
752
753 // Détermine le maximum des uniqueId() des noeuds
754 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
755 nodes_map.eachItem([&](Item item) {
756 Int64 node_uid = item.uniqueId();
757 if (node_uid > my_max_node_uid)
758 my_max_node_uid = node_uid;
759 });
760 Int64 global_max_node_uid = pm->reduce(Parallel::ReduceMax, my_max_node_uid);
761 debug() << "NODE_UID_INFO: MY_MAX_UID=" << my_max_node_uid
762 << " GLOBAL=" << global_max_node_uid;
763
764 Parallel3EdgeUniqueIdBuilder builder(traceMng(), m_mesh_builder, global_max_node_uid);
765 builder.compute();
766}
767
768/*---------------------------------------------------------------------------*/
769/*---------------------------------------------------------------------------*/
770
771void EdgeUniqueIdBuilder::
772_computeEdgesUniqueIdsParallel64bit()
773{
774 // Positionne les uniqueId() des arêtes
775 // en utilisant un hash des deux nœuds de l'arête.
776 ItemInternalMap& edges_map = m_mesh->edgesMap();
777
778 std::hash<Int64> hasher;
779
780 edges_map.eachItem([&](Edge edge) {
781 Node node0{edge.node(0)};
782 Node node1{edge.node(1)};
783 size_t hash0 = hasher(node0.uniqueId().asInt64());
784 size_t hash1 = hasher(node1.uniqueId().asInt64());
785 hash0 ^= hash1 + 0x9e3779b9 + (hash0 << 6) + (hash0 >> 2);
786 Int64 new_uid = hash0 & 0x7fffffff;
787 edge.mutableItemBase().setUniqueId(new_uid);
788 });
789}
790
791/*---------------------------------------------------------------------------*/
792/*---------------------------------------------------------------------------*/
793
794} // End namespace Arcane::mesh
795
796/*---------------------------------------------------------------------------*/
797/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
void fill(const DataType &data)
Remplissage du tableau.
void clear()
Supprime les éléments du tableau.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
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.
Maille d'un maillage.
Definition Item.h:1199
EdgeConnectedListViewType edges() const
Liste des arêtes de la maille.
Definition Item.h:1298
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Arête d'une maille.
Definition Item.h:817
Int32 nbCell() const
Nombre de mailles connectées à l'arête.
Definition Item.h:898
Face d'une maille.
Definition Item.h:952
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2)
Definition Item.h:1027
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.
bool add(KeyTypeConstRef id, const ValueType &value)
Ajoute la valeur value correspondant à la clé id.
void eachValue(const Lambda &lambda)
Applique le fonctor f à tous les éléments de la collection et utilise x->value() (de type ValueType) ...
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual Int32 maxLocalId() const =0
virtual Integer edgeBuilderVersion() const =0
Version de la numérotation des arêtes.
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 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 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.
@ ModePut
Le sérialiseur attend des reserve()
virtual Int64 getInt64()=0
Récupère une taille.
virtual void allocateBuffer()=0
Alloue la mémoire du sérialiseur.
virtual void putSpan(Span< const Real > values)
Ajoute le tableau values.
virtual void getSpan(Span< Real > values)
Récupère le tableau values.
virtual void reserveSpan(eBasicDataType dt, Int64 n)=0
Réserve de la mémoire pour n valeurs de dt.
virtual void setMode(eMode new_mode)=0
Positionne le fonctionnement actuel.
virtual void putInt64(Int64 value)=0
Ajoute l'entier value.
Interface du gestionnaire de traces.
virtual void flush()=0
Flush tous les flots.
ItemUniqueId uniqueId() const
Numéro unique de l'entité
ItemBase backCell() const
Maille derrière l'entité (nullItem() si aucune)
Infos sur un type d'entité du maillage.
Integer nbLocalNode() const
Nombre de noeuds de l'entité
Gestionnaire des types d'entités d'un maillage.
Definition ItemTypeMng.h:65
ItemTypeInfo * typeFromId(Integer id) const
Type correspondant au numéro id.
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:782
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:785
NodeLocalIdView nodeIds() const
Liste des noeuds de l'entité
Definition Item.h:788
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:374
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:219
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:225
impl::ItemBase itemBase() const
Partie interne de l'entité.
Definition Item.h:363
Int16 type() const
Type de l'entité
Definition Item.h:241
Interface d'un message de sérialisation entre IMessagePassingMng.
virtual MessageRank destination() const =0
Rang du destinataire (si isSend() est vrai) ou de l'envoyeur.
virtual ISerializer * serializer()=0
Sérialiseur.
Int32 value() const
Valeur du rang.
Definition MessageRank.h:72
Noeud d'un maillage.
Definition Item.h:576
Flot de sortie lié à une String.
Référence à une instance.
Vecteur 1D de données avec sémantique par référence.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
TraceMessage info() const
Flot pour un message d'information.
ITraceMng * traceMng() const
Gestionnaire de trace.
Vecteur 1D de données avec sémantique par valeur (style STL).
Construction d'un maillage de manière incrémentale.
Implémentation d'un maillage.
Definition DynamicMesh.h:97
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é
IMeshUniqueIdMng * meshUniqueIdMng() const override
Gestionnare de la numérotation des identifiants uniques.
EdgeUniqueIdBuilder(DynamicMeshIncrementalBuilder *mesh_builder)
Construit une instance pour le maillage mesh.
void _computeEdgesUniqueIdsSequential()
Calcul les numéros uniques de chaque edge en séquentiel.
Tableau associatif de ItemInternal.
void notifyUniqueIdsChanged()
Notifie que les numéros uniques des entités ont changés.
void eachItem(const Lambda &lambda)
Fonction template pour itérer sur les entités de l'instance.
void _exchangeData(IParallelExchanger *exchanger)
void compute()
Calcule les numéros uniques de chaque edge en parallèle.
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
@ ReduceMax
Maximum des valeurs.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Retourne une interface pour transférer des messages entre rangs.
ARCCORE_BASE_EXPORT Real getRealTime()
Temps Real utilisé en secondes.
Array< Int64 > Int64Array
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:212
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:426
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:567
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:428
double Real
Type représentant un réel.
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
Definition UtilsTypes.h:434
std::int32_t Int32
Type entier signé sur 32 bits.