Arcane  v3.16.2.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-2025 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/* Fonctions utilitaires sur un maillage. */
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 // On suppose qu'on connait les nouveaux propriétaires des mailles, qui
92 // se trouvent dans cells_owner. Il faut
93 // maintenant déterminer les nouveaux propriétaires des noeuds et
94 // des faces. En attendant d'avoir un algorithme qui équilibre mieux
95 // les messages, on applique le suivant:
96 // - chaque sous-domaine est responsable pour déterminer le nouveau
97 // propriétaire des noeuds et des faces qui lui appartiennent.
98 // - pour les noeuds, le nouveau propriétaire est le nouveau propriétaire
99 // de la maille connectée à ce noeud dont le uniqueId() est le plus petit.
100 // - pour les faces, le nouveau propriétaire est le nouveau propriétaire
101 // de la maille qui est derrière cette face s'il s'agit d'une face
102 // interne et de la maille connectée s'il s'agit d'une face frontière.
103 // - pour les noeuds duaux, le nouveau propriétaire est le nouveau propriétaire
104 // de la maille connectée à l'élément dual
105 // - pour les liaisons, le nouveau propriétaire est le nouveau propriétaire
106 // de la maille connectée au premier noeud dual, c'est-à-dire le propriétaire
107 // du premier noeud dual de la liaison
108
109 // Outil d'affectation des owners pour les 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 // Détermine les nouveaux propriétaires des noeuds
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 // Détermine les nouveaux propriétaires des arêtes
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 // Détermine les nouveaux propriétaires des 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
164 // Détermine les nouveaux propriétaires des particules
165 // Les particules ont le même propriétaire que celui de la maille dans
166 // laquelle elle se trouve.
167 for( IItemFamily* family : m_mesh->itemFamilies() ){
168 if (family->itemKind()!=IK_Particle)
169 continue;
170 // Positionne les nouveaux propriétaires des particle
171 VariableItemInt32& particles_owner(family->itemsNewOwner());
172 ENUMERATE_PARTICLE(i_particle,family->allItems()){
173 Particle particle = *i_particle ;
174 particles_owner[particle] = cells_owner[particle.cell()] ;
175 }
176 }
177
178 // GraphOnDoF
179 if(m_mesh->itemFamilyNetwork())
180 {
181 // Dof with Mesh Item connectivity
182 for( IItemFamily* family : m_mesh->itemFamilies() )
183 {
184 if (family->itemKind()!=IK_DoF || family->name()==mesh::GraphDoFs::linkFamilyName())
185 continue;
186 VariableItemInt32& dofs_new_owner(family->itemsNewOwner());
187 std::array<Arcane::eItemKind,5> dualitem_kinds = {IK_Cell,IK_Face,IK_Edge,IK_Node,IK_Particle} ;
188 for(auto dualitem_kind : dualitem_kinds)
189 {
190 IItemFamily* dualitem_family = dualitem_kind==IK_Particle? m_mesh->findItemFamily(dualitem_kind,mesh::ParticleFamily::defaultFamilyName(), false):
191 m_mesh->itemFamily(dualitem_kind) ;
192 if(dualitem_family)
193 {
194
195 VariableItemInt32& dualitems_new_owner(dualitem_family->itemsNewOwner());
196 auto connectivity_name = mesh::connectivityName(family,dualitem_family) ;
197 bool is_dof2dual = true ;
198 auto connectivity = m_mesh->itemFamilyNetwork()->getConnectivity(family,dualitem_family,connectivity_name) ;
199 if(!connectivity)
200 {
201 connectivity = m_mesh->itemFamilyNetwork()->getConnectivity(dualitem_family,family,connectivity_name) ;
202 is_dof2dual = false ;
203 }
204
205 if(connectivity)
206 {
207 ConnectivityItemVector accessor(connectivity);
208 if(is_dof2dual)
209 {
210 ENUMERATE_ITEM(item, family->allItems().own())
211 {
212 auto connected_items = accessor.connectedItems(ItemLocalId(item)) ;
213 if(connected_items.size()>0)
214 {
215 dofs_new_owner[*item] = dualitems_new_owner[connected_items[0]] ;
216 }
217 }
218 }
219 else
220 {
221 ENUMERATE_ITEM(item, dualitem_family->allItems())
222 {
223 ENUMERATE_ITEM(connected_item,accessor.connectedItems(ItemLocalId(item)))
224 {
225 dofs_new_owner[*connected_item] = dualitems_new_owner[*item] ;
226 }
227 }
228 }
229 }
230 }
231 }
232 }
233 // Dof with DoF connectivity
234 IItemFamily* links_family = m_mesh->findItemFamily(IK_DoF, mesh::GraphDoFs::linkFamilyName(), false);
235 if(links_family)
236 {
237 VariableItemInt32& links_new_owner(links_family->itemsNewOwner());
238 IItemFamily* dualnodes_family = m_mesh->findItemFamily(IK_DoF, mesh::GraphDoFs::dualNodeFamilyName(), false);
239 if(dualnodes_family)
240 {
241 VariableItemInt32& dualnodes_new_owner(dualnodes_family->itemsNewOwner());
242 auto connectivity_name = mesh::connectivityName(links_family,dualnodes_family) ;
243 auto connectivity = m_mesh->itemFamilyNetwork()->getConnectivity(links_family,dualnodes_family,connectivity_name) ;
244 if(connectivity)
245 {
246 ConnectivityItemVector accessor(connectivity);
247 ENUMERATE_ITEM(item, links_family->allItems().own())
248 {
249 auto connected_items = accessor.connectedItems(ItemLocalId(item)) ;
250 if(connected_items.size()>0)
251 {
252 links_new_owner[*item] = dualnodes_new_owner[connected_items[0]] ;
253 }
254 }
255 }
256 }
257 }
258 }
259}
260
261/*---------------------------------------------------------------------------*/
262/*---------------------------------------------------------------------------*/
263
264void UnstructuredMeshUtilities::
265localIdsFromConnectivity(eItemKind item_kind,
266 IntegerConstArrayView items_nb_node,
267 Int64ConstArrayView items_connectivity,
268 Int32ArrayView local_ids,
269 bool allow_null)
270{
271 Integer nb_item = items_nb_node.size();
272 if (item_kind!=IK_Face && item_kind!=IK_Cell)
273 throw InvalidArgumentException(A_FUNCINFO,"item_kind",
274 "IK_Cell or IK_Face expected",
275 (int)item_kind);
276 if (item_kind==IK_Cell)
277 throw NotImplementedException(A_FUNCINFO,"not implemented for cells");
278
279 if (nb_item!=local_ids.size())
280 throw InvalidArgumentException(A_FUNCINFO,"local_ids",
281 "Size different from 'items_nb_node'",
282 (int)item_kind);
283
284 Integer item_connectivity_index = 0;
286 buf.reserve(256);
287 ItemInternalList nodes(m_mesh->itemsInternal(IK_Node));
288 for( Integer i=0; i<nb_item; ++i ){
289 Integer current_nb_node = items_nb_node[i];
290 Int64ConstArrayView current_nodes(current_nb_node,items_connectivity.data()+item_connectivity_index);
291 item_connectivity_index += current_nb_node;
292 if (item_kind==IK_Face){
293 buf.resize(current_nb_node);
294 mesh_utils::reorderNodesOfFace(current_nodes,buf);
295 Int64 first_node_uid = buf[0];
296 Int64ArrayView first_node_uid_array(1,&first_node_uid);
297 Int32 first_node_lid = CheckedConvert::toInt32(buf[0]);
298 Int32ArrayView first_node_lid_array(1,&first_node_lid);
299 m_mesh->nodeFamily()->itemsUniqueIdToLocalId(first_node_lid_array,first_node_uid_array,!allow_null);
300 if (first_node_lid == NULL_ITEM_LOCAL_ID){
301 if (allow_null){
302 local_ids[i] = NULL_ITEM_LOCAL_ID;
303 }
304 else {
305 StringBuilder sb("Face with nodes (");
306 for(Integer j=0;j<current_nb_node;++j) {
307 if (j != 0) sb += " ";
308 sb += current_nodes[j];
309 }
310 sb += ") not found (first node ";
311 sb += first_node_uid;
312 sb += " not found)";
314 }
315 continue;
316 }
317
318 Node node(nodes[first_node_lid]);
319 Face face(mesh_utils::getFaceFromNodesUnique(node,buf));
320 if (face.null()){
321 if (allow_null){
322 local_ids[i] = NULL_ITEM_LOCAL_ID;
323 }
324 else {
325 StringBuilder sb("Face with nodes (");
326 for(Integer j=0;j<current_nb_node;++j) {
327 if (j != 0) sb += " ";
328 sb += current_nodes[j];
329 }
330 sb += ") not found";
332 }
333 }
334 else
335 local_ids[i] = face.localId();
336 }
337 }
338}
339
340/*---------------------------------------------------------------------------*/
341/*---------------------------------------------------------------------------*/
342
343void UnstructuredMeshUtilities::
344getFacesLocalIdFromConnectivity(ConstArrayView<ItemTypeId> items_type,
345 ConstArrayView<Int64> items_connectivity,
346 ArrayView<Int32> local_ids,
347 bool allow_null)
348{
349 Int32 nb_item = items_type.size();
350
351 if (nb_item!=local_ids.size())
352 throw InvalidArgumentException(A_FUNCINFO,"local_ids",
353 "Size different from 'items_type'");
354
355 Int32 item_connectivity_index = 0;
356 ItemTypeMng* item_type_mng = m_mesh->itemTypeMng();
357 NodesOfItemReorderer face_reorderer(item_type_mng);
358
359 ItemInternalList nodes(m_mesh->itemsInternal(IK_Node));
360 for( Integer i=0; i<nb_item; ++i ){
361 ItemTypeId current_type_id = items_type[i];
362 Int32 current_nb_node = item_type_mng->typeFromId(current_type_id)->nbLocalNode();
363 Int64ConstArrayView current_nodes(current_nb_node,items_connectivity.data()+item_connectivity_index);
364 item_connectivity_index += current_nb_node;
365
366 face_reorderer.reorder(current_type_id,current_nodes);
367 ConstArrayView<Int64> buf(face_reorderer.sortedNodes());
368 Int64 first_node_uid = buf[0];
369 Int64ArrayView first_node_uid_array(1,&first_node_uid);
370 Int32 first_node_lid = CheckedConvert::toInt32(buf[0]);
371 Int32ArrayView first_node_lid_array(1,&first_node_lid);
372 m_mesh->nodeFamily()->itemsUniqueIdToLocalId(first_node_lid_array,first_node_uid_array,!allow_null);
373 if (first_node_lid == NULL_ITEM_LOCAL_ID){
374 if (allow_null){
375 local_ids[i] = NULL_ITEM_LOCAL_ID;
376 }
377 else {
378 StringBuilder sb("Face with nodes (");
379 for(Integer j=0;j<current_nb_node;++j) {
380 if (j != 0) sb += " ";
381 sb += current_nodes[j];
382 }
383 sb += ") not found (first node ";
384 sb += first_node_uid;
385 sb += " not found)";
387 }
388 continue;
389 }
390
391 Node node(nodes[first_node_lid]);
392 Face face(MeshUtils::getFaceFromNodesUnique(node,buf));
393 if (face.null()){
394 if (allow_null){
395 local_ids[i] = NULL_ITEM_LOCAL_ID;
396 }
397 else {
398 StringBuilder sb("Face with nodes (");
399 for(Integer j=0;j<current_nb_node;++j) {
400 if (j != 0) sb += " ";
401 sb += current_nodes[j];
402 }
403 sb += ") not found";
405 }
406 }
407 else
408 local_ids[i] = face.localId();
409 }
410}
411
412/*---------------------------------------------------------------------------*/
413/*---------------------------------------------------------------------------*/
414
415Real3 UnstructuredMeshUtilities::
416_round(Real3 value)
417{
418 Real3 rvalue = value;
419 // Evite les problèmes d'arrondi numérique
420 if (math::isNearlyZero(value.x))
421 rvalue.x = 0.0;
422 if (math::isNearlyZero(value.y))
423 rvalue.y = 0.0;
424 if (math::isNearlyZero(value.z))
425 rvalue.z = 0.0;
426
427 if (math::isNearlyEqual(value.x,1.0))
428 rvalue.x = 1.0;
429 if (math::isNearlyEqual(value.y,1.0))
430 rvalue.y = 1.0;
431 if (math::isNearlyEqual(value.z,1.0))
432 rvalue.z = 1.0;
433
434 if (math::isNearlyEqual(value.x,-1.0))
435 rvalue.x = -1.0;
436 if (math::isNearlyEqual(value.y,-1.0))
437 rvalue.y = -1.0;
438 if (math::isNearlyEqual(value.z,-1.0))
439 rvalue.z = -1.0;
440
441 return rvalue;
442}
443
444/*---------------------------------------------------------------------------*/
445/*---------------------------------------------------------------------------*/
446
447Real3 UnstructuredMeshUtilities::
448computeNormal(const FaceGroup& face_group,const VariableNodeReal3& nodes_coord)
449{
450 String func_name = "UnstructuredMeshUtilities::computeNormal";
451 IParallelMng* pm = m_mesh->parallelMng();
452 Integer rank = pm->commRank();
453 //Integer nb_item = face_group.size();
454 Integer nb_node = 0;
455 Integer mesh_dimension = m_mesh->dimension();
456 // 'global_normal' et 'total_global_normal' servent à determiner
457 // une direction pour la surface en supposant qu'il s'agit
458 // d'une surface externe. La direction sert ensuite à orienter
459 // la normale calculée dans le sens normal sortante.
460 Real3 global_normal = Real3::null();
461 Real nb_global_normal_used_node = 0.0;
462 ENUMERATE_FACE(iface,face_group){
463 Face face = *iface;
464 Integer face_nb_node = face.nbNode();
465 nb_node += face_nb_node;
466
467 if (face.isSubDomainBoundary() && face.isOwn()){
468 Real3 face_normal;
469 if (mesh_dimension==3){
470 Real3 v1 = nodes_coord[face.node(1)] - nodes_coord[face.node(0)];
471 Real3 v2 = nodes_coord[face.node(2)] - nodes_coord[face.node(0)];
472 face_normal = math::vecMul(v1,v2);
473 }
474 else if (mesh_dimension==2){
475 Real3 dir = nodes_coord[face.node(0)] - nodes_coord[face.node(1)];
476 face_normal.x = - dir.y;
477 face_normal.y = dir.x;
478 face_normal.z = 0.0;
479 }
480 if (face.boundaryCell()==face.frontCell())
481 face_normal = -face_normal;
482 //info() << "ADD NORMAL normal=" << face_normal;
483 global_normal = global_normal + face_normal;
484 nb_global_normal_used_node += 1.0;
485 }
486 }
487 // L'algorithme tente de déterminer les noeuds aux extrémités de la surface
488 // On considère qu'il s'agit de ceux qui n'appartiennent qu'à une seule
489 // face de la surface. Cela fonctionne bien si toutes les faces ont au moins
490 // quatres arêtes. S'il y a des triangles, on suppose que ce n'est pas
491 // partout et dans ce cas on a au moins deux noeuds extrèmes connus.
492 typedef HashTableMapT<Int32,Int32> NodeOccurenceMap;
493 // Range dans la table pour chaque noeud le nombre de faces de la surface
494 // auxquelles il est connecté.
495 NodeOccurenceMap nodes_occurence(nb_node*2,true,nb_node);
496 ENUMERATE_FACE(iface,face_group){
497 Face face = *iface;
498 for( NodeLocalId inode : face.nodeIds() ){
499 NodeOccurenceMap::Data* v = nodes_occurence.lookup(inode);
500 if (v)
501 ++v->value();
502 else{
503 //info() << " ADD NODE " << ItemPrinter(*inode) << " coord=" << nodes_coord[inode];
504 nodes_occurence.add(inode,1);
505 }
506 }
507 }
508 UniqueArray<Node> single_nodes;
509 NodeLocalIdToNodeConverter nodes_internal(m_mesh->nodeFamily());
510 nodes_occurence.each([&](NodeOccurenceMap::Data* d){
511 if (d->value()==1){
512 Node node = nodes_internal[d->key()];
513 // En parallèle, ne traite que les noeuds qui nous appartiennent
514 if (node.owner()==rank){
515 single_nodes.add(node);
516 //info() << "SINGLE NODE OWNER lid=" << d->key() << " " << ItemPrinter(node)
517 // << " coord=" << nodes_coord[node];
518 }
519 }
520 });
521 // Chaque sous-domaine collecte les coordonnées des noeuds des autres sous-domaines
522 Integer nb_single_node = single_nodes.size();
523 //info() << "NB SINGLE NODE= " << nb_single_node;
524 Integer total_nb_single_node = pm->reduce(Parallel::ReduceSum,nb_single_node);
525 Real3 total_global_normal;
526 {
527 Real all_min = 0.0;
528 Real all_max = 0.0;
529 Real all_sum = 0.0;
530 Int32 min_rank = -1;
531 Int32 max_rank = -1;
532 pm->computeMinMaxSum(nb_global_normal_used_node,all_min,all_max,all_sum,min_rank,max_rank);
533 Real3 buf;
534 if (max_rank==rank){
535 // Je suis celui qui a le point le plus loin. Je l'envoie aux autres.
536 buf = global_normal;
537 }
538 pm->broadcast(Real3ArrayView(1,&buf),max_rank);
539 total_global_normal = buf;
540 }
541
542 info() << "TOTAL SINGLE NODE= " << total_nb_single_node << " surface=" << face_group.name()
543 << " global_normal = " << total_global_normal;
544 if (total_nb_single_node<2){
545 ARCANE_FATAL("not enough nodes connected to only one face");
546 }
547 Real3UniqueArray coords(nb_single_node);
548 for( Integer i=0; i<nb_single_node; ++i ){
549 coords[i] = nodes_coord[single_nodes[i]];
550 }
551 //Array<Real> all_nodes_coord_real;
552 UniqueArray<Real3> all_nodes_coord;
553 pm->allGatherVariable(coords,all_nodes_coord);
554 //info() << " ALL NODES COORD n=" << all_nodes_coord_real.size();
555 //Array<Real3> all_nodes_coord(total_nb_single_node);
556 Real3 barycentre = Real3::null();
557 for( Integer i=0; i<total_nb_single_node; ++i ){
558 barycentre += all_nodes_coord[i];
559 }
560 barycentre /= (Real)total_nb_single_node;
561 if (total_nb_single_node==2 && m_mesh->dimension()==3){
562 // On a que deux noeuds. Il en faut au moins un troisième pour déterminer
563 // la normale au plan. Pour cela, chaque processeur cherche le noeud de
564 // la surface qui est le plus éloigné du barycentre des deux noeuds déjà
565 // trouvé. Ce noeud le plus éloigné servira de troisième point pour le
566 // plan.
567 Real max_distance = 0.0;
568 Node farthest_node;
569 Real3 s0 = all_nodes_coord[0];
570 Real3 s1 = all_nodes_coord[1];
571 nodes_occurence.each([&](NodeOccurenceMap::Data* d){
572 Node node = nodes_internal[d->key()];
573 Real3 coord = nodes_coord[node];
574 // Ne traite pas les deux noeuds du déjà trouvés
575 if (math::isNearlyEqual(coord,s0))
576 return;
577 if (math::isNearlyEqual(coord,s1))
578 return;
579 Real distance = (coord - barycentre).squareNormL2();
580 if (distance>max_distance){
581 Real3 normal = math::cross(coord-s0, s1-s0);
582 // On ne prend le noeud que s'il n'est pas aligné avec les deux autres.
583 if (!math::isNearlyZero(normal.squareNormL2())){
584 max_distance = distance;
585 farthest_node = node;
586 }
587 }
588 });
589
590 if (!farthest_node.null()){
591 info() << " FARTHEST NODE= " << ItemPrinter(farthest_node) << " dist=" << max_distance;
592 }
593 {
594 Real3 farthest_coord = _broadcastFarthestNode(max_distance,farthest_node,nodes_coord);
595 info() << " FARTHEST NODE ALL coord=" << farthest_coord;
596 all_nodes_coord.add(farthest_coord);
597 }
598 }
599 // Trie les noeuds pour que le calcul ne dépende pas de l'ordre des
600 // opérations en parallèle.
601 std::sort(std::begin(all_nodes_coord),std::end(all_nodes_coord));
602 Integer nb_final_node = all_nodes_coord.size();
603 Real3 full_normal = Real3::null();
604 info() << " NB FINAL NODE=" << nb_final_node;
605 for( Integer i=0; i<nb_final_node; ++i )
606 info() << " NODE=" << all_nodes_coord[i];
607 if (m_mesh->dimension()==2){
608 if (nb_final_node!=2){
609 ARCANE_FATAL("should have 2 border nodes in 2D mesh");
610 }
611 Real3 direction = all_nodes_coord[1] - all_nodes_coord[0];
612 full_normal.x = - direction.y;
613 full_normal.y = direction.x;
614 }
615 else if (m_mesh->dimension()==3){
616 //nb_final_node = 3; // On prend que les 3 premiers points.
617 // NOTE: on pourrait prendre tous les points, car si les trois premiers sont
618 // alignés, la normale ne sera pas bonne.
619 // Si on prend tous les points, il faut être sur qu'ils soient ordonnés
620 // de telle sorte que la normale de trois points consécutifs est toujours
621 // dans le même sens. Cela signifie si on a quatres points par exemple,
622 // que ces 4 points forment un quadrangle non croisé (pas en forme
623 // de papillon)
624 Real3 first_normal = math::vecMul(all_nodes_coord[2]-all_nodes_coord[0],
625 all_nodes_coord[1]-all_nodes_coord[0]);
626 for( Integer i=0; i<nb_final_node; ++i ){
627 Real3 s0 = all_nodes_coord[i];
628 Real3 s1 = all_nodes_coord[(i+nb_final_node-1)%nb_final_node];
629 Real3 s2 = all_nodes_coord[(i+1)%nb_final_node];
630 Real3 normal = math::vecMul(s2-s0, s1-s0);
631 info() << " ADD NORMAL: " << normal;
632 full_normal += normal;
633 info() << " FULL: " << full_normal;
634 }
635 if (math::isNearlyZero(full_normal.squareNormL2()))
636 full_normal = first_normal;
637 }
638 else
639 ARCANE_FATAL("invalid mesh dimension (should be 2 or 3)");
640 Real a = full_normal.normL2();
641 if (math::isZero(a))
642 ARCANE_FATAL("invalid value for normal");
643 full_normal /= a;
644 Real b = total_global_normal.normL2();
645 Real dir = 0.0;
646 info() << " Normal is " << full_normal;
647 if (!math::isZero(b)){
648 total_global_normal /= b;
649 dir = math::scaMul(full_normal,total_global_normal);
650 if (dir<0.0)
651 full_normal = -full_normal;
652 }
653 full_normal = _round(full_normal);
654 info() << " Final normal is " << full_normal << " dir=" << dir;
655 return full_normal;
656}
657
658/*---------------------------------------------------------------------------*/
659/*---------------------------------------------------------------------------*/
667Real3 UnstructuredMeshUtilities::
668computeDirection(const NodeGroup& node_group,
669 const VariableNodeReal3& nodes_coord,
670 Real3* n1,Real3* n2)
671{
672 String func_name = "UnstructuredMeshUtilities::computeDirection";
673 IParallelMng* pm = m_mesh->parallelMng();
674 //Integer rank = pm->commRank();
675 //Integer nb_node_own = node_group.own().size();
676 //Integer total_nb_node_own = pm->reduce(Parallel::ReduceSum,nb_node_own);
677 Real3 barycentre = Real3::null();
678 ENUMERATE_NODE(inode,node_group.own()){
679 barycentre += nodes_coord[inode];
680 }
681 Real r_barycentre[3];
682 r_barycentre[0] = barycentre.x;
683 r_barycentre[1] = barycentre.y;
684 r_barycentre[2] = barycentre.z;
685 RealArrayView rav(3,r_barycentre);
687 barycentre = Real3(rav[0],rav[1],rav[2]);
688 debug() << " BARYCENTRE COMPUTE DIRECTION = " << barycentre;
689 pm->barrier();
690
691 // Détermine le noeud le plus éloigné du barycentre
692 Real3 first_boundary_coord;
693 {
694 Real max_distance = 0.0;
695 Node farthest_node;
696 ENUMERATE_NODE(inode,node_group.own()){
697 Node node = *inode;
698 Real3 coord = nodes_coord[node];
699 Real distance = (coord - barycentre).squareNormL2();
700 if (distance>max_distance){
701 max_distance = distance;
702 farthest_node = node;
703 }
704 }
705 first_boundary_coord = _broadcastFarthestNode(max_distance,farthest_node,nodes_coord);
706 if (n1)
707 *n1 = first_boundary_coord;
708 }
709 Real3 second_boundary_coord;
710 {
711 Real max_distance = 0.0;
712 Node farthest_node;
713 ENUMERATE_NODE(inode,node_group.own()){
714 Node node = *inode;
715 Real3 coord = nodes_coord[node];
716 Real distance = (coord - first_boundary_coord).squareNormL2();
717 if (distance>max_distance){
718 max_distance = distance;
719 farthest_node = node;
720 }
721 }
722 second_boundary_coord = _broadcastFarthestNode(max_distance,farthest_node,nodes_coord);
723 if (n2)
724 *n2 = second_boundary_coord;
725 }
726 Real3 direction = second_boundary_coord - first_boundary_coord;
727 Real norm = direction.normL2();
728 if (math::isZero(norm)){
729 ARCANE_FATAL("Direction is null for group '{0}' first_coord={1} second_coord={2}",
730 node_group.name(),first_boundary_coord,second_boundary_coord);
731 }
732 return direction / norm;
733}
734
735/*---------------------------------------------------------------------------*/
736/*---------------------------------------------------------------------------*/
737
738Real3 UnstructuredMeshUtilities::
739_broadcastFarthestNode(Real distance,const Node& farthest_node,
740 const VariableNodeReal3& nodes_coord)
741{
742 String func_name = "UnstructuredMeshUtilities::_broadcastFarthestNode()";
743 IParallelMng* pm = m_mesh->parallelMng();
744 Integer rank = pm->commRank();
745
746 Real all_min_distance = 0.0;
747 Real all_max_distance = 0.0;
748 Real all_sum_distance = 0.0;
749 Int32 min_rank = -1;
750 Int32 max_rank = -1;
751 pm->computeMinMaxSum(distance,all_min_distance,all_max_distance,all_sum_distance,min_rank,max_rank);
752 Real3 buf;
753 if (!farthest_node.null())
754 debug() << " FARTHEST NODE myself coord=" << nodes_coord[farthest_node]
755 << " distance=" << distance
756 << " rank=" << max_rank
757 << " max_distance=" << all_max_distance;
758 else
759 debug() << " FARTHEST NODE myself coord=none"
760 << " distance=" << distance
761 << " rank=" << max_rank
762 << " max_distance=" << all_max_distance;
763
764 if (max_rank==rank){
765 if (farthest_node.null())
766 ARCANE_FATAL("can not find farthest node");
767 // Je suis celui qui a le point le plus loin. Je l'envoie aux autres.
768 buf = nodes_coord[farthest_node];
769 debug() << " I AM FARTHEST NODE ALL coord=" << buf;
770 }
771 pm->broadcast(Real3ArrayView(1,&buf),max_rank);
772 Real3 farthest_coord(buf);
773 debug() << " FARTHEST NODE ALL coord=" << farthest_coord
774 << " rank=" << max_rank
775 << " max_distance=" << all_max_distance;
776 return farthest_coord;
777}
778
779/*---------------------------------------------------------------------------*/
780/*---------------------------------------------------------------------------*/
781
782void UnstructuredMeshUtilities::
783computeAdjency(ItemPairGroup adjency_array,eItemKind link_kind,Integer nb_layer)
784{
785 m_compute_adjacency_functor->computeAdjacency(adjency_array, link_kind, nb_layer);
786}
787
788/*---------------------------------------------------------------------------*/
789/*---------------------------------------------------------------------------*/
790
791bool UnstructuredMeshUtilities::
792writeToFile(const String& file_name,const String& service_name)
793{
794 ServiceBuilder<IMeshWriter> sb(m_mesh->handle());
795 auto mesh_writer = sb.createReference(service_name,SB_AllowNull);
796
797 if (!mesh_writer){
798 UniqueArray<String> available_names;
799 sb.getServicesNames(available_names);
800 warning() << String::format("The specified service '{0}' to write the mesh is not available."
801 " Valid names are {1}",service_name,available_names);
802 return true;
803 }
804 mesh_writer->writeMeshToFile(m_mesh,file_name);
805 return false;
806}
807
808/*---------------------------------------------------------------------------*/
809/*---------------------------------------------------------------------------*/
810
811void UnstructuredMeshUtilities::
812partitionAndExchangeMeshWithReplication(IMeshPartitionerBase* partitioner,
813 bool initial_partition)
814{
815 IPrimaryMesh* primary_mesh = partitioner->primaryMesh();
816 IMesh* mesh = primary_mesh;
817 if (mesh!=this->m_mesh)
818 throw ArgumentException(A_FUNCINFO,"partitioner->mesh() != this->m_mesh");
819
820 IParallelMng* pm = mesh->parallelMng();
821 ITimeStats* ts = pm->timeStats();
823 bool has_replication = pr->hasReplication();
824
825 // En mode réplication, seul le premier réplicat fait l'équilibrage.
826 // Il doit ensuite envoyer aux autres ces informations de maillage
827 // pour qu'ils aient le même maillage.
828
829 info() << "Partition start date=" << platform::getCurrentDateTime();
830 if (pr->isMasterRank()){
831 Timer::Action ts_action1(ts,"MeshPartition",true);
832 info() << "Partitioning the mesh (initial?=" << initial_partition << ")";
833 partitioner->partitionMesh(initial_partition);
834 }
835 else
836 info() << "Waiting for partition information from the master replica";
837
838 if (has_replication){
839 pm->barrier();
840
841 // Vérifie que toute les familles sont les mêmes.
842 mesh->checker()->checkValidReplication();
843
844 Int32 replica_master_rank = pr->masterReplicationRank();
845 IParallelMng* rep_pm = pr->replicaParallelMng();
846
847 // Seul le replica maitre a les bons propriétaires. Il faut mettre
848 // à jour les autres à partir de celui-ci. Pour cela on synchronize
849 // les propriétaires des mailles et ensuite on met à jour les autres familles
850 // à partir des propriétaires des mailles.
851 {
852 Int32ArrayView owners = mesh->cellFamily()->itemsNewOwner().asArray();
853 rep_pm->broadcast(owners,replica_master_rank);
854 if (!pr->isMasterRank()){
856 }
857 }
858 }
859 info() << "Partition end date=" << platform::getCurrentDateTime();
860 {
861 Timer::Action ts_action2(ts,"MeshExchange",true);
862 primary_mesh->exchangeItems();
863 }
864 info() << "Exchange end date=" << platform::getCurrentDateTime();
865 partitioner->notifyEndPartition();
866
867 // Il faut recompacter pour se retrouver dans la même situation que
868 // si on avait juste lu un maillage directement (qui fait un prepareForDump()
869 // lors de l'appel à endAllocate()).
870 // On le fait aussi en cas de réplication pour éviter d'éventuelles
871 // incohérences si par la suite certains réplicas appellent cette
872 // méthode et pas les autres.
873 // TODO: regarder s'il faut le faire aussi en cas de repartitionnement.
874 if (initial_partition || has_replication)
875 mesh->prepareForDump();
876}
877
878/*---------------------------------------------------------------------------*/
879/*---------------------------------------------------------------------------*/
880
881void UnstructuredMeshUtilities::
882mergeNodes(Int32ConstArrayView nodes_local_id,
883 Int32ConstArrayView nodes_to_merge_local_id,
884 bool allow_non_corresponding_face)
885{
886 mesh::MeshNodeMerger merger(m_mesh);
887 merger.mergeNodes(nodes_local_id, nodes_to_merge_local_id, allow_non_corresponding_face);
888}
889
890/*---------------------------------------------------------------------------*/
891/*---------------------------------------------------------------------------*/
892
893void UnstructuredMeshUtilities::
894computeAndSetOwnersForNodes()
895{
896 mesh::ItemsOwnerBuilder owner_builder(m_mesh);
897 owner_builder.computeNodesOwner();
898}
899
900/*---------------------------------------------------------------------------*/
901/*---------------------------------------------------------------------------*/
902
903void UnstructuredMeshUtilities::
904computeAndSetOwnersForFaces()
905{
906 mesh::ItemsOwnerBuilder owner_builder(m_mesh);
907 owner_builder.computeFacesOwner();
908}
909
910
911/*---------------------------------------------------------------------------*/
912/*---------------------------------------------------------------------------*/
913namespace
914{
915 void _recomputeUniqueIds(IItemFamily* family)
916 {
917 SmallArray<Int64> unique_ids;
918 ENUMERATE_ (ItemWithNodes, iitem, family->allItems()) {
919 ItemWithNodes item = *iitem;
920 Int32 index = 0;
921 unique_ids.resize(item.nbNode());
922 for (Node node : item.nodes()) {
923 unique_ids[index] = node.uniqueId();
924 ++index;
925 }
926 Int64 new_uid = MeshUtils::generateHashUniqueId(unique_ids);
927 item.mutableItemBase().setUniqueId(new_uid);
928 }
930 }
931} // namespace
932
933/*---------------------------------------------------------------------------*/
934/*---------------------------------------------------------------------------*/
935
936void UnstructuredMeshUtilities::
937recomputeItemsUniqueIdFromNodesUniqueId()
938{
939 IMesh* mesh = m_mesh;
941 ITraceMng* tm = mesh->traceMng();
942
943 tm->info() << "Calling RecomputeItemsUniqueIdFromNodesUniqueId()";
944 // D'abord indiquer que les noeuds ont changés pour éventuellement
945 // remettre à jour l'orientation des faces.
946 mesh->nodeFamily()->notifyItemsUniqueIdChanged();
947 _recomputeUniqueIds(mesh->edgeFamily());
948 _recomputeUniqueIds(mesh->faceFamily());
949 _recomputeUniqueIds(mesh->cellFamily());
950}
951
952/*---------------------------------------------------------------------------*/
953/*---------------------------------------------------------------------------*/
954
955} // End namespace Arcane
956
957/*---------------------------------------------------------------------------*/
958/*---------------------------------------------------------------------------*/
#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:1199
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:817
Face d'une maille.
Definition Item.h:952
Cell frontCell() const
Maille devant la face (maille nulle si aucune)
Definition Item.h:1628
bool isSubDomainBoundary() const
Indique si la face est au bord du sous-domaine (i.e nbCell()==1)
Definition Item.h:1046
Cell boundaryCell() const
Maille associée à cette face frontière (maille nulle si aucune)
Definition Item.h:1616
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 repartionnement (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:35
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:727
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:782
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:785
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:779
NodeLocalIdView nodeIds() const
Liste des noeuds de l'entité
Definition Item.h:788
impl::MutableItemBase mutableItemBase() const
Partie interne modifiable de l'entité.
Definition Item.h:374
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:219
bool isOwn() const
true si l'entité est appartient au sous-domaine
Definition Item.h:253
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
Classe pour convertir un NodeLocalId vers une arête.
Noeud d'un maillage.
Definition Item.h:576
Classe utilitaire pour réordonner les noeuds d'une entité.
Exception lorsqu'une fonction n'est pas implémentée.
Particule.
Definition Item.h:1405
Cell cell() const
Maille à laquelle appartient la particule. Il faut appeler setCell() avant d'appeler cette fonction....
Definition Item.h:1467
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:521
constexpr __host__ __device__ Real squareNormL2() const
Retourne la norme L2 au carré du triplet .
Definition Real3.h:408
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.
Definition SmallArray.h:89
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.
Classe générique pour calculer les propriétaires des entités.
Fusion de nœuds d'un maillage.
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.
Int32 toInt32(Int64 v)
Converti un Int64 en un Int32.
@ 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.
ARCCORE_BASE_EXPORT 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:538
@ SB_AllowNull
Autorise l'absence du service.
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:426
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:554
Int32 Integer
Type représentant un entier.
UniqueArray< Real3 > Real3UniqueArray
Tableau dynamique à une dimension de vecteurs de rang 3.
Definition UtilsTypes.h:450
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:569
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:567
ArrayView< Int32 > Int32ArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:540
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:573
ArrayView< Real > RealArrayView
Equivalent C d'un tableau à une dimension de réels.
Definition UtilsTypes.h:546
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