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