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