Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
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 allowing the creation of a mesh with a cut of another mesh. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/StringBuilder.h"
15
16#include "arcane/core/IGhostLayerMng.h"
17#include "arcane/core/IItemFamily.h"
18#include "arcane/core/IMesh.h"
19#include "arcane/core/IMeshFactoryMng.h"
20#include "arcane/core/IMeshMng.h"
21#include "arcane/core/IMeshModifier.h"
22#include "arcane/core/IPrimaryMesh.h"
23#include "arcane/core/MeshBuildInfo.h"
24
25#include "arcane/core/IMeshSection.h"
26#include "arcane/std/MeshCut_axl.h"
27
28/*---------------------------------------------------------------------------*/
29/*---------------------------------------------------------------------------*/
30
31namespace Arcane
32{
33
34/*---------------------------------------------------------------------------*/
35/*---------------------------------------------------------------------------*/
36
37namespace
38{
46struct NodeOnEdge
47{
48 NodeOnEdge(const Node first_node, const Node second_node)
49 {
50 const Int64 a = first_node.uniqueId();
51 const Int64 b = second_node.uniqueId();
52 if (a < b) {
53 m_node0 = first_node;
54 m_node1 = second_node;
55 m_uid_node0 = a;
56 m_uid_node1 = b;
57 }
58 else {
59 m_node0 = second_node;
60 m_node1 = first_node;
61 m_uid_node0 = b;
62 m_uid_node1 = a;
63 }
64 }
65
66 NodeOnEdge(Int64 first_node, Int64 second_node)
67 {
68 if (first_node < second_node) {
69 m_uid_node0 = first_node;
70 m_uid_node1 = second_node;
71 }
72 else {
73 m_uid_node0 = second_node;
74 m_uid_node1 = first_node;
75 }
76 }
77
78 NodeOnEdge() = default;
79
80 bool operator<(const NodeOnEdge& other) const
81 {
82 if (m_uid_node0 != other.m_uid_node0) {
83 return m_uid_node0 < other.m_uid_node0;
84 }
85 return m_uid_node1 < other.m_uid_node1;
86 }
87
88 bool operator==(const NodeOnEdge& other) const
89 {
90 return m_uid_node0 == other.m_uid_node0 && m_uid_node1 == other.m_uid_node1;
91 }
92
93 Node m_node0;
94 Node m_node1;
95
96 Int64 m_uid_node0 = -1;
97 Int64 m_uid_node1 = -1;
98
99 Int64 m_uid_new_node = -1;
100 Int32 m_owner_new_node = -1;
101};
102
103/*---------------------------------------------------------------------------*/
104/*---------------------------------------------------------------------------*/
105
109struct FaceLite
110{
111 FaceLite(const Ref<NodeOnEdge>& node0, const Ref<NodeOnEdge>& node1)
112 : m_node0(node0->m_uid_node0 < node1->m_uid_node0 ? node0 : node1)
113 , m_node1(node0->m_uid_node0 < node1->m_uid_node0 ? node1 : node0)
114 {
115 const Int64 node00 = node0->m_uid_node0;
116 const Int64 node01 = node0->m_uid_node1;
117 const Int64 node10 = node1->m_uid_node0;
118 const Int64 node11 = node1->m_uid_node1;
119
120 if (node00 < node10) {
121 m_node0 = node0;
122 m_node1 = node1;
123 }
124 else if (node00 > node10) {
125 m_node0 = node1;
126 m_node1 = node0;
127 }
128 else {
129 if (node01 == node11) {
130 ARCANE_FATAL("Impossible (normalement...)");
131 }
132 if (node01 < node11) {
133 m_node0 = node0;
134 m_node1 = node1;
135 }
136 else {
137 m_node0 = node1;
138 m_node1 = node0;
139 }
140 }
141 }
142
143 bool operator<(const FaceLite& other) const
144 {
145 return m_node0->operator<(*(other.m_node0.get())) || (m_node0->operator==(*(other.m_node0.get())) && m_node1->operator<(*(other.m_node1.get())));
146 }
147
148 bool operator==(const FaceLite& other) const
149 {
150 return m_node0->operator==(*(other.m_node0.get())) && m_node1->operator==(*(other.m_node1.get()));
151 }
152
153 Ref<NodeOnEdge> m_node0;
154 Ref<NodeOnEdge> m_node1;
155
156 Int64 m_uid_new_face = -1;
157 Int32 m_owner_new_face = -1;
158};
159
160/*---------------------------------------------------------------------------*/
161/*---------------------------------------------------------------------------*/
162
166struct NodeIntersection
167{
168 NodeIntersection(const Node first_node, const Node second_node, const Real3& intersection_pos)
169 : m_new_node(makeRef(new NodeOnEdge(first_node, second_node)))
170 , m_intersection_pos(intersection_pos)
171 {}
172
173 NodeIntersection(Int64 first_node, Int64 second_node, const Real3& intersection_pos)
174 : m_new_node(makeRef(new NodeOnEdge(first_node, second_node)))
175 , m_intersection_pos(intersection_pos)
176 {}
177
178 NodeIntersection() = default;
179
180 bool operator<(const NodeIntersection& other) const
181 {
182 return m_new_node->operator<(*(other.m_new_node.get()));
183 }
184
185 bool operator==(const NodeIntersection& other) const
186 {
187 return m_new_node->operator==(*(other.m_new_node.get()));
188 }
189
190 Ref<NodeOnEdge> m_new_node;
191 Real3 m_intersection_pos{ -1 };
192};
193
194/*---------------------------------------------------------------------------*/
195/*---------------------------------------------------------------------------*/
196
197struct UnknownNodeOrFace
198{
199 UnknownNodeOrFace(Int64 node0_uid, Int64 node1_uid, Int32 who) : m_node0_uid(node0_uid), m_node1_uid(node1_uid), m_who(who){}
200 bool null() const {return m_who == -1;}
201 bool operator==(const UnknownNodeOrFace& other) const{return m_node0_uid == other.m_node0_uid && m_node1_uid == other.m_node1_uid;}
202 Int64 m_node0_uid;
203 Int64 m_node1_uid;
204 Int32 m_who;
205};
206} // namespace
207
208/*---------------------------------------------------------------------------*/
209/*---------------------------------------------------------------------------*/
210
211/*---------------------------------------------------------------------------*/
212/*---------------------------------------------------------------------------*/
213
221class MeshCutService
222: public ArcaneMeshCutObject
223{
224 public:
225
226 explicit MeshCutService(const ServiceBuildInfo& sbi)
228 , m_creation_type(sbi.creationType())
229 {}
230
231 public:
232
233 void addPlane(const Real3& p0, const Real3& normal) override;
234
236
237 void setServiceMeshUniqueId(Int32 unique_id) override;
238
239 VariableCollection variables() override { return {}; }
240
241 void updateSection() override;
242
244 {
245 return m_cloned_mesh->handle();
246 }
247
248 private:
249
250 void _createMesh();
251 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);
252 void _makeUniqueCellUID(Int32 sd_nb_cell, UniqueArray<Int64>& new_cells, UniqueArray<NodeIntersection>& new_nodes);
253
254 void _fillNodeUID(Int32& sd_nb_node, UniqueArray<NodeIntersection>& new_nodes);
255 Int32 _makeUniqueNodeUID(Int32 sd_nb_node, UniqueArray<NodeIntersection>& new_nodes);
256 void _fillFaceUID(Int32& sd_nb_face, UniqueArray<FaceLite>& new_faces);
257 Int32 _makeUniqueFaceUID(Int32 sd_nb_face, UniqueArray<FaceLite>& new_faces);
258 void _compute();
259
260 std::optional<Int64> _find(Span<FaceLite> new_faces, Int64 node_uid0, Int64 node_uid1);
261
262 void _addFaces(UniqueArray<FaceLite>& new_faces) const;
263 void _addCells(UniqueArray<Int64>& new_cells);
264 void _setCoordNodesAndOwner(UniqueArray<NodeIntersection>& new_nodes);
265 void _setFacesOwner(UniqueArray<FaceLite>& new_faces);
266
267 private:
268
269 eServiceType m_creation_type;
270 // VariableCollection m_variables_ori;
271 IPrimaryMesh* m_cloned_mesh = nullptr;
273 Int32 m_mesh_uid = -1;
274};
275
276/*---------------------------------------------------------------------------*/
277/*---------------------------------------------------------------------------*/
278
279ARCANE_REGISTER_SERVICE_MESHCUT(MeshCut, MeshCutService);
280
281/*---------------------------------------------------------------------------*/
282/*---------------------------------------------------------------------------*/
283
284/*---------------------------------------------------------------------------*/
285/*---------------------------------------------------------------------------*/
286
288addPlane(const Real3& p0, const Real3& normal)
289{
290 m_plans.add({ p0, math::normalizeReal3(normal) });
291}
292
293/*---------------------------------------------------------------------------*/
294/*---------------------------------------------------------------------------*/
295
298{
299 ARCANE_UNUSED(variables);
300 ARCANE_NOT_YET_IMPLEMENTED("Not supported yet");
301 // m_variables_ori = variables;
302}
303
304/*---------------------------------------------------------------------------*/
305/*---------------------------------------------------------------------------*/
306
309{
310 m_mesh_uid = unique_id;
311}
312
313/*---------------------------------------------------------------------------*/
314/*---------------------------------------------------------------------------*/
315
318{
319 if (mesh()->ghostLayerMng()->nbGhostLayer() < 1) {
320 ARCANE_FATAL("A ghost layer is required for this service");
321 }
322 _createMesh();
323 _compute();
324}
325
326/*---------------------------------------------------------------------------*/
327/*---------------------------------------------------------------------------*/
328
329void MeshCutService::
330_createMesh()
331{
332 if (m_cloned_mesh != nullptr) {
333 m_cloned_mesh->modifier()->clearItems();
334 }
335
336 if (mesh()->dimension() != 3) {
337 ARCANE_FATAL("Only 3D meshes are supported");
338 }
339
340 IMeshMng* mm = subDomain()->meshMng();
341
342 if (m_mesh_uid == -1) {
343 if (m_creation_type == ST_CaseOption) {
344 m_mesh_uid = options()->getUniqueIdServiceMesh();
345 }
346 else {
347 m_mesh_uid = 0;
348 }
349 }
350
351 String service_mesh_name = mesh()->name() + "_MeshCut" + m_mesh_uid;
352
353 MeshHandle* mesh_handle = mm->findMeshHandle(service_mesh_name, false);
354
355 if (mesh_handle == nullptr) {
356 IParallelMng* pm = subDomain()->parallelMng();
357 MeshBuildInfo mbi(service_mesh_name);
358 // auto mesh_kind = mbi.meshKind();
359 // mesh_kind.setMeshDimensionKind(eMeshCellDimensionKind::NonManifold);
360 // mbi.addMeshKind(mesh_kind);
361 mbi.addParallelMng(makeRef(pm));
362 m_cloned_mesh = mm->meshFactoryMng()->createMesh(mbi);
363 m_cloned_mesh->modifier()->setDynamic(true);
364 m_cloned_mesh->setDimension(2);
365 m_cloned_mesh->endAllocate();
366 }
367 else {
368 m_cloned_mesh = mesh_handle->mesh()->toPrimaryMesh();
369 m_cloned_mesh->modifier()->clearItems();
370 }
371}
372
373/*---------------------------------------------------------------------------*/
374/*---------------------------------------------------------------------------*/
375
376void MeshCutService::
377_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)
378{
379 auto [p0, normal] = m_plans[plan_pos];
380
381 const Int32 mesh_dim = mesh()->dimension();
382
383 VariableNodeReal3& node_coord = mesh()->nodesCoordinates();
384 VariableNodeReal node_dist(VariableBuildInfo(mesh(), "NodeDist"));
385
386 UniqueArray<Int32> face_already_computed;
387
388 // Calcul de la distance signée de chaque noeud par rapport au plan de coupe.
389 ENUMERATE_ (Node, inode, allNodes()) {
390 Real d = math::dot({ node_coord[inode] - p0 }, normal);
391 node_dist[inode] = math::isNearlyZeroWithEpsilon(d, 1e-10) ? 0 : d;
392 }
393
394 // Tableau qui contiendra tous les noeuds d'une future maille.
395 // Une maille 3D, si elle est coupée par le plan, donnera forcément une
396 // maille 2D. Les noeuds de cette maille seront stockés dans ce tableau,
397 // ainsi que, pour chaque noeud, sa position et l'arête dont il est issu
398 // (pour éviter les doublons).
399 UniqueArray<NodeIntersection> point_coords_tmp;
400
401 ENUMERATE_ (Cell, icell, ownCells()) {
402 Cell cell = *icell;
403
404 bool has_face_on_plane = false;
405 {
406 bool cell_useful = true;
407 Int32 nb_node_on_plane = 0;
408
409 // On regarde si la maille traverse le plan ou si des noeuds sont sur le
410 // plan.
411 {
412 bool has_neg = false;
413 bool has_pos = false;
414 for (Node node : cell.nodes()) {
415 Real d = node_dist[node];
416 if (d < 0)
417 has_neg = true;
418 else if (d > 0)
419 has_pos = true;
420 else {
421 nb_node_on_plane++;
422 }
423 }
424
425 // Tous les noeuds sont du même coté du plan.
426 if (!(has_neg && has_pos))
427 cell_useful = false;
428 }
429
430 // Si le nombre de noeuds sur le plan correspond au nombre de noeuds
431 // minimum d'une face, il s'agit peut-être d'une face confondue au plan.
432 // Dans ce cas, il est nécessaire de faire un traitement spécial pour
433 // éviter un doublon de mailles dans le maillage final.
434 if (nb_node_on_plane >= mesh_dim) {
435 for (Face face : cell.faces()) {
436 // Pour éviter que deux processus créent la même maille.
437 if (!face.isOwn())
438 continue;
439 if (face.nbNode() != nb_node_on_plane)
440 continue;
441
442 bool has_egal = true;
443 for (Node node : face.nodes()) {
444 if (node_dist[node] != 0) {
445 has_egal = false;
446 break;
447 }
448 }
449
450 // On a trouvé la face confondue.
451 if (has_egal) {
452
453 // Si elle a déjà été traitée, on passe pour éviter un doublon.
454 if (face_already_computed.contains(face.localId())) {
455 cell_useful = false;
456 break;
457 }
458
459 // On sait que la face est confondue au plan et que la future
460 // maille créée grâce à cette face n'existe pas encore.
461 // On peut donc directement ajouter les noeuds de la face dans la
462 // liste des noeuds de la future maille.
463 face_already_computed.add(face.localId());
464 for (Node node : face.nodes()) {
465 auto ni = NodeIntersection{ node, node, node_coord[node] };
466 point_coords_tmp.add(ni);
467 }
468 has_face_on_plane = true;
469 cell_useful = true;
470 break;
471 }
472 }
473 }
474
475 if (!cell_useful)
476 continue;
477 }
478
479 if (!has_face_on_plane) {
480 // Tableaux définissant les arêtes pour chaque type d'élément.
481 // Chaque arête = [n0, n1] indices noeuds locaux de maille.
482 //
483 static constexpr Integer edges_tetraedron4[6][2] = {
484 { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 2 }, { 1, 3 }, { 2, 3 }
485 };
486 static constexpr Integer edges_pyramid5[8][2] = {
487 { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 }, { 0, 4 }, { 1, 4 }, { 2, 4 }, { 3, 4 }
488 };
489 static constexpr Integer edges_pentaedron6[9][2] = {
490 { 0, 1 }, { 1, 2 }, { 2, 0 }, { 0, 3 }, { 1, 4 }, { 2, 5 }, { 3, 4 }, { 4, 5 }, { 5, 3 }
491 };
492 static constexpr Integer edges_hexaedron8[12][2] = {
493 { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 }, { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 }
494 };
495
496 Integer nb_edges = 0;
497 const Integer(*edge_def)[2] = nullptr;
498
499 auto type = cell.itemTypeId();
500
501 if (type == ITI_Tetraedron4) {
502 nb_edges = 6;
503 edge_def = edges_tetraedron4;
504 }
505 else if (type == ITI_Pyramid5) {
506 nb_edges = 8;
507 edge_def = edges_pyramid5;
508 }
509 else if (type == ITI_Pentaedron6) {
510 nb_edges = 9;
511 edge_def = edges_pentaedron6;
512 }
513 else if (type == ITI_Hexaedron8) {
514 nb_edges = 12;
515 edge_def = edges_hexaedron8;
516 }
517
518 else {
519 ARCANE_FATAL("Cell type not supported -- type: {0}", type);
520 }
521
522 // Itère sur toutes les arêtes de la maille.
523 for (Integer i = 0; i < nb_edges; ++i) {
524 Node node0 = cell.node(edge_def[i][0]);
525 Node node1 = cell.node(edge_def[i][1]);
526
527 bool need_compute_intersection = true;
528
529 // Si le noeud 0 est sur le plan.
530 if (node_dist[node0] == 0) {
531 const Real3 p = node_coord[node0];
532
533 auto ni = NodeIntersection{ node0, node0, p };
534
535 if (!point_coords_tmp.contains(ni)) {
536 point_coords_tmp.add(ni);
537 }
538 need_compute_intersection = false;
539 }
540
541 // Si le noeud 1 est sur le plan.
542 if (node_dist[node1] == 0) {
543 const Real3 p = node_coord[node1];
544
545 auto ni = NodeIntersection{ node1, node1, p };
546
547 if (!point_coords_tmp.contains(ni)) {
548 point_coords_tmp.add(ni);
549 }
550 need_compute_intersection = false;
551 }
552
553 // Si l'arrête passe à travers le plan.
554 if (need_compute_intersection && node_dist[node0] * node_dist[node1] < 0) {
555
556 // Paramètre d'interpolation t dans [0,1] pour le point d'intersection
557 // le long de l'arête de node0 à node1.
558 Real t = std::abs(node_dist[node0]) / (std::abs(node_dist[node0]) + std::abs(node_dist[node1]));
559
560 // Calcul du point d'intersection par interpolation linéaire.
561 Real3 p;
562 p.x = node_coord[node0].x + t * (node_coord[node1].x - node_coord[node0].x);
563 p.y = node_coord[node0].y + t * (node_coord[node1].y - node_coord[node0].y);
564 p.z = node_coord[node0].z + t * (node_coord[node1].z - node_coord[node0].z);
565
566 auto ni = NodeIntersection{ node0, node1, p };
567
568 if (!point_coords_tmp.contains(ni)) {
569 point_coords_tmp.add(ni);
570 }
571 }
572 }
573 }
574
575 // Si le nombre de futurs noeuds est suffisant pour en faire une maille.
576 if (point_coords_tmp.size() >= mesh_dim) {
577
578 // Type cell.
579 if (point_coords_tmp.size() > 6)
580 ARCANE_FATAL("Pas implem : {0}", point_coords_tmp.size());
581
582 new_cells.add(point_coords_tmp.size());
583 new_cells.add(sd_nb_cell);
584
585 {
586 // Calcul du barycentre de tous les points d'intersection.
587 Real3 bary{ 0 };
588 for (const auto& node : point_coords_tmp) {
589 bary += node.m_intersection_pos;
590 }
591 bary /= point_coords_tmp.size();
592
593 // On choisit un vecteur de référence arbitraire non parallèle au normal.
594 // Si normal.x est grand (proche de l'axe X), utiliser l'axe Y ; sinon utiliser l'axe X.
595 const Real3 arbitrary = (std::abs(normal.x) > 0.9) ? Real3{ 0.0, 1.0, 0.0 } : Real3{ 1.0, 0.0, 0.0 };
596 // u et v forment une base orthonormale du plan de coupe.
597 // Ils sont perpendiculaires au normal et l'un à l'autre.
598 const Real3 u = math::normalizedCrossProduct3(arbitrary, normal);
599 const Real3 v = math::normalizedCrossProduct3(normal, u);
600
601 // On trie les points d'intersection par angle polaire autour du barycentre.
602 // Cela garantit que le polygone résultant est correctement ordonné (sens inverse des aiguilles d'une montre).
603 UniqueArray<Int64> indices;
604 indices.reserve(point_coords_tmp.size());
605 for (Int64 i = 0; i < point_coords_tmp.size(); ++i) {
606 indices.add(i);
607 }
608
609 std::sort(indices.begin(), indices.end(),
610 [&](const Int64 ia, const Int64 ib) {
611 const Real3& pa = point_coords_tmp[ia].m_intersection_pos;
612 const Real3& pb = point_coords_tmp[ib].m_intersection_pos;
613
614 // Vecteurs allant du barycentre vers chaque point.
615 const Real3 va{ pa - bary };
616 const Real3 vb{ pb - bary };
617
618 // Projeter sur la base 2D du plan (u, v).
619 const Real a_x = math::dot(va, u);
620 const Real a_y = math::dot(va, v);
621
622 const Real b_x = math::dot(vb, u);
623 const Real b_y = math::dot(vb, v);
624
625 // Comparer les angles en utilisant atan2.
626 const Real angle_a = std::atan2(a_y, a_x);
627 const Real angle_b = std::atan2(b_y, b_x);
628
629 return angle_a < angle_b;
630 });
631
632 // On crée la nouvelle maille.
633 // On en profite pour modifier le tableau "indices" :
634 // - avant la boucle, ce tableau contient les indices de positions de
635 // noeuds dans le tableau point_coords_tmp.
636 // - après la boucle, ce tableau contiendra les indices de positions
637 // de ces mêmes noeuds mais dans le tableau "global" new_nodes.
638 for (Int64& idx : indices) {
639 // On regarde si le noeud est déjà présent dans le tableau "global".
640 std::optional<Int64> pos = new_nodes.span().findFirst(point_coords_tmp[idx]);
641 if (pos) {
642 // Attention : on ajoute la position du noeud dans le tableau
643 // "global", pas le UID de celui-ci ! En effet, on ne le connait
644 // pas encore, ce sera ajusté dans la méthode
645 // "_makeUniqueCellUID()".
646 new_cells.add(static_cast<Int32>(pos.value()) + ajust_node_pos);
647 idx = pos.value();
648 }
649 // S'il n'est pas présent, on le crée.
650 else {
651 NodeIntersection& elem = point_coords_tmp[idx];
652
653 // Si les deux noeuds ont le même proprio, on sait que le nouveau noeud aura le même proprio.
654 if (elem.m_new_node->m_node0.owner() == elem.m_new_node->m_node1.owner()) {
655 elem.m_new_node->m_owner_new_node = elem.m_new_node->m_node0.owner();
656 // Si les deux noeuds sont à nous, on est sûr d'être le
657 // propriétaire du nouveau noeud. C'est donc à nous de donner le
658 // UniqueID (unique pour ce processus, la correction sera faite
659 // plus tard, quand on saura le nombre de noeuds de chaque
660 // processus).
661 if (elem.m_new_node->m_node0.isOwn()) {
662 elem.m_new_node->m_uid_new_node = sd_nb_node++;
663 }
664 else {
665 // -2 = nécessite d'être ajouté plus tard.
666 elem.m_new_node->m_uid_new_node = -2;
667 }
668 }
669 new_cells.add(new_nodes.size() + ajust_node_pos);
670 idx = new_nodes.size();
671 new_nodes.add(elem);
672 }
673 }
674
675 // Maintenant, on ajoute les faces.
676 Int64 idxm1 = indices[indices.size() - 1];
677 for (Int64 idx : indices) {
678 FaceLite fl(new_nodes[idx].m_new_node, new_nodes[idxm1].m_new_node);
679 if (!new_faces.contains(fl)) {
680 // info() << "Add face"
681 // << " -- N00 " << fl.m_node0->m_uid_node0
682 // << " -- N01 " << fl.m_node0->m_uid_node1
683 // << " -- N10 " << fl.m_node1->m_uid_node0
684 // << " -- N11 " << fl.m_node1->m_uid_node1;
685
686 // Même principe qu'avec les noeuds juste au-dessus.
687 if (new_nodes[idx].m_new_node->m_owner_new_node == new_nodes[idxm1].m_new_node->m_owner_new_node) {
688 fl.m_owner_new_face = new_nodes[idx].m_new_node->m_owner_new_node;
689 if (fl.m_owner_new_face == subDomain()->subDomainId()) {
690 fl.m_uid_new_face = sd_nb_face++;
691 }
692 else {
693 fl.m_uid_new_face = -2;
694 }
695 }
696 new_faces.add(fl);
697 }
698 idxm1 = idx;
699 }
700 }
701 sd_nb_cell++;
702 }
703 point_coords_tmp.clear();
704 }
705}
706
707/*---------------------------------------------------------------------------*/
708/*---------------------------------------------------------------------------*/
709
710void MeshCutService::
711_makeUniqueCellUID(Int32 sd_nb_cell, UniqueArray<Int64>& new_cells, UniqueArray<NodeIntersection>& new_nodes)
712{
713 IParallelMng* pm = subDomain()->parallelMng();
714
715 Int32 decal = sd_nb_cell;
716 pm->scan(MessagePassing::ReduceSum, ArrayView{ 1, &decal });
717
718 // Int32 nb_cells_global = decal;
719 // pm->broadcast(ArrayView{ 1, &nb_cells_global }, pm->commSize() - 1);
720
721 decal -= sd_nb_cell;
722
723 // info() << "[" << pm->commRank() << "] Scan result (rectified) : " << decal;
724
725 // En plus de décaler les uids des mailles pour les rendre unique sur tout le
726 // domaine, on ajoute les vrais UID des noeuds à la place des positions des
727 // noeuds dans le tableau "new_nodes".
728 Int32 pos0 = 0;
729 while (pos0 < new_cells.size()) {
730 Int64 type = new_cells[pos0++];
731 new_cells[pos0++] += decal;
732
733 for (Int32 i = 0; i < type; ++i) {
734 Int64& pos_to_uid = new_cells[pos0++];
735 pos_to_uid = new_nodes[pos_to_uid].m_new_node->m_uid_new_node;
736 }
737 }
738 // return nb_cells_global;
739}
740
741/*---------------------------------------------------------------------------*/
742/*---------------------------------------------------------------------------*/
743
744void MeshCutService::
745_fillNodeUID(Int32& sd_nb_node, UniqueArray<NodeIntersection>& new_nodes)
746{
747
748 // À partir d'ici, nous avons un tableau de noeuds. Les noeuds dont on est
749 // sûr qu'ils nous appartiennent ont déjà un UID/Owner.
750 //
751 // Il y a deux autres types de noeuds :
752 // - le noeud dont on pense connaitre le proprio à qui demander le UID,
753 // - le noeud dont on ne connait pas encore le proprio ni le UID.
754
755 IParallelMng* pm = subDomain()->parallelMng();
756 Int32 my_proc = pm->commRank();
757 UniqueArray<UniqueArray<Ref<NodeOnEdge>>> requested_nodes(subDomain()->nbSubDomain());
758
759 //
760 //
761 // Première étape : détermination des proprios potentiels et création des
762 // requêtes.
763 //
764 // Détermination des proprios :
765 // Si un noeud n'a pas encore de proprio, on choisit le proprio parmi les
766 // mailles des noeuds (N0 et N1) de l'arête dont est issu notre noeud (NN).
767 //
768 // N0 NN N1
769 // *-------*-------*
770 //
771 // NN = elem.m_new_node
772 // N0 = elem.m_new_node->m_node0
773 // N1 = elem.m_new_node->m_node1
774 //
775 // Il peut y avoir des cas où le proprio choisi ne possède pas le noeud.
776 // Ce cas sera traité plus tard dans la méthode.
777 //
778 // À partir de là, on a un proprio pour tous les noeuds.
779 //
780 // Création des requêtes :
781 // On a un message pour chaque processus.
782 // Ce message est composé de pairs de UID : les UID des noeuds de l'arête
783 // dont est issu notre noeud (seul moyen d'identifier notre noeud sur tous
784 // les processus (si l'on ne souhaite pas utiliser sa position)).
785 //
786 // Exemple :
787 // request_uid[][] :
788 // P0 : --Nous--
789 // P1 : [NN09_N0_UID, NN09_N1_UID, NN01_N0_UID, NN01_N1_UID, NN00_N0_UID, NN00_N1_UID]
790 // P2 : [NN14_N0_UID, NN14_N1_UID, NN15_N0_UID, NN15_N1_UID]
791 // P3 : []
792 //
793 // request_uid[][] :
794 // P0 : []
795 // P1 : [NN09_N0_UID, NN09_N1_UID]
796 // P2 : --Nous--
797 // P3 : []
798 //
799 // request_uid[][] :
800 // P0 : []
801 // P1 : [NN00_N0_UID, NN00_N1_UID]
802 // P2 : []
803 // P3 : --Nous--
804 //
805 // On stocke aussi, dans un autre tableau, les NodeOnEdge correspondant
806 // aux paires de UID, afin de les retrouver facilement lorsque l'on aura
807 // reçu les réponses des processus.
808 //
809 // Exemple :
810 // requested_nodes[][] :
811 // P0 : --Nous--
812 // P1 : [NN09, NN01, NN00]
813 // P2 : [NN14, NN15]
814 // P3 : []
815 //
816 //
817 {
818 UniqueArray<UniqueArray<Int64>> request_uid(subDomain()->nbSubDomain());
819
820 debug() << "[Node][" << my_proc << "] Step 1";
821
822 for (auto& elem : new_nodes) {
823 // Si le uid est déjà mis, pas besoin de le rechercher...
824 if (elem.m_new_node->m_uid_new_node >= 0) {
825 continue;
826 }
827
828 // Si le proprio n'est pas définit, on doit faire une recherche.
829 if (elem.m_new_node->m_owner_new_node < 0) {
830
831 Node node0 = elem.m_new_node->m_node0;
832 Node node1 = elem.m_new_node->m_node1;
833
834 // Le propriétaire du noeud est le propriétaire de la maille ayant le plus
835 // petit UID, parmi les mailles en commun entre les deux noeuds d'origine.
836
837 // TODO Ajouter traitement particulier pour le cas où node0 == node1
838 Int64 min_uid = INT64_MAX;
839 Int32 owner_min = -1;
840 for (Cell cell0 : node0.cells()) {
841 for (Cell cell1 : node1.cells()) {
842 if (cell0 == cell1) {
843 if (cell0.uniqueId() < min_uid) {
844 min_uid = cell0.uniqueId();
845 owner_min = cell0.owner();
846 }
847 }
848 }
849 }
850
851 // S'il l'on est le proprio, on peut définir le uid du noeud.
852 if (owner_min == subDomain()->subDomainId()) {
853 elem.m_new_node->m_owner_new_node = subDomain()->subDomainId();
854 elem.m_new_node->m_uid_new_node = sd_nb_node++;
855
856 // debug() << "[Node][" << my_proc << " -> " << elem.m_new_node->m_owner_new_node << "] Set UID"
857 // << " -- UID0 : " << elem.m_new_node->m_uid_node0
858 // << " -- UID1 : " << elem.m_new_node->m_uid_node1
859 // << " -- New UID : " << elem.m_new_node->m_uid_new_node;
860 }
861
862 // Sinon, on doit aller demander le uid au proprio.
863 else {
864 elem.m_new_node->m_owner_new_node = owner_min;
865 elem.m_new_node->m_uid_new_node = -2;
866
867 // Une requête est composée uniquement des deux UID des noeuds de
868 // l'arête dont est issue le nouveau noeud. C'est le seul moyen
869 // d'identifier ce noeud pour l'instant (si on exclut l'identification
870 // par sa position).
871 request_uid[elem.m_new_node->m_owner_new_node].add(elem.m_new_node->m_uid_node0);
872 request_uid[elem.m_new_node->m_owner_new_node].add(elem.m_new_node->m_uid_node1);
873
874 requested_nodes[elem.m_new_node->m_owner_new_node].add(elem.m_new_node);
875
876 // debug() << "[Node][" << my_proc << " -> " << elem.m_new_node->m_owner_new_node << "] Ask1"
877 // << " -- UID0 : " << elem.m_new_node->m_uid_node0
878 // << " -- UID1 : " << elem.m_new_node->m_uid_node1;
879 }
880 }
881
882 // Si le proprio est déjà défini, on doit lui demander le uid du noeud.
883 else {
884 request_uid[elem.m_new_node->m_owner_new_node].add(elem.m_new_node->m_uid_node0);
885 request_uid[elem.m_new_node->m_owner_new_node].add(elem.m_new_node->m_uid_node1);
886
887 requested_nodes[elem.m_new_node->m_owner_new_node].add(elem.m_new_node);
888
889 // debug() << "[Node][" << my_proc << " -> " << elem.m_new_node->m_owner_new_node << "] Ask2"
890 // << " -- UID0 : " << elem.m_new_node->m_uid_node0
891 // << " -- UID1 : " << elem.m_new_node->m_uid_node1;
892 }
893 }
894
895 // On envoie les requêtes.
896 {
897 UniqueArray<Parallel::Request> requests(subDomain()->nbSubDomain() * 2);
898
899 debug() << "[Node][" << my_proc << "] Step 1.2";
900
901 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
902 if (sr == subDomain()->subDomainId()) {
903 continue;
904 }
905 Int32 size = request_uid[sr].size();
906 requests[sr * 2] = pm->send(ArrayView{ 1, &size }, sr, false);
907 requests[sr * 2 + 1] = pm->send(request_uid[sr], sr, false);
908 // debug() << "[Node][" << my_proc << " -> " << sr << "] Requests : " << request_uid[sr];
909 }
910
911 pm->waitAllRequests(requests);
912 }
913 }
914
915 //
916 //
917 // Deuxième étape : traitement des requêtes des autres processus et gestion
918 // des inconnus.
919 //
920 // Traitement des requêtes :
921 //
922 // On effectue le traitement à la réception (donc processus par processus).
923 // Pour chaque paire de UID (N0-N1), on la recherche dans notre tableau des
924 // noeuds.
925 // On l'a trouve, parfait, on place l'UID du noeud (NN) dans le tableau de
926 // réponse.
927 //
928 // Gestion des inconnus :
929 //
930 // Si on ne trouve pas la paire dans notre tableau, on est dans le cas où le
931 // noeud NN est placé sur un noeud du maillage 3D (donc N0 == N1 et
932 // position(N0) == position(NN)).
933 // Lorsque l'on itère sur les mailles de N0, on peut tomber sur des mailles
934 // qui ne sont pas coupées par le plan, donc qui ne possède pas le noeud.
935 //
936 // On n'a pas le noeud dans notre tableau. Par contre, on sait qui demande
937 // ce noeud ! Grâce aux mailles fantômes, on est sûr que tous les processus
938 // qui souhaite le UID du noeud NN vont le demander au même processus. Nous
939 // pouvons donc construire la liste de ces processus demandeurs. Processus
940 // demandeurs dont on est sûr qu'ils possèdent le noeud NN !
941 // Nous allons donc leur envoyer cette liste et il se débrouilleront pour
942 // trouver le bon proprio parmi les processus de cette liste !
943 //
944 // Réponses :
945 //
946 // Le tableau des réponses doit donc contenir deux parties :
947 // - les UIDs, s'ils sont trouvés,
948 // - les processus possédant les noeuds inconnus.
949 //
950 // Pour avoir la limite entre ces deux parties, on place la taille de la
951 // première partie en première position du tableau de réponse.
952 //
953 // Si un UID est trouvé, on l'ajoute. S'il n'est pas trouvé, on place "-1".
954 //
955 // La seconde partie est structurée ainsi :
956 // - Pour chaque inconnu (pour chaque "-1") :
957 // - UID du noeud N0
958 // - UID du noeud N1
959 // - Nombre de processus demandeurs (donc possédant forcément le noeud NN),
960 // - Rangs des processus demandeurs.
961 //
962 // TODO : A changer :
963 // L'ordre de la seconde partie n'a pas d'importance.
964 // En effet, l'ordre de cette partie est le même pour tous les processus (il
965 // n'y a pas de tri par processus selon l'ordre des requêtes (qui
966 // correspondrait à l'ordre des "-1")).
967 // C'est pour ça qu'il y a la présence des "UID du noeud N0" et "UID du
968 // noeud N1".
969 // (trier avant envoi économiserait de la mémoire et réduirait la taille de
970 // la réponse, donc TODO).
971 //
972 //
973 // (Pour l'exemple, on suit le précédent exemple)
974 // answers_uid[][] :
975 // P0 : [3, -1, NN01_UID, -1, NN09_N0_UID, NN09_N1_UID, 2, 0, 2, NN00_N0_UID, NN00_N1_UID, 2, 0, 3]
976 // P1 : --Nous--
977 // P2 : [1, -1, NN09_N0_UID, NN09_N1_UID, 2, 0, 2 ]
978 // P3 : [1, -1, NN00_N0_UID, NN00_N1_UID, 2, 0, 3 ]
979 //
980 //
981 {
982 UniqueArray<UniqueArray<Int64>> answers_uid(subDomain()->nbSubDomain());
983 {
984 UniqueArray<UnknownNodeOrFace> unknown_node;
985 debug() << "[Node][" << my_proc << "] Step 2";
986
987 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
988 if (sr == subDomain()->subDomainId()) {
989 continue;
990 }
991 Int32 size = 0;
992 pm->recv(ArrayView{ 1, &size }, sr);
993
994 UniqueArray<Int64> requested_uid(size);
995 pm->recv(requested_uid, sr);
996
997 // Taille de la première partie.
998 answers_uid[sr].add(0);
999
1000 // On traite chaque paire de noeud de la requête.
1001 for (Int32 ipair_uid = 0; ipair_uid < requested_uid.size(); ipair_uid += 2) {
1002
1003 std::optional<Int64> pos = new_nodes.span().findFirst(NodeIntersection{ requested_uid[ipair_uid], requested_uid[ipair_uid + 1], Real3{ 0 } });
1004 if (pos) {
1005 answers_uid[sr].add(new_nodes[pos.value()].m_new_node->m_uid_new_node);
1006 // debug() << "[Node][" << my_proc << " <- " << sr << "] Found"
1007 // << " -- UID0 : " << requested_uid[ipair_uid]
1008 // << " -- UID1 : " << requested_uid[ipair_uid + 1]
1009 // << " -- New UID : " << new_nodes[pos.value()].m_new_node->m_uid_new_node;
1010 }
1011
1012 // Il peut arriver que l'on nous demande un noeud que nous n'avons pas.
1013 // Par exemple, si un plan arrive pile sur une des arêtes de nos mailles.
1014 // Par contre, on sait qui en a besoin, donc qui possède une maille avec
1015 // le noeud en question.
1016 // Pour donner cette information, on va ajouter "-1" puis, à la fin de
1017 // la réponse, on va placer les processus en question.
1018 else {
1019 answers_uid[sr].add(-1);
1020 unknown_node.add({ requested_uid[ipair_uid], requested_uid[ipair_uid + 1], sr });
1021 // debug() << "[Node][" << my_proc << " <- " << sr << "] NOT Found"
1022 // << " -- UID0 : " << requested_uid[ipair_uid]
1023 // << " -- UID1 : " << requested_uid[ipair_uid + 1];
1024 }
1025 }
1026 answers_uid[sr][0] = answers_uid[sr].size() - 1;
1027 }
1028
1029 UniqueArray<Int64> who;
1030 debug() << "[Node][" << my_proc << "] Step 2.2";
1031
1032 // Dès qu'il y a eu une paire de noeuds inconnus dans une requête, il y
1033 // a eu un enregistrement de fait dans le tableau unknown_node.
1034 // Il faut maintenant lister, pour chaque paire, qui l'a aussi demandé
1035 // (rechercher les doublons) et envoyer cette liste à chacun d'entre eux.
1036 for (Int32 i = 0; i < unknown_node.size(); ++i) {
1037 if (unknown_node[i].null())
1038 continue;
1039 who.clear();
1040 who.add(unknown_node[i].m_who);
1041 unknown_node[i].m_who = -1;
1042 for (Int32 j = i + 1; j < unknown_node.size(); ++j) {
1043 if (unknown_node[j].null())
1044 continue;
1045 if (unknown_node[j] == unknown_node[i]) {
1046 who.add(unknown_node[j].m_who);
1047 unknown_node[j].m_who = -1;
1048 }
1049 }
1050 // debug() << "[Node] Additionnal infos -- Node0UID : " << unknown_node[i].m_node0_uid << " -- Node1UID : " << unknown_node[i].m_node1_uid << " -- Who : " << who;
1051 for (auto proc : who) {
1052 answers_uid[proc].add(unknown_node[i].m_node0_uid);
1053 answers_uid[proc].add(unknown_node[i].m_node1_uid);
1054 answers_uid[proc].add(who.size());
1055 answers_uid[proc].addRange(who);
1056 }
1057 }
1058 }
1059
1060 {
1061 UniqueArray<Parallel::Request> requests(subDomain()->nbSubDomain() * 2);
1062
1063 // On envoie les réponses.
1064 debug() << "[Node][" << my_proc << "] Step 2.3";
1065 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1066 if (sr == subDomain()->subDomainId()) {
1067 continue;
1068 }
1069
1070 Int32 size = answers_uid[sr].size();
1071 requests[sr * 2] = pm->send(ArrayView{ 1, &size }, sr, false);
1072 requests[sr * 2 + 1] = pm->send(answers_uid[sr], sr, false);
1073
1074 // debug() << "[Node][" << my_proc << " -> " << sr << "] Send " << answers_uid[sr];
1075 }
1076
1077 pm->waitAllRequests(requests);
1078 }
1079 }
1080
1081
1082 //
1083 //
1084 // Troisième étape : Mise à jour des UIDs des noeuds et recherche
1085 // complémentaire de proprios.
1086 //
1087 // On commence par découper la réponse en deux, pour retrouver les deux
1088 // parties tèl que défini plus haut.
1089 // On itère sur la première partie. L'ordre des UIDs reçus est le même que
1090 // l'ordre des noeuds du tableau "requested_nodes" complété dans la première
1091 // partie. On peut ainsi aisément récupérer l'objet correspondant
1092 // (`node_on_edge` dans le code juste en dessous).
1093 //
1094 // Si nous avons reçu un UID valide, on met à jour le noeud correspondant
1095 // et on passe au suivant.
1096 //
1097 // Si nous avons "-1", c'est que le propriétaire que nous avons défini dans
1098 // la première partie n'est pas le bon. Nous devons donc organiser un nouvel
1099 // envoi.
1100 //
1101 // Recherche complémentaire de proprios :
1102 //
1103 // Comme l'ordre des infos complémentaires de la seconde partie du message
1104 // n'est pas forcément le même que l'ordre de la première partie (voir TODO
1105 // au dessus), on doit d'abord rechercher, dans la seconde partie, la paire
1106 // de UID correspondant au noeud que nous traitons actuellement.
1107 //
1108 // On trouve forcément une correspondance.
1109 //
1110 // On est sûr que l'ordre dans lequel est organisée la seconde partie est le
1111 // même pour tous. On va donc se caler sur cette ordre pour transmettre le
1112 // prochain message.
1113 //
1114 // Lorsqu'une correspondance est trouvée, on modifie le message. On remplace
1115 // UID0 par la position de l'objet `Ref<NodeOnEdge>` dans le tableau
1116 // `requested_nodes` (pour éviter une seconde recherche).
1117 //
1118 // Exemple :
1119 // Rappel tableau requested_nodes[][] (Première étape de la méthode) :
1120 // requested_nodes[][] :
1121 // P0 : --Nous--
1122 // P1 : [NN09, NN01, NN00]
1123 //
1124 // Avant modif :
1125 // answered_uid[] :
1126 // P0 : --Nous--
1127 // P1 : [3, -1, NN01_UID, -1, NN09_N0_UID, NN09_N1_UID, 2, 0, 2, NN00_N0_UID, NN00_N1_UID, 2, 0, 3]
1128 //
1129 // Après modif :
1130 // answered_uid[] :
1131 // P0 : --Nous--
1132 // P1 : [3, -1, NN01_UID, -1, 0, NN09_N1_UID, 2, 0, 2, 2, NN00_N1_UID, 2, 0, 3]
1133 //
1134 // Explication de l'exemple :
1135 // On remplace "NN09_N0_UID" par "0" car le noeud "NN09" se trouve à la
1136 // position 0 du tableau `requested_nodes[1][]` (le premier indice est le
1137 // rang du processus cible (donc 1 ici)).
1138 // On remplace "NN00_N0_UID" par "2" car le noeud "NN00" se trouve à la
1139 // position 2 du tableau `requested_nodes[1][]`.
1140 //
1141 // Cette algorithme est en deux étapes pour préserver simplement l'ordre de
1142 // la seconde partie de la réponse.
1143 //
1144 // Une fois `answered_uid[1]` modifié (donc une fois que l'on a fini
1145 // d'itérer sur la première partie de la réponse), on passe à la recherche
1146 // du propriétaire des noeuds restants.
1147 //
1148 // On itère sur la seconde partie de la réponse. Tous les processus
1149 // itèreront dans le même ordre !
1150 //
1151 // On récupère l'objet `Ref<NodeOnEdge>` à l'aide de sa position dans le
1152 // tableau `requested_nodes`. On reproduit l'algo de recherche de proprio de
1153 // la première étape de la méthode en s'assurant de tomber sur un proprio de
1154 // la liste des proprios potentiels.
1155 //
1156 // Par rapport à la première étape de la méthode, on sait de qui recevoir
1157 // des informations et on sait dans quel ordre les interpréter. Donc inutile
1158 // d'envoyer des messages vides si aucune infos n'est nécessaire.
1159 //
1160 // On va utiliser le tableau "request_uid" pour stocker les messages à
1161 // envoyer mais aussi la taille des messages que l'on devra recevoir.
1162 //
1163 // Pour les messages à envoyer, on stocke uniquement les UIDs qui devront
1164 // être appliqués.
1165 // Pour chaque UID stocké du coté du processus envoyeur, l'objet
1166 // `Ref<NodeOnEdge>` correspondant est stocké dans le tableau
1167 // `requested_nodes2` du coté du processus receveur.
1168 //
1169 // Exemple :
1170 // L'algo a déterminé que
1171 // - "NN09" appartient à "2" (et non à "0") et
1172 // - "NN00" appartient à "0" (et non à "3").
1173 //
1174 // request_uid[][] :
1175 // P0 : --Nous-- [0, 0, 1, 0]
1176 // P1 : []
1177 // P2 : []
1178 // P3 : [NN00_UID]
1179 //
1180 // (à lire : P0 attend un message de taille 1 de la part de P2)
1181 // ( P0 envoie NN00_UID à P3)
1182 //
1183 // request_uid[][] :
1184 // P0 : [NN09_UID]
1185 // P1 : []
1186 // P2 : --Nous-- [0, 0, 0, 0]
1187 // P3 : []
1188 //
1189 // request_uid[][] :
1190 // P0 : []
1191 // P1 : []
1192 // P2 : []
1193 // P3 : --Nous-- [1, 0, 0, 0]
1194 //
1195 //
1196 UniqueArray<UniqueArray<Int64>> request_uid(subDomain()->nbSubDomain());
1197 UniqueArray<UniqueArray<Ref<NodeOnEdge>>> requested_nodes2(subDomain()->nbSubDomain());
1198
1199 // On reçoit et traite les réponses.
1200 debug() << "[Node][" << my_proc << "] Step 3";
1201
1202 // Permet de savoir si les prochaines étapes sont utiles.
1203 bool need_more_comm = false;
1204
1205 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1206 if (sr == subDomain()->subDomainId()) {
1207 continue;
1208 }
1209
1210 Int32 total_size = 0;
1211 pm->recv(ArrayView{ 1, &total_size }, sr);
1212
1213 UniqueArray<Int64> answered_uid(total_size);
1214 pm->recv(answered_uid, sr);
1215
1216 if (total_size == 1) {
1217 continue;
1218 }
1219
1220 Int32 answer_to_request_size = static_cast<Int32>(answered_uid[0]);
1221
1222 Span<Int64> answer_to_request = answered_uid.subView(1, answer_to_request_size);
1223 Span<Int64> additionnal_answer = answered_uid.subView(answer_to_request_size+1, answered_uid.size() - (answer_to_request_size+1));
1224
1225 // debug() << "[Node][" << my_proc << " <- " << sr << "] Decoupe"
1226 // << " -- answer_to_request : " << answer_to_request
1227 // << " -- additionnal_answer : " << additionnal_answer;
1228
1229
1230 for (Int32 answer = 0; answer < answer_to_request.size(); ++answer) {
1231 Ref<NodeOnEdge> node_on_edge = requested_nodes[sr][answer];
1232
1233 if (answer_to_request[answer] != -1) {
1234 node_on_edge->m_uid_new_node = answer_to_request[answer];
1235 // debug() << "[Node][" << my_proc << "] Apply"
1236 // << " -- UID0 : " << node_on_edge->m_uid_node0
1237 // << " -- UID1 : " << node_on_edge->m_uid_node1
1238 // << " -- New UID : " << node_on_edge->m_uid_new_node;
1239 }
1240 else {
1241 Int64 pos = 0;
1242 while (pos < additionnal_answer.size()) {
1243 Int64& uid0 = additionnal_answer[pos++];
1244 Int64 uid1 = additionnal_answer[pos++];
1245 Int64 decal = additionnal_answer[pos++];
1246 if (uid0 == node_on_edge->m_uid_node0 && uid1 == node_on_edge->m_uid_node1) {
1247 uid0 = answer;
1248 break;
1249 }
1250 pos += decal;
1251 }
1252 if (pos >= additionnal_answer.size()) {
1253 ARCANE_FATAL("Unknown node -- UID0 : {0} -- UID1 : {1}", node_on_edge->m_uid_node0, node_on_edge->m_uid_node1);
1254 }
1255 }
1256 }
1257
1258 Int64 pos = 0;
1259 Span<Int64> sub_additionnal_answer;
1260
1261 while (pos < additionnal_answer.size()) {
1262 Int64 pos_node_in_array = additionnal_answer[pos++];
1263 pos++;
1264 Int64 decal = additionnal_answer[pos++];
1265
1266 Ref<NodeOnEdge> node_on_edge = requested_nodes[sr][pos_node_in_array];
1267 sub_additionnal_answer = additionnal_answer.subSpan(pos, decal);
1268
1269 pos += decal;
1270
1271 // debug() << "[Node][" << my_proc << " <- " << sr << "] Sub"
1272 // << " -- sub_additionnal_answer : " << sub_additionnal_answer;
1273
1274 Node node0 = node_on_edge->m_node0;
1275 Node node1 = node_on_edge->m_node1;
1276
1277 // Le propriétaire du noeud est le propriétaire de la maille ayant le plus
1278 // petit UID, parmi les mailles en commun entre les deux noeuds d'origine.
1279
1280 // TODO Ajouter traitement particulier pour le cas où node0 == node1
1281 Int64 min_uid = INT64_MAX;
1282 Int32 owner_min = -1;
1283 for (Cell cell0 : node0.cells()) {
1284 for (Cell cell1 : node1.cells()) {
1285 if (cell0 == cell1) {
1286 if (cell0.uniqueId() < min_uid && sub_additionnal_answer.contains(cell0.owner())) {
1287 min_uid = cell0.uniqueId();
1288 owner_min = cell0.owner();
1289 }
1290 }
1291 }
1292 }
1293
1294 // S'il l'on est le proprio, on peut définir le uid du noeud.
1295 if (owner_min == subDomain()->subDomainId()) {
1296 node_on_edge->m_owner_new_node = subDomain()->subDomainId();
1297 node_on_edge->m_uid_new_node = sd_nb_node++;
1298
1299 // On enregistre le UID à envoyer.
1300 if (sub_additionnal_answer.size() > 1) {
1301 need_more_comm = true;
1302
1303 // debug() << "[Node][" << my_proc << "] Send"
1304 // << " -- UID : " << node_on_edge->m_uid_new_node
1305 // << " -- for Node UID0 : " << node_on_edge->m_uid_node0
1306 // << " -- UID1 : " << node_on_edge->m_uid_node1
1307 // << " -- to : " << sub_additionnal_answer;
1308
1309 for (auto proc : sub_additionnal_answer) {
1310 if (proc == my_proc)
1311 continue;
1312 request_uid[proc].add(node_on_edge->m_uid_new_node);
1313 }
1314 }
1315 }
1316
1317 // Sinon, on doit aller demander le uid au proprio.
1318 else {
1319 need_more_comm = true;
1320 node_on_edge->m_owner_new_node = owner_min;
1321 node_on_edge->m_uid_new_node = -2;
1322
1323 if (request_uid[my_proc].empty()) {
1324 request_uid[my_proc].resize(subDomain()->nbSubDomain(), 0);
1325 }
1326
1327 request_uid[my_proc][owner_min]++;
1328
1329 requested_nodes2[owner_min].add(node_on_edge);
1330
1331 // debug() << "[Node][" << my_proc << " -> " << node_on_edge->m_owner_new_node << "] Recv UID for Node"
1332 // << " -- UID0 : " << node_on_edge->m_uid_node0
1333 // << " -- UID1 : " << node_on_edge->m_uid_node1;
1334 }
1335 }
1336 }
1337
1338 // Si nous n'avons pas de UID manquants et que personne n'a besoin de l'un
1339 // de nos UIDs, on passe cette étape.
1340 // Sinon :
1341 if (need_more_comm) {
1342 {
1343 UniqueArray<Parallel::Request> requests(subDomain()->nbSubDomain());
1344
1345 // On envoie les UID complémentaires.
1346 debug() << "[Node][" << my_proc << "] Step 3.2";
1347
1348 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1349 if (sr == subDomain()->subDomainId()) {
1350 // debug() << "[Node][" << my_proc << " -> " << sr << "] My RequestsC : " << request_uid[sr];
1351 continue;
1352 }
1353 if (request_uid[sr].empty()) continue;
1354 requests[sr] = pm->send(request_uid[sr], sr, false);
1355 // debug() << "[Node][" << my_proc << " -> " << sr << "] RequestsC : " << request_uid[sr];
1356 }
1357
1358 pm->waitAllRequests(requests);
1359 }
1360
1361 //
1362 //
1363 // Quatrième étape : Mise à jour des UIDs manquants.
1364 //
1365 // On est sûr d'avoir une réponse complète, donc c'est plus simple.
1366 // On récupère le nombre de messages à recevoir de la part de l'autre
1367 // processus et on traite son message dans l'ordre. Le tableau
1368 // `requested_nodes2[][]` est dans le même ordre ce qui facilite les
1369 // choses.
1370 //
1371 //
1372
1373 if (!request_uid[my_proc].empty()) {
1374 // On reçoit et traite les UID complémentaires.
1375 debug() << "[Node][" << my_proc << "] Step 4";
1376
1377 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1378 if (sr == subDomain()->subDomainId()) {
1379 continue;
1380 }
1381
1382 Int64 size = request_uid[my_proc][sr];
1383 if (size == 0) continue;
1384
1385 // debug() << "[Node][" << my_proc << " -> " << sr << "] Size recv : " << size;
1386
1387
1388 UniqueArray<Int64> requested_uid(size);
1389 pm->recv(requested_uid, sr);
1390
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() << "[Node][" << my_proc << "] Apply2"
1395 // << " -- UID0 : " << node_on_edge->m_uid_node0
1396 // << " -- UID1 : " << node_on_edge->m_uid_node1
1397 // << " -- New 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() << "] Gather result (rectified) : " << 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 << "] Step 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 << "] Set UID"
1487 // << " -- UID0 : " << elem.m_node0->m_uid_new_node
1488 // << " -- UID1 : " << elem.m_node1->m_uid_new_node
1489 // << " -- New 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 << "] Ask1"
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 << "] Ask2"
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 << "] Step 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 << "] Requests : " << 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 << "] Step 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 << "] Found"
1559 // << " -- UID0 : " << requested_uid[ipair_uid]
1560 // << " -- UID1 : " << requested_uid[ipair_uid + 1]
1561 // << " -- New 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 << "] NOT Found"
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 << "] Step 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] Additionnal infos -- Node0UID : " << unknown_face[i].m_node0_uid << " -- Node1UID : " << unknown_face[i].m_node1_uid << " -- Who : " << 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 << "] Step 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 << "] Step 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 << "] Decoupe"
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 << "] Apply"
1665 // << " -- UID0 : " << face_lite.m_node0->m_uid_new_node
1666 // << " -- UID1 : " << face_lite.m_node1->m_uid_new_node
1667 // << " -- New 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 << "] Sub"
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 << "] Send"
1742 // << " -- UID : " << face_lite.m_uid_new_face
1743 // << " -- for Node UID0 : " << face_lite.m_node0->m_uid_new_node
1744 // << " -- UID1 : " << face_lite.m_node1->m_uid_new_node
1745 // << " -- to : " << 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 << "] Recv UID for Node"
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 << "] Step 3.2";
1782
1783 for (Int32 sr = 0; sr < subDomain()->nbSubDomain(); ++sr) {
1784 if (sr == subDomain()->subDomainId()) {
1785 // debug() << "[Face][" << my_proc << " -> " << sr << "] My RequestsC : " << 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 << "] RequestsC : " << 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 << "] Step 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 << "] Size recv : " << 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 << "] Apply2"
1818 // << " -- UID0 : " << face_lite.m_node0->m_uid_new_node
1819 // << " -- UID1 : " << face_lite.m_node1->m_uid_new_node
1820 // << " -- New 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() << "] Gather result (rectified) : " << 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() << "New node"
1888 // << " -- UID : " << elem.m_new_node->m_uid_new_node
1889 // << " -- Owner : " << elem.m_new_node->m_owner_new_node
1890 // << " -- Pos : " << elem.m_intersection_pos
1891 // << " -- Edge node0 : " << elem.m_new_node->m_uid_node0
1892 // << " -- Edge node1 : " << 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() << "Fix node"
1904 // << " -- UID : " << elem.m_new_node->m_uid_new_node
1905 // << " -- Owner : " << elem.m_new_node->m_owner_new_node
1906 // << " -- Pos : " << elem.m_intersection_pos
1907 // << " -- Edge node0 : " << elem.m_new_node->m_uid_node0
1908 // << " -- Edge node1 : " << elem.m_new_node->m_uid_node1;
1909 // }
1910 //
1911 // for (auto& elem : plan_new_faces) {
1912 // debug() << "New face"
1913 // << " -- UID : " << elem.m_uid_new_face
1914 // << " -- Owner : " << elem.m_owner_new_face
1915 // << " -- Node0 : " << elem.m_node0->m_uid_new_node
1916 // << " -- Node00 : " << elem.m_node0->m_uid_node0
1917 // << " -- Node01 : " << elem.m_node0->m_uid_node1
1918 // << " -- Node1 : " << elem.m_node1->m_uid_new_node
1919 // << " -- Node10 : " << elem.m_node1->m_uid_node0
1920 // << " -- Node11 : " << 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() << "Fix face"
1930 // << " -- UID : " << elem.m_uid_new_face
1931 // << " -- Owner : " << elem.m_owner_new_face
1932 // << " -- Node0 : " << elem.m_node0->m_uid_new_node
1933 // << " -- Node00 : " << elem.m_node0->m_uid_node0
1934 // << " -- Node01 : " << elem.m_node0->m_uid_node1
1935 // << " -- Node1 : " << elem.m_node1->m_uid_new_node
1936 // << " -- Node10 : " << elem.m_node1->m_uid_node0
1937 // << " -- Node11 : " << 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 += "New cell -- 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 += " -- Node";
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() << "New mesh : " << m_cloned_mesh->name() << " -- NbNode : " << m_cloned_mesh->nbNode() << " -- NbCells : " << 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)=UIDNodes
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() << "NodeUID : " << uid << " -- Coord : " << 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
2083} // namespace Arcane
2084
2085/*---------------------------------------------------------------------------*/
2086/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ENUMERATE_(type, name, group)
Generic enumerator for an entity group.
CaseOptionsMeshCut * options() const
Options du jeu de données du service.
ArcaneMeshCutObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
virtual void clearItems()=0
Deletes all entities of all families in this mesh.
virtual IMeshModifier * modifier()=0
Associated modifier interface.
CellGroup ownCells() const
Returns the group containing all cells specific to this domain.
NodeGroup allNodes() const
Returns the group containing all nodes.
void addPlane(const Real3 &p0, const Real3 &normal) override
Method allowing to add a plane to the cut service. The use of these planes depends on the service.
void setServiceMeshUniqueId(Int32 unique_id) override
Method allowing to set a unique id allowing to create multiple section services for a mesh.
void setVariables(VariableCollection variables) override
Method allowing to add a set of variables to copy on the new mesh.
VariableCollection variables() override
Method allowing to get a set of variables copied on the new mesh.
void updateSection() override
Method allowing to update the mesh section with all planes.
MeshHandle meshSection() override
Méthod allowing to get the mesh section.
Handle on a mesh.
Definition MeshHandle.h:48
Class managing a 3-dimensional real vector.
eServiceType creationType() const
Type of service that can be created by this instance.
Structure containing the information to create a service.
View of an array of elements of type T.
Definition Span.h:633
1D data vector with value semantics (STL style).
__host__ __device__ Real dot(Real2 u, Real2 v)
Dot product of u by v in .
Definition MathUtils.h:94
Real3 normalizedCrossProduct3(Real3 v1, Real3 v2)
Normalized cross product.
Definition MathUtils.h:793
__host__ __device__ Real3 normalizeReal3(Real3 v)
Normalization of a Real3.
Definition MathUtils.h:778
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
MeshVariableScalarRefT< Node, Real > VariableNodeReal
Real type quantity at node.
constexpr __host__ __device__ bool isNearlyZeroWithEpsilon(const Type &a, const Type &epsilon)
Tests if a value is approximately equal to zero within an epsilon.
Definition TypeEqual.h:292
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
bool operator<(const Item &item1, const Item &item2)
Compare two entities.
Definition Item.h:566
eServiceType
Service type.
@ ST_CaseOption
The service is used at the dataset level.
double Real
Type representing a real number.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53
std::int32_t Int32
Signed integer type of 32 bits.