Arcane  4.1.11.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-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/* MeshNodeMerger.cc (C) 2000-2025 */
9/* */
10/* Mesh node merger. */
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/*---------------------------------------------------------------------------*/
81void MeshNodeMerger::
82mergeNodes(Int32ConstArrayView nodes_local_id,
83 Int32ConstArrayView nodes_to_merge_local_id,
84 bool allow_non_corresponding_face)
85{
86 ItemInternalList nodes_internal(m_node_family->itemsInternal());
87 Integer nb_node = nodes_local_id.size();
88 if (nb_node != nodes_to_merge_local_id.size())
89 throw ArgumentException(A_FUNCINFO, String::format("Arrays of different size"));
90 for (Integer i = 0; i < nb_node; ++i) {
91 Node node(nodes_internal[nodes_local_id[i]]);
92 Node node_to_merge(nodes_internal[nodes_to_merge_local_id[i]]);
93 // NOTE: June 2025: Remove the following test which is
94 // not useful because it must be possible for a face to merge
95 // a node with itself. The only case where this could cause a problem
96 // with the current algorithm is if all these
97 // nodes for a given face are merged with themselves.
98 // if (node.localId()==node_to_merge.localId())
99 // ARCANE_FATAL("Can not merge a node with itself");
100 info(4) << "ADD CORRESPONDANCE node=" << node.uniqueId() << " node_to_merge=" << node_to_merge.uniqueId();
101 m_nodes_correspondance.insert(std::make_pair(node_to_merge, node));
102 }
103
104 // Mark all faces that contain at least one merged node
105 // and determine which ones must be merged: these are the ones for
106 // which every node is merged.
107 std::set<Face> marked_faces;
108 Int64UniqueArray face_new_nodes_uid;
109 Int64UniqueArray face_new_nodes_sorted_uid;
110 ENUMERATE_ (Face, iface, m_face_family->allItems()) {
111 Face face = *iface;
112 Integer face_nb_node = face.nbNode();
113 Integer nb_merged_node = 0;
114 for (NodeEnumerator inode(face.nodes()); inode(); ++inode) {
115 Node node = *inode;
116 if (m_nodes_correspondance.find(node) != m_nodes_correspondance.end()) {
117 ++nb_merged_node;
118 marked_faces.insert(face);
119 }
120 }
121 if (nb_merged_node == face_nb_node) {
122 // All nodes of the face are merged. This means that the
123 // cells associated with this face will reference a new face.
124 // We must now find this new face.
125 info(4) << "FACE TO MERGE uid=" << face.uniqueId();
126 face_new_nodes_uid.resize(face_nb_node);
127 face_new_nodes_sorted_uid.resize(face_nb_node);
128 Node new_face_first_node;
129 for (NodeEnumerator inode(face.nodes()); inode(); ++inode) {
130 Node new_node = m_nodes_correspondance.find(*inode)->second;
131 if (inode.index() == 0)
132 new_face_first_node = new_node;
133 face_new_nodes_uid[inode.index()] = new_node.uniqueId();
134 info(4) << " OLD_node=" << (*inode).uniqueId() << " new=" << new_node.uniqueId();
135 }
136 mesh_utils::reorderNodesOfFace(face_new_nodes_uid, face_new_nodes_sorted_uid);
137 Face new_face = ItemTools::findFaceInNode2(new_face_first_node, face.type(), face_new_nodes_sorted_uid);
138 if (new_face.null()) {
139 // The face has no corresponding face. Do nothing if this is allowed.
140 if (allow_non_corresponding_face)
141 continue;
142 ARCANE_FATAL("Can not find corresponding face nodes_uid={0}", face_new_nodes_sorted_uid);
143 }
144 info(4) << "NEW FACE=" << new_face.uniqueId() << " nb_cell=" << new_face.nbCell();
145 m_faces_correspondance.insert(std::make_pair(face, new_face));
146 // Since this face is merged, it is removed from the list of
147 // marked faces.
148 marked_faces.erase(marked_faces.find(face));
149 }
150 }
151 // TODO: process edges
152
153 // Mark all cells that contain at least one merged node.
154 std::set<Cell> marked_cells;
155 ENUMERATE_CELL (icell, m_cell_family->allItems()) {
156 Cell cell = *icell;
157 for (NodeEnumerator inode(cell.nodes()); inode(); ++inode) {
158 if (m_nodes_correspondance.find(*inode) != m_nodes_correspondance.end())
159 marked_cells.insert(cell);
160 }
161 }
162
163 for (Cell cell : marked_cells) {
164 ItemLocalId cell_local_id(cell.localId());
165 info(4) << "MARKED CELL2=" << cell.localId();
166 for (NodeEnumerator inode(cell.nodes()); inode(); ++inode) {
167 Node node = *inode;
168 auto x = m_nodes_correspondance.find(node);
169 if (x != m_nodes_correspondance.end()) {
170 Node new_node = x->second;
171 info(4) << "REMOVE node=" << ItemPrinter(node) << " from cell=" << ItemPrinter(cell);
172 m_node_family->removeCellFromNode(node, cell_local_id);
173 m_node_family->addCellToNode(new_node, cell);
174 m_cell_family->replaceNode(cell, inode.index(), new_node);
175 }
176 }
177 for (FaceEnumerator iface(cell.faces()); iface(); ++iface) {
178 Face face = *iface;
179 auto x = m_faces_correspondance.find(face);
180 if (x != m_faces_correspondance.end()) {
181 Face new_face = x->second;
182 m_face_family->removeCellFromFace(face, cell_local_id);
183 if (new_face.backCell().null())
184 m_face_family->addBackCellToFace(new_face, cell);
185 else
186 m_face_family->addFrontCellToFace(new_face, cell);
187 m_cell_family->replaceFace(cell, iface.index(), new_face);
188 }
189 }
190 // TODO: add edge management.
191 }
192
193 for (Face face : marked_faces) {
194 info(4) << "MARKED FACE=" << face.localId();
195 for (NodeEnumerator inode(face.nodes()); inode(); ++inode) {
196 Node node = *inode;
197 auto x = m_nodes_correspondance.find(node);
198 if (x != m_nodes_correspondance.end()) {
199 Node new_node = x->second;
200 m_node_family->removeFaceFromNode(node, face);
201 m_node_family->addFaceToNode(new_node, face);
202 m_face_family->replaceNode(face, inode.index(), new_node);
203 }
204 }
205 }
206 // TODO: add edge management.
207
208 // Ensure that the new faces are properly oriented
209 {
210 FaceReorienter fr(m_mesh);
211 for (Face face : marked_faces) {
213 }
214 }
215
216 // Remove all faces that must be merged.
217 for (const auto& x : m_faces_correspondance) {
218 Face face = x.first;
219 m_face_family->removeFaceIfNotConnected(face);
220 }
221
222 // Remove all nodes that must be merged.
223 for (const auto& x : m_nodes_correspondance) {
224 Node node = x.first;
225 m_node_family->removeNodeIfNotConnected(node);
226 }
227
228 m_mesh->modifier()->endUpdate();
229}
230
231/*---------------------------------------------------------------------------*/
232/*---------------------------------------------------------------------------*/
233
234} // End namespace Arcane::mesh
235
236/*---------------------------------------------------------------------------*/
237/*---------------------------------------------------------------------------*/
#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:1214
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:964
Int32 nbCell() const
Nombre de mailles de la face (1 ou 2).
Definition Item.h:1042
Cell backCell() const
Maille derrière la face (maille nulle si aucune).
Definition Item.h:1646
Index d'un Item dans une variable.
Definition ItemLocalId.h:41
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:34
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
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:339
Int32 Integer
Type représentant un entier.
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:482
ConstArrayView< ItemInternal * > ItemInternalList
Type de la liste interne des entités.
Definition ItemTypes.h:466