Arcane  v3.16.3.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
MeshNodeMerger.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/* MeshNodeMerger.cc (C) 2000-2025 */
9/* */
10/* Fusions de noeuds d'un maillage. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/FatalErrorException.h"
15#include "arcane/utils/NotImplementedException.h"
16#include "arcane/utils/ArgumentException.h"
17
18#include "arcane/core/IMesh.h"
20#include "arcane/core/IMeshModifier.h"
22#include "arcane/core/ItemPrinter.h"
23#include "arcane/core/Connectivity.h"
24
25#include "arcane/mesh/MeshNodeMerger.h"
26#include "arcane/mesh/FaceReorienter.h"
27#include "arcane/mesh/ItemTools.h"
28#include "arcane/mesh/NodeFamily.h"
29#include "arcane/mesh/EdgeFamily.h"
30#include "arcane/mesh/FaceFamily.h"
31#include "arcane/mesh/CellFamily.h"
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
35
36namespace Arcane::mesh
37{
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
42MeshNodeMerger::
43MeshNodeMerger(IMesh* mesh)
44: TraceAccessor(mesh->traceMng())
45, m_mesh(mesh)
46{
47 if (m_mesh->hasTiedInterface())
48 throw NotImplementedException(A_FUNCINFO,"mesh with tied interfaces");
49 if (m_mesh->dimension()==3){
50 Int32 c = m_mesh->connectivity()();
51 if (Connectivity::hasConnectivity(c,Connectivity::CT_HasEdge))
52 throw NotImplementedException(A_FUNCINFO,"3D mesh with edges");
53 }
54 if (m_mesh->childMeshes().count()!=0)
55 throw NotSupportedException(A_FUNCINFO,"mesh with child meshes");
56 if (m_mesh->isAmrActivated())
57 throw NotSupportedException(A_FUNCINFO,"mesh with AMR cells");
58
59 m_node_family = ARCANE_CHECK_POINTER(dynamic_cast<NodeFamily*>(m_mesh->nodeFamily()));
60 m_edge_family = ARCANE_CHECK_POINTER(dynamic_cast<EdgeFamily*>(m_mesh->edgeFamily()));
61 m_face_family = ARCANE_CHECK_POINTER(dynamic_cast<FaceFamily*>(m_mesh->faceFamily()));
62 m_cell_family = ARCANE_CHECK_POINTER(dynamic_cast<CellFamily*>(m_mesh->cellFamily()));
63
64}
65
66/*---------------------------------------------------------------------------*/
67/*---------------------------------------------------------------------------*/
82void MeshNodeMerger::
83mergeNodes(Int32ConstArrayView nodes_local_id,
84 Int32ConstArrayView nodes_to_merge_local_id,
85 bool allow_non_corresponding_face)
86{
87 ItemInternalList nodes_internal(m_node_family->itemsInternal());
88 Integer nb_node = nodes_local_id.size();
89 if (nb_node != nodes_to_merge_local_id.size())
90 throw ArgumentException(A_FUNCINFO,String::format("Arrays of different size"));
91 for (Integer i = 0; i < nb_node; ++i) {
92 Node node(nodes_internal[nodes_local_id[i]]);
93 Node node_to_merge(nodes_internal[nodes_to_merge_local_id[i]]);
94 // NOTE: juin 2025: Supprime le test suivant qui n'est
95 // pas utile car il doit être possible pour une face de fusionner
96 // noeud avec lui-même. Le seul cas où cela pourrait poser problème
97 // avec l'algorithme actuel est si pour une face données tous ces
98 // noeuds sont fusionnés avec eux-même.
99 // if (node.localId()==node_to_merge.localId())
100 // ARCANE_FATAL("Can not merge a node with itself");
101 info(4) << "ADD CORRESPONDANCE node=" << node.uniqueId() << " node_to_merge=" << node_to_merge.uniqueId();
102 m_nodes_correspondance.insert(std::make_pair(node_to_merge,node));
103 }
104
105 // Marque toutes les faces qui contiennent au moins un nœud fusionné
106 // et détermine celles qui doivent être fusionnées : ce sont celles pour
107 // lesquelles chaque nœud est fusionné.
108 std::set<Face> marked_faces;
109 Int64UniqueArray face_new_nodes_uid;
110 Int64UniqueArray face_new_nodes_sorted_uid;
111 ENUMERATE_ (Face, iface, m_face_family->allItems()) {
112 Face face = *iface;
113 Integer face_nb_node = face.nbNode();
114 Integer nb_merged_node = 0;
115 for( NodeEnumerator inode(face.nodes()); inode(); ++inode ){
116 Node node = *inode;
117 if (m_nodes_correspondance.find(node)!=m_nodes_correspondance.end()){
118 ++nb_merged_node;
119 marked_faces.insert(face);
120 }
121 }
122 if (nb_merged_node == face_nb_node) {
123 // Tous les nœuds de la face sont fusionnés. Cela veut dire que les
124 // mailles associées à cette face vont faire référence à une nouvelle face.
125 // Il faut maintenant trouver cette nouvelle face.
126 info(4) << "FACE TO MERGE uid=" << face.uniqueId();
127 face_new_nodes_uid.resize(face_nb_node);
128 face_new_nodes_sorted_uid.resize(face_nb_node);
129 Node new_face_first_node;
130 for( NodeEnumerator inode(face.nodes()); inode(); ++inode ){
131 Node new_node = m_nodes_correspondance.find(*inode)->second;
132 if (inode.index()==0)
133 new_face_first_node = new_node;
134 face_new_nodes_uid[inode.index()] = new_node.uniqueId();
135 info(4) << " OLD_node=" << (*inode).uniqueId() << " new=" << new_node.uniqueId();
136 }
137 mesh_utils::reorderNodesOfFace(face_new_nodes_uid, face_new_nodes_sorted_uid);
138 Face new_face = ItemTools::findFaceInNode2(new_face_first_node, face.type(), face_new_nodes_sorted_uid);
139 if (new_face.null()) {
140 // La face n'a pas de correspondante. Ne fais rien si cela est autorisé.
141 if (allow_non_corresponding_face)
142 continue;
143 ARCANE_FATAL("Can not find corresponding face nodes_uid={0}", face_new_nodes_sorted_uid);
144 }
145 info(4) << "NEW FACE=" << new_face.uniqueId() << " nb_cell=" << new_face.nbCell();
146 m_faces_correspondance.insert(std::make_pair(face,new_face));
147 // Comme cette face est fusionnée, on la retire de la liste des faces
148 // marquées.
149 marked_faces.erase(marked_faces.find(face));
150 }
151 }
152 // TODO: traiter les arêtes
153
154 // Marque toutes les mailles qui contiennent au moins un noeud fusionné.
155 std::set<Cell> marked_cells;
156 ENUMERATE_CELL(icell,m_cell_family->allItems()){
157 Cell cell = *icell;
158 for( NodeEnumerator inode(cell.nodes()); inode(); ++inode ){
159 if (m_nodes_correspondance.find(*inode)!=m_nodes_correspondance.end())
160 marked_cells.insert(cell);
161 }
162 }
163
164 for( Cell cell : marked_cells ){
165 ItemLocalId cell_local_id(cell.localId());
166 info(4) << "MARKED CELL2=" << cell.localId();
167 for( NodeEnumerator inode(cell.nodes()); inode(); ++inode ){
168 Node node = *inode;
169 auto x = m_nodes_correspondance.find(node);
170 if (x!=m_nodes_correspondance.end()){
171 Node new_node = x->second;
172 info(4) << "REMOVE node=" << ItemPrinter(node) << " from cell=" << ItemPrinter(cell);
173 m_node_family->removeCellFromNode(node,cell_local_id);
174 m_node_family->addCellToNode(new_node,cell);
175 m_cell_family->replaceNode(cell,inode.index(),new_node);
176 }
177 }
178 for( FaceEnumerator iface(cell.faces()); iface(); ++iface ){
179 Face face = *iface;
180 auto x = m_faces_correspondance.find(face);
181 if (x!=m_faces_correspondance.end()){
182 Face new_face = x->second;
183 m_face_family->removeCellFromFace(face,cell_local_id);
184 if (new_face.backCell().null())
185 m_face_family->addBackCellToFace(new_face,cell);
186 else
187 m_face_family->addFrontCellToFace(new_face,cell);
188 m_cell_family->replaceFace(cell,iface.index(),new_face);
189 }
190 }
191 // TODO: ajouter gestion des aretes.
192 }
193
194 for( Face face : marked_faces ){
195 info(4) << "MARKED FACE=" << face.localId();
196 for( NodeEnumerator inode(face.nodes()); inode(); ++inode ){
197 Node node = *inode;
198 auto x = m_nodes_correspondance.find(node);
199 if (x!=m_nodes_correspondance.end()){
200 Node new_node = x->second;
201 m_node_family->removeFaceFromNode(node,face);
202 m_node_family->addFaceToNode(new_node,face);
203 m_face_family->replaceNode(face,inode.index(),new_node);
204 }
205 }
206 }
207 // TODO: ajouter gestion des arêtes.
208
209 // S'assure que les nouvelles faces sont bien orientées
210 {
211 FaceReorienter fr(m_mesh);
212 for( Face face : marked_faces ){
214 }
215 }
216
217 // Supprime toutes les faces qui doivent être fusionnées.
218 for( const auto& x : m_faces_correspondance ){
219 Face face = x.first;
220 m_face_family->removeFaceIfNotConnected(face);
221 }
222
223 // Supprime tous les noeuds qui doivent être fusionnées.
224 for( const auto& x : m_nodes_correspondance ){
225 Node node = x.first;
226 m_node_family->removeNodeIfNotConnected(node);
227 }
228
229 m_mesh->modifier()->endUpdate();
230}
231
232/*---------------------------------------------------------------------------*/
233/*---------------------------------------------------------------------------*/
234
235} // End namespace Arcane::mesh
236
237/*---------------------------------------------------------------------------*/
238/*---------------------------------------------------------------------------*/
239
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Types et macros pour itérer sur les entités du maillage.
#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.
Fonctions utilitaires sur le maillage.
bool reorderNodesOfFace(Int64ConstArrayView before_ids, Int64ArrayView after_ids)
Réordonne les noeuds d'une face.
Exception lorsqu'un argument est invalide.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
Maille d'un maillage.
Definition Item.h:1205
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Cette fonction/classe réoriente les faces.
ARCANE_DEPRECATED_260 void checkAndChangeOrientation(ItemInternal *face)
Face d'une maille.
Definition Item.h:958
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2)
Definition Item.h:1033
Cell backCell() const
Maille derrière la face (maille nulle si aucune)
Definition Item.h:1628
Index d'un Item dans une variable.
Definition ItemLocalId.h:41
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:35
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:791
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:785
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
Int16 type() const
Type de l'entité
Definition Item.h:241
Noeud d'un maillage.
Definition Item.h:582
TraceMessage info() const
Flot pour un message d'information.
static Face findFaceInNode2(Node node, Integer face_type_id, Int64ConstArrayView face_nodes_uid)
Definition ItemTools.cc:44
ItemEnumeratorT< Node > NodeEnumerator
Enumérateurs sur des noeuds.
Definition ItemTypes.h:254
ItemEnumeratorT< Face > FaceEnumerator
Enumérateurs sur des faces.
Definition ItemTypes.h:265
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:426
Int32 Integer
Type représentant un entier.
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:569
ConstArrayView< ItemInternal * > ItemInternalList
Type de la liste interne des entités.
Definition ItemTypes.h:466