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