Arcane  4.1.11.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
UnstructuredMeshUtilities.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/* UnstructuredMeshUtilities.cc (C) 2000-2025 */
9/* */
10/* Utility functions for a mesh. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/InvalidArgumentException.h"
15#include "arcane/utils/FatalErrorException.h"
16#include "arcane/utils/ParallelFatalErrorException.h"
17#include "arcane/utils/ArgumentException.h"
18#include "arcane/utils/Array.h"
19#include "arcane/utils/Real3.h"
20#include "arcane/utils/HashTableMap.h"
21#include "arcane/utils/OStringStream.h"
22#include "arcane/utils/ScopedPtr.h"
23#include "arcane/utils/StringBuilder.h"
24#include "arcane/utils/CheckedConvert.h"
25#include "arcane/utils/PlatformUtils.h"
26#include "arcane/utils/SmallArray.h"
27#include "arcane/utils/NotImplementedException.h"
28
29#include "arcane/core/IMesh.h"
30#include "arcane/core/IMeshWriter.h"
31#include "arcane/core/IParallelMng.h"
33#include "arcane/core/IItemFamily.h"
34#include "arcane/core/ItemPrinter.h"
35#include "arcane/core/VariableTypes.h"
36#include "arcane/core/ItemPairGroup.h"
37#include "arcane/core/ISubDomain.h"
38#include "arcane/core/ServiceBuilder.h"
39#include "arcane/core/IParallelReplication.h"
40#include "arcane/core/Timer.h"
41#include "arcane/core/IMeshPartitioner.h"
42#include "arcane/core/IPrimaryMesh.h"
43#include "arcane/core/IMeshChecker.h"
44#include "arcane/core/IItemFamilyNetwork.h"
45#include "arcane/core/NodesOfItemReorderer.h"
46
47#include "arcane/mesh/UnstructuredMeshUtilities.h"
48#include "arcane/ConnectivityItemVector.h"
49#include "arcane/mesh/NewItemOwnerBuilder.h"
50#include "arcane/mesh/ParticleFamily.h"
51#include "arcane/mesh/GraphDoFs.h"
52#include "arcane/mesh/BasicItemPairGroupComputeFunctor.h"
53#include "arcane/mesh/MeshNodeMerger.h"
54#include "arcane/mesh/ConnectivityNewWithDependenciesTypes.h"
55#include "arcane/mesh/ItemsOwnerBuilder.h"
56
57#include <algorithm>
58
59/*---------------------------------------------------------------------------*/
60/*---------------------------------------------------------------------------*/
61
62namespace Arcane
63{
64
65/*---------------------------------------------------------------------------*/
66/*---------------------------------------------------------------------------*/
67
68UnstructuredMeshUtilities::
69UnstructuredMeshUtilities(IMesh* mesh)
70: TraceAccessor(mesh->traceMng())
71, m_mesh(mesh)
72, m_compute_adjacency_functor(new BasicItemPairGroupComputeFunctor(traceMng()))
73{
74}
75
76/*---------------------------------------------------------------------------*/
77/*---------------------------------------------------------------------------*/
78
79UnstructuredMeshUtilities::
80~UnstructuredMeshUtilities()
81{
82 delete m_compute_adjacency_functor;
83}
84
85/*---------------------------------------------------------------------------*/
86/*---------------------------------------------------------------------------*/
87
88void UnstructuredMeshUtilities::
89changeOwnersFromCells()
90{
91 // We assume that we know the new owners of the cells, which
92 // are found in cells_owner. We must
93 // now determine the new owners of the nodes and
94 // faces. Pending an algorithm that better balances
95 // messages, we apply the following:
96 // - each subdomain is responsible for determining the new
97 // owner of the nodes and faces belonging to it.
98 // - for nodes, the new owner is the new owner
99 // of the cell connected to this node whose uniqueId() is the smallest.
100 // - for faces, the new owner is the new owner
101 // of the cell behind this face if it is an internal face
102 // and of the connected cell if it is a boundary face.
103 // - for dual nodes, the new owner is the new owner
104 // of the cell connected to the dual element
105 // - for links, the new owner is the new owner
106 // of the cell connected to the first dual node, that is, the owner
107 // of the link's first dual node
108
109 // Utility for assigning owners to items
110 mesh::NewItemOwnerBuilder owner_builder;
111
112 VariableItemInt32& nodes_owner(m_mesh->nodeFamily()->itemsNewOwner());
113 VariableItemInt32& edges_owner(m_mesh->edgeFamily()->itemsNewOwner());
114 VariableItemInt32& faces_owner(m_mesh->faceFamily()->itemsNewOwner());
115 VariableItemInt32& cells_owner(m_mesh->cellFamily()->itemsNewOwner());
116
117 // Determine the new owners of nodes
118 {
119 ENUMERATE_NODE (i_node, m_mesh->ownNodes()) {
120 const Node node = *i_node;
121 const Cell cell = owner_builder.connectedCellOfItem(node);
122#ifdef ARCANE_DEBUG_LOAD_BALANCING
123 if (nodes_owner[node] != cells_owner[cell]) {
124 info() << "New owner for node: " << ItemPrinter(node) << " cell=" << ItemPrinter(cell)
125 << " old_owner=" << nodes_owner[node]
126 << " current_cell_owner=" << cell.owner()
127 << " new_owner=" << cells_owner[cell];
128 }
129#endif /* ARCANE_DEBUG_LOAD_BALANCING */
130 nodes_owner[node] = cells_owner[cell];
131 }
132 nodes_owner.synchronize();
133 }
134
135 // Determine the new owners of edges
136 {
137 ENUMERATE_EDGE (i_edge, m_mesh->ownEdges()) {
138 const Edge edge = *i_edge;
139 const Cell cell = owner_builder.connectedCellOfItem(edge);
140#ifdef ARCANE_DEBUG_LOAD_BALANCING
141 if (edges_owner[edge] != cells_owner[cell]) {
142 info() << "New owner for edge: " << ItemPrinter(edge) << " cell=" << ItemPrinter(cell)
143 << " old_owner=" << edges_owner[edge]
144 << " current_cell_owner=" << cell.owner()
145 << " new_owner=" << cells_owner[cell];
146 }
147#endif /* ARCANE_DEBUG_LOAD_BALANCING */
148 edges_owner[edge] = cells_owner[cell];
149 }
150 edges_owner.synchronize();
151 }
152
153 // Determine the new owners of faces
154 {
155 ENUMERATE_FACE (i_face, m_mesh->ownFaces()) {
156 const Face face = *i_face;
157 const Cell cell = owner_builder.connectedCellOfItem(face);
158 faces_owner[face] = cells_owner[cell];
159 }
160 faces_owner.synchronize();
161 }
162
163 // Determine the new owners of particles
164 // Particles have the same owner as the cell they are in.
165 for (IItemFamily* family : m_mesh->itemFamilies()) {
166 if (family->itemKind() != IK_Particle)
167 continue;
168 // Position the new owners of particles
169 VariableItemInt32& particles_owner(family->itemsNewOwner());
170 ENUMERATE_PARTICLE (i_particle, family->allItems()) {
171 Particle particle = *i_particle;
172 particles_owner[particle] = cells_owner[particle.cell()];
173 }
174 }
175
176 // GraphOnDoF
177 if (m_mesh->itemFamilyNetwork()) {
178 // Dof with Mesh Item connectivity
179 for (IItemFamily* family : m_mesh->itemFamilies()) {
180 if (family->itemKind() != IK_DoF || family->name() == mesh::GraphDoFs::linkFamilyName())
181 continue;
182 VariableItemInt32& dofs_new_owner(family->itemsNewOwner());
183 std::array<Arcane::eItemKind, 5> dualitem_kinds = { IK_Cell, IK_Face, IK_Edge, IK_Node, IK_Particle };
184 for (auto dualitem_kind : dualitem_kinds) {
185 IItemFamily* dualitem_family = dualitem_kind == IK_Particle ? m_mesh->findItemFamily(dualitem_kind, mesh::ParticleFamily::defaultFamilyName(), false) : m_mesh->itemFamily(dualitem_kind);
186 if (dualitem_family) {
187
188 VariableItemInt32& dualitems_new_owner(dualitem_family->itemsNewOwner());
189 auto connectivity_name = mesh::connectivityName(family, dualitem_family);
190 bool is_dof2dual = true;
191 auto connectivity = m_mesh->itemFamilyNetwork()->getConnectivity(family, dualitem_family, connectivity_name);
192 if (!connectivity) {
193 connectivity = m_mesh->itemFamilyNetwork()->getConnectivity(dualitem_family, family, connectivity_name);
194 is_dof2dual = false;
195 }
196
197 if (connectivity) {
198 ConnectivityItemVector accessor(connectivity);
199 if (is_dof2dual) {
200 ENUMERATE_ITEM (item, family->allItems().own()) {
201 auto connected_items = accessor.connectedItems(ItemLocalId(item));
202 if (connected_items.size() > 0) {
203 dofs_new_owner[*item] = dualitems_new_owner[connected_items[0]];
204 }
205 }
206 }
207 else {
208 ENUMERATE_ITEM (item, dualitem_family->allItems()) {
209 ENUMERATE_ITEM (connected_item, accessor.connectedItems(ItemLocalId(item))) {
210 dofs_new_owner[*connected_item] = dualitems_new_owner[*item];
211 }
212 }
213 }
214 }
215 }
216 }
217 }
218 // Dof with DoF connectivity
219 IItemFamily* links_family = m_mesh->findItemFamily(IK_DoF, mesh::GraphDoFs::linkFamilyName(), false);
220 if (links_family) {
221 VariableItemInt32& links_new_owner(links_family->itemsNewOwner());
222 IItemFamily* dualnodes_family = m_mesh->findItemFamily(IK_DoF, mesh::GraphDoFs::dualNodeFamilyName(), false);
223 if (dualnodes_family) {
224 VariableItemInt32& dualnodes_new_owner(dualnodes_family->itemsNewOwner());
225 auto connectivity_name = mesh::connectivityName(links_family, dualnodes_family);
226 auto connectivity = m_mesh->itemFamilyNetwork()->getConnectivity(links_family, dualnodes_family, connectivity_name);
227 if (connectivity) {
228 ConnectivityItemVector accessor(connectivity);
229 ENUMERATE_ITEM (item, links_family->allItems().own()) {
230 auto connected_items = accessor.connectedItems(ItemLocalId(item));
231 if (connected_items.size() > 0) {
232 links_new_owner[*item] = dualnodes_new_owner[connected_items[0]];
233 }
234 }
235 }
236 }
237 }
238 }
239}
240
241/*---------------------------------------------------------------------------*/
242/*---------------------------------------------------------------------------*/
243
244void UnstructuredMeshUtilities::
245localIdsFromConnectivity(eItemKind item_kind,
246 IntegerConstArrayView items_nb_node,
247 Int64ConstArrayView items_connectivity,
248 Int32ArrayView local_ids,
249 bool allow_null)
250{
251 Integer nb_item = items_nb_node.size();
252 if (item_kind != IK_Face && item_kind != IK_Cell)
253 throw InvalidArgumentException(A_FUNCINFO, "item_kind",
254 "IK_Cell or IK_Face expected",
255 (int)item_kind);
256 if (item_kind == IK_Cell)
257 throw NotImplementedException(A_FUNCINFO, "not implemented for cells");
258
259 if (nb_item != local_ids.size())
260 throw InvalidArgumentException(A_FUNCINFO, "local_ids",
261 "Size different from 'items_nb_node'",
262 (int)item_kind);
263
264 Integer item_connectivity_index = 0;
266 buf.reserve(256);
267 ItemInternalList nodes(m_mesh->itemsInternal(IK_Node));
268 for (Integer i = 0; i < nb_item; ++i) {
269 Integer current_nb_node = items_nb_node[i];
270 Int64ConstArrayView current_nodes(current_nb_node, items_connectivity.data() + item_connectivity_index);
271 item_connectivity_index += current_nb_node;
272 if (item_kind == IK_Face) {
273 buf.resize(current_nb_node);
274 mesh_utils::reorderNodesOfFace(current_nodes, buf);
275 Int64 first_node_uid = buf[0];
276 Int64ArrayView first_node_uid_array(1, &first_node_uid);
277 Int32 first_node_lid = CheckedConvert::toInt32(buf[0]);
278 Int32ArrayView first_node_lid_array(1, &first_node_lid);
279 m_mesh->nodeFamily()->itemsUniqueIdToLocalId(first_node_lid_array, first_node_uid_array, !allow_null);
280 if (first_node_lid == NULL_ITEM_LOCAL_ID) {
281 if (allow_null) {
282 local_ids[i] = NULL_ITEM_LOCAL_ID;
283 }
284 else {
285 StringBuilder sb("Face with nodes (");
286 for (Integer j = 0; j < current_nb_node; ++j) {
287 if (j != 0)
288 sb += " ";
289 sb += current_nodes[j];
290 }
291 sb += ") not found (first node ";
292 sb += first_node_uid;
293 sb += " not found)";
295 }
296 continue;
297 }
298
299 Node node(nodes[first_node_lid]);
300 Face face(mesh_utils::getFaceFromNodesUnique(node, buf));
301 if (face.null()) {
302 if (allow_null) {
303 local_ids[i] = NULL_ITEM_LOCAL_ID;
304 }
305 else {
306 StringBuilder sb("Face with nodes (");
307 for (Integer j = 0; j < current_nb_node; ++j) {
308 if (j != 0)
309 sb += " ";
310 sb += current_nodes[j];
311 }
312 sb += ") not found";
314 }
315 }
316 else
317 local_ids[i] = face.localId();
318 }
319 }
320}
321
322/*---------------------------------------------------------------------------*/
323/*---------------------------------------------------------------------------*/
324
325void UnstructuredMeshUtilities::
326getFacesLocalIdFromConnectivity(ConstArrayView<ItemTypeId> items_type,
327 ConstArrayView<Int64> items_connectivity,
328 ArrayView<Int32> local_ids,
329 bool allow_null)
330{
331 Int32 nb_item = items_type.size();
332
333 if (nb_item != local_ids.size())
334 throw InvalidArgumentException(A_FUNCINFO, "local_ids",
335 "Size different from 'items_type'");
336
337 Int32 item_connectivity_index = 0;
338 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
339 NodesOfItemReorderer face_reorderer(item_type_mng);
340
341 ItemInternalList nodes(m_mesh->itemsInternal(IK_Node));
342 for (Integer i = 0; i < nb_item; ++i) {
343 ItemTypeId current_type_id = items_type[i];
344 Int32 current_nb_node = item_type_mng->typeFromId(current_type_id)->nbLocalNode();
345 Int64ConstArrayView current_nodes(current_nb_node, items_connectivity.data() + item_connectivity_index);
346 item_connectivity_index += current_nb_node;
347
348 face_reorderer.reorder(current_type_id, current_nodes);
349 ConstArrayView<Int64> buf(face_reorderer.sortedNodes());
350 Int64 first_node_uid = buf[0];
351 Int64ArrayView first_node_uid_array(1, &first_node_uid);
352 Int32 first_node_lid = CheckedConvert::toInt32(buf[0]);
353 Int32ArrayView first_node_lid_array(1, &first_node_lid);
354 m_mesh->nodeFamily()->itemsUniqueIdToLocalId(first_node_lid_array, first_node_uid_array, !allow_null);
355 if (first_node_lid == NULL_ITEM_LOCAL_ID) {
356 if (allow_null) {
357 local_ids[i] = NULL_ITEM_LOCAL_ID;
358 }
359 else {
360 StringBuilder sb("Face with nodes (");
361 for (Integer j = 0; j < current_nb_node; ++j) {
362 if (j != 0)
363 sb += " ";
364 sb += current_nodes[j];
365 }
366 sb += ") not found (first node ";
367 sb += first_node_uid;
368 sb += " not found)";
370 }
371 continue;
372 }
373
374 Node node(nodes[first_node_lid]);
375 Face face(MeshUtils::getFaceFromNodesUnique(node, buf));
376 if (face.null()) {
377 if (allow_null) {
378 local_ids[i] = NULL_ITEM_LOCAL_ID;
379 }
380 else {
381 StringBuilder sb("Face with nodes (");
382 for (Integer j = 0; j < current_nb_node; ++j) {
383 if (j != 0)
384 sb += " ";
385 sb += current_nodes[j];
386 }
387 sb += ") not found";
389 }
390 }
391 else
392 local_ids[i] = face.localId();
393 }
394}
395
396/*---------------------------------------------------------------------------*/
397/*---------------------------------------------------------------------------*/
398
399Real3 UnstructuredMeshUtilities::
400_round(Real3 value)
401{
402 Real3 rvalue = value;
403 // Avoid numerical rounding issues
404 if (math::isNearlyZero(value.x))
405 rvalue.x = 0.0;
406 if (math::isNearlyZero(value.y))
407 rvalue.y = 0.0;
408 if (math::isNearlyZero(value.z))
409 rvalue.z = 0.0;
410
411 if (math::isNearlyEqual(value.x, 1.0))
412 rvalue.x = 1.0;
413 if (math::isNearlyEqual(value.y, 1.0))
414 rvalue.y = 1.0;
415 if (math::isNearlyEqual(value.z, 1.0))
416 rvalue.z = 1.0;
417
418 if (math::isNearlyEqual(value.x, -1.0))
419 rvalue.x = -1.0;
420 if (math::isNearlyEqual(value.y, -1.0))
421 rvalue.y = -1.0;
422 if (math::isNearlyEqual(value.z, -1.0))
423 rvalue.z = -1.0;
424
425 return rvalue;
426}
427
428/*---------------------------------------------------------------------------*/
429/*---------------------------------------------------------------------------*/
430
431Real3 UnstructuredMeshUtilities::
432computeNormal(const FaceGroup& face_group, const VariableNodeReal3& nodes_coord)
433{
434 String func_name = "UnstructuredMeshUtilities::computeNormal";
435 IParallelMng* pm = m_mesh->parallelMng();
436 Integer rank = pm->commRank();
437 //Integer nb_item = face_group.size();
438 Integer nb_node = 0;
439 Integer mesh_dimension = m_mesh->dimension();
440 // 'global_normal' and 'total_global_normal' are used to determine
441 // a direction for the surface assuming it is
442 // an external surface. The direction is then used to orient
443 // the calculated normal in the outward normal direction.
444 Real3 global_normal = Real3::null();
445 Real nb_global_normal_used_node = 0.0;
446 ENUMERATE_FACE (iface, face_group) {
447 Face face = *iface;
448 Integer face_nb_node = face.nbNode();
449 nb_node += face_nb_node;
450
451 if (face.isSubDomainBoundary() && face.isOwn()) {
452 Real3 face_normal;
453 if (mesh_dimension == 3) {
454 Real3 v1 = nodes_coord[face.node(1)] - nodes_coord[face.node(0)];
455 Real3 v2 = nodes_coord[face.node(2)] - nodes_coord[face.node(0)];
456 face_normal = math::vecMul(v1, v2);
457 }
458 else if (mesh_dimension == 2) {
459 Real3 dir = nodes_coord[face.node(0)] - nodes_coord[face.node(1)];
460 face_normal.x = -dir.y;
461 face_normal.y = dir.x;
462 face_normal.z = 0.0;
463 }
464 if (face.boundaryCell() == face.frontCell())
465 face_normal = -face_normal;
466 //info() << "ADD NORMAL normal=" << face_normal;
467 global_normal = global_normal + face_normal;
468 nb_global_normal_used_node += 1.0;
469 }
470 }
471 // The algorithm attempts to determine the nodes at the ends of the surface
472 // It assumes these are nodes that belong to only one
473 // face of the surface. This works well if all faces have at least
474 // four edges. If there are triangles, we assume this is not
475 // everywhere, and in this case, we have at least two known extreme nodes.
476 typedef HashTableMapT<Int32, Int32> NodeOccurenceMap;
477 // Range in the table for each node the number of surface faces
478 // to which it is connected.
479 NodeOccurenceMap nodes_occurence(nb_node * 2, true, nb_node);
480 ENUMERATE_FACE (iface, face_group) {
481 Face face = *iface;
482 for (NodeLocalId inode : face.nodeIds()) {
483 NodeOccurenceMap::Data* v = nodes_occurence.lookup(inode);
484 if (v)
485 ++v->value();
486 else {
487 //info() << " ADD NODE " << ItemPrinter(*inode) << " coord=" << nodes_coord[inode];
488 nodes_occurence.add(inode, 1);
489 }
490 }
491 }
492 UniqueArray<Node> single_nodes;
493 NodeLocalIdToNodeConverter nodes_internal(m_mesh->nodeFamily());
494 nodes_occurence.each([&](NodeOccurenceMap::Data* d) {
495 if (d->value() == 1) {
496 Node node = nodes_internal[d->key()];
497 // In parallel, only process the nodes that belong to us
498 if (node.owner() == rank) {
499 single_nodes.add(node);
500 //info() << "SINGLE NODE OWNER lid=" << d->key() << " " << ItemPrinter(node)
501 // << " coord=" << nodes_coord[node];
502 }
503 }
504 });
505 // Each sub-domain collects the coordinates of the nodes from the other sub-domains
506 Integer nb_single_node = single_nodes.size();
507 //info() << "NB SINGLE NODE= " << nb_single_node;
508 Integer total_nb_single_node = pm->reduce(Parallel::ReduceSum, nb_single_node);
509 Real3 total_global_normal;
510 {
511 Real all_min = 0.0;
512 Real all_max = 0.0;
513 Real all_sum = 0.0;
514 Int32 min_rank = -1;
515 Int32 max_rank = -1;
516 pm->computeMinMaxSum(nb_global_normal_used_node, all_min, all_max, all_sum, min_rank, max_rank);
517 Real3 buf;
518 if (max_rank == rank) {
519 // I am the one with the farthest point. I send it to the others.
520 buf = global_normal;
521 }
522 pm->broadcast(Real3ArrayView(1, &buf), max_rank);
523 total_global_normal = buf;
524 }
525
526 info() << "TOTAL SINGLE NODE= " << total_nb_single_node << " surface=" << face_group.name()
527 << " global_normal = " << total_global_normal;
528 if (total_nb_single_node < 2) {
529 ARCANE_FATAL("not enough nodes connected to only one face");
530 }
531 Real3UniqueArray coords(nb_single_node);
532 for (Integer i = 0; i < nb_single_node; ++i) {
533 coords[i] = nodes_coord[single_nodes[i]];
534 }
535 //Array<Real> all_nodes_coord_real;
536 UniqueArray<Real3> all_nodes_coord;
537 pm->allGatherVariable(coords, all_nodes_coord);
538 //info() << " ALL NODES COORD n=" << all_nodes_coord_real.size();
539 //Array<Real3> all_nodes_coord(total_nb_single_node);
540 Real3 barycentre = Real3::null();
541 for (Integer i = 0; i < total_nb_single_node; ++i) {
542 barycentre += all_nodes_coord[i];
543 }
544 barycentre /= (Real)total_nb_single_node;
545 if (total_nb_single_node == 2 && m_mesh->dimension() == 3) {
546 // We only have two nodes. We need at least a third one to determine
547 // the normal to the plane. For this, each processor searches for the node
548 // on the surface that is farthest from the barycenter of the two nodes already
549 // found. This farthest node will serve as the third point for the
550 // plane.
551 Real max_distance = 0.0;
552 Node farthest_node;
553 Real3 s0 = all_nodes_coord[0];
554 Real3 s1 = all_nodes_coord[1];
555 nodes_occurence.each([&](NodeOccurenceMap::Data* d) {
556 Node node = nodes_internal[d->key()];
557 Real3 coord = nodes_coord[node];
558 // Do not process the two nodes already found
559 if (math::isNearlyEqual(coord, s0))
560 return;
561 if (math::isNearlyEqual(coord, s1))
562 return;
563 Real distance = (coord - barycentre).squareNormL2();
564 if (distance > max_distance) {
565 Real3 normal = math::cross(coord - s0, s1 - s0);
566 // We only take the node if it is not aligned with the other two.
567 if (!math::isNearlyZero(normal.squareNormL2())) {
568 max_distance = distance;
569 farthest_node = node;
570 }
571 }
572 });
573
574 if (!farthest_node.null()) {
575 info() << " FARTHEST NODE= " << ItemPrinter(farthest_node) << " dist=" << max_distance;
576 }
577 {
578 Real3 farthest_coord = _broadcastFarthestNode(max_distance, farthest_node, nodes_coord);
579 info() << " FARTHEST NODE ALL coord=" << farthest_coord;
580 all_nodes_coord.add(farthest_coord);
581 }
582 }
583 // Sort the nodes so that the calculation does not depend on the order of
584 // parallel operations.
585 std::sort(std::begin(all_nodes_coord), std::end(all_nodes_coord));
586 Integer nb_final_node = all_nodes_coord.size();
587 Real3 full_normal = Real3::null();
588 info() << " NB FINAL NODE=" << nb_final_node;
589 for (Integer i = 0; i < nb_final_node; ++i)
590 info() << " NODE=" << all_nodes_coord[i];
591 if (m_mesh->dimension() == 2) {
592 if (nb_final_node != 2) {
593 ARCANE_FATAL("should have 2 border nodes in 2D mesh");
594 }
595 Real3 direction = all_nodes_coord[1] - all_nodes_coord[0];
596 full_normal.x = -direction.y;
597 full_normal.y = direction.x;
598 }
599 else if (m_mesh->dimension() == 3) {
600 //nb_final_node = 3; // We only take the first 3 points.
601 // NOTE: we could take all points, because if the first three are
602 // aligned, the normal will not be correct.
603 // If we take all points, we must ensure they are ordered
604 // such that the normal of three consecutive points is always
605 // in the same direction. This means if we have four points, for example,
606 // that these 4 points form a non-crossed quadrangle (not in the shape
607 // of a butterfly)
608 Real3 first_normal = math::vecMul(all_nodes_coord[2] - all_nodes_coord[0],
609 all_nodes_coord[1] - all_nodes_coord[0]);
610 for (Integer i = 0; i < nb_final_node; ++i) {
611 Real3 s0 = all_nodes_coord[i];
612 Real3 s1 = all_nodes_coord[(i + nb_final_node - 1) % nb_final_node];
613 Real3 s2 = all_nodes_coord[(i + 1) % nb_final_node];
614 Real3 normal = math::vecMul(s2 - s0, s1 - s0);
615 info() << " ADD NORMAL: " << normal;
616 full_normal += normal;
617 info() << " FULL: " << full_normal;
618 }
619 if (math::isNearlyZero(full_normal.squareNormL2()))
620 full_normal = first_normal;
621 }
622 else
623 ARCANE_FATAL("invalid mesh dimension (should be 2 or 3)");
624 Real a = full_normal.normL2();
625 if (math::isZero(a))
626 ARCANE_FATAL("invalid value for normal");
627 full_normal /= a;
628 Real b = total_global_normal.normL2();
629 Real dir = 0.0;
630 info() << " Normal is " << full_normal;
631 if (!math::isZero(b)) {
632 total_global_normal /= b;
633 dir = math::scaMul(full_normal, total_global_normal);
634 if (dir < 0.0)
635 full_normal = -full_normal;
636 }
637 full_normal = _round(full_normal);
638 info() << " Final normal is " << full_normal << " dir=" << dir;
639 return full_normal;
640}
641
642/*---------------------------------------------------------------------------*/
643/*---------------------------------------------------------------------------*/
651Real3 UnstructuredMeshUtilities::
652computeDirection(const NodeGroup& node_group,
653 const VariableNodeReal3& nodes_coord,
654 Real3* n1, Real3* n2)
655{
656 String func_name = "UnstructuredMeshUtilities::computeDirection";
657 IParallelMng* pm = m_mesh->parallelMng();
658 //Integer rank = pm->commRank();
659 //Integer nb_node_own = node_group.own().size();
660 //Integer total_nb_node_own = pm->reduce(Parallel::ReduceSum,nb_node_own);
661 Real3 barycentre = Real3::null();
662 ENUMERATE_NODE (inode, node_group.own()) {
663 barycentre += nodes_coord[inode];
664 }
665 Real r_barycentre[3];
666 r_barycentre[0] = barycentre.x;
667 r_barycentre[1] = barycentre.y;
668 r_barycentre[2] = barycentre.z;
669 RealArrayView rav(3, r_barycentre);
670 pm->reduce(Parallel::ReduceSum, rav);
671 barycentre = Real3(rav[0], rav[1], rav[2]);
672 debug() << " BARYCENTRE COMPUTE DIRECTION = " << barycentre;
673 pm->barrier();
674
675 // Determines the node farthest from the barycenter
676 Real3 first_boundary_coord;
677 {
678 Real max_distance = 0.0;
679 Node farthest_node;
680 ENUMERATE_NODE (inode, node_group.own()) {
681 Node node = *inode;
682 Real3 coord = nodes_coord[node];
683 Real distance = (coord - barycentre).squareNormL2();
684 if (distance > max_distance) {
685 max_distance = distance;
686 farthest_node = node;
687 }
688 }
689 first_boundary_coord = _broadcastFarthestNode(max_distance, farthest_node, nodes_coord);
690 if (n1)
691 *n1 = first_boundary_coord;
692 }
693 Real3 second_boundary_coord;
694 {
695 Real max_distance = 0.0;
696 Node farthest_node;
697 ENUMERATE_NODE (inode, node_group.own()) {
698 Node node = *inode;
699 Real3 coord = nodes_coord[node];
700 Real distance = (coord - first_boundary_coord).squareNormL2();
701 if (distance > max_distance) {
702 max_distance = distance;
703 farthest_node = node;
704 }
705 }
706 second_boundary_coord = _broadcastFarthestNode(max_distance, farthest_node, nodes_coord);
707 if (n2)
708 *n2 = second_boundary_coord;
709 }
710 Real3 direction = second_boundary_coord - first_boundary_coord;
711 Real norm = direction.normL2();
712 if (math::isZero(norm)) {
713 ARCANE_FATAL("Direction is null for group '{0}' first_coord={1} second_coord={2}",
714 node_group.name(), first_boundary_coord, second_boundary_coord);
715 }
716 return direction / norm;
717}
718
719/*---------------------------------------------------------------------------*/
720/*---------------------------------------------------------------------------*/
721
722Real3 UnstructuredMeshUtilities::
723_broadcastFarthestNode(Real distance, const Node& farthest_node,
724 const VariableNodeReal3& nodes_coord)
725{
726 String func_name = "UnstructuredMeshUtilities::_broadcastFarthestNode()";
727 IParallelMng* pm = m_mesh->parallelMng();
728 Integer rank = pm->commRank();
729
730 Real all_min_distance = 0.0;
731 Real all_max_distance = 0.0;
732 Real all_sum_distance = 0.0;
733 Int32 min_rank = -1;
734 Int32 max_rank = -1;
735 pm->computeMinMaxSum(distance, all_min_distance, all_max_distance, all_sum_distance, min_rank, max_rank);
736 Real3 buf;
737 if (!farthest_node.null())
738 debug() << " FARTHEST NODE myself coord=" << nodes_coord[farthest_node]
739 << " distance=" << distance
740 << " rank=" << max_rank
741 << " max_distance=" << all_max_distance;
742 else
743 debug() << " FARTHEST NODE myself coord=none"
744 << " distance=" << distance
745 << " rank=" << max_rank
746 << " max_distance=" << all_max_distance;
747
748 if (max_rank == rank) {
749 if (farthest_node.null())
750 ARCANE_FATAL("can not find farthest node");
751 // I am the one with the farthest point. I send it to the others.
752 buf = nodes_coord[farthest_node];
753 debug() << " I AM FARTHEST NODE ALL coord=" << buf;
754 }
755 pm->broadcast(Real3ArrayView(1, &buf), max_rank);
756 Real3 farthest_coord(buf);
757 debug() << " FARTHEST NODE ALL coord=" << farthest_coord
758 << " rank=" << max_rank
759 << " max_distance=" << all_max_distance;
760 return farthest_coord;
761}
762
763/*---------------------------------------------------------------------------*/
764/*---------------------------------------------------------------------------*/
765
766void UnstructuredMeshUtilities::
767computeAdjency(ItemPairGroup adjency_array, eItemKind link_kind, Integer nb_layer)
768{
769 m_compute_adjacency_functor->computeAdjacency(adjency_array, link_kind, nb_layer);
770}
771
772/*---------------------------------------------------------------------------*/
773/*---------------------------------------------------------------------------*/
774
775bool UnstructuredMeshUtilities::
776writeToFile(const String& file_name, const String& service_name)
777{
778 ServiceBuilder<IMeshWriter> sb(m_mesh->handle());
779 auto mesh_writer = sb.createReference(service_name, SB_AllowNull);
780
781 if (!mesh_writer) {
782 UniqueArray<String> available_names;
783 sb.getServicesNames(available_names);
784 warning() << String::format("The specified service '{0}' to write the mesh is not available."
785 " Valid names are {1}",
786 service_name, available_names);
787 return true;
788 }
789 mesh_writer->writeMeshToFile(m_mesh, file_name);
790 return false;
791}
792
793/*---------------------------------------------------------------------------*/
794/*---------------------------------------------------------------------------*/
795
796void UnstructuredMeshUtilities::
797partitionAndExchangeMeshWithReplication(IMeshPartitionerBase* partitioner,
798 bool initial_partition)
799{
800 IPrimaryMesh* primary_mesh = partitioner->primaryMesh();
801 IMesh* mesh = primary_mesh;
802 if (mesh != this->m_mesh)
803 throw ArgumentException(A_FUNCINFO, "partitioner->mesh() != this->m_mesh");
804
805 IParallelMng* pm = mesh->parallelMng();
806 ITimeStats* ts = pm->timeStats();
808 bool has_replication = pr->hasReplication();
809
810 // In replication mode, only the first replica performs the balancing.
811 // It must then send this mesh information to the others
812 // so that they have the same mesh.
813
814 info() << "Partition start date=" << platform::getCurrentDateTime();
815 if (pr->isMasterRank()) {
816 Timer::Action ts_action1(ts, "MeshPartition", true);
817 info() << "Partitioning the mesh (initial?=" << initial_partition << ")";
818 partitioner->partitionMesh(initial_partition);
819 }
820 else
821 info() << "Waiting for partition information from the master replica";
822
823 if (has_replication) {
824 pm->barrier();
825
826 // Checks that all families are the same.
827 mesh->checker()->checkValidReplication();
828
829 Int32 replica_master_rank = pr->masterReplicationRank();
830 IParallelMng* rep_pm = pr->replicaParallelMng();
831
832 // Only the master replica has the correct owners. It must update
833 // the others from this. To do this, we synchronize
834 // the owners of the meshes and then update the other families
835 // from the mesh owners.
836 {
837 Int32ArrayView owners = mesh->cellFamily()->itemsNewOwner().asArray();
838 rep_pm->broadcast(owners, replica_master_rank);
839 if (!pr->isMasterRank()) {
841 }
842 }
843 }
844 info() << "Partition end date=" << platform::getCurrentDateTime();
845 {
846 Timer::Action ts_action2(ts, "MeshExchange", true);
847 primary_mesh->exchangeItems();
848 }
849 info() << "Exchange end date=" << platform::getCurrentDateTime();
850 partitioner->notifyEndPartition();
851
852 // It must be compacted to return to the same situation as
853 // if we had just read a mesh directly (which performs a prepareForDump()
854 // when calling endAllocate()).
855 // We do this also in case of replication to avoid potential
856 // inconsistencies if later some replicas call this
857 // method and others do not.
858 // TODO: check if it should also be done in case of repartitioning.
859 if (initial_partition || has_replication)
860 mesh->prepareForDump();
861}
862
863/*---------------------------------------------------------------------------*/
864/*---------------------------------------------------------------------------*/
865
866void UnstructuredMeshUtilities::
867mergeNodes(Int32ConstArrayView nodes_local_id,
868 Int32ConstArrayView nodes_to_merge_local_id,
869 bool allow_non_corresponding_face)
870{
871 mesh::MeshNodeMerger merger(m_mesh);
872 merger.mergeNodes(nodes_local_id, nodes_to_merge_local_id, allow_non_corresponding_face);
873}
874
875/*---------------------------------------------------------------------------*/
876/*---------------------------------------------------------------------------*/
877
878void UnstructuredMeshUtilities::
879computeAndSetOwnersForNodes()
880{
881 mesh::ItemsOwnerBuilder owner_builder(m_mesh);
882 owner_builder.computeNodesOwner();
883}
884
885/*---------------------------------------------------------------------------*/
886/*---------------------------------------------------------------------------*/
887
888void UnstructuredMeshUtilities::
889computeAndSetOwnersForEdges()
890{
891 mesh::ItemsOwnerBuilder owner_builder(m_mesh);
892 owner_builder.computeEdgesOwner();
893}
894
895/*---------------------------------------------------------------------------*/
896/*---------------------------------------------------------------------------*/
897
898void UnstructuredMeshUtilities::
899computeAndSetOwnersForFaces()
900{
901 mesh::ItemsOwnerBuilder owner_builder(m_mesh);
902 owner_builder.computeFacesOwner();
903}
904
905/*---------------------------------------------------------------------------*/
906/*---------------------------------------------------------------------------*/
907namespace
908{
909 void _recomputeUniqueIds(IItemFamily* family)
910 {
911 SmallArray<Int64> unique_ids;
912 ENUMERATE_ (ItemWithNodes, iitem, family->allItems()) {
913 ItemWithNodes item = *iitem;
914 Int32 index = 0;
915 unique_ids.resize(item.nbNode());
916 for (Node node : item.nodes()) {
917 unique_ids[index] = node.uniqueId();
918 ++index;
919 }
920 Int64 new_uid = MeshUtils::generateHashUniqueId(unique_ids);
921 item.mutableItemBase().setUniqueId(new_uid);
922 }
924 }
925} // namespace
926
927/*---------------------------------------------------------------------------*/
928/*---------------------------------------------------------------------------*/
929
930void UnstructuredMeshUtilities::
931recomputeItemsUniqueIdFromNodesUniqueId()
932{
933 IMesh* mesh = m_mesh;
935 ITraceMng* tm = mesh->traceMng();
936
937 tm->info() << "Calling RecomputeItemsUniqueIdFromNodesUniqueId()";
938 // First indicate that the nodes have changed to potentially
939 // update the orientation of the faces.
940 mesh->nodeFamily()->notifyItemsUniqueIdChanged();
941 _recomputeUniqueIds(mesh->edgeFamily());
942 _recomputeUniqueIds(mesh->faceFamily());
943 _recomputeUniqueIds(mesh->cellFamily());
944}
945
946/*---------------------------------------------------------------------------*/
947/*---------------------------------------------------------------------------*/
948
949} // End namespace Arcane
950
951/*---------------------------------------------------------------------------*/
952/*---------------------------------------------------------------------------*/
#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.
#define ENUMERATE_FACE(name, group)
Enumérateur générique d'un groupe de faces.
#define ENUMERATE_(type, name, group)
Enumérateur générique d'un groupe d'entité
#define ENUMERATE_PARTICLE(name, group)
Enumérateur générique d'un groupe de particules.
#define ENUMERATE_EDGE(name, group)
Enumérateur générique d'un groupe d'arêtes.
#define ENUMERATE_ITEM(name, group)
Enumérateur générique d'un groupe de noeuds.
#define ENUMERATE_NODE(name, group)
Enumérateur générique d'un groupe de noeuds.
Fonctions utilitaires sur le maillage.
bool reorderNodesOfFace(Int64ConstArrayView before_ids, Int64ArrayView after_ids)
Réordonne les noeuds d'une face.
Integer size() const
Nombre d'éléments du vecteur.
Exception lorsqu'un argument est invalide.
Vue modifiable d'un tableau d'un type T.
constexpr Integer size() const noexcept
Retourne la taille du tableau.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void reserve(Int64 new_capacity)
Réserve le mémoire pour new_capacity éléments.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Maille d'un maillage.
Definition Item.h:1214
Gère la récupération des informations de connectivité.
ItemVectorView connectedItems(ItemLocalId item)
Retourne les entités connectées à item.
Vue constante d'un tableau de type T.
constexpr const_pointer data() const noexcept
Pointeur sur la mémoire allouée.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Arête d'une maille.
Definition Item.h:826
Face d'une maille.
Definition Item.h:964
Cell frontCell() const
Maille devant la face (maille nulle si aucune).
Definition Item.h:1652
bool isSubDomainBoundary() const
Indique si la face est au bord du sous-domaine (i.e nbCell()==1).
Definition Item.h:1061
Cell boundaryCell() const
Maille associée à cette face frontière (maille nulle si aucune).
Definition Item.h:1640
Table de hachage pour tableaux associatifs.
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual void notifyItemsUniqueIdChanged()=0
Notifie que les numéros uniques des entités ont été modifiées.
virtual ItemGroup allItems() const =0
Groupe de toutes les entités.
virtual VariableItemInt32 & itemsNewOwner()=0
Variable contenant le numéro du nouveau sous-domaine propriétaire de l'entité.
Interface d'un partitionneur de maillage.
virtual IPrimaryMesh * primaryMesh()=0
Maillage associé
virtual void partitionMesh(bool initial_partition)=0
virtual void notifyEndPartition()=0
Notification lors de la fin d'un re-partitionnement (après échange des entités).
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual void computeMinMaxSum(char val, char &min_val, char &max_val, char &sum_val, Int32 &min_rank, Int32 &max_rank)=0
Calcule en une opération la somme, le min, le max d'une valeur.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual IParallelReplication * replication() const =0
Informations sur la réplication.
virtual ITimeStats * timeStats() const =0
Gestionnaire de statistiques associé (peut être nul).
virtual void allGatherVariable(ConstArrayView< char > send_buf, Array< char > &recv_buf)=0
Effectue un regroupement sur tous les processeurs.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
virtual void barrier()=0
Effectue une barière.
Informations sur la réplication des sous-domaines en parallèle.
virtual bool hasReplication() const =0
Indique si la réplication est active.
virtual IParallelMng * replicaParallelMng() const =0
Communicateur associé à tous les réplicats représentant un même sous-domaine.
virtual Int32 masterReplicationRank() const =0
Rang dans la réplication du maître.
virtual bool isMasterRank() const =0
Indique si ce rang de réplication est le maître.
virtual void exchangeItems()=0
Change les sous-domaines propriétaires des entités.
Interface gérant les statistiques sur les temps d'exécution.
Definition ITimeStats.h:43
Interface du gestionnaire de traces.
virtual TraceMessage info()=0
Flot pour un message d'information.
Exception lorsqu'une erreur fatale est survenue.
const String & name() const
Nom du groupe.
Definition ItemGroup.h:76
ItemGroup own() const
Groupe équivalent à celui-ci mais contenant uniquement les éléments propres au sous-domaine.
Definition ItemGroup.cc:190
Index d'un Item dans une variable.
Definition ItemLocalId.h:41
Tableau de listes d'entités.
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:34
Type d'une entité (Item).
Definition ItemTypeId.h:32
Integer nbLocalNode() const
Nombre de noeuds de l'entité
Gestionnaire des types d'entités d'un maillage.
Definition ItemTypeMng.h:65
ItemTypeInfo * typeFromId(Integer id) const
Type correspondant au numéro id.
Elément de maillage s'appuyant sur des noeuds (Edge,Face,Cell).
Definition Item.h:736
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:791
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
NodeLocalIdView nodeIds() const
Liste des noeuds de l'entité
Definition Item.h:797
impl::MutableItemBase mutableItemBase() const
Partie interne modifiable de l'entité.
Definition Item.h:380
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:219
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
Definition Item.h:238
constexpr bool null() const
true si l'entité est nul (i.e. non connecté au maillage)
Definition Item.h:216
constexpr bool isOwn() const
true si l'entité est appartient au sous-domaine
Definition Item.h:253
Classe pour convertir un NodeLocalId vers une arête.
Noeud d'un maillage.
Definition Item.h:582
Classe utilitaire pour réordonner les noeuds d'une entité.
Exception lorsqu'une fonction n'est pas implémentée.
Particule.
Definition Item.h:1423
Cell cell() const
Maille à laquelle appartient la particule. Il faut appeler setCell() avant d'appeler cette fonction....
Definition Item.h:1488
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
__host__ __device__ Real normL2() const
Retourne la norme L2 du triplet .
Definition Real3.h:555
constexpr __host__ __device__ Real squareNormL2() const
Retourne la norme L2 au carré du triplet .
Definition Real3.h:429
Classe utilitaire pour instantier un service d'une interface donnée.
Ref< InterfaceType > createReference(const String &name, eServiceBuilderProperties properties=SB_None)
Créé une instance implémentant l'interface InterfaceType.
void getServicesNames(Array< String > &names) const
Remplit names avec les noms des services disponibles pour instantier cette interface.
Tableau 1D de données avec buffer pré-alloué sur la pile.
Constructeur de chaîne de caractère unicode.
String toString() const
Retourne la chaîne de caractères construite.
Chaîne de caractères unicode.
Postionne le nom de l'action en cours d'exécution.
Definition Timer.h:110
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage warning() const
Flot pour un message d'avertissement.
Vecteur 1D de données avec sémantique par valeur (style STL).
void changeOwnersFromCells() override
Positionne les nouveaux propriétaires des noeuds, arêtes et faces à partir des mailles.
Generic class for calculating entity owners.
Merging nodes of a mesh.
void mergeNodes(Int32ConstArrayView nodes_local_id, Int32ConstArrayView nodes_to_merge_local_id, bool allow_non_corresponding_face=false)
__host__ __device__ Real3 vecMul(Real3 u, Real3 v)
Produit vectoriel de u par v. dans .
Definition MathUtils.h:52
__host__ __device__ Real scaMul(Real2 u, Real2 v)
Produit scalaire de u par v dans .
Definition MathUtils.h:113
__host__ __device__ Real3 cross(Real3 v1, Real3 v2)
Produit vectoriel de deux vecteurs à 3 composantes.
Definition MathUtils.h:723
ItemGroupT< Face > FaceGroup
Groupe de faces.
Definition ItemTypes.h:178
ItemGroupT< Node > NodeGroup
Groupe de noeuds.
Definition ItemTypes.h:167
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
ItemVariableScalarRefT< Int32 > VariableItemInt32
Grandeur de type entier 32 bits.
@ ReduceSum
Somme des valeurs.
constexpr __host__ __device__ bool isNearlyEqual(const _Type &a, const _Type &b)
Teste si deux valeurs sont à un peu près égales. Pour les types entiers, cette fonction est équivalen...
Definition Numeric.h:212
bool isZero(const BuiltInProxy< _Type > &a)
Teste si une valeur est exactement égale à zéro.
String getCurrentDateTime()
Date et l'heure courante sous la forme ISO 8601.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
ArrayView< Int64 > Int64ArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:451
@ SB_AllowNull
Autorise l'absence du service.
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:339
std::int64_t Int64
Type entier signé sur 64 bits.
ArrayView< Real3 > Real3ArrayView
Equivalent C d'un tableau à une dimension de Real3.
Definition UtilsTypes.h:467
Int32 Integer
Type représentant un entier.
UniqueArray< Real3 > Real3UniqueArray
Tableau dynamique à une dimension de vecteurs de rang 3.
Definition UtilsTypes.h:363
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
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:480
ArrayView< Int32 > Int32ArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:453
eItemKind
Genre d'entité de maillage.
@ IK_Particle
Entité de maillage de genre particule.
@ IK_Node
Entité de maillage de genre noeud.
@ IK_Cell
Entité de maillage de genre maille.
@ IK_Face
Entité de maillage de genre face.
@ IK_DoF
Entité de maillage de genre degre de liberte.
@ IK_Edge
Entité de maillage de genre arête.
double Real
Type représentant un réel.
ConstArrayView< Integer > IntegerConstArrayView
Equivalent C d'un tableau à une dimension d'entiers.
Definition UtilsTypes.h:486
ArrayView< Real > RealArrayView
Equivalent C d'un tableau à une dimension de réels.
Definition UtilsTypes.h:459
std::int32_t Int32
Type entier signé sur 32 bits.
Real y
deuxième composante du triplet
Definition Real3.h:36
Real z
troisième composante du triplet
Definition Real3.h:37
Real x
première composante du triplet
Definition Real3.h:35