Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
CellMerger.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/* CellMerger.cc (C) 2000-2025 */
9/* */
10/* Merges two cells. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/mesh/CellMerger.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/StringBuilder.h"
18#include "arcane/utils/TraceInfo.h"
19#include "arcane/utils/CheckedConvert.h"
20#include "arcane/utils/TraceAccessor.h"
21
22#include "arcane/core/Item.h"
24#include "arcane/core/IItemFamily.h"
25#include "arcane/core/IItemFamilyTopologyModifier.h"
26#include "arcane/core/IMesh.h"
27#include "arcane/core/internal/IItemFamilyInternal.h"
28
29#include "arcane/mesh/FaceReorienter.h"
30
31#include <map>
32#include <set>
33
34/*---------------------------------------------------------------------------*/
35/*---------------------------------------------------------------------------*/
36
37namespace Arcane::mesh
38{
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
42
44class ItemSwapperUtils
45: public TraceAccessor
46{
47 public:
48
49 explicit ItemSwapperUtils(IMesh* mesh)
50 : TraceAccessor(mesh->traceMng())
51 , m_face_reorienter(mesh)
52 , m_cell_tm(mesh->cellFamily()->_internalApi()->topologyModifier())
53 , m_face_tm(mesh->faceFamily()->_internalApi()->topologyModifier())
54 , m_node_tm(mesh->nodeFamily()->_internalApi()->topologyModifier())
55 {
56 }
57
58 public:
59
66 void swapFaceNodes(Face face_1, Face face_2,
67 Integer face1_node_idx, Integer face2_node_idx)
68 {
69 NodeLocalId face1_node = face_1.node(face1_node_idx);
70 NodeLocalId face2_node = face_2.node(face2_node_idx);
71
72 m_face_tm->replaceNode(face_1, face1_node_idx, face2_node);
73 m_face_tm->replaceNode(face_2, face2_node_idx, face1_node);
74
75 m_node_tm->findAndReplaceFace(face1_node, face_1, face_2);
76 m_node_tm->findAndReplaceFace(face2_node, face_2, face_1);
77 }
78
85 void swapCellNodes(Cell cell1, Cell cell2,
86 Integer cell1_node_idx, Integer cell2_node_idx)
87 {
88 NodeLocalId cell1_node = cell1.node(cell1_node_idx);
89 NodeLocalId cell2_node = cell2.node(cell2_node_idx);
90
91 m_cell_tm->replaceNode(cell1, cell1_node_idx, cell2_node);
92 m_cell_tm->replaceNode(cell2, cell2_node_idx, cell1_node);
93
94 m_node_tm->findAndReplaceCell(cell1_node, cell1, cell2);
95 m_node_tm->findAndReplaceCell(cell2_node, cell2, cell1);
96 }
97
104 void swapCellFaces(Cell cell1, Cell cell2,
105 Integer cell1_face_idx, Integer cell2_face_idx)
106 {
107 FaceLocalId cell1_face = cell1.face(cell1_face_idx);
108 FaceLocalId cell2_face = cell2.face(cell2_face_idx);
109
110 m_cell_tm->replaceFace(cell1, cell1_face_idx, cell2_face);
111 m_cell_tm->replaceFace(cell2, cell2_face_idx, cell1_face);
112
113 m_face_tm->findAndReplaceCell(cell1_face, cell1, cell2);
114 m_face_tm->findAndReplaceCell(cell2_face, cell2, cell1);
115 }
116
117 void checkAndChangeFaceOrientation(Cell cell)
118 {
119 // This could undoubtedly be optimized
120 for (Integer i = 0, n = cell.nbFace(); i < n; ++i) {
121 m_face_reorienter.checkAndChangeOrientation(cell.face(i));
122 }
123 }
124
125 private:
126
127 FaceReorienter m_face_reorienter;
128 IItemFamilyTopologyModifier* m_cell_tm;
129 IItemFamilyTopologyModifier* m_face_tm;
130 IItemFamilyTopologyModifier* m_node_tm;
131};
132
133/*---------------------------------------------------------------------------*/
134/*---------------------------------------------------------------------------*/
143{
144 public:
145
146 typedef std::set<Integer> NodesLIDSet;
147
148 private:
149
152
153 NodesLIDSet m_nodes_lid_set;
154
155 public:
156
162 const NodesLIDSet& nodesLID() const
163 {
164 return m_nodes_lid_set;
165 }
166
174 {
176 }
177
185 {
187 }
188
195 CommonFaceFinder(Cell i_cell_1, Cell i_cell_2);
197};
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201
203CommonFaceFinder(Cell i_cell_1, Cell i_cell_2)
206{
207 typedef std::map<Integer, Integer> LIDCellMapping;
208 LIDCellMapping faces1; // number of faces in cell 1
209 LIDCellMapping faces2; // number of faces in cell 2
210
211 { // creation of localId to number mappings in the cell for cell 1
212 Integer n = 0;
213 for (ItemEnumerator i_face(i_cell_1.faces()); i_face(); ++i_face) {
214 faces1[i_face->localId()] = n;
215 n++;
216 }
217 }
218 { // creation of localId to number mappings in the cell for cell 2
219 Integer n = 0;
220 for (ItemEnumerator i_face(i_cell_2.faces()); i_face(); ++i_face) {
221 faces2[i_face->localId()] = n;
222 n++;
223 }
224 }
225
226 // We now iterate through the two tables created previously. Since
227 // they are sorted by increasing localId, we simply deduce
228 // the common face.
229 LIDCellMapping::const_iterator i_face1 = faces1.begin();
230 LIDCellMapping::const_iterator i_face2 = faces2.begin();
231
232 do {
233 const Integer& lid1 = i_face1->first; // localId of the face in list 1
234 const Integer& lid2 = i_face2->first; // localId of the face in list 2
235
236 if (lid1 == lid2) { // we found the common face
237 m_cell_1_local_number = i_face1->second;
238 m_cell_2_local_number = i_face2->second;
239
240 // Recording the localIds of the nodes of the common face
241 Face common_face = i_cell_1.face(m_cell_1_local_number);
242
243 for (NodeEnumerator i_node(common_face.nodes()); i_node(); ++i_node) {
244 m_nodes_lid_set.insert(i_node->localId());
245 }
246 return;
247 }
248 else {
249 if (lid1 < lid2) {
250 ++i_face1;
251 }
252 else {
253 ++i_face2;
254 }
255 }
256 } while (i_face1 != faces1.end() && i_face2 != faces2.end());
257
258 ARCANE_FATAL("Common face not found!");
259}
260
261/*---------------------------------------------------------------------------*/
262/*---------------------------------------------------------------------------*/
263
264/*---------------------------------------------------------------------------*/
265/*---------------------------------------------------------------------------*/
270{
271 private:
272
276
284 void _setFacesNodeNumbers(Face i_face_1, Face i_face_2);
285
286 public:
287
294 Faces2DMerger(ItemSwapperUtils* swap_utils, Face i_face_1, Face i_face_2);
295};
296
297/*---------------------------------------------------------------------------*/
298/*---------------------------------------------------------------------------*/
299
301_setFacesNodeNumbers(Face i_face_1, Face i_face_2)
302{
303 typedef std::map<Integer, Integer> LocalIDToLocalNumber;
304 LocalIDToLocalNumber face1_node_localId;
305 LocalIDToLocalNumber face2_node_localId;
306
307 {
308 Integer n = 0;
309 for (ItemEnumerator i_node(i_face_1.nodes()); i_node(); ++i_node) {
310 face1_node_localId[i_node->localId()] = n++;
311 }
312 }
313 {
314 Integer n = 0;
315 for (ItemEnumerator i_node(i_face_2.nodes()); i_node(); ++i_node) {
316 face2_node_localId[i_node->localId()] = n++;
317 }
318 }
319
320 //Integer face2_common_edge_node_number = std::numeric_limits<Integer>::max();
321
322 for (LocalIDToLocalNumber::const_iterator
323 i = face1_node_localId.begin(),
324 j = face2_node_localId.begin();
325 i != face1_node_localId.end() && j != face2_node_localId.end();) {
326 Int32 node1_localId = i->first;
327 Int32 node2_localId = j->first;
328 if (node1_localId == node2_localId) {
331 break;
332 }
333 else {
334 if (node1_localId < node2_localId) {
335 ++i;
336 }
337 else {
338 ++j;
339 }
340 }
341 }
342
344}
345
346/*---------------------------------------------------------------------------*/
347/*---------------------------------------------------------------------------*/
348
350Faces2DMerger(ItemSwapperUtils* swap_utils, Face face1, Face face2)
351: m_face_1_common_node_numbers(std::numeric_limits<Integer>::max())
352, m_face_2_common_node_numbers(std::numeric_limits<Integer>::max())
353, m_face_2_exchanged_node_numbers(std::numeric_limits<Integer>::max())
354{
355 ARCANE_ASSERT(face2.type() == IT_Line2, ("The cell is not a line"));
356
357 _setFacesNodeNumbers(face1, face2);
358
359 swap_utils->swapFaceNodes(face1, face2, m_face_1_common_node_numbers,
361}
362
363/*---------------------------------------------------------------------------*/
364/*---------------------------------------------------------------------------*/
370{
371 private:
372
374
381 IntegerUniqueArray m_cell2_edge_face_list;
383
395 IntegerArray& edge_face_list,
396 Integer common_face_number,
397 const CommonFaceFinder::NodesLIDSet& common_face_nodes)
398 {
399 typedef Integer _EdgeDescriptor;
400 typedef std::map<_EdgeDescriptor, Integer> _EdgeFaceList;
401
402 _EdgeFaceList temp_edge_face_list;
403 Integer face_number = 0;
404 // For each face in the cell
405 for (FaceEnumerator i_face(i_cell.faces()); i_face(); ++i_face, ++face_number) {
406 if (face_number == common_face_number) {
407 continue; // if the face is the common face, do nothing
408 }
409
410 // Create the list of nodes of this face that are common
411 std::multiset<Integer> node_list;
412 for (NodeEnumerator i_node(i_face->nodes()); i_node(); ++i_node) {
413 const Integer& node_lid = i_node->localId();
414 if (common_face_nodes.find(node_lid) != common_face_nodes.end()) {
415 node_list.insert(node_lid);
416 }
417 }
418
419 switch (node_list.size()) {
420 case 0: // the face is not to be retriangled [already processed]
421 case 2:
422 continue;
423 case 1: { // If the list contains only one element, it means the face is to be merged
424 std::multiset<Integer>::const_iterator i = node_list.begin();
425 const Integer node_lid = *i;
426 temp_edge_face_list[node_lid] = face_number;
427 break;
428 }
429 default: {
430 ARCANE_FATAL("Unexpected number of nodes on the common face !");
431 }
432 }
433 }
434
435 // We copy the data: we no longer need the edges
436 edge_face_list.reserve((Integer)temp_edge_face_list.size());
437 for (_EdgeFaceList::const_iterator i = temp_edge_face_list.begin();
438 i != temp_edge_face_list.end(); ++i) {
439 edge_face_list.add(i->second); // we store the numbers of the faces to be merged
440 }
441 }
442
443 public:
444
451 {
452 return m_cell1_edge_face_list.size();
453 }
454
463 {
464 return m_cell1_edge_face_list[i];
465 }
466
475 {
476 return m_cell2_edge_face_list[i];
477 }
478
487 const CommonFaceFinder& common_face)
488 {
489 this->_setEdgeFaceList(cell1,
491 common_face.cell1LocalNumber(),
492 common_face.nodesLID());
493 this->_setEdgeFaceList(cell2,
494 m_cell2_edge_face_list,
495 common_face.cell2LocalNumber(),
496 common_face.nodesLID());
497
498 ARCANE_ASSERT(m_cell1_edge_face_list.size() == m_cell2_edge_face_list.size(),
499 ("Incompatible number of 2D faces to merge !"));
500 }
501};
502
503/*---------------------------------------------------------------------------*/
504/*---------------------------------------------------------------------------*/
505
506/*---------------------------------------------------------------------------*/
507/*---------------------------------------------------------------------------*/
508
514{
515 public:
516
523 {
524 return m_cell1_edge_face_list.size();
525 }
526
535 {
536 return m_cell1_edge_face_list[i];
537 }
538
547 {
548 return m_cell2_edge_face_list[i];
549 }
550
559 const CommonFaceFinder& common_face)
560 {
562 common_face.cell1LocalNumber(), common_face.nodesLID());
563 _setEdgeFaceList(cell2, m_cell2_edge_face_list,
564 common_face.cell2LocalNumber(), common_face.nodesLID());
565
566 ARCANE_ASSERT(m_cell1_edge_face_list.size() == m_cell2_edge_face_list.size(),
567 ("Incompatible number of faces to merge !"));
568 }
569
570 private:
571
573
580 IntegerUniqueArray m_cell2_edge_face_list;
582 void _setEdgeFaceList(Cell i_cell,
583 IntegerArray& edge_face_list,
584 Integer common_face_number,
585 const CommonFaceFinder::NodesLIDSet& common_face_nodes);
586};
587
588/*---------------------------------------------------------------------------*/
589/*---------------------------------------------------------------------------*/
590
603 IntegerArray& edge_face_list,
604 Integer common_face_number,
605 const CommonFaceFinder::NodesLIDSet& common_face_nodes)
606{
607 typedef std::pair<Integer, Integer> _EdgeDescriptor;
608 typedef std::map<_EdgeDescriptor, Integer> _EdgeFaceList;
609
610 _EdgeFaceList temp_edge_face_list; // sorted list of face numbers by edges
611 Integer face_number = 0;
612 for (FaceEnumerator i_face(i_cell.faces()); i_face(); ++i_face, ++face_number) {
613 if (face_number == common_face_number) { // if the face is the common face, it is not processed
614 continue;
615 }
616
617 std::multiset<Integer> node_list; // list of localIds of the nodes of the face that are common
618 for (NodeEnumerator i_node(i_face->nodes()); i_node(); ++i_node) {
619 Int32 node_lid = i_node->localId();
620 // if the node is common, add it to the list of common nodes
621 if (common_face_nodes.find(node_lid) != common_face_nodes.end()) {
622 node_list.insert(node_lid);
623 }
624 }
625
626 switch (node_list.size()) {
627 case 0: // the face is not to be retriangled [already processed]
628 case 4:
629 continue;
630 case 2: {
631 std::multiset<Integer>::const_iterator i = node_list.begin();
632 const Integer first_node_lid = *i;
633 ++i;
634 const Integer second_node_lid = *i;
635 // We create the edge/face correspondence (the nodes of the edge being sorted)
636 temp_edge_face_list[std::make_pair(first_node_lid, second_node_lid)] = face_number;
637 break;
638 }
639 default:
640 ARCANE_FATAL("Unexpected number of nodes on the common face !");
641 }
642 }
643
644 // We copy the data: we no longer need the edges. The
645 // face numbers are oriented as desired.
646 edge_face_list.reserve(CheckedConvert::toInteger(temp_edge_face_list.size()));
647 for (_EdgeFaceList::const_iterator i = temp_edge_face_list.begin();
648 i != temp_edge_face_list.end(); ++i) {
649 edge_face_list.add(i->second);
650 }
651}
652
653/*---------------------------------------------------------------------------*/
654/*---------------------------------------------------------------------------*/
688
689/*---------------------------------------------------------------------------*/
690/*---------------------------------------------------------------------------*/
691
693_setFacesNodeNumbers(Face i_face_1, Face i_face_2)
694{
695 typedef std::map<Integer, Integer> LocalIDToLocalNumber;
696 LocalIDToLocalNumber face1_node_localId;
697 LocalIDToLocalNumber face2_node_localId;
698
699 {
700 Integer n = 0;
701 for (NodeEnumerator i_node(i_face_1.nodes()); i_node(); ++i_node) {
702 face1_node_localId[i_node->localId()] = n++;
703 }
704 }
705 {
706 Integer n = 0;
707 for (NodeEnumerator i_node(i_face_2.nodes()); i_node(); ++i_node) {
708 face2_node_localId[i_node->localId()] = n++;
709 }
710 }
711
714
715 std::set<Integer> face2_common_edge_node_number;
716
717 for (LocalIDToLocalNumber::const_iterator
718 i = face1_node_localId.begin(),
719 j = face2_node_localId.begin();
720 i != face1_node_localId.end() && j != face2_node_localId.end();) {
721 const Integer& node1_localId = i->first;
722 const Integer& node2_localId = j->first;
723 if (node1_localId == node2_localId) {
724 m_face_1_common_node_numbers.add(i->second);
725 m_face_2_common_node_numbers.add(j->second);
726 face2_common_edge_node_number.insert(j->second);
727 ++i;
728 ++j;
729 }
730 else {
731 if (node1_localId < node2_localId) {
732 ++i;
733 }
734 else {
735 ++j;
736 }
737 }
738 }
739
740 if (m_face_1_common_node_numbers.size() == 0)
741 return false;
742
743 ARCANE_ASSERT((m_face_2_common_node_numbers.size() == 2) && (m_face_1_common_node_numbers.size() == 2),
744 ("Incorrect number of shared vertices"));
745
747 for (Integer i = 0; i < m_face_2_common_node_numbers.size(); ++i) {
748 const Integer& node_number = m_face_2_common_node_numbers[i];
749 for (Integer j = 0; j < 2; ++j) {
750 const Integer& edge_node = m_quad_node_neighbors[node_number][j];
751 if (face2_common_edge_node_number.find(edge_node) == face2_common_edge_node_number.end()) {
752 m_face_2_exchanged_node_numbers.add(edge_node);
753 break;
754 }
755 }
756 }
757 return true;
758}
759
760/*---------------------------------------------------------------------------*/
761/*---------------------------------------------------------------------------*/
762
764FaceToQuadrilateralMerger(ItemSwapperUtils* swap_utils, Face face1, Face face2)
765{
766 ARCANE_ASSERT(face2.type() == IT_Quad4, ("The cell is not a quadrangle"));
767
768 if (_setFacesNodeNumbers(face1, face2)) {
769 ARCANE_ASSERT(m_face_2_exchanged_node_numbers.size() == 2,
770 ("Incorrect number of exchange vertices"));
771
772 // Exchange of face nodes
773 for (Integer i = 0; i < 2; ++i) {
774 swap_utils->swapFaceNodes(face1, face2, m_face_1_common_node_numbers[i],
776 }
777 }
778}
779
780/*---------------------------------------------------------------------------*/
781/*---------------------------------------------------------------------------*/
782
783const Integer
785m_quad_node_neighbors[4][2] = { { 1, 3 }, { 0, 2 }, { 1, 3 }, { 0, 2 } };
786
787/*---------------------------------------------------------------------------*/
788/*---------------------------------------------------------------------------*/
789
790/*---------------------------------------------------------------------------*/
791/*---------------------------------------------------------------------------*/
792
826
827/*---------------------------------------------------------------------------*/
828/*---------------------------------------------------------------------------*/
829
831_setCellsNodeNumbers(Cell i_cell_1, Cell i_cell_2)
832{
833 typedef std::map<Integer, Integer> LocalIDToLocalNumber;
834 LocalIDToLocalNumber cell1_node_localId;
835 LocalIDToLocalNumber cell2_node_localId;
836
837 {
838 Integer n = 0;
839 for (NodeEnumerator i_node(i_cell_1.nodes()); i_node(); ++i_node) {
840 cell1_node_localId[i_node->localId()] = n++;
841 }
842 }
843 {
844 Integer n = 0;
845 for (NodeEnumerator i_node(i_cell_2.nodes()); i_node(); ++i_node) {
846 cell2_node_localId[i_node->localId()] = n++;
847 }
848 }
849
850 std::set<Integer> cell2_common_edge_node_number;
851 for (LocalIDToLocalNumber::const_iterator
852 i = cell1_node_localId.begin(),
853 j = cell2_node_localId.begin();
854 i != cell1_node_localId.end() && j != cell2_node_localId.end();) {
855 const Integer& node1_localId = i->first;
856 const Integer& node2_localId = j->first;
857 if (node1_localId == node2_localId) {
858 m_cell_1_common_node_numbers.add(i->second);
859 m_cell_2_common_node_numbers.add(j->second);
860 cell2_common_edge_node_number.insert(j->second);
861 ++i;
862 ++j;
863 }
864 else {
865 if (node1_localId < node2_localId) {
866 ++i;
867 }
868 else {
869 ++j;
870 }
871 }
872 }
873
874 ARCANE_ASSERT(m_cell_1_common_node_numbers.size() == 2,
875 ("Bad number of shared vertices"));
876
878 for (Integer i = 0; i < m_cell_2_common_node_numbers.size(); ++i) {
879 const Integer& node_number = m_cell_2_common_node_numbers[i];
880 for (Integer j = 0; j < 2; ++j) {
881 const Integer& edge_node = m_quad_node_neighbors[node_number][j];
882 if (cell2_common_edge_node_number.find(edge_node) == cell2_common_edge_node_number.end()) {
883 m_cell_2_exchanged_node_numbers.add(edge_node);
884 break;
885 }
886 }
887 }
888}
889
890/*---------------------------------------------------------------------------*/
891/*---------------------------------------------------------------------------*/
892
894CellToQuadrilateralMerger(ItemSwapperUtils* swap_utils, Cell cell1, Cell cell2)
895{
896 ARCANE_ASSERT(cell2.type() == IT_Quad4, ("Cell2 is not a IT_Quad4"));
897
898 CommonFaceFinder common_face(cell1, cell2);
899
900 this->_setCellsNodeNumbers(cell1, cell2);
901
902 // Fusion of side cells
903 Faces2DToMergeFinder faces_to_merge(cell1, cell2, common_face);
904 for (Integer i = 0; i < faces_to_merge.getNumber(); ++i) {
905 Faces2DMerger(swap_utils,
906 cell1.face(faces_to_merge.cell1FaceNumber(i)),
907 cell2.face(faces_to_merge.cell2FaceNumber(i)));
908 }
909
910 // Face exchange.
911 swap_utils->swapCellFaces(cell1, cell2,
912 common_face.cell1LocalNumber(),
913 (common_face.cell2LocalNumber() + 2) % 4); // opposite face
914
915 // cell vertex exchange
916 for (Integer i = 0, n = m_cell_1_common_node_numbers.size(); i < n; ++i) {
917 swap_utils->swapCellNodes(cell1, cell2,
920 }
921
922 swap_utils->checkAndChangeFaceOrientation(cell1);
923}
924
925/*---------------------------------------------------------------------------*/
926/*---------------------------------------------------------------------------*/
927
928const Integer CellToQuadrilateralMerger::m_quad_node_neighbors[4][2] = { { 1, 3 }, { 0, 2 }, { 1, 3 }, { 0, 2 } };
929
930/*---------------------------------------------------------------------------*/
931/*---------------------------------------------------------------------------*/
932
966
967/*---------------------------------------------------------------------------*/
968/*---------------------------------------------------------------------------*/
969
971_setCellsNodeNumbers(Cell cell1, Cell cell2)
972{
973 typedef std::map<Integer, Integer> LocalIDToLocalNumber;
974 LocalIDToLocalNumber cell1_node_localId;
975 LocalIDToLocalNumber cell2_node_localId;
976
977 // We associate the numbers (in the cell) of the nodes with their
978 // localId. These lists are sorted by localId!
979 {
980 // first for cell 1
981 Integer n = 0;
982 for (NodeEnumerator i_node(cell1.nodes()); i_node(); ++i_node) {
983 cell1_node_localId[i_node->localId()] = n++;
984 }
985 }
986 {
987 // then for cell 2
988 Integer n = 0;
989 for (NodeEnumerator i_node(cell2.nodes()); i_node(); ++i_node) {
990 cell2_node_localId[i_node->localId()] = n++;
991 }
992 }
993
994 // We then determine the set of common nodes between the two
995 // cells
996 std::set<Integer> cell2_common_edge_node_number;
997 for (LocalIDToLocalNumber::const_iterator
998 i = cell1_node_localId.begin(),
999 j = cell2_node_localId.begin();
1000 i != cell1_node_localId.end() && j != cell2_node_localId.end();) {
1001 Integer node1_localId = i->first;
1002 Integer node2_localId = j->first;
1003 if (node1_localId == node2_localId) { // if the nodes are the same
1004 // we store the numbers in the meshes of these vertices
1005 m_cell_1_common_node_numbers.add(i->second); // for cell 1
1006 m_cell_2_common_node_numbers.add(j->second); // for cell 2
1007
1008 // and we create the ordered set of common nodes in the
1009 // second cell
1010 cell2_common_edge_node_number.insert(j->second);
1011 ++i;
1012 ++j;
1013 }
1014 else {
1015 if (node1_localId < node2_localId) {
1016 ++i;
1017 }
1018 else {
1019 ++j;
1020 }
1021 }
1022 }
1023
1024 ARCANE_ASSERT(m_cell_1_common_node_numbers.size() == 4,
1025 ("Bad number of shared vertices"));
1026
1027 // We are now looking for the neighbors of the common nodes
1028 // belonging to the second cell and which are not exchanged vertices.
1029 // These are the vertices that will form the new cell
1030 // by substitution with the common vertices of the first cell.
1032 for (Integer i = 0; i < m_cell_2_common_node_numbers.size(); ++i) {
1033 const Integer& node_number = m_cell_2_common_node_numbers[i];
1034 for (Integer j = 0; j < 3; ++j) {
1035 const Integer& edge_node = m_hexa_node_neighbors[node_number][j];
1036 if (cell2_common_edge_node_number.find(edge_node) == cell2_common_edge_node_number.end()) {
1037 m_cell_2_exchanged_node_numbers.add(edge_node);
1038 break;
1039 }
1040 }
1041 }
1042}
1043
1044/*---------------------------------------------------------------------------*/
1045/*---------------------------------------------------------------------------*/
1046
1048CellToHexahedronMerger(ItemSwapperUtils* swap_utils, Cell cell1, Cell cell2)
1049{
1050 // TODO: merge this code with CellToQuadrilateralMerger.
1051
1052 ARCANE_ASSERT(cell2.type() == IT_Hexaedron8, ("Cell2 is not a IT_Hexaedron8"));
1053
1054 CommonFaceFinder common_face(cell1, cell2);
1055
1056 this->_setCellsNodeNumbers(cell1, cell2);
1057
1058 // Fusion of side cells
1059 FacesToMergeFinder faces_to_merge(cell1, cell2, common_face);
1060 for (Integer i = 0; i < faces_to_merge.getNumber(); ++i) {
1061 FaceToQuadrilateralMerger(swap_utils,
1062 cell1.face(faces_to_merge.cell1FaceNumber(i)),
1063 cell2.face(faces_to_merge.cell2FaceNumber(i)));
1064 }
1065
1066 // Face exchange.
1067 swap_utils->swapCellFaces(cell1, cell2,
1068 common_face.cell1LocalNumber(),
1069 (common_face.cell2LocalNumber() + 3) % 6); // opposite face
1070
1071 // Cell vertex exchange
1072 for (Integer i = 0, n = m_cell_1_common_node_numbers.size(); i < n; ++i) {
1073 swap_utils->swapCellNodes(cell1, cell2,
1076 }
1077
1078 swap_utils->checkAndChangeFaceOrientation(cell1);
1079}
1080
1081/*---------------------------------------------------------------------------*/
1082/*---------------------------------------------------------------------------*/
1083
1084const Integer
1086m_hexa_node_neighbors[8][3] = { { 1, 3, 4 }, { 0, 2, 5 }, { 1, 3, 6 }, { 0, 2, 7 }, { 0, 5, 7 }, { 1, 4, 6 }, { 2, 5, 7 }, { 3, 4, 6 } };
1087
1088/*---------------------------------------------------------------------------*/
1089/*---------------------------------------------------------------------------*/
1090
1092_typeName(const CellMerger::_Type& t) const
1093{
1094 switch (t) {
1095 case Hexahedron:
1096 return "hexahedron";
1097 case Pyramid:
1098 return "pyramid";
1099 case Pentahedron:
1100 return "pentahedron";
1101 case Quadrilateral:
1102 return "quadrangle";
1103 case Triangle:
1104 return "triangle";
1105 default:
1106 return "unknown";
1107 }
1108}
1109
1110/*---------------------------------------------------------------------------*/
1111/*---------------------------------------------------------------------------*/
1112
1114_getCellType(const Integer& internal_cell_type) const
1115{
1116 switch (internal_cell_type) {
1117 case IT_Hexaedron8: {
1118 return Hexahedron;
1119 }
1120 case IT_Pyramid5: {
1121 return Pyramid;
1122 }
1123 case IT_Pentaedron6: {
1124 return Pentahedron;
1125 }
1126 case IT_Quad4: {
1127 return Quadrilateral;
1128 }
1129 case IT_Triangle3: {
1130 return Triangle;
1131 }
1132 default: {
1133 return NotMergeable;
1134 }
1135 }
1136}
1137
1138/*---------------------------------------------------------------------------*/
1139/*---------------------------------------------------------------------------*/
1140
1142_promoteType(const _Type& t1, const _Type& t2) const
1143{
1144 switch (t1 * t2) {
1145 case 1:
1146 return Hexahedron;
1147 case 2:
1148 return Pyramid;
1149 case 3:
1150 return Pentahedron;
1151 case 100:
1152 return Quadrilateral;
1153 case 110:
1154 return Triangle;
1155 default:
1156 ARCANE_FATAL("Can not merge cells of type {0} and {1}", _typeName(t1), _typeName(t2));
1157 }
1158}
1159
1160/*---------------------------------------------------------------------------*/
1161/*---------------------------------------------------------------------------*/
1162
1164merge(Cell i_cell_1, Cell i_cell_2)
1165{
1166 _Type cell_1_type = _getCellType(i_cell_1.type());
1167 IMesh* mesh = i_cell_1.itemFamily()->mesh();
1168 ItemSwapperUtils swap_utils(mesh);
1169
1170 switch (cell_1_type) {
1171 case Hexahedron:
1172 case Pyramid:
1173 case Pentahedron: {
1174 CellToHexahedronMerger(&swap_utils, i_cell_1, i_cell_2);
1175 return;
1176 }
1177 case Quadrilateral:
1178 case Triangle: {
1179 {
1180 CellToQuadrilateralMerger(&swap_utils, i_cell_1, i_cell_2);
1181 return;
1182 }
1183 }
1184 case NotMergeable: {
1185 ARCANE_FATAL("Impossible to merge the entities !\n");
1186 }
1187 }
1188 ARCANE_FATAL("Merge for this kind of cell not implemented\n");
1189}
1190
1191/*---------------------------------------------------------------------------*/
1192/*---------------------------------------------------------------------------*/
1193
1195getCell(Cell i_cell_1, Cell i_cell_2)
1196{
1197 _Type cell_1_type = _getCellType(i_cell_1.type());
1198 _Type cell_2_type = _getCellType(i_cell_2.type());
1199
1200 _Type merged_cell_type = _promoteType(cell_1_type, cell_2_type);
1201
1202 switch (merged_cell_type) {
1203 case Hexahedron: {
1204 return i_cell_1;
1205 }
1206 case Pyramid:
1207 case Pentahedron: {
1208 if (cell_2_type == Hexahedron) {
1209 return i_cell_1;
1210 }
1211 else {
1212 return i_cell_2;
1213 }
1214 }
1215 case Quadrilateral: {
1216 return i_cell_1;
1217 }
1218 case Triangle: {
1219 if (cell_2_type == Quadrilateral) {
1220 return i_cell_1;
1221 }
1222 else {
1223 return i_cell_2;
1224 }
1225 }
1226 case NotMergeable: {
1227 ARCANE_FATAL("Impossible to merge the entities !\n");
1228 }
1229 default:
1230 ARCANE_FATAL("Merge for this kind of cell not implemented\n");
1231 }
1232 return 0;
1233}
1234
1235/*---------------------------------------------------------------------------*/
1236/*---------------------------------------------------------------------------*/
1237
1239getItemInternal(ItemInternal* i_cell_1, ItemInternal* i_cell_2)
1240{
1241 return ItemCompatibility::_itemInternal(getCell(i_cell_1, i_cell_2));
1242}
1243
1244/*---------------------------------------------------------------------------*/
1245/*---------------------------------------------------------------------------*/
1246
1247} // End namespace Arcane::mesh
1248
1249/*---------------------------------------------------------------------------*/
1250/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Types and macros for iterating over mesh entities.
void add(ConstReferenceType val)
Adds element val to the end of the array.
void reserve(Int64 new_capacity)
Reserves memory for new_capacity elements.
Cell of a mesh.
Definition Item.h:1300
FaceConnectedListViewType faces() const
List of faces of the cell.
Definition Item.h:1403
Face face(Int32 i) const
i-th face of the cell
Definition Item.h:1400
Int32 nbFace() const
Number of faces of the cell.
Definition Item.h:1397
ARCANE_DEPRECATED_260 void checkAndChangeOrientation(ItemInternal *face)
Face of a cell.
Definition Item.h:1032
virtual IMesh * mesh() const =0
Associated mesh.
Enumerator over a list of entities.
Internal structure of a mesh entity.
Node node(Int32 i) const
i-th node of the entity
Definition Item.h:840
NodeConnectedListViewType nodes() const
List of nodes of the entity.
Definition Item.h:843
IItemFamily * itemFamily() const
Family from which the entity originates.
Definition Item.h:261
Int16 type() const
Entity type.
Definition Item.h:255
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
_Type _getCellType(const Integer &internal_cell_type) const
Determines the cell _Type based on its "ItemInternal" type.
String _typeName(const _Type &t) const
Returns the name associated with the cell type.
void merge(Cell i_cell_1, Cell i_cell_2)
Merges the two cells i_cell_1 and i_cell_2.
ItemInternal * getItemInternal(ItemInternal *i_cell_1, ItemInternal *i_cell_2)
Returns the ItemInternal used by the cell after merging.
_Type _promoteType(const _Type &t1, const _Type &t2) const
Determines the cell type resulting from the merging of two given types.
Cell getCell(Cell i_cell_1, Cell i_cell_2)
Returns the cell used by the cell after merging.
This function-class aims to merge two cells where the second one is necessarily a hexahedron.
void _setCellsNodeNumbers(Cell cell1, Cell cell2)
static const Integer m_hexa_node_neighbors[8][3]
IntegerUniqueArray m_cell_2_exchanged_node_numbers
IntegerUniqueArray m_cell_1_common_node_numbers
IntegerUniqueArray m_cell_2_common_node_numbers
CellToHexahedronMerger(ItemSwapperUtils *swap_utils, Cell cell1, Cell cell2)
static const Integer m_quad_node_neighbors[4][2]
List of neighboring nodes by edge in a quadrangle.
void _setCellsNodeNumbers(Cell i_cell_1, Cell i_cell_2)
IntegerUniqueArray m_cell_2_exchanged_node_numbers
Numbers in cell 2 of the vertices that will define the merged cell.
IntegerUniqueArray m_cell_2_common_node_numbers
Numbers in cell 2 of the common vertices with cell 1.
CellToQuadrilateralMerger(ItemSwapperUtils *swap_utils, Cell cell1, Cell cell2)
IntegerUniqueArray m_cell_1_common_node_numbers
Numbers in cell 1 of the common vertices with cell 2.
Finds the common face between two cells.
Integer m_cell_2_local_number
Number of the common face in cell 2.
Integer m_cell_1_local_number
Number of the common face in cell 1.
CommonFaceFinder(Cell i_cell_1, Cell i_cell_2)
const NodesLIDSet & nodesLID() const
Set of localIds of common nodes.
This function-class aims to merge two faces, where the second is necessarily a quadrangle.
IntegerUniqueArray m_face_2_exchanged_node_numbers
IntegerUniqueArray m_face_2_common_node_numbers
bool _setFacesNodeNumbers(Face i_face_1, Face i_face_2)
static const Integer m_quad_node_neighbors[4][2]
IntegerUniqueArray m_face_1_common_node_numbers
FaceToQuadrilateralMerger(ItemSwapperUtils *swap_utils, Face face1, Face face2)
Merges two faces in 2D (in fact, two edges).
void _setFacesNodeNumbers(Face i_face_1, Face i_face_2)
Faces2DMerger(ItemSwapperUtils *swap_utils, Face i_face_1, Face i_face_2)
In dimension 2, finds common faces between two cells (The faces are actually edges).
Integer cell1FaceNumber(Integer i) const
Integer cell2FaceNumber(Integer i) const
IntegerUniqueArray m_cell1_edge_face_list
void _setEdgeFaceList(Cell i_cell, IntegerArray &edge_face_list, Integer common_face_number, const CommonFaceFinder::NodesLIDSet &common_face_nodes)
Faces2DToMergeFinder(Cell cell1, Cell cell2, const CommonFaceFinder &common_face)
This function-class searches for faces to merge when merging two cells.
Integer cell1FaceNumber(Integer i) const
Integer cell2FaceNumber(Integer i) const
IntegerUniqueArray m_cell1_edge_face_list
void _setEdgeFaceList(Cell i_cell, IntegerArray &edge_face_list, Integer common_face_number, const CommonFaceFinder::NodesLIDSet &common_face_nodes)
FacesToMergeFinder(Cell cell1, Cell cell2, const CommonFaceFinder &common_face)
Utility class for swapping entities between two entities.
Definition CellMerger.cc:46
void swapFaceNodes(Face face_1, Face face_2, Integer face1_node_idx, Integer face2_node_idx)
Swaps two nodes between two faces.
Definition CellMerger.cc:66
void swapCellFaces(Cell cell1, Cell cell2, Integer cell1_face_idx, Integer cell2_face_idx)
Swaps two faces between two cells.
void swapCellNodes(Cell cell1, Cell cell2, Integer cell1_node_idx, Integer cell2_node_idx)
Swaps two nodes between two cells.
Definition CellMerger.cc:85
ItemEnumeratorT< Node > NodeEnumerator
Enumerators over nodes.
Definition ItemTypes.h:255
ItemEnumeratorT< Face > FaceEnumerator
Enumerators over faces.
Definition ItemTypes.h:266
Int32 Integer
Type representing an integer.
Array< Integer > IntegerArray
Dynamic one-dimensional array of integers.
Definition UtilsTypes.h:133
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
Definition UtilsTypes.h:347
std::int32_t Int32
Signed integer type of 32 bits.