Arcane  v3.16.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
FaceUniqueIdBuilder.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* FaceUniqueIdBuilder.cc (C) 2000-2025 */
9/* */
10/* Construction des identifiants uniques des faces. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/ScopedPtr.h"
16#include "arcane/utils/ITraceMng.h"
17#include "arcane/utils/OStringStream.h"
18#include "arcane/utils/CheckedConvert.h"
19
20#include "arcane/core/IMeshUniqueIdMng.h"
21#include "arcane/core/IParallelExchanger.h"
22#include "arcane/core/IParallelMng.h"
23#include "arcane/core/ISerializeMessage.h"
24#include "arcane/core/ISerializer.h"
25#include "arcane/core/ParallelMngUtils.h"
26
27#include "arcane/mesh/DynamicMesh.h"
28#include "arcane/mesh/OneMeshItemAdder.h"
29#include "arcane/mesh/GhostLayerBuilder.h"
30#include "arcane/mesh/FaceUniqueIdBuilder.h"
31#include "arcane/mesh/ItemTools.h"
32#include "arcane/mesh/ItemsOwnerBuilder.h"
33
34#include <unordered_set>
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39namespace Arcane::mesh
40{
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45extern "C++" void
46_computeFaceUniqueIdVersion3(DynamicMesh* mesh);
47extern "C++" void
48_computeFaceUniqueIdVersion5(DynamicMesh* mesh);
49extern "C++" void
50arcaneComputeCartesianFaceUniqueId(DynamicMesh* mesh);
51
52/*---------------------------------------------------------------------------*/
53/*---------------------------------------------------------------------------*/
54
57: TraceAccessor(mesh_builder->mesh()->traceMng())
58, m_mesh(mesh_builder->mesh())
59, m_mesh_builder(mesh_builder)
60{
61}
62
63/*---------------------------------------------------------------------------*/
64/*---------------------------------------------------------------------------*/
65
66void FaceUniqueIdBuilder::
67computeFacesUniqueIds()
68{
69 IParallelMng* pm = m_mesh->parallelMng();
70 Real begin_time = platform::getRealTime();
71 Integer face_version = m_mesh->meshUniqueIdMng()->faceBuilderVersion();
72 bool is_parallel = pm->isParallel();
73 info() << "Using version=" << face_version << " to compute faces unique ids"
74 << " mesh=" << m_mesh->name() << " is_parallel=" << is_parallel;
75
76 if (face_version > 5 || face_version < 0)
77 ARCANE_FATAL("Invalid value '{0}' for compute face unique ids versions: v>=0 && v<=6", face_version);
78
79 if (face_version == 5)
80 _computeFaceUniqueIdVersion5(m_mesh);
81 else if (face_version == 4)
82 arcaneComputeCartesianFaceUniqueId(m_mesh);
83 else if (face_version == 3)
84 _computeFaceUniqueIdVersion3(m_mesh);
85 else if (face_version == 0) {
86 info() << "No face renumbering";
87 }
88 else {
89 // Version 1 ou 2
90 if (is_parallel) {
91 if (face_version == 2) {
92 //PAS ENCORE PAR DEFAUT
93 info() << "Use new mesh init in FaceUniqueIdBuilder";
95 }
96 else {
97 // Version par défaut.
99 }
100 }
101 else {
103 }
104 }
105
106 Real end_time = platform::getRealTime();
107 Real diff = (Real)(end_time - begin_time);
108 info() << "TIME to compute face unique ids=" << diff;
109
110 if (arcaneIsCheck())
112
113 ItemInternalMap& faces_map = m_mesh->facesMap();
114
115 // Il faut ranger à nouveau #m_faces_map car les uniqueId() des
116 // faces ont été modifiés
117 if (face_version != 0)
118 m_mesh->faceFamily()->notifyItemsUniqueIdChanged();
119
120 bool is_verbose = m_mesh_builder->isVerbose();
121 if (is_verbose) {
122 info() << "NEW FACES_MAP after re-indexing";
123 faces_map.eachItem([&](Item face) {
124 info() << "Face uid=" << face.uniqueId() << " lid=" << face.localId();
125 });
126 }
127 // Avec la version 0 ou 5, les propriétaires ne sont pas positionnées
128 // Il faut le faire maintenant
129 if (face_version == 0 || face_version == 5) {
130 ItemsOwnerBuilder owner_builder(m_mesh);
131 owner_builder.computeFacesOwner();
132 }
133}
134
135/*---------------------------------------------------------------------------*/
136/*---------------------------------------------------------------------------*/
142{
143 info() << "Check no duplicate face uniqueId";
144 ItemInternalMap& faces_map = m_mesh->facesMap();
145 std::unordered_set<Int64> checked_faces_map;
146 faces_map.eachItem([&](Item face) {
147 ItemUniqueId uid = face.uniqueId();
148 auto p = checked_faces_map.find(uid);
149 if (p!=checked_faces_map.end()){
150 pwarning() << "Duplicate Face UniqueId=" << uid;
151 ARCANE_FATAL("Duplicate Face uniqueId={0}",uid);
152 }
153 checked_faces_map.insert(uid);
154 });
155}
156
157/*---------------------------------------------------------------------------*/
158/*---------------------------------------------------------------------------*/
167class T_CellFaceInfo
168{
169 public:
170
171 T_CellFaceInfo(Int64 uid,Integer nb_back_face,Integer nb_true_boundary_face)
172 : m_unique_id(uid), m_nb_back_face(nb_back_face), m_nb_true_boundary_face(nb_true_boundary_face)
173 {
174 }
175
176 T_CellFaceInfo()
177 : m_unique_id(NULL_ITEM_ID), m_nb_back_face(0), m_nb_true_boundary_face(0)
178 {
179 }
180
181 public:
182
183 bool operator<(const T_CellFaceInfo& ci) const
184 {
185 return m_unique_id<ci.m_unique_id;
186 }
187
188 public:
189
190 Int64 m_unique_id;
191 Int64 m_nb_back_face;
192 Int64 m_nb_true_boundary_face;
193};
194
195/*---------------------------------------------------------------------------*/
196/*---------------------------------------------------------------------------*/
214{
215 IParallelMng* pm = m_mesh->parallelMng();
216 Integer my_rank = pm->commRank();
217 Integer nb_rank = pm->commSize();
218
219 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
220 Integer nb_local_cell = m_mesh_builder->oneMeshItemAdder()->nbCell();
221 bool is_verbose = m_mesh_builder->isVerbose();
222
223 UniqueArray<Int64> faces_opposite_cell_uid(nb_local_face);
224 faces_opposite_cell_uid.fill(NULL_ITEM_ID);
225 UniqueArray<Integer> faces_opposite_cell_index(nb_local_face);
226 UniqueArray<Integer> faces_opposite_cell_owner(nb_local_face);
227
228 // Pour vérification, s'assure que tous les éléments de ce tableau
229 // sont valides, ce qui signifie que toutes les faces ont bien été
230 // renumérotés
231 UniqueArray<Int64> faces_new_uid(nb_local_face);
232 faces_new_uid.fill(NULL_ITEM_ID);
233
234 Integer nb_recv_sub_domain_boundary_face = 0;
235
236 Int64UniqueArray faces_infos;
237 faces_infos.reserve(10000);
238 ItemInternalMap& cells_map = m_mesh->cellsMap();
239 ItemInternalMap& faces_map = m_mesh->facesMap();
240 ItemInternalMap& nodes_map = m_mesh->nodesMap();
241
242
243 // NOTE: ce tableau n'est pas utile sur toutes les mailles. Il
244 // suffit qu'il contienne les mailles dont on a besoin, c'est à dire
245 // les notres + celles connectées à une de nos faces. Une table
246 // de hashage sera plus appropriée.
247 HashTableMapT<Int64,Int64> cells_first_face_uid(m_mesh_builder->oneMeshItemAdder()->nbCell()*2,true);
248
249 // Rassemble les données des autres processeurs dans recv_cells;
250 // Pour éviter que les tableaux ne soient trop gros, on procède en plusieurs
251 // étapes.
252 // Chaque sous-domaine construit sa liste de faces frontières, avec pour
253 // chaque face:
254 // - son type
255 // - la liste de ses noeuds,
256 // - le numéro unique de sa maille
257 // - le propriétaire de sa maille
258 // - son indice dans sa maille
259 // Cette liste sera ensuite envoyée à tous les sous-domaines.
260 {
261 ItemTypeMng* itm = m_mesh->itemTypeMng();
262
263 UniqueArray<Int32> faces_local_id;
264
265 faces_map.eachItem([&](Face face) {
266 bool boundary_val = face.isSubDomainBoundary();
267 if (boundary_val)
268 faces_local_id.add(face.localId());
269 });
270
271 Integer nb_sub_domain_boundary_face = faces_local_id.size();
272 Int64 global_nb_boundary_face = pm->reduce(Parallel::ReduceSum,(Int64)nb_sub_domain_boundary_face);
273 debug() << "NB BOUNDARY FACE=" << nb_sub_domain_boundary_face
274 << " NB_FACE=" << nb_local_face
275 << " GLOBAL_NB_BOUNDARY_FACE=" << global_nb_boundary_face;
276
277
278 Int64UniqueArray faces_infos2;
279 Int64UniqueArray recv_faces_infos;
280
281 // Calcule la taille d'un bloc d'envoi
282 // La mémoire nécessaire pour une face est égale à nb_node + 4.
283 // Si on suppose qu'on a des quadrangles en général, cela
284 // fait 8 Int64 par face, soit 64 octets par face.
285 // La mémoire nécessaire pour tout envoyer est donc 64 * global_nb_boundary_face.
286 // step_size * nb_proc * 64 octets.
287 // Le step_size par défaut est calculé pour que la mémoire nécessaire
288 // soit de l'ordre de 100 Mo pour chaque message.
289 Int64 step_size = 1500000;
290 Integer nb_phase = CheckedConvert::toInteger((global_nb_boundary_face / step_size) + 1);
291 FaceLocalIdToFaceConverter faces(m_mesh->faceFamily());
292 for( Integer i_phase=0; i_phase<nb_phase; ++i_phase ){
293 Integer nb_face_to_send = nb_sub_domain_boundary_face / nb_phase;
294 Integer first_face_to_send = nb_face_to_send * i_phase;
295 Integer last_face_to_send = first_face_to_send + nb_face_to_send;
296 if (i_phase+1==nb_phase)
297 last_face_to_send = nb_sub_domain_boundary_face;
298 Integer real_nb_face_to_send = last_face_to_send - first_face_to_send;
299
300 faces_infos2.clear();
301 for( Integer i_face=first_face_to_send; i_face<first_face_to_send+real_nb_face_to_send; ++i_face ){
302 Face face(faces[faces_local_id[i_face]]);
304 bool has_back_cell = face.itemBase().flags() & ItemFlags::II_HasBackCell;
305 faces_infos2.add(face.type());
306 for( Node node : face.nodes() )
307 faces_infos2.add(node.uniqueId().asInt64());
308
309 //info() << " ADD FACE lid=" << face->localId();
310
311 Cell cell = face.cell(0);
312 faces_infos2.add(cell.uniqueId().asInt64());
313 faces_infos2.add(cell.owner());
314
315 Integer face_index_in_cell = 0;
316 if (has_back_cell){
317 for( Face current_face_in_cell : cell.faces() ){
318 if (current_face_in_cell==face)
319 break;
320 if (current_face_in_cell.backCell()==cell)
321 ++face_index_in_cell;
322 }
323 }
324 else
325 face_index_in_cell = NULL_ITEM_ID;
326 faces_infos2.add(face_index_in_cell);
327 }
328 faces_infos2.add(IT_NullType); // Pour dire que la liste s'arête
329
330 pm->allGatherVariable(faces_infos2,recv_faces_infos);
331
332 info() << "Number of face bytes received: " << recv_faces_infos.size()
333 << " phase=" << i_phase << "/" << nb_phase
334 << " first_face=" << first_face_to_send
335 << " last_face=" << last_face_to_send
336 << " nb=" << real_nb_face_to_send;
337
338 Integer recv_faces_infos_index = 0;
339
340 for( Integer i_sub_domain=0; i_sub_domain<nb_rank; ++i_sub_domain ){
341 bool is_end = false;
342 // Il ne faut pas lire les infos qui viennent de moi
343 if (i_sub_domain==my_rank){
344 recv_faces_infos_index += faces_infos2.size();
345 continue;
346 }
347 // Désérialise les infos de chaque sous-domaine
348 while (!is_end){
349 Integer face_type = CheckedConvert::toInteger(recv_faces_infos[recv_faces_infos_index]);
350 ++recv_faces_infos_index;
351 if (face_type==IT_NullType){
352 is_end = true;
353 break;
354 }
355 ItemTypeInfo* itt = itm->typeFromId(face_type);
356 Integer face_nb_node = itt->nbLocalNode();
357 ConstArrayView<Int64> faces_nodes_uid(face_nb_node,&recv_faces_infos[recv_faces_infos_index]);
358
359 recv_faces_infos_index += face_nb_node;
360 Int64 cell_uid = recv_faces_infos[recv_faces_infos_index];
361 ++recv_faces_infos_index;
362 Integer cell_owner = CheckedConvert::toInteger(recv_faces_infos[recv_faces_infos_index]);
363 ++recv_faces_infos_index;
364 Integer cell_face_index = CheckedConvert::toInteger(recv_faces_infos[recv_faces_infos_index]);
365 ++recv_faces_infos_index;
366
367 Node node = nodes_map.tryFind(faces_nodes_uid[0]);
368 // Si la face n'existe pas dans mon sous-domaine, elle ne m'intéresse pas
369 if (node.null())
370 continue;
371 Face face = ItemTools::findFaceInNode2(node, face_type, faces_nodes_uid);
372 if (face.null())
373 continue;
374 ++nb_recv_sub_domain_boundary_face;
375 faces_opposite_cell_uid[face.localId()] = cell_uid;
376 faces_opposite_cell_index[face.localId()] = cell_face_index;
377 faces_opposite_cell_owner[face.localId()] = cell_owner;
378 cells_first_face_uid.add(cell_uid,-1);
379 }
380 }
381 }
382 info() << "Number of faces on the subdomain interface: "
383 << nb_sub_domain_boundary_face << ' ' << nb_recv_sub_domain_boundary_face;
384 }
385
386 // Cherche le uniqueId max des mailles sur tous les sous-domaines.
387 Int64 max_cell_uid = 0;
388 Int32 max_cell_local_id = 0;
389 cells_map.eachItem([&](Item cell) {
390 Int64 cell_uid = cell.uniqueId().asInt64();
391 Int32 cell_local_id = cell.localId();
392 if (cell_uid>max_cell_uid)
393 max_cell_uid = cell_uid;
394 if (cell_local_id>max_cell_local_id)
395 max_cell_local_id = cell_local_id;
396 });
397 Int64 global_max_cell_uid = pm->reduce(Parallel::ReduceMax,max_cell_uid);
398 debug() << "GLOBAL MAX CELL UID=" << global_max_cell_uid;
399
400
401 UniqueArray<T_CellFaceInfo> my_cells_faces_info;
402 my_cells_faces_info.reserve(nb_local_cell);
403 IntegerUniqueArray my_cells_nb_back_face(max_cell_local_id+1);
404 my_cells_nb_back_face.fill(0);
405
406 cells_map.eachItem([&](Cell cell) {
407 Int64 cell_uid = cell.uniqueId().asInt64();
408 Int32 cell_local_id = cell.localId();
409 Integer nb_back_face = 0;
410 Integer nb_true_boundary_face = 0;
411 for( Face face : cell.faces() ){
412 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
413 if (face.backCell()==cell)
414 ++nb_back_face;
415 else if (face.nbCell()==1 && opposite_cell_uid==NULL_ITEM_ID){
416 ++nb_true_boundary_face;
417 }
418 }
419 my_cells_nb_back_face[cell_local_id] = nb_back_face;
420 my_cells_faces_info.add(T_CellFaceInfo(cell_uid,nb_back_face,nb_true_boundary_face));
421 });
422 std::sort(std::begin(my_cells_faces_info),std::end(my_cells_faces_info));
423
424 {
425 Integer nb_phase = 16;
426 Integer first_cell_index_to_send = 0;
427 Int64 current_face_uid = 0;
428
429 for( Integer i_phase=0; i_phase<nb_phase; ++i_phase ){
430 Integer nb_uid_to_send = CheckedConvert::toInteger(global_max_cell_uid / nb_phase);
431 Integer first_uid_to_send = nb_uid_to_send * i_phase;
432 Int64 last_uid_to_send = first_uid_to_send + nb_uid_to_send;
433 if (i_phase+1==nb_phase)
434 last_uid_to_send = global_max_cell_uid;
435
436 //Integer last_cell_index_to_send = first_cell_index_to_send;
437 Integer nb_cell_to_send = 0;
438 for( Integer zz=first_cell_index_to_send, zs=my_cells_faces_info.size(); zz<zs; ++zz ){
439 if (my_cells_faces_info[zz].m_unique_id<=last_uid_to_send)
440 ++nb_cell_to_send;
441 else
442 break;
443 }
444 debug() << "FIRST TO SEND=" << first_cell_index_to_send
445 << " NB=" << nb_cell_to_send
446 << " first_uid=" << first_uid_to_send
447 << " last_uid=" << last_uid_to_send;
448
449 T_CellFaceInfo* begin_cell_array = my_cells_faces_info.data()+first_cell_index_to_send;
450 Int64* begin_array = reinterpret_cast<Int64*>(begin_cell_array);
451 Integer begin_size = nb_cell_to_send*3;
452
453 Int64ConstArrayView cells_faces_infos(begin_size,begin_array);
454
455 Int64UniqueArray recv_cells_faces_infos;
456 pm->allGatherVariable(cells_faces_infos,recv_cells_faces_infos);
457 first_cell_index_to_send += nb_cell_to_send;
458
459 info() << "Infos faces (received) nb_int64=" << recv_cells_faces_infos.size();
460 Integer recv_nb_cell = recv_cells_faces_infos.size() / 3;
461
462 // NOTE: comme on connait le uid min et max possible, on peut optimiser en
463 // creant un tableau dimensionne avec comme borne ce min et ce max et
464 // remplir directement les elements de ce tableau. Comme cela, on
465 // n'a pas besoin de tri.
466 UniqueArray<T_CellFaceInfo> global_cells_faces_info(recv_nb_cell);
467 for( Integer i=0; i<recv_nb_cell; ++i ){
468 Int64 cell_uid = recv_cells_faces_infos[i*3];
469 global_cells_faces_info[i].m_unique_id = cell_uid;
470 global_cells_faces_info[i].m_nb_back_face = recv_cells_faces_infos[(i*3) +1];
471 global_cells_faces_info[i].m_nb_true_boundary_face = recv_cells_faces_infos[(i*3) +2];
472 }
473 info() << "Sorting the faces nb=" << global_cells_faces_info.size();
474 std::sort(std::begin(global_cells_faces_info),std::end(global_cells_faces_info));
475
476 for( Integer i=0; i<recv_nb_cell; ++i ){
477 Int64 cell_uid = global_cells_faces_info[i].m_unique_id;
478 if (cells_map.hasKey(cell_uid) || cells_first_face_uid.hasKey(cell_uid))
479 cells_first_face_uid.add(cell_uid,current_face_uid);
480 current_face_uid += global_cells_faces_info[i].m_nb_back_face + global_cells_faces_info[i].m_nb_true_boundary_face;
481 }
482 }
483 }
484
485 cells_map.eachItem([&](Cell cell) {
486 Int64 cell_uid = cell.uniqueId();
487 Int32 cell_local_id = cell.localId();
488 Integer num_local_face = 0;
489 Integer num_true_boundary_face = 0;
490 for( Face face : cell.faces() ){
491 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
492 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
493 if (face.backCell()==cell){
494 if (!cells_first_face_uid.hasKey(cell_uid))
495 fatal() << "NO KEY 0 for cell_uid=" << cell_uid;
496 face_new_uid = cells_first_face_uid[cell_uid]+num_local_face;
497 face.mutableItemBase().setOwner(my_rank,my_rank);
498 ++num_local_face;
499 }
500 else if (face.nbCell()==1){
501 if (opposite_cell_uid==NULL_ITEM_UNIQUE_ID){
502 // Il s'agit d'une face frontière du domaine initial
503 if (!cells_first_face_uid.hasKey(cell_uid))
504 fatal() << "NO KEY 1 for cell_uid=" << cell_uid;
505 face_new_uid = cells_first_face_uid[cell_uid] + my_cells_nb_back_face[cell_local_id] + num_true_boundary_face;
506 ++num_true_boundary_face;
507 face.mutableItemBase().setOwner(my_rank,my_rank);
508 }
509 else{
510 if (!cells_first_face_uid.hasKey(opposite_cell_uid))
511 fatal() << "NO KEY 1 for cell_uid=" << cell_uid << " opoosite=" << opposite_cell_uid;
512 face_new_uid = cells_first_face_uid[opposite_cell_uid]+faces_opposite_cell_index[face.localId()];
513 face.mutableItemBase().setOwner(faces_opposite_cell_owner[face.localId()],my_rank);
514 }
515 }
516 if (face_new_uid!=NULL_ITEM_UNIQUE_ID){
517 faces_new_uid[face.localId()] = face_new_uid;
518 face.mutableItemBase().setUniqueId(face_new_uid);
519 }
520 }
521 });
522
523 // Vérifie que toutes les faces ont été réindéxées
524 {
525 Integer nb_error = 0;
526 for( Integer i=0, is=nb_local_face; i<is; ++i ){
527 if (faces_new_uid[i]==NULL_ITEM_UNIQUE_ID){
528 ++nb_error;
529 if (nb_error<10)
530 error() << "The face lid=" << i << " has not been re-indexed.";
531 }
532 }
533 if (nb_error!=0)
534 ARCANE_FATAL("Some ({0}) faces have not been reindexed",nb_error);
535 }
536
537 if (is_verbose){
538 OStringStream ostr;
539 cells_map.eachItem([&](Cell cell) {
540 Int64 cell_uid = cell.uniqueId().asInt64();
541 Integer face_index = 0;
542 for( Face face : cell.faces() ){
543 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
544 bool shared = false;
545 bool true_boundary = false;
546 bool internal_other = false;
547 if (face.backCell()==cell){
548 }
549 else if (face.nbCell()==1){
550 if (opposite_cell_uid==NULL_ITEM_ID)
551 true_boundary = true;
552 else
553 shared = true;
554 }
555 else{
556 internal_other = true;
557 opposite_cell_uid = face.backCell().uniqueId().asInt64();
558 }
559 ostr() << "NEW UNIQUE ID FOR FACE"
560 << " lid=" << face.localId()
561 << " cell=" << cell_uid
562 << " face=" << face.uniqueId()
563 << " nbcell=" << face.nbCell()
564 << " cellindex=" << face_index << " (";
565 for( Node node : face.nodes() )
566 ostr() << ' ' << node.uniqueId();
567 ostr() << ")";
568 if (internal_other)
569 ostr() << " internal-other";
570 if (true_boundary)
571 ostr() << " true-boundary";
572 if (opposite_cell_uid!=NULL_ITEM_ID){
573 ostr() << " opposite " << opposite_cell_uid;
574 }
575 if (shared)
576 ostr() << " (shared)";
577 ostr() << "\n";
578 ++face_index;
579 }
580 });
581 info() << ostr.str();
582 String file_name("faces_uid.");
583 file_name = file_name + my_rank;
584 std::ofstream ofile(file_name.localstr());
585 ofile << ostr.str();
586 }
587}
588
589/*---------------------------------------------------------------------------*/
590/*---------------------------------------------------------------------------*/
596_exchangeData(IParallelExchanger* exchanger,BoundaryInfosMap& boundary_infos_to_send)
597{
598 for( BoundaryInfosMapEnumerator i_map(boundary_infos_to_send); ++i_map; ){
599 Int32 sd = i_map.data()->key();
600 exchanger->addSender(sd);
601 }
603 Integer nb_sender = exchanger->nbSender();
604 Integer nb_receiver = exchanger->nbReceiver();
605 info() << "NB_SEND=" << nb_sender << " NB_RECV=" << nb_receiver;
606 Integer total = nb_sender+nb_receiver;
607 Integer global_total = exchanger->parallelMng()->reduce(Parallel::ReduceSum,total);
608 info() << "GLOBAL_NB_MESSAGE=" << global_total;
609
610 {
611 for( Integer i=0, ns=exchanger->nbSender(); i<ns; ++i ){
612 ISerializeMessage* sm = exchanger->messageToSend(i);
613 Int32 rank = sm->destination().value();
614 ISerializer* s = sm->serializer();
615 Int64ConstArrayView infos = boundary_infos_to_send[rank];
616 Integer nb_info = infos.size();
617 s->setMode(ISerializer::ModeReserve);
618 s->reserveInt64(1); // Pour le nombre d'elements
619 s->reserveSpan(eBasicDataType::Int64,nb_info); // Pour les elements
620 s->allocateBuffer();
622 s->putInt64(nb_info);
623 s->putSpan(infos);
624 }
625 }
626 exchanger->processExchange();
627 debug() << "END EXCHANGE";
628}
629
630template<typename DataType>
632{
633 public:
634 private:
635
636 class MyInfo
637 {
638 public:
639 MyInfo(const DataType& d,Integer n) : data(d), next_index(n) {}
640 public:
641 DataType data;
642 Integer next_index;
643 };
644
645 public:
646 ItemInfoMultiList() : m_last_index(5000,true) {}
647
648 public:
649
650 void add(Int64 node_uid,const DataType& data)
651 {
652 Integer current_index = m_values.size();
653
654 bool is_add = false;
655 HashTableMapT<Int64,Int32>::Data* d = m_last_index.lookupAdd(node_uid,-1,is_add);
656
657 m_values.add(MyInfo(data,d->value()));
658 d->value() = current_index;
659 }
660
661 public:
662 UniqueArray<MyInfo> m_values;
663 HashTableMapT<Int64,Int32> m_last_index;
664};
665
666/*---------------------------------------------------------------------------*/
667/*---------------------------------------------------------------------------*/
677{
678 IParallelMng* pm = m_mesh->parallelMng();
679 Integer my_rank = pm->commRank();
680 Integer nb_rank = pm->commSize();
681
682 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
683 //Integer nb_local_cell = m_mesh_builder->nbCell();
684 //bool is_verbose = m_mesh_builder->isVerbose();
685
686 Int64UniqueArray faces_opposite_cell_uid(nb_local_face);
687 faces_opposite_cell_uid.fill(NULL_ITEM_ID);
688 IntegerUniqueArray faces_opposite_cell_index(nb_local_face);
689 IntegerUniqueArray faces_opposite_cell_owner(nb_local_face);
690
691 // Pour vérification, s'assure que tous les éléments de ce tableau
692 // sont valides, ce qui signifie que toutes les faces ont bien été
693 // renumérotés
694 Int64UniqueArray faces_new_uid(nb_local_face);
695 faces_new_uid.fill(NULL_ITEM_ID);
696
697 Int64UniqueArray faces_infos;
698 faces_infos.reserve(10000);
699 ItemInternalMap& faces_map = m_mesh->facesMap();
700 ItemInternalMap& nodes_map = m_mesh->nodesMap();
701
702
703 // NOTE: ce tableau n'est pas utile sur toutes les mailles. Il
704 // suffit qu'il contienne les mailles dont on a besoin, c'est à dire
705 // les notres + celles connectées à une de nos faces.
706 HashTableMapT<Int32,Int32> cell_first_face_uid(m_mesh_builder->oneMeshItemAdder()->nbCell()*2,true);
707
708 // Rassemble les données des autres processeurs dans recv_cells;
709 // Pour éviter que les tableaux ne soient trop gros, on procède en plusieurs
710 // étapes.
711 // Chaque sous-domaine construit sa liste de faces frontières, avec pour
712 // chaque face:
713 // - son type
714 // - la liste de ses noeuds,
715 // - le numéro unique de sa maille
716 // - le propriétaire de sa maille
717 // - son indice dans sa maille
718 // Cette liste sera ensuite envoyée à tous les sous-domaines.
719 ItemTypeMng* itm = m_mesh->itemTypeMng();
720
721 // Détermine le unique id max des noeuds
722 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
723 nodes_map.eachItem([&](Item node) {
724 Int64 node_uid = node.uniqueId();
725 if (node_uid>my_max_node_uid)
726 my_max_node_uid = node_uid;
727 });
728 Int64 global_max_node_uid = pm->reduce(Parallel::ReduceMax,my_max_node_uid);
729 debug() << "NODE_UID_INFO: MY_MAX_UID=" << my_max_node_uid
730 << " GLOBAL=" << global_max_node_uid;
731
732 //TODO: choisir bonne valeur pour initialiser la table
733 BoundaryInfosMap boundary_infos_to_send(nb_rank,true);
734 NodeUidToSubDomain uid_to_subdomain_converter(global_max_node_uid,nb_rank);
735 info() << "NB_CORE modulo=" << uid_to_subdomain_converter.modulo();
736 HashTableMapT<Int64,SharedArray<Int64> > nodes_info(100000,true);
737 IItemFamily* node_family = m_mesh->nodeFamily();
738 UniqueArray<bool> is_boundary_nodes(node_family->maxLocalId(),false);
739
740 // Marque tous les noeuds frontieres car ce sont ceux qu'il faudra envoyer
741 faces_map.eachItem([&](Face face) {
742 Integer face_nb_cell = face.nbCell();
743 if (face_nb_cell==1){
744 for( Node node : face.nodes() )
745 is_boundary_nodes[node.localId()] = true;
746 }
747 });
748
749 // Détermine la liste des faces frontières
750 faces_map.eachItem([&](Face face) {
751 Node first_node = face.node(0);
752 Int64 first_node_uid = first_node.uniqueId();
754 Int32 dest_rank = -1;
755 if (!is_boundary_nodes[first_node.localId()]){
756 v = nodes_info.lookupAdd(first_node_uid)->value();
757 }
758 else{
759 dest_rank = uid_to_subdomain_converter.uidToRank(first_node_uid);
760 v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
761 }
762 v.add(first_node_uid); // 0
763 v.add(my_rank); // 1
764 v.add(face.uniqueId()); // 2
765 v.add(face.type()); // 3
766 Cell back_cell = face.backCell();
767 Cell front_cell = face.frontCell();
768 if (back_cell.null()) // 4 : only used for debug
769 v.add(NULL_ITEM_UNIQUE_ID);
770 else
771 v.add(back_cell.uniqueId());
772 if (front_cell.null()) // 5 : only used for debug
773 v.add(NULL_ITEM_UNIQUE_ID);
774 else
775 v.add(front_cell.uniqueId());
776 for( Integer z=0, zs=face.nbNode(); z<zs; ++z )
777 v.add(face.node(z).uniqueId());
778 });
779
780 // Positionne la liste des envoies
782 _exchangeData(exchanger.get(),boundary_infos_to_send);
783
784 {
785 Integer nb_receiver = exchanger->nbReceiver();
786 debug() << "NB RECEIVER=" << nb_receiver;
787 Int64UniqueArray received_infos;
788 for( Integer i=0; i<nb_receiver; ++i ){
789 ISerializeMessage* sm = exchanger->messageToReceive(i);
790 //Int32 orig_rank = sm->destSubDomain();
791 ISerializer* s = sm->serializer();
793 Int64 nb_info = s->getInt64();
794 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
795 received_infos.resize(nb_info);
796 s->getSpan(received_infos);
797 //if ((nb_info % 3)!=0)
798 //fatal() << "info size can not be divided by 3";
799 Integer z =0;
800 while(z<nb_info){
801 Int64 node_uid = received_infos[z+0];
802 Int32 face_type = (Int32)received_infos[z+3];
803 ItemTypeInfo* itt = itm->typeFromId(face_type);
804 Integer face_nb_node = itt->nbLocalNode();
805 Int64Array& a = nodes_info.lookupAdd(node_uid)->value();
806 a.addRange(Int64ConstArrayView(6+face_nb_node,&received_infos[z]));
807 z += 6;
808 z += face_nb_node;
809 }
810 }
811 Integer my_max_face_node = 0;
812 for( HashTableMapT<Int64,SharedArray<Int64> >::Enumerator inode(nodes_info); ++inode; ){
813 Int64ConstArrayView a = *inode;
814 Integer nb_info = a.size();
815 Integer z = 0;
816 Integer node_nb_face = 0;
817 while(z<nb_info){
818 ++node_nb_face;
819 Int32 face_type = (Int32)a[z+3];
820 ItemTypeInfo* itt = itm->typeFromId(face_type);
821 Integer face_nb_node = itt->nbLocalNode();
822 z += 6;
823 z += face_nb_node;
824 }
825 my_max_face_node = math::max(node_nb_face,my_max_face_node);
826 }
827 Integer global_max_face_node = pm->reduce(Parallel::ReduceMax,my_max_face_node);
828 debug() << "GLOBAL MAX FACE NODE=" << global_max_face_node;
829 // OK, maintenant donne comme uid de la face (node_uid * global_max_face_node + index)
830 IntegerUniqueArray indexes;
831 boundary_infos_to_send = BoundaryInfosMap(nb_rank,true);
832
833 for( HashTableMapT<Int64,SharedArray<Int64> >::Enumerator inode(nodes_info); ++inode; ){
834 Int64ConstArrayView a = *inode;
835 Integer nb_info = a.size();
836 Integer z = 0;
837 Integer node_nb_face = 0;
838 indexes.clear();
839 while(z<nb_info){
840 Int64 node_uid = a[z+0];
841 Int32 sender_rank = (Int32)a[z+1];
842 Int64 face_uid = a[z+2];
843 Int32 face_type = (Int32)a[z+3];
844 ItemTypeInfo* itt = itm->typeFromId(face_type);
845 Integer face_nb_node = itt->nbLocalNode();
846
847 // Regarde si la face est déjà dans la liste:
848 Integer face_index = node_nb_face;
849 Int32 face_new_owner = sender_rank;
850 for( Integer y=0; y<node_nb_face; ++y ){
851 if (memcmp(&a[indexes[y]+6],&a[z+6],sizeof(Int64)*face_nb_node)==0){
852 face_index = y;
853 face_new_owner = (Int32)a[indexes[y]+1];
854 }
855 }
856 Int64 face_new_uid = (node_uid * global_max_face_node) + face_index;
857 Int64Array& v = boundary_infos_to_send.lookupAdd(sender_rank)->value();
858 // Indique au propriétaire de cette face son nouvel uid
859 v.add(face_uid);
860 v.add(face_new_uid);
861 v.add(face_new_owner);
862 indexes.add(z);
863 z += 6;
864 z += face_nb_node;
865 ++node_nb_face;
866 }
867 my_max_face_node = math::max(node_nb_face,my_max_face_node);
868 }
869 }
871
872 _exchangeData(exchanger.get(),boundary_infos_to_send);
873 {
874 Integer nb_receiver = exchanger->nbReceiver();
875 debug() << "NB RECEIVER=" << nb_receiver;
876 Int64UniqueArray received_infos;
877 for( Integer i=0; i<nb_receiver; ++i ){
878 ISerializeMessage* sm = exchanger->messageToReceive(i);
879 ISerializer* s = sm->serializer();
881 Int64 nb_info = s->getInt64();
882 received_infos.resize(nb_info);
883 s->getSpan(received_infos);
884 if ((nb_info % 3)!=0)
885 ARCANE_FATAL("info size can not be divided by 3 v={0}",nb_info);;
886 Int64 nb_item = nb_info / 3;
887 for (Int64 z=0; z<nb_item; ++z ){
888 Int64 old_uid = received_infos[(z*3)];
889 Int64 new_uid = received_infos[(z*3)+1];
890 Int32 new_owner = (Int32)received_infos[(z*3)+2];
891 impl::MutableItemBase face(faces_map.tryFind(old_uid));
892 if (face.null())
893 ARCANE_FATAL("Can not find own face uid={0}", old_uid);
894 face.setUniqueId(new_uid);
895 face.setOwner(new_owner, my_rank);
896 }
897 }
898 }
899
900 traceMng()->flush();
901 pm->barrier();
902 debug() << "END OF TEST NEW FACE COMPUTE";
903 return;
904}
905
906/*---------------------------------------------------------------------------*/
907/*---------------------------------------------------------------------------*/
915{
916 bool is_verbose = m_mesh_builder->isVerbose();
917
918 ItemInternalMap& cells_map = m_mesh->cellsMap();
919
920 // En séquentiel, les uniqueId() des mailles ne peuvent dépasser la
921 // taille des Integers même en 32bits.
922 Int32 max_uid = 0;
923 cells_map.eachItem([&](Item cell) {
924 Int32 cell_uid = cell.uniqueId().asInt32();
925 if (cell_uid>max_uid)
926 max_uid = cell_uid;
927 });
928 info() << "Max uid=" << max_uid;
929 Integer nb_computed = max_uid + 1;
930 Int32UniqueArray cell_first_face_uid(nb_computed,0);
931 Int32UniqueArray cell_nb_num_back_face(nb_computed,0);
932 Int32UniqueArray cell_true_boundary_face(nb_computed,0);
933
934 cells_map.eachItem([&](Cell cell) {
935 Int32 cell_uid = cell.uniqueId().asInt32();
936 Integer nb_num_back_face = 0;
937 Integer nb_true_boundary_face = 0;
938 for( Face face : cell.faces() ){
939 if (face.backCell()==cell)
940 ++nb_num_back_face;
941 else if (face.nbCell()==1){
942 ++nb_true_boundary_face;
943 }
944 }
945 cell_nb_num_back_face[cell_uid] = nb_num_back_face;
946 cell_true_boundary_face[cell_uid] = nb_true_boundary_face;
947 });
948
949 Integer current_face_uid = 0;
950 for( Integer i=0; i<nb_computed; ++i ){
951 cell_first_face_uid[i] = current_face_uid;
952 current_face_uid += cell_nb_num_back_face[i] + cell_true_boundary_face[i];
953 }
954
955 if (is_verbose){
956 cells_map.eachItem([&](Item cell) {
957 Int32 i = cell.uniqueId().asInt32();
958 info() << "Recv: Cell FaceInfo celluid=" << i
959 << " firstfaceuid=" << cell_first_face_uid[i]
960 << " nbback=" << cell_nb_num_back_face[i]
961 << " nbbound=" << cell_true_boundary_face[i];
962 });
963 }
964
965 cells_map.eachItem([&](Cell cell) {
966 Int32 cell_uid = cell.uniqueId().asInt32();
967 Integer nb_num_back_face = 0;
968 Integer nb_true_boundary_face = 0;
969 for( Face face : cell.faces() ){
970 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
971 if (face.backCell()==cell){
972 face_new_uid = cell_first_face_uid[cell_uid] + nb_num_back_face;
973 ++nb_num_back_face;
974 }
975 else if (face.nbCell()==1){
976 face_new_uid = cell_first_face_uid[cell_uid] + cell_nb_num_back_face[cell_uid] + nb_true_boundary_face;
977 ++nb_true_boundary_face;
978 }
979 if (face_new_uid!=NULL_ITEM_UNIQUE_ID){
980 face.mutableItemBase().setUniqueId(face_new_uid);
981 }
982 }
983 });
984
985 if (is_verbose){
986 OStringStream ostr;
987 cells_map.eachItem([&](Cell cell) {
988 Integer face_index = 0;
989 for( Face face : cell.faces() ){
990 Int64 opposite_cell_uid = NULL_ITEM_UNIQUE_ID;
991 bool true_boundary = false;
992 bool internal_other = false;
993 if (face.backCell()==cell){
994 }
995 else if (face.nbCell()==1){
996 true_boundary = true;
997 }
998 else{
999 internal_other = true;
1000 opposite_cell_uid = face.backCell().uniqueId().asInt64();
1001 }
1002 ostr() << "NEW LOCAL ID FOR CELLFACE cell_uid=" << cell.uniqueId() << ' '
1003 << face_index << " uid=" << face.uniqueId() << " (";
1004 for( Node node : face.nodes() )
1005 ostr() << ' ' << node.uniqueId();
1006 ostr() << ")";
1007 if (internal_other)
1008 ostr() << " internal-other";
1009 if (true_boundary)
1010 ostr() << " true-boundary";
1011 if (opposite_cell_uid!=NULL_ITEM_ID)
1012 ostr() << " opposite " << opposite_cell_uid;
1013 ostr() << '\n';
1014 ++face_index;
1015 }
1016 });
1017 info() << ostr.str();
1018 }
1019}
1020
1021/*---------------------------------------------------------------------------*/
1022/*---------------------------------------------------------------------------*/
1023
1024} // End namespace Arcane::mesh
1025
1026/*---------------------------------------------------------------------------*/
1027/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Integer size() const
Nombre d'éléments du vecteur.
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.
const T * data() const
Accès à la racine du tableau hors toute protection.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Maille d'un maillage.
Definition Item.h:1191
FaceConnectedListViewType faces() const
Liste des faces de la maille.
Definition Item.h:1272
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Classe pour convertir un FaceLocalId vers une face.
Face d'une maille.
Definition Item.h:944
Cell frontCell() const
Maille devant la face (maille nulle si aucune)
Definition Item.h:1620
Cell cell(Int32 i) const
i-ème maille de la face
Definition Item.h:1633
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2)
Definition Item.h:1019
bool isSubDomainBoundary() const
Indique si la face est au bord du sous-domaine (i.e nbCell()==1)
Definition Item.h:1038
Cell backCell() const
Maille derrière la face (maille nulle si aucune)
Definition Item.h:1614
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.
bool hasKey(KeyTypeConstRef id)
true si une valeur avec la clé id est présente
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual Int32 maxLocalId() const =0
virtual Integer faceBuilderVersion() const =0
Version de la numérotation des faces.
Echange d'informations entre processeurs.
virtual void addSender(Int32 rank)=0
Ajoute un processeur à envoyer.
virtual Integer nbSender() const =0
Nombre de processeurs auquel on envoie.
virtual Integer nbReceiver() const =0
Nombre de processeurs dont on va réceptionner les messages.
virtual bool initializeCommunicationsMessages()=0
Calcule les communications.
virtual ISerializeMessage * messageToSend(Integer i)=0
Message destiné au ième processeur.
virtual void processExchange()=0
Effectue l'échange avec les options par défaut de ParallelExchangerOptions.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual void allGatherVariable(ConstArrayView< char > send_buf, Array< char > &recv_buf)=0
Effectue un regroupement sur tous les processeurs.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
virtual void barrier()=0
Effectue une barière.
@ 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.
virtual void flush()=0
Flush tous les flots.
Int32 flags() const
Flags de l'entité
bool null() const
Vrai si l'entité est l'entité nulle.
@ II_Shared
L'entité est partagée par un autre sous-domaine.
Definition ItemFlags.h:51
@ II_HasBackCell
L'entité a une maille derrière.
Definition ItemFlags.h:45
@ II_SubDomainBoundary
L'entité est à la frontière de deux sous-domaines.
Definition ItemFlags.h:52
Infos sur un type d'entité du maillage.
Integer nbLocalNode() const
Nombre de noeuds de l'entité
Gestionnaire des types d'entités de maillage.
Definition ItemTypeMng.h:66
ItemTypeInfo * typeFromId(Integer id) const
Type correspondant au numéro id.
Identifiant unique d'une entité.
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:779
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:782
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:776
Classe de base d'un élément de maillage.
Definition Item.h:83
impl::MutableItemBase mutableItemBase() const
Partie interne modifiable de l'entité.
Definition Item.h:374
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:219
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
Definition Item.h:238
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:225
constexpr bool null() const
true si l'entité est nul (i.e. non connecté au maillage)
Definition Item.h:216
impl::ItemBase itemBase() const
Partie interne de l'entité.
Definition Item.h:363
Int16 type() const
Type de l'entité
Definition Item.h:241
Interface d'un message de sérialisation entre IMessagePassingMng.
virtual MessageRank destination() const =0
Rang du destinataire (si isSend() est vrai) ou de l'envoyeur.
virtual ISerializer * serializer()=0
Sérialiseur.
Int32 value() const
Valeur du rang.
Definition MessageRank.h:72
void setOwner(Integer suid, Int32 current_sub_domain)
Positionne le numéro du sous-domaine propriétaire de l'entité.
void addFlags(Int32 added_flags)
Ajoute les flags \added_flags à ceux de l'entité
Noeud d'un maillage.
Definition Item.h:573
Flot de sortie lié à une String.
Référence à une instance.
Vecteur 1D de données avec sémantique par référence.
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:227
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 fatal() const
Flot pour un message d'erreur fatale.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage error() const
Flot pour un message d'erreur.
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage pwarning() const
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.
IMeshUniqueIdMng * meshUniqueIdMng() const override
Gestionnare de la numérotation des identifiants uniques.
void _computeFacesUniqueIdsParallelV2()
Calcul les numéros uniques de chaque face en parallèle V2.
void _computeFacesUniqueIdsSequential()
Calcul les numéros uniques de chaque face en séquentiel.
FaceUniqueIdBuilder(DynamicMeshIncrementalBuilder *mesh_builder)
Construit une instance pour le maillage mesh.
void _exchangeData(IParallelExchanger *exchanger, BoundaryInfosMap &boundary_infos_to_send)
void _checkNoDuplicate()
Vérifie qu'on n'a pas deux fois le même uniqueId().
void _computeFacesUniqueIdsParallelV1()
Calcul les numéros uniques de chaque face en parallèle.
Tableau associatif de ItemInternal.
void eachItem(const Lambda &lambda)
Fonction template pour itérer sur les entités de l'instance.
bool hasKey(Int64 key)
true si une valeur avec la clé id est présente
impl::ItemBase tryFind(Int64 key) const
Retourne l'entité associée à key si trouvé ou l'entité nulle sinon.
static Face findFaceInNode2(Node node, Integer face_type_id, Int64ConstArrayView face_nodes_uid)
Definition ItemTools.cc:44
Classe d'aide pour la détermination en parallèle des unique_id des faces.
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
Integer toInteger(Real r)
Converti un Int64 en un Integer.
@ ReduceSum
Somme des valeurs.
@ 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
bool arcaneIsCheck()
Vrai si on est en mode vérification.
Definition Misc.cc:68
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:426
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:567
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:428
double Real
Type représentant un réel.
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
Definition UtilsTypes.h:434
std::int32_t Int32
Type entier signé sur 32 bits.