Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
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 returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Types and macros for iterating over mesh entities.
#define ENUMERATE_(type, name, group)
Generic enumerator for an entity group.
#define ENUMERATE_CELL(name, group)
Generic enumerator for a cell group.
Utility functions for the mesh.
bool reorderNodesOfFace(Int64ConstArrayView before_ids, Int64ArrayView after_ids)
Reorders the nodes of a face.
void resize(Int64 s)
Changes the number of elements in the array to s.
Cell of a mesh.
Definition Item.h:1300
constexpr Integer size() const noexcept
Number of elements in the array.
This function/class reorients faces.
ARCANE_DEPRECATED_260 void checkAndChangeOrientation(ItemInternal *face)
Face of a cell.
Definition Item.h:1032
Int32 nbCell() const
Number of cells of the face (1 or 2).
Definition Item.h:1129
Cell backCell() const
Cell behind the face (null cell if none).
Definition Item.h:1774
Index of an Item in a variable.
Definition ItemLocalId.h:42
Utility class for printing information about an entity.
Definition ItemPrinter.h:35
NodeConnectedListViewType nodes() const
List of nodes of the entity.
Definition Item.h:843
Int32 nbNode() const
Number of nodes of the entity.
Definition Item.h:837
ItemUniqueId uniqueId() const
Unique identifier across all domains.
Definition Item.h:239
constexpr bool null() const
true if the entity is null (i.e. not connected to the mesh)
Definition Item.h:230
Int16 type() const
Entity type.
Definition Item.h:255
Node of a mesh.
Definition Item.h:598
TraceMessage info() const
Flow for an information message.
static Face findFaceInNode2(Node node, Integer face_type_id, Int64ConstArrayView face_nodes_uid)
Definition ItemTools.cc:44
ItemEnumeratorT< Node > NodeEnumerator
Enumerators over nodes.
Definition ItemTypes.h:255
ItemEnumeratorT< Face > FaceEnumerator
Enumerators over faces.
Definition ItemTypes.h:266
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
Definition UtilsTypes.h:339
Int32 Integer
Type representing an integer.
ConstArrayView< Int32 > Int32ConstArrayView
C equivalent of a 1D array of 32-bit integers.
Definition UtilsTypes.h:482
ConstArrayView< ItemInternal * > ItemInternalList
Type of the internal list of entities.
Definition ItemTypes.h:466