NEMoSys  0.63.0
A modular, extensible resource with robust automated mesh generation, mesh quality analysis, adaptive mesh refinement, and data transfer between arbitrary meshes.
smeshGeoMesh.C
Go to the documentation of this file.
1 /*******************************************************************************
2 * Promesh *
3 * Copyright (C) 2022, IllinoisRocstar LLC. All rights reserved. *
4 * *
5 * Promesh is the property of IllinoisRocstar LLC. *
6 * *
7 * IllinoisRocstar LLC *
8 * Champaign, IL *
9 * www.illinoisrocstar.com *
10 * promesh@illinoisrocstar.com *
11 *******************************************************************************/
12 /*******************************************************************************
13 * This file is part of Promesh *
14 * *
15 * This version of Promesh is free software: you can redistribute it and/or *
16 * modify it under the terms of the GNU Lesser General Public License as *
17 * published by the Free Software Foundation, either version 3 of the License, *
18 * or (at your option) any later version. *
19 * *
20 * Promesh is distributed in the hope that it will be useful, but WITHOUT ANY *
21 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more *
23 * details. *
24 * *
25 * You should have received a copy of the GNU Lesser General Public License *
26 * along with this program. If not, see <https://www.gnu.org/licenses/>. *
27 * *
28 *******************************************************************************/
29 #include "Mesh/smeshGeoMesh.H"
30 
31 #include <algorithm>
32 #include <array>
33 #include <cassert>
34 
35 #include <SMESH_Gen.hxx>
36 #include <SMESH_Group.hxx>
37 #include <SMESH_Mesh.hxx>
38 #include <SMESHDS_Group.hxx>
39 #include <SMESHDS_Mesh.hxx>
40 
41 #include <vtkCellIterator.h>
42 #include <vtkCellType.h>
43 #include <vtkDataSet.h>
44 #include <vtkStringArray.h>
45 #include <vtkUnstructuredGrid.h>
46 
47 #include "Mesh/smeshUtils.H"
48 
49 namespace {
50 
51 void insertWithGroup(const std::vector<SMDS_MeshNode *> &smdsNodes,
52  SMESHDS_Mesh *meshDS, SMESH_Mesh &outMesh,
53  vtkDataSet *dataset, vtkDataArray *entArr,
54  vtkStringArray *groupNames) {
55  std::vector<vtkIdType> pointIdBuffer;
56  std::map<int, SMESH_Group *> groups;
57  for (auto cellIter =
58  vtkSmartPointer<vtkCellIterator>::Take(dataset->NewCellIterator());
59  !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell()) {
60  pointIdBuffer.clear();
61  auto vtkPointIds = cellIter->GetPointIds();
62  auto cellDim = cellIter->GetCellDimension();
63  SMDS_MeshCell *outCell;
64  if (cellDim == 0) {
65  outCell = meshDS->Add0DElement(smdsNodes[vtkPointIds->GetId(0)]);
66  } else if (cellDim == 1) {
67  auto cellType = cellIter->GetCellType();
68  if (cellType == VTK_LINE) {
69  outCell = meshDS->AddEdge(smdsNodes[vtkPointIds->GetId(0)],
70  smdsNodes[vtkPointIds->GetId(1)]);
71  } else if (cellType == VTK_QUADRATIC_EDGE) {
72  outCell = meshDS->AddEdge(smdsNodes[vtkPointIds->GetId(0)],
73  smdsNodes[vtkPointIds->GetId(1)],
74  smdsNodes[vtkPointIds->GetId(2)]);
75  }
76  } else if (cellDim == 2 || cellDim == 3) {
77  for (int i = 0; i < vtkPointIds->GetNumberOfIds(); ++i) {
78  pointIdBuffer.emplace_back(
79  smdsNodes[vtkPointIds->GetId(i)]->GetVtkID());
80  }
81  if (cellDim == 2) {
82  outCell = meshDS->AddFaceFromVtkIds(pointIdBuffer);
83  } else {
84  assert(cellDim == 3);
85  outCell = meshDS->AddVolumeFromVtkIds(pointIdBuffer);
86  }
87  }
88  if (!outCell) {
89  std::cerr << "Failed to add cell with vtk type "
90  << cellIter->GetCellType() << '\n';
91  }
92  if (entArr) {
93  auto gmGroupId =
94  static_cast<int>(entArr->GetComponent(cellIter->GetCellId(), 0));
95  auto &group = groups[gmGroupId];
96  if (!group) {
97  std::string groupName;
98  if (groupNames && gmGroupId >= 0 &&
99  gmGroupId < groupNames->GetNumberOfValues()) {
100  groupName = groupNames->GetValue(gmGroupId);
101  }
102  if (groupName.empty()) {
103  groupName = "Group " + std::to_string(gmGroupId);
104  }
105  group = outMesh.AddGroup(SMDSAbs_All, groupName.c_str());
106  }
107  if (auto manualGroup =
108  dynamic_cast<SMESHDS_Group *>(group->GetGroupDS())) {
109  manualGroup->Add(outCell);
110  }
111  }
112  }
113 }
114 
115 } // namespace
116 
117 namespace NEM {
118 namespace MSH {
119 
121 
123  : geoMeshBase(), gen_{new SMESH_Gen{}}, mesh_(gen_->CreateMesh(false)) {}
124 
125 // Not in header so we can forward declare SMESH_Mesh and SMESH_Gen
126 smeshGeoMesh::~smeshGeoMesh() = default;
127 
128 void smeshGeoMesh::write(const std::string &fileName) {
129  std::cerr << "Currently unsupported.\n";
130 }
131 
132 void smeshGeoMesh::report(std::ostream &out) const { geoMeshBase::report(out); }
133 
135  // Careful! Delete mesh before deleting gen!
136  mesh_.reset();
137  gen_.reset(new SMESH_Gen{});
138  mesh_.reset(gen_->CreateMesh(false));
140 }
141 
142 void smeshGeoMesh::setSMeshMesh(std::unique_ptr<SMESH_Mesh> &&mesh,
143  std::shared_ptr<SMESH_Gen> gen) {
144  mesh_ = std::move(mesh);
145  gen_ = std::move(gen);
147 }
148 
149 const SMESH_Mesh &smeshGeoMesh::getSMESHMesh() const { return *mesh_; }
150 
151 void smeshGeoMesh::GMToSMESH(const GeoMesh &geoMesh, SMESH_Mesh &outMesh) {
152  auto grid = geoMesh.mesh;
153  if (grid->GetNumberOfCells() == 0) { return; }
154  auto linkArr = grid->GetCellData()->GetArray(geoMesh.link.c_str());
155  auto points = grid->GetPoints();
156  auto meshDS = outMesh.GetMeshDS();
157  std::vector<SMDS_MeshNode *> smdsNodes; // indexed by geoMesh id
158  smdsNodes.reserve(points->GetNumberOfPoints());
159  {
160  std::array<double, 3> pointBuffer{};
161  for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i) {
162  grid->GetPoint(i, pointBuffer.data());
163  smdsNodes.emplace_back(
164  meshDS->AddNode(pointBuffer[0], pointBuffer[1], pointBuffer[2]));
165  }
166  }
167  insertWithGroup(smdsNodes, meshDS, outMesh, grid, linkArr,
168  vtkStringArray::SafeDownCast(
169  grid->GetFieldData()->GetArray("Group Names")));
170  insertWithGroup(smdsNodes, meshDS, outMesh, geoMesh.sideSet.sides,
171  geoMesh.sideSet.getGeoEntArr(),
172  geoMesh.sideSet.getSideSetNames());
173 }
174 
175 // Note not hardened to support cells belonging to multiple groups
177  vtkNew<vtkUnstructuredGrid> gmGrid;
178  vtkNew<vtkPolyData> sideSetSides;
179  int numGMCells;
180  int maxDim;
181  if ((numGMCells = mesh.NbVolumes()) > 0) {
182  maxDim = 3;
183  } else if ((numGMCells = mesh.NbFaces()) > 0) {
184  maxDim = 2;
185  } else if ((numGMCells = mesh.NbEdges()) > 0) {
186  maxDim = 1;
187  } else {
188  return {gmGrid, {}, {}, {}};
189  }
190  auto smeshGrid = mesh.GetMeshDS()->GetGrid();
191  gmGrid->Allocate(numGMCells);
192  gmGrid->SetPoints(smeshGrid->GetPoints());
193  sideSetSides->Allocate();
194  sideSetSides->SetPoints(smeshGrid->GetPoints());
195  vtkNew<vtkStringArray> groupNamesGrid;
196  groupNamesGrid->SetName("Group Names");
197  vtkNew<vtkStringArray> groupNamesSides;
198  // indexed by vtkID on mesh.GetMeshDS()->GetGrid()
199  std::vector<int> groups(smeshGrid->GetNumberOfCells(), -1);
200  for (auto group : NEM::MSH::containerWrapper(mesh.GetGroups())) {
201  auto groupId = group->GetID();
202  if (groupId >= 0) {
203  for (auto elem :
204  NEM::MSH::containerWrapper(group->GetGroupDS()->GetElements())) {
205  auto vtkId = elem->GetVtkID();
206  if (vtkId >= 0) {
207  auto &cellGroup = groups[vtkId];
208  if (cellGroup >= 0) {
209  // For now, the behavior is to choose the "latest" group.
210  std::cerr << "Warning! SMESH Element found on multiple groups. "
211  "Behavior is undefined.\n";
212  }
213  cellGroup = groupId;
214  }
215  }
216  auto elemType = group->GetGroupDS()->GetType();
217  auto groupDim =
218  elemType == SMDSAbs_Volume ? 3
219  : elemType == SMDSAbs_Face ? 2
220  : (elemType == SMDSAbs_Node || elemType == SMDSAbs_0DElement) ? 1
221  : -1;
222  if (groupDim == maxDim || groupDim == -1) {
223  groupNamesGrid->InsertValue(groupId, group->GetName());
224  }
225  if (groupDim == maxDim - 1 || groupDim == -1) {
226  groupNamesSides->InsertValue(groupId, group->GetName());
227  }
228  }
229  }
230  vtkNew<vtkIntArray> groupsArr;
231  groupsArr->SetName("GeoEnt");
232  groupsArr->SetNumberOfComponents(1);
233  groupsArr->SetNumberOfTuples(numGMCells);
234  groupsArr->FillComponent(0, -1);
235  vtkNew<vtkIntArray> sideSetEntArr;
236  bool geoMeshHasLink;
237  for (auto cellIter =
238  vtkSmartPointer<vtkCellIterator>::Take(smeshGrid->NewCellIterator());
239  !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell()) {
240  auto cellDim = cellIter->GetCellDimension();
241  if (cellDim == maxDim) {
242  auto gmId = gmGrid->InsertNextCell(cellIter->GetCellType(),
243  cellIter->GetPointIds());
244  auto group = groups[cellIter->GetCellId()];
245  if (group >= 0) {
246  geoMeshHasLink = true;
247  groupsArr->SetComponent(gmId, 0, group);
248  }
249  } else if (cellDim == maxDim - 1) {
250  auto group = groups[cellIter->GetCellId()];
251  if (group >= 0) {
252  sideSetSides->InsertNextCell(cellIter->GetCellType(),
253  cellIter->GetPointIds());
254  sideSetEntArr->InsertNextValue(group);
255  }
256  }
257  }
258  std::string link;
259  if (geoMeshHasLink) {
260  gmGrid->GetCellData()->AddArray(groupsArr);
261  gmGrid->GetFieldData()->AddArray(groupNamesGrid);
262  link = groupsArr->GetName();
263  }
264  return {gmGrid,
265  {},
266  std::move(link),
267  sideSetSides->GetNumberOfCells() > 0
268  ? SideSet(sideSetSides, sideSetEntArr, nullptr, nullptr,
269  groupNamesSides)
270  : SideSet{}};
271 }
272 
273 } // namespace MSH
274 } // namespace NEM
static void GMToSMESH(const GeoMesh &geoMesh, SMESH_Mesh &outMesh)
Definition: smeshGeoMesh.C:151
virtual void report(std::ostream &out) const =0
Print a report about the mesh.
Definition: geoMeshBase.C:97
int maxDim
Definition: inpGeoMesh.C:135
vtkSmartPointer< vtkUnstructuredGrid > mesh
Definition: geoMeshBase.H:419
static GeoMesh SmeshToGM(SMESH_Mesh &mesh)
Definition: smeshGeoMesh.C:176
void resetNative() override
Definition: smeshGeoMesh.C:134
void setGeoMesh(const geoMeshBase::GeoMesh &geoMesh)
Set the underlying geometry object.
Definition: geoMeshBase.H:538
void setSMeshMesh(std::unique_ptr< SMESH_Mesh > &&mesh, std::shared_ptr< SMESH_Gen > gen)
Definition: smeshGeoMesh.C:142
VTKCellType cellType
Definition: inpGeoMesh.C:129
vtkSmartPointer< vtkPolyData > sides
Cells represent edges/faces of some GeoMesh.
Definition: geoMeshBase.H:399
std::shared_ptr< meshBase > mesh
SM_StdContainerWrapperFromIter< typename std::decay< PtrSMDSIterator >::type, VALUE, EqualVALUE > containerWrapper(PtrSMDSIterator &&iter)
Definition: smeshUtils.H:57
std::vector< vtkIdType > points
points given by id in .inp file
Definition: inpGeoMesh.C:133
vtkSmartPointer< vtkIntArray > getGeoEntArr() const
Definition: geoMeshBase.C:252
vtkStandardNewMacro(exoGeoMesh)
Definition: exoGeoMesh.C:247
mesh_(gen_->CreateMesh(false))
Definition: smeshGeoMesh.C:123
std::unique_ptr< SMESH_Mesh > mesh_
Definition: smeshGeoMesh.H:64
std::shared_ptr< SMESH_Gen > gen_
Definition: smeshGeoMesh.H:63
virtual void write(const std::string &fileName)=0
Write mesh to file.
const SMESH_Mesh & getSMESHMesh() const
Definition: smeshGeoMesh.C:149
abstract class to specify geometry and mesh data
Definition: geoMeshBase.H:102
vtkSmartPointer< vtkStringArray > getSideSetNames() const
Definition: geoMeshBase.C:298
const GeoMesh & getGeoMesh() const
Get the underlying geometry object.
Definition: geoMeshBase.H:533