Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
TiedInterfaceMng.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/* TiedInterfaceMng.cc (C) 2000-2023 */
9/* */
10/* Tied interface manager. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/mesh/TiedInterfaceMng.h"
15#include "arcane/mesh/DynamicMesh.h"
16#include "arcane/mesh/FaceFamily.h"
17
18#include "arcane/mesh/TiedInterface.h"
19
20#include "arcane/core/XmlNode.h"
21#include "arcane/core/IMesh.h"
22#include "arcane/core/ISubDomain.h"
23#include "arcane/core/ICaseDocument.h"
24#include "arcane/core/CaseNodeNames.h"
25#include "arcane/core/IParallelMng.h"
26#include "arcane/core/IMeshPartitionConstraintMng.h"
27#include "arcane/core/IMeshUtilities.h"
28#include "arcane/core/ArcaneException.h"
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32
33namespace Arcane::mesh
34{
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39TiedInterfaceMng::
40TiedInterfaceMng(DynamicMesh* mesh)
41: TraceAccessor(mesh->traceMng())
42, m_mesh(mesh)
43, m_sub_domain(mesh->subDomain())
44, m_name(mesh->name())
45, m_tied_interface_items_info(VariableBuildInfo(m_sub_domain, m_name + "TiedInterfaceItemsInfo"))
46, m_tied_interface_nodes_iso(VariableBuildInfo(m_sub_domain, m_name + "TiedInterfaceNodesIso"))
47, m_tied_interface_face_groups(VariableBuildInfo(m_sub_domain, m_name + "TiedInterfaceFaceGroups"))
48, m_tied_constraint(0)
49{
50}
51
52/*---------------------------------------------------------------------------*/
53/*---------------------------------------------------------------------------*/
54
55TiedInterfaceMng::
56~TiedInterfaceMng()
57{
58 // m_tied_constraint is destroyed by the mesh constraint manager
59 m_tied_constraint = 0;
60
61 _deleteTiedInterfaces();
62}
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
66
67void TiedInterfaceMng::
68computeTiedInterfaces(const XmlNode& mesh_node)
69{
70 ICaseDocument* doc = subDomain()->caseDocument();
71 CaseNodeNames* cnn = doc->caseNodeNames();
72 String tied_interfaces_name = cnn->tied_interfaces;
73 String tied_interface_not_structured_name = cnn->tied_interfaces_not_structured;
74 String tied_interfaces_planar_tolerance = cnn->tied_interfaces_planar_tolerance;
75 String semi_conform_name = cnn->tied_interfaces_semi_conform;
76 String name_attribute = cnn->tied_interfaces_slave;
77 XmlNode tied_interface_elem = mesh_node.child(tied_interfaces_name);
78 XmlNodeList child_list = tied_interface_elem.children(semi_conform_name);
79 bool has_error = false;
80
81 IParallelMng* pm = m_mesh->parallelMng();
82 bool is_parallel = pm->isParallel();
83 UniqueArray<FaceGroup> interfaces_group;
84 UniqueArray<bool> is_structured_list;
85 UniqueArray<Real> planar_tolerance_list;
86 FaceFamily& face_family = m_mesh->trueFaceFamily();
87 for (auto& i : child_list) {
88 XmlNode group_attr = i.attr(name_attribute);
89 if (group_attr.null()) {
90 error() << "Attribute '" << name_attribute << "' missing";
91 has_error = true;
92 continue;
93 }
94 String group_name = i.attrValue(name_attribute);
95 FaceGroup face_group = face_family.findGroup(group_name);
96 if (face_group.null()) {
97 error() << "Can't find the interface '" << group_name << "'";
98 has_error = true;
99 continue;
100 }
101 if (interfaces_group.contains(face_group)) {
102 error() << "The group '" << group_name << "' is already present in list of tied interfaces.";
103 has_error = true;
104 continue;
105 }
106 interfaces_group.add(face_group);
107
108 bool is_not_structured = i.attr(tied_interface_not_structured_name).valueAsBoolean();
109 info() << "** NOT STRUCTURED? = " << is_not_structured;
110 is_structured_list.add(!is_not_structured);
111 XmlNode tolerance_node = i.attr(tied_interfaces_planar_tolerance);
112 if (tolerance_node.null()) {
113 planar_tolerance_list.add(0.);
114 }
115 else {
116 planar_tolerance_list.add(tolerance_node.valueAsReal());
117 }
118 }
119 if (has_error)
120 fatal() << "Can't determine the tied interfaces";
121
122 // If no tied interface is specified in the dataset,
123 // search for a face group named SOUDURE or SOUDURES
124 // and consider it a weld interface in that case
125 {
126 FaceGroup g1 = face_family.findGroup("SOUDURE");
127 if (g1.null())
128 g1 = face_family.findGroup("SOUDURES");
129 if (!g1.null()) {
130 // Only add the group if it is not already in the list
131 if (!interfaces_group.contains(g1)) {
132 info() << "Add automatically the group '" << g1.name() << "' to the list of tied interfaces";
133 interfaces_group.add(g1);
134 is_structured_list.add(true);
135 planar_tolerance_list.add(0.0);
136 }
137 else {
138 info() << "built-in group " << g1.name() << " already in list of tied interfaces";
139 }
140 }
141 }
142 Integer nb_interface = interfaces_group.size();
143 IItemFamily* cell_family = m_mesh->cellFamily();
144 if (nb_interface != 0) {
145 // In parallel, cells must be migrated so that the cells
146 // on both sides of an interface face are in the same subdomain.
147 // In parallel, first recalculate the owners, perform
148 // the exchange, and finally calculate the projections
149 if (is_parallel) {
150 VariableItemInt32& cells_owner = cell_family->itemsNewOwner();
151 ENUMERATE_ITEM (iitem, cell_family->allItems()) {
152 cells_owner[iitem] = (*iitem).owner();
153 }
154 //for( Integer i=0, is=interfaces_group.size(); i<is; ++i ){
155 //FaceGroup face_group = interfaces_group[i];
156 TiedInterface::PartitionConstraintBase* c = TiedInterface::createConstraint(m_mesh, interfaces_group);
157 m_tied_constraint = c;
158 IMeshPartitionConstraintMng* pcmng = m_mesh->partitionConstraintMng();
159 pcmng->addConstraint(c);
160 pcmng->computeAndApplyConstraints();
161 //}
162 cells_owner.synchronize();
163 m_mesh->utilities()->changeOwnersFromCells();
164 m_mesh->setDynamic(true);
165 m_mesh->exchangeItems();
166 // Indicates that the initial partitioning has been performed
167 c->setInitialRepartition(false);
168 }
169 for (Integer i = 0, is = interfaces_group.size(); i < is; ++i) {
170 FaceGroup face_group = interfaces_group[i];
171 info() << " Semi-conform interface name=" << face_group.name();
172 TiedInterface* tied_interface = new TiedInterface(m_mesh);
173 if (planar_tolerance_list[i] > 0)
174 tied_interface->setPlanarTolerance(planar_tolerance_list[i]);
175 tied_interface->build(face_group, is_structured_list[i]);
176 //if (is_structured_list[i]){
177 //_applyTiedInterfaceStructuration(tied_interface);
178 //}
179 m_true_tied_interfaces.add(tied_interface);
180 m_tied_interfaces.add(tied_interface);
181 face_family.applyTiedInterface(tied_interface);
182 }
183
184 face_family.endUpdate();
185 face_family.prepareForDump();
186 }
187 prepareTiedInterfacesForDump();
188}
189
190/*---------------------------------------------------------------------------*/
191/*---------------------------------------------------------------------------*/
192
193void TiedInterfaceMng::
194prepareTiedInterfacesForDump()
195{
196 Integer nb_tied_interface = m_tied_interfaces.count();
197 m_tied_interface_face_groups.resize(nb_tied_interface * 2);
198
199 Integer total_nb_node = 0;
200 Integer total_nb_face = 0;
201 Integer nb_tied_node_per_interface = 0;
202 Integer nb_tied_face_per_interface = 0;
203 for (Integer i = 0; i < nb_tied_interface; ++i) {
204 ITiedInterface* ti = m_tied_interfaces[i];
205
206 TiedInterfaceNodeList nodes = ti->tiedNodes();
207 nb_tied_node_per_interface += nodes.dim1Size();
208 for (Integer zz = 0, zs = nodes.dim1Size(); zz < zs; ++zz)
209 total_nb_node += nodes[zz].size();
210
211 TiedInterfaceFaceList faces = ti->tiedFaces();
212 nb_tied_face_per_interface += faces.dim1Size();
213 for (Integer zz = 0, zs = faces.dim1Size(); zz < zs; ++zz)
214 total_nb_face += faces[zz].size();
215 }
216
217 Integer items_info_size = total_nb_node + total_nb_face +
218 nb_tied_node_per_interface + nb_tied_face_per_interface + nb_tied_interface * 2;
219
220 Integer nodes_iso_size = total_nb_node;
221
222 m_tied_interface_items_info.resize(items_info_size);
223 m_tied_interface_nodes_iso.resize(nodes_iso_size);
224
225 Integer items_info_index = 0;
226 Integer nodes_iso_index = 0;
227 for (Integer i = 0; i < nb_tied_interface; ++i) {
228 ITiedInterface* ti = m_tied_interfaces[i];
229
230 TiedInterfaceNodeList nodes = ti->tiedNodes();
231 Integer nb_node = nodes.dim1Size();
232 m_tied_interface_items_info[items_info_index] = nb_node;
233 ++items_info_index;
234 for (Integer zz = 0; zz < nb_node; ++zz) {
235 Integer nb_node2 = nodes[zz].size();
236 m_tied_interface_items_info[items_info_index] = nb_node2;
237 ++items_info_index;
238 }
239
240 for (Integer zz = 0; zz < nb_node; ++zz) {
241 Integer nb_node2 = nodes[zz].size();
242 for (Integer zz2 = 0; zz2 < nb_node2; ++zz2) {
243 m_tied_interface_items_info[items_info_index] = nodes[zz][zz2].node().uniqueId().asInt64();
244 ++items_info_index;
245 m_tied_interface_nodes_iso[nodes_iso_index] = nodes[zz][zz2].isoCoordinates();
246 ++nodes_iso_index;
247 }
248 }
249
250 TiedInterfaceFaceList faces = ti->tiedFaces();
251 Integer nb_face = faces.dim1Size();
252 m_tied_interface_items_info[items_info_index] = nb_face;
253 ++items_info_index;
254 for (Integer zz = 0; zz < nb_face; ++zz) {
255 Integer nb_face2 = faces[zz].size();
256 m_tied_interface_items_info[items_info_index] = nb_face2;
257 ++items_info_index;
258 }
259
260 for (Integer zz = 0; zz < nb_face; ++zz) {
261 Integer nb_face2 = faces[zz].size();
262 for (Integer zz2 = 0; zz2 < nb_face2; ++zz2) {
263 m_tied_interface_items_info[items_info_index] = faces[zz][zz2].face().uniqueId().asInt64();
264 ++items_info_index;
265 }
266 }
267 }
268 debug() << "ITEMS_INFO_INDEX=" << items_info_index << " N=" << items_info_size;
269 debug() << "NODES_ISO_INDEX=" << nodes_iso_index << " N=" << nodes_iso_size;
270 if (nodes_iso_index != nodes_iso_size)
271 throw InternalErrorException(A_FUNCINFO, "Bad size for 'nodes_iso_index'");
272 if (items_info_index != items_info_size)
273 throw InternalErrorException(A_FUNCINFO, "Bad size for 'items_info_index'");
274 for (Integer i = 0; i < nb_tied_interface; ++i) {
275 ITiedInterface* ti = m_tied_interfaces[i];
276 m_tied_interface_face_groups[(i * 2)] = ti->masterInterfaceName();
277 m_tied_interface_face_groups[(i * 2) + 1] = ti->slaveInterfaceName();
278 }
279}
280
281/*---------------------------------------------------------------------------*/
282/*---------------------------------------------------------------------------*/
283
284void TiedInterfaceMng::
285readTiedInterfacesFromDump()
286{
287 _deleteTiedInterfaces();
288 Integer nb_tied_interface = m_tied_interface_face_groups.size() / 2;
289
290 Integer items_info_index = 0;
291 Integer nodes_iso_index = 0;
292
293 IItemFamily* node_family = m_mesh->nodeFamily();
294 FaceFamily& face_family = m_mesh->trueFaceFamily();
295 NodeInfoListView nodes_internal(node_family);
296 FaceInfoListView faces_internal(&face_family);
297 UniqueArray<TiedNode> nodes;
298 UniqueArray<TiedFace> faces;
299
300 for (Integer i = 0; i < nb_tied_interface; ++i) {
301 TiedInterface* tied_interface = new TiedInterface(m_mesh);
302 String master_group_name = m_tied_interface_face_groups[(i * 2)];
303 String slave_group_name = m_tied_interface_face_groups[(i * 2) + 1];
304 tied_interface->reload(&face_family, master_group_name, slave_group_name);
305 FaceGroup master_group = tied_interface->masterInterface();
306 FaceGroup slave_group = tied_interface->slaveInterface();
307 m_tied_interfaces.add(tied_interface);
308 m_true_tied_interfaces.add(tied_interface);
309
310 Integer nb_node = arcaneCheckArraySize(m_tied_interface_items_info[items_info_index]);
311 ++items_info_index;
312 IntegerUniqueArray items_size(nb_node);
313 for (Integer zz = 0; zz < nb_node; ++zz) {
314 Integer nb_node2 = arcaneCheckArraySize(m_tied_interface_items_info[items_info_index]);
315 ++items_info_index;
316 items_size[zz] = nb_node2;
317 }
318 tied_interface->resizeNodes(items_size);
319 Int32UniqueArray local_ids;
320 for (Integer zz = 0; zz < nb_node; ++zz) {
321 Integer nb_node2 = items_size[zz];
322 nodes.clear();
323 local_ids.resize(nb_node2);
324 Int64ConstArrayView unique_ids(nb_node2, &m_tied_interface_items_info[items_info_index]);
325 node_family->itemsUniqueIdToLocalId(local_ids, unique_ids, true);
326 items_info_index += nb_node2;
327
328 for (Integer zz2 = 0; zz2 < nb_node2; ++zz2) {
329 Node node(nodes_internal[local_ids[zz2]]);
330 nodes.add(TiedNode(zz2, node, m_tied_interface_nodes_iso[nodes_iso_index]));
331 ++nodes_iso_index;
332 }
333 tied_interface->setNodes(zz, nodes);
334 }
335
336 Integer nb_face = arcaneCheckArraySize(m_tied_interface_items_info[items_info_index]);
337 ++items_info_index;
338 items_size.resize(nb_face);
339 for (Integer zz = 0; zz < nb_face; ++zz) {
340 Integer nb_face2 = arcaneCheckArraySize(m_tied_interface_items_info[items_info_index]);
341 ++items_info_index;
342 items_size[zz] = nb_face2;
343 }
344 tied_interface->resizeFaces(items_size);
345 UniqueArray<TiedFace> faces2;
346 for (Integer zz = 0; zz < nb_face; ++zz) {
347 Integer nb_face2 = items_size[zz];
348 faces2.clear();
349 local_ids.resize(nb_face2);
350 Int64ConstArrayView unique_ids(nb_face2, &m_tied_interface_items_info[items_info_index]);
351 face_family.itemsUniqueIdToLocalId(local_ids, unique_ids, true);
352 items_info_index += nb_face2;
353 for (Integer zz2 = 0; zz2 < nb_face2; ++zz2) {
354 Face face(faces_internal[local_ids[zz2]]);
355 faces2.add(TiedFace(zz2, face));
356 }
357 tied_interface->setFaces(zz, faces2);
358 }
359 info() << "Read interface nb_face=" << nb_face << " nb_node=" << nb_node;
360 }
361
362 // Rebuild constraints if necessary
363 if (!m_tied_constraint) {
364 info() << "Rebuilding tied interface constraints";
365 UniqueArray<FaceGroup> interface_groups;
366 for (Integer i = 0, n = m_true_tied_interfaces.size(); i < n; ++i)
367 interface_groups.add(m_true_tied_interfaces[i]->slaveInterface());
368
369 Integer nb_interface = interface_groups.size();
370 if (nb_interface != 0) {
371 TiedInterface::PartitionConstraintBase* c = TiedInterface::createConstraint(m_mesh, interface_groups);
372 m_tied_constraint = c;
373 IMeshPartitionConstraintMng* pcmng = m_mesh->partitionConstraintMng();
374 pcmng->addConstraint(c);
375 // Indicates that the initial partitioning has been performed
376 c->setInitialRepartition(false);
377 }
378 }
379}
380
381/*---------------------------------------------------------------------------*/
382/*---------------------------------------------------------------------------*/
383
384void TiedInterfaceMng::
385_applyTiedInterfaceStructuration(TiedInterface* tied_interface)
386{
387 // Assumes the interface is structured MxN.
388 // To find M, iterate through the list of tied nodes and detect
389 // when a node has an iso.y coordinate lower than that of the
390 // previous node. This means we are changing lines in
391 // the structure.
392 // Once MxN is known, normalize the iso coordinates so that
393 // they correspond to this structure
394
395 TiedInterfaceNodeList nodes = tied_interface->tiedNodes();
396 for (Integer zz = 0, zs = nodes.dim1Size(); zz < zs; ++zz) {
397 Integer current_nb_node = nodes[zz].size();
398 Real old_y = -10.0;
399 Integer computed_m = 0;
400 for (Integer i = 0; i < current_nb_node; ++i) {
401 Real2 iso_val = nodes[zz][i].isoCoordinates();
402 info() << "ISO zz=" << zz << " i=" << i << " v=" << iso_val << " old=" << old_y;
403 if (iso_val.y > old_y) {
404 ++computed_m;
405 }
406 else {
407 info() << "COMPUTED M = " << computed_m;
408 computed_m = 0;
409 }
410 old_y = iso_val.y;
411 }
412 }
413}
414
415/*---------------------------------------------------------------------------*/
416/*---------------------------------------------------------------------------*/
417
418void TiedInterfaceMng::
419_deleteTiedInterfaces()
420{
421 for (Integer i = 0, is = m_tied_interfaces.count(); i < is; ++i)
422 delete m_tied_interfaces[i];
423 m_tied_interfaces.clear();
424 m_true_tied_interfaces.clear();
425}
426
427/*---------------------------------------------------------------------------*/
428/*---------------------------------------------------------------------------*/
429
430} // namespace Arcane::mesh
431
432/*---------------------------------------------------------------------------*/
433/*---------------------------------------------------------------------------*/
#define ENUMERATE_ITEM(name, group)
Generic enumerator for a node group.
Int32 dim1Size() const
Number of elements in the first dimension.
const String & name() const
Group name.
Definition ItemGroup.h:81
Implementation of a mesh.
Definition DynamicMesh.h:98
ItemGroupT< Face > FaceGroup
Group of faces.
Definition ItemTypes.h:179
ItemVariableScalarRefT< Int32 > VariableItemInt32
32-bit integer type quantity
Integer arcaneCheckArraySize(unsigned long long size)
Checks that size can be converted into an 'Integer' to serve as the size of an array....
Int32 Integer
Type representing an integer.
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:480
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
Definition UtilsTypes.h:341
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
Definition UtilsTypes.h:347