Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
MeshUtils.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/* MeshUtils.cc (C) 2000-2026 */
9/* */
10/* Miscellaneous functions on mesh elements. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/CheckedConvert.h"
15#include "arcane/utils/List.h"
16#include "arcane/utils/ScopedPtr.h"
17#include "arcane/utils/OStringStream.h"
18#include "arcane/utils/StringBuilder.h"
19#include "arcane/utils/ITraceMng.h"
20#include "arcane/utils/JSONWriter.h"
21#include "arcane/utils/IHashAlgorithm.h"
22
24#include "arcane/core/IVariableMng.h"
25#include "arcane/core/VariableTypes.h"
26#include "arcane/core/ISubDomain.h"
27#include "arcane/core/StdNum.h"
28#include "arcane/core/MeshVariableInfo.h"
29#include "arcane/core/Variable.h"
30#include "arcane/core/IMesh.h"
31#include "arcane/core/IMeshSubMeshTransition.h"
33#include "arcane/core/ItemGroup.h"
34#include "arcane/core/Item.h"
35#include "arcane/core/ItemCompare.h"
36#include "arcane/core/ItemPrinter.h"
38#include "arcane/core/XmlNode.h"
39#include "arcane/core/XmlNodeList.h"
40#include "arcane/core/IParallelMng.h"
41#include "arcane/core/IIOMng.h"
42#include "arcane/core/IXmlDocumentHolder.h"
43#include "arcane/core/IItemFamily.h"
44#include "arcane/core/VariableCollection.h"
45#include "arcane/core/ITiedInterface.h"
46#include "arcane/core/SharedVariable.h"
47#include "arcane/core/MeshVisitor.h"
48#include "arcane/core/IMeshUtilities.h"
49#include "arcane/core/IVariableSynchronizer.h"
50#include "arcane/core/UnstructuredMeshConnectivity.h"
51#include "arcane/core/datatype/DataAllocationInfo.h"
52
54
55#include <algorithm>
56#include <map>
57
58/*---------------------------------------------------------------------------*/
59/*---------------------------------------------------------------------------*/
60
61namespace Arcane
62{
63using impl::ItemBase;
64
65/*---------------------------------------------------------------------------*/
66/*---------------------------------------------------------------------------*/
67
68// #define ARCANE_DEBUG_MESH
69
70/*---------------------------------------------------------------------------*/
71/*---------------------------------------------------------------------------*/
72
73template <class ValueType> inline void
74_writeValue(ITraceMng* trace, const String& name, ValueType v)
75{
76 Integer wl = CheckedConvert::toInteger(65 - name.length());
77 trace->pinfo() << name << Trace::Width(wl) << v;
78}
79
80template <> inline void
81_writeValue(ITraceMng* trace, const String& name, Real3 v)
82{
83 Integer wl = CheckedConvert::toInteger(63 - name.length());
84 trace->pinfo() << name << ".x" << Trace::Width(wl) << v.x;
85 trace->pinfo() << name << ".y" << Trace::Width(wl) << v.y;
86 trace->pinfo() << name << ".z" << Trace::Width(wl) << v.z;
87}
88
89template <> inline void
90_writeValue(ITraceMng* trace, const String& name, Real3x3 v)
91{
92 Integer wl = CheckedConvert::toInteger(62 - name.length());
93 trace->pinfo() << name << ".xx" << Trace::Width(wl) << v.x.x;
94 trace->pinfo() << name << ".xy" << Trace::Width(wl) << v.x.y;
95 trace->pinfo() << name << ".xz" << Trace::Width(wl) << v.x.z;
96
97 trace->pinfo() << name << ".yx" << Trace::Width(wl) << v.y.x;
98 trace->pinfo() << name << ".yy" << Trace::Width(wl) << v.y.y;
99 trace->pinfo() << name << ".yz" << Trace::Width(wl) << v.y.z;
100
101 trace->pinfo() << name << ".zx" << Trace::Width(wl) << v.z.x;
102 trace->pinfo() << name << ".zy" << Trace::Width(wl) << v.z.y;
103 trace->pinfo() << name << ".zz" << Trace::Width(wl) << v.z.z;
104}
105
106template <class ItemType, class ValueType> inline void
107_writeInfo(ISubDomain* mng, const VariableCollection& variables, const ItemType& item)
108{
109 typedef typename MeshVariableInfoT<ItemType, ValueType, 0>::PrivateType VariableScalarTrueType;
110 typedef typename MeshVariableInfoT<ItemType, ValueType, 1>::PrivateType VariableArrayTrueType;
111
112 ITraceMng* trace = mng->traceMng();
114
115 for (VariableCollection::Enumerator i(variables); ++i;) {
116 IVariable* vp = *i;
117 // For now, does not display partial variables
118 if (vp->isPartial())
119 continue;
120 // Checks if it is indeed a mesh variable and of the correct type
121 ItemGroup group = vp->itemGroup();
122 if (group.itemKind() != item_kind)
123 continue;
124
125 const String& name = vp->name();
126 auto* v = dynamic_cast<VariableScalarTrueType*>(vp);
127 if (v) {
128 ConstArrayView<ValueType> values = v->valueView();
129 if (values.size() < item.localId()) {
130 trace->error() << "Invalid dimensions for variable '" << name << "' "
131 << "(size=" << values.size() << " index=" << item.localId();
132 continue;
133 }
134 _writeValue(trace, name, values[item.localId()]);
135 }
136
137 auto* v2 = dynamic_cast<VariableArrayTrueType*>(vp);
138 if (v2) {
139 Array2View<ValueType> values = v2->valueView();
140 Integer lid = item.localId();
141 if (values.dim1Size() < lid) {
142 trace->error() << "Invalid dimensions for variable '" << name << "' "
143 << "(size=" << values.dim1Size() << " index=" << lid;
144 continue;
145 }
146 Integer n = values[lid].size();
147 for (Integer z = 0; z < n; ++z) {
148 _writeValue(trace, name + "[" + z + "]", values[lid][z]);
149 }
150 }
151 }
152}
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
156
157void MeshUtils::
158writeMeshItemInfo(ISubDomain* sd, Cell cell, bool depend_info)
159{
160 ITraceMng* trace = sd->traceMng();
161 Integer sid = sd->subDomainId();
162 StringBuilder buf("Info-");
163 buf += sid;
164 Trace::Setter mci(trace, buf.toString());
165
166 VariableCollection variables(sd->variableMng()->usedVariables());
167
168 Integer nb_node = cell.nbNode();
169 Integer nb_edge = cell.nbEdge();
170 Integer nb_face = cell.nbFace();
171
172 trace->pinfo() << "** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- **";
173 trace->pinfo() << "** -- Dumping information for cell " << cell.uniqueId();
174 trace->pinfo() << "** -- Structure:";
175 trace->pinfo() << "unique id: " << Trace::Width(5) << cell.uniqueId();
176 trace->pinfo() << "local id: " << Trace::Width(5) << cell.localId();
177 trace->pinfo() << "owner: " << Trace::Width(5) << cell.owner();
178 trace->pinfo() << "type: " << Trace::Width(5) << cell.typeInfo()->typeName();
179
180 trace->pinfo() << "number of nodes: " << Trace::Width(5) << nb_node;
181 for (Integer i = 0; i < nb_node; ++i)
182 trace->pinfo() << "unique id of node " << Trace::Width(2)
183 << i << " : " << Trace::Width(5) << cell.node(i).uniqueId();
184
185 trace->pinfo() << "number of edges: " << Trace::Width(5) << nb_edge;
186 for (Integer i = 0; i < nb_edge; ++i)
187 trace->pinfo() << "unique id of edge " << Trace::Width(2)
188 << i << " : " << Trace::Width(5) << cell.edge(i).uniqueId();
189
190 trace->pinfo() << "number of faces: " << Trace::Width(5) << nb_face;
191 for (Integer i = 0; i < nb_face; ++i)
192 trace->pinfo() << "local id of face " << Trace::Width(2)
193 << i << " : " << Trace::Width(5) << cell.face(i).localId();
194
195 trace->pinfo() << "** -- Variables:";
196 _writeInfo<Cell, Real>(sd, variables, cell);
197 _writeInfo<Cell, Real2>(sd, variables, cell);
198 _writeInfo<Cell, Real3>(sd, variables, cell);
199 _writeInfo<Cell, Real2x2>(sd, variables, cell);
200 _writeInfo<Cell, Real3x3>(sd, variables, cell);
201 _writeInfo<Cell, Int32>(sd, variables, cell);
202 _writeInfo<Cell, Int64>(sd, variables, cell);
203
204 trace->pinfo() << "** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- **";
205
206 if (depend_info) {
207 for (Integer i = 0; i < nb_node; ++i)
208 writeMeshItemInfo(sd, cell.node(i), false);
209 for (Integer i = 0; i < nb_edge; ++i)
210 writeMeshItemInfo(sd, cell.edge(i), false);
211 for (Integer i = 0; i < nb_face; ++i)
212 writeMeshItemInfo(sd, cell.face(i), false);
213 }
214}
215
216/*---------------------------------------------------------------------------*/
217/*---------------------------------------------------------------------------*/
218
219void MeshUtils::
220writeMeshItemInfo(ISubDomain* sd, Node node, bool depend_info)
221{
222 ITraceMng* trace = sd->traceMng();
223 Integer sid = sd->subDomainId();
224 StringBuilder buf("Info-");
225 buf += sid;
226 Trace::Setter mci(trace, buf.toString());
227
228 VariableCollection variables(sd->variableMng()->usedVariables());
229
230 Integer nb_cell = node.nbCell();
231 Integer nb_edge = node.nbEdge();
232 Integer nb_face = node.nbFace();
233
234 trace->pinfo() << "** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- **";
235 trace->pinfo() << "** -- Dumping information for node " << node.uniqueId();
236 trace->pinfo() << "** -- Structure:";
237 trace->pinfo() << "unique id: " << Trace::Width(5) << node.uniqueId();
238 trace->pinfo() << "local id: " << Trace::Width(5) << node.localId();
239 trace->pinfo() << "owner: " << Trace::Width(5) << node.owner();
240
241 trace->pinfo() << "number of cells: " << Trace::Width(5) << nb_cell;
242 for (Integer i = 0; i < nb_cell; ++i)
243 trace->pinfo() << "unique id of cell " << Trace::Width(2)
244 << i << " : " << Trace::Width(5) << node.cell(i).uniqueId();
245
246 trace->pinfo() << "number of faces: " << Trace::Width(5) << nb_face;
247 for (Integer i = 0; i < nb_face; ++i)
248 trace->pinfo() << "local id of face " << Trace::Width(2)
249 << i << " : " << Trace::Width(5) << node.face(i).localId();
250
251 trace->pinfo() << "** -- Variables:";
252 _writeInfo<Node, Real>(sd, variables, node);
253 _writeInfo<Node, Real2>(sd, variables, node);
254 _writeInfo<Node, Real3>(sd, variables, node);
255 _writeInfo<Node, Real2x2>(sd, variables, node);
256 _writeInfo<Node, Real3x3>(sd, variables, node);
257 _writeInfo<Node, Int32>(sd, variables, node);
258 _writeInfo<Node, Int64>(sd, variables, node);
259
260 if (depend_info) {
261 for (Integer i = 0; i < nb_cell; ++i)
262 writeMeshItemInfo(sd, node.cell(i), false);
263 for (Integer i = 0; i < nb_edge; ++i)
264 writeMeshItemInfo(sd, node.edge(i), false);
265 for (Integer i = 0; i < nb_face; ++i)
266 writeMeshItemInfo(sd, node.face(i), false);
267 }
268}
269
270/*---------------------------------------------------------------------------*/
271/*---------------------------------------------------------------------------*/
272
273void MeshUtils::
274writeMeshItemInfo(ISubDomain* sd, Edge edge, bool depend_info)
275{
276 ITraceMng* trace = sd->traceMng();
277 Integer sid = sd->subDomainId();
278 StringBuilder buf("Info-");
279 buf += sid;
280 Trace::Setter mci(trace, buf.toString());
281
282 VariableCollection variables(sd->variableMng()->usedVariables());
283
284 Integer nb_cell = edge.nbCell();
285 Integer nb_face = edge.nbFace();
286 Integer nb_node = edge.nbNode();
287
288 trace->pinfo() << "** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- **";
289 trace->pinfo() << "** -- Dumping information for face " << edge.localId() << " (localid)";
290 trace->pinfo() << "** -- Structure:";
291 trace->pinfo() << "unique id: " << Trace::Width(5) << "None";
292 trace->pinfo() << "local id: " << Trace::Width(5) << edge.localId();
293 trace->pinfo() << "owner: " << Trace::Width(5) << edge.owner();
294
295 trace->pinfo() << "number of nodes: " << Trace::Width(5) << nb_node;
296 for (Integer i = 0; i < nb_node; ++i)
297 trace->pinfo() << "unique id of node " << Trace::Width(2)
298 << i << " : " << Trace::Width(5) << edge.node(i).uniqueId();
299
300 trace->pinfo() << "number of cells: " << Trace::Width(5) << nb_cell;
301 for (Integer i = 0; i < nb_cell; ++i)
302 trace->pinfo() << "unique id of cell " << Trace::Width(2)
303 << i << " : " << Trace::Width(5) << edge.cell(i).uniqueId();
304
305 trace->pinfo() << "** -- Variables:";
306 _writeInfo<Edge, Real>(sd, variables, edge);
307 _writeInfo<Edge, Real2>(sd, variables, edge);
308 _writeInfo<Edge, Real3>(sd, variables, edge);
309 _writeInfo<Edge, Real2x2>(sd, variables, edge);
310 _writeInfo<Edge, Real3x3>(sd, variables, edge);
311 _writeInfo<Edge, Int32>(sd, variables, edge);
312 _writeInfo<Edge, Int64>(sd, variables, edge);
313
314 if (depend_info) {
315 for (Integer i = 0; i < nb_node; ++i)
316 writeMeshItemInfo(sd, edge.node(i), false);
317 for (Integer i = 0; i < nb_face; ++i)
318 writeMeshItemInfo(sd, edge.face(i), false);
319 for (Integer i = 0; i < nb_cell; ++i)
320 writeMeshItemInfo(sd, edge.cell(i), false);
321 }
322}
323
324/*---------------------------------------------------------------------------*/
325/*---------------------------------------------------------------------------*/
326
327void MeshUtils::
328writeMeshItemInfo(ISubDomain* sd, Face face, bool depend_info)
329{
330 ITraceMng* trace = sd->traceMng();
331 Integer sid = sd->subDomainId();
332 StringBuilder buf("Info-");
333 buf += sid;
334 Trace::Setter mci(trace, buf.toString());
335
336 VariableCollection variables(sd->variableMng()->usedVariables());
337
338 Integer nb_cell = face.nbCell();
339 Integer nb_edge = face.nbEdge();
340 Integer nb_node = face.nbNode();
341
342 trace->pinfo() << "** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- ** -- **";
343 trace->pinfo() << "** -- Dumping information for face " << face.localId() << " (localid)";
344 trace->pinfo() << "** -- Structure:";
345 trace->pinfo() << "unique id: " << Trace::Width(5) << "None";
346 trace->pinfo() << "local id: " << Trace::Width(5) << face.localId();
347 trace->pinfo() << "owner: " << Trace::Width(5) << face.owner();
348
349 trace->pinfo() << "number of nodes: " << Trace::Width(5) << nb_node;
350 for (Integer i = 0; i < nb_node; ++i)
351 trace->pinfo() << "unique id of node " << Trace::Width(2)
352 << i << " : " << Trace::Width(5) << face.node(i).uniqueId();
353
354 trace->pinfo() << "number of cells: " << Trace::Width(5) << nb_cell;
355 for (Integer i = 0; i < nb_cell; ++i)
356 trace->pinfo() << "unique id of cell " << Trace::Width(2)
357 << i << " : " << Trace::Width(5) << face.cell(i).uniqueId();
358
359 trace->pinfo() << "** -- Variables:";
360 _writeInfo<Face, Real>(sd, variables, face);
361 _writeInfo<Face, Real2>(sd, variables, face);
362 _writeInfo<Face, Real3>(sd, variables, face);
363 _writeInfo<Face, Real2x2>(sd, variables, face);
364 _writeInfo<Face, Real3x3>(sd, variables, face);
365 _writeInfo<Face, Int32>(sd, variables, face);
366 _writeInfo<Face, Int64>(sd, variables, face);
367
368 if (depend_info) {
369 for (Integer i = 0; i < nb_node; ++i)
370 writeMeshItemInfo(sd, face.node(i), false);
371 for (Integer i = 0; i < nb_edge; ++i)
372 writeMeshItemInfo(sd, face.edge(i), false);
373 for (Integer i = 0; i < nb_cell; ++i)
374 writeMeshItemInfo(sd, face.cell(i), false);
375 }
376}
377
378/*---------------------------------------------------------------------------*/
379/*---------------------------------------------------------------------------*/
380
381class _CompareNodes
382{
383 public:
384
385 bool operator()(const Node& node1, const Node& node2)
386 {
387 const Real3& r1 = m_coords[node1];
388 const Real3& r2 = m_coords[node2];
389 return r1 < r2;
390 }
391
392 public:
393
394 _CompareNodes(IMesh* mesh, const SharedVariableNodeReal3& coords)
395 : m_items(mesh->itemsInternal(IK_Node))
396 , m_coords(coords)
397 {
398 }
399 ItemInternalList m_items;
400 const SharedVariableNodeReal3& m_coords;
401};
402
403class _CompareItemWithNodes
404{
405 public:
406
407 bool operator()(const ItemWithNodes& cell1, const ItemWithNodes& cell2)
408 {
409 Integer nb1 = cell1.nbNode();
410 Integer nb2 = cell2.nbNode();
411 if (nb1 < nb2)
412 return true;
413 if (nb2 < nb1)
414 return false;
415 Integer n = nb1;
416 for (Integer i = 0; i < n; ++i) {
417 Integer n1 = m_nodes_sorted_id[cell1.node(i).localId()];
418 Integer n2 = m_nodes_sorted_id[cell2.node(i).localId()];
419 if (n1 != n2)
420 return n1 < n2;
421 }
422 return false;
423 //return n1<n2;
424 }
425
426 public:
427
428 _CompareItemWithNodes(IMesh* mesh, eItemKind ik, Int32ConstArrayView nodes_sorted_id)
429 : m_items(mesh->itemsInternal(ik))
430 , m_nodes_sorted_id(nodes_sorted_id)
431 {
432 }
433 ItemInternalList m_items;
434 Int32ConstArrayView m_nodes_sorted_id;
435};
436
437/*---------------------------------------------------------------------------*/
438/*---------------------------------------------------------------------------*/
439
440void _writeItems(std::ostream& ofile, const String& name, Int32ConstArrayView ids)
441{
442 Integer nb_sub_item = ids.size();
443 ofile << " " << name << " " << nb_sub_item << " (";
444 for (Integer i = 0; i < nb_sub_item; ++i)
445 ofile << ' ' << ids[i];
446 ofile << " )";
447}
448
450{
451 public:
452
453 virtual ~IItemFiller() {}
454
455 public:
456
457 virtual Integer nbItem(ItemBase item) const = 0;
458 virtual void fillLocalIds(ItemBase item, Int32ArrayView ids) const = 0;
459};
460
462: public IItemFiller
463{
464 Integer nbItem(ItemBase item) const override { return item.nbEdge(); }
465 void fillLocalIds(ItemBase item, Int32ArrayView ids) const override
466 {
467 Integer nb_edge = ids.size();
468 for (Integer i = 0; i < nb_edge; ++i)
469 ids[i] = item.edgeId(i);
470 }
471};
472
474: public IItemFiller
475{
476 Int32 nbItem(ItemBase item) const override { return item.nbCell(); }
477 void fillLocalIds(ItemBase item, Int32ArrayView ids) const override
478 {
479 Integer nb_cell = ids.size();
480 for (Integer i = 0; i < nb_cell; ++i)
481 ids[i] = item.cellId(i);
482 }
483};
484
486: public IItemFiller
487{
488 Int32 nbItem(ItemBase item) const override { return item.nbFace(); }
489 void fillLocalIds(ItemBase item, Int32ArrayView ids) const override
490 {
491 Integer nb_face = ids.size();
492 for (Integer i = 0; i < nb_face; ++i)
493 ids[i] = item.faceId(i);
494 }
495};
496
498: public IItemFiller
499{
500 virtual Int32 nbItem(ItemBase item) const { return item.nbNode(); }
501 virtual void fillLocalIds(ItemBase item, Int32ArrayView ids) const
502 {
503 Integer nb_node = ids.size();
504 for (Integer i = 0; i < nb_node; ++i)
505 ids[i] = item.nodeId(i);
506 }
507};
508
509void _fillSorted(Item titem, Int32Array& local_ids, Int32ConstArrayView sorted_ids, const IItemFiller& filler)
510{
511 ItemBase item = titem.itemBase();
512 Integer n = filler.nbItem(item);
513 local_ids.resize(n);
514 filler.fillLocalIds(item, local_ids);
515 for (Integer i = 0; i < n; ++i)
516 local_ids[i] = sorted_ids[local_ids[i]];
517}
518
519/*---------------------------------------------------------------------------*/
520/*---------------------------------------------------------------------------*/
521
522void MeshUtils::
523writeMeshInfosSorted(IMesh* mesh, const String& file_name)
524{
525 if (!mesh)
526 return;
527 std::ofstream ofile(file_name.localstr());
528 ofile.precision(FloatInfo<Real>::maxDigit() + 1);
529 Integer nb_node = mesh->nbNode();
530 Integer nb_edge = mesh->nbEdge();
531 Integer nb_face = mesh->nbFace();
532 Integer nb_cell = mesh->nbCell();
533 ofile << "** Mesh Sorted --> "
534 << " Nodes " << nb_node
535 << " Edges " << nb_edge
536 << " Faces " << nb_face
537 << " Cells " << nb_cell
538 << "\n";
539 UniqueArray<Node> sorted_nodes(nb_node);
540 UniqueArray<Edge> sorted_edges(nb_edge);
541 UniqueArray<Face> sorted_faces(nb_face);
542 UniqueArray<Cell> sorted_cells(nb_cell);
543
544 Int32UniqueArray nodes_sorted_id(nb_node);
545 Int32UniqueArray edges_sorted_id(nb_edge);
546 Int32UniqueArray faces_sorted_id(nb_face);
547 Int32UniqueArray cells_sorted_id(nb_cell);
548 {
549 // Sort nodes by ascending coordinates
550 NodeInfoListView nodes(mesh->nodeFamily());
551 for (Integer i = 0; i < nb_node; ++i)
552 sorted_nodes[i] = nodes[i];
553 {
554 SharedVariableNodeReal3 shared_coords(mesh->sharedNodesCoordinates());
555 _CompareNodes compare_nodes(mesh, shared_coords);
556 std::sort(std::begin(sorted_nodes), std::end(sorted_nodes), compare_nodes);
557 }
558 for (Integer i = 0; i < nb_node; ++i)
559 nodes_sorted_id[sorted_nodes[i].localId()] = i;
560
561 // Sort edges
562 EdgeInfoListView edges(mesh->edgeFamily());
563 for (Integer i = 0; i < nb_edge; ++i)
564 sorted_edges[i] = edges[i];
565 {
566 _CompareItemWithNodes compare_edges(mesh, IK_Edge, nodes_sorted_id);
567 std::sort(std::begin(sorted_edges), std::end(sorted_edges), compare_edges);
568 }
569 for (Integer i = 0; i < nb_edge; ++i)
570 edges_sorted_id[sorted_edges[i].localId()] = i;
571
572 // Sort faces
573 FaceInfoListView faces(mesh->faceFamily());
574 for (Integer i = 0; i < nb_face; ++i)
575 sorted_faces[i] = faces[i];
576 {
577 _CompareItemWithNodes compare_faces(mesh, IK_Face, nodes_sorted_id);
578 std::sort(std::begin(sorted_faces), std::end(sorted_faces), compare_faces);
579 }
580 for (Integer i = 0; i < nb_face; ++i)
581 faces_sorted_id[sorted_faces[i].localId()] = i;
582
583 // Sort cells
584 CellInfoListView cells(mesh->cellFamily());
585 for (Integer i = 0; i < nb_cell; ++i)
586 sorted_cells[i] = cells[i];
587 {
588 _CompareItemWithNodes compare_cells(mesh, IK_Cell, nodes_sorted_id);
589 std::sort(std::begin(sorted_cells), std::end(sorted_cells), compare_cells);
590 }
591 for (Integer i = 0; i < nb_cell; ++i)
592 cells_sorted_id[sorted_cells[i].localId()] = i;
593
594 SharedVariableNodeReal3 coords(mesh->sharedNodesCoordinates());
595
596 ofile << "** Nodes\n";
597 Int32UniqueArray lids;
598 for (Integer i = 0; i < nb_node; ++i) {
599 const Node& node = sorted_nodes[i];
600 ofile << "Node: " << i << " Coord: " << coords[node];
601
602 _fillSorted(node, lids, edges_sorted_id, EdgeFiller());
603 std::sort(std::begin(lids), std::end(lids));
604 _writeItems(ofile, "Edges", lids);
605
606 _fillSorted(node, lids, faces_sorted_id, FaceFiller());
607 std::sort(std::begin(lids), std::end(lids));
608 _writeItems(ofile, "Faces", lids);
609
610 _fillSorted(node, lids, cells_sorted_id, CellFiller());
611 std::sort(std::begin(lids), std::end(lids));
612 _writeItems(ofile, "Cells", lids);
613
614 ofile << '\n';
615 }
616
617 ofile << "** Edges\n";
618 for (Integer i = 0; i < nb_edge; ++i) {
619 Edge edge = sorted_edges[i];
620 Integer edge_nb_node = edge.nbNode();
621 Integer edge_nb_face = edge.nbFace();
622 Integer edge_nb_cell = edge.nbCell();
623 ofile << "Edge: " << i
624 << " Nodes " << edge_nb_node << " (";
625 for (Integer i_node = 0; i_node < edge_nb_node; ++i_node)
626 ofile << ' ' << nodes_sorted_id[edge.node(i_node).localId()];
627 ofile << " )";
628 ofile << " Faces " << edge_nb_face << " (";
629 for (Integer i_face = 0; i_face < edge_nb_face; ++i_face)
630 ofile << ' ' << faces_sorted_id[edge.face(i_face).localId()];
631 ofile << " )";
632 ofile << " Cells " << edge_nb_cell << " (";
633 for (Integer i_cell = 0; i_cell < edge_nb_cell; ++i_cell)
634 ofile << ' ' << cells_sorted_id[edge.cell(i_cell).localId()];
635 ofile << " )";
636 ofile << '\n';
637 }
638
639 ofile << "** Faces\n";
640 for (Integer i = 0; i < nb_face; ++i) {
641 Face face = sorted_faces[i];
642 Integer face_nb_node = face.nbNode();
643 Integer face_nb_edge = face.nbEdge();
644 Integer face_nb_cell = face.nbCell();
645 ofile << "Face: " << i;
646 ofile << " Nodes " << face.nbNode() << " (";
647 for (Integer i_node = 0; i_node < face_nb_node; ++i_node)
648 ofile << ' ' << nodes_sorted_id[face.node(i_node).localId()];
649 ofile << " )";
650
651 ofile << " Edges " << face_nb_edge << " (";
652 for (Integer i_edge = 0; i_edge < face_nb_edge; ++i_edge)
653 ofile << ' ' << edges_sorted_id[face.edge(i_edge).localId()];
654 ofile << " )";
655
656 ofile << " Cells " << face_nb_cell << " (";
657 for (Integer i_cell = 0; i_cell < face_nb_cell; ++i_cell)
658 ofile << ' ' << cells_sorted_id[face.cell(i_cell).localId()];
659
660 const Cell& back_cell = face.backCell();
661 if (!back_cell.null())
662 ofile << " Back " << cells_sorted_id[back_cell.localId()];
663
664 const Cell& front_cell = face.frontCell();
665 if (!front_cell.null())
666 ofile << " Front " << cells_sorted_id[front_cell.localId()];
667
668 ofile << " )";
669 ofile << '\n';
670 }
671
672 ofile << "** Cells\n";
673 for (Integer i = 0; i < nb_cell; ++i) {
674 Cell cell = sorted_cells[i];
675 //Integer cell_nb_node = cell.nbNode();
676 ofile << "Cell: " << i;
677
678 _fillSorted(cell, lids, nodes_sorted_id, NodeFiller());
679 _writeItems(ofile, "Nodes", lids);
680 _fillSorted(cell, lids, edges_sorted_id, EdgeFiller());
681 _writeItems(ofile, "Edges", lids);
682 _fillSorted(cell, lids, faces_sorted_id, FaceFiller());
683 _writeItems(ofile, "Faces", lids);
684 ofile << '\n';
685 }
686 }
687}
688
689/*---------------------------------------------------------------------------*/
690/*---------------------------------------------------------------------------*/
691
692void MeshUtils::
693writeMeshInfos(IMesh* mesh, const String& file_name)
694{
695 if (!mesh)
696 return;
697 std::ofstream ofile(file_name.localstr());
698 ofile.precision(FloatInfo<Real>::maxDigit() + 1);
699 Integer nb_node = mesh->nbNode();
700 Integer nb_edge = mesh->nbEdge();
701 Integer nb_face = mesh->nbFace();
702 Integer nb_cell = mesh->nbCell();
703 ofile << "** Mesh --> "
704 << " Nodes " << nb_node
705 << " Edges " << nb_edge
706 << " Faces " << nb_face
707 << " Cells " << nb_cell
708 << "\n";
709
710 NodeInfoListView nodes(mesh->nodeFamily());
711 FaceInfoListView faces(mesh->faceFamily());
712 CellInfoListView cells(mesh->cellFamily());
713 //TODO display infos even if not a primary mesh
714 VariableNodeReal3& coords(mesh->toPrimaryMesh()->nodesCoordinates());
715
716 ofile << "** Nodes\n";
717 for (Integer i = 0; i < nb_node; ++i) {
718 Node node = nodes[i];
719 Integer node_nb_face = node.nbFace();
720 Integer node_nb_cell = node.nbCell();
721 ofile << "Node: " << i << " Coord: " << coords[node];
722 ofile << " Faces " << node_nb_face << " (";
723 for (Integer i_face = 0; i_face < node_nb_face; ++i_face)
724 ofile << ' ' << node.face(i_face).localId();
725 ofile << " )";
726 ofile << " Cells " << node_nb_cell << " (";
727 for (Integer i_cell = 0; i_cell < node_nb_cell; ++i_cell)
728 ofile << ' ' << node.cell(i_cell).localId();
729 ofile << " )";
730 ofile << '\n';
731 }
732
733 ofile << "** Faces\n";
734 for (Integer i = 0; i < nb_face; ++i) {
735 Face face = faces[i];
736 Integer face_nb_node = face.nbNode();
737 Integer face_nb_cell = face.nbCell();
738 ofile << "Face: " << i
739 << " Nodes " << face_nb_node << " (";
740 for (Integer i_node = 0; i_node < face_nb_node; ++i_node)
741 ofile << ' ' << face.node(i_node).localId();
742 ofile << " )";
743 ofile << " Cells " << face_nb_cell << " (";
744
745 for (Integer i_cell = 0; i_cell < face_nb_cell; ++i_cell)
746 ofile << ' ' << face.cell(i_cell).localId();
747
748 const Cell& back_cell = face.backCell();
749 if (!back_cell.null())
750 ofile << " Back " << back_cell.localId();
751
752 const Cell& front_cell = face.frontCell();
753 if (!front_cell.null())
754 ofile << " Front " << front_cell.localId();
755
756 ofile << " )";
757 ofile << '\n';
758 }
759
760 ofile << "** Cells\n";
761 for (Integer i = 0; i < nb_cell; ++i) {
762 Cell cell = cells[i];
763 Integer cell_nb_node = cell.nbNode();
764 Integer cell_nb_face = cell.nbFace();
765 ofile << "Cell: " << i
766 << " Nodes " << cell_nb_node << " (";
767 for (Integer i_node = 0; i_node < cell_nb_node; ++i_node)
768 ofile << ' ' << cell.node(i_node).localId();
769 ofile << " )";
770 ofile << " Faces " << cell_nb_face << " (";
771 for (Integer i_face = 0; i_face < cell_nb_face; ++i_face)
772 ofile << ' ' << cell.face(i_face).localId();
773 ofile << " )";
774 ofile << '\n';
775 }
776}
777
778/*---------------------------------------------------------------------------*/
779/*---------------------------------------------------------------------------*/
780
781namespace
782{
783 template <typename ItemType> void
784 _sortByUniqueIds(IMesh* mesh, eItemKind ik, Array<ItemType>& items)
785 {
786 ItemGroup all_items(mesh->itemFamily(ik)->allItems());
787 items.resize(all_items.size());
788
789 Integer index = 0;
790 ENUMERATE_ (ItemType, i, all_items) {
791 ItemType item = *i;
792 items[index] = item;
793 ++index;
794 }
795 std::sort(std::begin(items), std::end(items), ItemCompare());
796 }
797
798 void
799 _stringToIds(const String& str, Int64Array& ids)
800 {
801 ids.clear();
802 std::istringstream istr(str.localstr());
803 Integer z = 0;
804 while (istr.good()) {
805 istr >> z;
806 if (!istr)
807 break;
808 ids.add(z);
809 }
810 }
811
812 template <typename SubItemType> void
813 _writeSubItems(std::ostream& ofile, const char* item_name, ItemConnectedListViewT<SubItemType> sub_list)
814 {
815 Int32 n = sub_list.size();
816 if (n == 0)
817 return;
818 ofile << "<" << item_name << " count='" << n << "'>";
819 for (SubItemType sub_item : sub_list)
820 ofile << ' ' << sub_item.uniqueId();
821 ofile << "</" << item_name << ">";
822 }
823} // namespace
824
825/*---------------------------------------------------------------------------*/
826/*---------------------------------------------------------------------------*/
827
828void MeshUtils::
829writeMeshConnectivity(IMesh* mesh, const String& file_name)
830{
831 std::ofstream ofile(file_name.localstr());
832 ofile.precision(FloatInfo<Real>::maxDigit() + 1);
833 if (!mesh)
834 return;
835
836 ITraceMng* trace = mesh->traceMng();
837
838 trace->info() << "Writing mesh connectivity in '" << file_name << "'";
839
840 ofile << "<?xml version='1.0' ?>\n";
841 ofile << "<mesh-connectivity>\n";
842 UniqueArray<Node> nodes;
843 UniqueArray<Edge> edges;
844 UniqueArray<Face> faces;
845 UniqueArray<Cell> cells;
846
847 _sortByUniqueIds(mesh, IK_Node, nodes);
848 _sortByUniqueIds(mesh, IK_Edge, edges);
849 _sortByUniqueIds(mesh, IK_Face, faces);
850 _sortByUniqueIds(mesh, IK_Cell, cells);
851
852 // Write nodes
853 {
854 ofile << "<nodes count='" << nodes.size() << "'>\n";
855 for (Node item : nodes) {
856 ofile << " <node uid='" << item.uniqueId() << "' owner='" << item.owner() << "'>";
857 _writeSubItems(ofile, "cells", item.cells());
858 _writeSubItems(ofile, "faces", item.faces());
859 _writeSubItems(ofile, "edges", item.edges());
860 ofile << "</node>\n";
861 }
862 ofile << "</nodes>\n";
863 }
864
865 // Write edges
866 {
867 ofile << "<edges count='" << edges.size() << "'>\n";
868 for (Edge edge : edges) {
869 ofile << " <edge uid='" << edge.uniqueId() << "' owner='" << edge.owner() << "'>";
870 _writeSubItems(ofile, "nodes", edge.nodes());
871 _writeSubItems(ofile, "cells", edge.cells());
872 _writeSubItems(ofile, "faces", edge.faces());
873 ofile << "</edge>\n";
874 }
875 ofile << "</edges>\n";
876 }
877
878 // Write faces
879 {
880 ofile << "<faces count='" << faces.size() << "'>\n";
881 for (Face face : faces) {
882 // Integer item_nb_face = item.nbFace();
883 ofile << " <face uid='" << face.uniqueId()
884 << "' typeid='" << face.type()
885 << "' owner='" << face.owner() << "'>";
886 _writeSubItems(ofile, "nodes", face.nodes());
887 _writeSubItems(ofile, "edges", face.edges());
888 {
889 // Cell info
890 ofile << "<cells";
891 Cell back_cell = face.backCell();
892 if (!back_cell.null())
893 ofile << " back='" << back_cell.uniqueId() << "'";
894 Cell front_cell = face.frontCell();
895 if (!front_cell.null())
896 ofile << " front='" << front_cell.uniqueId() << "'";
897 ofile << "/>";
898 }
899
900 // Master/slave info
901 if (face.isSlaveFace())
902 _writeSubItems(ofile, "slave-faces", face.slaveFaces());
903 if (face.isMasterFace()) {
904 ofile << "<faces count='1'>";
905 ofile << ' ' << face.masterFace().uniqueId();
906 ofile << "</faces>";
907 }
908
909 ofile << "</face>\n";
910 }
911 ofile << "</faces>\n";
912 }
913
914 // Write cells
915 {
916 ofile << "<cells count='" << cells.size() << "'>\n";
917 // For cells around a cell.
918 // A cell is around another if it is connected by
919 // at least one node
920 Int64UniqueArray ghost_cells_layer1;
921 ghost_cells_layer1.reserve(100);
922 for (Cell cell : cells) {
923 ofile << " <cell uid='" << cell.uniqueId()
924 << "' typeid='" << cell.type()
925 << "' owner='" << cell.owner() << "'>";
926 _writeSubItems(ofile, "nodes", cell.nodes());
927 _writeSubItems(ofile, "edges", cell.edges());
928 _writeSubItems(ofile, "faces", cell.faces());
929 if (mesh->isAmrActivated()) {
930 ofile << "<amr level='" << cell.level() << "'>";
931 // {
932 // ofile << "<parent count='" << item.nbHParent() << "'>";
933 // trace->info() << "Truc : " << item.nbHParent();
934 // for (Integer j = 0; j < item.nbHParent(); ++j) {
935 // ofile << ' ' << item.parent(j).uniqueId();
936 // }
937 // ofile << "</parent>";
938 // }
939 {
940 ofile << "<child count='" << cell.nbHChildren() << "'>";
941 for (Integer j = 0; j < cell.nbHChildren(); ++j) {
942 ofile << ' ' << cell.hChild(j).uniqueId();
943 }
944 ofile << "</child>";
945 }
946 ofile << "</amr>";
947 }
948 {
949 ghost_cells_layer1.clear();
950 for (Node node : cell.nodes()) {
951 for (Cell sub_cell : node.cells()) {
952 ghost_cells_layer1.add(sub_cell.uniqueId().asInt64());
953 }
954 }
955
956 {
957 // Sort the list of ghost cells and remove duplicates.
958 std::sort(std::begin(ghost_cells_layer1), std::end(ghost_cells_layer1));
959 auto new_end = std::unique(std::begin(ghost_cells_layer1), std::end(ghost_cells_layer1));
960 ghost_cells_layer1.resize(arcaneCheckArraySize(new_end - std::begin(ghost_cells_layer1)));
961 ofile << "<ghost1 count='" << ghost_cells_layer1.size() << "'>";
962 for (auto j : ghost_cells_layer1)
963 ofile << ' ' << j;
964 ofile << "</ghost1>\n";
965 }
966 }
967 ofile << "</cell>\n";
968 }
969 ofile << "</cells>\n";
970 }
971
972 // Save groups
973
974 {
975 ofile << "<groups>\n";
976 // Sort groups alphabetically to ensure they are
977 // always written in the same order.
978 std::map<String, ItemGroup> sorted_groups;
979 for (ItemGroupCollection::Enumerator i_group(mesh->groups()); ++i_group;) {
980 const ItemGroup& group = *i_group;
981 if (group.isLocalToSubDomain())
982 continue;
983 sorted_groups.insert(std::make_pair(group.name(), group));
984 }
985 for (const auto& [name, group] : sorted_groups) {
986 ofile << "<group name='" << group.name()
987 << "' kind='" << itemKindName(group.itemKind())
988 << "' count='" << group.size() << "'>\n";
989 ENUMERATE_ (Item, i_item, group) {
990 ofile << ' ' << i_item->uniqueId();
991 }
992 ofile << "\n</group>\n";
993 }
994 ofile << "</groups>\n";
995 }
996
997 // Save the tied interfaces
998 {
999 ofile << "<tied-interfaces>\n";
1000 TiedInterfaceCollection tied_interfaces(mesh->tiedInterfaces());
1001 for (TiedInterfaceCollection::Enumerator itied(tied_interfaces); ++itied;) {
1002 ITiedInterface* interface = *itied;
1003 FaceGroup slave_group = interface->slaveInterface();
1004 FaceGroup master_group = interface->masterInterface();
1005 ofile << "<tied-interface master_name='" << master_group.name()
1006 << "' slave_name='" << slave_group.name() << "'>\n";
1007 TiedInterfaceNodeList tied_nodes(interface->tiedNodes());
1008 TiedInterfaceFaceList tied_faces(interface->tiedFaces());
1009 ENUMERATE_FACE (iface, master_group) {
1010 Face face = *iface;
1011 //FaceVectorView slave_faces = face.slaveFaces();
1012 ofile << "<master-face uid='" << face.uniqueId() << "'>\n";
1013 for (Integer zz = 0, zs = tied_nodes[iface.index()].size(); zz < zs; ++zz) {
1014 TiedNode tn = tied_nodes[iface.index()][zz];
1015 ofile << "<node uid='" << tn.node().uniqueId() << "' iso='" << tn.isoCoordinates() << "' />\n";
1016 }
1017 for (Integer zz = 0, zs = tied_faces[iface.index()].size(); zz < zs; ++zz) {
1018 TiedFace tf = tied_faces[iface.index()][zz];
1019 ofile << "<face uid='" << tf.face().uniqueId() << "'/>\n";
1020 }
1021 ofile << "</master-face>\n";
1022 }
1023 ofile << "</tied-interface>\n";
1024 }
1025 ofile << "</tied-interfaces>\n";
1026 }
1027 ofile << "</mesh-connectivity>\n";
1028}
1029
1030/*---------------------------------------------------------------------------*/
1031/*---------------------------------------------------------------------------*/
1032
1033/*---------------------------------------------------------------------------*/
1034/*---------------------------------------------------------------------------*/
1035
1036class MeshUtilsCheckConnectivity
1037{
1038 public:
1039
1040 class ItemInternalXml
1041 {
1042 public:
1043
1044 ItemInternalXml() {}
1045 explicit ItemInternalXml(Item item)
1046 : m_item(item)
1047 {}
1048
1049 public:
1050
1051 bool operator<(const ItemInternalXml& i2) const
1052 {
1053 return m_item.uniqueId() < i2.m_item.uniqueId();
1054 }
1055 bool operator<(Int64 uid) const
1056 {
1057 return m_item.uniqueId() < uid;
1058 }
1059
1060 public:
1061
1062 Item m_item;
1063 XmlNode m_element;
1064 };
1065 typedef std::map<Int64, ItemInternalXml> ItemInternalXmlMap;
1066
1067 public:
1068
1069 MeshUtilsCheckConnectivity(IMesh* mesh, const XmlNode& doc_node, bool check_sub_domain)
1070 : m_mesh(mesh)
1071 , m_doc_node(doc_node)
1072 , m_has_error(false)
1073 , m_check_sub_domain(check_sub_domain)
1074 {
1075 }
1076
1077 public:
1078
1079 void doCheck();
1080
1081 public:
1082
1083 IMesh* m_mesh;
1084 XmlNode m_doc_node;
1085 bool m_has_error;
1086 bool m_check_sub_domain;
1087 ItemInternalXmlMap m_nodes_internal;
1088 ItemInternalXmlMap m_edges_internal;
1089 ItemInternalXmlMap m_faces_internal;
1090 ItemInternalXmlMap m_cells_internal;
1091 Int64UniqueArray m_items_unique_id;
1092
1093 private:
1094
1095 /*void _sortByUniqueIds(eItemKind ik,Array<ItemInternalXml>& items_internal)
1096 {
1097 ItemGroup all_items(m_mesh->allItems(ik));
1098 items_internal.resize(all_items.size());
1099
1100 Integer index = 0;
1101 ENUMERATE_ITEM(i,all_items){
1102 const Item& item = *i;
1103 items_internal[index].m_item = item.internal();
1104 ++index;
1105 }
1106 std::sort(items_internal.begin(),items_internal.end());
1107 }*/
1108 void _read(eItemKind ik, ItemInternalXmlMap& items_internal,
1109 XmlNode root_node, const String& lower_case_kind_name);
1110
1111 /*ItemInternalXml* _find(Array<ItemInternalXml>& items_internal,Integer uid)
1112 {
1113 ItemInternalXmlIterator z = std::lower_bound(items_internal.begin(),items_internal.end(),uid);
1114 if (z==items_internal.end())
1115 return 0;
1116 ItemInternalXml* ixml = &(*z);
1117 if (ixml->m_item->uniqueId()!=uid)
1118 return 0;
1119 return ixml;
1120 //cout << "NOT IMPLEMENTED!\n";
1121 //return 0;
1122 }*/
1123};
1124
1125/*---------------------------------------------------------------------------*/
1126/*---------------------------------------------------------------------------*/
1127
1128void MeshUtils::
1129checkMeshConnectivity(IMesh* mesh, const XmlNode& doc_node, bool check_sub_domain)
1130{
1131 if (!mesh)
1132 return;
1133 MeshUtilsCheckConnectivity v(mesh, doc_node, check_sub_domain);
1134 v.doCheck();
1135}
1136
1137void MeshUtils::
1138checkMeshConnectivity(IMesh* mesh, const String& file_name, bool check_sub_domain)
1139{
1140 ITraceMng* tm = mesh->traceMng();
1142 //IXmlDocumentHolder* doc = io_mng->parseXmlFile(file_name);
1143 XmlNode root = doc->documentNode();
1144 checkMeshConnectivity(mesh, root, check_sub_domain);
1145}
1146
1147void MeshUtilsCheckConnectivity::
1148_read(eItemKind ik, ItemInternalXmlMap& items_internal, XmlNode root_node,
1149 const String& lower_case_kind_name)
1150{
1151 ITraceMng* trace = m_mesh->traceMng();
1152
1153 //_sortByUniqueIds(ik,items_internal);
1154
1155 String ustr_uid("uid");
1156 String ustr_cells("cells");
1157 String ustr_count("count");
1158 String ustr_nodes("nodes");
1159 String ustr_ghost1("ghost1");
1160
1161 String kind_name(itemKindName(ik));
1162
1163 ENUMERATE_ITEM (iitem, m_mesh->itemFamily(ik)->allItems()) {
1164 Item item = *iitem;
1165 ItemInternalXml ixml(item);
1166 items_internal.insert(ItemInternalXmlMap::value_type(item.uniqueId().asInt64(), ixml));
1167 }
1168
1169#ifdef ARCANE_DEBUG_MESH
1170 for (Integer i = 0; i < items_internal.size(); ++i) {
1171 const ItemInternalXml& item_xml = items_internal[i];
1172 trace->info() << "Item " << kind_name << ":" << item_xml.m_item->uniqueId()
1173 << ' ' << i << ' ' << item_xml.m_item;
1174 }
1175#endif
1176
1177 XmlNodeList xml_items(root_node.children(lower_case_kind_name));
1178 for (const auto& xml_node : xml_items) {
1179 Integer uid = xml_node.attr(ustr_uid).valueAsInteger();
1180 ItemInternalXmlMap::iterator iixml = items_internal.find(uid);
1181 if (iixml != items_internal.end()) {
1182 iixml->second.m_element = xml_node;
1183 }
1184#if 0
1185 ItemInternalXml* ixml = _find(items_internal,uid);
1186 if (ixml){
1187 ixml->m_element = xml_node;
1188#ifdef ARCANE_DEBUG_MESH
1189 trace->info() << "FOUND " << uid << ' ' << z->m_item->uniqueId() << ' ' << z->m_element.name()
1190 << ' ' << z->m_item;
1191#endif
1192 }
1193#ifdef ARCANE_DEBUG_MESH
1194 else
1195 trace->info() << "FOUND " << uid << " NOT HERE";
1196#endif
1197#endif
1198 }
1199
1200 Int32UniqueArray local_ids;
1201 local_ids.reserve(100);
1202 for (ItemInternalXmlMap::const_iterator i(items_internal.begin()); i != items_internal.end(); ++i) {
1203 const ItemInternalXml& item_xml = i->second;
1204 Item item = item_xml.m_item;
1205 const XmlNode& xitem = item_xml.m_element;
1206 if (xitem.null()) {
1207 trace->error() << "Item " << kind_name << ":" << item.uniqueId()
1208 << "unknown in reference mesh";
1209 m_has_error = true;
1210 continue;
1211 }
1212 if (ik != IK_Node) {
1213 ItemWithNodes item_with_node(item);
1214 XmlNode xitem_node = xitem.child(ustr_nodes);
1215 Integer ref_nb_node = xitem_node.attr(ustr_count).valueAsInteger();
1216 Integer nb_node = item_with_node.nbNode();
1217 if (ref_nb_node != nb_node) {
1218 trace->error() << "Item " << kind_name << ":" << item.uniqueId()
1219 << ": number of nodes (" << nb_node << ") "
1220 << "different than reference (" << ref_nb_node << ")";
1221 m_has_error = true;
1222 continue;
1223 }
1224
1225 m_items_unique_id.reserve(ref_nb_node);
1226 String s = xitem_node.value();
1227 _stringToIds(s, m_items_unique_id);
1228 bool is_bad = false;
1229 for (NodeEnumerator i_node(item_with_node.nodes()); i_node(); ++i_node) {
1230 if (m_items_unique_id[i_node.index()] != i_node->uniqueId()) {
1231 is_bad = true;
1232 break;
1233 }
1234 }
1235 if (is_bad) {
1236 m_has_error = true;
1237 OStringStream ostr;
1238 ostr() << "Item " << kind_name << ":" << item.uniqueId()
1239 << ": nodes (";
1240 for (NodeEnumerator i_node(item_with_node.nodes()); i_node(); ++i_node) {
1241 ostr() << ' ' << i_node->uniqueId();
1242 }
1243 ostr() << ") different than reference (" << s << ")";
1244 trace->error() << ostr.str();
1245 }
1246 }
1247 if (item.isOwn()) {
1248 // If it is a cell, search whether the cells that should be
1249 // ghosts are present in the mesh.
1250 // If it is a node, search whether the cells around this node
1251 // are present in the mesh.
1252 XmlNode elem;
1253 if (ik == IK_Cell)
1254 elem = xitem.child(ustr_ghost1);
1255 else if (ik == IK_Node)
1256 elem = xitem.child(ustr_cells);
1257 if (!elem.null()) {
1258 _stringToIds(elem.value(), m_items_unique_id);
1259 local_ids.resize(m_items_unique_id.size());
1260 m_mesh->cellFamily()->itemsUniqueIdToLocalId(local_ids, m_items_unique_id, false);
1261 StringBuilder not_found;
1262 bool has_not_found = false;
1263 for (Integer uui = 0, uuis = m_items_unique_id.size(); uui < uuis; ++uui) {
1264 if (local_ids[uui] == NULL_ITEM_ID) {
1265 not_found += " ";
1266 not_found += m_items_unique_id[uui];
1267 m_has_error = true;
1268 has_not_found = true;
1269 }
1270 }
1271 if (has_not_found) {
1272 if (ik == IK_Cell)
1273 trace->info() << "ERROR: One or more ghost cells of cell "
1274 << ItemPrinter(item) << " are not in the sub-domain"
1275 << " ref='" << elem.value() << "' not_found='" << not_found << '\'';
1276 else if (ik == IK_Node) {
1277 trace->info() << "ERROR: One or more cells with node "
1278 << ItemPrinter(item) << " are not in the sub-domain"
1279 << " ref='" << elem.value() << "' not_found='" << not_found << '\'';
1280 }
1281 }
1282 }
1283 }
1284 }
1285}
1286
1287/*---------------------------------------------------------------------------*/
1288/*---------------------------------------------------------------------------*/
1289
1290/*---------------------------------------------------------------------------*/
1291/*---------------------------------------------------------------------------*/
1292
1293void MeshUtilsCheckConnectivity::
1294doCheck()
1295{
1296 ITraceMng* trace = m_mesh->traceMng();
1297
1298 trace->info() << "Checking mesh checkMeshConnectivity()";
1299
1300 XmlNode root_node = m_doc_node.child(String("mesh-connectivity"));
1301 if (!root_node) {
1302 trace->warning() << "Incorrect connectivity file";
1303 return;
1304 }
1305 XmlNode nodes_root = root_node.child("nodes");
1306 XmlNode faces_root = root_node.child("faces");
1307 XmlNode cells_root = root_node.child("cells");
1308
1309 _read(IK_Node, m_nodes_internal, nodes_root, "node");
1310 _read(IK_Face, m_faces_internal, faces_root, "face");
1311 _read(IK_Cell, m_cells_internal, cells_root, "cell");
1312
1313 String ustr_groups("groups");
1314 String ustr_group("group");
1315 String ustr_count("count");
1316
1317 XmlNode groups_root = root_node.child(ustr_groups);
1318 for (ItemGroupCollection::Enumerator i_group(m_mesh->groups()); ++i_group;) {
1319 const ItemGroup& group = *i_group;
1320 if (group.isLocalToSubDomain() || group.isOwn())
1321 continue;
1322 XmlNode group_elem = groups_root.childWithNameAttr(ustr_group, String(group.name()));
1323 if (group_elem.null()) {
1324 m_has_error = true;
1325 trace->error() << "Unable to find group <" << group.name()
1326 << "> in reference file";
1327 continue;
1328 }
1329 Integer size = group_elem.attr(ustr_count).valueAsInteger();
1330 m_items_unique_id.reserve(size);
1331 _stringToIds(group_elem.value(), m_items_unique_id);
1332 Integer ref_size = m_items_unique_id.size();
1333 if (ref_size != size) {
1334 trace->error() << "Number of items in group <" << group.name()
1335 << "> (" << size << " different than reference (" << ref_size;
1336 }
1337 // TODO: verify that all group entities in the reference mesh
1338 // are also in the corresponding group of this mesh.
1339 }
1340
1341 if (m_has_error) {
1342 trace->fatal() << "Error(s) while checking mesh";
1343 }
1344}
1345
1346/*---------------------------------------------------------------------------*/
1347/*---------------------------------------------------------------------------*/
1348
1349/*---------------------------------------------------------------------------*/
1350/*---------------------------------------------------------------------------*/
1351
1352void MeshUtils::
1353checkMeshProperties(IMesh* mesh, bool is_sorted, bool has_no_hole, bool check_faces)
1354{
1355 if (!mesh)
1356 return;
1357 if (has_no_hole)
1358 throw NotImplementedException(A_FUNCINFO, "Has no hole");
1359
1360 ITraceMng* trace = mesh->traceMng();
1361 bool has_error = false;
1362 if (is_sorted) {
1363 //for( Integer iki=0; iki<NB_ITEM_KIND; ++iki ){
1364 // eItemKind ik = static_cast<eItemKind>(iki);
1365 for (IItemFamilyCollection::Enumerator i(mesh->itemFamilies()); ++i;) {
1366 eItemKind ik = (*i)->itemKind();
1367 if (!check_faces && ik == IK_Face)
1368 continue;
1369 // It is normal that particles are not sorted
1370 if (ik == IK_Particle)
1371 continue;
1372 //ItemGroup all_items = mesh->itemFamily(ik)->allItems();
1373 ItemGroup all_items = (*i)->allItems();
1374 Item last_item;
1375 ENUMERATE_ITEM (iitem, all_items) {
1376 Item item = *iitem;
1377
1378 if (!last_item.null() && (last_item.uniqueId() >= item.uniqueId() || last_item.localId() >= item.localId())) {
1379 trace->error() << "Item not sorted " << ItemPrinter(item, ik)
1380 << " Last item " << ItemPrinter(last_item, ik);
1381 has_error = true;
1382 }
1383 last_item = item;
1384 }
1385 }
1386 }
1387 if (has_error) {
1388 ARCANE_FATAL("Missing required mesh properties (sorted and/or no hole)");
1389 }
1390}
1391
1392/*---------------------------------------------------------------------------*/
1393/*---------------------------------------------------------------------------*/
1394
1395void MeshUtils::
1396printItems(std::ostream& ostr, const String& name, ItemGroup item_group)
1397{
1398 ostr << " ------- " << name << '\n';
1399 ENUMERATE_ITEM (iitem, item_group) {
1400 ostr << FullItemPrinter((*iitem)) << "\n";
1401 }
1402}
1403
1404/*---------------------------------------------------------------------------*/
1405/*---------------------------------------------------------------------------*/
1406
1407bool MeshUtils::
1408reorderNodesOfFace(Int64ConstArrayView before_ids, Int64ArrayView after_ids)
1409{
1410 // \a true if the faces need to be reoriented so that their orientation
1411 // is independent of the initial mesh partitioning.
1412 bool need_swap_orientation = false;
1413 Integer min_node_index = 0;
1414 Integer nb_node = before_ids.size();
1415
1416 // Directly handles the edge case
1417 if (nb_node == 2) {
1418 if (before_ids[0] < before_ids[1]) {
1419 after_ids[0] = before_ids[0];
1420 after_ids[1] = before_ids[1];
1421 return false;
1422 }
1423 after_ids[0] = before_ids[1];
1424 after_ids[1] = before_ids[0];
1425 return true;
1426 }
1427
1428 // The following algorithm orients the faces taking into account only
1429 // the order of the node numbering. If this order is
1430 // preserved during partitioning, then the face orientation
1431 // will also be preserved.
1432
1433 // The algorithm is as follows:
1434 // - Find node n with the smallest index.
1435 // - Find n-1 and n+1, the indices of its 2 neighboring nodes.
1436 // - If (n+1) is less than (n-1), the orientation is not modified.
1437 // - If (n+1) is greater than (n-1), the orientation is inverted.
1438
1439 // Find the node with the smallest index
1440
1441 Int64 min_node = INT64_MAX;
1442 for (Integer k = 0; k < nb_node; ++k) {
1443 Int64 id = before_ids[k];
1444 if (id < min_node) {
1445 min_node = id;
1446 min_node_index = k;
1447 }
1448 }
1449 Int64 next_node = before_ids[(min_node_index + 1) % nb_node];
1450 Int64 prev_node = before_ids[(min_node_index + (nb_node - 1)) % nb_node];
1451 Integer incr = 0;
1452 Integer incr2 = 0;
1453 if (next_node == min_node) {
1454 next_node = before_ids[(min_node_index + (nb_node + 2)) % nb_node];
1455 incr = 1;
1456 }
1457 if (prev_node == min_node) {
1458 prev_node = before_ids[(min_node_index + (nb_node - 2)) % nb_node];
1459 incr2 = nb_node - 1;
1460 }
1461 if (next_node > prev_node)
1462 need_swap_orientation = true;
1463 if (need_swap_orientation) {
1464 for (Integer k = 0; k < nb_node; ++k) {
1465 Integer index = (nb_node - k + min_node_index + incr) % nb_node;
1466 after_ids[k] = before_ids[index];
1467 }
1468 }
1469 else {
1470 for (Integer k = 0; k < nb_node; ++k) {
1471 Integer index = (k + min_node_index + incr2) % nb_node;
1472 after_ids[k] = before_ids[index];
1473 }
1474 }
1475 return need_swap_orientation;
1476}
1477
1478/*---------------------------------------------------------------------------*/
1479/*---------------------------------------------------------------------------*/
1480
1481bool MeshUtils::
1482reorderNodesOfFace2(Int64ConstArrayView nodes_unique_id, IntegerArrayView new_index)
1483{
1484 // \a true if the faces need to be reoriented so that their orientation
1485 // is independent of the initial mesh partitioning.
1486 bool need_swap_orientation = false;
1487 Integer min_node_index = 0;
1488 Integer nb_node = nodes_unique_id.size();
1489
1490 // Directly handles the edge case for edges
1491 if (nb_node == 2) {
1492 if (nodes_unique_id[0] < nodes_unique_id[1]) {
1493 new_index[0] = 0;
1494 new_index[1] = 1;
1495 return false;
1496 }
1497 new_index[0] = 1;
1498 new_index[1] = 0;
1499 return true;
1500 }
1501
1502 // The following algorithm orients the faces considering only
1503 // the order of the numbering of these nodes. If this order is
1504 // preserved during partitioning, then the orientation of the faces
1505 // will also be preserved.
1506
1507 // The algorithm is as follows:
1508 // - Find the node n with the smallest index.
1509 // - Find n-1 and n+1, the indices of its 2 neighboring nodes.
1510 // - If (n+1) is less than (n-1), the orientation n is not modified.
1511 // - If (n+1) is greater than (n-1), the orientation is inverted.
1512
1513 // Search for the node with the smallest index
1514
1515 Int64 min_node = INT64_MAX;
1516 for (Integer k = 0; k < nb_node; ++k) {
1517 Int64 id = nodes_unique_id[k];
1518 if (id < min_node) {
1519 min_node = id;
1520 min_node_index = k;
1521 }
1522 }
1523 Int64 next_node = nodes_unique_id[(min_node_index + 1) % nb_node];
1524 Int64 prev_node = nodes_unique_id[(min_node_index + (nb_node - 1)) % nb_node];
1525 Integer incr = 0;
1526 Integer incr2 = 0;
1527 if (next_node == min_node) {
1528 next_node = nodes_unique_id[(min_node_index + 2) % nb_node];
1529 incr = 1;
1530 }
1531 if (prev_node == min_node) {
1532 prev_node = nodes_unique_id[(min_node_index + (nb_node - 2)) % nb_node];
1533 incr2 = nb_node - 1;
1534 }
1535 if (next_node > prev_node)
1536 need_swap_orientation = true;
1537 if (need_swap_orientation) {
1538 for (Integer k = 0; k < nb_node; ++k) {
1539 Integer index = (nb_node - k + min_node_index + incr) % nb_node;
1540 new_index[k] = index;
1541 }
1542 }
1543 else {
1544 for (Integer k = 0; k < nb_node; ++k) {
1545 Integer index = (k + min_node_index + incr2) % nb_node;
1546 new_index[k] = index;
1547 }
1548 }
1549 return need_swap_orientation;
1550}
1551
1552/*---------------------------------------------------------------------------*/
1553/*---------------------------------------------------------------------------*/
1554
1555Face MeshUtils::
1556getFaceFromNodesLocalId(Node node, Int32ConstArrayView face_nodes_local_id)
1557{
1558 Integer n = face_nodes_local_id.size();
1559 for (Integer i = 0, s = node.nbFace(); i < s; ++i) {
1560 Face f(node.face(i));
1561 Integer fn = f.nbNode();
1562 if (fn == n) {
1563 bool same_face = true;
1564 for (Integer zz = 0; zz < n; ++zz)
1565 if (f.node(zz).localId() != face_nodes_local_id[zz]) {
1566 same_face = false;
1567 break;
1568 }
1569 if (same_face)
1570 return f;
1571 }
1572 }
1573 return Face();
1574}
1575
1576/*---------------------------------------------------------------------------*/
1577/*---------------------------------------------------------------------------*/
1578
1579Face MeshUtils::
1580getFaceFromNodesUniqueId(Node node, Int64ConstArrayView face_nodes_unique_id)
1581{
1582 Integer n = face_nodes_unique_id.size();
1583 for (Integer i = 0, s = node.nbFace(); i < s; ++i) {
1584 Face f(node.face(i));
1585 Integer fn = f.nbNode();
1586 if (fn == n) {
1587 bool same_face = true;
1588 for (Integer zz = 0; zz < n; ++zz)
1589 if (f.node(zz).uniqueId() != face_nodes_unique_id[zz]) {
1590 same_face = false;
1591 break;
1592 }
1593 if (same_face)
1594 return f;
1595 }
1596 }
1597 return Face();
1598}
1599
1600/*---------------------------------------------------------------------------*/
1601/*---------------------------------------------------------------------------*/
1602
1603void MeshUtils::
1604removeItemAndKeepOrder(Int32ArrayView items, Int32 local_id)
1605{
1606 Integer n = items.size();
1607 if (n <= 0)
1608 ARCANE_FATAL("Can not remove item lid={0} because list is empty", local_id);
1609
1610 --n;
1611 if (n == 0) {
1612 if (items[0] == local_id)
1613 return;
1614 }
1615 else {
1616 // If the element is the last, do nothing.
1617 if (items[n] == local_id)
1618 return;
1619 for (Integer i = 0; i < n; ++i) {
1620 if (items[i] == local_id) {
1621 for (Integer z = i; z < n; ++z)
1622 items[z] = items[z + 1];
1623 return;
1624 }
1625 }
1626 }
1627 // TODO: This needs to be enabled, but for now it crashes a test.
1628 //ARCANE_FATAL("No entity with local_id={0} found in list {1}",local_id,items);
1629}
1630
1631/*---------------------------------------------------------------------------*/
1632/*---------------------------------------------------------------------------*/
1633
1634void MeshUtils::
1635shrinkMeshGroups(IMesh* mesh)
1636{
1637 auto f = [&](ItemGroup& group) {
1638 group.internal()->shrinkMemory();
1639 };
1640 meshvisitor::visitGroups(mesh, f);
1641}
1642
1643/*---------------------------------------------------------------------------*/
1644/*---------------------------------------------------------------------------*/
1645
1646Int64 MeshUtils::
1647printMeshGroupsMemoryUsage(IMesh* mesh, Int32 print_level)
1648{
1649 ITraceMng* tm = mesh->traceMng();
1650 Int64 total_capacity = 0;
1651 Int64 total_computed_capacity = 0;
1652 auto f = [&](ItemGroup& group) {
1653 ItemGroupImpl* p = group.internal();
1654 // Be careful to get the group size via \a p
1655 // because otherwise, for a computed group, it is reconstructed.
1656 Int64 c = p->capacity();
1657 bool is_computed = p->hasComputeFunctor();
1658 total_capacity += c;
1659 if (is_computed)
1660 total_computed_capacity += c;
1661 if (print_level >= 1)
1662 tm->info() << "GROUP Name=" << group.name() << " computed?=" << p->hasComputeFunctor()
1663 << " nb_ref=" << p->nbRef() << " size=" << p->size()
1664 << " capacity=" << c;
1665 };
1666 meshvisitor::visitGroups(mesh, f);
1667 tm->info() << "MeshGroupsMemoryUsage: capacity = " << total_capacity
1668 << " computed_capacity=" << total_computed_capacity;
1669 return total_capacity * sizeof(Int32);
1670}
1671
1672/*---------------------------------------------------------------------------*/
1673/*---------------------------------------------------------------------------*/
1674
1675void MeshUtils::
1676dumpSynchronizerTopologyJSON(IVariableSynchronizer* var_syncer, const String& filename)
1677{
1678 IParallelMng* pm = var_syncer->parallelMng();
1679 ITraceMng* tm = pm->traceMng();
1680 Int32 nb_rank = pm->commSize();
1681 Int32 my_rank = pm->commRank();
1682 Int32ConstArrayView comm_ranks = var_syncer->communicatingRanks();
1683
1684 tm->info(4) << "Dumping VariableSynchronizerTopology filename=" << filename;
1685 Int32 nb_comm_rank = comm_ranks.size();
1686
1687 UniqueArray<Int32> nb_items_by_rank(nb_comm_rank);
1688 for (Integer i = 0; i < nb_comm_rank; ++i)
1689 nb_items_by_rank[i] = var_syncer->sharedItems(i).size();
1690
1691 JSONWriter json_writer(JSONWriter::FormatFlags::None);
1692 json_writer.beginObject();
1693
1694 if (my_rank == 0) {
1695 UniqueArray<Int32> all_nb_comm_ranks(nb_rank);
1696 pm->gather(Int32ConstArrayView(1, &nb_comm_rank), all_nb_comm_ranks, 0);
1697 json_writer.write("NbNeighbor", all_nb_comm_ranks);
1698
1699 {
1700 UniqueArray<Int32> all_neighbor_ranks;
1701 pm->gatherVariable(comm_ranks, all_neighbor_ranks, 0);
1702 json_writer.write("NeighborsRank", all_neighbor_ranks);
1703 }
1704 {
1705 UniqueArray<Int32> all_nb_items_by_rank;
1706 pm->gatherVariable(nb_items_by_rank, all_nb_items_by_rank, 0);
1707 json_writer.write("NeighborsSize", all_nb_items_by_rank);
1708 }
1709 }
1710 else {
1711 pm->gather(Int32ConstArrayView(1, &nb_comm_rank), {}, 0);
1712 UniqueArray<Int32> empty_array;
1713 pm->gatherVariable(comm_ranks, empty_array, 0);
1714 pm->gatherVariable(nb_items_by_rank, empty_array, 0);
1715 }
1716
1717 json_writer.endObject();
1718
1719 if (my_rank == 0) {
1720 std::ofstream ofile(filename.localstr());
1721 auto bytes = json_writer.getBuffer().bytes();
1722 ofile.write(reinterpret_cast<const char*>(bytes.data()), bytes.size());
1723 }
1724}
1725
1726/*---------------------------------------------------------------------------*/
1727/*---------------------------------------------------------------------------*/
1728
1729namespace
1730{
1731 class MyIdsToTest
1732 {
1733 public:
1734
1735 friend bool operator<(const MyIdsToTest& a, const MyIdsToTest& b)
1736 {
1737 return a.ids < b.ids;
1738 }
1739 static constexpr int MAX_SIZE = 16;
1740
1741 public:
1742
1743 std::array<Int32, MAX_SIZE> ids = {};
1744 };
1745
1746 void _computePatternOccurence(const ItemGroup& items, const String& message,
1748 {
1749 std::map<MyIdsToTest, Int32> occurence_map;
1750 Int32 nb_skipped = 0;
1751 ENUMERATE_ (Item, iitem, items) {
1752 Item item = *iitem;
1753 MyIdsToTest diff_ids;
1754
1755 Int32 index = 0;
1756 Int32 lid0 = 0;
1757 bool is_skipped = false;
1758 for (ItemLocalId sub_item : cty.items(item)) {
1759 if (index >= MyIdsToTest::MAX_SIZE) {
1760 is_skipped = true;
1761 break;
1762 }
1763 if (index == 0)
1764 lid0 = sub_item.localId();
1765 diff_ids.ids[index] = sub_item.localId() - lid0;
1766 //info() << " Cell lid=" << item.localId() << " I=" << index << " diff_lid=" << diff_ids.ids[index];
1767 ++index;
1768 }
1769 if (is_skipped)
1770 ++nb_skipped;
1771 else
1772 ++occurence_map[diff_ids];
1773 }
1774 ITraceMng* tm = items.mesh()->traceMng();
1775 tm->info() << "Occurence: " << message << " group=" << items.name()
1776 << " nb=" << items.size() << " map_size=" << occurence_map.size()
1777 << " nb_skipped=" << nb_skipped;
1778 }
1779} // namespace
1780
1781void MeshUtils::
1782computeConnectivityPatternOccurence(IMesh* mesh)
1783{
1785
1787
1788 _computePatternOccurence(mesh->allNodes(), "NodeCells", cty.nodeCell());
1789 _computePatternOccurence(mesh->allNodes(), "NodeFaces", cty.nodeFace());
1790 _computePatternOccurence(mesh->allFaces(), "FaceCells", cty.faceCell());
1791 _computePatternOccurence(mesh->allFaces(), "FaceNodes", cty.faceNode());
1792 _computePatternOccurence(mesh->allCells(), "CellNodes", cty.cellNode());
1793 _computePatternOccurence(mesh->allCells(), "CellFaces", cty.cellFace());
1794}
1795
1796/*---------------------------------------------------------------------------*/
1797/*---------------------------------------------------------------------------*/
1798
1799void MeshUtils::
1800markMeshConnectivitiesAsMostlyReadOnly(IMesh* mesh, RunQueue* queue, bool do_prefetch)
1801{
1802 if (!mesh)
1803 return;
1804 IVariableMng* vm = mesh->variableMng();
1805 VariableCollection used_variables = vm->usedVariables();
1806 const String tag_name = "ArcaneConnectivity";
1808
1809 // Variables associated with connectivity have the tag 'ArcaneConnectivity'.
1810 for (VariableCollection::Enumerator iv(used_variables); ++iv;) {
1811 IVariable* v = *iv;
1812 if (!v->hasTag(tag_name))
1813 continue;
1814 if (v->meshHandle().meshOrNull() == mesh) {
1815 v->setAllocationInfo(alloc_info);
1816 if (do_prefetch)
1818 }
1819 }
1820}
1821
1822/*---------------------------------------------------------------------------*/
1823/*---------------------------------------------------------------------------*/
1824
1825impl::ItemBase MeshUtils::
1826findOneItem(IItemFamily* family, Int64 unique_id)
1827{
1828 ItemInternal* v = family->findOneItem(unique_id);
1829 if (v)
1830 return { v };
1831 return {};
1832}
1833
1834/*---------------------------------------------------------------------------*/
1835/*---------------------------------------------------------------------------*/
1836
1837impl::ItemBase MeshUtils::
1838findOneItem(IItemFamily* family, ItemUniqueId unique_id)
1839{
1840 ItemInternal* v = family->findOneItem(unique_id);
1841 if (v)
1842 return { v };
1843 return {};
1844}
1845
1846/*---------------------------------------------------------------------------*/
1847/*---------------------------------------------------------------------------*/
1848
1849namespace MeshUtils::impl
1850{
1852 Int64 _getMaxUniqueId(const ItemGroup& group, Int64 max_uid)
1853 {
1854 ENUMERATE_ (Item, iitem, group) {
1855 Item item = *iitem;
1856 if (max_uid < item.uniqueId())
1857 max_uid = item.uniqueId();
1858 }
1859 return max_uid;
1860 }
1861} // namespace MeshUtils::impl
1862
1863/*---------------------------------------------------------------------------*/
1864/*---------------------------------------------------------------------------*/
1865
1866ItemUniqueId MeshUtils::
1867getMaxItemUniqueIdCollective(IMesh* mesh)
1868{
1869 Int64 max_uid = NULL_ITEM_UNIQUE_ID;
1870 max_uid = impl::_getMaxUniqueId(mesh->allNodes(), max_uid);
1871 max_uid = impl::_getMaxUniqueId(mesh->allEdges(), max_uid);
1872 max_uid = impl::_getMaxUniqueId(mesh->allCells(), max_uid);
1873 max_uid = impl::_getMaxUniqueId(mesh->allFaces(), max_uid);
1874 Int64 global_max = mesh->parallelMng()->reduce(Parallel::ReduceMax, max_uid);
1875 return ItemUniqueId(global_max);
1876}
1877
1878/*---------------------------------------------------------------------------*/
1879/*---------------------------------------------------------------------------*/
1880
1881void MeshUtils::
1882checkUniqueIdsHashCollective(IItemFamily* family, IHashAlgorithm* hash_algo,
1883 const String& expected_hash, bool print_hash,
1884 bool include_ghost)
1885{
1886 ARCANE_CHECK_POINTER(family);
1887 ARCANE_CHECK_POINTER(hash_algo);
1888
1889 IParallelMng* pm = family->parallelMng();
1890 ITraceMng* tm = family->traceMng();
1891
1892 UniqueArray<Int64> own_items_uid;
1893 ItemGroup own_items_group = (include_ghost ? family->allItems() : family->allItems().own());
1894 ENUMERATE_ (Item, iitem, own_items_group) {
1895 Item item{ *iitem };
1896 own_items_uid.add(item.uniqueId());
1897 }
1898 UniqueArray<Int64> global_items_uid;
1899 pm->allGatherVariable(own_items_uid, global_items_uid);
1900 std::sort(global_items_uid.begin(), global_items_uid.end());
1901
1902 UniqueArray<Byte> hash_result;
1903 hash_algo->computeHash64(asBytes(global_items_uid.constSpan()), hash_result);
1904 String hash_str = Convert::toHexaString(hash_result);
1905 if (print_hash)
1906 tm->info() << "HASH_RESULT family=" << family->name()
1907 << " v=" << hash_str << " expected=" << expected_hash;
1908 if (!expected_hash.empty() && hash_str != expected_hash)
1909 ARCANE_FATAL("Bad hash for uniqueId() for family '{0}' v='{1}' expected='{2}'",
1910 family->fullName(), hash_str, expected_hash);
1911}
1912
1913/*---------------------------------------------------------------------------*/
1914/*---------------------------------------------------------------------------*/
1915
1916void MeshUtils::
1917fillUniqueIds(ItemVectorView items, Array<Int64>& uids)
1918{
1919 Integer nb_item = items.size();
1920 uids.resize(nb_item);
1921 ENUMERATE_ITEM (iitem, items)
1922 uids[iitem.index()] = iitem->uniqueId();
1923}
1924
1925/*---------------------------------------------------------------------------*/
1926/*---------------------------------------------------------------------------*/
1927
1928Int64 MeshUtils::
1929generateHashUniqueId(SmallSpan<const Int64> nodes_unique_id)
1930{
1931 // All bits are formed using the hash function.
1932 // The generated uniqueId() must always be positive
1933 // except for the null entity.
1934 Int32 nb_node = nodes_unique_id.size();
1935 if (nb_node == 0)
1936 return -1;
1938 Int64 uid0 = nodes_unique_id[0];
1939 Int64 hash = Hasher::hashfunc(uid0);
1940 for (Int32 i = 1; i < nb_node; ++i) {
1941 Int64 next_hash = Hasher::hashfunc(nodes_unique_id[i]);
1942 hash ^= next_hash + 0x9e3779b9 + (hash << 6) + (hash >> 2);
1943 }
1944 Int64 new_uid = abs(hash);
1945 ARCANE_ASSERT(new_uid >= 0, ("UniqueId is not >= 0"));
1946 return new_uid;
1947}
1948
1949/*---------------------------------------------------------------------------*/
1950/*---------------------------------------------------------------------------*/
1951
1952void MeshUtils::
1953computeAndSetOwnerForNodes(IMesh* mesh)
1954{
1956 mesh->utilities()->computeAndSetOwnersForNodes();
1957}
1958
1959/*---------------------------------------------------------------------------*/
1960/*---------------------------------------------------------------------------*/
1961
1962void MeshUtils::
1963computeAndSetOwnerForEdges(IMesh* mesh)
1964{
1966 mesh->utilities()->computeAndSetOwnersForEdges();
1967}
1968
1969/*---------------------------------------------------------------------------*/
1970/*---------------------------------------------------------------------------*/
1971
1972void MeshUtils::
1973computeAndSetOwnerForFaces(IMesh* mesh)
1974{
1976 mesh->utilities()->computeAndSetOwnersForFaces();
1977}
1978
1979/*---------------------------------------------------------------------------*/
1980/*---------------------------------------------------------------------------*/
1981
1982} // End namespace Arcane
1983
1984/*---------------------------------------------------------------------------*/
1985/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Types and macros for iterating over mesh entities.
#define ENUMERATE_FACE(name, group)
Generic enumerator for a face group.
#define ENUMERATE_(type, name, group)
Generic enumerator for an entity group.
#define ENUMERATE_ITEM(name, group)
Generic enumerator for a node group.
Various mathematical functions.
Utility functions for the mesh.
Utility functions for variables.
void prefetchVariableAsync(IVariable *var, const RunQueue *queue_or_null)
Prefetches the memory associated with the variable var.
Integer size() const
Number of elements in the vector.
constexpr Integer size() const noexcept
Returns the size of the array.
Base class for 1D data vectors.
void resize(Int64 s)
Changes the number of elements in the array to s.
void clear()
Removes the elements from the array.
iterator begin()
Iterator over the first element of the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
Span< const T > constSpan() const
Constant view of this array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
iterator end()
Iterator over the first element after the end of the array.
View of cell information.
Cell of a mesh.
Definition Item.h:1300
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
ARCANE_DEPRECATED_122 Int32 size() const
Number of elements in the first dimension.
Information on data allocation.
View of edge information.
Edge of a cell.
Definition Item.h:875
Cell cell(Int32 i) const
i-th cell of the edge
Definition Item.h:1759
Face face(Int32 i) const
i-th face of the edge
Definition Item.h:1753
Int32 nbFace() const
Number of faces connected to the edge.
Definition Item.h:975
Int32 nbNode() const
Number of vertices of the edge.
Definition Item.h:972
Int32 nbCell() const
Number of cells connected to the edge.
Definition Item.h:978
View of face information.
Face of a cell.
Definition Item.h:1032
Cell frontCell() const
Cell in front of the face (null cell if none).
Definition Item.h:1780
Cell cell(Int32 i) const
i-th cell of the face
Definition Item.h:1793
Int32 nbCell() const
Number of cells of the face (1 or 2).
Definition Item.h:1129
Edge edge(Int32 i) const
i-th edge of the face
Definition Item.h:1243
Int32 nbEdge() const
Number of edges of the face.
Definition Item.h:1240
Cell backCell() const
Cell behind the face (null cell if none).
Definition Item.h:1774
Information about the floating-point type.
Definition Limits.h:49
Interface of a hashing algorithm.
virtual void computeHash64(Span< const Byte > input, ByteArray &output)
Calculates the hash value for the array input.
Interface of an entity family.
Definition IItemFamily.h:83
virtual ItemGroup allItems() const =0
Group of all entities.
virtual ItemInternal * findOneItem(Int64 unique_id)=0
Unique ID entity unique_id.
virtual IParallelMng * parallelMng() const =0
Associated parallelism manager.
virtual String name() const =0
Family name.
virtual ITraceMng * traceMng() const =0
Associated trace manager.
virtual String fullName() const =0
Full family name (with the mesh's name).
Interface of the parallelism manager for a subdomain.
virtual void gatherVariable(ConstArrayView< char > send_buf, Array< char > &recv_buf, Int32 rank)=0
Performs an all-gather operation across all processors.
virtual ITraceMng * traceMng() const =0
Trace manager.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual void allGatherVariable(ConstArrayView< char > send_buf, Array< char > &recv_buf)=0
Performs an all-gather operation across all processors.
virtual Int32 commSize() const =0
Number of instances in the communicator.
virtual void gather(ConstArrayView< char > send_buf, ArrayView< char > recv_buf, Int32 rank)=0
Performs a gather operation onto a processor. This is a collective operation. The array send_buf must...
Interface of the subdomain manager.
Definition ISubDomain.h:75
Interface of a class managing semi-conforming mesh.
virtual TraceMessage pinfo()=0
Stream for a parallel information message.
virtual TraceMessage error()=0
Stream for an error message.
virtual TraceMessage info()=0
Stream for an information message.
Variable manager interface.
virtual VariableCollection usedVariables()=0
List of used variables.
Interface of a variable synchronization service.
virtual Int32ConstArrayView communicatingRanks()=0
Ranks of subdomains with which communication occurs.
virtual IParallelMng * parallelMng()=0
Associated parallel manager.
virtual Int32ConstArrayView sharedItems(Int32 index)=0
List of local IDs of entities shared with a subdomain.
Interface of a variable.
Definition IVariable.h:40
virtual bool hasTag(const String &tagname)=0
true if the variable has the tag tagname
virtual void setAllocationInfo(const DataAllocationInfo &v)=0
Sets allocation information.
virtual MeshHandle meshHandle() const =0
Mesh associated with the variable.
static IXmlDocumentHolder * loadFromFile(const String &filename, ITraceMng *tm)
Loads an XML document.
Definition DomUtils.cc:444
Base class for a view on unstructured connectivity.
Functor for a hash function.
Base class for mesh entities.
Integer nbEdge() const
Number of edges of the entity or number of edges connected to the entity (for nodes).
ItemUniqueId uniqueId() const
Unique number of the entity.
Integer nbCell() const
Number of cells connected to the entity (for nodes, edges, and faces).
Int32 owner() const
Number of the owning subdomain of the entity.
Integer nbFace() const
Number of faces of the entity or number of faces connected to the entity (for nodes and edges).
Integer nbNode() const
Number of nodes of the entity.
View of a list of entities connected to another.
Brief: Implementation of a mesh entity group.
virtual Integer nbRef() const
Number of references on the group.
Integer size() const
Number of entities in the group.
Int64 capacity() const
Number of allocated elements.
bool hasComputeFunctor() const
Indicates if the group is calculated.
Mesh entity group.
Definition ItemGroup.h:51
const String & name() const
Group name.
Definition ItemGroup.h:81
bool isLocalToSubDomain() const
True if the group is local to the subdomain.
Definition ItemGroup.h:230
ItemGroup own() const
Group equivalent to this one but containing only the local elements of the subdomain.
Definition ItemGroup.cc:182
Internal structure of a mesh entity.
Index of an Item in a variable.
Definition ItemLocalId.h:42
Utility class for printing information about an entity.
Definition ItemPrinter.h:35
static eItemKind kind()
Entity kind.
Definition ItemTypes.h:629
Unique identifier of an entity.
View on a vector of entities.
Int32 size() const
Number of elements in the vector.
Mesh element based on nodes (Edge,Face,Cell).
Definition Item.h:773
Node node(Int32 i) const
i-th node of the entity
Definition Item.h:840
Int32 nbNode() const
Number of nodes of the entity.
Definition Item.h:837
Base class for a mesh element.
Definition Item.h:84
constexpr Int32 localId() const
Local identifier of the entity in the processor subdomain.
Definition Item.h:233
ItemUniqueId uniqueId() const
Unique identifier across all domains.
Definition Item.h:239
constexpr bool null() const
true if the entity is null (i.e. not connected to the mesh)
Definition Item.h:230
impl::ItemBase itemBase() const
Internal part of the entity.
Definition Item.h:383
IMesh * meshOrNull() const
Returns the mesh associated with this instance.
Generic information about the types of a mesh variable.
View of node information.
Node of a mesh.
Definition Item.h:598
Cell cell(Int32 i) const
i-th cell of the node
Definition Item.h:1744
CellConnectedListViewType cells() const
List of cells of the node.
Definition Item.h:728
constexpr Int32 nbFace() const
Number of faces connected to the node.
Definition Item.h:698
Face face(Int32 i) const
i-th face of the node
Definition Item.h:1738
Int32 nbCell() const
Number of cells connected to the node.
Definition Item.h:701
Class managing a 3-dimensional real vector.
Definition Real3.h:132
Encapsulation of an automatically destructing pointer.
Definition ScopedPtr.h:44
View of an array of elements of type T.
Definition Span.h:805
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
Definition Span.h:327
Unicode character string constructor.
constexpr Span< const Byte > bytes() const ARCCORE_NOEXCEPT
Returns the conversion of the instance in UTF-8 encoding.
Definition StringView.h:93
Int64 length() const
Returns the length of the string.
Definition String.cc:340
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:229
bool empty() const
True if the string is empty (null or "").
Definition String.cc:317
Semi-conforming mesh face.
Definition TiedFace.h:35
Face face() const
Welded face.
Definition TiedFace.h:52
Semi-conformal mesh node.
Definition TiedNode.h:40
Node node() const
Tied node.
Definition TiedNode.h:59
Real2 isoCoordinates() const
Iso-barycentric coordinates of the node.
Definition TiedNode.h:62
Formatting the stream by length.
1D data vector with value semantics (STL style).
View of the standard connectivities of an unstructured mesh.
Node of a DOM tree.
Definition XmlNode.h:51
Class to calculate the hash of an array.
ItemGroupT< Face > FaceGroup
Group of faces.
Definition ItemTypes.h:179
ItemEnumeratorT< Node > NodeEnumerator
Enumerators over nodes.
Definition ItemTypes.h:255
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
String toHexaString(ByteConstArrayView input)
Converts a byte array to its hexadecimal representation.
@ ReduceMax
Maximum of values.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Array< Int64 > Int64Array
Dynamic one-dimensional array of 64-bit integers.
Definition UtilsTypes.h:125
ArrayView< Int64 > Int64ArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:451
Integer arcaneCheckArraySize(unsigned long long size)
Checks that size can be converted into an 'Integer' to serve as the size of an array....
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
Definition UtilsTypes.h:339
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ConstArrayView< Int32 > Int32ConstArrayView
C equivalent of a 1D array of 32-bit integers.
Definition UtilsTypes.h:482
ArrayView< Integer > IntegerArrayView
C equivalent of a 1D array of integers.
Definition UtilsTypes.h:457
bool operator<(const Item &item1, const Item &item2)
Compare two entities.
Definition Item.h:566
ConstArrayView< ItemInternal * > ItemInternalList
Type of the internal list of entities.
Definition ItemTypes.h:466
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:480
@ HostAndDeviceMostlyRead
Indicates that the data will be used both on the accelerator and on the CPU and will not be frequentl...
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
Definition UtilsTypes.h:341
ArrayView< Int32 > Int32ArrayView
C equivalent of a 1D array of 32-bit integers.
Definition UtilsTypes.h:453
SharedMeshVariableScalarRefT< Node, Real3 > SharedVariableNodeReal3
Quantity at the node of coordinate type.
eItemKind
Mesh entity type.
@ IK_Particle
Particle mesh entity.
@ IK_Node
Node mesh entity.
@ IK_Cell
Cell mesh entity.
@ IK_Face
Face mesh entity.
@ IK_Edge
Edge mesh entity.
const char * itemKindName(eItemKind kind)
Entity kind name.
Impl::SpanTypeFromSize< conststd::byte, SizeType >::SpanType asBytes(const SpanImpl< DataType, SizeType, Extent > &s)
Converts the view into an array of non-modifiable bytes.
Definition Span.h:1032
Array< Int32 > Int32Array
Dynamic one-dimensional array of 32-bit integers.
Definition UtilsTypes.h:127
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53
Collection< ITiedInterface * > TiedInterfaceCollection
Collection of tied interfaces.
std::int32_t Int32
Signed integer type of 32 bits.
Real y
second component of the triplet
Definition Real3.h:36
Real z
third component of the triplet
Definition Real3.h:37
Real x
first component of the triplet
Definition Real3.h:35