Arcane  4.1.11.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-2026 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 of unique face identifiers. */
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 or 2
90 if (is_parallel) {
91 if (face_version == 2) {
92 //NOT YET BY DEFAULT
93 info() << "Use new mesh init in FaceUniqueIdBuilder";
95 }
96 else {
97 // Default version.
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 // We must re-index #m_faces_map because the uniqueId() of the
116 // faces have been modified
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 // With version 0 or 5, the owners are not positioned
128 // We must do it now
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/*---------------------------------------------------------------------------*/
166class T_CellFaceInfo
167{
168 public:
169
170 T_CellFaceInfo(Int64 uid, Integer nb_back_face, Integer nb_true_boundary_face)
171 : m_unique_id(uid)
172 , m_nb_back_face(nb_back_face)
173 , m_nb_true_boundary_face(nb_true_boundary_face)
174 {
175 }
176
177 T_CellFaceInfo()
178 : m_unique_id(NULL_ITEM_ID)
179 , m_nb_back_face(0)
180 , m_nb_true_boundary_face(0)
181 {
182 }
183
184 public:
185
186 bool operator<(const T_CellFaceInfo& ci) const
187 {
188 return m_unique_id < ci.m_unique_id;
189 }
190
191 public:
192
193 Int64 m_unique_id;
194 Int64 m_nb_back_face;
195 Int64 m_nb_true_boundary_face;
196};
197
198/*---------------------------------------------------------------------------*/
199/*---------------------------------------------------------------------------*/
217{
218 IParallelMng* pm = m_mesh->parallelMng();
219 Integer my_rank = pm->commRank();
220 Integer nb_rank = pm->commSize();
221
222 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
223 Integer nb_local_cell = m_mesh_builder->oneMeshItemAdder()->nbCell();
224 bool is_verbose = m_mesh_builder->isVerbose();
225
226 UniqueArray<Int64> faces_opposite_cell_uid(nb_local_face);
227 faces_opposite_cell_uid.fill(NULL_ITEM_ID);
228 UniqueArray<Integer> faces_opposite_cell_index(nb_local_face);
229 UniqueArray<Integer> faces_opposite_cell_owner(nb_local_face);
230
231 // For verification, ensures that all elements of this array
232 // are valid, which means that all faces have been
233 // renumbered
234 UniqueArray<Int64> faces_new_uid(nb_local_face);
235 faces_new_uid.fill(NULL_ITEM_ID);
236
237 Integer nb_recv_sub_domain_boundary_face = 0;
238
239 Int64UniqueArray faces_infos;
240 faces_infos.reserve(10000);
241 ItemInternalMap& cells_map = m_mesh->cellsMap();
242 ItemInternalMap& faces_map = m_mesh->facesMap();
243 ItemInternalMap& nodes_map = m_mesh->nodesMap();
244
245 // NOTE: this array is not useful on all meshes. It
246 // is enough that it contains the meshes that we need, that is to say
247 // ours + those connected to one of our faces. A hash table
248 // would be more appropriate.
249 HashTableMapT<Int64, Int64> cells_first_face_uid(m_mesh_builder->oneMeshItemAdder()->nbCell() * 2, true);
250
251 // Gather data from other processors into recv_cells;
252 // To prevent the arrays from being too large, we proceed in several
253 // steps.
254 // Each sub-domain builds its list of boundary faces, with for each face:
255 // - its type
256 // - the list of its nodes,
257 // - the unique number of its cell
258 // - the owner of its cell
259 // - its index in its cell
260 // This list will then be sent to all sub-domains.
261 {
262 ItemTypeMng* itm = m_mesh->itemTypeMng();
263
264 UniqueArray<Int32> faces_local_id;
265
266 faces_map.eachItem([&](Face face) {
267 bool boundary_val = face.isSubDomainBoundary();
268 if (boundary_val)
269 faces_local_id.add(face.localId());
270 });
271
272 Integer nb_sub_domain_boundary_face = faces_local_id.size();
273 Int64 global_nb_boundary_face = pm->reduce(Parallel::ReduceSum, (Int64)nb_sub_domain_boundary_face);
274 debug() << "NB BOUNDARY FACE=" << nb_sub_domain_boundary_face
275 << " NB_FACE=" << nb_local_face
276 << " GLOBAL_NB_BOUNDARY_FACE=" << global_nb_boundary_face;
277
278 Int64UniqueArray faces_infos2;
279 Int64UniqueArray recv_faces_infos;
280
281 // Calculate the size of a send block
282 // The memory required for a face is equal to nb_node + 4.
283 // If we assume we have quadrangles in general, this
284 // makes 8 Int64 per face, or 64 bytes per face.
285 // The memory required to send everything is therefore 64 * global_nb_boundary_face.
286 // step_size * nb_proc * 64 bytes.
287 // The default step_size is calculated so that the required memory
288 // is on the order of 100 Mo for each 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); // To indicate that the list ends
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 // We must not read the info that comes from me
343 if (i_sub_domain == my_rank) {
344 recv_faces_infos_index += faces_infos2.size();
345 continue;
346 }
347 // Deserializes the info for each subdomain
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 // If the face does not exist in my subdomain, it is not of interest to me
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 // Finds the max uniqueId of the meshes across all subdomains.
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 UniqueArray<T_CellFaceInfo> my_cells_faces_info;
401 my_cells_faces_info.reserve(nb_local_cell);
402 IntegerUniqueArray my_cells_nb_back_face(max_cell_local_id + 1);
403 my_cells_nb_back_face.fill(0);
404
405 cells_map.eachItem([&](Cell cell) {
406 Int64 cell_uid = cell.uniqueId().asInt64();
407 Int32 cell_local_id = cell.localId();
408 Integer nb_back_face = 0;
409 Integer nb_true_boundary_face = 0;
410 for (Face face : cell.faces()) {
411 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
412 if (face.backCell() == cell)
413 ++nb_back_face;
414 else if (face.nbCell() == 1 && opposite_cell_uid == NULL_ITEM_ID) {
415 ++nb_true_boundary_face;
416 }
417 }
418 my_cells_nb_back_face[cell_local_id] = nb_back_face;
419 my_cells_faces_info.add(T_CellFaceInfo(cell_uid, nb_back_face, nb_true_boundary_face));
420 });
421 std::sort(std::begin(my_cells_faces_info), std::end(my_cells_faces_info));
422
423 {
424 Integer nb_phase = 16;
425 Integer first_cell_index_to_send = 0;
426 Int64 current_face_uid = 0;
427
428 for (Integer i_phase = 0; i_phase < nb_phase; ++i_phase) {
429 Integer nb_uid_to_send = CheckedConvert::toInteger(global_max_cell_uid / nb_phase);
430 Integer first_uid_to_send = nb_uid_to_send * i_phase;
431 Int64 last_uid_to_send = first_uid_to_send + nb_uid_to_send;
432 if (i_phase + 1 == nb_phase)
433 last_uid_to_send = global_max_cell_uid;
434
435 //Integer last_cell_index_to_send = first_cell_index_to_send;
436 Integer nb_cell_to_send = 0;
437 for (Integer zz = first_cell_index_to_send, zs = my_cells_faces_info.size(); zz < zs; ++zz) {
438 if (my_cells_faces_info[zz].m_unique_id <= last_uid_to_send)
439 ++nb_cell_to_send;
440 else
441 break;
442 }
443 debug() << "FIRST TO SEND=" << first_cell_index_to_send
444 << " NB=" << nb_cell_to_send
445 << " first_uid=" << first_uid_to_send
446 << " last_uid=" << last_uid_to_send;
447
448 T_CellFaceInfo* begin_cell_array = my_cells_faces_info.data() + first_cell_index_to_send;
449 Int64* begin_array = reinterpret_cast<Int64*>(begin_cell_array);
450 Integer begin_size = nb_cell_to_send * 3;
451
452 Int64ConstArrayView cells_faces_infos(begin_size, begin_array);
453
454 Int64UniqueArray recv_cells_faces_infos;
455 pm->allGatherVariable(cells_faces_infos, recv_cells_faces_infos);
456 first_cell_index_to_send += nb_cell_to_send;
457
458 info() << "Infos faces (received) nb_int64=" << recv_cells_faces_infos.size();
459 Integer recv_nb_cell = recv_cells_faces_infos.size() / 3;
460
461 // NOTE: since we know the possible min and max uid, we can optimize by
462 // creating an array dimensioned with this min and max as bounds and
463 // filling the elements of this array directly. This way, we
464 UniqueArray<T_CellFaceInfo> global_cells_faces_info(recv_nb_cell);
465 for (Integer i = 0; i < recv_nb_cell; ++i) {
466 Int64 cell_uid = recv_cells_faces_infos[i * 3];
467 global_cells_faces_info[i].m_unique_id = cell_uid;
468 global_cells_faces_info[i].m_nb_back_face = recv_cells_faces_infos[(i * 3) + 1];
469 global_cells_faces_info[i].m_nb_true_boundary_face = recv_cells_faces_infos[(i * 3) + 2];
470 }
471 info() << "Sorting the faces nb=" << global_cells_faces_info.size();
472 std::sort(std::begin(global_cells_faces_info), std::end(global_cells_faces_info));
473
474 for (Integer i = 0; i < recv_nb_cell; ++i) {
475 Int64 cell_uid = global_cells_faces_info[i].m_unique_id;
476 if (cells_map.hasKey(cell_uid) || cells_first_face_uid.hasKey(cell_uid))
477 cells_first_face_uid.add(cell_uid, current_face_uid);
478 current_face_uid += global_cells_faces_info[i].m_nb_back_face + global_cells_faces_info[i].m_nb_true_boundary_face;
479 }
480 }
481 }
482
483 cells_map.eachItem([&](Cell cell) {
484 Int64 cell_uid = cell.uniqueId();
485 Int32 cell_local_id = cell.localId();
486 Integer num_local_face = 0;
487 Integer num_true_boundary_face = 0;
488 for (Face face : cell.faces()) {
489 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
490 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
491 if (face.backCell() == cell) {
492 if (!cells_first_face_uid.hasKey(cell_uid))
493 fatal() << "NO KEY 0 for cell_uid=" << cell_uid;
494 face_new_uid = cells_first_face_uid[cell_uid] + num_local_face;
495 face.mutableItemBase().setOwner(my_rank, my_rank);
496 ++num_local_face;
497 }
498 else if (face.nbCell() == 1) {
499 if (opposite_cell_uid == NULL_ITEM_UNIQUE_ID) {
500 // This is a boundary face of the initial domain
501 if (!cells_first_face_uid.hasKey(cell_uid))
502 fatal() << "NO KEY 1 for cell_uid=" << cell_uid;
503 face_new_uid = cells_first_face_uid[cell_uid] + my_cells_nb_back_face[cell_local_id] + num_true_boundary_face;
504 ++num_true_boundary_face;
505 face.mutableItemBase().setOwner(my_rank, my_rank);
506 }
507 else {
508 if (!cells_first_face_uid.hasKey(opposite_cell_uid))
509 fatal() << "NO KEY 1 for cell_uid=" << cell_uid << " opoosite=" << opposite_cell_uid;
510 face_new_uid = cells_first_face_uid[opposite_cell_uid] + faces_opposite_cell_index[face.localId()];
511 face.mutableItemBase().setOwner(faces_opposite_cell_owner[face.localId()], my_rank);
512 }
513 }
514 if (face_new_uid != NULL_ITEM_UNIQUE_ID) {
515 faces_new_uid[face.localId()] = face_new_uid;
516 face.mutableItemBase().setUniqueId(face_new_uid);
517 }
518 }
519 });
520
521 // Verifies that all faces have been re-indexed
522 {
523 Integer nb_error = 0;
524 for (Integer i = 0, is = nb_local_face; i < is; ++i) {
525 if (faces_new_uid[i] == NULL_ITEM_UNIQUE_ID) {
526 ++nb_error;
527 if (nb_error < 10)
528 error() << "The face lid=" << i << " has not been re-indexed.";
529 }
530 }
531 if (nb_error != 0)
532 ARCANE_FATAL("Some ({0}) faces have not been reindexed", nb_error);
533 }
534
535 if (is_verbose) {
536 OStringStream ostr;
537 cells_map.eachItem([&](Cell cell) {
538 Int64 cell_uid = cell.uniqueId().asInt64();
539 Integer face_index = 0;
540 for (Face face : cell.faces()) {
541 Int64 opposite_cell_uid = faces_opposite_cell_uid[face.localId()];
542 bool shared = false;
543 bool true_boundary = false;
544 bool internal_other = false;
545 if (face.backCell() == cell) {
546 }
547 else if (face.nbCell() == 1) {
548 if (opposite_cell_uid == NULL_ITEM_ID)
549 true_boundary = true;
550 else
551 shared = true;
552 }
553 else {
554 internal_other = true;
555 opposite_cell_uid = face.backCell().uniqueId().asInt64();
556 }
557 ostr() << "NEW UNIQUE ID FOR FACE"
558 << " lid=" << face.localId()
559 << " cell=" << cell_uid
560 << " face=" << face.uniqueId()
561 << " nbcell=" << face.nbCell()
562 << " cellindex=" << face_index << " (";
563 for (Node node : face.nodes())
564 ostr() << ' ' << node.uniqueId();
565 ostr() << ")";
566 if (internal_other)
567 ostr() << " internal-other";
568 if (true_boundary)
569 ostr() << " true-boundary";
570 if (opposite_cell_uid != NULL_ITEM_ID) {
571 ostr() << " opposite " << opposite_cell_uid;
572 }
573 if (shared)
574 ostr() << " (shared)";
575 ostr() << "\n";
576 ++face_index;
577 }
578 });
579 info() << ostr.str();
580 String file_name("faces_uid.");
581 file_name = file_name + my_rank;
582 std::ofstream ofile(file_name.localstr());
583 ofile << ostr.str();
584 }
585}
586
587/*---------------------------------------------------------------------------*/
588/*---------------------------------------------------------------------------*/
594_exchangeData(IParallelExchanger* exchanger, BoundaryInfosMap& boundary_infos_to_send)
595{
596 for (BoundaryInfosMapEnumerator i_map(boundary_infos_to_send); ++i_map;) {
597 Int32 sd = i_map.data()->key();
598 exchanger->addSender(sd);
599 }
601 Integer nb_sender = exchanger->nbSender();
602 Integer nb_receiver = exchanger->nbReceiver();
603 info() << "NB_SEND=" << nb_sender << " NB_RECV=" << nb_receiver;
604 Integer total = nb_sender + nb_receiver;
605 Integer global_total = exchanger->parallelMng()->reduce(Parallel::ReduceSum, total);
606 info() << "GLOBAL_NB_MESSAGE=" << global_total;
607
608 {
609 for (Integer i = 0, ns = exchanger->nbSender(); i < ns; ++i) {
610 ISerializeMessage* sm = exchanger->messageToSend(i);
611 Int32 rank = sm->destination().value();
612 ISerializer* s = sm->serializer();
613 Int64ConstArrayView infos = boundary_infos_to_send[rank];
614 Integer nb_info = infos.size();
615 s->setMode(ISerializer::ModeReserve);
616 s->reserveInt64(1); // For the number of elements
617 s->reserveSpan(eBasicDataType::Int64, nb_info); // For the elements
618 s->allocateBuffer();
620 s->putInt64(nb_info);
621 s->putSpan(infos);
622 }
623 }
624 exchanger->processExchange();
625 debug() << "END EXCHANGE";
626}
627
628template <typename DataType>
630{
631 public:
632 private:
633
634 class MyInfo
635 {
636 public:
637
638 MyInfo(const DataType& d, Integer n)
639 : data(d)
640 , next_index(n)
641 {}
642
643 public:
644
645 DataType data;
646 Integer next_index;
647 };
648
649 public:
650
651 ItemInfoMultiList()
652 : m_last_index(5000, true)
653 {}
654
655 public:
656
657 void add(Int64 node_uid, const DataType& data)
658 {
659 Integer current_index = m_values.size();
660
661 bool is_add = false;
662 HashTableMapT<Int64, Int32>::Data* d = m_last_index.lookupAdd(node_uid, -1, is_add);
663
664 m_values.add(MyInfo(data, d->value()));
665 d->value() = current_index;
666 }
667
668 public:
669
670 UniqueArray<MyInfo> m_values;
671 HashTableMapT<Int64, Int32> m_last_index;
672};
673
674/*---------------------------------------------------------------------------*/
675/*---------------------------------------------------------------------------*/
685{
686 IParallelMng* pm = m_mesh->parallelMng();
687 Integer my_rank = pm->commRank();
688 Integer nb_rank = pm->commSize();
689
690 Integer nb_local_face = m_mesh_builder->oneMeshItemAdder()->nbFace();
691 //Integer nb_local_cell = m_mesh_builder->nbCell();
692 //bool is_verbose = m_mesh_builder->isVerbose();
693
694 Int64UniqueArray faces_opposite_cell_uid(nb_local_face);
695 faces_opposite_cell_uid.fill(NULL_ITEM_ID);
696 IntegerUniqueArray faces_opposite_cell_index(nb_local_face);
697 IntegerUniqueArray faces_opposite_cell_owner(nb_local_face);
698
699 // For verification, ensures that all elements of this array
700 // are valid, which means that all faces have been renumbered.
701 Int64UniqueArray faces_new_uid(nb_local_face);
702 faces_new_uid.fill(NULL_ITEM_ID);
703
704 Int64UniqueArray faces_infos;
705 faces_infos.reserve(10000);
706 ItemInternalMap& faces_map = m_mesh->facesMap();
707 ItemInternalMap& nodes_map = m_mesh->nodesMap();
708
709 // NOTE: this array is not useful on all meshes. It
710 // is enough that it contains the meshes we need, that is,
711 // ours + those connected to one of our faces.
712 HashTableMapT<Int32, Int32> cell_first_face_uid(m_mesh_builder->oneMeshItemAdder()->nbCell() * 2, true);
713
714 // Collects data from other processors into recv_cells;
715 // To prevent the arrays from being too large, we proceed in several
716 // steps.
717 // Each subdomain builds its list of boundary faces, for each face:
718 // - its type
719 // - the list of its nodes,
720 // - the unique ID of its mesh
721 // - the owner of its mesh
722 // - its index in its mesh
723 // This list will then be sent to all subdomains.
724 ItemTypeMng* itm = m_mesh->itemTypeMng();
725
726 // Determines the max unique id of the nodes
727 Int64 my_max_node_uid = NULL_ITEM_UNIQUE_ID;
728 nodes_map.eachItem([&](Item node) {
729 Int64 node_uid = node.uniqueId();
730 if (node_uid > my_max_node_uid)
731 my_max_node_uid = node_uid;
732 });
733 Int64 global_max_node_uid = pm->reduce(Parallel::ReduceMax, my_max_node_uid);
734 debug() << "NODE_UID_INFO: MY_MAX_UID=" << my_max_node_uid
735 << " GLOBAL=" << global_max_node_uid;
736
737 //TODO: choose a good value to initialize the table
738 BoundaryInfosMap boundary_infos_to_send(nb_rank, true);
739 NodeUidToSubDomain uid_to_subdomain_converter(global_max_node_uid, nb_rank);
740 info() << "NB_CORE modulo=" << uid_to_subdomain_converter.modulo();
741 HashTableMapT<Int64, SharedArray<Int64>> nodes_info(100000, true);
742 IItemFamily* node_family = m_mesh->nodeFamily();
743 UniqueArray<bool> is_boundary_nodes(node_family->maxLocalId(), false);
744
745 // Marks all boundary nodes because these are the ones that need to be sent
746 faces_map.eachItem([&](Face face) {
747 Integer face_nb_cell = face.nbCell();
748 if (face_nb_cell == 1) {
749 for (Node node : face.nodes())
750 is_boundary_nodes[node.localId()] = true;
751 }
752 });
753
754 // Determines the list of boundary faces
755 faces_map.eachItem([&](Face face) {
756 Node first_node = face.node(0);
757 Int64 first_node_uid = first_node.uniqueId();
759 Int32 dest_rank = -1;
760 if (!is_boundary_nodes[first_node.localId()]) {
761 v = nodes_info.lookupAdd(first_node_uid)->value();
762 }
763 else {
764 dest_rank = uid_to_subdomain_converter.uidToRank(first_node_uid);
765 v = boundary_infos_to_send.lookupAdd(dest_rank)->value();
766 }
767 v.add(first_node_uid); // 0
768 v.add(my_rank); // 1
769 v.add(face.uniqueId()); // 2
770 v.add(face.type()); // 3
771 Cell back_cell = face.backCell();
772 Cell front_cell = face.frontCell();
773 if (back_cell.null()) // 4 : only used for debug
774 v.add(NULL_ITEM_UNIQUE_ID);
775 else
776 v.add(back_cell.uniqueId());
777 if (front_cell.null()) // 5 : only used for debug
778 v.add(NULL_ITEM_UNIQUE_ID);
779 else
780 v.add(front_cell.uniqueId());
781 for (Integer z = 0, zs = face.nbNode(); z < zs; ++z)
782 v.add(face.node(z).uniqueId());
783 });
784
785 // Positions the list of sends
787 _exchangeData(exchanger.get(), boundary_infos_to_send);
788
789 {
790 Integer nb_receiver = exchanger->nbReceiver();
791 debug() << "NB RECEIVER=" << nb_receiver;
792 Int64UniqueArray received_infos;
793 for (Integer i = 0; i < nb_receiver; ++i) {
794 ISerializeMessage* sm = exchanger->messageToReceive(i);
795 //Int32 orig_rank = sm->destSubDomain();
796 ISerializer* s = sm->serializer();
798 Int64 nb_info = s->getInt64();
799 //info() << "RECEIVE NB_INFO=" << nb_info << " from=" << orig_rank;
800 received_infos.resize(nb_info);
801 s->getSpan(received_infos);
802 //if ((nb_info % 3)!=0)
803 //fatal() << "info size can not be divided by 3";
804 Integer z = 0;
805 while (z < nb_info) {
806 Int64 node_uid = received_infos[z + 0];
807 Int32 face_type = (Int32)received_infos[z + 3];
808 ItemTypeInfo* itt = itm->typeFromId(face_type);
809 Integer face_nb_node = itt->nbLocalNode();
810 Int64Array& a = nodes_info.lookupAdd(node_uid)->value();
811 a.addRange(Int64ConstArrayView(6 + face_nb_node, &received_infos[z]));
812 z += 6;
813 z += face_nb_node;
814 }
815 }
816 Integer my_max_face_node = 0;
817 for (HashTableMapT<Int64, SharedArray<Int64>>::Enumerator inode(nodes_info); ++inode;) {
818 Int64ConstArrayView a = *inode;
819 Integer nb_info = a.size();
820 Integer z = 0;
821 Integer node_nb_face = 0;
822 while (z < nb_info) {
823 ++node_nb_face;
824 Int32 face_type = (Int32)a[z + 3];
825 ItemTypeInfo* itt = itm->typeFromId(face_type);
826 Integer face_nb_node = itt->nbLocalNode();
827 z += 6;
828 z += face_nb_node;
829 }
830 my_max_face_node = math::max(node_nb_face, my_max_face_node);
831 }
832 Integer global_max_face_node = pm->reduce(Parallel::ReduceMax, my_max_face_node);
833 debug() << "GLOBAL MAX FACE NODE=" << global_max_face_node;
834 // OK, maintenant donne comme uid de la face (node_uid * global_max_face_node + index)
835 IntegerUniqueArray indexes;
836 boundary_infos_to_send = BoundaryInfosMap(nb_rank, true);
837
838 for (HashTableMapT<Int64, SharedArray<Int64>>::Enumerator inode(nodes_info); ++inode;) {
839 Int64ConstArrayView a = *inode;
840 Integer nb_info = a.size();
841 Integer z = 0;
842 Integer node_nb_face = 0;
843 indexes.clear();
844 while (z < nb_info) {
845 Int64 node_uid = a[z + 0];
846 Int32 sender_rank = (Int32)a[z + 1];
847 Int64 face_uid = a[z + 2];
848 Int32 face_type = (Int32)a[z + 3];
849 ItemTypeInfo* itt = itm->typeFromId(face_type);
850 Integer face_nb_node = itt->nbLocalNode();
851
852 // Checks if the face is already in the list:
853 Integer face_index = node_nb_face;
854 Int32 face_new_owner = sender_rank;
855 for (Integer y = 0; y < node_nb_face; ++y) {
856 if (memcmp(&a[indexes[y] + 6], &a[z + 6], sizeof(Int64) * face_nb_node) == 0) {
857 face_index = y;
858 face_new_owner = (Int32)a[indexes[y] + 1];
859 }
860 }
861 Int64 face_new_uid = (node_uid * global_max_face_node) + face_index;
862 Int64Array& v = boundary_infos_to_send.lookupAdd(sender_rank)->value();
863 // Indicates to the owner of this face its new uid
864 v.add(face_uid);
865 v.add(face_new_uid);
866 v.add(face_new_owner);
867 indexes.add(z);
868 z += 6;
869 z += face_nb_node;
870 ++node_nb_face;
871 }
872 my_max_face_node = math::max(node_nb_face, my_max_face_node);
873 }
874 }
876
877 _exchangeData(exchanger.get(), boundary_infos_to_send);
878 {
879 Integer nb_receiver = exchanger->nbReceiver();
880 debug() << "NB RECEIVER=" << nb_receiver;
881 Int64UniqueArray received_infos;
882 for (Integer i = 0; i < nb_receiver; ++i) {
883 ISerializeMessage* sm = exchanger->messageToReceive(i);
884 ISerializer* s = sm->serializer();
886 Int64 nb_info = s->getInt64();
887 received_infos.resize(nb_info);
888 s->getSpan(received_infos);
889 if ((nb_info % 3) != 0)
890 ARCANE_FATAL("info size can not be divided by 3 v={0}", nb_info);
891 ;
892 Int64 nb_item = nb_info / 3;
893 for (Int64 z = 0; z < nb_item; ++z) {
894 Int64 old_uid = received_infos[(z * 3)];
895 Int64 new_uid = received_infos[(z * 3) + 1];
896 Int32 new_owner = (Int32)received_infos[(z * 3) + 2];
897 impl::MutableItemBase face(faces_map.tryFind(old_uid));
898 if (face.null())
899 ARCANE_FATAL("Can not find own face uid={0}", old_uid);
900 face.setUniqueId(new_uid);
901 face.setOwner(new_owner, my_rank);
902 }
903 }
904 }
905
906 traceMng()->flush();
907 pm->barrier();
908 debug() << "END OF TEST NEW FACE COMPUTE";
909 return;
910}
911
912/*---------------------------------------------------------------------------*/
913/*---------------------------------------------------------------------------*/
921{
922 bool is_verbose = m_mesh_builder->isVerbose();
923
924 ItemInternalMap& cells_map = m_mesh->cellsMap();
925
926 // In sequential mode, the uniqueIds() of the meshes cannot exceed the
927 // size of Integers even in 32 bits.
928 Int32 max_uid = 0;
929 cells_map.eachItem([&](Item cell) {
930 Int32 cell_uid = cell.uniqueId().asInt32();
931 if (cell_uid > max_uid)
932 max_uid = cell_uid;
933 });
934 info() << "Max uid=" << max_uid;
935 Integer nb_computed = max_uid + 1;
936 Int32UniqueArray cell_first_face_uid(nb_computed, 0);
937 Int32UniqueArray cell_nb_num_back_face(nb_computed, 0);
938 Int32UniqueArray cell_true_boundary_face(nb_computed, 0);
939
940 cells_map.eachItem([&](Cell cell) {
941 Int32 cell_uid = cell.uniqueId().asInt32();
942 Integer nb_num_back_face = 0;
943 Integer nb_true_boundary_face = 0;
944 for (Face face : cell.faces()) {
945 if (face.backCell() == cell)
946 ++nb_num_back_face;
947 else if (face.nbCell() == 1) {
948 ++nb_true_boundary_face;
949 }
950 }
951 cell_nb_num_back_face[cell_uid] = nb_num_back_face;
952 cell_true_boundary_face[cell_uid] = nb_true_boundary_face;
953 });
954
955 Integer current_face_uid = 0;
956 for (Integer i = 0; i < nb_computed; ++i) {
957 cell_first_face_uid[i] = current_face_uid;
958 current_face_uid += cell_nb_num_back_face[i] + cell_true_boundary_face[i];
959 }
960
961 if (is_verbose) {
962 cells_map.eachItem([&](Item cell) {
963 Int32 i = cell.uniqueId().asInt32();
964 info() << "Recv: Cell FaceInfo celluid=" << i
965 << " firstfaceuid=" << cell_first_face_uid[i]
966 << " nbback=" << cell_nb_num_back_face[i]
967 << " nbbound=" << cell_true_boundary_face[i];
968 });
969 }
970
971 cells_map.eachItem([&](Cell cell) {
972 Int32 cell_uid = cell.uniqueId().asInt32();
973 Integer nb_num_back_face = 0;
974 Integer nb_true_boundary_face = 0;
975 for (Face face : cell.faces()) {
976 Int64 face_new_uid = NULL_ITEM_UNIQUE_ID;
977 if (face.backCell() == cell) {
978 face_new_uid = cell_first_face_uid[cell_uid] + nb_num_back_face;
979 ++nb_num_back_face;
980 }
981 else if (face.nbCell() == 1) {
982 face_new_uid = cell_first_face_uid[cell_uid] + cell_nb_num_back_face[cell_uid] + nb_true_boundary_face;
983 ++nb_true_boundary_face;
984 }
985 if (face_new_uid != NULL_ITEM_UNIQUE_ID) {
986 face.mutableItemBase().setUniqueId(face_new_uid);
987 }
988 }
989 });
990
991 if (is_verbose) {
992 OStringStream ostr;
993 cells_map.eachItem([&](Cell cell) {
994 Integer face_index = 0;
995 for (Face face : cell.faces()) {
996 Int64 opposite_cell_uid = NULL_ITEM_UNIQUE_ID;
997 bool true_boundary = false;
998 bool internal_other = false;
999 if (face.backCell() == cell) {
1000 }
1001 else if (face.nbCell() == 1) {
1002 true_boundary = true;
1003 }
1004 else {
1005 internal_other = true;
1006 opposite_cell_uid = face.backCell().uniqueId().asInt64();
1007 }
1008 ostr() << "NEW LOCAL ID FOR CELLFACE cell_uid=" << cell.uniqueId() << ' '
1009 << face_index << " uid=" << face.uniqueId() << " (";
1010 for (Node node : face.nodes())
1011 ostr() << ' ' << node.uniqueId();
1012 ostr() << ")";
1013 if (internal_other)
1014 ostr() << " internal-other";
1015 if (true_boundary)
1016 ostr() << " true-boundary";
1017 if (opposite_cell_uid != NULL_ITEM_ID)
1018 ostr() << " opposite " << opposite_cell_uid;
1019 ostr() << '\n';
1020 ++face_index;
1021 }
1022 });
1023 info() << ostr.str();
1024 }
1025}
1026
1027/*---------------------------------------------------------------------------*/
1028/*---------------------------------------------------------------------------*/
1029
1030} // End namespace Arcane::mesh
1031
1032/*---------------------------------------------------------------------------*/
1033/*---------------------------------------------------------------------------*/
#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:1214
FaceConnectedListViewType faces() const
Liste des faces de la maille.
Definition Item.h:1298
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Classe pour convertir un FaceLocalId vers une face.
Face d'une maille.
Definition Item.h:964
Cell frontCell() const
Maille devant la face (maille nulle si aucune).
Definition Item.h:1652
Cell cell(Int32 i) const
i-ème maille de la face
Definition Item.h:1665
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2).
Definition Item.h:1042
bool isSubDomainBoundary() const
Indique si la face est au bord du sous-domaine (i.e nbCell()==1).
Definition Item.h:1061
Cell backCell() const
Maille derrière la face (maille nulle si aucune).
Definition Item.h:1646
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.
É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 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:58
@ II_HasBackCell
L'entité a une maille derrière.
Definition ItemFlags.h:52
@ II_SubDomainBoundary
L'entité est à la frontière de deux sous-domaines.
Definition ItemFlags.h:59
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.
Identifiant unique d'une entité.
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:791
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:794
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:788
Classe de base d'un élément de maillage.
Definition Item.h:83
impl::MutableItemBase mutableItemBase() const
Partie interne modifiable de l'entité.
Definition Item.h:380
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: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
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:582
Flot de sortie lié à une String.
InstanceType * get() const
Instance associée ou nullptr si aucune.
Référence à une instance.
Vecteur 1D de données avec sémantique par référence.
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:228
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).
Implementation of a mesh.
Definition DynamicMesh.h:98
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()
Calculates the unique IDs for each face in parallel V2.
void _computeFacesUniqueIdsSequential()
Calculates the unique IDs for each face sequentially.
FaceUniqueIdBuilder(DynamicMeshIncrementalBuilder *mesh_builder)
Constructs an instance for the mesh.
void _exchangeData(IParallelExchanger *exchanger, BoundaryInfosMap &boundary_infos_to_send)
void _checkNoDuplicate()
Checks that there are no duplicate uniqueIds.
void _computeFacesUniqueIdsParallelV1()
Calculates the unique numbers for each face in parallel.
Associative array of ItemInternal.
void eachItem(const Lambda &lambda)
Template function to iterate over the instance's entities.
bool hasKey(Int64 key)
true if a value with the key id is present
impl::ItemBase tryFind(Int64 key) const
Returns the entity associated with key if found, or the null entity otherwise.
static Face findFaceInNode2(Node node, Integer face_type_id, Int64ConstArrayView face_nodes_uid)
Definition ItemTools.cc:44
Helper class for parallel determination of face unique_ids.
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
@ ReduceSum
Somme des valeurs.
@ ReduceMax
Maximum des valeurs.
Ref< IParallelExchanger > createExchangerRef(IParallelMng *pm)
Retourne une interface pour transférer des messages entre rangs.
Real getRealTime()
Temps Real utilisé en secondes.
Array< Int64 > Int64Array
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:125
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:339
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:480
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:341
double Real
Type représentant un réel.
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
Definition UtilsTypes.h:347
std::int32_t Int32
Type entier signé sur 32 bits.