Arcane  v4.1.0.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-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* DynamicMeshChecker.cc (C) 2000-2025 */
9/* */
10/* Classe fournissant des méthodes de vérification sur le maillage. */
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/*---------------------------------------------------------------------------*/
74void DynamicMeshChecker::
75checkValidMesh()
76{
77 info(4) << "Check mesh coherence.";
79
80 for( IItemFamilyCollection::Enumerator i(m_mesh->itemFamilies()); ++i; ){
81 IItemFamily* family = *i;
82 //GG: regarder pourquoi il y a ce test.
83 if (family->itemKind()>=NB_ITEM_KIND)
84 continue;
85 family->checkValid();
86 }
87 mesh_utils::checkMeshProperties(m_mesh,false,false,true);
88
89 // Sauve dans une variable aux mailles la liste des faces et
90 // noeuds qui la composent.
91 // Ceci n'est utile que pour des vérifications
92 // NOTE: pour l'instant mis a false car fait planter si utilise
93 // partitionnement initial dans Arcane
94 const bool global_check = false;
95 if (m_check_level>=1 && global_check){
96 if (!m_var_cells_faces)
97 m_var_cells_faces = new VariableCellArrayInt64(VariableBuildInfo(m_mesh,"MeshTestCellFaces"));
98
99 if (!m_var_cells_nodes)
100 m_var_cells_nodes = new VariableCellArrayInt64(VariableBuildInfo(m_mesh,"MeshTestCellNodes"));
101
102 CellGroup all_cells(m_mesh->allCells());
103 Integer max_nb_face = 0;
104 Integer max_nb_node = 0;
105 ENUMERATE_CELL(i,all_cells){
106 Cell cell = *i;
107 Integer nb_face = cell.nbFace();
108 Integer nb_node = cell.nbNode();
109 if (nb_face>max_nb_face)
110 max_nb_face = nb_face;
111 if (nb_node>max_nb_node)
112 max_nb_node = nb_node;
113 }
114 m_var_cells_faces->resize(max_nb_face);
115 m_var_cells_nodes->resize(max_nb_node);
116 ENUMERATE_CELL(i,all_cells){
117 Cell cell = *i;
118 Integer nb_face = cell.nbFace();
119 for( Integer z=0; z<nb_face; ++z )
120 (*m_var_cells_faces)[cell][z] = cell.face(z).uniqueId().asInt64();
121 Integer nb_node = cell.nbNode();
122 for( Integer z=0; z<nb_node; ++z )
123 (*m_var_cells_nodes)[cell][z] = cell.node(z).uniqueId().asInt64();
124 }
125 }
127}
128
129/*---------------------------------------------------------------------------*/
130/*---------------------------------------------------------------------------*/
131
132void DynamicMeshChecker::
133checkValidMeshFull()
134{
135 String func_name("DynamicMesh::checkValidMeshFull");
136 info() << func_name << " on " << m_mesh->name();
137 Integer nb_error = 0;
138 VariableFaceInt64 var_faces(VariableBuildInfo(m_mesh,"MeshCheckFaces"));
139 debug() << " VAR_FACE GROUP=" << var_faces.variable()->itemFamily()
140 << " NAME=" << var_faces.itemGroup().name()
141 << " FAMILY_NAME=" << var_faces.variable()->itemFamilyName()
142 << " GROUP_NAME=" << var_faces.variable()->itemGroupName();
143 ENUMERATE_FACE(iface,m_mesh->allFaces()){
144 Face face = *iface;
145 Cell c = face.backCell();
146 Int64 uid = c.null() ? NULL_ITEM_UNIQUE_ID : c.uniqueId();
147 var_faces[face] = uid;
148 }
149 var_faces.synchronize();
150 ENUMERATE_FACE(iface,m_mesh->allFaces()){
151 Face face = *iface;
152 Cell c = face.backCell();
153 Int64 uid = c.null() ? NULL_ITEM_UNIQUE_ID : c.uniqueId();
154 if (uid!=var_faces[face] && uid!=NULL_ITEM_ID && var_faces[face]!=NULL_ITEM_ID){
155 error() << func_name << " bad back cell in face uid=" << face.uniqueId();
156 ++nb_error;
157 }
158 }
159
160 ENUMERATE_FACE(iface,m_mesh->allFaces()){
161 Face face = *iface;
162 Cell c = face.frontCell();
163 Int64 uid = c.null() ? NULL_ITEM_UNIQUE_ID : c.uniqueId();
164 var_faces[face] = uid;
165 }
166 var_faces.synchronize();
167 ENUMERATE_FACE(iface,m_mesh->allFaces()){
168 Face face = *iface;
169 Cell c = face.frontCell();
170 Int64 uid = c.null() ? NULL_ITEM_UNIQUE_ID : c.uniqueId();
171 if (uid!=var_faces[face] && uid!=NULL_ITEM_ID && var_faces[face]!=NULL_ITEM_ID){
172 error() << func_name << " bad front cell in face uid=" << face.uniqueId();
173 ++nb_error;
174 }
175 }
176
177 ENUMERATE_CELL(icell,m_mesh->allCells()){
178 Cell cell = *icell;
179 Integer cell_type = cell.type();
180 if (cell_type == IT_Line2) {
181 error() << func_name << " bad cell type in face uid=" << cell.uniqueId();
182 ++nb_error;
183 }
184 }
185
186 ENUMERATE_FACE(iface,m_mesh->allFaces()){
187 Face face = *iface;
188 Integer face_type = face.type();
189 if (face_type == IT_Vertex) {
190 error() << func_name << " bad face type in face uid=" << face.uniqueId();
191 ++nb_error;
192 }
193 }
194
195 if (nb_error!=0)
196 ARCANE_FATAL("Invalid mesh");
197}
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201/*
202 * \brief Vérifie que la connectivité est valide.
203 *
204 * Les vérifications portent sur les points suivants:
205 * - pas d'entités du maillage ayant un indice nul.
206 * - pour les faces, vérifie qu'il existe au moins une frontCell ou une
207 * backCell. De plus, si elle a deux mailles, la backCell doit
208 * toujours être la première.
209 * - les noeuds et les faces doivent avoir le même propriétaire
210 * qu'une des mailles attenante.
211 * - vérifie que les faces sont bien ordonnées et orientées
212 */
213void DynamicMeshChecker::
214checkValidConnectivity()
215{
216 String func_name = "MeshChecker::checkValidConnectivity";
217 debug() << func_name << " check";
218
219 // Appelle la méthode de vérification de chaque famille.
220 IItemFamilyCollection item_families = m_mesh->itemFamilies();
221 for( auto x = item_families.enumerator(); ++x; ){
222 IItemFamily* f = *x;
224 }
225
226 if (!m_mesh->parentMesh()){
227 Integer index = 0;
228 ENUMERATE_(Face,i,m_mesh->allFaces()){
229 Face elem = *i;
230 Cell front_cell = elem.frontCell();
231 Cell back_cell = elem.backCell();
232 if (front_cell.null() && back_cell.null())
233 ARCANE_FATAL("Local face '{0}' has two null cell face=",index,ItemPrinter(elem));
234 index++;
235 }
236 }
237
238 // Vérifie que la connective maille<->noeud
239 // est réciproque
240 ENUMERATE_NODE(inode,m_mesh->allNodes()){
241 Node node = *inode;
242 for( Cell cell : node.cells() ){
243 bool has_found = false;
244 for( Node node2 : cell.nodes() ){
245 if (node2==node){
246 has_found = true;
247 break;
248 }
249 }
250 if (!has_found){
251 ARCANE_FATAL("Node uid={0} is connected to the cell uid={1} but the cell"
252 " is not connected to this node.",ItemPrinter(node),ItemPrinter(cell));
253 }
254 }
255 }
256
257 // ATT: les verifications suivantes ne sont pas compatible avec l'AMR
258 // TODO : etendre les verifs au cas AMR
260 if(!m_mesh->isAmrActivated()){
261 // Vérifie que la connective maille<->arêtes
262 // est réciproque
263 ENUMERATE_EDGE(iedge,m_mesh->allEdges()){
264 Edge edge = *iedge;
265 for( Cell cell : edge.cells() ){
266 bool has_found = false;
267 for( Edge edge2 : cell.edges() ){
268 if (edge2==edge){
269 has_found = true;
270 break;
271 }
272 }
273 if (!has_found){
274 ARCANE_FATAL("Edge uid={0} is connected to the cell uid={1} but the cell"
275 " is not connected to this edge.",ItemPrinter(edge),ItemPrinter(cell));
276 }
277 }
278 }
279 }
280 // Vérifie que la connective maille<->face
281 // est réciproque
282 ENUMERATE_FACE(iface,m_mesh->allFaces()){
283 Face face = *iface;
284 if(!m_mesh->isAmrActivated()){
285 for( Cell cell : face.cells() ){
286 bool has_found = false;
287 for( Face face2 : cell.faces() ){
288 if (face2==face){
289 has_found = true;
290 break;
291 }
292 }
293 if (!has_found){
294 ARCANE_FATAL("Face uid={0} is connected to the cell uid={1} but the cell"
295 " is not connected to this face.",ItemPrinter(face),ItemPrinter(cell));
296 }
297 }
298 }
299 for( Cell cell : face.cells() ){
300 bool has_found = false;
301 for( Face face2 : cell.faces() ){
302 if (face2==face){
303 has_found = true;
304 break;
305 }
306 }
307 if (!has_found && (face.backCell().level() == face.frontCell().level())){
308 warning() << func_name << ". The face " << FullItemPrinter(face)
309 << " is connected to the cell " << FullItemPrinter(cell)
310 << " but the cell (level "<< cell.level()<< ")"
311 << " is not connected to the face.";
312 }
313 }
314
315 Integer nb_cell = face.nbCell();
316 Cell back_cell = face.backCell();
317 Cell front_cell = face.frontCell();
318 if ((back_cell.null() || front_cell.null()) && nb_cell==2)
319 ARCANE_FATAL("Face uid='{0}' bad number of cells face",ItemPrinter(face));
320 // Si on a deux mailles connectées, alors la back cell doit être la première
321 if (nb_cell==2 && back_cell!=face.cell(0))
322 ARCANE_FATAL("Bad face face.backCell()!=face.cell(0) face={0} back_cell={1} from_cell={2} cell0={3}",
323 ItemPrinter(face),ItemPrinter(back_cell),ItemPrinter(front_cell),ItemPrinter(face.cell(0)));
324 }
325
328
329 if (m_mesh->parentMesh()){
330 Integer nerror = 0;
331 eItemKind kinds[] = { IK_Node, IK_Edge, IK_Face, IK_Cell };
332 Integer nb_kind = sizeof(kinds)/sizeof(eItemKind);
333
334 for(Integer i_kind=0;i_kind<nb_kind;++i_kind){
335 const eItemKind kind = kinds[i_kind];
336 IItemFamily * family = m_mesh->itemFamily(kind);
337 if (!family->parentFamily()){
338 error() << "Mesh " << m_mesh->name() << " : Family " << kind << " does not exist in mesh";
339 ++nerror;
340 }
341 else{
342 ENUMERATE_ITEM(iitem,family->allItems()){
343 const Item & item = *iitem;
344 const Item & parent_item = item.parent();
345 if (parent_item.itemBase().isSuppressed()){
346 error() << "Mesh " << m_mesh->name() << " : Inconsistent suppresssed parent item uid : "
347 << ItemPrinter(item) << " / " << ItemPrinter(parent_item);
348 ++nerror;
349 }
350 if (parent_item.uniqueId() != item.uniqueId()){
351 error() << "Mesh " << m_mesh->name() << " : Inconsistent item/parent item uid : " << ItemPrinter(item);
352 ++nerror;
353 }
354 }
355 }
356 }
357 if (nerror > 0)
358 ARCANE_FATAL("Mesh name={0} has {1} (see above)",m_mesh->name(),String::plural(nerror, "error"));
359
360 // Vérifie la consistence parallèle du groupe parent
361 nerror = 0;
362 {
363 ItemGroup parent_group = m_mesh->parentGroup();
364 String var_name = String::format("SubMesh_{0}_GroupConsistencyChecker",parent_group.name());
365 TemporaryVariableBuildInfo tvbi(m_mesh->parentMesh(),var_name,parent_group.itemFamily()->name());
366 ItemVariableScalarRefT<Integer> var(tvbi,m_mesh->parentGroup().itemKind());
367 var.fill(-1);
368 ENUMERATE_ITEM(iitem, m_mesh->parentGroup()){
369 var[iitem] = iitem->owner();
370 }
371 nerror += var.checkIfSync(10);
372 }
373 if (nerror > 0)
374 ARCANE_FATAL("Mesh name={0} has parent group consistency {1}\n"
375 "This usually means that parent group was not symmetrically built",
376 m_mesh->name(),String::plural(nerror, "error", false));
377 }
378
379 if (m_is_check_items_owner){
380 _checkValidItemOwner(m_mesh->nodeFamily());
381 _checkValidItemOwner(m_mesh->edgeFamily());
382 _checkValidItemOwner(m_mesh->faceFamily());
383 _checkValidItemOwner(m_mesh->cellFamily());
384 }
385}
386
387/*---------------------------------------------------------------------------*/
388/*---------------------------------------------------------------------------*/
389
390void DynamicMeshChecker::
391updateAMRFaceOrientation()
392{
393 String func_name = "MeshChecker::updateAMRFaceOrientation";
394 FaceReorienter fr(m_mesh);
395 ENUMERATE_FACE(iface,m_mesh->allFaces()){
396 Face face = *iface;
397 Integer nb_cell = face.nbCell();
398 Cell back_cell = face.backCell();
399 Cell front_cell = face.frontCell();
400 if ((back_cell.null() || front_cell.null()) && nb_cell==2)
401 ARCANE_FATAL("Bad number of cells for face={0}",ItemPrinter(face));
402 // Si on a deux mailles connectées, alors la back cell doit être la première
403 if (nb_cell==2 && back_cell!=face.cell(0))
404 ARCANE_FATAL("Bad face face.backCell()!=face.cell(0) face={0} back_cell={1} from_cell={2} cell0={3}",
405 ItemPrinter(face),ItemPrinter(back_cell),ItemPrinter(front_cell),ItemPrinter(face.cell(0)));
406
407 // Ceci pourrait sans doutes etre optimise
408 fr.checkAndChangeOrientationAMR(face);
409 }
410}
411
412/*---------------------------------------------------------------------------*/
413/*---------------------------------------------------------------------------*/
414
415void DynamicMeshChecker::
416updateAMRFaceOrientation(ArrayView<Int64> ghost_cell_to_refine)
417{
418 ItemInternalList cells = m_mesh->itemsInternal(IK_Cell) ;
419 UniqueArray<Integer> lids(ghost_cell_to_refine.size()) ;
420 m_mesh->cellFamily()->itemsUniqueIdToLocalId(lids,ghost_cell_to_refine,true) ;
421 FaceReorienter fr(m_mesh);
422 std::set<Int64> set ;
423 typedef std::pair<std::set<Int64>::iterator,bool> return_type ;
424 for(Integer i=0, n=lids.size();i<n;++i){
425 Cell icell = cells[lids[i]] ;
426 for( Integer ic=0, nchild=icell.nbHChildren();ic<nchild;++ic){
427 Cell child = icell.hChild(ic) ;
428 for( Face face : child.faces() ){
429 return_type value = set.insert(face.uniqueId());
430 if(value.second){
431 fr.checkAndChangeOrientationAMR(face);
432 }
433 }
434 }
435 }
436}
437
438/*---------------------------------------------------------------------------*/
439/*---------------------------------------------------------------------------*/
443void DynamicMeshChecker::
444_checkFacesOrientation()
445{
446 bool is_1d = (m_mesh->dimension()==1);
447 //Temporaire: pour l'instant, ne teste pas l'orientation en 1D.
448 if (is_1d)
449 return;
450
451 String func_name = "MeshChecker::_checkFacesOrientation";
452
453 Int64UniqueArray work_face_sorted_nodes;
454 IntegerUniqueArray work_face_nodes_index;
455 Int64UniqueArray work_face_orig_nodes_uid;
456 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
457 NodesOfItemReorderer face_reorderer(item_type_mng);
458 ENUMERATE_(Cell,icell,m_mesh->allCells()){
459 Cell cell = *icell;
460 const ItemTypeInfo* type = cell.typeInfo();
461 Int32 cell_nb_face = type->nbLocalFace();
462 for( Integer i_face=0; i_face<cell_nb_face; ++i_face ){
463 const ItemTypeInfo::LocalFace& lf = type->localFace(i_face);
464 Integer face_nb_node = lf.nbNode();
465
466 work_face_orig_nodes_uid.resize(face_nb_node);
467 for( Integer z=0; z<face_nb_node; ++z )
468 work_face_orig_nodes_uid[z] = cell.node(lf.node(z)).uniqueId();
469
470 bool is_reorder = false;
471 if (is_1d){
472 is_reorder = face_reorderer.reorder1D(i_face, work_face_orig_nodes_uid[0]);
473 }
474 else
475 is_reorder = face_reorderer.reorder(ItemTypeId::fromInteger(lf.typeId()), work_face_orig_nodes_uid);
476 ConstArrayView<Int64> face_sorted_nodes(face_reorderer.sortedNodes());
477
478 Face cell_face = cell.face(i_face);
479 if (cell_face.nbNode()!=face_nb_node)
480 ARCANE_FATAL("Incoherent number of node for 'face' and 'localFace'"
481 " cell={0} face={1} nb_local_node={2} nb_face_node={3}",
482 ItemPrinter(cell),ItemPrinter(cell_face),face_nb_node,cell_face.nbNode());
483
484 for( Integer z=0; z<face_nb_node; ++z ){
485 if (cell_face.node(z).uniqueId()!=face_sorted_nodes[z])
486 ARCANE_FATAL("Bad node unique id for face: cell={0} face={1} cell_node_uid={2} face_node_uid={3} z={4}",
487 ItemPrinter(cell),ItemPrinter(cell_face),face_sorted_nodes[z],
488 cell_face.node(z).uniqueId());
489 }
490 if (is_reorder){
491 Cell front_cell = cell_face.frontCell();
492 if (front_cell!=cell){
493 if (!front_cell.null())
494 ARCANE_FATAL("Bad orientation for face. Should be front cell: cell={0} face={1} front_cell={2}",
495 ItemPrinter(cell),ItemPrinter(cell_face),ItemPrinter(front_cell));
496 else
497 ARCANE_FATAL("Bad orientation for face. Should be front cell (no front cell) cell={0} face={1}",
498 ItemPrinter(cell),ItemPrinter(cell_face));
499 }
500 }
501 else{
502 Cell back_cell = cell_face.backCell();
503 if (back_cell!=cell){
504 if (!back_cell.null())
505 ARCANE_FATAL("Bad orientation for face. Should be back cell: cell={0} face={1} front_cell={2}",
506 ItemPrinter(cell),ItemPrinter(cell_face),ItemPrinter(back_cell));
507 else
508 ARCANE_FATAL("Bad orientation for face. Should be back cell (no back cell) cell={0} face={1}",
509 ItemPrinter(cell),ItemPrinter(cell_face));
510 }
511 }
512 }
513 }
514}
515
516/*---------------------------------------------------------------------------*/
517/*---------------------------------------------------------------------------*/
521void DynamicMeshChecker::
522_checkEdgesOrientation()
523{
524 // Pour les arêtes, vérifie que le uniqueId() du premier noeud est
525 // inférieur à celui du deuxième.
526 Int32 nb_error = 0;
527 ENUMERATE_ (Edge, iedge, m_mesh->allEdges()) {
528 Edge edge = *iedge;
529 Int32 nb_node = edge.nbNode();
530 if (nb_node >= 2) {
531 Node node0 = edge.node(0);
532 Node node1 = edge.node(1);
533 if (node0.uniqueId() > node1.uniqueId()) {
534 ++nb_error;
535 info() << "Error: bad orientation for edge '" << ItemPrinter(edge)
536 << " n0=" << node0.uniqueId() << " n1=" << node1.uniqueId();
537 }
538 }
539 }
540 if (nb_error != 0)
541 ARCANE_FATAL("Bad connectivity for '{0}' edges", nb_error);
542}
543
544/*---------------------------------------------------------------------------*/
545/*---------------------------------------------------------------------------*/
546
547void DynamicMeshChecker::
548_checkValidItemOwner(IItemFamily* family)
549{
550 // Pour les maillages non sous-maillages, il faut que tout sub-item
551 // (Node, Edge ou Face) ait une cellule voisine de même propriétaire,
552 // sauf si on autorise les entités orphelines et que l'entité n'est
553 // connectée à aucune maille.
554 // Pour les sous-maillages, il faut, en plus, que tout item soit de
555 // même propriétaire que son parent.
556 bool allow_orphan_items = m_mesh->meshKind().isNonManifold();
557
558 Integer nerror = 0;
559 if (!m_mesh->parentMesh()){
560
561 if (family->itemKind() == IK_Cell)
562 return; // implicitement valide pour les cellules
563
564 ItemGroup own_items = family->allItems().own();
565 ENUMERATE_ITEM(iitem,own_items){
566 Item item = *iitem;
567 Int32 owner = item.owner();
568 bool is_ok = false;
569 ItemVectorView cells = item.itemBase().cellList();
570 if (cells.size()==0 && allow_orphan_items)
571 continue;
572 for( Item cell : cells ){
573 if (cell.owner()==owner){
574 is_ok = true;
575 break;
576 }
577 }
578 if (!is_ok) {
579 OStringStream ostr;
580 Integer index = 0;
581 ostr() << " nb_cell=" << cells.size();
582 for( Item cell : cells ){
583 ostr() << " SubCell i=" << index << " cell=" << ItemPrinter(cell);
584 ++index;
585 }
586 error() << "Mesh " << m_mesh->name() << " family=" << family->name()
587 << " Item" << ItemPrinter(item) << " has no cell with same owner:"
588 << ostr.str();
589 ++nerror;
590 }
591 }
592 }
593 else {
594 ENUMERATE_ITEM(iitem,family->allItems()){
595 Item item = *iitem;
596 Item parent_item = item.parent();
597 if (parent_item.owner() != item.owner()) {
598 error() << "Mesh " << m_mesh->name() << " : Inconsistent item/parent item owner : "
599 << ItemPrinter(item) << " / " << ItemPrinter(parent_item);
600 ++nerror;
601 }
602 }
603 }
604
605 if (nerror>0)
606 ARCANE_FATAL("mesh {0} family={1} has {2}",m_mesh->name(),family->name(),
607 String::plural(nerror,"owner error"));
608}
609
610/*---------------------------------------------------------------------------*/
611/*---------------------------------------------------------------------------*/
612
613void DynamicMeshChecker::
614checkVariablesSynchronization()
615{
616 Int64 nb_diff = 0;
617 VariableCollection used_vars(m_mesh->variableMng()->usedVariables());
618 for( VariableCollection::Enumerator i_var(used_vars); ++i_var; ){
619 IVariable* var = *i_var;
620 switch (var->itemKind()){
621 case IK_Node:
622 case IK_Edge:
623 case IK_Face:
624 case IK_Cell:
625 case IK_DoF:
626 nb_diff += var->checkIfSync(10);
627 break;
628 case IK_Particle:
629 case IK_Unknown:
630 break;
631 }
632 }
633 if (nb_diff!=0)
634 ARCANE_FATAL("Error in checkVariablesSynchronization() nb_diff=",nb_diff);
635}
636
637/*---------------------------------------------------------------------------*/
638/*---------------------------------------------------------------------------*/
639
640void DynamicMeshChecker::
641checkItemGroupsSynchronization()
642{
643 Int64 nb_diff = 0;
644 // TODO: parcourir toutes les familles (sauf particules)
645 ItemGroupsSynchronize node_sync(m_mesh->nodeFamily());
646 nb_diff += node_sync.checkSynchronize();
647 ItemGroupsSynchronize edge_sync(m_mesh->edgeFamily());
648 nb_diff += edge_sync.checkSynchronize();
649 ItemGroupsSynchronize face_sync(m_mesh->faceFamily());
650 nb_diff += face_sync.checkSynchronize();
651 ItemGroupsSynchronize cell_sync(m_mesh->cellFamily());
652 nb_diff += cell_sync.checkSynchronize();
653 if (nb_diff!=0)
654 ARCANE_FATAL("some groups are not synchronized nb_diff={0}",nb_diff);
655}
656
657/*---------------------------------------------------------------------------*/
658/*---------------------------------------------------------------------------*/
668void DynamicMeshChecker::
669checkGhostCells()
670{
671 pwarning() << "CHECK GHOST CELLS";
672 Integer sid = m_mesh->meshPartInfo().partRank();
673 ENUMERATE_CELL (icell, m_mesh->cellFamily()->allItems()) {
674 Cell cell = *icell;
675 if (cell.isOwn())
676 continue;
677 bool is_ok = false;
678 for (Node node : cell.nodes()) {
679 for (Cell cell2 : node.cells()) {
680 if (cell2.owner() == sid) {
681 is_ok = true;
682 }
683 }
684 }
685 if (!is_ok)
686 info() << "WARNING: Cell " << ItemPrinter(cell) << " should not be a ghost cell";
687 }
688}
689
690/*---------------------------------------------------------------------------*/
691/*---------------------------------------------------------------------------*/
692
693void DynamicMeshChecker::
694checkMeshFromReferenceFile()
695{
696 if (!m_compare_reference_file)
697 return;
698
699 IParallelMng* pm = m_mesh->parallelMng();
700
701 if (!pm->isParallel())
702 return; // uniquement en parallèle
703
704 debug() << "Testing the mesh against the initial mesh";
705 String base_file_name("meshconnectivity");
706 // En parallèle, compare le maillage actuel avec le fichier
707 // contenant la connectivité complète (cas séquentiel)
708 IIOMng* io_mng = pm->ioMng();
709 ScopedPtrT<IXmlDocumentHolder> xml_doc(io_mng->parseXmlFile(base_file_name));
710 if (xml_doc.get()){
711 XmlNode doc_node = xml_doc->documentNode();
712 if (!doc_node.null())
713 mesh_utils::checkMeshConnectivity(m_mesh,doc_node,true);
714 }
715 else{
716 warning() << "Can't test the subdomain coherence "
717 << "against the initial mesh";
718 }
719}
720
721/*---------------------------------------------------------------------------*/
722/*---------------------------------------------------------------------------*/
723
724void DynamicMeshChecker::
725checkValidReplication()
726{
727 info() << "Checking valid replication";
728 IParallelMng* mesh_pm = m_mesh->parallelMng();
729 IParallelReplication* pr = mesh_pm->replication();
730 if (!pr->hasReplication())
731 return;
732
734
735 // Vérifie que toutes les familles (sauf les particules) sont les mêmes
736 UniqueArray<IItemFamily*> wanted_same_family;
737
738 for( IItemFamilyCollection::Enumerator i(m_mesh->itemFamilies()); ++i; ){
739 IItemFamily* family = *i;
740 if (family->itemKind()!=IK_Particle)
741 wanted_same_family.add(family);
742 }
743 ValueChecker vc(A_FUNCINFO);
744
745 // Vérifie que tout le monde à le même nombre de famille.
746 Integer nb_family = wanted_same_family.size();
747 Integer max_nb_family = pm->reduce(Parallel::ReduceMax,nb_family);
748 vc.areEqual(nb_family,max_nb_family,"Bad number of family");
749
750 // Vérifie que toutes les familles ont le même nombre d'éléments.
751 //TODO: il faudrait vérifier aussi que les noms des familles correspondent.
752 {
753 UniqueArray<Int32> families_size(nb_family);
754 for( Integer i=0; i<nb_family; ++i )
755 families_size[i] = wanted_same_family[i]->nbItem();
756 UniqueArray<Int32> global_families_size(families_size);
757 pm->reduce(Parallel::ReduceMax,global_families_size.view());
758 vc.areEqualArray(global_families_size,families_size,"Bad family");
759 }
760
761 // Vérifie que toutes les familles ont les mêmes entités (même uniqueId())
762 {
763 UniqueArray<Int64> unique_ids;
764 UniqueArray<Int64> global_unique_ids;
765 for( Integer i=0; i<nb_family; ++i ){
766 ItemGroup group = wanted_same_family[i]->allItems();
767 unique_ids.resize(group.size());
768 Integer index = 0;
769 ENUMERATE_ITEM(iitem,group){
770 unique_ids[index] = iitem->uniqueId();
771 ++index;
772 }
773 global_unique_ids.resize(group.size());
774 global_unique_ids.copy(unique_ids);
775 pm->reduce(Parallel::ReduceMax,global_unique_ids.view());
776 String message = String::format("Bad unique ids for family '{0}'",
777 wanted_same_family[i]->name());
778 vc.areEqualArray(global_unique_ids,unique_ids,message);
779 }
780 }
781}
782
783/*---------------------------------------------------------------------------*/
784/*---------------------------------------------------------------------------*/
785
786void DynamicMeshChecker::
787_checkReplicationFamily(IItemFamily*)
788{
789}
790
791/*---------------------------------------------------------------------------*/
792/*---------------------------------------------------------------------------*/
793
794} // End namespace Arcane::mesh
795
796/*---------------------------------------------------------------------------*/
797/*---------------------------------------------------------------------------*/
#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
EnumeratorT< IItemFamily * > Enumerator
Definition Collection.h:129
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
Informations pour synchroniser les groupes entre sous-domaines.
Integer checkSynchronize()
Vérifie si les groupes sont synchronisé.
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()
Vérifie que les arêtes sont correctement numérotées.
void _checkFacesOrientation()
Vérifie que les faces sont correctement orientées et connectées.
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:355
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:363
std::int32_t Int32
Type entier signé sur 32 bits.