Arcane  v3.14.10.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-2023 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-2023 */
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
27#include "arcane/utils/NotImplementedException.h"
28
29#include "arcane/IMesh.h"
30#include "arcane/IMeshWriter.h"
31#include "arcane/IParallelMng.h"
32#include "arcane/MeshUtils.h"
33#include "arcane/IItemFamily.h"
34#include "arcane/ItemPrinter.h"
35#include "arcane/VariableTypes.h"
36#include "arcane/ItemPairGroup.h"
37#include "arcane/ISubDomain.h"
38#include "arcane/ServiceBuilder.h"
39#include "arcane/IParallelReplication.h"
40#include "arcane/Timer.h"
41#include "arcane/IMeshPartitioner.h"
42#include "arcane/IPrimaryMesh.h"
43#include "arcane/IMeshChecker.h"
44
45#include "arcane/mesh/UnstructuredMeshUtilities.h"
46#include "arcane/IItemFamilyNetwork.h"
47#include "arcane/ConnectivityItemVector.h"
48#include "arcane/mesh/NewItemOwnerBuilder.h"
49#include "arcane/mesh/ParticleFamily.h"
50#include "arcane/mesh/GraphDoFs.h"
51#include "arcane/mesh/BasicItemPairGroupComputeFunctor.h"
52#include "arcane/mesh/MeshNodeMerger.h"
53#include "arcane/mesh/ConnectivityNewWithDependenciesTypes.h"
54
55#include <algorithm>
56
57/*---------------------------------------------------------------------------*/
58/*---------------------------------------------------------------------------*/
59
60namespace Arcane
61{
62
63/*---------------------------------------------------------------------------*/
64/*---------------------------------------------------------------------------*/
65
66UnstructuredMeshUtilities::
67UnstructuredMeshUtilities(IMesh* mesh)
68: TraceAccessor(mesh->traceMng())
69, m_mesh(mesh)
70, m_compute_adjency_functor(new BasicItemPairGroupComputeFunctor(traceMng()))
71{
72}
73
74/*---------------------------------------------------------------------------*/
75/*---------------------------------------------------------------------------*/
76
77UnstructuredMeshUtilities::
78~UnstructuredMeshUtilities()
79{
80 delete m_compute_adjency_functor;
81}
82
83/*---------------------------------------------------------------------------*/
84/*---------------------------------------------------------------------------*/
85
86void UnstructuredMeshUtilities::
87changeOwnersFromCells()
88{
89 // On suppose qu'on connait les nouveaux propriétaires des mailles, qui
90 // se trouvent dans cells_owner. Il faut
91 // maintenant déterminer les nouveaux propriétaires des noeuds et
92 // des faces. En attendant d'avoir un algorithme qui équilibre mieux
93 // les messages, on applique le suivant:
94 // - chaque sous-domaine est responsable pour déterminer le nouveau
95 // propriétaire des noeuds et des faces qui lui appartiennent.
96 // - pour les noeuds, le nouveau propriétaire est le nouveau propriétaire
97 // de la maille connectée à ce noeud dont le uniqueId() est le plus petit.
98 // - pour les faces, le nouveau propriétaire est le nouveau propriétaire
99 // de la maille qui est derrière cette face s'il s'agit d'une face
100 // interne et de la maille connectée s'il s'agit d'une face frontière.
101 // - pour les noeuds duaux, le nouveau propriétaire est le nouveau propriétaire
102 // de la maille connectée à l'élément dual
103 // - pour les liaisons, le nouveau propriétaire est le nouveau propriétaire
104 // de la maille connectée au premier noeud dual, c'est-à-dire le propriétaire
105 // du premier noeud dual de la liaison
106
107 // Outil d'affectation des owners pour les items
108 mesh::NewItemOwnerBuilder owner_builder;
109
110 VariableItemInt32& nodes_owner(m_mesh->nodeFamily()->itemsNewOwner());
111 VariableItemInt32& edges_owner(m_mesh->edgeFamily()->itemsNewOwner());
112 VariableItemInt32& faces_owner(m_mesh->faceFamily()->itemsNewOwner());
113 VariableItemInt32& cells_owner(m_mesh->cellFamily()->itemsNewOwner());
114
115 // Détermine les nouveaux propriétaires des noeuds
116 {
117 ENUMERATE_NODE(i_node,m_mesh->ownNodes()){
118 const Node node = *i_node;
119 const Cell cell = owner_builder.connectedCellOfItem(node);
120#ifdef ARCANE_DEBUG_LOAD_BALANCING
121 if (m_nodes_owner[node]!=m_cells_owner[cell]){
122 info() << "New owner for node: " << ItemPrinter(node) << " cell=" << ItemPrinter(cell)
123 << " old_owner=" << nodes_owner[node]
124 << " current_cell_owner=" << cell.owner()
125 << " new_owner=" << cells_owner[cell];
126 }
127#endif /* ARCANE_DEBUG_LOAD_BALANCING */
128 nodes_owner[node] = cells_owner[cell];
129 }
130 nodes_owner.synchronize();
131 }
132
133 // Détermine les nouveaux propriétaires des arêtes
134 {
135 ENUMERATE_EDGE(i_edge,m_mesh->ownEdges()){
136 const Edge edge = *i_edge;
137 const Cell cell = owner_builder.connectedCellOfItem(edge);
138#ifdef ARCANE_DEBUG_LOAD_BALANCING
139 if (m_edges_owner[edge]!=m_cells_owner[cell]){
140 info() << "New owner for edge: " << ItemPrinter(edge) << " cell=" << ItemPrinter(cell)
141 << " old_owner=" << edges_owner[edge]
142 << " current_cell_owner=" << cell.owner()
143 << " new_owner=" << cells_owner[cell];
144 }
145#endif /* ARCANE_DEBUG_LOAD_BALANCING */
146 edges_owner[edge] = cells_owner[cell];
147 }
148 edges_owner.synchronize();
149 }
150
151 // Détermine les nouveaux propriétaires des faces
152 {
153 ENUMERATE_FACE(i_face,m_mesh->ownFaces()){
154 const Face face = *i_face;
155 const Cell cell = owner_builder.connectedCellOfItem(face);
156 faces_owner[face] = cells_owner[cell];
157 }
158 faces_owner.synchronize();
159 }
160
161
162 // Détermine les nouveaux propriétaires des particules
163 // Les particules ont le même propriétaire que celui de la maille dans
164 // laquelle elle se trouve.
165 for( IItemFamily* family : m_mesh->itemFamilies() ){
166 if (family->itemKind()!=IK_Particle)
167 continue;
168 // Positionne les nouveaux propriétaires des particle
169 VariableItemInt32& particles_owner(family->itemsNewOwner());
170 ENUMERATE_PARTICLE(i_particle,family->allItems()){
173 }
174 }
175
176 // GraphOnDoF
177 if(m_mesh->itemFamilyNetwork())
178 {
179 // Dof with Mesh Item connectivity
180 for( IItemFamily* family : m_mesh->itemFamilies() )
181 {
182 if (family->itemKind()!=IK_DoF || family->name()==mesh::GraphDoFs::linkFamilyName())
183 continue;
184 VariableItemInt32& dofs_new_owner(family->itemsNewOwner());
185 std::array<Arcane::eItemKind,5> dualitem_kinds = {IK_Cell,IK_Face,IK_Edge,IK_Node,IK_Particle} ;
186 for(auto dualitem_kind : dualitem_kinds)
187 {
188 IItemFamily* dualitem_family = dualitem_kind==IK_Particle? m_mesh->findItemFamily(dualitem_kind,mesh::ParticleFamily::defaultFamilyName(), false):
189 m_mesh->itemFamily(dualitem_kind) ;
191 {
192
194 auto connectivity_name = mesh::connectivityName(family,dualitem_family) ;
195 bool is_dof2dual = true ;
196 auto connectivity = m_mesh->itemFamilyNetwork()->getConnectivity(family,dualitem_family,connectivity_name) ;
197 if(!connectivity)
198 {
199 connectivity = m_mesh->itemFamilyNetwork()->getConnectivity(dualitem_family,family,connectivity_name) ;
201 }
202
203 if(connectivity)
204 {
205 ConnectivityItemVector accessor(connectivity);
206 if(is_dof2dual)
207 {
208 ENUMERATE_ITEM(item, family->allItems().own())
209 {
210 auto connected_items = accessor.connectedItems(ItemLocalId(item)) ;
211 if(connected_items.size()>0)
212 {
214 }
215 }
216 }
217 else
218 {
219 ENUMERATE_ITEM(item, dualitem_family->allItems())
220 {
222 {
224 }
225 }
226 }
227 }
228 }
229 }
230 }
231 // Dof with DoF connectivity
232 IItemFamily* links_family = m_mesh->findItemFamily(IK_DoF, mesh::GraphDoFs::linkFamilyName(), false);
233 if(links_family)
234 {
236 IItemFamily* dualnodes_family = m_mesh->findItemFamily(IK_DoF, mesh::GraphDoFs::dualNodeFamilyName(), false);
238 {
240 auto connectivity_name = mesh::connectivityName(links_family,dualnodes_family) ;
241 auto connectivity = m_mesh->itemFamilyNetwork()->getConnectivity(links_family,dualnodes_family,connectivity_name) ;
242 if(connectivity)
243 {
244 ConnectivityItemVector accessor(connectivity);
245 ENUMERATE_ITEM(item, links_family->allItems().own())
246 {
247 auto connected_items = accessor.connectedItems(ItemLocalId(item)) ;
248 if(connected_items.size()>0)
249 {
251 }
252 }
253 }
254 }
255 }
256 }
257}
258
259/*---------------------------------------------------------------------------*/
260/*---------------------------------------------------------------------------*/
261
262void UnstructuredMeshUtilities::
263localIdsFromConnectivity(eItemKind item_kind,
267 bool allow_null)
268{
269 Integer nb_item = items_nb_node.size();
270 if (item_kind!=IK_Face && item_kind!=IK_Cell)
271 throw InvalidArgumentException(A_FUNCINFO,"item_kind",
272 "IK_Cell or IK_Face expected",
273 (int)item_kind);
274 if (item_kind==IK_Cell)
275 throw NotImplementedException(A_FUNCINFO,"not implemented for cells");
276
277 if (nb_item!=local_ids.size())
278 throw InvalidArgumentException(A_FUNCINFO,"local_ids",
279 "Size different from 'items_nb_node'",
280 (int)item_kind);
281
282 Integer item_connectivity_index = 0;
284 buf.reserve(256);
285 ItemInternalList nodes(m_mesh->itemsInternal(IK_Node));
286 for( Integer i=0; i<nb_item; ++i ){
287 Integer current_nb_node = items_nb_node[i];
290 if (item_kind==IK_Face){
292 mesh_utils::reorderNodesOfFace(current_nodes,buf);
293 Int64 first_node_uid = buf[0];
295 Int32 first_node_lid = CheckedConvert::toInt32(buf[0]);
297 m_mesh->nodeFamily()->itemsUniqueIdToLocalId(first_node_lid_array,first_node_uid_array,!allow_null);
298 if (first_node_lid == NULL_ITEM_LOCAL_ID){
299 if (allow_null){
300 local_ids[i] = NULL_ITEM_LOCAL_ID;
301 }
302 else {
303 StringBuilder sb("Face with nodes (");
304 for(Integer j=0;j<current_nb_node;++j) {
305 if (j != 0) sb += " ";
306 sb += current_nodes[j];
307 }
308 sb += ") not found (first node ";
310 sb += " not found)";
311 ARCANE_FATAL(sb.toString());
312 }
313 continue;
314 }
315
316 Node node(nodes[first_node_lid]);
317 Face face(mesh_utils::getFaceFromNodesUnique(node,buf));
318 if (face.null()){
319 if (allow_null){
320 local_ids[i] = NULL_ITEM_LOCAL_ID;
321 }
322 else {
323 StringBuilder sb("Face with nodes (");
324 for(Integer j=0;j<current_nb_node;++j) {
325 if (j != 0) sb += " ";
326 sb += current_nodes[j];
327 }
328 sb += ") not found";
329 ARCANE_FATAL(sb.toString());
330 }
331 }
332 else
333 local_ids[i] = face.localId();
334 }
335 }
336}
337
338/*---------------------------------------------------------------------------*/
339/*---------------------------------------------------------------------------*/
340
341Real3 UnstructuredMeshUtilities::
342_round(Real3 value)
343{
344 Real3 rvalue = value;
345 // Evite les problèmes d'arrondi numérique
346 if (math::isNearlyZero(value.x))
347 rvalue.x = 0.0;
348 if (math::isNearlyZero(value.y))
349 rvalue.y = 0.0;
350 if (math::isNearlyZero(value.z))
351 rvalue.z = 0.0;
352
353 if (math::isNearlyEqual(value.x,1.0))
354 rvalue.x = 1.0;
355 if (math::isNearlyEqual(value.y,1.0))
356 rvalue.y = 1.0;
357 if (math::isNearlyEqual(value.z,1.0))
358 rvalue.z = 1.0;
359
360 if (math::isNearlyEqual(value.x,-1.0))
361 rvalue.x = -1.0;
362 if (math::isNearlyEqual(value.y,-1.0))
363 rvalue.y = -1.0;
364 if (math::isNearlyEqual(value.z,-1.0))
365 rvalue.z = -1.0;
366
367 return rvalue;
368}
369
370/*---------------------------------------------------------------------------*/
371/*---------------------------------------------------------------------------*/
372
373Real3 UnstructuredMeshUtilities::
374computeNormal(const FaceGroup& face_group,const VariableNodeReal3& nodes_coord)
375{
376 String func_name = "UnstructuredMeshUtilities::computeNormal";
377 IParallelMng* pm = m_mesh->parallelMng();
378 Integer rank = pm->commRank();
379 //Integer nb_item = face_group.size();
380 Integer nb_node = 0;
381 Integer mesh_dimension = m_mesh->dimension();
382 // 'global_normal' et 'total_global_normal' servent à determiner
383 // une direction pour la surface en supposant qu'il s'agit
384 // d'une surface externe. La direction sert ensuite à orienter
385 // la normale calculée dans le sens normal sortante.
386 Real3 global_normal = Real3::null();
389 Face face = *iface;
390 Integer face_nb_node = face.nbNode();
392
393 if (face.isSubDomainBoundary() && face.isOwn()){
395 if (mesh_dimension==3){
396 Real3 v1 = nodes_coord[face.node(1)] - nodes_coord[face.node(0)];
397 Real3 v2 = nodes_coord[face.node(2)] - nodes_coord[face.node(0)];
398 face_normal = math::vecMul(v1,v2);
399 }
400 else if (mesh_dimension==2){
401 Real3 dir = nodes_coord[face.node(0)] - nodes_coord[face.node(1)];
402 face_normal.x = - dir.y;
403 face_normal.y = dir.x;
404 face_normal.z = 0.0;
405 }
406 if (face.boundaryCell()==face.frontCell())
408 //info() << "ADD NORMAL normal=" << face_normal;
411 }
412 }
413 // L'algorithme tente de déterminer les noeuds aux extrémités de la surface
414 // On considère qu'il s'agit de ceux qui n'appartiennent qu'à une seule
415 // face de la surface. Cela fonctionne bien si toutes les faces ont au moins
416 // quatres arêtes. S'il y a des triangles, on suppose que ce n'est pas
417 // partout et dans ce cas on a au moins deux noeuds extrèmes connus.
419 // Range dans la table pour chaque noeud le nombre de faces de la surface
420 // auxquelles il est connecté.
423 Face face = *iface;
424 for( NodeLocalId inode : face.nodeIds() ){
425 NodeOccurenceMap::Data* v = nodes_occurence.lookup(inode);
426 if (v)
427 ++v->value();
428 else{
429 //info() << " ADD NODE " << ItemPrinter(*inode) << " coord=" << nodes_coord[inode];
430 nodes_occurence.add(inode,1);
431 }
432 }
433 }
435 NodeInfoListView nodes_internal(m_mesh->nodeFamily());
436 nodes_occurence.each([&](NodeOccurenceMap::Data* d){
437 if (d->value()==1){
438 Node node = nodes_internal[d->key()];
439 // En parallèle, ne traite que les noeuds qui nous appartiennent
440 if (node.owner()==rank){
441 single_nodes.add(node);
442 //info() << "SINGLE NODE OWNER lid=" << d->key() << " " << ItemPrinter(node)
443 // << " coord=" << nodes_coord[node];
444 }
445 }
446 });
447 // Chaque sous-domaine collecte les coordonnées des noeuds des autres sous-domaines
448 Integer nb_single_node = single_nodes.size();
449 //info() << "NB SINGLE NODE= " << nb_single_node;
450 Integer total_nb_single_node = pm->reduce(Parallel::ReduceSum,nb_single_node);
452 {
453 Real all_min = 0.0;
454 Real all_max = 0.0;
455 Real all_sum = 0.0;
456 Int32 min_rank = -1;
457 Int32 max_rank = -1;
459 Real3 buf;
460 if (max_rank==rank){
461 // Je suis celui qui a le point le plus loin. Je l'envoie aux autres.
462 buf = global_normal;
463 }
464 pm->broadcast(Real3ArrayView(1,&buf),max_rank);
465 total_global_normal = buf;
466 }
467
468 info() << "TOTAL SINGLE NODE= " << total_nb_single_node << " surface=" << face_group.name()
469 << " global_normal = " << total_global_normal;
470 if (total_nb_single_node<2){
471 ARCANE_FATAL("not enough nodes connected to only one face");
472 }
473 Real3UniqueArray coords(nb_single_node);
474 for( Integer i=0; i<nb_single_node; ++i ){
475 coords[i] = nodes_coord[single_nodes[i]];
476 }
477 //Array<Real> all_nodes_coord_real;
478 UniqueArray<Real3> all_nodes_coord;
479 pm->allGatherVariable(coords,all_nodes_coord);
480 //info() << " ALL NODES COORD n=" << all_nodes_coord_real.size();
481 //Array<Real3> all_nodes_coord(total_nb_single_node);
482 Real3 barycentre = Real3::null();
483 for( Integer i=0; i<total_nb_single_node; ++i ){
484 barycentre += all_nodes_coord[i];
485 }
486 barycentre /= (Real)total_nb_single_node;
487 if (total_nb_single_node==2 && m_mesh->dimension()==3){
488 // On a que deux noeuds. Il en faut au moins un troisième pour déterminer
489 // la normale au plan. Pour cela, chaque processeur cherche le noeud de
490 // la surface qui est le plus éloigné du barycentre des deux noeuds déjà
491 // trouvé. Ce noeud le plus éloigné servira de troisième point pour le
492 // plan.
493 Real max_distance = 0.0;
494 Node farthest_node;
495 Real3 s0 = all_nodes_coord[0];
496 Real3 s1 = all_nodes_coord[1];
497 nodes_occurence.each([&](NodeOccurenceMap::Data* d){
498 Node node = nodes_internal[d->key()];
499 Real3 coord = nodes_coord[node];
500 // Ne traite pas les deux noeuds du déjà trouvés
501 if (math::isNearlyEqual(coord,s0))
502 return;
503 if (math::isNearlyEqual(coord,s1))
504 return;
505 Real distance = (coord - barycentre).squareNormL2();
506 if (distance>max_distance){
507 Real3 normal = math::cross(coord-s0, s1-s0);
508 // On ne prend le noeud que s'il n'est pas aligné avec les deux autres.
509 if (!math::isNearlyZero(normal.squareNormL2())){
510 max_distance = distance;
511 farthest_node = node;
512 }
513 }
514 });
515
516 if (!farthest_node.null()){
517 info() << " FARTHEST NODE= " << ItemPrinter(farthest_node) << " dist=" << max_distance;
518 }
519 {
520 Real3 farthest_coord = _broadcastFarthestNode(max_distance,farthest_node,nodes_coord);
521 info() << " FARTHEST NODE ALL coord=" << farthest_coord;
522 all_nodes_coord.add(farthest_coord);
523 }
524 }
525 // Trie les noeuds pour que le calcul ne dépende pas de l'ordre des
526 // opérations en parallèle.
527 std::sort(std::begin(all_nodes_coord),std::end(all_nodes_coord));
528 Integer nb_final_node = all_nodes_coord.size();
529 Real3 full_normal = Real3::null();
530 info() << " NB FINAL NODE=" << nb_final_node;
531 for( Integer i=0; i<nb_final_node; ++i )
532 info() << " NODE=" << all_nodes_coord[i];
533 if (m_mesh->dimension()==2){
534 if (nb_final_node!=2){
535 ARCANE_FATAL("should have 2 border nodes in 2D mesh");
536 }
537 Real3 direction = all_nodes_coord[1] - all_nodes_coord[0];
538 full_normal.x = - direction.y;
539 full_normal.y = direction.x;
540 }
541 else if (m_mesh->dimension()==3){
542 //nb_final_node = 3; // On prend que les 3 premiers points.
543 // NOTE: on pourrait prendre tous les points, car si les trois premiers sont
544 // alignés, la normale ne sera pas bonne.
545 // Si on prend tous les points, il faut être sur qu'ils soient ordonnés
546 // de telle sorte que la normale de trois points consécutifs est toujours
547 // dans le même sens. Cela signifie si on a quatres points par exemple,
548 // que ces 4 points forment un quadrangle non croisé (pas en forme
549 // de papillon)
550 Real3 first_normal = math::vecMul(all_nodes_coord[2]-all_nodes_coord[0],
551 all_nodes_coord[1]-all_nodes_coord[0]);
552 for( Integer i=0; i<nb_final_node; ++i ){
553 Real3 s0 = all_nodes_coord[i];
554 Real3 s1 = all_nodes_coord[(i+nb_final_node-1)%nb_final_node];
555 Real3 s2 = all_nodes_coord[(i+1)%nb_final_node];
556 Real3 normal = math::vecMul(s2-s0, s1-s0);
557 info() << " ADD NORMAL: " << normal;
558 full_normal += normal;
559 info() << " FULL: " << full_normal;
560 }
561 if (math::isNearlyZero(full_normal.squareNormL2()))
562 full_normal = first_normal;
563 }
564 else
565 ARCANE_FATAL("invalid mesh dimension (should be 2 or 3)");
566 Real a = full_normal.normL2();
567 if (math::isZero(a))
568 ARCANE_FATAL("invalid value for normal");
569 full_normal /= a;
570 Real b = total_global_normal.normL2();
571 Real dir = 0.0;
572 info() << " Normal is " << full_normal;
573 if (!math::isZero(b)){
574 total_global_normal /= b;
575 dir = math::scaMul(full_normal,total_global_normal);
576 if (dir<0.0)
577 full_normal = -full_normal;
578 }
579 full_normal = _round(full_normal);
580 info() << " Final normal is " << full_normal << " dir=" << dir;
581 return full_normal;
582}
583
584/*---------------------------------------------------------------------------*/
585/*---------------------------------------------------------------------------*/
593Real3 UnstructuredMeshUtilities::
594computeDirection(const NodeGroup& node_group,
596 Real3* n1,Real3* n2)
597{
598 String func_name = "UnstructuredMeshUtilities::computeDirection";
599 IParallelMng* pm = m_mesh->parallelMng();
600 //Integer rank = pm->commRank();
601 //Integer nb_node_own = node_group.own().size();
602 //Integer total_nb_node_own = pm->reduce(Parallel::ReduceSum,nb_node_own);
603 Real3 barycentre = Real3::null();
606 }
607 Real r_barycentre[3];
612 pm->reduce(Parallel::ReduceSum,rav);
613 barycentre = Real3(rav[0],rav[1],rav[2]);
614 debug() << " BARYCENTRE COMPUTE DIRECTION = " << barycentre;
615 pm->barrier();
616
617 // Détermine le noeud le plus éloigné du barycentre
619 {
620 Real max_distance = 0.0;
623 Node node = *inode;
624 Real3 coord = nodes_coord[node];
625 Real distance = (coord - barycentre).squareNormL2();
626 if (distance>max_distance){
627 max_distance = distance;
628 farthest_node = node;
629 }
630 }
632 if (n1)
634 }
636 {
637 Real max_distance = 0.0;
640 Node node = *inode;
641 Real3 coord = nodes_coord[node];
642 Real distance = (coord - first_boundary_coord).squareNormL2();
643 if (distance>max_distance){
644 max_distance = distance;
645 farthest_node = node;
646 }
647 }
649 if (n2)
651 }
653 Real norm = direction.normL2();
654 if (math::isZero(norm)){
655 ARCANE_FATAL("Direction is null for group '{0}' first_coord={1} second_coord={2}",
657 }
658 return direction / norm;
659}
660
661/*---------------------------------------------------------------------------*/
662/*---------------------------------------------------------------------------*/
663
664Real3 UnstructuredMeshUtilities::
665_broadcastFarthestNode(Real distance,const Node& farthest_node,
667{
668 String func_name = "UnstructuredMeshUtilities::_broadcastFarthestNode()";
669 IParallelMng* pm = m_mesh->parallelMng();
670 Integer rank = pm->commRank();
671
672 Real all_min_distance = 0.0;
673 Real all_max_distance = 0.0;
674 Real all_sum_distance = 0.0;
675 Int32 min_rank = -1;
676 Int32 max_rank = -1;
678 Real3 buf;
679 if (!farthest_node.null())
680 debug() << " FARTHEST NODE myself coord=" << nodes_coord[farthest_node]
681 << " distance=" << distance
682 << " rank=" << max_rank
683 << " max_distance=" << all_max_distance;
684 else
685 debug() << " FARTHEST NODE myself coord=none"
686 << " distance=" << distance
687 << " rank=" << max_rank
688 << " max_distance=" << all_max_distance;
689
690 if (max_rank==rank){
691 if (farthest_node.null())
692 ARCANE_FATAL("can not find farthest node");
693 // Je suis celui qui a le point le plus loin. Je l'envoie aux autres.
695 debug() << " I AM FARTHEST NODE ALL coord=" << buf;
696 }
697 pm->broadcast(Real3ArrayView(1,&buf),max_rank);
698 Real3 farthest_coord(buf);
699 debug() << " FARTHEST NODE ALL coord=" << farthest_coord
700 << " rank=" << max_rank
701 << " max_distance=" << all_max_distance;
702 return farthest_coord;
703}
704
705/*---------------------------------------------------------------------------*/
706/*---------------------------------------------------------------------------*/
707
708void UnstructuredMeshUtilities::
710{
711 m_compute_adjency_functor->computeAdjency(adjency_array,link_kind,nb_layer);
712}
713
714/*---------------------------------------------------------------------------*/
715/*---------------------------------------------------------------------------*/
716
717bool UnstructuredMeshUtilities::
718writeToFile(const String& file_name,const String& service_name)
719{
720 ServiceBuilder<IMeshWriter> sb(m_mesh->handle());
721 auto mesh_writer = sb.createReference(service_name,SB_AllowNull);
722
723 if (!mesh_writer){
725 sb.getServicesNames(available_names);
726 warning() << String::format("The specified service '{0}' to write the mesh is not available."
727 " Valid names are {1}",service_name,available_names);
728 return true;
729 }
730 mesh_writer->writeMeshToFile(m_mesh,file_name);
731 return false;
732}
733
734/*---------------------------------------------------------------------------*/
735/*---------------------------------------------------------------------------*/
736
737void UnstructuredMeshUtilities::
738partitionAndExchangeMeshWithReplication(IMeshPartitionerBase* partitioner,
740{
741 IPrimaryMesh* primary_mesh = partitioner->primaryMesh();
742 IMesh* mesh = primary_mesh;
743 if (mesh!=this->m_mesh)
744 throw ArgumentException(A_FUNCINFO,"partitioner->mesh() != this->m_mesh");
745
746 IParallelMng* pm = mesh->parallelMng();
747 ITimeStats* ts = pm->timeStats();
749 bool has_replication = pr->hasReplication();
750
751 // En mode réplication, seul le premier réplicat fait l'équilibrage.
752 // Il doit ensuite envoyer aux autres ces informations de maillage
753 // pour qu'ils aient le même maillage.
754
755 info() << "Partition start date=" << platform::getCurrentDateTime();
756 if (pr->isMasterRank()){
757 Timer::Action ts_action1(ts,"MeshPartition",true);
758 info() << "Partitioning the mesh (initial?=" << initial_partition << ")";
759 partitioner->partitionMesh(initial_partition);
760 }
761 else
762 info() << "Waiting for partition information from the master replica";
763
764 if (has_replication){
765 pm->barrier();
766
767 // Vérifie que toute les familles sont les mêmes.
768 mesh->checker()->checkValidReplication();
769
770 Int32 replica_master_rank = pr->masterReplicationRank();
771 IParallelMng* rep_pm = pr->replicaParallelMng();
772
773 // Seul le replica maitre a les bons propriétaires. Il faut mettre
774 // à jour les autres à partir de celui-ci. Pour cela on synchronize
775 // les propriétaires des mailles et ensuite on met à jour les autres familles
776 // à partir des propriétaires des mailles.
777 {
778 Int32ArrayView owners = mesh->cellFamily()->itemsNewOwner().asArray();
780 if (!pr->isMasterRank()){
781 changeOwnersFromCells();
782 }
783 }
784 }
785 info() << "Partition end date=" << platform::getCurrentDateTime();
786 {
787 Timer::Action ts_action2(ts,"MeshExchange",true);
788 primary_mesh->exchangeItems();
789 }
790 info() << "Exchange end date=" << platform::getCurrentDateTime();
791 partitioner->notifyEndPartition();
792
793 // Il faut recompacter pour se retrouver dans la même situation que
794 // si on avait juste lu un maillage directement (qui fait un prepareForDump()
795 // lors de l'appel à endAllocate()).
796 // On le fait aussi en cas de réplication pour éviter d'éventuelles
797 // incohérences si par la suite certains réplicas appellent cette
798 // méthode et pas les autres.
799 // TODO: regarder s'il faut le faire aussi en cas de repartitionnement.
801 mesh->prepareForDump();
802}
803
804/*---------------------------------------------------------------------------*/
805/*---------------------------------------------------------------------------*/
806
807void UnstructuredMeshUtilities::
810{
811 mesh::MeshNodeMerger merger(m_mesh);
813}
814
815/*---------------------------------------------------------------------------*/
816/*---------------------------------------------------------------------------*/
817
818} // End namespace Arcane
819
820/*---------------------------------------------------------------------------*/
821/*---------------------------------------------------------------------------*/
822
#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_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.
Maille d'un maillage.
Definition Item.h:1178
Gère la récupération des informations de connectivité.
ItemVectorView connectedItems(ItemLocalId item)
Retourne les entités connectées à item.
Arête d'une maille.
Definition Item.h:798
Face d'une maille.
Definition Item.h:932
Cell frontCell() const
Maille devant la face (maille nulle si aucune)
Definition Item.h:1604
bool isSubDomainBoundary() const
Indique si la face est au bord du sous-domaine (i.e nbCell()==1)
Definition Item.h:1025
Cell boundaryCell() const
Maille associée à cette face frontière (maille nulle si aucune)
Definition Item.h:1592
Interface d'une famille d'entités.
virtual IItemFamily * cellFamily()=0
Retourne la famille des mailles.
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)
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual IMeshChecker * checker() const =0
Interface du vérificateur.
virtual void prepareForDump()=0
Prépare l'instance en vue d'une protection.
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.
Interface gérant les statistiques sur les temps d'exécution.
Definition ITimeStats.h:48
Exception lorsqu'une erreur fatale est survenue.
Index d'un Item dans une variable.
Definition ItemLocalId.h:40
Tableau de listes d'entités.
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:35
Node node(Int32 i) const
i-ème noeud de l'entité
Definition Item.h:768
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:765
NodeLocalIdView nodeIds() const
Liste des noeuds de l'entité
Definition Item.h:774
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:210
bool isOwn() const
true si l'entité est appartient au sous-domaine
Definition Item.h:244
Int32 owner() const
Numéro du sous-domaine propriétaire de l'entité
Definition Item.h:229
constexpr bool null() const
true si l'entité est nul (i.e. non connecté au maillage)
Definition Item.h:207
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Vue sur les informations des noeuds.
Noeud d'un maillage.
Definition Dom.h:204
Particule.
Definition Item.h:1383
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
ARCCORE_HOST_DEVICE Real normL2() const
Retourne la norme L2 du triplet .
Definition Real3.h:232
Postionne le nom de l'action en cours d'exécution.
Definition Timer.h:110
Exception lorsqu'un argument est invalide.
Vue modifiable d'un tableau d'un type T.
void reserve(Int64 new_capacity)
Réserve le mémoire pour new_capacity éléments.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
Vue constante d'un tableau de type T.
Exception lorsqu'une fonction n'est pas implémentée.
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
Vecteur 1D de données avec sémantique par valeur (style STL).
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
@ SB_AllowNull
Autorise l'absence du service.
UniqueArray< Real3 > Real3UniqueArray
Tableau dynamique à une dimension de vecteurs de rang 3.
Definition UtilsTypes.h:529
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.
Int32 Integer
Type représentant un entier.