Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
MeshCutService.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/* MeshCutService.cc (C) 2000-2026 */
9/* */
10/* Service permettant la création d'un maillage avec une coupe d'un autre */
11/* maillage. */
12/*---------------------------------------------------------------------------*/
13/*---------------------------------------------------------------------------*/
14
15#include "arcane/utils/StringBuilder.h"
16
17#include "arcane/core/IGhostLayerMng.h"
18#include "arcane/core/IItemFamily.h"
19#include "arcane/core/IMesh.h"
20#include "arcane/core/IMeshFactoryMng.h"
21#include "arcane/core/IMeshMng.h"
22#include "arcane/core/IMeshModifier.h"
23#include "arcane/core/IPrimaryMesh.h"
24#include "arcane/core/MeshBuildInfo.h"
25
26#include "arcane/core/IMeshSection.h"
27#include "arcane/std/MeshCut_axl.h"
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane
33{
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38namespace
39{
47struct NodeOnEdge
48{
49 NodeOnEdge(const Node first_node, const Node second_node)
50 {
51 const Int64 a = first_node.uniqueId();
52 const Int64 b = second_node.uniqueId();
53 if (a < b) {
54 m_node0 = first_node;
55 m_node1 = second_node;
56 m_uid_node0 = a;
57 m_uid_node1 = b;
58 }
59 else {
60 m_node0 = second_node;
61 m_node1 = first_node;
62 m_uid_node0 = b;
63 m_uid_node1 = a;
64 }
65 }
66
67 NodeOnEdge(Int64 first_node, Int64 second_node)
68 {
69 if (first_node < second_node) {
70 m_uid_node0 = first_node;
71 m_uid_node1 = second_node;
72 }
73 else {
74 m_uid_node0 = second_node;
75 m_uid_node1 = first_node;
76 }
77 }
78
79 NodeOnEdge() = default;
80
81 bool operator<(const NodeOnEdge& other) const
82 {
83 if (m_uid_node0 != other.m_uid_node0) {
84 return m_uid_node0 < other.m_uid_node0;
85 }
86 return m_uid_node1 < other.m_uid_node1;
87 }
88
89 bool operator==(const NodeOnEdge& other) const
90 {
91 return m_uid_node0 == other.m_uid_node0 && m_uid_node1 == other.m_uid_node1;
92 }
93
94 Node m_node0;
95 Node m_node1;
96
97 Int64 m_uid_node0 = -1;
98 Int64 m_uid_node1 = -1;
99
100 Int64 m_uid_new_node = -1;
101 Int32 m_owner_new_node = -1;
102};
103
104/*---------------------------------------------------------------------------*/
105/*---------------------------------------------------------------------------*/
106
110struct FaceLite
111{
112 FaceLite(const Ref<NodeOnEdge>& node0, const Ref<NodeOnEdge>& node1)
113 : m_node0(node0->m_uid_node0 < node1->m_uid_node0 ? node0 : node1)
114 , m_node1(node0->m_uid_node0 < node1->m_uid_node0 ? node1 : node0)
115 {
116 const Int64 node00 = node0->m_uid_node0;
117 const Int64 node01 = node0->m_uid_node1;
118 const Int64 node10 = node1->m_uid_node0;
119 const Int64 node11 = node1->m_uid_node1;
120
121 if (node00 < node10) {
122 m_node0 = node0;
123 m_node1 = node1;
124 }
125 else if (node00 > node10) {
126 m_node0 = node1;
127 m_node1 = node0;
128 }
129 else {
130 if (node01 == node11) {
131 ARCANE_FATAL("Impossible (normalement...)");
132 }
133 if (node01 < node11) {
134 m_node0 = node0;
135 m_node1 = node1;
136 }
137 else {
138 m_node0 = node1;
139 m_node1 = node0;
140 }
141 }
142 }
143
144 bool operator<(const FaceLite& other) const
145 {
146 return m_node0->operator<(*(other.m_node0.get())) || (m_node0->operator==(*(other.m_node0.get())) && m_node1->operator<(*(other.m_node1.get())));
147 }
148
149 bool operator==(const FaceLite& other) const
150 {
151 return m_node0->operator==(*(other.m_node0.get())) && m_node1->operator==(*(other.m_node1.get()));
152 }
153
154 Ref<NodeOnEdge> m_node0;
155 Ref<NodeOnEdge> m_node1;
156
157 Int64 m_uid_new_face = -1;
158 Int32 m_owner_new_face = -1;
159};
160
161/*---------------------------------------------------------------------------*/
162/*---------------------------------------------------------------------------*/
163
167struct NodeIntersection
168{
169 NodeIntersection(const Node first_node, const Node second_node, const Real3& intersection_pos)
170 : m_new_node(makeRef(new NodeOnEdge(first_node, second_node)))
171 , m_intersection_pos(intersection_pos)
172 {}
173
174 NodeIntersection(Int64 first_node, Int64 second_node, const Real3& intersection_pos)
175 : m_new_node(makeRef(new NodeOnEdge(first_node, second_node)))
176 , m_intersection_pos(intersection_pos)
177 {}
178
179 NodeIntersection() = default;
180
181 bool operator<(const NodeIntersection& other) const
182 {
183 return m_new_node->operator<(*(other.m_new_node.get()));
184 }
185
186 bool operator==(const NodeIntersection& other) const
187 {
188 return m_new_node->operator==(*(other.m_new_node.get()));
189 }
190
191 Ref<NodeOnEdge> m_new_node;
192 Real3 m_intersection_pos{ -1 };
193};
194
195/*---------------------------------------------------------------------------*/
196/*---------------------------------------------------------------------------*/
197
198struct UnknownNodeOrFace
199{
200 UnknownNodeOrFace(Int64 node0_uid, Int64 node1_uid, Int32 who) : m_node0_uid(node0_uid), m_node1_uid(node1_uid), m_who(who){}
201 bool null() const {return m_who == -1;}
202 bool operator==(const UnknownNodeOrFace& other) const{return m_node0_uid == other.m_node0_uid && m_node1_uid == other.m_node1_uid;}
203 Int64 m_node0_uid;
204 Int64 m_node1_uid;
205 Int32 m_who;
206};
207} // namespace
208
209/*---------------------------------------------------------------------------*/
210/*---------------------------------------------------------------------------*/
211
212/*---------------------------------------------------------------------------*/
213/*---------------------------------------------------------------------------*/
214
222class MeshCutService
223: public ArcaneMeshCutObject
224{
225 public:
226
227 explicit MeshCutService(const ServiceBuildInfo& sbi)
229 , m_creation_type(sbi.creationType())
230 {}
231
232 public:
233
234 void addPlane(const Real3& p0, const Real3& normal) override;
235
237
238 void setServiceMeshUniqueId(Int32 unique_id) override;
239
240 VariableCollection variables() override { return {}; }
241
242 void updateSection() override;
243
245 {
246 return m_cloned_mesh->handle();
247 }
248
249 private:
250
251 void _createMesh();
252 void _createNodesAndCells(Int32 plan_pos, Int32& sd_nb_node, UniqueArray<NodeIntersection>& new_nodes, Int32 ajust_node_pos, Int32& sd_nb_cell, UniqueArray<Int64>& new_cells, Int32& sd_nb_face, UniqueArray<FaceLite>& new_faces);
253 void _makeUniqueCellUID(Int32 sd_nb_cell, UniqueArray<Int64>& new_cells, UniqueArray<NodeIntersection>& new_nodes);
254
255 void _fillNodeUID(Int32& sd_nb_node, UniqueArray<NodeIntersection>& new_nodes);
256 Int32 _makeUniqueNodeUID(Int32 sd_nb_node, UniqueArray<NodeIntersection>& new_nodes);
257 void _fillFaceUID(Int32& sd_nb_face, UniqueArray<FaceLite>& new_faces);
258 Int32 _makeUniqueFaceUID(Int32 sd_nb_face, UniqueArray<FaceLite>& new_faces);
259 void _compute();
260
261 std::optional<Int64> _find(Span<FaceLite> new_faces, Int64 node_uid0, Int64 node_uid1);
262
263 void _addFaces(UniqueArray<FaceLite>& new_faces) const;
264 void _addCells(UniqueArray<Int64>& new_cells);
265 void _setCoordNodesAndOwner(UniqueArray<NodeIntersection>& new_nodes);
266 void _setFacesOwner(UniqueArray<FaceLite>& new_faces);
267
268 private:
269
270 eServiceType m_creation_type;
271 // VariableCollection m_variables_ori;
272 IPrimaryMesh* m_cloned_mesh = nullptr;
274 Int32 m_mesh_uid = -1;
275};
276
277/*---------------------------------------------------------------------------*/
278/*---------------------------------------------------------------------------*/
279
280ARCANE_REGISTER_SERVICE_MESHCUT(MeshCut, MeshCutService);
281
282/*---------------------------------------------------------------------------*/
283/*---------------------------------------------------------------------------*/
284
285/*---------------------------------------------------------------------------*/
286/*---------------------------------------------------------------------------*/
287
289addPlane(const Real3& p0, const Real3& normal)
290{
291 m_plans.add({ p0, math::normalizeReal3(normal) });
292}
293
294/*---------------------------------------------------------------------------*/
295/*---------------------------------------------------------------------------*/
296
299{
300 ARCANE_UNUSED(variables);
301 ARCANE_NOT_YET_IMPLEMENTED("Not supported yet");
302 // m_variables_ori = variables;
303}
304
305/*---------------------------------------------------------------------------*/
306/*---------------------------------------------------------------------------*/
307
310{
311 m_mesh_uid = unique_id;
312}
313
314/*---------------------------------------------------------------------------*/
315/*---------------------------------------------------------------------------*/
316
319{
320 if (mesh()->ghostLayerMng()->nbGhostLayer() < 1) {
321 ARCANE_FATAL("A ghost layer is required for this service");
322 }
323 _createMesh();
324 _compute();
325}
326
327/*---------------------------------------------------------------------------*/
328/*---------------------------------------------------------------------------*/
329
330void MeshCutService::
331_createMesh()
332{
333 if (m_cloned_mesh != nullptr) {
334 m_cloned_mesh->modifier()->clearItems();
335 }
336
337 if (mesh()->dimension() != 3) {
338 ARCANE_FATAL("Only 3D meshes are supported");
339 }
340
341 IMeshMng* mm = subDomain()->meshMng();
342
343 if (m_mesh_uid == -1) {
344 if (m_creation_type == ST_CaseOption) {
345 m_mesh_uid = options()->getUniqueIdServiceMesh();
346 }
347 else {
348 m_mesh_uid = 0;
349 }
350 }
351
352 String service_mesh_name = mesh()->name() + "_MeshCut" + m_mesh_uid;
353
354 MeshHandle* mesh_handle = mm->findMeshHandle(service_mesh_name, false);
355
356 if (mesh_handle == nullptr) {
357 IParallelMng* pm = subDomain()->parallelMng();
358 MeshBuildInfo mbi(service_mesh_name);
359 // auto mesh_kind = mbi.meshKind();
360 // mesh_kind.setMeshDimensionKind(eMeshCellDimensionKind::NonManifold);
361 // mbi.addMeshKind(mesh_kind);
362 mbi.addParallelMng(makeRef(pm));
363 m_cloned_mesh = mm->meshFactoryMng()->createMesh(mbi);
364 m_cloned_mesh->modifier()->setDynamic(true);
365 m_cloned_mesh->setDimension(2);
366 m_cloned_mesh->endAllocate();
367 }
368 else {
369 m_cloned_mesh = mesh_handle->mesh()->toPrimaryMesh();
370 m_cloned_mesh->modifier()->clearItems();
371 }
372}
373
374/*---------------------------------------------------------------------------*/
375/*---------------------------------------------------------------------------*/
376
377void MeshCutService::
378_createNodesAndCells(Int32 plan_pos, Int32& sd_nb_node, UniqueArray<NodeIntersection>& new_nodes, Int32 ajust_node_pos, Int32& sd_nb_cell, UniqueArray<Int64>& new_cells, Int32& sd_nb_face, UniqueArray<FaceLite>& new_faces)
379{
380 auto [p0, normal] = m_plans[plan_pos];
381
382 const Int32 mesh_dim = mesh()->dimension();
383
384 VariableNodeReal3& node_coord = mesh()->nodesCoordinates();
385 VariableNodeReal node_dist(VariableBuildInfo(mesh(), "NodeDist"));
386
387 UniqueArray<Int32> face_already_computed;
388
389 // Calcul de la distance signée de chaque noeud par rapport au plan de coupe.
390 ENUMERATE_ (Node, inode, allNodes()) {
391 Real d = math::dot({ node_coord[inode] - p0 }, normal);
392 node_dist[inode] = math::isNearlyZeroWithEpsilon(d, 1e-10) ? 0 : d;
393 }
394
395 // Tableau qui contiendra tous les noeuds d'une future maille.
396 // Une maille 3D, si elle est coupée par le plan, donnera forcément une
397 // maille 2D. Les noeuds de cette maille seront stockés dans ce tableau,
398 // ainsi que, pour chaque noeud, sa position et l'arête dont il est issu
399 // (pour éviter les doublons).
400 UniqueArray<NodeIntersection> point_coords_tmp;
401
402 ENUMERATE_ (Cell, icell, ownCells()) {
403 Cell cell = *icell;
404
405 bool has_face_on_plane = false;
406 {
407 bool cell_useful = true;
408 Int32 nb_node_on_plane = 0;
409
410 // On regarde si la maille traverse le plan ou si des noeuds sont sur le
411 // plan.
412 {
413 bool has_neg = false;
414 bool has_pos = false;
415 for (Node node : cell.nodes()) {
416 Real d = node_dist[node];
417 if (d < 0)
418 has_neg = true;
419 else if (d > 0)
420 has_pos = true;
421 else {
422 nb_node_on_plane++;
423 }
424 }
425
426 // Tous les noeuds sont du même coté du plan.
427 if (!(has_neg && has_pos))
428 cell_useful = false;
429 }
430
431 // Si le nombre de noeuds sur le plan correspond au nombre de noeuds
432 // minimum d'une face, il s'agit peut-être d'une face confondue au plan.
433 // Dans ce cas, il est nécessaire de faire un traitement spécial pour
434 // éviter un doublon de mailles dans le maillage final.
435 if (nb_node_on_plane >= mesh_dim) {
436 for (Face face : cell.faces()) {
437 // Pour éviter que deux processus créent la même maille.
438 if (!face.isOwn())
439 continue;
440 if (face.nbNode() != nb_node_on_plane)
441 continue;
442
443 bool has_egal = true;
444 for (Node node : face.nodes()) {
445 if (node_dist[node] != 0) {
446 has_egal = false;
447 break;
448 }
449 }
450
451 // On a trouvé la face confondue.
452 if (has_egal) {
453
454 // Si elle a déjà été traitée, on passe pour éviter un doublon.
455 if (face_already_computed.contains(face.localId())) {
456 cell_useful = false;
457 break;
458 }
459
460 // On sait que la face est confondue au plan et que la future
461 // maille créée grâce à cette face n'existe pas encore.
462 // On peut donc directement ajouter les noeuds de la face dans la
463 // liste des noeuds de la future maille.
464 face_already_computed.add(face.localId());
465 for (Node node : face.nodes()) {
466 auto ni = NodeIntersection{ node, node, node_coord[node] };
467 point_coords_tmp.add(ni);
468 }
469 has_face_on_plane = true;
470 cell_useful = true;
471 break;
472 }
473 }
474 }
475
476 if (!cell_useful)
477 continue;
478 }
479
480 if (!has_face_on_plane) {
481 // Tableaux définissant les arêtes pour chaque type d'élément.
482 // Chaque arête = [n0, n1] indices noeuds locaux de maille.
483 //
484 static constexpr Integer edges_tetraedron4[6][2] = {
485 { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 2 }, { 1, 3 }, { 2, 3 }
486 };
487 static constexpr Integer edges_pyramid5[8][2] = {
488 { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 }, { 0, 4 }, { 1, 4 }, { 2, 4 }, { 3, 4 }
489 };
490 static constexpr Integer edges_pentaedron6[9][2] = {
491 { 0, 1 }, { 1, 2 }, { 2, 0 }, { 0, 3 }, { 1, 4 }, { 2, 5 }, { 3, 4 }, { 4, 5 }, { 5, 3 }
492 };
493 static constexpr Integer edges_hexaedron8[12][2] = {
494 { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 }, { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 }
495 };
496
497 Integer nb_edges = 0;
498 const Integer(*edge_def)[2] = nullptr;
499
500 auto type = cell.itemTypeId();
501
502 if (type == ITI_Tetraedron4) {
503 nb_edges = 6;
504 edge_def = edges_tetraedron4;
505 }
506 else if (type == ITI_Pyramid5) {
507 nb_edges = 8;
508 edge_def = edges_pyramid5;
509 }
510 else if (type == ITI_Pentaedron6) {
511 nb_edges = 9;
512 edge_def = edges_pentaedron6;
513 }
514 else if (type == ITI_Hexaedron8) {
515 nb_edges = 12;
516 edge_def = edges_hexaedron8;
517 }
518
519 else {
520 ARCANE_FATAL("Cell type not supported -- type: {0}", type);
521 }
522
523 // Itère sur toutes les arêtes de la maille.
524 for (Integer i = 0; i < nb_edges; ++i) {
525 Node node0 = cell.node(edge_def[i][0]);
526 Node node1 = cell.node(edge_def[i][1]);
527
528 bool need_compute_intersection = true;
529
530 // Si le noeud 0 est sur le plan.
531 if (node_dist[node0] == 0) {
532 const Real3 p = node_coord[node0];
533
534 auto ni = NodeIntersection{ node0, node0, p };
535
536 if (!point_coords_tmp.contains(ni)) {
537 point_coords_tmp.add(ni);
538 }
539 need_compute_intersection = false;
540 }
541
542 // Si le noeud 1 est sur le plan.
543 if (node_dist[node1] == 0) {
544 const Real3 p = node_coord[node1];
545
546 auto ni = NodeIntersection{ node1, node1, p };
547
548 if (!point_coords_tmp.contains(ni)) {
549 point_coords_tmp.add(ni);
550 }
551 need_compute_intersection = false;
552 }
553
554 // Si l'arrête passe à travers le plan.
555 if (need_compute_intersection && node_dist[node0] * node_dist[node1] < 0) {
556
557 // Paramètre d'interpolation t dans [0,1] pour le point d'intersection
558 // le long de l'arête de node0 à node1.
559 Real t = std::abs(node_dist[node0]) / (std::abs(node_dist[node0]) + std::abs(node_dist[node1]));
560
561 // Calcul du point d'intersection par interpolation linéaire.
562 Real3 p;
563 p.x = node_coord[node0].x + t * (node_coord[node1].x - node_coord[node0].x);
564 p.y = node_coord[node0].y + t * (node_coord[node1].y - node_coord[node0].y);
565 p.z = node_coord[node0].z + t * (node_coord[node1].z - node_coord[node0].z);
566
567 auto ni = NodeIntersection{ node0, node1, p };
568
569 if (!point_coords_tmp.contains(ni)) {
570 point_coords_tmp.add(ni);
571 }
572 }
573 }
574 }
575
576 // Si le nombre de futurs noeuds est suffisant pour en faire une maille.
577 if (point_coords_tmp.size() >= mesh_dim) {
578
579 // Type de maille.
580 if (point_coords_tmp.size() > 6)
581 ARCANE_FATAL("Pas implem : {0}", point_coords_tmp.size());
582
583 new_cells.add(point_coords_tmp.size());
584 new_cells.add(sd_nb_cell);
585
586 {
587 // Calcul du barycentre de tous les points d'intersection.
588 Real3 bary{ 0 };
589 for (const auto& node : point_coords_tmp) {
590 bary += node.m_intersection_pos;
591 }
592 bary /= point_coords_tmp.size();
593
594 // On choisit un vecteur de référence arbitraire non parallèle au normal.
595 // Si normal.x est grand (proche de l'axe X), utiliser l'axe Y ; sinon utiliser l'axe X.
596 const Real3 arbitrary = (std::abs(normal.x) > 0.9) ? Real3{ 0.0, 1.0, 0.0 } : Real3{ 1.0, 0.0, 0.0 };
597 // u et v forment une base orthonormale du plan de coupe.
598 // Ils sont perpendiculaires au normal et l'un à l'autre.
599 const Real3 u = math::normalizedCrossProduct3(arbitrary, normal);
600 const Real3 v = math::normalizedCrossProduct3(normal, u);
601
602 // On trie les points d'intersection par angle polaire autour du barycentre.
603 // Cela garantit que le polygone résultant est correctement ordonné (sens inverse des aiguilles d'une montre).
604 UniqueArray<Int64> indices;
605 indices.reserve(point_coords_tmp.size());
606 for (Int64 i = 0; i < point_coords_tmp.size(); ++i) {
607 indices.add(i);
608 }
609
610 std::sort(indices.begin(), indices.end(),
611 [&](const Int64 ia, const Int64 ib) {
612 const Real3& pa = point_coords_tmp[ia].m_intersection_pos;
613 const Real3& pb = point_coords_tmp[ib].m_intersection_pos;
614
615 // Vecteurs allant du barycentre vers chaque point.
616 const Real3 va{ pa - bary };
617 const Real3 vb{ pb - bary };
618
619 // Projeter sur la base 2D du plan (u, v).
620 const Real a_x = math::dot(va, u);
621 const Real a_y = math::dot(va, v);
622
623 const Real b_x = math::dot(vb, u);
624 const Real b_y = math::dot(vb, v);
625
626 // Comparer les angles en utilisant atan2.
627 const Real angle_a = std::atan2(a_y, a_x);
628 const Real angle_b = std::atan2(b_y, b_x);
629
630 return angle_a < angle_b;
631 });
632
633 // On crée la nouvelle maille.
634 // On en profite pour modifier le tableau "indices" :
635 // - avant la boucle, ce tableau contient les indices de positions de
636 // noeuds dans le tableau point_coords_tmp.
637 // - après la boucle, ce tableau contiendra les indices de positions
638 // de ces mêmes noeuds mais dans le tableau "global" new_nodes.
639 for (Int64& idx : indices) {
640 // On regarde si le noeud est déjà présent dans le tableau "global".
641 std::optional<Int64> pos = new_nodes.span().findFirst(point_coords_tmp[idx]);
642 if (pos) {
643 // Attention : on ajoute la position du noeud dans le tableau
644 // "global", pas le UID de celui-ci ! En effet, on ne le connait
645 // pas encore, ce sera ajusté dans la méthode
646 // "_makeUniqueCellUID()".
647 new_cells.add(static_cast<Int32>(pos.value()) + ajust_node_pos);
648 idx = pos.value();
649 }
650 // S'il n'est pas présent, on le crée.
651 else {
652 NodeIntersection& elem = point_coords_tmp[idx];
653
654 // Si les deux noeuds ont le même proprio, on sait que le nouveau noeud aura le même proprio.
655 if (elem.m_new_node->m_node0.owner() == elem.m_new_node->m_node1.owner()) {
656 elem.m_new_node->m_owner_new_node = elem.m_new_node->m_node0.owner();
657 // Si les deux noeuds sont à nous, on est sûr d'être le
658 // propriétaire du nouveau noeud. C'est donc à nous de donner le
659 // UniqueID (unique pour ce processus, la correction sera faite
660 // plus tard, quand on saura le nombre de noeuds de chaque
661 // processus).
662 if (elem.m_new_node->m_node0.isOwn()) {
663 elem.m_new_node->m_uid_new_node = sd_nb_node++;
664 }
665 else {
666 // -2 = nécessite d'être ajouté plus tard.
667 elem.m_new_node->m_uid_new_node = -2;
668 }
669 }
670 new_cells.add(new_nodes.size() + ajust_node_pos);
671 idx = new_nodes.size();
672 new_nodes.add(elem);
673 }
674 }
675
676 // Maintenant, on ajoute les faces.
677 Int64 idxm1 = indices[indices.size() - 1];
678 for (Int64 idx : indices) {
679 FaceLite fl(new_nodes[idx].m_new_node, new_nodes[idxm1].m_new_node);
680 if (!new_faces.contains(fl)) {
681 // info() << "Add face"
682 // << " -- N00 " << fl.m_node0->m_uid_node0
683 // << " -- N01 " << fl.m_node0->m_uid_node1
684 // << " -- N10 " << fl.m_node1->m_uid_node0
685 // << " -- N11 " << fl.m_node1->m_uid_node1;
686
687 // Même principe qu'avec les noeuds juste au-dessus.
688 if (new_nodes[idx].m_new_node->m_owner_new_node == new_nodes[idxm1].m_new_node->m_owner_new_node) {
689 fl.m_owner_new_face = new_nodes[idx].m_new_node->m_owner_new_node;
690 if (fl.m_owner_new_face == subDomain()->subDomainId()) {
691 fl.m_uid_new_face = sd_nb_face++;
692 }
693 else {
694 fl.m_uid_new_face = -2;
695 }
696 }
697 new_faces.add(fl);
698 }
699 idxm1 = idx;
700 }
701 }
702 sd_nb_cell++;
703 }
704 point_coords_tmp.clear();
705 }
706}
707
708/*---------------------------------------------------------------------------*/
709/*---------------------------------------------------------------------------*/
710
711void MeshCutService::
712_makeUniqueCellUID(Int32 sd_nb_cell, UniqueArray<Int64>& new_cells, UniqueArray<NodeIntersection>& new_nodes)
713{
714 IParallelMng* pm = subDomain()->parallelMng();
715
716 Int32 decal = sd_nb_cell;
717 pm->scan(MessagePassing::ReduceSum, ArrayView{ 1, &decal });
718
719 // Int32 nb_cells_global = decal;
720 // pm->broadcast(ArrayView{ 1, &nb_cells_global }, pm->commSize() - 1);
721
722 decal -= sd_nb_cell;
723
724 // info() << "[" << pm->commRank() << "] Scan result (rectified) : " << decal;
725
726 // En plus de décaler les uids des mailles pour les rendre unique sur tout le
727 // domaine, on ajoute les vrais UID des noeuds à la place des positions des
728 // noeuds dans le tableau "new_nodes".
729 Int32 pos0 = 0;
730 while (pos0 < new_cells.size()) {
731 Int64 type = new_cells[pos0++];
732 new_cells[pos0++] += decal;
733
734 for (Int32 i = 0; i < type; ++i) {
735 Int64& pos_to_uid = new_cells[pos0++];
736 pos_to_uid = new_nodes[pos_to_uid].m_new_node->m_uid_new_node;
737 }
738 }
739 // return nb_cells_global;
740}
741
742/*---------------------------------------------------------------------------*/
743/*---------------------------------------------------------------------------*/
744
745void MeshCutService::
746_fillNodeUID(Int32& sd_nb_node, UniqueArray<NodeIntersection>& new_nodes)
747{
748
749 // À partir d'ici, nous avons un tableau de noeuds. Les noeuds dont on est
750 // sûr qu'ils nous appartiennent ont déjà un UID/Owner.
751 //
752 // Il y a deux autres types de noeuds :
753 // - le noeud dont on pense connaitre le proprio à qui demander le UID,
754 // - le noeud dont on ne connait pas encore le proprio ni le UID.
755
756 IParallelMng* pm = subDomain()->parallelMng();
757 Int32 my_proc = pm->commRank();
758 UniqueArray<UniqueArray<Ref<NodeOnEdge>>> requested_nodes(subDomain()->nbSubDomain());
759
760 //
761 //
762 // Première étape : détermination des proprios potentiels et création des
763 // requêtes.
764 //
765 // Détermination des proprios :
766 // Si un noeud n'a pas encore de proprio, on choisit le proprio parmi les
767 // mailles des noeuds (N0 et N1) de l'arête dont est issu notre noeud (NN).
768 //
769 // N0 NN N1
770 // *-------*-------*
771 //
772 // NN = elem.m_new_node
773 // N0 = elem.m_new_node->m_node0
774 // N1 = elem.m_new_node->m_node1
775 //
776 // Il peut y avoir des cas où le proprio choisi ne possède pas le noeud.
777 // Ce cas sera traité plus tard dans la méthode.
778 //
779 // À partir de là, on a un proprio pour tous les noeuds.
780 //
781 // Création des requêtes :
782 // On a un message pour chaque processus.
783 // Ce message est composé de pairs de UID : les UID des noeuds de l'arête
784 // dont est issu notre noeud (seul moyen d'identifier notre noeud sur tous
785 // les processus (si l'on ne souhaite pas utiliser sa position)).
786 //
787 // Exemple :
788 // request_uid[][] :
789 // P0 : --Nous--
790 // P1 : [NN09_N0_UID, NN09_N1_UID, NN01_N0_UID, NN01_N1_UID, NN00_N0_UID, NN00_N1_UID]
791 // P2 : [NN14_N0_UID, NN14_N1_UID, NN15_N0_UID, NN15_N1_UID]
792 // P3 : []
793 //
794 // request_uid[][] :
795 // P0 : []
796 // P1 : [NN09_N0_UID, NN09_N1_UID]
797 // P2 : --Nous--
798 // P3 : []
799 //
800 // request_uid[][] :
801 // P0 : []
802 // P1 : [NN00_N0_UID, NN00_N1_UID]
803 // P2 : []
804 // P3 : --Nous--
805 //
806 // On stocke aussi, dans un autre tableau, les NodeOnEdge correspondant
807 // aux paires de UID, afin de les retrouver facilement lorsque l'on aura
808 // reçu les réponses des processus.
809 //
810 // Exemple :
811 // requested_nodes[][] :
812 // P0 : --Nous--
813 // P1 : [NN09, NN01, NN00]
814 // P2 : [NN14, NN15]
815 // P3 : []
816 //
817 //
818 {
819 UniqueArray<UniqueArray<Int64>> request_uid(subDomain()->nbSubDomain());
820
821 debug() << "[Node][" << my_proc << "] Step 1";
822
823 for (auto& elem : new_nodes) {
824 // Si le uid est déjà mis, pas besoin de le rechercher...
825 if (elem.m_new_node->m_uid_new_node >= 0) {
826 continue;
827 }
828
829 // Si le proprio n'est pas définit, on doit faire une recherche.
830 if (elem.m_new_node->m_owner_new_node < 0) {
831
832 Node node0 = elem.m_new_node->m_node0;
833 Node node1 = elem.m_new_node->m_node1;
834
835 // Le propriétaire du noeud est le propriétaire de la maille ayant le plus
836 // petit UID, parmi les mailles en commun entre les deux noeuds d'origine.
837
838 // TODO Ajouter traitement particulier pour le cas où node0 == node1
839 Int64 min_uid = INT64_MAX;
840 Int32 owner_min = -1;
841 for (Cell cell0 : node0.cells()) {
842 for (Cell cell1 : node1.cells()) {
843 if (cell0 == cell1) {
844 if (cell0.uniqueId() < min_uid) {
845 min_uid = cell0.uniqueId();
846 owner_min = cell0.owner();
847 }
848 }
849 }
850 }
851
852 // S'il l'on est le proprio, on peut définir le uid du noeud.
853 if (owner_min == subDomain()->subDomainId()) {
854 elem.m_new_node->m_owner_new_node = subDomain()->subDomainId();
855 elem.m_new_node->m_uid_new_node = sd_nb_node++;
856
857 // debug() << "[Node][" << my_proc << " -> " << elem.m_new_node->m_owner_new_node << "] Set UID"
858 // << " -- UID0 : " << elem.m_new_node->m_uid_node0
859 // << " -- UID1 : " << elem.m_new_node->m_uid_node1
860 // << " -- New UID : " << elem.m_new_node->m_uid_new_node;
861 }
862
863 // Sinon, on doit aller demander le uid au proprio.
864 else {
865 elem.m_new_node->m_owner_new_node = owner_min;
866 elem.m_new_node->m_uid_new_node = -2;
867
868 // Une requête est composée uniquement des deux UID des noeuds de
869 // l'arête dont est issue le nouveau noeud. C'est le seul moyen
870 // d'identifier ce noeud pour l'instant (si on exclut l'identification
871 // par sa position).
872 request_uid[elem.m_new_node->m_owner_new_node].add(elem.m_new_node->m_uid_node0);
873 request_uid[elem.m_new_node->m_owner_new_node].add(elem.m_new_node->m_uid_node1);
874
875 requested_nodes[elem.m_new_node->m_owner_new_node].add(elem.m_new_node);
876
877 // debug() << "[Node][" << my_proc << " -> " << elem.m_new_node->m_owner_new_node << "] Ask1"
878 // << " -- UID0 : " << elem.m_new_node->m_uid_node0
879 // << " -- UID1 : " << elem.m_new_node->m_uid_node1;
880 }
881 }
882
883 // Si le proprio est déjà défini, on doit lui demander le uid du noeud.
884 else {
885 request_uid[elem.m_new_node->m_owner_new_node].add(elem.m_new_node->m_uid_node0);
886 request_uid[elem.m_new_node->m_owner_new_node].add(elem.m_new_node->m_uid_node1);
887
888 requested_nodes[elem.m_new_node->m_owner_new_node].add(elem.m_new_node);
889
890 // debug() << "[Node][" << my_proc << " -> " << elem.m_new_node->m_owner_new_node << "] Ask2"
891 // << " -- UID0 : " << elem.m_new_node->m_uid_node0
892 // << " -- UID1 : " << elem.m_new_node->m_uid_node1;
893 }
894 }
895
896 // On envoie les requêtes.
897 {
898 UniqueArray<Parallel::Request> requests(subDomain()->nbSubDomain() * 2);
899
900 debug() << "[Node][" << my_proc << "] Step 1.2";
901
902 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
903 if (sr == subDomain()->subDomainId()) {
904 continue;
905 }
906 Int32 size = request_uid[sr].size();
907 requests[sr * 2] = pm->send(ArrayView{ 1, &size }, sr, false);
908 requests[sr * 2 + 1] = pm->send(request_uid[sr], sr, false);
909 // debug() << "[Node][" << my_proc << " -> " << sr << "] Requests : " << request_uid[sr];
910 }
911
912 pm->waitAllRequests(requests);
913 }
914 }
915
916 //
917 //
918 // Deuxième étape : traitement des requêtes des autres processus et gestion
919 // des inconnus.
920 //
921 // Traitement des requêtes :
922 //
923 // On effectue le traitement à la réception (donc processus par processus).
924 // Pour chaque paire de UID (N0-N1), on la recherche dans notre tableau des
925 // noeuds.
926 // On l'a trouve, parfait, on place l'UID du noeud (NN) dans le tableau de
927 // réponse.
928 //
929 // Gestion des inconnus :
930 //
931 // Si on ne trouve pas la paire dans notre tableau, on est dans le cas où le
932 // noeud NN est placé sur un noeud du maillage 3D (donc N0 == N1 et
933 // position(N0) == position(NN)).
934 // Lorsque l'on itère sur les mailles de N0, on peut tomber sur des mailles
935 // qui ne sont pas coupées par le plan, donc qui ne possède pas le noeud.
936 //
937 // On n'a pas le noeud dans notre tableau. Par contre, on sait qui demande
938 // ce noeud ! Grâce aux mailles fantômes, on est sûr que tous les processus
939 // qui souhaite le UID du noeud NN vont le demander au même processus. Nous
940 // pouvons donc construire la liste de ces processus demandeurs. Processus
941 // demandeurs dont on est sûr qu'ils possèdent le noeud NN !
942 // Nous allons donc leur envoyer cette liste et il se débrouilleront pour
943 // trouver le bon proprio parmi les processus de cette liste !
944 //
945 // Réponses :
946 //
947 // Le tableau des réponses doit donc contenir deux parties :
948 // - les UIDs, s'ils sont trouvés,
949 // - les processus possédant les noeuds inconnus.
950 //
951 // Pour avoir la limite entre ces deux parties, on place la taille de la
952 // première partie en première position du tableau de réponse.
953 //
954 // Si un UID est trouvé, on l'ajoute. S'il n'est pas trouvé, on place "-1".
955 //
956 // La seconde partie est structurée ainsi :
957 // - Pour chaque inconnu (pour chaque "-1") :
958 // - UID du noeud N0
959 // - UID du noeud N1
960 // - Nombre de processus demandeurs (donc possédant forcément le noeud NN),
961 // - Rangs des processus demandeurs.
962 //
963 // TODO : A changer :
964 // L'ordre de la seconde partie n'a pas d'importance.
965 // En effet, l'ordre de cette partie est le même pour tous les processus (il
966 // n'y a pas de tri par processus selon l'ordre des requêtes (qui
967 // correspondrait à l'ordre des "-1")).
968 // C'est pour ça qu'il y a la présence des "UID du noeud N0" et "UID du
969 // noeud N1".
970 // (trier avant envoi économiserait de la mémoire et réduirait la taille de
971 // la réponse, donc TODO).
972 //
973 //
974 // (Pour l'exemple, on suit le précédent exemple)
975 // answers_uid[][] :
976 // P0 : [3, -1, NN01_UID, -1, NN09_N0_UID, NN09_N1_UID, 2, 0, 2, NN00_N0_UID, NN00_N1_UID, 2, 0, 3]
977 // P1 : --Nous--
978 // P2 : [1, -1, NN09_N0_UID, NN09_N1_UID, 2, 0, 2 ]
979 // P3 : [1, -1, NN00_N0_UID, NN00_N1_UID, 2, 0, 3 ]
980 //
981 //
982 {
983 UniqueArray<UniqueArray<Int64>> answers_uid(subDomain()->nbSubDomain());
984 {
985 UniqueArray<UnknownNodeOrFace> unknown_node;
986 debug() << "[Node][" << my_proc << "] Step 2";
987
988 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
989 if (sr == subDomain()->subDomainId()) {
990 continue;
991 }
992 Int32 size = 0;
993 pm->recv(ArrayView{ 1, &size }, sr);
994
995 UniqueArray<Int64> requested_uid(size);
996 pm->recv(requested_uid, sr);
997
998 // Taille de la première partie.
999 answers_uid[sr].add(0);
1000
1001 // On traite chaque paire de noeud de la requête.
1002 for (Int32 ipair_uid = 0; ipair_uid < requested_uid.size(); ipair_uid += 2) {
1003
1004 std::optional<Int64> pos = new_nodes.span().findFirst(NodeIntersection{ requested_uid[ipair_uid], requested_uid[ipair_uid + 1], Real3{ 0 } });
1005 if (pos) {
1006 answers_uid[sr].add(new_nodes[pos.value()].m_new_node->m_uid_new_node);
1007 // debug() << "[Node][" << my_proc << " <- " << sr << "] Found"
1008 // << " -- UID0 : " << requested_uid[ipair_uid]
1009 // << " -- UID1 : " << requested_uid[ipair_uid + 1]
1010 // << " -- New UID : " << new_nodes[pos.value()].m_new_node->m_uid_new_node;
1011 }
1012
1013 // Il peut arriver que l'on nous demande un noeud que nous n'avons pas.
1014 // Par exemple, si un plan arrive pile sur une des arêtes de nos mailles.
1015 // Par contre, on sait qui en a besoin, donc qui possède une maille avec
1016 // le noeud en question.
1017 // Pour donner cette information, on va ajouter "-1" puis, à la fin de
1018 // la réponse, on va placer les processus en question.
1019 else {
1020 answers_uid[sr].add(-1);
1021 unknown_node.add({ requested_uid[ipair_uid], requested_uid[ipair_uid + 1], sr });
1022 // debug() << "[Node][" << my_proc << " <- " << sr << "] NOT Found"
1023 // << " -- UID0 : " << requested_uid[ipair_uid]
1024 // << " -- UID1 : " << requested_uid[ipair_uid + 1];
1025 }
1026 }
1027 answers_uid[sr][0] = answers_uid[sr].size() - 1;
1028 }
1029
1030 UniqueArray<Int64> who;
1031 debug() << "[Node][" << my_proc << "] Step 2.2";
1032
1033 // Dès qu'il y a eu une paire de noeuds inconnus dans une requête, il y
1034 // a eu un enregistrement de fait dans le tableau unknown_node.
1035 // Il faut maintenant lister, pour chaque paire, qui l'a aussi demandé
1036 // (rechercher les doublons) et envoyer cette liste à chacun d'entre eux.
1037 for (Int32 i = 0; i < unknown_node.size(); ++i) {
1038 if (unknown_node[i].null())
1039 continue;
1040 who.clear();
1041 who.add(unknown_node[i].m_who);
1042 unknown_node[i].m_who = -1;
1043 for (Int32 j = i + 1; j < unknown_node.size(); ++j) {
1044 if (unknown_node[j].null())
1045 continue;
1046 if (unknown_node[j] == unknown_node[i]) {
1047 who.add(unknown_node[j].m_who);
1048 unknown_node[j].m_who = -1;
1049 }
1050 }
1051 // debug() << "[Node] Additionnal infos -- Node0UID : " << unknown_node[i].m_node0_uid << " -- Node1UID : " << unknown_node[i].m_node1_uid << " -- Who : " << who;
1052 for (auto proc : who) {
1053 answers_uid[proc].add(unknown_node[i].m_node0_uid);
1054 answers_uid[proc].add(unknown_node[i].m_node1_uid);
1055 answers_uid[proc].add(who.size());
1056 answers_uid[proc].addRange(who);
1057 }
1058 }
1059 }
1060
1061 {
1062 UniqueArray<Parallel::Request> requests(subDomain()->nbSubDomain() * 2);
1063
1064 // On envoie les réponses.
1065 debug() << "[Node][" << my_proc << "] Step 2.3";
1066 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1067 if (sr == subDomain()->subDomainId()) {
1068 continue;
1069 }
1070
1071 Int32 size = answers_uid[sr].size();
1072 requests[sr * 2] = pm->send(ArrayView{ 1, &size }, sr, false);
1073 requests[sr * 2 + 1] = pm->send(answers_uid[sr], sr, false);
1074
1075 // debug() << "[Node][" << my_proc << " -> " << sr << "] Send " << answers_uid[sr];
1076 }
1077
1078 pm->waitAllRequests(requests);
1079 }
1080 }
1081
1082
1083 //
1084 //
1085 // Troisième étape : Mise à jour des UIDs des noeuds et recherche
1086 // complémentaire de proprios.
1087 //
1088 // On commence par découper la réponse en deux, pour retrouver les deux
1089 // parties tèl que défini plus haut.
1090 // On itère sur la première partie. L'ordre des UIDs reçus est le même que
1091 // l'ordre des noeuds du tableau "requested_nodes" complété dans la première
1092 // partie. On peut ainsi aisément récupérer l'objet correspondant
1093 // (`node_on_edge` dans le code juste en dessous).
1094 //
1095 // Si nous avons reçu un UID valide, on met à jour le noeud correspondant
1096 // et on passe au suivant.
1097 //
1098 // Si nous avons "-1", c'est que le propriétaire que nous avons défini dans
1099 // la première partie n'est pas le bon. Nous devons donc organiser un nouvel
1100 // envoi.
1101 //
1102 // Recherche complémentaire de proprios :
1103 //
1104 // Comme l'ordre des infos complémentaires de la seconde partie du message
1105 // n'est pas forcément le même que l'ordre de la première partie (voir TODO
1106 // au dessus), on doit d'abord rechercher, dans la seconde partie, la paire
1107 // de UID correspondant au noeud que nous traitons actuellement.
1108 //
1109 // On trouve forcément une correspondance.
1110 //
1111 // On est sûr que l'ordre dans lequel est organisée la seconde partie est le
1112 // même pour tous. On va donc se caler sur cette ordre pour transmettre le
1113 // prochain message.
1114 //
1115 // Lorsqu'une correspondance est trouvée, on modifie le message. On remplace
1116 // UID0 par la position de l'objet `Ref<NodeOnEdge>` dans le tableau
1117 // `requested_nodes` (pour éviter une seconde recherche).
1118 //
1119 // Exemple :
1120 // Rappel tableau requested_nodes[][] (Première étape de la méthode) :
1121 // requested_nodes[][] :
1122 // P0 : --Nous--
1123 // P1 : [NN09, NN01, NN00]
1124 //
1125 // Avant modif :
1126 // answered_uid[] :
1127 // P0 : --Nous--
1128 // P1 : [3, -1, NN01_UID, -1, NN09_N0_UID, NN09_N1_UID, 2, 0, 2, NN00_N0_UID, NN00_N1_UID, 2, 0, 3]
1129 //
1130 // Après modif :
1131 // answered_uid[] :
1132 // P0 : --Nous--
1133 // P1 : [3, -1, NN01_UID, -1, 0, NN09_N1_UID, 2, 0, 2, 2, NN00_N1_UID, 2, 0, 3]
1134 //
1135 // Explication de l'exemple :
1136 // On remplace "NN09_N0_UID" par "0" car le noeud "NN09" se trouve à la
1137 // position 0 du tableau `requested_nodes[1][]` (le premier indice est le
1138 // rang du processus cible (donc 1 ici)).
1139 // On remplace "NN00_N0_UID" par "2" car le noeud "NN00" se trouve à la
1140 // position 2 du tableau `requested_nodes[1][]`.
1141 //
1142 // Cette algorithme est en deux étapes pour préserver simplement l'ordre de
1143 // la seconde partie de la réponse.
1144 //
1145 // Une fois `answered_uid[1]` modifié (donc une fois que l'on a fini
1146 // d'itérer sur la première partie de la réponse), on passe à la recherche
1147 // du propriétaire des noeuds restants.
1148 //
1149 // On itère sur la seconde partie de la réponse. Tous les processus
1150 // itèreront dans le même ordre !
1151 //
1152 // On récupère l'objet `Ref<NodeOnEdge>` à l'aide de sa position dans le
1153 // tableau `requested_nodes`. On reproduit l'algo de recherche de proprio de
1154 // la première étape de la méthode en s'assurant de tomber sur un proprio de
1155 // la liste des proprios potentiels.
1156 //
1157 // Par rapport à la première étape de la méthode, on sait de qui recevoir
1158 // des informations et on sait dans quel ordre les interpréter. Donc inutile
1159 // d'envoyer des messages vides si aucune infos n'est nécessaire.
1160 //
1161 // On va utiliser le tableau "request_uid" pour stocker les messages à
1162 // envoyer mais aussi la taille des messages que l'on devra recevoir.
1163 //
1164 // Pour les messages à envoyer, on stocke uniquement les UIDs qui devront
1165 // être appliqués.
1166 // Pour chaque UID stocké du coté du processus envoyeur, l'objet
1167 // `Ref<NodeOnEdge>` correspondant est stocké dans le tableau
1168 // `requested_nodes2` du coté du processus receveur.
1169 //
1170 // Exemple :
1171 // L'algo a déterminé que
1172 // - "NN09" appartient à "2" (et non à "0") et
1173 // - "NN00" appartient à "0" (et non à "3").
1174 //
1175 // request_uid[][] :
1176 // P0 : --Nous-- [0, 0, 1, 0]
1177 // P1 : []
1178 // P2 : []
1179 // P3 : [NN00_UID]
1180 //
1181 // (à lire : P0 attend un message de taille 1 de la part de P2)
1182 // ( P0 envoie NN00_UID à P3)
1183 //
1184 // request_uid[][] :
1185 // P0 : [NN09_UID]
1186 // P1 : []
1187 // P2 : --Nous-- [0, 0, 0, 0]
1188 // P3 : []
1189 //
1190 // request_uid[][] :
1191 // P0 : []
1192 // P1 : []
1193 // P2 : []
1194 // P3 : --Nous-- [1, 0, 0, 0]
1195 //
1196 //
1197 UniqueArray<UniqueArray<Int64>> request_uid(subDomain()->nbSubDomain());
1198 UniqueArray<UniqueArray<Ref<NodeOnEdge>>> requested_nodes2(subDomain()->nbSubDomain());
1199
1200 // On reçoit et traite les réponses.
1201 debug() << "[Node][" << my_proc << "] Step 3";
1202
1203 // Permet de savoir si les prochaines étapes sont utiles.
1204 bool need_more_comm = false;
1205
1206 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1207 if (sr == subDomain()->subDomainId()) {
1208 continue;
1209 }
1210
1211 Int32 total_size = 0;
1212 pm->recv(ArrayView{ 1, &total_size }, sr);
1213
1214 UniqueArray<Int64> answered_uid(total_size);
1215 pm->recv(answered_uid, sr);
1216
1217 if (total_size == 1) {
1218 continue;
1219 }
1220
1221 Int32 answer_to_request_size = static_cast<Int32>(answered_uid[0]);
1222
1223 Span<Int64> answer_to_request = answered_uid.subView(1, answer_to_request_size);
1224 Span<Int64> additionnal_answer = answered_uid.subView(answer_to_request_size+1, answered_uid.size() - (answer_to_request_size+1));
1225
1226 // debug() << "[Node][" << my_proc << " <- " << sr << "] Decoupe"
1227 // << " -- answer_to_request : " << answer_to_request
1228 // << " -- additionnal_answer : " << additionnal_answer;
1229
1230
1231 for (Int32 answer = 0; answer < answer_to_request.size(); ++answer) {
1232 Ref<NodeOnEdge> node_on_edge = requested_nodes[sr][answer];
1233
1234 if (answer_to_request[answer] != -1) {
1235 node_on_edge->m_uid_new_node = answer_to_request[answer];
1236 // debug() << "[Node][" << my_proc << "] Apply"
1237 // << " -- UID0 : " << node_on_edge->m_uid_node0
1238 // << " -- UID1 : " << node_on_edge->m_uid_node1
1239 // << " -- New UID : " << node_on_edge->m_uid_new_node;
1240 }
1241 else {
1242 Int64 pos = 0;
1243 while (pos < additionnal_answer.size()) {
1244 Int64& uid0 = additionnal_answer[pos++];
1245 Int64 uid1 = additionnal_answer[pos++];
1246 Int64 decal = additionnal_answer[pos++];
1247 if (uid0 == node_on_edge->m_uid_node0 && uid1 == node_on_edge->m_uid_node1) {
1248 uid0 = answer;
1249 break;
1250 }
1251 pos += decal;
1252 }
1253 if (pos >= additionnal_answer.size()) {
1254 ARCANE_FATAL("Unknown node -- UID0 : {0} -- UID1 : {1}", node_on_edge->m_uid_node0, node_on_edge->m_uid_node1);
1255 }
1256 }
1257 }
1258
1259 Int64 pos = 0;
1260 Span<Int64> sub_additionnal_answer;
1261
1262 while (pos < additionnal_answer.size()) {
1263 Int64 pos_node_in_array = additionnal_answer[pos++];
1264 pos++;
1265 Int64 decal = additionnal_answer[pos++];
1266
1267 Ref<NodeOnEdge> node_on_edge = requested_nodes[sr][pos_node_in_array];
1268 sub_additionnal_answer = additionnal_answer.subSpan(pos, decal);
1269
1270 pos += decal;
1271
1272 // debug() << "[Node][" << my_proc << " <- " << sr << "] Sub"
1273 // << " -- sub_additionnal_answer : " << sub_additionnal_answer;
1274
1275 Node node0 = node_on_edge->m_node0;
1276 Node node1 = node_on_edge->m_node1;
1277
1278 // Le propriétaire du noeud est le propriétaire de la maille ayant le plus
1279 // petit UID, parmi les mailles en commun entre les deux noeuds d'origine.
1280
1281 // TODO Ajouter traitement particulier pour le cas où node0 == node1
1282 Int64 min_uid = INT64_MAX;
1283 Int32 owner_min = -1;
1284 for (Cell cell0 : node0.cells()) {
1285 for (Cell cell1 : node1.cells()) {
1286 if (cell0 == cell1) {
1287 if (cell0.uniqueId() < min_uid && sub_additionnal_answer.contains(cell0.owner())) {
1288 min_uid = cell0.uniqueId();
1289 owner_min = cell0.owner();
1290 }
1291 }
1292 }
1293 }
1294
1295 // S'il l'on est le proprio, on peut définir le uid du noeud.
1296 if (owner_min == subDomain()->subDomainId()) {
1297 node_on_edge->m_owner_new_node = subDomain()->subDomainId();
1298 node_on_edge->m_uid_new_node = sd_nb_node++;
1299
1300 // On enregistre le UID à envoyer.
1301 if (sub_additionnal_answer.size() > 1) {
1302 need_more_comm = true;
1303
1304 // debug() << "[Node][" << my_proc << "] Send"
1305 // << " -- UID : " << node_on_edge->m_uid_new_node
1306 // << " -- for Node UID0 : " << node_on_edge->m_uid_node0
1307 // << " -- UID1 : " << node_on_edge->m_uid_node1
1308 // << " -- to : " << sub_additionnal_answer;
1309
1310 for (auto proc : sub_additionnal_answer) {
1311 if (proc == my_proc)
1312 continue;
1313 request_uid[proc].add(node_on_edge->m_uid_new_node);
1314 }
1315 }
1316 }
1317
1318 // Sinon, on doit aller demander le uid au proprio.
1319 else {
1320 need_more_comm = true;
1321 node_on_edge->m_owner_new_node = owner_min;
1322 node_on_edge->m_uid_new_node = -2;
1323
1324 if (request_uid[my_proc].empty()) {
1325 request_uid[my_proc].resize(subDomain()->nbSubDomain(), 0);
1326 }
1327
1328 request_uid[my_proc][owner_min]++;
1329
1330 requested_nodes2[owner_min].add(node_on_edge);
1331
1332 // debug() << "[Node][" << my_proc << " -> " << node_on_edge->m_owner_new_node << "] Recv UID for Node"
1333 // << " -- UID0 : " << node_on_edge->m_uid_node0
1334 // << " -- UID1 : " << node_on_edge->m_uid_node1;
1335 }
1336 }
1337 }
1338
1339 // Si nous n'avons pas de UID manquants et que personne n'a besoin de l'un
1340 // de nos UIDs, on passe cette étape.
1341 // Sinon :
1342 if (need_more_comm) {
1343 {
1344 UniqueArray<Parallel::Request> requests(subDomain()->nbSubDomain());
1345
1346 // On envoie les UID complémentaires.
1347 debug() << "[Node][" << my_proc << "] Step 3.2";
1348
1349 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1350 if (sr == subDomain()->subDomainId()) {
1351 // debug() << "[Node][" << my_proc << " -> " << sr << "] My RequestsC : " << request_uid[sr];
1352 continue;
1353 }
1354 if (request_uid[sr].empty()) continue;
1355 requests[sr] = pm->send(request_uid[sr], sr, false);
1356 // debug() << "[Node][" << my_proc << " -> " << sr << "] RequestsC : " << request_uid[sr];
1357 }
1358
1359 pm->waitAllRequests(requests);
1360 }
1361
1362 //
1363 //
1364 // Quatrième étape : Mise à jour des UIDs manquants.
1365 //
1366 // On est sûr d'avoir une réponse complète, donc c'est plus simple.
1367 // On récupère le nombre de messages à recevoir de la part de l'autre
1368 // processus et on traite son message dans l'ordre. Le tableau
1369 // `requested_nodes2[][]` est dans le même ordre ce qui facilite les
1370 // choses.
1371 //
1372 //
1373
1374 if (!request_uid[my_proc].empty()) {
1375 // On reçoit et traite les UID complémentaires.
1376 debug() << "[Node][" << my_proc << "] Step 4";
1377
1378 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1379 if (sr == subDomain()->subDomainId()) {
1380 continue;
1381 }
1382
1383 Int64 size = request_uid[my_proc][sr];
1384 if (size == 0) continue;
1385
1386 // debug() << "[Node][" << my_proc << " -> " << sr << "] Size recv : " << size;
1387
1388
1389 UniqueArray<Int64> requested_uid(size);
1390 pm->recv(requested_uid, sr);
1391 for (Int32 i = 0; i < size; ++i) {
1392 Ref<NodeOnEdge> node_on_edge = requested_nodes2[sr][i];
1393 node_on_edge->m_uid_new_node = requested_uid[i];
1394 // debug() << "[Nœud][" << my_proc << "] Appliquer2"
1395 // << " -- UID0 : " << node_on_edge->m_uid_node0
1396 // << " -- UID1 : " << node_on_edge->m_uid_node1
1397 // << " -- Nouveau UID : " << node_on_edge->m_uid_new_node;
1398 }
1399 }
1400 }
1401 }
1402}
1403
1404/*---------------------------------------------------------------------------*/
1405/*---------------------------------------------------------------------------*/
1406
1407Int32 MeshCutService::
1408_makeUniqueNodeUID(Int32 sd_nb_node, UniqueArray<NodeIntersection>& new_nodes)
1409{
1410 IParallelMng* pm = subDomain()->parallelMng();
1411
1412 UniqueArray<Int32> all_nb_node(pm->commSize());
1413 pm->allGather(ArrayView{ 1, &sd_nb_node }, all_nb_node);
1414
1415 Int32 sum = 0;
1416 for (auto& elem : all_nb_node) {
1417 const Int32 old = elem;
1418 elem = sum;
1419 sum += old;
1420 }
1421
1422 // info() << "[" << pm->commRank() << "] Résultat de la collecte (rectifié) : " << all_nb_node;
1423
1424 for (auto& elem : new_nodes) {
1425 elem.m_new_node->m_uid_new_node += all_nb_node[elem.m_new_node->m_owner_new_node];
1426 }
1427 return sum;
1428}
1429
1430/*---------------------------------------------------------------------------*/
1431/*---------------------------------------------------------------------------*/
1432
1433void MeshCutService::
1434_fillFaceUID(Int32& sd_nb_face, UniqueArray<FaceLite>& new_faces)
1435{
1436 // Cet algo est repris de celui traitant les noeuds.
1437 IParallelMng* pm = subDomain()->parallelMng();
1438 Int32 my_proc = pm->commRank();
1439 UniqueArray<UniqueArray<Int32>> requested_faces(subDomain()->nbSubDomain());
1440
1441 {
1442 Int32 iter = -1;
1443 UniqueArray<UniqueArray<Int64>> request_uid(subDomain()->nbSubDomain());
1444
1445 debug() << "[Face][" << my_proc << "] Étape 1";
1446
1447 for (auto& elem : new_faces) {
1448 iter++;
1449 if (elem.m_uid_new_face >= 0) {
1450 continue;
1451 }
1452 if (elem.m_owner_new_face < 0) {
1453
1454 Node node00 = elem.m_node0->m_node0;
1455 Node node01 = elem.m_node0->m_node1;
1456 Node node10 = elem.m_node1->m_node0;
1457 Node node11 = elem.m_node1->m_node1;
1458
1459 Int64 min_uid = INT64_MAX;
1460 Int32 owner_min = -1;
1461
1462 // TODO AH : C'est quand même TURBO moche
1463 for (Cell cell00 : node00.cells()) {
1464 for (Cell cell01 : node01.cells()) {
1465 if (cell00 == cell01) {
1466 for (Cell cell10 : node10.cells()) {
1467 if (cell01 == cell10 ) {
1468 for (Cell cell11 : node11.cells()) {
1469 if (cell10 == cell11) {
1470 if (cell11.uniqueId() < min_uid) {
1471 min_uid = cell11.uniqueId();
1472 owner_min = cell11.owner();
1473 }
1474 }
1475 }
1476 }
1477 }
1478 }
1479 }
1480 }
1481
1482 if (owner_min == subDomain()->subDomainId()) {
1483 elem.m_owner_new_face = subDomain()->subDomainId();
1484 elem.m_uid_new_face = sd_nb_face++;
1485
1486 // debug() << "[Face][" << my_proc << " -> " << elem.m_owner_new_face << "] Définir UID"
1487 // << " -- UID0 : " << elem.m_node0->m_uid_new_node
1488 // << " -- UID1 : " << elem.m_node1->m_uid_new_node
1489 // << " -- Nouveau UID : " << elem.m_uid_new_face;
1490 }
1491 else {
1492 elem.m_owner_new_face = owner_min;
1493 elem.m_uid_new_face = -2;
1494 request_uid[elem.m_owner_new_face].add(elem.m_node0->m_uid_new_node);
1495 request_uid[elem.m_owner_new_face].add(elem.m_node1->m_uid_new_node);
1496
1497 requested_faces[elem.m_owner_new_face].add(iter);
1498
1499 // debug() << "[Face][" << my_proc << " -> " << elem.m_owner_new_face << "] Demande1"
1500 // << " -- UID0 : " << elem.m_node0->m_uid_new_node
1501 // << " -- UID1 : " << elem.m_node1->m_uid_new_node;
1502 }
1503 }
1504 else {
1505 request_uid[elem.m_owner_new_face].add(elem.m_node0->m_uid_new_node);
1506 request_uid[elem.m_owner_new_face].add(elem.m_node1->m_uid_new_node);
1507
1508 requested_faces[elem.m_owner_new_face].add(iter);
1509
1510 // debug() << "[Face][" << my_proc << " -> " << elem.m_owner_new_face << "] Demande2"
1511 // << " -- UID0 : " << elem.m_node0->m_uid_new_node
1512 // << " -- UID1 : " << elem.m_node1->m_uid_new_node;
1513 }
1514 }
1515
1516 {
1517 UniqueArray<Parallel::Request> requests(subDomain()->nbSubDomain() * 2);
1518
1519 // On envoie les requêtes.
1520 debug() << "[Face][" << my_proc << "] Étape 1.2";
1521
1522 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1523 if (sr == subDomain()->subDomainId()) {
1524 continue;
1525 }
1526 Int32 size = request_uid[sr].size();
1527 requests[sr * 2] = pm->send(ArrayView{ 1, &size }, sr, false);
1528 requests[sr * 2 + 1] = pm->send(request_uid[sr], sr, false);
1529 // debug() << "[Face][" << my_proc << " -> " << sr << "] Requêtes : " << request_uid[sr];
1530 }
1531
1532 pm->waitAllRequests(requests);
1533 }
1534 }
1535
1536 {
1537 UniqueArray<UniqueArray<Int64>> answers_uid(subDomain()->nbSubDomain());
1538 {
1539 UniqueArray<UnknownNodeOrFace> unknown_face;
1540 debug() << "[Face][" << my_proc << "] Étape 2";
1541
1542 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1543 if (sr == subDomain()->subDomainId()) {
1544 continue;
1545 }
1546 Int32 size = 0;
1547 pm->recv(ArrayView{ 1, &size }, sr);
1548
1549 UniqueArray<Int64> requested_uid(size);
1550 pm->recv(requested_uid, sr);
1551
1552 answers_uid[sr].add(0);
1553
1554 for (Int32 ipair_uid = 0; ipair_uid < requested_uid.size(); ipair_uid += 2) {
1555 std::optional<Int64> pos = _find(new_faces, requested_uid[ipair_uid], requested_uid[ipair_uid + 1]);
1556 if (pos) {
1557 answers_uid[sr].add(new_faces[pos.value()].m_uid_new_face);
1558 // debug() << "[Face][" << my_proc << " <- " << sr << "] Trouvé"
1559 // << " -- UID0 : " << requested_uid[ipair_uid]
1560 // << " -- UID1 : " << requested_uid[ipair_uid + 1]
1561 // << " -- Nouveau UID : " << new_faces[pos.value()].m_uid_new_face;
1562 }
1563
1564 // Il peut arriver que l'on nous demande une face que nous n'avons pas.
1565 // Par exemple, si un plan arrive pile sur une des arêtes de nos mailles.
1566 // Par contre, on sait qui en a besoin, donc qui possède une maille avec
1567 // la face en question.
1568 // Pour donner cette information, on va ajouter "-1" puis, à la fin de
1569 // la réponse, on va placer les processus en question.
1570 else {
1571 answers_uid[sr].add(-1);
1572 unknown_face.add({ requested_uid[ipair_uid], requested_uid[ipair_uid + 1], sr });
1573 // debug() << "[Face][" << my_proc << " <- " << sr << "] NON Trouvé"
1574 // << " -- UID0 : " << requested_uid[ipair_uid]
1575 // << " -- UID1 : " << requested_uid[ipair_uid + 1];
1576 }
1577 }
1578 answers_uid[sr][0] = answers_uid[sr].size() - 1;
1579 }
1580
1581 UniqueArray<Int64> who;
1582 debug() << "[Face][" << my_proc << "] Étape 2.2";
1583
1584 for (Int32 i = 0; i < unknown_face.size(); ++i) {
1585 if (unknown_face[i].null())
1586 continue;
1587 who.clear();
1588 who.add(unknown_face[i].m_who);
1589 unknown_face[i].m_who = -1;
1590 for (Int32 j = i + 1; j < unknown_face.size(); ++j) {
1591 if (unknown_face[j].null())
1592 continue;
1593 if (unknown_face[j] == unknown_face[i]) {
1594 who.add(unknown_face[j].m_who);
1595 unknown_face[j].m_who = -1;
1596 }
1597 }
1598 // debug() << "[Face] Infos additionnelles -- Node0UID : " << unknown_face[i].m_node0_uid << " -- Node1UID : " << unknown_face[i].m_node1_uid << " -- Qui : " << who;
1599 for (auto proc : who) {
1600 answers_uid[proc].add(unknown_face[i].m_node0_uid);
1601 answers_uid[proc].add(unknown_face[i].m_node1_uid);
1602 answers_uid[proc].add(who.size());
1603 answers_uid[proc].addRange(who);
1604 }
1605 }
1606 }
1607
1608 {
1609 UniqueArray<Parallel::Request> requests(subDomain()->nbSubDomain() * 2);
1610
1611 // On envoie les réponses.
1612 debug() << "[Face][" << my_proc << "] Étape 2.3";
1613 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1614 if (sr == subDomain()->subDomainId()) {
1615 continue;
1616 }
1617
1618 Int32 size = answers_uid[sr].size();
1619 requests[sr * 2] = pm->send(ArrayView{ 1, &size }, sr, false);
1620 requests[sr * 2 + 1] = pm->send(answers_uid[sr], sr, false);
1621 }
1622
1623 pm->waitAllRequests(requests);
1624 }
1625 }
1626
1627 UniqueArray<UniqueArray<Int64>> request_uid(subDomain()->nbSubDomain());
1628 UniqueArray<UniqueArray<Int32>> requested_faces2(subDomain()->nbSubDomain());
1629
1630 // On reçoit et traite les réponses.
1631 debug() << "[Face][" << my_proc << "] Étape 3";
1632
1633 bool need_more_comm = false;
1634
1635 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1636 if (sr == subDomain()->subDomainId()) {
1637 continue;
1638 }
1639
1640 Int32 total_size = 0;
1641 pm->recv(ArrayView{ 1, &total_size }, sr);
1642
1643 UniqueArray<Int64> answered_uid(total_size);
1644 pm->recv(answered_uid, sr);
1645
1646 if (total_size == 1) {
1647 continue;
1648 }
1649
1650 Int32 answer_to_request_size = static_cast<Int32>(answered_uid[0]);
1651
1652 Span<Int64> answer_to_request = answered_uid.subView(1, answer_to_request_size);
1653 Span<Int64> additionnal_answer = answered_uid.subView(answer_to_request_size + 1, answered_uid.size() - (answer_to_request_size + 1));
1654
1655 // debug() << "[Face][" << my_proc << " <- " << sr << "] Découpe"
1656 // << " -- answer_to_request : " << answer_to_request
1657 // << " -- additionnal_answer : " << additionnal_answer;
1658
1659 for (Int32 answer = 0; answer < answer_to_request.size(); ++answer) {
1660 FaceLite& face_lite = new_faces[requested_faces[sr][answer]];
1661
1662 if (answer_to_request[answer] != -1) {
1663 face_lite.m_uid_new_face = answer_to_request[answer];
1664 // debug() << "[Face][" << my_proc << "] Appliquer"
1665 // << " -- UID0 : " << face_lite.m_node0->m_uid_new_node
1666 // << " -- UID1 : " << face_lite.m_node1->m_uid_new_node
1667 // << " -- Nouveau UID : " << face_lite.m_uid_new_face;
1668 }
1669 else {
1670 Int64 pos = 0;
1671 while (pos < additionnal_answer.size()) {
1672 Int64& uid0 = additionnal_answer[pos++];
1673 Int64 uid1 = additionnal_answer[pos++];
1674 Int64 decal = additionnal_answer[pos++];
1675 if (uid0 == face_lite.m_node0->m_uid_new_node && uid1 == face_lite.m_node1->m_uid_new_node) {
1676 uid0 = answer;
1677 break;
1678 }
1679 pos += decal;
1680 }
1681 if (pos >= additionnal_answer.size()) {
1682 ARCANE_FATAL("Unknown face -- UID0 : {0} -- UID1 : {1}", face_lite.m_node0->m_uid_new_node, face_lite.m_node1->m_uid_new_node);
1683 }
1684 }
1685 }
1686
1687 Int64 pos = 0;
1688 Span<Int64> sub_additionnal_answer;
1689
1690 while (pos < additionnal_answer.size()) {
1691 Int64 pos_node_in_array = additionnal_answer[pos++];
1692 pos++;
1693 Int64 decal = additionnal_answer[pos++];
1694
1695 FaceLite& face_lite = new_faces[requested_faces[sr][pos_node_in_array]];
1696 sub_additionnal_answer = additionnal_answer.subSpan(pos, decal);
1697
1698 pos += decal;
1699
1700
1701 // debug() << "[Face][" << my_proc << " <- " << sr << "] Sous"
1702 // << " -- sub_additionnal_answer : " << sub_additionnal_answer;
1703
1704 Node node00 = face_lite.m_node0->m_node0;
1705 Node node01 = face_lite.m_node0->m_node1;
1706 Node node10 = face_lite.m_node1->m_node0;
1707 Node node11 = face_lite.m_node1->m_node1;
1708
1709 Int64 min_uid = INT64_MAX;
1710 Int32 owner_min = -1;
1711
1712 // TODO AH : C'est quand même TURBO moche
1713 for (Cell cell00 : node00.cells()) {
1714 for (Cell cell01 : node01.cells()) {
1715 if (cell00 == cell01) {
1716 for (Cell cell10 : node10.cells()) {
1717 if (cell01 == cell10) {
1718 for (Cell cell11 : node11.cells()) {
1719 if (cell10 == cell11) {
1720 if (cell11.uniqueId() < min_uid && sub_additionnal_answer.contains(cell11.owner())) {
1721 min_uid = cell11.uniqueId();
1722 owner_min = cell11.owner();
1723 }
1724 }
1725 }
1726 }
1727 }
1728 }
1729 }
1730 }
1731
1732 // S'il l'on est le proprio, on peut définir le uid du noeud.
1733 if (owner_min == subDomain()->subDomainId()) {
1734 face_lite.m_owner_new_face = subDomain()->subDomainId();
1735 face_lite.m_uid_new_face = sd_nb_face++;
1736
1737 // On enregistre le UID à envoyer.
1738 if (sub_additionnal_answer.size() > 1) {
1739 need_more_comm = true;
1740
1741 // debug() << "[Face][" << my_proc << "] Envoyer"
1742 // << " -- UID : " << face_lite.m_uid_new_face
1743 // << " -- pour UID Nœud0 : " << face_lite.m_node0->m_uid_new_node
1744 // << " -- UID1 : " << face_lite.m_node1->m_uid_new_node
1745 // << " -- à : " << sub_additionnal_answer;
1746
1747 for (auto proc : sub_additionnal_answer) {
1748 if (proc == my_proc)
1749 continue;
1750 request_uid[proc].add(face_lite.m_uid_new_face);
1751 }
1752 }
1753 }
1754
1755 // Sinon, on doit aller demander le uid au proprio.
1756 else {
1757 need_more_comm = true;
1758 face_lite.m_owner_new_face = owner_min;
1759 face_lite.m_uid_new_face = -2;
1760
1761 if (request_uid[my_proc].empty()) {
1762 request_uid[my_proc].resize(subDomain()->nbSubDomain(), 0);
1763 }
1764
1765 request_uid[my_proc][owner_min]++;
1766
1767 requested_faces2[owner_min].add(requested_faces[sr][pos_node_in_array]);
1768
1769 // debug() << "[Face][" << my_proc << " -> " << face_lite.m_owner_new_face << "] Recevoir UID pour Nœud"
1770 // << " -- UID0 : " << face_lite.m_node0->m_uid_new_node
1771 // << " -- UID1 : " << face_lite.m_node1->m_uid_new_node;
1772 }
1773 }
1774 }
1775
1776 if (need_more_comm) {
1777 {
1778 UniqueArray<Parallel::Request> requests(subDomain()->nbSubDomain());
1779
1780 // On envoie les UID complémentaires.
1781 debug() << "[Face][" << my_proc << "] Étape 3.2";
1782
1783 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1784 if (sr == subDomain()->subDomainId()) {
1785 // debug() << "[Face][" << my_proc << " -> " << sr << "] Mes RequêtesC : " << request_uid[sr];
1786 continue;
1787 }
1788 if (request_uid[sr].empty()) continue;
1789 requests[sr] = pm->send(request_uid[sr], sr, false);
1790 // debug() << "[Face][" << my_proc << " -> " << sr << "] RequêtesC : " << request_uid[sr];
1791 }
1792
1793 pm->waitAllRequests(requests);
1794 }
1795
1796 // On reçoit et traite les UID complémentaires.
1797 debug() << "[Face][" << my_proc << "] Étape 7";
1798
1799 if (!request_uid[my_proc].empty()) {
1800 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1801 if (sr == subDomain()->subDomainId()) {
1802 continue;
1803 }
1804
1805 Int64 size = request_uid[my_proc][sr];
1806 if (size == 0) continue;
1807
1808 // debug() << "[Face][" << my_proc << " -> " << sr << "] Taille reçue : " << size;
1809
1810
1811 UniqueArray<Int64> requested_uid(size);
1812 pm->recv(requested_uid, sr);
1813
1814 for (Int32 i = 0; i < size; ++i) {
1815 FaceLite& face_lite = new_faces[requested_faces2[sr][i]];
1816 face_lite.m_uid_new_face = requested_uid[i];
1817 // debug() << "[Face][" << my_proc << "] Appliquer2"
1818 // << " -- UID0 : " << face_lite.m_node0->m_uid_new_node
1819 // << " -- UID1 : " << face_lite.m_node1->m_uid_new_node
1820 // << " -- Nouveau UID : " << face_lite.m_uid_new_face;
1821 }
1822 }
1823 }
1824 }
1825}
1826
1827/*---------------------------------------------------------------------------*/
1828/*---------------------------------------------------------------------------*/
1829
1830Int32 MeshCutService::
1831_makeUniqueFaceUID(Int32 sd_nb_face, UniqueArray<FaceLite>& new_faces)
1832{
1833 IParallelMng* pm = subDomain()->parallelMng();
1834
1835 UniqueArray<Int32> all_nb_node(pm->commSize());
1836 pm->allGather(ArrayView{ 1, &sd_nb_face }, all_nb_node);
1837
1838 Int32 sum = 0;
1839 for (auto& elem : all_nb_node) {
1840 const Int32 old = elem;
1841 elem = sum;
1842 sum += old;
1843 }
1844
1845 // info() << "[" << pm->commRank() << "] Résultat de la collecte (rectifié) : " << all_nb_node;
1846
1847 for (auto& elem : new_faces) {
1848 elem.m_uid_new_face += all_nb_node[elem.m_owner_new_face];
1849 }
1850 return sum;
1851}
1852
1853/*---------------------------------------------------------------------------*/
1854/*---------------------------------------------------------------------------*/
1855
1856void MeshCutService::
1857_compute()
1858{
1859 Int32 nb_cell = 0;
1860 Int32 g_nb_node = 0;
1861 Int32 g_nb_face = 0;
1862
1863 UniqueArray<Int64> new_cells;
1864
1865 UniqueArray<NodeIntersection> new_nodes;
1866 UniqueArray<FaceLite> new_faces;
1867
1868 for (Int32 i = 0; i < m_plans.size(); ++i) {
1869
1870 debug() << "Plan : " << m_plans[i].first << ", " << m_plans[i].second;
1871
1872 UniqueArray<NodeIntersection> plan_new_nodes;
1873 UniqueArray<FaceLite> plan_new_faces;
1874
1875 Int32 ajust = new_nodes.size();
1876
1877 Int32 previous_g_nb_node = g_nb_node;
1878 Int32 previous_g_nb_face = g_nb_face;
1879
1880 Int32 nb_node_for_this_plan = g_nb_node;
1881 Int32 nb_face_for_this_plan = g_nb_face;
1882
1883 debug() << "[" << subDomain()->parallelMng()->commRank() << "] _createNodesAndCells";
1884 _createNodesAndCells(i, g_nb_node, plan_new_nodes, ajust, nb_cell, new_cells, g_nb_face, plan_new_faces);
1885
1886 // for (auto& elem : plan_new_nodes) {
1887 // debug() << "Nouveau nœud"
1888 // << " -- UID : " << elem.m_new_node->m_uid_new_node
1889 // << " -- Propriétaire : " << elem.m_new_node->m_owner_new_node
1890 // << " -- Pos : " << elem.m_intersection_pos
1891 // << " -- Nœud d'arête0 : " << elem.m_new_node->m_uid_node0
1892 // << " -- Nœud d'arête1 : " << elem.m_new_node->m_uid_node1;
1893 // }
1894
1895 debug() << "[" << subDomain()->parallelMng()->commRank() << "] _fillNodeUID";
1896 _fillNodeUID(g_nb_node, plan_new_nodes);
1897 nb_node_for_this_plan = g_nb_node - nb_node_for_this_plan;
1898
1899 nb_node_for_this_plan = _makeUniqueNodeUID(nb_node_for_this_plan, plan_new_nodes);
1900 g_nb_node = previous_g_nb_node + nb_node_for_this_plan;
1901
1902 // for (auto& elem : plan_new_nodes) {
1903 // debug() << "Fixer le nœud"
1904 // << " -- UID : " << elem.m_new_node->m_uid_new_node
1905 // << " -- Propriétaire : " << elem.m_new_node->m_owner_new_node
1906 // << " -- Pos : " << elem.m_intersection_pos
1907 // << " -- Nœud d'arête0 : " << elem.m_new_node->m_uid_node0
1908 // << " -- Nœud d'arête1 : " << elem.m_new_node->m_uid_node1;
1909 // }
1910 //
1911 // for (auto& elem : plan_new_faces) {
1912 // debug() << "Nouvelle face"
1913 // << " -- UID : " << elem.m_uid_new_face
1914 // << " -- Propriétaire : " << elem.m_owner_new_face
1915 // << " -- Nœud0 : " << elem.m_node0->m_uid_new_node
1916 // << " -- Nœud00 : " << elem.m_node0->m_uid_node0
1917 // << " -- Nœud01 : " << elem.m_node0->m_uid_node1
1918 // << " -- Nœud1 : " << elem.m_node1->m_uid_new_node
1919 // << " -- Nœud10 : " << elem.m_node1->m_uid_node0
1920 // << " -- Nœud11 : " << elem.m_node1->m_uid_node1;
1921 // }
1922 _fillFaceUID(g_nb_face, plan_new_faces);
1923 nb_face_for_this_plan = g_nb_face - nb_face_for_this_plan;
1924
1925 nb_face_for_this_plan = _makeUniqueFaceUID(nb_face_for_this_plan, plan_new_faces);
1926 g_nb_face = previous_g_nb_face + nb_face_for_this_plan;
1927
1928 // for (auto& elem : plan_new_faces) {
1929 // debug() << "Fixer la face"
1930 // << " -- UID : " << elem.m_uid_new_face
1931 // << " -- Propriétaire : " << elem.m_owner_new_face
1932 // << " -- Nœud0 : " << elem.m_node0->m_uid_new_node
1933 // << " -- Nœud00 : " << elem.m_node0->m_uid_node0
1934 // << " -- Nœud01 : " << elem.m_node0->m_uid_node1
1935 // << " -- Nœud1 : " << elem.m_node1->m_uid_new_node
1936 // << " -- Nœud10 : " << elem.m_node1->m_uid_node0
1937 // << " -- Nœud11 : " << elem.m_node1->m_uid_node1;
1938 // }
1939
1940 new_nodes.addRange(plan_new_nodes);
1941 new_faces.addRange(plan_new_faces);
1942 }
1943
1944 _makeUniqueCellUID(nb_cell, new_cells, new_nodes);
1945
1946 {
1947 // Int32 pos0 = 0;
1948 // while (pos0 < new_cells.size()) {
1949 // StringBuilder logs;
1950 // logs += "Nouvelle maille -- Type : ";
1951 // Int64 type = new_cells[pos0++];
1952 // logs += type;
1953 // logs += " -- UID : ";
1954 // logs += new_cells[pos0++];
1955 //
1956 // for (Int32 i = 0; i < type; ++i) {
1957 // logs += " -- Nœud";
1958 // logs += i;
1959 // logs += " : ";
1960 // logs += new_cells[pos0++];
1961 // }
1962 // debug() << logs;
1963 // }
1964 }
1965
1966 _addFaces(new_faces);
1967 _addCells(new_cells);
1968 m_cloned_mesh->modifier()->endUpdate();
1969 _setCoordNodesAndOwner(new_nodes);
1970 _setFacesOwner(new_faces);
1971
1972 m_cloned_mesh->nodeFamily()->notifyItemsOwnerChanged();
1973 m_cloned_mesh->faceFamily()->notifyItemsOwnerChanged();
1974
1975 info() << "Nouveau maillage : " << m_cloned_mesh->name() << " -- NbNœuds : " << m_cloned_mesh->nbNode() << " -- NbMailles : " << m_cloned_mesh->nbCell();
1976}
1977
1978/*---------------------------------------------------------------------------*/
1979/*---------------------------------------------------------------------------*/
1980
1981std::optional<Int64> MeshCutService::
1982_find(Span<FaceLite> new_faces, Int64 node_uid0, Int64 node_uid1)
1983{
1984 for (Int32 i = 0; i < new_faces.size(); ++i) {
1985 if (new_faces[i].m_node0->m_uid_new_node == node_uid0 && new_faces[i].m_node1->m_uid_new_node == node_uid1) {
1986 return i;
1987 }
1988 }
1989 return std::nullopt;
1990}
1991
1992/*---------------------------------------------------------------------------*/
1993/*---------------------------------------------------------------------------*/
1994
1995void MeshCutService::
1996_addFaces(UniqueArray<FaceLite>& new_faces) const
1997{
1998 UniqueArray<Int64> faces_infos;
1999 faces_infos.reserve(new_faces.size() * 4);
2000
2001 Int32 nb_faces = 0;
2002
2003 for (auto& elem : new_faces) {
2004 faces_infos.add(ITI_Line2);
2005 faces_infos.add(elem.m_uid_new_face);
2006 faces_infos.add(elem.m_node0->m_uid_new_node);
2007 faces_infos.add(elem.m_node1->m_uid_new_node);
2008 nb_faces++;
2009 }
2010
2011 m_cloned_mesh->modifier()->addFaces(nb_faces, faces_infos);
2012}
2013
2014/*---------------------------------------------------------------------------*/
2015/*---------------------------------------------------------------------------*/
2016
2017void MeshCutService::
2018_addCells(UniqueArray<Int64>& new_cells)
2019{
2020 Int32 nb_cells = 0;
2021
2022 Int32 pos0 = 0;
2023 while (pos0 < new_cells.size()) {
2024 const Int64 type = new_cells[pos0];
2025
2026 if (type == 3)
2027 new_cells[pos0++] = ITI_Triangle3;
2028 else if (type == 4)
2029 new_cells[pos0++] = ITI_Quad4;
2030 else if (type == 5)
2031 new_cells[pos0++] = ITI_Pentagon5;
2032 else if (type == 6)
2033 new_cells[pos0++] = ITI_Hexagon6;
2034 else
2035 ARCANE_FATAL("Pas implem : {0}", type);
2036
2037 pos0 += 1 + static_cast<Int32>(type); // (1)=UID + (type)=UIDNœuds
2038
2039 nb_cells++;
2040 }
2041
2042 m_cloned_mesh->modifier()->addCells(nb_cells, new_cells);
2043}
2044
2045/*---------------------------------------------------------------------------*/
2046/*---------------------------------------------------------------------------*/
2047
2048void MeshCutService::
2049_setCoordNodesAndOwner(UniqueArray<NodeIntersection>& new_nodes)
2050{
2051 VariableNodeReal3& node_coords(m_cloned_mesh->nodesCoordinates());
2052 ENUMERATE_ (Node, inode, m_cloned_mesh->allNodes()) {
2053 const Int64 uid = inode->uniqueId();
2054 for (const auto& elem : new_nodes) {
2055 if (elem.m_new_node->m_uid_new_node == uid) {
2056 node_coords[inode] = elem.m_intersection_pos;
2057 inode->mutableItemBase().setOwner(elem.m_new_node->m_owner_new_node, subDomain()->subDomainId());
2058 // debug() << "UID Nœud : " << uid << " -- Coordonnée : " << node_coords[inode];
2059 }
2060 }
2061 }
2062}
2063
2064/*---------------------------------------------------------------------------*/
2065/*---------------------------------------------------------------------------*/
2066
2067void MeshCutService::
2068_setFacesOwner(UniqueArray<FaceLite>& new_faces)
2069{
2070 ENUMERATE_ (Face, iface, m_cloned_mesh->allFaces()) {
2071 const Int64 uid = iface->uniqueId();
2072 for (const auto& elem : new_faces) {
2073 if (elem.m_uid_new_face == uid) {
2074 iface->mutableItemBase().setOwner(elem.m_owner_new_face, subDomain()->subDomainId());
2075 }
2076 }
2077 }
2078}
2079
2080/*---------------------------------------------------------------------------*/
2081
2082} // namespace Arcane
2083
2084/*---------------------------------------------------------------------------*/
2085/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_(type, name, group)
Enumérateur générique d'un groupe d'entité
CaseOptionsMeshCut * options() const
Options du jeu de données du service.
ArcaneMeshCutObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
virtual void clearItems()=0
Supprime toutes les entitées de toutes les familles de ce maillage.
virtual IMeshModifier * modifier()=0
Interface de modification associée.
CellGroup ownCells() const
Retourne le groupe contenant toutes les mailles propres à ce domaine.
NodeGroup allNodes() const
Retourne le groupe contenant tous les noeuds.
void addPlane(const Real3 &p0, const Real3 &normal) override
Méthode permettant d'ajouter un plan au service de coupe. L'utilisation de ces plans dépend du servic...
void setServiceMeshUniqueId(Int32 unique_id) override
Méthode permettant de définir un identifiant unique pour créer plusieurs services de section pour un ...
void setVariables(VariableCollection variables) override
Méthode permettant d'ajouter un ensemble de variables à copier sur le nouveau maillage.
VariableCollection variables() override
Méthode permettant d'obtenir un ensemble de variables copiées sur le nouveau maillage.
void updateSection() override
Méthode permettant de mettre à jour la section du maillage avec tous les plans.
MeshHandle meshSection() override
Méthode permettant d'obtenir la section du maillage.
Handle sur un maillage.
Definition MeshHandle.h:47
Classe gérant un vecteur réel de 3 dimensions.
eServiceType creationType() const
Type du service pouvant être créé par cette instance.
Structure contenant les informations pour créer un service.
Vue d'un tableau d'éléments de type T.
Definition Span.h:633
Vecteur 1D de données avec sémantique par valeur (style STL).
Collection de variables.
__host__ __device__ Real dot(Real2 u, Real2 v)
Produit scalaire de u par v dans .
Definition MathUtils.h:94
Real3 normalizedCrossProduct3(Real3 v1, Real3 v2)
Produit vectoriel normalisé.
Definition MathUtils.h:792
__host__ __device__ Real3 normalizeReal3(Real3 v)
Normalisation d'un Real3.
Definition MathUtils.h:777
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
MeshVariableScalarRefT< Node, Real > VariableNodeReal
Grandeur au noeud de type réel.
constexpr __host__ __device__ bool isNearlyZeroWithEpsilon(const Type &a, const Type &epsilon)
Teste si une valeur est approximativement égale à zéro dans un epsilon.
Definition TypeEqual.h:292
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
bool operator<(const Item &item1, const Item &item2)
Compare deux entités.
Definition Item.h:551
eServiceType
Type du service.
@ ST_CaseOption
Le service s'utilise au niveau du jeu de données.
double Real
Type représentant un réel.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
@ Cell
Le maillage est AMR par maille.
Definition MeshKind.h:52
std::int32_t Int32
Type entier signé sur 32 bits.