Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
NodeFamily.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/* NodeFamily.cc (C) 2000-2025 */
9/* */
10/* Node family. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/mesh/NodeFamily.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/PlatformUtils.h"
18#include "arcane/utils/ITraceMng.h"
19#include "arcane/utils/ValueConvert.h"
20
21#include "arcane/core/ISubDomain.h"
22#include "arcane/core/ItemPrinter.h"
23#include "arcane/core/VariableTypes.h"
24#include "arcane/core/IMesh.h"
26#include "arcane/core/Connectivity.h"
27#include "arcane/core/ConnectivityItemVector.h"
28#include "arcane/core/Properties.h"
29
30#include "arcane/mesh/IncrementalItemConnectivity.h"
31#include "arcane/mesh/CompactIncrementalItemConnectivity.h"
32#include "arcane/mesh/ItemConnectivitySelector.h"
33#include "arcane/mesh/AbstractItemFamilyTopologyModifier.h"
34#include "arcane/mesh/NewWithLegacyConnectivity.h"
35#include "arcane/mesh/FaceFamily.h"
36#include "arcane/mesh/EdgeFamily.h"
37
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
40
41namespace Arcane::mesh
42{
43
44/*---------------------------------------------------------------------------*/
45/*---------------------------------------------------------------------------*/
46
48: public AbstractItemFamilyTopologyModifier
49{
50 public:
51
52 TopologyModifier(NodeFamily* f)
53 : AbstractItemFamilyTopologyModifier(f)
54 , m_true_family(f)
55 {}
56
57 public:
58
59 void replaceEdge(ItemLocalId item_lid, Integer index, ItemLocalId new_lid) override
60 {
61 m_true_family->replaceEdge(item_lid, index, new_lid);
62 }
63 void replaceFace(ItemLocalId item_lid, Integer index, ItemLocalId new_lid) override
64 {
65 m_true_family->replaceFace(item_lid, index, new_lid);
66 }
67 void replaceCell(ItemLocalId item_lid, Integer index, ItemLocalId new_lid) override
68 {
69 m_true_family->replaceCell(item_lid, index, new_lid);
70 }
71
72 private:
73
74 NodeFamily* m_true_family;
75};
76
77/*---------------------------------------------------------------------------*/
78/*---------------------------------------------------------------------------*/
79
80NodeFamily::
81NodeFamily(IMesh* mesh, const String& name)
82: ItemFamily(mesh, IK_Node, name)
83{
84 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_SORT_FACE_AND_EDGE_OF_NODE", true)) {
86 info() << "Set sort faces and edges of nodes v?=" << m_is_sort_connected_faces_and_edges;
87 }
88 _setTopologyModifier(new TopologyModifier(this));
89}
90
91/*---------------------------------------------------------------------------*/
92/*---------------------------------------------------------------------------*/
93
94NodeFamily::
95~NodeFamily()
96{
97 delete m_nodes_coords;
98}
99
100/*---------------------------------------------------------------------------*/
101/*---------------------------------------------------------------------------*/
102
103void NodeFamily::
104build()
105{
106 ItemFamily::build();
107
108 ItemTypeMng* itm = m_mesh->itemTypeMng();
109 m_node_type = itm->typeFromId(IT_Vertex);
110 if (m_parent_family)
111 m_nodes_coords = nullptr;
112 else
113 m_nodes_coords = new VariableNodeReal3(VariableBuildInfo(mesh(), "NodeCoord"));
114
115 m_face_family = ARCANE_CHECK_POINTER(dynamic_cast<FaceFamily*>(mesh()->faceFamily()));
116 m_edge_family = ARCANE_CHECK_POINTER(dynamic_cast<EdgeFamily*>(mesh()->edgeFamily()));
117
118 if (m_mesh->useMeshItemFamilyDependencies()) // temporary to fill legacy, even with family dependencies
119 {
120 m_edge_connectivity = dynamic_cast<NewWithLegacyConnectivityType<NodeFamily, EdgeFamily>::type*>(m_mesh->itemFamilyNetwork()->getConnectivity(this, mesh()->edgeFamily(), connectivityName(this, mesh()->edgeFamily())));
121 m_face_connectivity = dynamic_cast<NewWithLegacyConnectivityType<NodeFamily, FaceFamily>::type*>(m_mesh->itemFamilyNetwork()->getConnectivity(this, m_face_family, connectivityName(this, mesh()->faceFamily())));
122 m_cell_connectivity = dynamic_cast<NewWithLegacyConnectivityType<NodeFamily, CellFamily>::type*>(m_mesh->itemFamilyNetwork()->getConnectivity(this, mesh()->cellFamily(), connectivityName(this, mesh()->cellFamily())));
123 }
124 else {
125 m_edge_connectivity = new EdgeConnectivity(this, mesh()->edgeFamily(), "NodeEdge");
126 m_face_connectivity = new FaceConnectivity(this, m_face_family, "NodeFace");
127 m_cell_connectivity = new CellConnectivity(this, mesh()->cellFamily(), "NodeCell");
128 }
129 m_hparent_connectivity = new HParentConnectivity(this, this, "HParentNode");
130 m_hchild_connectivity = new HChildConnectivity(this, this, "HChildNode");
131
132 _addConnectivitySelector(m_edge_connectivity);
133 _addConnectivitySelector(m_face_connectivity);
134 _addConnectivitySelector(m_cell_connectivity);
135 _addConnectivitySelector(m_hparent_connectivity);
136 _addConnectivitySelector(m_hchild_connectivity);
137
138 _buildConnectivitySelectors();
139}
140
141/*---------------------------------------------------------------------------*/
142/*---------------------------------------------------------------------------*/
143
144void NodeFamily::
145preAllocate(Integer nb_item)
146{
147 this->_preAllocate(nb_item, true);
148}
149
150/*---------------------------------------------------------------------------*/
151/*---------------------------------------------------------------------------*/
152
153void NodeFamily::
154_endAllocate()
155{
156 if (m_nodes_coords)
157 m_nodes_coords->setUsed(true);
158 ItemFamily::_endAllocate();
159}
160
161/*---------------------------------------------------------------------------*/
162/*---------------------------------------------------------------------------*/
163
164void NodeFamily::
165addCellToNode(Node node, Cell new_cell)
166{
167 _checkValidSourceTargetItems(node, new_cell);
168 Int32 cell_lid = new_cell.localId();
169 m_cell_connectivity->addConnectedItem(ItemLocalId(node), ItemLocalId(cell_lid));
170}
171
172/*---------------------------------------------------------------------------*/
173/*---------------------------------------------------------------------------*/
174
175void NodeFamily::
176addFaceToNode(Node node, Face new_face)
177{
178 if (m_no_face_connectivity)
179 return;
180
181 _checkValidSourceTargetItems(node, new_face);
182 m_face_connectivity->addConnectedItem(ItemLocalId(node), ItemLocalId(new_face));
183}
184
185/*---------------------------------------------------------------------------*/
186/*---------------------------------------------------------------------------*/
187
188void NodeFamily::
189addEdgeToNode(Node node, Edge new_edge)
190{
191 if (!Connectivity::hasConnectivity(m_mesh_connectivity, Connectivity::CT_NodeToEdge))
192 return;
193
194 _checkValidSourceTargetItems(node, new_edge);
195 m_edge_connectivity->addConnectedItem(ItemLocalId(node), ItemLocalId(new_edge));
196}
197
198/*---------------------------------------------------------------------------*/
199/*---------------------------------------------------------------------------*/
200
201void NodeFamily::
202removeEdgeFromNode(ItemLocalId node, ItemLocalId edge_to_remove)
203{
204 if (!Connectivity::hasConnectivity(m_mesh_connectivity, Connectivity::CT_NodeToEdge))
205 return;
206 m_edge_connectivity->removeConnectedItem(node, edge_to_remove);
207}
208
209/*---------------------------------------------------------------------------*/
210/*---------------------------------------------------------------------------*/
211
212void NodeFamily::
213removeFaceFromNode(ItemLocalId node, ItemLocalId face_to_remove)
214{
215 if (m_no_face_connectivity)
216 return;
217
218 m_face_connectivity->removeConnectedItem(node, face_to_remove);
219}
220
221/*---------------------------------------------------------------------------*/
222/*---------------------------------------------------------------------------*/
223
224void NodeFamily::
225removeCellFromNode(Node node, ItemLocalId cell_to_remove_lid)
226{
227 _checkValidItem(node);
228 m_cell_connectivity->removeConnectedItem(ItemLocalId(node), cell_to_remove_lid);
229}
230
231/*---------------------------------------------------------------------------*/
232/*---------------------------------------------------------------------------*/
233
236{
237 _checkValidItem(node);
238 if (!node.itemBase().isSuppressed()) {
239 Integer nb_cell = node.nbCell();
240 if (nb_cell == 0)
241 _removeNode(node);
242 }
243}
244
245/*---------------------------------------------------------------------------*/
246/*---------------------------------------------------------------------------*/
247
250{
251 debug() << "Creating the ghosts nodes list";
253}
254
255/*---------------------------------------------------------------------------*/
256/*---------------------------------------------------------------------------*/
257
258inline void NodeFamily::
259_removeNode(Node node)
260{
261 _removeOne(node);
262 // Do not remove other relationships here (edge->node, face->node)
263 // Because the order of deletion must always be cell, face, edge, node
264 // so node is last and everything is already done
265 // Furthermore, this avoids recursion problems
266}
267
268/*---------------------------------------------------------------------------*/
269/*---------------------------------------------------------------------------*/
270
277{
278 m_cell_connectivity->replaceItem(node, index, cell);
279}
280
281/*---------------------------------------------------------------------------*/
282/*---------------------------------------------------------------------------*/
289{
290 m_edge_connectivity->replaceItem(node, index, edge);
291}
292
293/*---------------------------------------------------------------------------*/
294/*---------------------------------------------------------------------------*/
301{
302 m_face_connectivity->replaceItem(node, index, face);
303}
304
305/*---------------------------------------------------------------------------*/
306/*---------------------------------------------------------------------------*/
307
310{
311 m_mesh_connectivity = c;
312 if (Connectivity::hasConnectivity(m_mesh_connectivity, Connectivity::CT_HasEdge))
313 m_edge_prealloc = Connectivity::getPrealloc(m_mesh_connectivity, IK_Node, IK_Edge);
314 m_face_prealloc = Connectivity::getPrealloc(m_mesh_connectivity, IK_Node, IK_Face);
315 m_cell_prealloc = Connectivity::getPrealloc(m_mesh_connectivity, IK_Node, IK_Cell);
316 m_face_connectivity->setPreAllocatedSize(m_face_prealloc);
317 m_cell_connectivity->setPreAllocatedSize(m_cell_prealloc);
318 debug() << "Family " << name() << " prealloc "
319 << m_edge_prealloc << " by edge, "
320 << m_face_prealloc << " by face, "
321 << m_cell_prealloc << " by cell.";
322 m_no_face_connectivity = !Connectivity::hasConnectivity(m_mesh_connectivity, Connectivity::CT_NodeToFace);
323}
324
325/*---------------------------------------------------------------------------*/
326/*---------------------------------------------------------------------------*/
327
329{
330 public:
331
332 explicit ItemCompare2(const ItemInfoListView& items)
333 : m_items(items)
334 {
335 }
336
337 public:
338
339 bool operator()(Int32 item1, Int32 item2) const
340 {
341 return m_items.uniqueId(item1) < m_items.uniqueId(item2);
342 }
343
344 private:
345
346 ItemInfoListView m_items;
347};
348
349/*---------------------------------------------------------------------------*/
350/*---------------------------------------------------------------------------*/
351
353{
354 public:
355
356 explicit ItemCompare3(ITraceMng* msg)
357 : m_msg(msg)
358 {}
359
360 public:
361
362 ITraceMng* m_msg;
363 ItemInternalArrayView m_items;
364
365 public:
366
367 bool operator()(Integer item1, Integer item2) const
368 {
369 m_msg->info() << "** Compare ptr=" << m_items.data()
370 << " i1=" << item1 << " i2=" << item2
371 << " i1=" << m_items[item1] << " i2=" << m_items[item2]
372 << " uid1=" << m_items[item1]->uniqueId()
373 << " uid2=" << m_items[item2]->uniqueId();
374 return m_items[item1]->uniqueId() < m_items[item2]->uniqueId();
375 }
376};
377
378/*---------------------------------------------------------------------------*/
379/*---------------------------------------------------------------------------*/
380
381void NodeFamily::
382_sortConnectedItems(IItemFamily* family, IncrementalItemConnectivity* connectivity)
383{
384 if (!connectivity)
385 return;
386
387 // Sort the entities connected to nodes by increasing uniqueId().
388 // This is useful to guarantee a traversal order of these entities
389 // that is identical regardless of the decomposition and thus improves
390 // reproducibility.
391 ItemInfoListView items_infos(family->itemInfoListView());
392 ItemCompare2 ic_items(items_infos);
393 ENUMERATE_ITEM (iitem, allItems()) {
394 ItemLocalId lid(iitem.itemLocalId());
395 Int32ArrayView conn_lids = connectivity->_connectedItemsLocalId(lid);
396 std::sort(std::begin(conn_lids), std::end(conn_lids), ic_items);
397 }
398}
399
400/*---------------------------------------------------------------------------*/
401/*---------------------------------------------------------------------------*/
402
403void NodeFamily::
404sortInternalReferences()
405{
406 // Sort the cells connected to nodes by increasing uniqueId().
407 _sortConnectedItems(mesh()->cellFamily(), m_cell_connectivity->trueCustomConnectivity());
408
409 // Do the same for faces and edges.
410 // For historical reasons, this is not active by default.
411 bool do_sort = properties()->getBoolWithDefault("sort-connected-faces-edges", m_is_sort_connected_faces_and_edges);
412 if (do_sort) {
413 info(4) << "Sorting connected faces and edges family=" << fullName();
414 _sortConnectedItems(m_face_family, m_face_connectivity->trueCustomConnectivity());
415 if (Connectivity::hasConnectivity(m_mesh_connectivity, Connectivity::CT_NodeToEdge))
416 _sortConnectedItems(mesh()->edgeFamily(), m_edge_connectivity->trueCustomConnectivity());
417 }
418}
419
420/*---------------------------------------------------------------------------*/
421/*---------------------------------------------------------------------------*/
422
425{
427 // If the uniqueId() of nodes change, this can influence
428 // the orientation of faces and edges. These must therefore be reoriented
429 m_face_family->reorientFacesIfNeeded();
430 m_edge_family->reorientEdgesIfNeeded();
431}
432
433/*---------------------------------------------------------------------------*/
434/*---------------------------------------------------------------------------*/
435
436void NodeFamily::
437_addParentNodeToNode(Node parent_node, Node child_node)
438{
439 m_hparent_connectivity->addConnectedItem(ItemLocalId(child_node), ItemLocalId(parent_node));
440}
441
442/*---------------------------------------------------------------------------*/
443/*---------------------------------------------------------------------------*/
444
445void NodeFamily::
446_addChildNodeToNode(Node parent_node, Node child_node)
447{
448 m_hchild_connectivity->addConnectedItem(ItemLocalId(parent_node), ItemLocalId(child_node));
449}
450
451/*---------------------------------------------------------------------------*/
452/*---------------------------------------------------------------------------*/
453
454} // End namespace Arcane::mesh
455
456/*---------------------------------------------------------------------------*/
457/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ENUMERATE_ITEM(name, group)
Generic enumerator for a node group.
Utility functions for the mesh.
Template class for converting a type.
Interface of an entity family.
Definition IItemFamily.h:83
virtual TraceMessage info()=0
Stream for an information message.
bool isSuppressed() const
True if the entity is suppressed.
View of a list to obtain information about entities.
Index of an Item in a variable.
Definition ItemLocalId.h:42
impl::ItemBase itemBase() const
Internal part of the entity.
Definition Item.h:383
Node of a mesh.
Definition Item.h:598
Int32 nbCell() const
Number of cells connected to the node.
Definition Item.h:701
bool getBoolWithDefault(const String &name, bool default_value) const
Value of the property named name.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flow for a debug message.
TraceMessage info() const
Flow for an information message.
IMesh * mesh() const override
Associated mesh.
String fullName() const override
Full family name (with the mesh's name).
Definition ItemFamily.h:141
ItemGroup allItems() const override
Group of all entities.
void notifyItemsUniqueIdChanged() override
Notifies that the unique IDs of the entities have been modified.
void computeSynchronizeInfos() override
Constructs the structures necessary for synchronization.
Properties * properties() override
Properties associated with this family.
Definition ItemFamily.h:285
String name() const override
Family name.
Definition ItemFamily.h:140
void replaceCell(ItemLocalId item_lid, Integer index, ItemLocalId new_lid) override
Replaces a cell of an entity.
Definition NodeFamily.cc:67
void replaceFace(ItemLocalId item_lid, Integer index, ItemLocalId new_lid) override
Replaces a face of an entity.
Definition NodeFamily.cc:63
void replaceEdge(ItemLocalId item_lid, Integer index, ItemLocalId new_lid) override
Replaces an edge of an entity.
Definition NodeFamily.cc:59
void computeSynchronizeInfos() override
Constructs the structures necessary for synchronization.
void replaceCell(ItemLocalId node, Integer index, ItemLocalId cell)
Replaces the cell index index of the node node with that of localId() node_lid.
void removeNodeIfNotConnected(Node node)
Removes the node if it is no longer connected.
void replaceFace(ItemLocalId node, Integer index, ItemLocalId face)
Replaces the face index index of the node node with that of localId() face_lid.
void notifyItemsUniqueIdChanged() override
Notifies that the unique IDs of the entities have been modified.
void setConnectivity(const Integer c)
Sets the active connectivity for the associated mesh.
void replaceEdge(ItemLocalId node, Integer index, ItemLocalId edge)
Replaces the edge index index of the node node with that of localId() face_lid.
ItemTypeInfo * m_node_type
Instance containing the node type.
Definition NodeFamily.h:148
bool m_is_sort_connected_faces_and_edges
Indicates if connected faces and edges are sorted by nodes.
Definition NodeFamily.h:164
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
Int32 Integer
Type representing an integer.
ArrayView< Int32 > Int32ArrayView
C equivalent of a 1D array of 32-bit integers.
Definition UtilsTypes.h:453
@ IK_Node
Node mesh entity.
@ IK_Cell
Cell mesh entity.
@ IK_Face
Face mesh entity.
@ IK_Edge
Edge mesh entity.
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53
std::int32_t Int32
Signed integer type of 32 bits.