Arcane  4.1.11.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
DynamicMeshChecker.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/* DynamicMeshChecker.cc (C) 2000-2025 */
9/* */
10/* Class providing methods for mesh checking. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ScopedPtr.h"
15#include "arcane/utils/ValueChecker.h"
16
17#include "arcane/mesh/DynamicMesh.h"
18#include "arcane/mesh/ItemGroupsSynchronize.h"
19#include "arcane/mesh/FaceReorienter.h"
20#include "arcane/mesh/DynamicMeshChecker.h"
21
23#include "arcane/core/Properties.h"
24#include "arcane/core/ItemPrinter.h"
25#include "arcane/core/TemporaryVariableBuildInfo.h"
26#include "arcane/core/IXmlDocumentHolder.h"
27#include "arcane/core/XmlNodeList.h"
28#include "arcane/core/IIOMng.h"
29#include "arcane/core/IParallelMng.h"
30#include "arcane/core/IParallelReplication.h"
31#include "arcane/core/VariableCollection.h"
32#include "arcane/core/NodesOfItemReorderer.h"
33
34#include <set>
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39namespace Arcane::mesh
40{
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45DynamicMeshChecker::
46DynamicMeshChecker(IMesh* mesh)
47: TraceAccessor(mesh->traceMng())
48, m_mesh(mesh)
49{
50 if (arcaneIsCheck())
51 m_check_level = 1;
52}
53
54/*---------------------------------------------------------------------------*/
55/*---------------------------------------------------------------------------*/
56
57DynamicMeshChecker::
58~DynamicMeshChecker()
59{
60 delete m_var_cells_faces;
61 delete m_var_cells_nodes;
62}
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
73void DynamicMeshChecker::
74checkValidMesh()
75{
76 info(4) << "Check mesh coherence.";
78
79 for (IItemFamilyCollection::Enumerator i(m_mesh->itemFamilies()); ++i;) {
80 IItemFamily* family = *i;
81 //GG: check why this test exists.
82 if (family->itemKind() >= NB_ITEM_KIND)
83 continue;
84 family->checkValid();
85 }
86 mesh_utils::checkMeshProperties(m_mesh, false, false, true);
87
88 // Store in a mesh variable the list of faces and
89 // nodes that compose it.
90 // This is only useful for checks
91 // NOTE: currently set to false because it crashes if
92 // initial partitioning is used in Arcane
93 const bool global_check = false;
94 if (m_check_level >= 1 && global_check) {
95 if (!m_var_cells_faces)
96 m_var_cells_faces = new VariableCellArrayInt64(VariableBuildInfo(m_mesh, "MeshTestCellFaces"));
97
98 if (!m_var_cells_nodes)
99 m_var_cells_nodes = new VariableCellArrayInt64(VariableBuildInfo(m_mesh, "MeshTestCellNodes"));
100
101 CellGroup all_cells(m_mesh->allCells());
102 Integer max_nb_face = 0;
103 Integer max_nb_node = 0;
104 ENUMERATE_CELL (i, all_cells) {
105 Cell cell = *i;
106 Integer nb_face = cell.nbFace();
107 Integer nb_node = cell.nbNode();
108 if (nb_face > max_nb_face)
109 max_nb_face = nb_face;
110 if (nb_node > max_nb_node)
111 max_nb_node = nb_node;
112 }
113 m_var_cells_faces->resize(max_nb_face);
114 m_var_cells_nodes->resize(max_nb_node);
115 ENUMERATE_CELL (i, all_cells) {
116 Cell cell = *i;
117 Integer nb_face = cell.nbFace();
118 for (Integer z = 0; z < nb_face; ++z)
119 (*m_var_cells_faces)[cell][z] = cell.face(z).uniqueId().asInt64();
120 Integer nb_node = cell.nbNode();
121 for (Integer z = 0; z < nb_node; ++z)
122 (*m_var_cells_nodes)[cell][z] = cell.node(z).uniqueId().asInt64();
123 }
124 }
126}
127
128/*---------------------------------------------------------------------------*/
129/*---------------------------------------------------------------------------*/
130
131void DynamicMeshChecker::
132checkValidMeshFull()
133{
134 String func_name("DynamicMesh::checkValidMeshFull");
135 info() << func_name << " on " << m_mesh->name();
136 Integer nb_error = 0;
137 VariableFaceInt64 var_faces(VariableBuildInfo(m_mesh, "MeshCheckFaces"));
138 debug() << " VAR_FACE GROUP=" << var_faces.variable()->itemFamily()
139 << " NAME=" << var_faces.itemGroup().name()
140 << " FAMILY_NAME=" << var_faces.variable()->itemFamilyName()
141 << " GROUP_NAME=" << var_faces.variable()->itemGroupName();
142 ENUMERATE_FACE (iface, m_mesh->allFaces()) {
143 Face face = *iface;
144 Cell c = face.backCell();
145 Int64 uid = c.null() ? NULL_ITEM_UNIQUE_ID : c.uniqueId();
146 var_faces[face] = uid;
147 }
148 var_faces.synchronize();
149 ENUMERATE_FACE (iface, m_mesh->allFaces()) {
150 Face face = *iface;
151 Cell c = face.backCell();
152 Int64 uid = c.null() ? NULL_ITEM_UNIQUE_ID : c.uniqueId();
153 if (uid != var_faces[face] && uid != NULL_ITEM_ID && var_faces[face] != NULL_ITEM_ID) {
154 error() << func_name << " bad back cell in face uid=" << face.uniqueId();
155 ++nb_error;
156 }
157 }
158
159 ENUMERATE_FACE (iface, m_mesh->allFaces()) {
160 Face face = *iface;
161 Cell c = face.frontCell();
162 Int64 uid = c.null() ? NULL_ITEM_UNIQUE_ID : c.uniqueId();
163 var_faces[face] = uid;
164 }
165 var_faces.synchronize();
166 ENUMERATE_FACE (iface, m_mesh->allFaces()) {
167 Face face = *iface;
168 Cell c = face.frontCell();
169 Int64 uid = c.null() ? NULL_ITEM_UNIQUE_ID : c.uniqueId();
170 if (uid != var_faces[face] && uid != NULL_ITEM_ID && var_faces[face] != NULL_ITEM_ID) {
171 error() << func_name << " bad front cell in face uid=" << face.uniqueId();
172 ++nb_error;
173 }
174 }
175
176 ENUMERATE_CELL (icell, m_mesh->allCells()) {
177 Cell cell = *icell;
178 Integer cell_type = cell.type();
179 if (cell_type == IT_Line2) {
180 error() << func_name << " bad cell type in face uid=" << cell.uniqueId();
181 ++nb_error;
182 }
183 }
184
185 ENUMERATE_FACE (iface, m_mesh->allFaces()) {
186 Face face = *iface;
187 Integer face_type = face.type();
188 if (face_type == IT_Vertex) {
189 error() << func_name << " bad face type in face uid=" << face.uniqueId();
190 ++nb_error;
191 }
192 }
193
194 if (nb_error != 0)
195 ARCANE_FATAL("Invalid mesh");
196}
197
198/*---------------------------------------------------------------------------*/
199/*---------------------------------------------------------------------------*/
200/*
201 * \brief Checks that connectivity is valid.
202 *
203 * The checks cover the following points:
204 * - no mesh entities having a null index.
205 * - for faces, checks that at least one frontCell or backCell exists. Furthermore, if it has two meshes, the backCell must always be the first.
206 * - nodes and faces must have the same owner as one of the adjacent meshes.
207 * - checks that faces are correctly ordered and oriented
208 */
209void DynamicMeshChecker::
210checkValidConnectivity()
211{
212 String func_name = "MeshChecker::checkValidConnectivity";
213 debug() << func_name << " check";
214
215 // Calls the checkValidConnectivity method for each family.
216 IItemFamilyCollection item_families = m_mesh->itemFamilies();
217 for (auto x = item_families.enumerator(); ++x;) {
218 IItemFamily* f = *x;
220 }
221
222 if (!m_mesh->parentMesh()) {
223 Integer index = 0;
224 ENUMERATE_ (Face, i, m_mesh->allFaces()) {
225 Face elem = *i;
226 Cell front_cell = elem.frontCell();
227 Cell back_cell = elem.backCell();
228 if (front_cell.null() && back_cell.null())
229 ARCANE_FATAL("Local face '{0}' has two null cell face=", index, ItemPrinter(elem));
230 index++;
231 }
232 }
233
234 // Checks that the mesh<->node connectivity
235 // is reciprocal
236 ENUMERATE_NODE (inode, m_mesh->allNodes()) {
237 Node node = *inode;
238 for (Cell cell : node.cells()) {
239 bool has_found = false;
240 for (Node node2 : cell.nodes()) {
241 if (node2 == node) {
242 has_found = true;
243 break;
244 }
245 }
246 if (!has_found) {
247 ARCANE_FATAL("Node uid={0} is connected to the cell uid={1} but the cell"
248 " is not connected to this node.",
249 ItemPrinter(node), ItemPrinter(cell));
250 }
251 }
252 }
253
254 // ATT: the following checks are not compatible with AMR
255 // TODO : extend checks for AMR
257 if (!m_mesh->isAmrActivated()) {
258 // Checks that the mesh<->edge connectivity
259 // is reciprocal
260 ENUMERATE_EDGE (iedge, m_mesh->allEdges()) {
261 Edge edge = *iedge;
262 for (Cell cell : edge.cells()) {
263 bool has_found = false;
264 for (Edge edge2 : cell.edges()) {
265 if (edge2 == edge) {
266 has_found = true;
267 break;
268 }
269 }
270 if (!has_found) {
271 ARCANE_FATAL("Edge uid={0} is connected to the cell uid={1} but the cell"
272 " is not connected to this edge.",
273 ItemPrinter(edge), ItemPrinter(cell));
274 }
275 }
276 }
277 }
278 // Checks that the mesh<->face connectivity
279 // is reciprocal
280 ENUMERATE_FACE (iface, m_mesh->allFaces()) {
281 Face face = *iface;
282 if (!m_mesh->isAmrActivated()) {
283 for (Cell cell : face.cells()) {
284 bool has_found = false;
285 for (Face face2 : cell.faces()) {
286 if (face2 == face) {
287 has_found = true;
288 break;
289 }
290 }
291 if (!has_found) {
292 ARCANE_FATAL("Face uid={0} is connected to the cell uid={1} but the cell"
293 " is not connected to this face.",
294 ItemPrinter(face), ItemPrinter(cell));
295 }
296 }
297 }
298 for (Cell cell : face.cells()) {
299 bool has_found = false;
300 for (Face face2 : cell.faces()) {
301 if (face2 == face) {
302 has_found = true;
303 break;
304 }
305 }
306 if (!has_found && (face.backCell().level() == face.frontCell().level())) {
307 warning() << func_name << ". The face " << FullItemPrinter(face)
308 << " is connected to the cell " << FullItemPrinter(cell)
309 << " but the cell (level " << cell.level() << ")"
310 << " is not connected to the face.";
311 }
312 }
313
314 Integer nb_cell = face.nbCell();
315 Cell back_cell = face.backCell();
316 Cell front_cell = face.frontCell();
317 if ((back_cell.null() || front_cell.null()) && nb_cell == 2)
318 ARCANE_FATAL("Face uid='{0}' bad number of cells face", ItemPrinter(face));
319 // If we have two connected meshes, then the back cell must be the first
320 if (nb_cell == 2 && back_cell != face.cell(0))
321 ARCANE_FATAL("Bad face face.backCell()!=face.cell(0) face={0} back_cell={1} from_cell={2} cell0={3}",
322 ItemPrinter(face), ItemPrinter(back_cell), ItemPrinter(front_cell), ItemPrinter(face.cell(0)));
323 }
324
327
328 if (m_mesh->parentMesh()) {
329 Integer nerror = 0;
330 eItemKind kinds[] = { IK_Node, IK_Edge, IK_Face, IK_Cell };
331 Integer nb_kind = sizeof(kinds) / sizeof(eItemKind);
332
333 for (Integer i_kind = 0; i_kind < nb_kind; ++i_kind) {
334 const eItemKind kind = kinds[i_kind];
335 IItemFamily* family = m_mesh->itemFamily(kind);
336 if (!family->parentFamily()) {
337 error() << "Mesh " << m_mesh->name() << " : Family " << kind << " does not exist in mesh";
338 ++nerror;
339 }
340 else {
341 ENUMERATE_ITEM (iitem, family->allItems()) {
342 const Item& item = *iitem;
343 const Item& parent_item = item.parent();
344 if (parent_item.itemBase().isSuppressed()) {
345 error() << "Mesh " << m_mesh->name() << " : Inconsistent suppresssed parent item uid : "
346 << ItemPrinter(item) << " / " << ItemPrinter(parent_item);
347 ++nerror;
348 }
349 if (parent_item.uniqueId() != item.uniqueId()) {
350 error() << "Mesh " << m_mesh->name() << " : Inconsistent item/parent item uid : " << ItemPrinter(item);
351 ++nerror;
352 }
353 }
354 }
355 }
356 if (nerror > 0)
357 ARCANE_FATAL("Mesh name={0} has {1} (see above)", m_mesh->name(), String::plural(nerror, "error"));
358
359 // Checks the parallel consistency of the parent group
360 nerror = 0;
361 {
362 ItemGroup parent_group = m_mesh->parentGroup();
363 String var_name = String::format("SubMesh_{0}_GroupConsistencyChecker", parent_group.name());
364 TemporaryVariableBuildInfo tvbi(m_mesh->parentMesh(), var_name, parent_group.itemFamily()->name());
365 ItemVariableScalarRefT<Integer> var(tvbi, m_mesh->parentGroup().itemKind());
366 var.fill(-1);
367 ENUMERATE_ITEM (iitem, m_mesh->parentGroup()) {
368 var[iitem] = iitem->owner();
369 }
370 nerror += var.checkIfSync(10);
371 }
372 if (nerror > 0)
373 ARCANE_FATAL("Mesh name={0} has parent group consistency {1}\n"
374 "This usually means that parent group was not symmetrically built",
375 m_mesh->name(), String::plural(nerror, "error", false));
376 }
377
378 if (m_is_check_items_owner) {
379 _checkValidItemOwner(m_mesh->nodeFamily());
380 _checkValidItemOwner(m_mesh->edgeFamily());
381 _checkValidItemOwner(m_mesh->faceFamily());
382 _checkValidItemOwner(m_mesh->cellFamily());
383 }
384}
385
386/*---------------------------------------------------------------------------*/
387/*---------------------------------------------------------------------------*/
388
389void DynamicMeshChecker::
390updateAMRFaceOrientation()
391{
392 String func_name = "MeshChecker::updateAMRFaceOrientation";
393 FaceReorienter fr(m_mesh);
394 ENUMERATE_FACE (iface, m_mesh->allFaces()) {
395 Face face = *iface;
396 Integer nb_cell = face.nbCell();
397 Cell back_cell = face.backCell();
398 Cell front_cell = face.frontCell();
399 if ((back_cell.null() || front_cell.null()) && nb_cell == 2)
400 ARCANE_FATAL("Bad number of cells for face={0}", ItemPrinter(face));
401 // If we have two connected meshes, then the back cell must be the first
402 if (nb_cell == 2 && back_cell != face.cell(0))
403 ARCANE_FATAL("Bad face face.backCell()!=face.cell(0) face={0} back_cell={1} from_cell={2} cell0={3}",
404 ItemPrinter(face), ItemPrinter(back_cell), ItemPrinter(front_cell), ItemPrinter(face.cell(0)));
405
406 // This could undoubtedly be optimized
407 fr.checkAndChangeOrientationAMR(face);
408 }
409}
410
411/*---------------------------------------------------------------------------*/
412/*---------------------------------------------------------------------------*/
413
414void DynamicMeshChecker::
415updateAMRFaceOrientation(ArrayView<Int64> ghost_cell_to_refine)
416{
417 ItemInternalList cells = m_mesh->itemsInternal(IK_Cell);
418 UniqueArray<Integer> lids(ghost_cell_to_refine.size());
419 m_mesh->cellFamily()->itemsUniqueIdToLocalId(lids, ghost_cell_to_refine, true);
420 FaceReorienter fr(m_mesh);
421 std::set<Int64> set;
422 typedef std::pair<std::set<Int64>::iterator, bool> return_type;
423 for (Integer i = 0, n = lids.size(); i < n; ++i) {
424 Cell icell = cells[lids[i]];
425 for (Integer ic = 0, nchild = icell.nbHChildren(); ic < nchild; ++ic) {
426 Cell child = icell.hChild(ic);
427 for (Face face : child.faces()) {
428 return_type value = set.insert(face.uniqueId());
429 if (value.second) {
430 fr.checkAndChangeOrientationAMR(face);
431 }
432 }
433 }
434 }
435}
436
437/*---------------------------------------------------------------------------*/
438/*---------------------------------------------------------------------------*/
442void DynamicMeshChecker::
443_checkFacesOrientation()
444{
445 bool is_1d = (m_mesh->dimension() == 1);
446 //Temporary: for now, does not test orientation in 1D.
447 if (is_1d)
448 return;
449
450 String func_name = "MeshChecker::_checkFacesOrientation";
451
452 Int64UniqueArray work_face_sorted_nodes;
453 IntegerUniqueArray work_face_nodes_index;
454 Int64UniqueArray work_face_orig_nodes_uid;
455 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
456 NodesOfItemReorderer face_reorderer(item_type_mng);
457 ENUMERATE_ (Cell, icell, m_mesh->allCells()) {
458 Cell cell = *icell;
459 const ItemTypeInfo* type = cell.typeInfo();
460 Int32 cell_nb_face = type->nbLocalFace();
461 for (Integer i_face = 0; i_face < cell_nb_face; ++i_face) {
462 const ItemTypeInfo::LocalFace& lf = type->localFace(i_face);
463 Integer face_nb_node = lf.nbNode();
464
465 work_face_orig_nodes_uid.resize(face_nb_node);
466 for (Integer z = 0; z < face_nb_node; ++z)
467 work_face_orig_nodes_uid[z] = cell.node(lf.node(z)).uniqueId();
468
469 bool is_reorder = false;
470 if (is_1d) {
471 is_reorder = face_reorderer.reorder1D(i_face, work_face_orig_nodes_uid[0]);
472 }
473 else
474 is_reorder = face_reorderer.reorder(ItemTypeId::fromInteger(lf.typeId()), work_face_orig_nodes_uid);
475 ConstArrayView<Int64> face_sorted_nodes(face_reorderer.sortedNodes());
476
477 Face cell_face = cell.face(i_face);
478 if (cell_face.nbNode() != face_nb_node)
479 ARCANE_FATAL("Incoherent number of node for 'face' and 'localFace'"
480 " cell={0} face={1} nb_local_node={2} nb_face_node={3}",
481 ItemPrinter(cell), ItemPrinter(cell_face), face_nb_node, cell_face.nbNode());
482
483 for (Integer z = 0; z < face_nb_node; ++z) {
484 if (cell_face.node(z).uniqueId() != face_sorted_nodes[z])
485 ARCANE_FATAL("Bad node unique id for face: cell={0} face={1} cell_node_uid={2} face_node_uid={3} z={4}",
486 ItemPrinter(cell), ItemPrinter(cell_face), face_sorted_nodes[z],
487 cell_face.node(z).uniqueId());
488 }
489 if (is_reorder) {
490 Cell front_cell = cell_face.frontCell();
491 if (front_cell != cell) {
492 if (!front_cell.null())
493 ARCANE_FATAL("Bad orientation for face. Should be front cell: cell={0} face={1} front_cell={2}",
494 ItemPrinter(cell), ItemPrinter(cell_face), ItemPrinter(front_cell));
495 else
496 ARCANE_FATAL("Bad orientation for face. Should be front cell (no front cell) cell={0} face={1}",
497 ItemPrinter(cell), ItemPrinter(cell_face));
498 }
499 }
500 else {
501 Cell back_cell = cell_face.backCell();
502 if (back_cell != cell) {
503 if (!back_cell.null())
504 ARCANE_FATAL("Bad orientation for face. Should be back cell: cell={0} face={1} front_cell={2}",
505 ItemPrinter(cell), ItemPrinter(cell_face), ItemPrinter(back_cell));
506 else
507 ARCANE_FATAL("Bad orientation for face. Should be back cell (no back cell) cell={0} face={1}",
508 ItemPrinter(cell), ItemPrinter(cell_face));
509 }
510 }
511 }
512 }
513}
514
515/*---------------------------------------------------------------------------*/
516/*---------------------------------------------------------------------------*/
520void DynamicMeshChecker::
521_checkEdgesOrientation()
522{
523 // For edges, checks that the uniqueId() of the first node is
524 // less than that of the second.
525 Int32 nb_error = 0;
526 ENUMERATE_ (Edge, iedge, m_mesh->allEdges()) {
527 Edge edge = *iedge;
528 Int32 nb_node = edge.nbNode();
529 if (nb_node >= 2) {
530 Node node0 = edge.node(0);
531 Node node1 = edge.node(1);
532 if (node0.uniqueId() > node1.uniqueId()) {
533 ++nb_error;
534 info() << "Error: bad orientation for edge '" << ItemPrinter(edge)
535 << " n0=" << node0.uniqueId() << " n1=" << node1.uniqueId();
536 }
537 }
538 }
539 if (nb_error != 0)
540 ARCANE_FATAL("Bad connectivity for '{0}' edges", nb_error);
541}
542
543/*---------------------------------------------------------------------------*/
544/*---------------------------------------------------------------------------*/
545
546void DynamicMeshChecker::
547_checkValidItemOwner(IItemFamily* family)
548{
549 // For non-sub-meshes, every sub-item
550 // (Node, Edge or Face) must have an adjacent cell with the same owner,
551 // unless orphan entities are allowed and the entity is not
552 // connected to any mesh.
553 // For sub-meshes, furthermore, every item must have the same owner
554 // as its parent.
555 bool allow_orphan_items = m_mesh->meshKind().isNonManifold();
556
557 Integer nerror = 0;
558 if (!m_mesh->parentMesh()) {
559
560 if (family->itemKind() == IK_Cell)
561 return; // implicitly valid for cells
562
563 ItemGroup own_items = family->allItems().own();
564 ENUMERATE_ITEM (iitem, own_items) {
565 Item item = *iitem;
566 Int32 owner = item.owner();
567 bool is_ok = false;
568 ItemVectorView cells = item.itemBase().cellList();
569 if (cells.size() == 0 && allow_orphan_items)
570 continue;
571 for (Item cell : cells) {
572 if (cell.owner() == owner) {
573 is_ok = true;
574 break;
575 }
576 }
577 if (!is_ok) {
578 OStringStream ostr;
579 Integer index = 0;
580 ostr() << " nb_cell=" << cells.size();
581 for (Item cell : cells) {
582 ostr() << " SubCell i=" << index << " cell=" << ItemPrinter(cell);
583 ++index;
584 }
585 error() << "Mesh " << m_mesh->name() << " family=" << family->name()
586 << " Item" << ItemPrinter(item) << " has no cell with same owner:"
587 << ostr.str();
588 ++nerror;
589 }
590 }
591 }
592 else {
593 ENUMERATE_ITEM (iitem, family->allItems()) {
594 Item item = *iitem;
595 Item parent_item = item.parent();
596 if (parent_item.owner() != item.owner()) {
597 error() << "Mesh " << m_mesh->name() << " : Inconsistent item/parent item owner : "
598 << ItemPrinter(item) << " / " << ItemPrinter(parent_item);
599 ++nerror;
600 }
601 }
602 }
603
604 if (nerror > 0)
605 ARCANE_FATAL("mesh {0} family={1} has {2}", m_mesh->name(), family->name(),
606 String::plural(nerror, "owner error"));
607}
608
609/*---------------------------------------------------------------------------*/
610/*---------------------------------------------------------------------------*/
611
612void DynamicMeshChecker::
613checkVariablesSynchronization()
614{
615 Int64 nb_diff = 0;
616 VariableCollection used_vars(m_mesh->variableMng()->usedVariables());
617 for (VariableCollection::Enumerator i_var(used_vars); ++i_var;) {
618 IVariable* var = *i_var;
619 switch (var->itemKind()) {
620 case IK_Node:
621 case IK_Edge:
622 case IK_Face:
623 case IK_Cell:
624 case IK_DoF:
625 nb_diff += var->checkIfSync(10);
626 break;
627 case IK_Particle:
628 case IK_Unknown:
629 break;
630 }
631 }
632 if (nb_diff != 0)
633 ARCANE_FATAL("Error in checkVariablesSynchronization() nb_diff=", nb_diff);
634}
635
636/*---------------------------------------------------------------------------*/
637/*---------------------------------------------------------------------------*/
638
639void DynamicMeshChecker::
640checkItemGroupsSynchronization()
641{
642 Int64 nb_diff = 0;
643 // TODO: iterate over all families (except particles)
644 ItemGroupsSynchronize node_sync(m_mesh->nodeFamily());
645 nb_diff += node_sync.checkSynchronize();
646 ItemGroupsSynchronize edge_sync(m_mesh->edgeFamily());
647 nb_diff += edge_sync.checkSynchronize();
648 ItemGroupsSynchronize face_sync(m_mesh->faceFamily());
649 nb_diff += face_sync.checkSynchronize();
650 ItemGroupsSynchronize cell_sync(m_mesh->cellFamily());
651 nb_diff += cell_sync.checkSynchronize();
652 if (nb_diff != 0)
653 ARCANE_FATAL("some groups are not synchronized nb_diff={0}", nb_diff);
654}
655
656/*---------------------------------------------------------------------------*/
657/*---------------------------------------------------------------------------*/
666void DynamicMeshChecker::
667checkGhostCells()
668{
669 pwarning() << "CHECK GHOST CELLS";
670 Integer sid = m_mesh->meshPartInfo().partRank();
671 ENUMERATE_CELL (icell, m_mesh->cellFamily()->allItems()) {
672 Cell cell = *icell;
673 if (cell.isOwn())
674 continue;
675 bool is_ok = false;
676 for (Node node : cell.nodes()) {
677 for (Cell cell2 : node.cells()) {
678 if (cell2.owner() == sid) {
679 is_ok = true;
680 }
681 }
682 }
683 if (!is_ok)
684 info() << "WARNING: Cell " << ItemPrinter(cell) << " should not be a ghost cell";
685 }
686}
687
688/*---------------------------------------------------------------------------*/
689/*---------------------------------------------------------------------------*/
690
691void DynamicMeshChecker::
692checkMeshFromReferenceFile()
693{
694 if (!m_compare_reference_file)
695 return;
696
697 IParallelMng* pm = m_mesh->parallelMng();
698
699 if (!pm->isParallel())
700 return; // only in parallel
701
702 debug() << "Testing the mesh against the initial mesh";
703 String base_file_name("meshconnectivity");
704 // In parallel, compare the current mesh with the file
705 // containing the full connectivity (sequential case)
706 IIOMng* io_mng = pm->ioMng();
707 ScopedPtrT<IXmlDocumentHolder> xml_doc(io_mng->parseXmlFile(base_file_name));
708 if (xml_doc.get()) {
709 XmlNode doc_node = xml_doc->documentNode();
710 if (!doc_node.null())
711 mesh_utils::checkMeshConnectivity(m_mesh, doc_node, true);
712 }
713 else {
714 warning() << "Can't test the subdomain coherence "
715 << "against the initial mesh";
716 }
717}
718
719/*---------------------------------------------------------------------------*/
720/*---------------------------------------------------------------------------*/
721
722void DynamicMeshChecker::
723checkValidReplication()
724{
725 info() << "Checking valid replication";
726 IParallelMng* mesh_pm = m_mesh->parallelMng();
727 IParallelReplication* pr = mesh_pm->replication();
728 if (!pr->hasReplication())
729 return;
730
732
733 // Checks that all families (except particles) are the same
734 UniqueArray<IItemFamily*> wanted_same_family;
735
736 for (IItemFamilyCollection::Enumerator i(m_mesh->itemFamilies()); ++i;) {
737 IItemFamily* family = *i;
738 if (family->itemKind() != IK_Particle)
739 wanted_same_family.add(family);
740 }
741 ValueChecker vc(A_FUNCINFO);
742
743 // Checks that everyone has the same number of families.
744 Integer nb_family = wanted_same_family.size();
745 Integer max_nb_family = pm->reduce(Parallel::ReduceMax, nb_family);
746 vc.areEqual(nb_family, max_nb_family, "Bad number of family");
747
748 // Checks that all families have the same number of elements.
749 //TODO: it should also check that the family names match.
750 {
751 UniqueArray<Int32> families_size(nb_family);
752 for (Integer i = 0; i < nb_family; ++i)
753 families_size[i] = wanted_same_family[i]->nbItem();
754 UniqueArray<Int32> global_families_size(families_size);
755 pm->reduce(Parallel::ReduceMax, global_families_size.view());
756 vc.areEqualArray(global_families_size, families_size, "Bad family");
757 }
758
759 // Checks that all families have the same entities (same uniqueId())
760 {
761 UniqueArray<Int64> unique_ids;
762 UniqueArray<Int64> global_unique_ids;
763 for (Integer i = 0; i < nb_family; ++i) {
764 ItemGroup group = wanted_same_family[i]->allItems();
765 unique_ids.resize(group.size());
766 Integer index = 0;
767 ENUMERATE_ITEM (iitem, group) {
768 unique_ids[index] = iitem->uniqueId();
769 ++index;
770 }
771 global_unique_ids.resize(group.size());
772 global_unique_ids.copy(unique_ids);
773 pm->reduce(Parallel::ReduceMax, global_unique_ids.view());
774 String message = String::format("Bad unique ids for family '{0}'",
775 wanted_same_family[i]->name());
776 vc.areEqualArray(global_unique_ids, unique_ids, message);
777 }
778 }
779}
780
781/*---------------------------------------------------------------------------*/
782/*---------------------------------------------------------------------------*/
783
784void DynamicMeshChecker::
785_checkReplicationFamily(IItemFamily*)
786{
787}
788
789/*---------------------------------------------------------------------------*/
790/*---------------------------------------------------------------------------*/
791
792} // End namespace Arcane::mesh
793
794/*---------------------------------------------------------------------------*/
795/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_FACE(name, group)
Enumérateur générique d'un groupe de faces.
#define ENUMERATE_(type, name, group)
Enumérateur générique d'un groupe d'entité
#define ENUMERATE_CELL(name, group)
Enumérateur générique d'un groupe de mailles.
#define ENUMERATE_EDGE(name, group)
Enumérateur générique d'un groupe d'arêtes.
#define ENUMERATE_ITEM(name, group)
Enumérateur générique d'un groupe de noeuds.
#define ENUMERATE_NODE(name, group)
Enumérateur générique d'un groupe de noeuds.
Fonctions utilitaires sur le maillage.
void checkMeshProperties(IMesh *mesh, bool is_sorted, bool has_no_hole, bool check_faces)
Vérifie que le maillage possède certaines propriétés.
Integer size() const
Nombre d'éléments du vecteur.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void copy(Span< const T > rhs)
Copie les valeurs de rhs dans l'instance.
ArrayView< T > view() const
Vue mutable sur ce tableau.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Maille d'un maillage.
Definition Item.h:1214
Face face(Int32 i) const
i-ème face de la maille
Definition Item.h:1295
Int32 nbFace() const
Nombre de faces de la maille.
Definition Item.h:1292
Int32 level() const
Definition Item.h:1368
Vue constante d'un tableau de type T.
Arête d'une maille.
Definition Item.h:826
CellConnectedListViewType cells() const
Liste des mailles de l'arête.
Definition Item.h:916
Int32 nbNode() const
Nombre de sommets de l'arête.
Definition Item.h:904
Cette fonction/classe réoriente les faces.
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
CellConnectedListViewType cells() const
Liste des mailles de la face.
Definition Item.h:1048
Cell backCell() const
Maille derrière la face (maille nulle si aucune).
Definition Item.h:1646
Interface du gestionnaire des entrées sorties.
Definition IIOMng.h:36
virtual IXmlDocumentHolder * parseXmlFile(const String &filename, const String &schemaname=String{})=0
Lit et analyse le fichier XML filename.
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual ItemGroup allItems() const =0
Groupe de toutes les entités.
virtual void checkValid()=0
Vérification de la validité des structures internes (interne).
virtual String name() const =0
Nom de la famille.
virtual IItemFamily * parentFamily() const =0
IItemFamily parent.
virtual eItemKind itemKind() const =0
Genre des entités.
virtual void checkValidConnectivity()=0
Vérification de la validité des structures internes concernant la connectivité.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual IParallelReplication * replication() const =0
Informations sur la réplication.
virtual IIOMng * ioMng() const =0
Gestionnaire des entrées/sorties.
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.
Informations sur la réplication des sous-domaines en parallèle.
virtual bool hasReplication() const =0
Indique si la réplication est active.
virtual IParallelMng * replicaParallelMng() const =0
Communicateur associé à tous les réplicats représentant un même sous-domaine.
Interface d'une variable.
Definition IVariable.h:39
virtual String itemFamilyName() const =0
Nom de la famille associée (nul si aucune).
virtual eItemKind itemKind() const =0
Genre des entités du maillage sur lequel repose la variable.
virtual Int32 checkIfSync(Integer max_print=0)=0
Vérifie si la variable est bien synchronisée.
virtual IItemFamily * itemFamily() const =0
Famille d'entité associée.
virtual String itemGroupName() const =0
Nom du groupe d'entité associée.
bool isSuppressed() const
Vrai si l'entité est supprimée.
Groupe d'entités de maillage.
Definition ItemGroup.h:49
const String & name() const
Nom du groupe.
Definition ItemGroup.h:76
Integer size() const
Nombre d'éléments du groupe.
Definition ItemGroup.h:88
IItemFamily * itemFamily() const
Famille d'entité à laquelle appartient ce groupe (0 pour le group nul).
Definition ItemGroup.h:123
ItemGroup own() const
Groupe équivalent à celui-ci mais contenant uniquement les éléments propres au sous-domaine.
Definition ItemGroup.cc:190
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:34
static ItemTypeId fromInteger(Int64 v)
Créé une instance à partir d'un entier.
Informations locales sur une face d'une maille.
Integer node(Integer i) const
Indice locale dans la maille du i-ème noeud de la face.
Integer typeId() const
Type de l'entité face.
Integer nbNode() const
Nombre de noeuds de la face.
Infos sur un type d'entité du maillage.
Gestionnaire des types d'entités d'un maillage.
Definition ItemTypeMng.h:65
Variable scalaire sur un type d'entité du maillage.
Vue sur un vecteur d'entités.
Int32 size() const
Nombre d'éléments du vecteur.
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
const ItemTypeInfo * typeInfo() const
Infos sur le type de l'entité.
Definition Item.h:392
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
constexpr bool isOwn() const
true si l'entité est appartient au sous-domaine
Definition Item.h:253
Item parent(Int32 i) const
i-ème parent pour les sous-maillages
Definition Item.h:286
impl::ItemBase itemBase() const
Partie interne de l'entité.
Definition Item.h:369
Int16 type() const
Type de l'entité
Definition Item.h:241
GroupType itemGroup() const
Groupe associé à la grandeur.
Noeud d'un maillage.
Definition Item.h:582
CellConnectedListViewType cells() const
Liste des mailles du noeud.
Definition Item.h:692
Classe utilitaire pour réordonner les noeuds d'une entité.
Encapsulation d'un pointeur qui se détruit automatiquement.
Definition ScopedPtr.h:44
Chaîne de caractères unicode.
static String plural(const Integer n, const String &str, const bool with_number=true)
Forme standard du pluriel par ajout d'un 's'.
Definition String.cc:1041
Paramètres nécessaires à la construction d'une variable temporaire.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage error() const
Flot pour un message d'erreur.
TraceMessage warning() const
Flot pour un message d'avertissement.
TraceMessage pwarning() const
Vecteur 1D de données avec sémantique par valeur (style STL).
Vérification de la validité de certaines valeurs.
void areEqual(const T1 &value, const T2 &expected_value, const String &message)
void areEqualArray(const T1 &x_values, const T2 &x_expected_values, const String &message)
Vérifie que les deux tableaux values et expected_values ont les mêmes valeurs.
Paramètres nécessaires à la construction d'une variable.
Collection de variables.
virtual Integer checkIfSync(int max_print=0)
Vérifie si la variable est bien synchronisée.
IVariable * variable() const
Variable associée.
Noeud d'un arbre DOM.
Definition XmlNode.h:51
bool null() const
Vrai si le noeud est nul.
Definition XmlNode.h:294
void checkValidMeshFull() override
Vérification de la validité du maillage.
void _checkEdgesOrientation()
Checks that edges are correctly numbered.
void _checkFacesOrientation()
Checks that faces are correctly oriented and connected.
Information to synchronize groups between sub-domains.
Integer checkSynchronize()
Checks if the groups are synchronized.
ItemGroupT< Cell > CellGroup
Groupe de mailles.
Definition ItemTypes.h:183
MeshVariableArrayRefT< Cell, Int64 > VariableCellArrayInt64
Grandeur au centre des mailles de type tableau d'entiers.
MeshVariableScalarRefT< Face, Int64 > VariableFaceInt64
Grandeur aux faces de type entier 64 bits.
@ ReduceMax
Maximum des valeurs.
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.
Collection< IItemFamily * > IItemFamilyCollection
Collection de familles d'entités.
eItemKind
Genre d'entité de maillage.
@ IK_Particle
Entité de maillage de genre particule.
@ IK_Node
Entité de maillage de genre noeud.
@ IK_Cell
Entité de maillage de genre maille.
@ IK_Unknown
Entité de maillage de genre inconnu ou non initialisé
@ IK_Face
Entité de maillage de genre face.
@ IK_DoF
Entité de maillage de genre degre de liberte.
@ IK_Edge
Entité de maillage de genre arête.
UniqueArray< Integer > IntegerUniqueArray
Tableau dynamique à une dimension d'entiers.
Definition UtilsTypes.h:347
std::int32_t Int32
Type entier signé sur 32 bits.