Arcane  v4.1.0.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:1205
EdgeConnectedListViewType edges() const
Liste des arêtes de la maille.
Definition Item.h:1304
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:823
Int32 nbCell() const
Nombre de mailles connectées à l'arête.
Definition Item.h:904
Face d'une maille.
Definition Item.h:958
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2)
Definition Item.h:1033
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.
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:788
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:791
NodeLocalIdView nodeIds() const
Liste des noeuds de l'entité
Definition Item.h:794
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
impl::ItemBase itemBase() const
Partie interne de l'entité.
Definition Item.h:369
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.
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.
ARCCORE_BASE_EXPORT Real getRealTime()
Temps Real utilisé en secondes.
Array< Int64 > Int64Array
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:154
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:368
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:509
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:370
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
Definition UtilsTypes.h:376
std::int32_t Int32
Type entier signé sur 32 bits.