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.
meshBase.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/meshBase.H"
30 
31 #include <exodusII.h>
32 #include <vtkAppendFilter.h>
33 #include <vtkCell.h>
34 #include <vtkCellData.h>
35 #include <vtkCellTypes.h>
36 #include <vtkDataArray.h>
37 #include <vtkDataSetTriangleFilter.h>
38 #include <vtkExtractSelection.h>
39 #include <vtkGenericCell.h>
40 #include <vtkIdList.h>
41 #include <vtkIntArray.h>
42 #include <vtkPointData.h>
43 #include <vtkPoints.h>
44 #include <vtkSelection.h>
45 #include <vtkSelectionNode.h>
46 #include <vtkUnstructuredGrid.h>
47 
48 //#include "Mesh/cobalt.H"
49 //#include "Mesh/patran.H"
50 #include "AuxiliaryFunctions.H"
51 #include "Integration/Cubature.H"
54 #include "Mesh/exoMesh.H"
55 #include "MeshGeneration/meshGen.H"
57 #include "Mesh/pntMesh.H"
58 #include "Mesh/vtkMesh.H"
59 
60 #ifdef HAVE_GMSH
61 #include "Refinement/Refine.H"
62 #endif
63 
64 // netgen
65 #ifdef HAVE_NGEN
66 namespace nglib {
67 # include <nglib.h>
68 }
69 #endif
70 
71 // TODO: Stop using setPoint/CellDataArray in export methods
72 // - instead, use the faster vtkDataArray creation and insertion
73 /** This method calls the other factory methods based on extension.
74 
75  Caller must delete object after use.
76 **/
77 
78 meshBase *meshBase::Create(const std::string &fname) {
79  if (fname.find(".vt") != std::string::npos ||
80  fname.find(".stl") != std::string::npos) {
81  auto *vtkmesh = new vtkMesh(fname);
82  vtkmesh->setFileName(fname);
83  return vtkmesh;
84  } else if (fname.find(".msh") != std::string::npos) {
85  std::cout << "Detected file in GMSH format" << std::endl;
86  std::cout << "Exporting to VTK ...." << std::endl;
87  return exportGmshToVtk(fname);
88  } else if (fname.find(".vol") != std::string::npos) {
89  std::cout << "Detected file in Netgen .vol format" << std::endl;
90  std::cout << "Exporting to VTK ...." << std::endl;
91  return exportVolToVtk(fname);
92  } else if (fname.find(".pntmesh") != std::string::npos) {
93  std::cout << "Detected file in PNTmesh format" << std::endl;
94  std::cout << "Processing the file ...." << std::endl;
95  return exportPntToVtk(fname);
96  } else if (fname.find(".g") != std::string::npos ||
97  fname.find(".exo") != std::string::npos ||
98  fname.find(".e") != std::string::npos) {
99  std::cout << "Detected file in Exodus II format" << std::endl;
100  std::cout << "Processing the file ...." << std::endl;
101  return exportExoToVtk(fname);
102  } else {
103  std::cout << "mesh files with extension "
104  << fname.substr(fname.find_last_of('.')) << " are not supported!"
105  << std::endl;
106  exit(1);
107  }
108 }
109 
110 /** Caller must delete object after use.
111  **/
112 meshBase *meshBase::Create(vtkSmartPointer<vtkDataSet> other,
113  const std::string &newname) {
114  return new vtkMesh(other, newname);
115 }
116 
117 /** Use of this is only valid when mesh has one cell type.
118  Caller must delete object after use.
119 **/
120 meshBase *meshBase::Create(const std::vector<double> &xCrds,
121  const std::vector<double> &yCrds,
122  const std::vector<double> &zCrds,
123  const std::vector<nemId_t> &elmConn,
124  const int cellType, const std::string &newname) {
125  return new vtkMesh(xCrds, yCrds, zCrds, elmConn, cellType, newname);
126 }
127 
128 /** Memory is managed by shared pointer, so do not call delete after use.
129  **/
130 std::unique_ptr<meshBase> meshBase::CreateUnique(
131  const std::vector<double> &xCrds, const std::vector<double> &yCrds,
132  const std::vector<double> &zCrds, const std::vector<nemId_t> &elmConn,
133  const int cellType, const std::string &newname) {
134  return std::unique_ptr<meshBase>(
135  meshBase::Create(xCrds, yCrds, zCrds, elmConn, cellType, newname));
136 }
137 
138 /** Memory is managed by shared pointer, so do not call delete after use.
139  **/
140 std::unique_ptr<meshBase> meshBase::CreateUnique(
141  vtkSmartPointer<vtkDataSet> other, const std::string &newname) {
142  return std::unique_ptr<meshBase>(meshBase::Create(other, newname));
143 }
144 
145 /** Memory is managed by shared pointer, so do not call delete after use.
146  **/
147 std::unique_ptr<meshBase> meshBase::CreateUnique(meshBase *mesh) {
148  return std::unique_ptr<meshBase>(mesh);
149 }
150 
151 /** Memory is managed by shared pointer, so do not call delete after use.
152  (be careful with this one!)
153 **/
154 std::shared_ptr<meshBase> meshBase::CreateShared(meshBase *mesh) {
155  std::shared_ptr<meshBase> sharedMesh;
156  sharedMesh.reset(mesh);
157  return sharedMesh;
158 }
159 
160 /** Memory is managed by shared pointer, so do not call delete after use.
161  **/
162 std::shared_ptr<meshBase> meshBase::CreateShared(
163  vtkSmartPointer<vtkDataSet> other, const std::string &newname) {
164  std::shared_ptr<meshBase> mesh;
165  mesh.reset(meshBase::Create(other, newname));
166  return mesh;
167 }
168 
169 /** Memory is managed by shared pointer, so do not call delete after use.
170  **/
171 std::shared_ptr<meshBase> meshBase::CreateShared(const std::string &fname) {
172  std::shared_ptr<meshBase> mesh;
173  mesh.reset(meshBase::Create(fname));
174  return mesh;
175 }
176 
177 /** Memory is managed by shared pointer, so do not call delete after use.
178  **/
179 std::shared_ptr<meshBase> meshBase::CreateShared(
180  const std::vector<double> &xCrds, const std::vector<double> &yCrds,
181  const std::vector<double> &zCrds, const std::vector<nemId_t> &elmConn,
182  const int cellType, const std::string &newname) {
183  std::shared_ptr<meshBase> mesh;
184  mesh.reset(meshBase::Create(xCrds, yCrds, zCrds, elmConn, cellType, newname));
185  return mesh;
186 }
187 
188 /** Memory is managed by shared pointer, so do not call delete after use.
189  **/
190 std::unique_ptr<meshBase> meshBase::CreateUnique(const std::string &fname) {
191  return std::unique_ptr<meshBase>(meshBase::Create(fname));
192 }
193 
194 /** Caller must delete object after use.
195  **/
196 meshBase *meshBase::stitchMB(const std::vector<meshBase *> &mbObjs) {
197  if (!mbObjs.empty()) {
198  vtkSmartPointer<vtkAppendFilter> appender =
200  appender->MergePointsOn();
201  for (int i = 0; i < mbObjs.size(); ++i) {
202  appender->AddInputData(mbObjs[i]->getDataSet());
203  }
204  appender->Update();
205  return meshBase::Create(appender->GetOutput(), "stitched.vtu");
206  } else {
207  std::cerr << "Nothing to stitch!" << std::endl;
208  exit(1);
209  }
210 }
211 
212 /** This is the shared pointer version of stitchMB. Memory is managed by shared
213  pointer, so do not call delete after use.
214 **/
215 std::shared_ptr<meshBase> meshBase::stitchMB(
216  const std::vector<std::shared_ptr<meshBase>> &_mbObjs) {
217  std::vector<meshBase *> mbObjs(_mbObjs.size());
218  for (int i = 0; i < mbObjs.size(); ++i) {
219  mbObjs[i] = _mbObjs[i].get();
220  }
222 }
223 
224 /**
225  **/
227  const std::vector<nemId_t> &cellIds) {
228  vtkSmartPointer<vtkIdTypeArray> selectionIds =
230  selectionIds->SetNumberOfComponents(1);
231  for (const auto &cellId : cellIds) {
232  selectionIds->InsertNextValue(cellId);
233  }
234  return extractSelectedCells(mesh->getDataSet(), selectionIds);
235 }
236 
237 /**
238  **/
240  vtkSmartPointer<vtkDataSet> mesh, vtkSmartPointer<vtkIdTypeArray> cellIds) {
241  vtkSmartPointer<vtkSelectionNode> selectionNode =
243  selectionNode->SetFieldType(vtkSelectionNode::CELL);
244  selectionNode->SetContentType(vtkSelectionNode::INDICES);
245  selectionNode->SetSelectionList(cellIds);
246  // create the selection
247  vtkSmartPointer<vtkSelection> selection =
249  selection->AddNode(selectionNode);
250  // creating extractor
251  vtkSmartPointer<vtkExtractSelection> extractSelection =
253  // set stitch surf as input on first port
254  extractSelection->SetInputData(0, mesh);
255  // set selectionNode as input on second port
256  extractSelection->SetInputData(1, selection);
257  extractSelection->Update();
258  vtkSmartPointer<vtkDataSet> extractedCellMesh =
259  vtkDataSet::SafeDownCast(extractSelection->GetOutput());
260  meshBase *selectedCellMesh =
261  meshBase::Create(extractedCellMesh, "extracted.vtu");
262  return selectedCellMesh;
263 }
264 
265 /** check for named array in vtk
266  **/
267 int meshBase::IsArrayName(const std::string &name,
268  const bool pointOrCell) const {
269  if (!pointOrCell) {
270  vtkPointData *pd = dataSet->GetPointData();
271  if (pd->GetNumberOfArrays()) {
272  for (int i = 0; i < pd->GetNumberOfArrays(); ++i) {
273  if (name == (pd->GetArrayName(i) ? pd->GetArrayName(i) : "NULL")) {
274  return i;
275  }
276  }
277  }
278  } else {
279  vtkCellData *cd = dataSet->GetCellData();
280  if (cd->GetNumberOfArrays()) {
281  for (int i = 0; i < cd->GetNumberOfArrays(); ++i) {
282  if (name == (cd->GetArrayName(i) ? cd->GetArrayName(i) : "Null")) {
283  return i;
284  }
285  }
286  }
287  }
288  return -1;
289 }
290 
291 /** partition mesh into numPartition pieces (static fcn)
292 
293  Memory is managed by shared pointer, so do not call delete after use.
294 **/
295 std::vector<std::shared_ptr<meshBase>> meshBase::partition(
296  const meshBase *mbObj, const int numPartitions) {
297  // construct partitioner with meshBase object
298  auto *mPart = new meshPartitioner(mbObj);
299  if (mPart->partition(numPartitions)) {
300  exit(1);
301  }
302  // initialize vector of meshBase partitions
303  std::vector<std::shared_ptr<meshBase>> mbParts(numPartitions);
304  for (int i = 0; i < numPartitions; ++i) {
305  // define coordinates
306  std::vector<std::vector<double>> comp_crds(mbObj->getVertCrds());
307  // get partition connectivity and zero index it
308  std::vector<int> vtkConn_int(mPart->getConns(i));
309  std::vector<nemId_t> vtkConn(vtkConn_int.begin(), vtkConn_int.end());
310  for (auto &&it : vtkConn) it -= 1;
311 
312  std::string basename(nemAux::trim_fname(mbObj->getFileName(), ""));
313  basename += std::to_string(i);
314  basename += ".vtu";
315  // construct meshBase partition from coordinates and connectivities
316  // from partitioner
317  mbParts[i] = meshBase::CreateShared(
318  mPart->getCrds(i, comp_crds[0]), mPart->getCrds(i, comp_crds[1]),
319  mPart->getCrds(i, comp_crds[2]), vtkConn, VTK_TETRA, basename);
320  // add partition id to node and cell data of mbPart
321  vtkSmartPointer<vtkIntArray> nodePartitionIds =
323  nodePartitionIds->SetName("NodePartitionIds");
324  nodePartitionIds->SetNumberOfComponents(1);
325  nodePartitionIds->SetNumberOfTuples(mbParts[i]->getNumberOfPoints());
326  nodePartitionIds->FillComponent(0, i);
327  mbParts[i]->getDataSet()->GetPointData()->AddArray(nodePartitionIds);
328 
329  vtkSmartPointer<vtkIntArray> cellPartitionIds =
331  cellPartitionIds->SetName("CellPartitionIds");
332  cellPartitionIds->SetNumberOfComponents(1);
333  cellPartitionIds->SetNumberOfTuples(mbParts[i]->getNumberOfCells());
334  cellPartitionIds->FillComponent(0, i);
335  mbParts[i]->getDataSet()->GetCellData()->AddArray(cellPartitionIds);
336 
337  // add global node index array to partition
338  std::map<int, int> partToGlobNodeMap(mPart->getPartToGlobNodeMap(i));
339  vtkSmartPointer<vtkIdTypeArray> globalNodeIds =
341  globalNodeIds->SetName("GlobalNodeIds");
342  globalNodeIds->SetNumberOfComponents(1);
343  globalNodeIds->SetNumberOfTuples(mbParts[i]->getNumberOfPoints());
344  globalNodeIds->SetNumberOfValues(mbParts[i]->getNumberOfPoints());
345  auto it = partToGlobNodeMap.begin();
346  int idx = 0;
347  while (it != partToGlobNodeMap.end()) {
348  int globidx = it->second - 1;
349  int locidx = it->first - 1;
350  globalNodeIds->SetTuple1(idx, globidx);
351  mbParts[i]->globToPartNodeMap[globidx] = locidx;
352  mbParts[i]->partToGlobNodeMap[locidx] = globidx;
353  ++idx;
354  ++it;
355  }
356  mbParts[i]->getDataSet()->GetPointData()->AddArray(globalNodeIds);
357  // add global cell index array to partition
358  std::map<int, int> partToGlobCellMap(mPart->getPartToGlobElmMap(i));
359  // vtkSmartPointer<vtkIdTypeArray> globalCellIds =
360  // vtkSmartPointer<vtkIdTypeArray>::New();
361  // globalCellIds->SetName("GlobalCellIds");
362  // globalCellIds->SetNumberOfComponents(1);
363  // globalCellIds->SetNumberOfTuples(mbPart->getNumberOfCells());
364  // globalCellIds->SetNumberOfValues(mbPart->getNumberOfCells());
365  it = partToGlobCellMap.begin();
366  idx = 0;
367  while (it != partToGlobCellMap.end()) {
368  int globidx = it->second - 1;
369  int locidx = it->first - 1;
370  // globalCellIds->SetTuple1(idx,globidx);
371  mbParts[i]->globToPartCellMap[globidx] = locidx;
372  mbParts[i]->partToGlobCellMap[locidx] = globidx;
373  ++idx;
374  ++it;
375  }
376  // mbPart->getDataSet()->GetCellData()->AddArray(globalCellIds);
377  mbParts[i]->write();
378  // mbParts[i] = mbPart;
379  }
380  delete mPart;
381  mPart = nullptr;
382  return mbParts;
383 }
384 
385 /** integrated data is available per cell as vtk cell data after operation
386  **/
387 std::vector<std::vector<double>> meshBase::integrateOverMesh(
388  const std::vector<int> &arrayIDs) {
389  std::unique_ptr<GaussCubature> cubature =
390  GaussCubature::CreateUnique(dataSet, arrayIDs);
391  return cubature->integrateOverAllCells();
392 }
393 
394 /**
395  **/
396 void meshBase::generateSizeField(const std::string &method, int arrayID,
397  double dev_mult, bool maxIsmin,
398  double sizeFactor, int order) {
399  std::cout << "Size Factor = " << sizeFactor << std::endl;
400  std::unique_ptr<NEM::ADP::SizeFieldBase> sfobj =
401  NEM::ADP::SizeFieldBase::CreateUnique(dataSet, method, arrayID, dev_mult,
402  maxIsmin, sizeFactor, order);
403  sfobj->setSizeFactor(sizeFactor);
404  sfobj->computeSizeField(dataSet->GetPointData()->GetArray(arrayID));
405 }
406 
407 /**
408  **/
409 meshBase *meshBase::exportGmshToVtk(const std::string &fname) {
410  std::ifstream meshStream(fname);
411  if (!meshStream.good()) {
412  std::cout << "Error opening file " << fname << std::endl;
413  exit(1);
414  }
415 
416  bool warning = true;
417 
418  std::string line;
419  int numPoints = 0, numCells = 0, numPhysGrps = 0;
420  bool fndPhyGrp = false;
421  std::vector<int> physGrpDims;
422  std::map<int, std::string> physGrpIdName;
423  std::vector<std::vector<std::vector<double>>> pointData;
424  std::vector<std::vector<std::vector<double>>> cellData;
425  std::vector<std::vector<double>> cellPhysGrpIds;
426  std::vector<std::string> pointDataNames;
427  std::vector<std::string> cellDataNames;
428  std::vector<std::string> fieldDataNames;
429  std::vector<std::string> fieldData;
430 
431  // declare points to be pushed into dataSet_tmp
432  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
433  points->SetDataTypeToDouble();
434  // declare dataSet_tmp which will be associated to output vtkMesh
435  vtkSmartPointer<vtkUnstructuredGrid> dataSet_tmp =
437  // map to hold true index of points (gmsh allows non-contiguous ordering)
438  std::map<int, int> trueIndex;
439 
440  while (getline(meshStream, line)) {
441  if (line.find("$PhysicalNames") != -1) {
442  fndPhyGrp = true;
443  getline(meshStream, line);
444  std::stringstream ss(line);
445  ss >> numPhysGrps;
446  std::cout << "Found " << numPhysGrps << " physical groups!\n";
447  for (int i = 0; i < numPhysGrps; ++i) {
448  int grpDim, grpId;
449  std::string grpName;
450  getline(meshStream, line);
451  std::stringstream ss(line);
452  ss >> grpDim >> grpId >> grpName;
453  grpName.erase(std::remove(grpName.begin(), grpName.end(), '\"'),
454  grpName.end());
455  /*std::cout << "Group Dim = " << grpDim
456  << "\nGroup Id = " << grpId
457  << "\nGroup Name = " << grpName
458  << std::endl;*/
459  physGrpDims.push_back(grpDim);
460  physGrpIdName[grpId] = grpName;
461  }
462  }
463 
464  if (line.find("$Nodes") != -1) {
465  getline(meshStream, line);
466  std::stringstream ss(line);
467  ss >> numPoints;
468  int id;
469  double x, y, z;
470  // allocate memory for points
471  points->SetNumberOfPoints(numPoints);
472  for (int i = 0; i < numPoints; ++i) {
473  getline(meshStream, line);
474  std::stringstream ss(line);
475  ss >> id >> std::setprecision(16) >> x >> y >> z;
476  double point[3];
477  point[0] = x;
478  point[1] = y;
479  point[2] = z;
480  // insert point i
481  points->SetPoint(i, point);
482  trueIndex.insert(std::pair<int, int>(id, i));
483  }
484  // inserting point array into dataSet_tmp
485  dataSet_tmp->SetPoints(points);
486  }
487 
488  if (line.find("$Elements") != -1) {
489  getline(meshStream, line);
490  // std::cout << "line = " << line << std::endl;
491  std::stringstream ss(line);
492  ss >> numCells;
493  int id, type, numTags;
494  // double tmp2[1];
495  // allocate space for cell connectivities
496  dataSet_tmp->Allocate(numCells);
497  for (int i = 0; i < numCells; ++i) {
498  getline(meshStream, line);
499  std::stringstream ss(line);
500  ss >> id >> type >> numTags;
501  vtkSmartPointer<vtkIdList> vtkCellIds =
503  if (type == 2) {
504  int tmp;
505  if (!fndPhyGrp) {
506  for (int j = 0; j < numTags; ++j) ss >> tmp;
507  } else {
508  std::vector<double> physGrpId(1);
509  ss >> physGrpId[0];
510  cellPhysGrpIds.push_back(physGrpId);
511  for (int j = 0; j < numTags - 1; ++j) ss >> tmp;
512  }
513  for (int j = 0; j < 3; ++j) {
514  ss >> tmp;
515  // insert connectivities for cell into cellIds container
516  vtkCellIds->InsertNextId(trueIndex[tmp]); //-1);
517  }
518  // insert connectivities for triangle elements into dataSet
519  dataSet_tmp->InsertNextCell(VTK_TRIANGLE, vtkCellIds);
520  } else if (type == 4) {
521  int tmp;
522  if (!fndPhyGrp) {
523  for (int j = 0; j < numTags; ++j) ss >> tmp;
524  } else {
525  std::vector<double> physGrpId(1);
526  ss >> physGrpId[0];
527  cellPhysGrpIds.push_back(physGrpId);
528  for (int j = 0; j < numTags - 1; ++j) ss >> tmp;
529  }
530  for (int j = 0; j < 4; ++j) {
531  ss >> tmp;
532  // insert connectivities for cell into cellIds container
533  vtkCellIds->InsertNextId(trueIndex[tmp]); //-1);
534  }
535  // insert connectivities for tet elements into dataSet
536  dataSet_tmp->InsertNextCell(VTK_TETRA, vtkCellIds);
537  } else if (type == 3) {
538  int tmp;
539  if (!fndPhyGrp) {
540  for (int j = 0; j < numTags; ++j) ss >> tmp;
541  } else {
542  std::vector<double> physGrpId(1);
543  ss >> physGrpId[0];
544  cellPhysGrpIds.push_back(physGrpId);
545  for (int j = 0; j < numTags - 1; ++j) ss >> tmp;
546  }
547  for (int j = 0; j < 4; ++j) {
548  ss >> tmp;
549  // insert connectivities for cell into cellIds container
550  vtkCellIds->InsertNextId(trueIndex[tmp]); //-1);
551  }
552  // insert connectivities for tet elements into dataSet
553  dataSet_tmp->InsertNextCell(VTK_QUAD, vtkCellIds);
554  } else if (type == 5) {
555  int tmp;
556  if (!fndPhyGrp) {
557  for (int j = 0; j < numTags; ++j) ss >> tmp;
558  } else {
559  std::vector<double> physGrpId(1);
560  ss >> physGrpId[0];
561  cellPhysGrpIds.push_back(physGrpId);
562  for (int j = 0; j < numTags - 1; ++j) ss >> tmp;
563  }
564  for (int j = 0; j < 8; ++j) {
565  ss >> tmp;
566  // insert connectivities for cell into cellIds container
567  vtkCellIds->InsertNextId(trueIndex[tmp]); //-1);
568  }
569  // insert connectivities for hex elements into dataSet
570  dataSet_tmp->InsertNextCell(VTK_HEXAHEDRON, vtkCellIds);
571  } else if (type == 6) {
572  int tmp;
573  if (!fndPhyGrp) {
574  for (int j = 0; j < numTags; ++j) ss >> tmp;
575  } else {
576  std::vector<double> physGrpId(1);
577  ss >> physGrpId[0];
578  cellPhysGrpIds.push_back(physGrpId);
579  for (int j = 0; j < numTags - 1; ++j) ss >> tmp;
580  }
581  for (int j = 0; j < 6; ++j) {
582  ss >> tmp;
583  // insert connectivities for cell into cellIds container
584  vtkCellIds->InsertNextId(trueIndex[tmp]); //-1);
585  }
586  // insert connectivities for wedge/prism elements into dataSet
587  dataSet_tmp->InsertNextCell(VTK_WEDGE, vtkCellIds);
588  } else if (type == 11) {
589  int tmp;
590  if (!fndPhyGrp) {
591  for (int j = 0; j < numTags; ++j) ss >> tmp;
592  } else {
593  std::vector<double> physGrpId(1);
594  ss >> physGrpId[0];
595  cellPhysGrpIds.push_back(physGrpId);
596  for (int j = 0; j < numTags - 1; ++j) ss >> tmp;
597  }
598  for (int j = 0; j < 10; ++j) {
599  ss >> tmp;
600  // insert connectivities for cell into cellIds container
601  vtkCellIds->InsertNextId(trueIndex[tmp]); //-1);
602  }
603  // insert connectivities for tet elements into dataSet
604  dataSet_tmp->InsertNextCell(VTK_QUADRATIC_TETRA, vtkCellIds);
605  } else {
606  if (warning) {
607  std::cout
608  << "Warning: Only triangular, quadrilateral, "
609  "tetrahedral, hexahedral, wedge, and quadratic tetrahedral"
610  "elements are supported, "
611  << "everything else is ignored! " << std::endl;
612  warning = false;
613  // exit(1);
614  }
615  }
616  }
617  }
618 
619  if (line.find("$NodeData") != -1) {
620  std::vector<std::vector<double>> currPointData;
621  getline(meshStream, line); // moving to num_string_tags
622  std::stringstream ss(line);
623  int num_string_tags;
624  ss >> num_string_tags;
625  std::string dataname;
626  for (int i = 0; i < num_string_tags; ++i) {
627  getline(meshStream, line); // get string tag
628  if (i == 0) {
629  std::stringstream ss(line);
630  ss >> dataname;
631  }
632  }
633  dataname.erase(std::remove(dataname.begin(), dataname.end(), '\"'),
634  dataname.end());
635  pointDataNames.push_back(dataname);
636  getline(meshStream, line); // moving to num_real_tags
637  std::stringstream ss1(line);
638  int num_real_tags;
639  ss1 >> num_real_tags;
640  for (int i = 0; i < num_real_tags; ++i) getline(meshStream, line);
641 
642  getline(meshStream, line); // moving to num_int_tags
643  std::stringstream ss2(line);
644  int num_int_tags;
645  ss2 >> num_int_tags;
646  int dt, dim, numFields, tmp;
647  for (int i = 0; i < num_int_tags; ++i) {
648  getline(meshStream, line); // get int tag
649  std::stringstream ss(line);
650  if (i == 0)
651  ss >> dt;
652  else if (i == 1)
653  ss >> dim;
654  else if (i == 2)
655  ss >> numFields;
656  else
657  ss >> tmp;
658  }
659  for (int i = 0; i < numFields; ++i) {
660  std::vector<double> data(dim);
661  int id;
662  double val;
663  getline(meshStream, line);
664  std::stringstream ss(line);
665  ss >> id;
666  for (int j = 0; j < dim; ++j) {
667  ss >> val;
668  data[j] = val;
669  }
670  currPointData.push_back(data);
671  }
672  pointData.push_back(currPointData);
673  }
674 
675  if (line.find("$ElementData") != -1) {
676  std::vector<std::vector<double>> currCellData;
677  getline(meshStream, line); // moving to num_string_tags
678  std::stringstream ss(line);
679  int num_string_tags;
680  ss >> num_string_tags;
681  std::string dataname;
682  for (int i = 0; i < num_string_tags; ++i) {
683  getline(meshStream, line); // get string tag
684  if (i == 0) {
685  std::stringstream ss(line);
686  ss >> dataname;
687  }
688  }
689  dataname.erase(std::remove(dataname.begin(), dataname.end(), '\"'),
690  dataname.end());
691  cellDataNames.push_back(dataname);
692  getline(meshStream, line); // moving to num_real_tags
693  std::stringstream ss1(line);
694  int num_real_tags;
695  ss1 >> num_real_tags;
696  for (int i = 0; i < num_real_tags; ++i) getline(meshStream, line);
697 
698  getline(meshStream, line); // moving to num_int_tags
699  std::stringstream ss2(line);
700  int num_int_tags;
701  ss2 >> num_int_tags;
702  int dt, dim, numFields, tmp;
703  for (int i = 0; i < num_int_tags; ++i) {
704  getline(meshStream, line); // get int tag
705  std::stringstream ss(line);
706  if (i == 0)
707  ss >> dt;
708  else if (i == 1)
709  ss >> dim;
710  else if (i == 2)
711  ss >> numFields;
712  else
713  ss >> tmp;
714  }
715  for (int i = 0; i < numFields; ++i) {
716  std::vector<double> data(dim);
717  int id;
718  double val;
719  getline(meshStream, line);
720  std::stringstream ss(line);
721  ss >> id;
722  for (int j = 0; j < dim; ++j) {
723  ss >> val;
724  data[j] = val;
725  }
726  currCellData.push_back(data);
727  }
728  cellData.push_back(currCellData);
729  }
730  }
731 
732  if (fndPhyGrp) {
733  cellDataNames.push_back("PhysGrpId");
734  cellData.push_back(cellPhysGrpIds);
735  }
736 
737  vtkMesh *vtkmesh = new vtkMesh();
738  // vtkmesh->dataSet = dataSet_tmp->NewInstance();
739  // vtkmesh->dataSet->DeepCopy(dataSet_tmp);
740  vtkmesh->dataSet = dataSet_tmp;
741  vtkmesh->numCells = vtkmesh->dataSet->GetNumberOfCells();
742  if (numCells == 0) std::cerr << "Warning: No cells were found in the mesh!\n";
743  vtkmesh->numPoints = vtkmesh->dataSet->GetNumberOfPoints();
744  if (numPoints == 0)
745  std::cerr << "Warning: No points were found in the mesh!\n";
746 
747  if (numPoints > 0) {
748  for (int i = 0; i < pointData.size(); ++i)
749  vtkmesh->setPointDataArray(&(pointDataNames[i])[0u], pointData[i]);
750  }
751 
752  if (numCells > 0) {
753  for (int i = 0; i < cellData.size(); ++i)
754  vtkmesh->setCellDataArray(&(cellDataNames[i])[0u], cellData[i]);
755  }
756 
757  // vtkmesh->setFileName(nemAux::trim_fname(fname, ".vtu"));
758  // vtkmesh->write();
759  std::cout << "vtkMesh constructed" << std::endl;
760 
761  return vtkmesh;
762 }
763 
764 /**
765  **/
766 meshBase *meshBase::exportVolToVtk(const std::string &fname) {
767 #ifdef HAVE_NGEN
768  nglib::Ng_Mesh *Ngmesh;
769  nglib::Ng_Init();
770  Ngmesh = nglib::Ng_NewMesh();
771 
772  int status = nglib::Ng_MergeMesh(Ngmesh, &fname[0u]);
773  if (status) {
774  std::cout << "Error: NetGen Returned: " << status << std::endl;
775  std::cout << "Could not load " << fname << " into netgen" << std::endl;
776  exit(1);
777  }
778 
779  // declare points to be pushed into dataSet_tmp
780  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
781  // declare dataSet_tmp which will be associated to output vtkMesh
782  vtkSmartPointer<vtkUnstructuredGrid> dataSet_tmp =
784  int numNgPoints = nglib::Ng_GetNP(Ngmesh);
785  int numSurfCells = nglib::Ng_GetNSE(Ngmesh);
786  int numVolCells = nglib::Ng_GetNE(Ngmesh);
787 
788  // allocate memory for points
789  points->SetNumberOfPoints(numNgPoints);
790  for (int i = 1; i <= numNgPoints; ++i) {
791  double point[3];
792  nglib::Ng_GetPoint(Ngmesh, i, point);
793  // insert point i
794  points->SetPoint(i - 1, point);
795  }
796  // inserting point array into dataSet_tmp
797  dataSet_tmp->SetPoints(points);
798 
799  // allocating space for cell connectivities
800  dataSet_tmp->Allocate(numSurfCells + numVolCells);
801 
802  for (int i = 1; i <= numSurfCells; ++i) {
803  vtkSmartPointer<vtkIdList> vtkcellIds = vtkSmartPointer<vtkIdList>::New();
804  int tri[3];
805  nglib::Ng_GetSurfaceElement(Ngmesh, i, tri);
806  for (int j = 0; j < 3; ++j) {
807  // insert connectivies for cell into cellIds container
808  vtkcellIds->InsertNextId(tri[j] - 1);
809  }
810  // insert connectivies for triangle elements into dataSet
811  dataSet_tmp->InsertNextCell(VTK_TRIANGLE, vtkcellIds);
812  }
813 
814  for (int i = 1; i <= numVolCells; ++i) {
815  vtkSmartPointer<vtkIdList> vtkcellIds = vtkSmartPointer<vtkIdList>::New();
816  int tet[4];
817  nglib::Ng_GetVolumeElement(Ngmesh, i, tet);
818  for (int j = 0; j < 4; ++j) {
819  // insert connectivies for cell into cellIds container
820  vtkcellIds->InsertNextId(tet[j] - 1);
821  }
822  // insert connectivies for triangle elements into dataSet
823  dataSet_tmp->InsertNextCell(VTK_TETRA, vtkcellIds);
824  }
825 
826  vtkMesh *vtkmesh = new vtkMesh();
827  // vtkmesh->dataSet = dataSet_tmp->NewInstance();//
828  // vtkmesh->dataSet->DeepCopy(dataSet_tmp);//vtkDataSet::SafeDownCast(dataSet_tmp));
829  vtkmesh->dataSet = dataSet_tmp;
830  vtkmesh->numCells = vtkmesh->dataSet->GetNumberOfCells();
831  vtkmesh->numPoints = vtkmesh->dataSet->GetNumberOfPoints();
832 
833  vtkmesh->setFileName(nemAux::trim_fname(fname, ".vtu"));
834  std::cout << "vtkMesh constructed" << std::endl;
835 
836  if (Ngmesh) nglib::Ng_DeleteMesh(Ngmesh);
837  nglib::Ng_Exit();
838  return vtkmesh;
839 #else
840  std::cerr << "ENABLE_NETGEN is not used during build."
841  << " Build with ENABLE_NETGEN to use this function." << std::endl;
842  exit(1);
843 #endif
844 }
845 
846 /** exports pntMesh to vtk format
847  **/
848 meshBase *meshBase::exportPntToVtk(const std::string &fname) {
849  PNTMesh::pntMesh *pMesh;
850  pMesh = new PNTMesh::pntMesh(fname);
851 
852  vtkMesh *vtkmesh = new vtkMesh();
853 
854  /*
855  if (!pMesh->isCompatible())
856  {
857  std::cerr << "Mesh contains unsupported element types.\n";
858  std::cerr << "Only 3-Node TRIs and 4-Node TETs are supported.\n";
859  vtkmesh->numCells = 0;
860  vtkmesh->numPoints = 0;
861  return vtkmesh;
862  }
863  */
864 
865  // declare points to be pushed into dataSet_tmp
866  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
867  // declare dataSet_tmp which will be associated to output vtkMesh
868  vtkSmartPointer<vtkUnstructuredGrid> dataSet_tmp =
870 
871  int numPoints = pMesh->getNumberOfPoints();
872  int numVolCells = pMesh->getNumberOfCells();
873 
874  // allocate memory for points
875  points->SetNumberOfPoints(numPoints);
876  for (int i = 0; i < numPoints; ++i) {
877  std::vector<double> point;
878  point = pMesh->getPointCrd(i);
879  // insert point i
880  points->SetPoint(i, &point[0]);
881  }
882  // inserting point array into dataSet_tmp
883  dataSet_tmp->SetPoints(points);
884 
885  // allocating space for cell connectivities
886  dataSet_tmp->Allocate(numVolCells);
887  for (int i = 0; i < numVolCells; ++i) {
888  std::cout << "Element " << i << std::endl;
889  vtkSmartPointer<vtkIdList> vtkcellIds = vtkSmartPointer<vtkIdList>::New();
890  std::vector<int> conn;
891  VTKCellType vct =
892  pMesh->getVtkCellTag(pMesh->getElmType(i), pMesh->getElmOrder(i));
893  conn = pMesh->getElmConn(i, vct);
894  for (int j = 0; j < conn.size(); ++j) {
895  // insert connectivies for cell into cellIds container
896  vtkcellIds->InsertNextId(conn[j]);
897  }
898  // insert connectivies
899  dataSet_tmp->InsertNextCell(vct, vtkcellIds);
900  }
901 
902  vtkmesh->dataSet = dataSet_tmp;
903  vtkmesh->numCells = vtkmesh->dataSet->GetNumberOfCells();
904  vtkmesh->numPoints = vtkmesh->dataSet->GetNumberOfPoints();
905 
906  //
907  std::cout << "Trimmed name = " << nemAux::trim_fname(fname, ".vtu")
908  << std::endl;
909  vtkmesh->setFileName(nemAux::trim_fname(fname, ".vtu"));
910  // vtkmesh->write();
911  std::cout << "vtkMesh constructed" << std::endl;
912 
913  return vtkmesh;
914 }
915 
916 /** exports exodusII to vtk format
917  **/
918 meshBase *meshBase::exportExoToVtk(const std::string &fname) {
919  // opening the file
920  int CPU_word_size, IO_word_size;
921  int fid, _exErr;
922  float version;
923  CPU_word_size = sizeof(float);
924  IO_word_size = 0;
925  _exErr = 0;
926 
927  /* open EXODUS II files */
928  fid =
929  ex_open(fname.c_str(), EX_READ, &CPU_word_size, &IO_word_size, &version);
930  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem opening file " + fname + "\n");
931 
932  // declare points to be pushed into dataSet_tmp
933  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
934 
935  // declare dataSet_tmp which will be associated to output vtkMesh
936  vtkSmartPointer<vtkUnstructuredGrid> dataSet_tmp =
938 
939  int numPoints;
940  int numVolCells;
941  int numElmBlk;
942  int numNdeSet;
943  int numSideSet;
944 
945  // parameter inquiry from Exodus file
946  int num_props;
947  float fdum;
948  char cdum;
949  _exErr = ex_inquire(fid, EX_INQ_API_VERS, &num_props, &fdum, &cdum);
950  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem reading file contents.\n");
951  std::cout << "Exodus II API version is " << fdum << std::endl;
952 
953  _exErr = ex_inquire(fid, EX_INQ_DB_VERS, &num_props, &fdum, &cdum);
954  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem reading file contents.\n");
955  std::cout << "Exodus II Database version is " << fdum << std::endl;
956 
957  _exErr = ex_inquire(fid, EX_INQ_DIM, &num_props, &fdum, &cdum);
958  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem reading file contents.\n");
959  std::cout << "Number of coordinate dimensions is " << num_props << std::endl;
960  if (num_props != 3)
961  NEM::MSH::EXOMesh::wrnErrMsg(-1, "Only 3D mesh data is supported!\n");
962 
963  _exErr = ex_inquire(fid, EX_INQ_NODES, &num_props, &fdum, &cdum);
964  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem reading file contents.\n");
965  numPoints = num_props;
966  std::cout << "Number of points " << numPoints << std::endl;
967 
968  _exErr = ex_inquire(fid, EX_INQ_ELEM, &num_props, &fdum, &cdum);
969  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem reading file contents.\n");
970  numVolCells = num_props;
971  std::cout << "Number of elements " << numVolCells << std::endl;
972 
973  _exErr = ex_inquire(fid, EX_INQ_ELEM_BLK, &num_props, &fdum, &cdum);
974  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem reading file contents.\n");
975  numElmBlk = num_props;
976  std::cout << "Number of element blocks " << numElmBlk << std::endl;
977 
978  _exErr = ex_inquire(fid, EX_INQ_NODE_SETS, &num_props, &fdum, &cdum);
979  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem reading file contents.\n");
980  numNdeSet = num_props;
981  std::cout << "Number of node sets " << numNdeSet << std::endl;
982 
983  _exErr = ex_inquire(fid, EX_INQ_SIDE_SETS, &num_props, &fdum, &cdum);
984  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem reading file contents.\n");
985  numSideSet = num_props;
986  std::cout << "Number of side sets " << numSideSet << std::endl;
987 
988  // nodal coordinates
989  std::vector<float> x, y, z;
990  x.resize(numPoints, 0);
991  y.resize(numPoints, 0);
992  z.resize(numPoints, 0);
993  _exErr = ex_get_coord(fid, &x[0], &y[0], &z[0]);
994  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem reading nodal coordinates.\n");
995 
996  // allocate memory for points
997  points->SetNumberOfPoints(numPoints);
998  for (int i = 0; i < numPoints; ++i) {
999  std::vector<double> pt = {x[i], y[i], z[i]};
1000  points->SetPoint(i, &pt[0]);
1001  }
1002  // inserting point array into dataSet_tmp
1003  dataSet_tmp->SetPoints(points);
1004 
1005  // Connectivities
1006  // allocating space for cell connectivities
1007  dataSet_tmp->Allocate(numVolCells);
1008 
1009  // VTK int array for block IDs
1010  vtkSmartPointer<vtkIntArray> blocks = vtkSmartPointer<vtkIntArray>::New();
1011  blocks->SetNumberOfValues(numVolCells);
1012  blocks->SetName("BlockId");
1013 
1014  int count = 0;
1015  // read element blocks
1016  for (int iEB = 1; iEB <= numElmBlk; iEB++) {
1017  int num_el_in_blk, num_nod_per_el, num_attr /*, *connect*/;
1018  // float *attrib;
1019  char elem_type[MAX_STR_LENGTH + 1];
1020  // read element block parameters
1021  _exErr = ex_get_elem_block(fid, iEB, elem_type, &num_el_in_blk,
1022  &num_nod_per_el, &num_attr);
1024  "Problem reading element block parameters.\n");
1025  // read element connectivity
1026  std::vector<int> conn;
1027  conn.resize(num_el_in_blk * num_nod_per_el, 0);
1028  _exErr = ex_get_elem_conn(fid, iEB, &conn[0]);
1030  _exErr, "Problem reading element block connectivities.\n");
1031  // read element block attributes
1032  // std::vector<float> attr;
1033  // attr.resize(0.,num_el_in_blk*num_nod_per_el);
1034  //_exErr = ex_get_elem_attr (fid, iEB, &attrib[0]);
1035  // EXOMesh::wrnErrMsg(_exErr, "Problem reading element block
1036  // attributes.\n");
1037 
1038  for (int iEl = 0; iEl < num_el_in_blk; ++iEl) {
1039  vtkSmartPointer<vtkIdList> vtkcellIds = vtkSmartPointer<vtkIdList>::New();
1040  VTKCellType vct =
1042  for (int jc = iEl * num_nod_per_el; jc < (iEl + 1) * num_nod_per_el;
1043  jc++) {
1044  // insert connectivities for cell into cellIds container
1045  vtkcellIds->InsertNextId(conn[jc] - 1);
1046  }
1047  // insert connectivities
1048  dataSet_tmp->InsertNextCell(vct, vtkcellIds);
1049 
1050  vtkIdType i = count;
1051  blocks->SetValue(i, iEB);
1052  count++;
1053  }
1054  }
1055  // std::cout << "Trimmed name = " << nemAux::trim_fname(fname, ".vtu")
1056  // << std::endl;
1057 
1058  vtkMesh *vtkmesh = new vtkMesh();
1059  vtkmesh->dataSet = dataSet_tmp;
1060  vtkmesh->numCells = vtkmesh->dataSet->GetNumberOfCells();
1061  vtkmesh->numPoints = vtkmesh->dataSet->GetNumberOfPoints();
1062 
1063  vtkmesh->dataSet->GetCellData()->AddArray(blocks);
1064 
1065  vtkmesh->setFileName("vtkWithIds.vtu");
1066  vtkmesh->write();
1067  std::cout << "vtkMesh constructed" << std::endl;
1068 
1069  // closing the file
1070  _exErr = ex_close(fid);
1071  NEM::MSH::EXOMesh::wrnErrMsg(_exErr, "Problem closing the exodusII file.");
1072 
1073  return vtkmesh;
1074 }
1075 
1076 /** convert to gmsh format without data
1077  **/
1078 void meshBase::writeMSH(std::ofstream &outputStream) {
1079  if (!outputStream.good()) {
1080  std::cout << "Output file stream is bad" << std::endl;
1081  exit(1);
1082  }
1083 
1084  if (!dataSet) {
1085  std::cout << "No data to write" << std::endl;
1086  exit(1);
1087  }
1088  // --------- writing gmsh header ----------- //
1089  outputStream << "$MeshFormat" << std::endl
1090  << "2.2 0 8" << std::endl
1091  << "$EndMeshFormat" << std::endl;
1092 
1093  // -------- ensure all cell types are tri/tet or below -------------- //
1094  int type_id;
1095  for (int i = 0; i < numCells; i++) {
1096  type_id = dataSet->GetCellType(i);
1097  if (!(type_id == 3 || type_id == 5 || type_id == 10 || type_id == 9)) {
1098  std::cout << "Error: Only tetrahedral, triangular, and quadrilateral"
1099  << " meshes can be written to gmsh format" << std::endl;
1100  exit(3);
1101  }
1102  }
1103 
1104  // ------------------------ write point coords -------------------------- //
1105  outputStream << "$Nodes" << std::endl << numPoints << std::endl;
1106  for (int i = 0; i < numPoints; ++i) {
1107  std::vector<double> pntcrds = getPoint(i);
1108  outputStream << i + 1 << " " << pntcrds[0] << " " << pntcrds[1] << " "
1109  << pntcrds[2] << " " << std::endl;
1110  }
1111  outputStream << "$EndNodes" << std::endl;
1112 
1113  // ------------- write element type and connectivity --------------------- //
1114  outputStream << "$Elements" << std::endl << numCells << std::endl;
1115  for (int i = 0; i < numCells; ++i) {
1116  vtkIdList *point_ids = dataSet->GetCell(i)->GetPointIds();
1117  int numComponent = point_ids->GetNumberOfIds();
1118  type_id = dataSet->GetCell(i)->GetCellType();
1119  outputStream << i + 1 << " ";
1120  switch (numComponent) {
1121  case 2: {
1122  outputStream << 1 << " " << 2 << " " << 1 << " " << 1 << " ";
1123  break;
1124  }
1125  case 3: {
1126  outputStream << 2 << " " << 2 << " " << 1 << " " << 1 << " ";
1127  break;
1128  }
1129  case 4: {
1130  if (type_id == 10) // tetra
1131  {
1132  outputStream << 4 << " " << 2 << " " << 1 << " " << 1 << " ";
1133  break;
1134  } else if (type_id == 9) // quad
1135  {
1136  outputStream << 3 << " " << 2 << " " << 1 << " " << 1 << " ";
1137  break;
1138  } else
1139  {
1140  std::cerr << "Cells with 4 components must be tet or quad."
1141  << std::endl;
1142  exit(1);
1143  }
1144  }
1145 
1146  default: {
1147  std::cerr << "Components in cell should be <= 4" << std::endl;
1148  exit(1);
1149  }
1150  }
1151  for (int j = 0; j < numComponent; ++j)
1152  outputStream << point_ids->GetId(j) + 1 << " ";
1153  outputStream << std::endl;
1154  }
1155  outputStream << "$EndElements" << std::endl;
1156 }
1157 
1158 /** convert to gmsh format with specified point or cell data
1159  **/
1160 void meshBase::writeMSH(std::ofstream &outputStream,
1161  const std::string &pointOrCell, int arrayID) {
1162  // write points and cells
1163  writeMSH(outputStream);
1164 
1165  if (!outputStream.good()) {
1166  std::cout << "Output file stream is bad" << std::endl;
1167  exit(1);
1168  }
1169 
1170  if (!pointOrCell.compare("point")) {
1171  // ---------------------------- write point data -------------------------
1172  // //
1173  vtkPointData *pointData = dataSet->GetPointData();
1174  if (pointData) {
1175  int numArr = pointData->GetNumberOfArrays();
1176  if (arrayID >= numArr) {
1177  std::cout << "ERROR: arrayID is out of bounds" << std::endl;
1178  std::cout << "There are " << numArr << " point data arrays"
1179  << std::endl;
1180  exit(1);
1181  } else if (numArr < 1) {
1182  std::cout << "no point data found" << std::endl;
1183  exit(1);
1184  }
1185  vtkDataArray *da = pointData->GetArray(arrayID);
1186  if (da) {
1187  int numComponent = da->GetNumberOfComponents();
1188  int numTuple = da->GetNumberOfTuples();
1189  std::string tmpname = "PointArray";
1190  tmpname += std::to_string(arrayID);
1191  outputStream << "$NodeData" << std::endl
1192  << 1 << std::endl // 1 string tag
1193  << "\""
1194  << (pointData->GetArrayName(arrayID)
1195  ? pointData->GetArrayName(arrayID)
1196  : tmpname) // name of view
1197  << "\"" << std::endl
1198  << 0 << std::endl // 0 real tag
1199  << 3 << std::endl // 3 int tags (dt index, dim of field,
1200  // number of fields)
1201  << 0 << std::endl // dt index
1202  << numComponent << std::endl // dim of field
1203  << numTuple << std::endl; // number of fields
1204  for (int j = 0; j < numTuple; ++j) {
1205  double *data = da->GetTuple(j);
1206  outputStream << j + 1 << " ";
1207  for (int k = 0; k < numComponent; ++k) {
1208  outputStream << data[k] << " ";
1209  }
1210  outputStream << std::endl;
1211  }
1212  outputStream << "$EndNodeData" << std::endl;
1213  }
1214  }
1215  } else if (!pointOrCell.compare("cell")) {
1216  // -------------------------- write cell data ----------------------------
1217  // //
1218 
1219  vtkCellData *cellData = dataSet->GetCellData();
1220  if (cellData) {
1221  int numArr = cellData->GetNumberOfArrays();
1222  if (arrayID >= numArr) {
1223  std::cout << "ERROR: arrayID is out of bounds" << std::endl;
1224  std::cout << "There are " << numArr << " cell data arrays" << std::endl;
1225  exit(1);
1226  } else if (numArr < 1) {
1227  std::cout << "no cell data found" << std::endl;
1228  exit(1);
1229  }
1230  vtkDataArray *da = cellData->GetArray(arrayID);
1231  if (da) {
1232  int numComponent = da->GetNumberOfComponents();
1233  int numTuple = da->GetNumberOfTuples();
1234  std::string tmpname = "CellArray";
1235  tmpname += std::to_string(arrayID);
1236  outputStream << "$ElementData" << std::endl
1237  << 1 << std::endl // 1 string tag
1238  << "\""
1239  << (cellData->GetArrayName(arrayID)
1240  ? cellData->GetArrayName(arrayID)
1241  : tmpname) // name of view
1242  << "\"" << std::endl
1243  << 0 << std::endl // 0 real tag
1244  << 3 << std::endl // 3 int tags (dt index, dim of field,
1245  // number of fields)
1246  << 0 << std::endl // dt index
1247  << numComponent << std::endl // dim of field
1248  << numTuple << std::endl; // number of fields
1249  for (int j = 0; j < numTuple; ++j) {
1250  double *data = da->GetTuple(j);
1251  outputStream << j + 1 << " ";
1252  for (int k = 0; k < numComponent; ++k) {
1253  outputStream << data[k] << " ";
1254  }
1255  outputStream << std::endl;
1256  }
1257  outputStream << "$EndElementData" << std::endl;
1258  }
1259  }
1260  }
1261 }
1262 
1263 /** convert to gmsh format with specified point or cell data for
1264  **/
1265 void meshBase::writeMSH(std::ofstream &outputStream,
1266  const std::string &pointOrCell, int arrayID,
1267  bool onlyVol) {
1268  if (!outputStream.good()) {
1269  std::cout << "Output file stream is bad" << std::endl;
1270  exit(1);
1271  }
1272 
1273  if (!dataSet) {
1274  std::cout << "No data to write" << std::endl;
1275  exit(2);
1276  }
1277  // --------- writing gmsh header ----------- //
1278  outputStream << "$MeshFormat" << std::endl
1279  << "2.2 0 8" << std::endl
1280  << "$EndMeshFormat" << std::endl;
1281 
1282  // ---- get number of points and number of elements ---- //
1283  getNumberOfCells();
1284  getNumberOfPoints();
1285 
1286  // -------- ensure all cell types are tri/tet or below -------------- //
1287  int num_bad = 0;
1288  for (int i = 0; i < numCells; i++) {
1289  int type_id = dataSet->GetCellType(i);
1290  if (!(type_id == 3 || type_id == 5 || type_id == 10 || type_id == 9)) {
1291  std::cout << "Error: Only tetrahedral, triangular, and quadrilateral"
1292  << " meshes can be written to gmsh format" << std::endl;
1293  exit(3);
1294  }
1295  if (!(type_id == 10)) num_bad += 1;
1296  }
1297 
1298  // ------------------------ write point coords -------------------------- //
1299  outputStream << "$Nodes" << std::endl << numPoints << std::endl;
1300  for (int i = 0; i < numPoints; ++i) {
1301  std::vector<double> pntcrds = getPoint(i);
1302  outputStream << i + 1 << " ";
1303  outputStream << std::setprecision(16) << pntcrds[0] << " " << pntcrds[1]
1304  << " " << pntcrds[2] << " " << std::endl;
1305  }
1306  outputStream << "$EndNodes" << std::endl;
1307 
1308  // ------------- write element type and connectivity --------------------- //
1309  outputStream << "$Elements" << std::endl << numCells - num_bad << std::endl;
1310  // int k = 0;
1311  for (int i = 0; i < numCells; ++i) {
1312  vtkIdList *point_ids = dataSet->GetCell(i)->GetPointIds();
1313  int numComponent = point_ids->GetNumberOfIds();
1314  int type_id = dataSet->GetCellType(i);
1315  if (type_id == 10) {
1316  outputStream << i + 1 << " ";
1317  switch (numComponent) {
1318  case 2: {
1319  break;
1320  }
1321  case 3: {
1322  outputStream << 2 << " " << 2 << " " << 1 << " " << 1 << " ";
1323  break;
1324  }
1325  case 4: {
1326  outputStream << 4 << " " << 2 << " " << 1 << " " << 1 << " ";
1327  break;
1328  }
1329 
1330  default: {
1331  std::cerr << "Components in cell should be less than 4" << std::endl;
1332  exit(1);
1333  }
1334  }
1335  for (int j = 0; j < numComponent; ++j)
1336  outputStream << point_ids->GetId(j) + 1 << " ";
1337  outputStream << std::endl;
1338  // k+=1;
1339  }
1340  }
1341  outputStream << "$EndElements" << std::endl;
1342  // -------------------------- write cell data ---------------------------- //
1343  vtkCellData *cellData = dataSet->GetCellData();
1344  vtkDataArray *da = cellData->GetArray(arrayID);
1345  if (da) {
1346  std::string tmpname = "CellArray";
1347  tmpname += std::to_string(arrayID);
1348  outputStream
1349  << "$ElementData" << std::endl
1350  << 1 << std::endl // 1 string tag
1351  << "\""
1352  << (cellData->GetArrayName(arrayID) ? cellData->GetArrayName(arrayID)
1353  : tmpname) // name of view
1354  << "\"" << std::endl
1355  << 0 << std::endl // 0 real tag
1356  << 3
1357  << std::endl // 3 int tags (dt index, dim of field, number of fields)
1358  << 0 << std::endl // dt index
1359  << 1 << std::endl // dim of field
1360  << numCells - num_bad << std::endl; // number of fields
1361  for (int j = 0; j < numCells; ++j) {
1362  int type_id = dataSet->GetCellType(j);
1363  if (type_id == 10) {
1364  double *data = da->GetTuple(j);
1365  outputStream << j + 1 << " ";
1366  outputStream << data[0] << " ";
1367  outputStream << std::endl;
1368  }
1369  }
1370  outputStream << "$EndElementData" << std::endl;
1371  }
1372 }
1373 
1374 /**
1375  **/
1376 void writePatchMap(const std::string &mapFile,
1377  const std::map<int, int> &patchMap) {
1378  std::ofstream outputStream(mapFile);
1379  if (!outputStream.good()) {
1380  std::cout << "Error opening file " << mapFile << std::endl;
1381  exit(1);
1382  }
1383  writePatchMap(outputStream, patchMap);
1384 }
1385 
1386 /**
1387  **/
1388 void writePatchMap(std::ofstream &outputStream,
1389  const std::map<int, int> &patchMap) {
1390  outputStream << patchMap.size() << std::endl;
1391  outputStream << patchMap.size() << std::endl;
1392  auto it = patchMap.begin();
1393  int normPatchNo = 1;
1394  while (it != patchMap.end()) {
1395  for (int i = 0; i < 2; ++i) {
1396  outputStream << std::setw(2) << std::left << it->first << " ";
1397  }
1398  outputStream << std::setw(2) << std::left << normPatchNo << " ";
1399  outputStream << std::endl;
1400  ++it;
1401  normPatchNo++;
1402  }
1403 }
1404 
1405 /** for rocstar restart hack through rflupart/prep
1406  **/
1407 void meshBase::writeCobalt(meshBase *surfWithPatches,
1408  const std::string &mapFile,
1409  std::ofstream &outputStream) {
1410  if (!surfWithPatches) {
1411  std::cout << "surface mesh is empty!" << std::endl;
1412  exit(1);
1413  }
1414  if (surfWithPatches->IsArrayName("patchNo", 1) == -1) {
1415  std::cout << "surface mesh must have patchNo cell array" << std::endl;
1416  exit(1);
1417  }
1418  vtkSmartPointer<vtkIdList> facePtIds;
1419  vtkSmartPointer<vtkIdList> sharedCellPtIds =
1421  vtkSmartPointer<vtkGenericCell> genCell1 =
1423  vtkSmartPointer<vtkGenericCell> genCell2 =
1425  std::map<std::vector<nemId_t>, std::pair<nemId_t, nemId_t>,
1427  faceMap;
1428  // building cell locator for looking up patch number in remeshed surface mesh
1429  vtkSmartPointer<vtkStaticCellLocator> surfCellLocator =
1430  surfWithPatches->buildStaticCellLocator();
1431  // maximum number of vertices per face (to be found in proceeding loop)
1432  int nVerticesPerFaceMax = 0;
1433  // maximum number of faces per cell (to be found in proceeding loop)
1434  int nFacesPerCellMax = 0;
1435 
1436  for (nemId_t i = 0; i < this->getNumberOfCells(); ++i) {
1437  // get cell i
1438  dataSet->GetCell(i, genCell1);
1439  // get faces, find cells sharing it. if no cell shares it,
1440  // use the locator of the surfWithPatches to find the patch number
1441  int numFaces = genCell1->GetNumberOfFaces();
1442  nFacesPerCellMax =
1443  (nFacesPerCellMax < numFaces ? numFaces : nFacesPerCellMax);
1444  for (int j = 0; j < numFaces; ++j) {
1445  vtkCell *face = genCell1->GetFace(j);
1446  // bool shared = false;
1447  vtkIdType numVerts = face->GetNumberOfPoints();
1448  nVerticesPerFaceMax =
1449  (nVerticesPerFaceMax < numVerts ? numVerts : nVerticesPerFaceMax);
1450  facePtIds = face->GetPointIds();
1451  dataSet->GetCellNeighbors(i, facePtIds, sharedCellPtIds);
1452  std::vector<nemId_t> facePntIds(numVerts);
1453  for (vtkIdType k = 0; k < numVerts; ++k) {
1454  facePntIds[k] = face->GetPointId(k) + 1;
1455  }
1456  // std::cout << "sharedCellPtIds->GetNumberOfIds() = " <<
1457  // sharedCellPtIds->GetNumberOfIds() << std::endl;
1458  if (sharedCellPtIds->GetNumberOfIds()) {
1459  faceMap.insert(
1460  std::pair<std::vector<nemId_t>, std::pair<nemId_t, nemId_t>>(
1461  facePntIds,
1462  std::make_pair(i + 1, sharedCellPtIds->GetId(0) + 1)));
1463  } else {
1464  double p1[3], p2[3], p3[3];
1465  face->GetPoints()->GetPoint(0, p1);
1466  face->GetPoints()->GetPoint(1, p2);
1467  face->GetPoints()->GetPoint(2, p3);
1468  double faceCenter[3];
1469  for (vtkIdType k = 0; k < numVerts; ++k) {
1470  faceCenter[k] = (p1[k] + p2[k] + p3[k]) / 3.0;
1471  }
1472  vtkIdType closestCellId;
1473  int subId;
1474  double minDist2;
1475  double closestPoint[3];
1476  // find closest point and closest cell to faceCenter
1477  surfCellLocator->FindClosestPoint(faceCenter, closestPoint, genCell2,
1478  closestCellId, subId, minDist2);
1479  double patchNo[1];
1480  surfWithPatches->getDataSet()
1481  ->GetCellData()
1482  ->GetArray("patchNo")
1483  ->GetTuple(closestCellId, patchNo);
1484  faceMap.insert(
1485  std::pair<std::vector<nemId_t>, std::pair<nemId_t, nemId_t>>(
1486  facePntIds, std::make_pair(i + 1, -1 * patchNo[0])));
1487  }
1488  }
1489  }
1490 
1491  std::map<int, int> patchMap;
1492  for (int i = 0; i < surfWithPatches->getNumberOfCells(); ++i) {
1493  double patchNo[1];
1494  surfWithPatches->getDataSet()->GetCellData()->GetArray("patchNo")->GetTuple(
1495  i, patchNo);
1496  patchMap.insert(std::pair<int, int>(patchNo[0], i));
1497  }
1498 
1499  // write patch mapping file
1500  writePatchMap(mapFile, patchMap);
1501  // write cobalt file
1502  outputStream << 3 << " " << 1 << " " << patchMap.size() << std::endl;
1503  outputStream << this->getNumberOfPoints() << " " << faceMap.size() << " "
1504  << this->getNumberOfCells() << " " << nVerticesPerFaceMax << " "
1505  << nFacesPerCellMax << std::endl;
1506  for (int i = 0; i < this->getNumberOfPoints(); ++i) {
1507  std::vector<double> pnt(this->getPoint(i));
1508  outputStream << std::setw(21) << std::fixed << std::setprecision(15)
1509  << pnt[0] << " " << pnt[1] << " " << pnt[2] << std::endl;
1510  }
1511 
1512  auto it = faceMap.begin();
1513  while (it != faceMap.end()) {
1514  outputStream << it->first.size() << " ";
1515  auto faceIdIter = it->first.begin();
1516  while (faceIdIter != it->first.end()) {
1517  outputStream << *faceIdIter << " ";
1518  ++faceIdIter;
1519  }
1520  outputStream << it->second.first << " " << it->second.second << std::endl;
1521  ++it;
1522  }
1523 }
1524 
1525 /** for rocstar restart hack through rflupart/prep
1526  **/
1527 void meshBase::writeCobalt(meshBase *surfWithPatches,
1528  const std::string &mapFile,
1529  const std::string &ofname) {
1530  std::ofstream outputStream(ofname);
1531  if (!outputStream.good()) {
1532  std::cout << "Cannot open file " << ofname << std::endl;
1533  exit(1);
1534  }
1535  writeCobalt(surfWithPatches, mapFile, outputStream);
1536 }
1537 
1538 /**
1539  **/
1540 void meshBase::writeMSH(const std::string &fname,
1541  const std::string &pointOrCell, int arrayID,
1542  bool onlyVol) {
1543  std::ofstream outputStream(fname.c_str());
1544  writeMSH(outputStream, pointOrCell, arrayID, onlyVol);
1545 }
1546 
1547 /**
1548  **/
1549 void meshBase::writeMSH(const std::string &fname) {
1550  std::ofstream outputStream(fname.c_str());
1551  writeMSH(outputStream);
1552 }
1553 
1554 /**
1555  **/
1556 void meshBase::writeMSH(const std::string &fname,
1557  const std::string &pointOrCell, int arrayID) {
1558  std::ofstream outputStream(fname.c_str());
1559  writeMSH(outputStream, pointOrCell, arrayID);
1560 }
1561 
1562 /** edge_scale is for uniform refinement and is ignored in calls where
1563  method is "gradient", "value", etc. instead of "uniform"
1564 **/
1565 void meshBase::refineMesh(const std::string &method, int arrayID,
1566  double dev_mult, bool maxIsmin, double edge_scale,
1567  const std::string &ofname, bool transferData,
1568  double sizeFactor, bool constrainBoundary) {
1569 #ifdef HAVE_GMSH
1570  std::unique_ptr<NEM::ADP::Refine> refineobj =
1571  std::unique_ptr<NEM::ADP::Refine>(
1572  new NEM::ADP::Refine(this, method, arrayID, dev_mult, maxIsmin,
1573  edge_scale, ofname, sizeFactor));
1574  refineobj->run(transferData, constrainBoundary);
1575 #else
1576  std::cerr << "Cannot use meshBase::refineMesh without Gmsh. Please configure "
1577  "with ENABLE_GMSH=ON.\n";
1578 #endif
1579 }
1580 
1581 /**
1582  **/
1583 void meshBase::refineMesh(const std::string &method, int arrayID, int _order,
1584  const std::string &ofname, bool transferData) {
1585 #ifdef HAVE_GMSH
1586  std::unique_ptr<NEM::ADP::Refine> refineobj =
1587  std::unique_ptr<NEM::ADP::Refine>(new NEM::ADP::Refine(
1588  this, method, arrayID, 0.0, false, 0.0, ofname, 1.0, _order));
1589  refineobj->run(transferData);
1590 #else
1591  std::cerr << "Cannot use meshBase::refineMesh without Gmsh. Please configure "
1592  "with ENABLE_GMSH=ON.\n";
1593 #endif
1594 }
1595 
1596 /** edge_scale is for uniform refinement and is ignored in calls where
1597  method is "gradient", "value", etc. instead of "uniform"
1598 **/
1599 void meshBase::refineMesh(const std::string &method,
1600  const std::string &arrayName, double dev_mult,
1601  bool maxIsmin, double edge_scale,
1602  const std::string &ofname, bool transferData,
1603  double sizeFactor) {
1604  int arrayID = IsArrayName(arrayName);
1605  if (arrayID == -1) {
1606  std::cout << "Array " << arrayName
1607  << " not found in set of point data arrays" << std::endl;
1608  exit(1);
1609  }
1610  refineMesh(method, arrayID, dev_mult, maxIsmin, edge_scale, ofname,
1611  transferData, sizeFactor);
1612 }
1613 
1614 /**
1615  **/
1616 void meshBase::refineMesh(const std::string &method,
1617  const std::string &arrayName, int order,
1618  const std::string &ofname, bool transferData) {
1619  int arrayID = IsArrayName(arrayName);
1620  if (arrayID == -1) {
1621  std::cout << "Array " << arrayName
1622  << " not found in set of point data arrays" << std::endl;
1623  exit(1);
1624  }
1625 
1626  refineMesh(method, arrayID, order, ofname, transferData);
1627 }
1628 
1629 /** added for uniform refinement by driver
1630  **/
1631 void meshBase::refineMesh(const std::string &method, double edge_scale,
1632  const std::string &ofname, bool transferData,
1633  bool constrainBoundary) {
1634  refineMesh(method, 0, 0, false, edge_scale, ofname, transferData, 1.0,
1635  constrainBoundary);
1636 }
1637 
1638 /**
1639  **/
1640 vtkSmartPointer<vtkStaticCellLocator> meshBase::buildStaticCellLocator() {
1641  vtkSmartPointer<vtkStaticCellLocator> cellLocator =
1643  cellLocator->SetDataSet(dataSet);
1644  cellLocator->BuildLocator();
1645  return cellLocator;
1646 }
1647 
1648 vtkSmartPointer<vtkStaticPointLocator> meshBase::buildStaticPointLocator() {
1649  auto pointLocator = vtkSmartPointer<vtkStaticPointLocator>::New();
1650  pointLocator->SetDataSet(dataSet);
1651  pointLocator->BuildLocator();
1652  return pointLocator;
1653 }
1654 
1655 /**
1656  **/
1657 void meshBase::checkMesh(const std::string &ofname) const {
1658  std::unique_ptr<MeshQuality> qualCheck =
1659  std::unique_ptr<MeshQuality>(new MeshQuality(this));
1660  qualCheck->checkMesh(ofname);
1661 }
1662 
1663 /**
1664  **/
1665 int diffMesh(meshBase *mesh1, meshBase *mesh2) {
1666  // double tol = 1e-14;
1667  double tol = 3e-2;
1668 
1669  if (mesh1->getNumberOfPoints() != mesh2->getNumberOfPoints() ||
1670  mesh1->getNumberOfCells() != mesh2->getNumberOfCells()) {
1671  std::cerr << "Meshes don't have the same number of points or cells"
1672  << std::endl;
1673  return 1;
1674  }
1675 
1676  for (int i = 0; i < mesh1->getNumberOfPoints(); ++i) {
1677  std::vector<double> coord1 = mesh1->getPoint(i);
1678  std::vector<double> coord2 = mesh2->getPoint(i);
1679  for (int j = 0; j < 3; ++j) {
1680  if (std::fabs((coord1[j] - coord2[j]) / coord2[j]) > tol) {
1681  std::cerr << "Meshes differ in point coordinates" << std::endl;
1682  std::cerr << "Index " << i << " Component " << j << std::endl;
1683  std::cerr << "Coord 1 " << std::setprecision(15) << coord1[j]
1684  << " Coord 2 " << std::setprecision(15) << coord2[j]
1685  << std::endl;
1686  std::cerr << "Meshes differ in point coordinates" << std::endl;
1687  return 1;
1688  }
1689  }
1690  }
1691 
1692  for (int i = 0; i < mesh1->getNumberOfCells(); ++i) {
1693  std::vector<std::vector<double>> cell1 = mesh1->getCellVec(i);
1694  std::vector<std::vector<double>> cell2 = mesh2->getCellVec(i);
1695  if (cell1.size() != cell2.size()) {
1696  std::cerr << "Meshes differ in cells" << std::endl;
1697  return 1;
1698  }
1699  for (int j = 0; j < cell1.size(); ++j) {
1700  for (int k = 0; k < 3; ++k) {
1701  if (std::fabs((cell1[j][k] - cell2[j][k]) / cell2[j][k]) > tol) {
1702  std::cerr << "Meshes differ in cells" << std::endl;
1703  return 1;
1704  }
1705  }
1706  }
1707  }
1708 
1709  vtkSmartPointer<vtkPointData> pd1 = vtkSmartPointer<vtkPointData>::New();
1710  pd1 = mesh1->getDataSet()->GetPointData();
1711  vtkSmartPointer<vtkPointData> pd2 = vtkSmartPointer<vtkPointData>::New();
1712  pd2 = mesh2->getDataSet()->GetPointData();
1713  int numArr1 = pd1->GetNumberOfArrays();
1714  int numArr2 = pd2->GetNumberOfArrays();
1715 
1716  if (numArr1 != numArr2) {
1717  std::cerr << "Meshes have different numbers of point data" << std::endl;
1718  std::cerr << "Mesh 1 has " << numArr1 << std::endl;
1719  std::cerr << "Mesh 2 has " << numArr2 << std::endl;
1720  return 1;
1721  }
1722 
1723  for (int i = 0; i < numArr1; ++i) {
1724  vtkDataArray *da1 = pd1->GetArray(i);
1725  std::cerr << "checking array " << da1->GetName() << std::endl;
1726  vtkDataArray *da2 = pd2->GetArray(pd1->GetArrayName(i));
1727  double range[2];
1728  double abs_error;
1729  double rel_error;
1730  int numComponent = da1->GetNumberOfComponents();
1731  for (int j = 0; j < mesh1->getNumberOfPoints(); ++j) {
1732  double *comps1 = new double[numComponent];
1733  double *comps2 = new double[numComponent];
1734  da1->GetTuple(j, comps1);
1735  da2->GetTuple(j, comps2);
1736  for (int k = 0; k < numComponent; ++k) {
1737  da1->GetRange(range, k);
1738  abs_error = std::fabs(comps1[k] - comps2[k]);
1739  double max_val = std::max(std::abs(range[0]), std::abs(range[1]));
1740  rel_error = abs_error / std::max(1.0, max_val);
1741  if (rel_error > tol) {
1742  std::cerr << "For point data array " << da1->GetName() << std::endl;
1743  std::cerr << "Meshes differ in point data values at point " << j
1744  << " component " << k << std::endl;
1745  std::cerr << std::setprecision(15) << "Mesh 1 value : " << comps1[k]
1746  << std::endl;
1747  std::cerr << std::setprecision(15) << "Mesh 2 value : " << comps2[k]
1748  << std::endl;
1749  return 1;
1750  }
1751  }
1752  delete[] comps1;
1753  delete[] comps2;
1754  }
1755  }
1756  std::cerr << "Meshes are the same" << std::endl;
1757  return 0;
1758 }
1759 
1760 bool sortNemId_tVec_compare::operator()(std::vector<nemId_t> lhs,
1761  std::vector<nemId_t> rhs) const {
1762  std::sort(lhs.begin(), lhs.end());
1763  std::sort(rhs.begin(), rhs.end());
1764  return lhs < rhs;
1765 }
1766 
1767 // convert all quadrilateral elements to triangular elements
1768 // using naive quad splitting
1770  // Create new dataset
1771  vtkSmartPointer<vtkUnstructuredGrid> vtkDataSetNoQuads =
1773  // Accumulate vector of ID lists for quads removed
1774  std::vector<std::vector<int>> removedQuadIds;
1775  // Set points
1776  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
1777  points->SetNumberOfPoints(this->getDataSet()->GetNumberOfPoints());
1778  double pt[3];
1779  for (int iPoint = 0; iPoint < this->getDataSet()->GetNumberOfPoints();
1780  iPoint++) {
1781  this->getDataSet()->GetPoint(iPoint, pt);
1782  points->SetPoint(iPoint, pt[0], pt[1], pt[2]);
1783  }
1784  vtkDataSetNoQuads->SetPoints(points);
1785 
1786  // loop through elements and remove quads by splitting into tris
1787  for (int iCell = 0; iCell < this->getDataSet()->GetNumberOfCells(); iCell++) {
1788  // is quad?
1789  if (this->getDataSet()->GetCell(iCell)->GetCellType() == VTK_QUAD) {
1790  vtkSmartPointer<vtkIdList> elmIds =
1791  this->getDataSet()->GetCell(iCell)->GetPointIds();
1792  std::vector<int> elmIdsVec = {static_cast<int>(elmIds->GetId(0)),
1793  static_cast<int>(elmIds->GetId(1)),
1794  static_cast<int>(elmIds->GetId(2)),
1795  static_cast<int>(elmIds->GetId(3))};
1796  removedQuadIds.push_back(elmIdsVec);
1797  }
1798  // only add non-quads to vtkdataset
1799  else {
1800  vtkDataSetNoQuads->InsertNextCell(
1801  this->getDataSet()->GetCell(iCell)->GetCellType(),
1802  this->getDataSet()->GetCell(iCell)->GetPointIds());
1803  }
1804  }
1805 
1806  // Add in new tris based on accumulated quad Ids
1807  for (auto elemItr = removedQuadIds.begin(); elemItr != removedQuadIds.end();
1808  elemItr++) {
1809  vtkSmartPointer<vtkIdList> triList1 = vtkSmartPointer<vtkIdList>::New();
1810  triList1->InsertNextId((*elemItr)[0]);
1811  triList1->InsertNextId((*elemItr)[1]);
1812  triList1->InsertNextId((*elemItr)[2]);
1813  vtkDataSetNoQuads->InsertNextCell(VTK_TRIANGLE, triList1);
1814 
1815  vtkSmartPointer<vtkIdList> triList2 = vtkSmartPointer<vtkIdList>::New();
1816  triList2->InsertNextId((*elemItr)[0]);
1817  triList2->InsertNextId((*elemItr)[2]);
1818  triList2->InsertNextId((*elemItr)[3]);
1819 
1820  vtkDataSetNoQuads->InsertNextCell(VTK_TRIANGLE, triList2);
1821  }
1822 
1823  return Create(vtkDataSetNoQuads, "removedQuads.vtu");
1824 }
1825 
1826 void meshBase::convertHexToTetVTK(vtkSmartPointer<vtkDataSet> meshdataSet) {
1827  vtkSmartPointer<vtkDataSetTriangleFilter> triFilter =
1829  triFilter->SetInputData(meshdataSet);
1830  triFilter->Update();
1831 
1832  dataSet = triFilter->GetOutput();
1833 }
1834 
1835 std::vector<int> meshBase::getArrayIDs(std::vector<std::string> arrayNames,
1836  bool fromPointArrays) {
1837  std::vector<int> arrayIDs(arrayNames.size());
1838  for (int i = 0; i < arrayNames.size(); ++i) {
1839  int id = IsArrayName(arrayNames[i], fromPointArrays);
1840  if (id == -1) {
1841  std::cerr << "Array " << arrayNames[i]
1842  << " not found in set of data arrays." << std::endl;
1843  exit(1);
1844  }
1845  arrayIDs[i] = id;
1846  }
1847  return arrayIDs;
1848 }
void setPointDataArray(const std::string &name, const std::vector< std::vector< double >> &data) override
register data to dataSet&#39;s point data
Definition: vtkMesh.C:896
std::vector< std::vector< nemId_t > > globalNodeIds
std::vector< std::map< nemId_t, nemId_t > > partToGlobCellMap
virtual void computeSizeField(vtkDataArray *da)=0
static std::unique_ptr< SizeFieldBase > CreateUnique(vtkDataSet *_dataSet, const std::string &method, int arrayID, double _dev_mult, bool _maxIsmin, double _sizeFactor=1.0, int _order=1)
Definition: SizeFieldGen.C:103
data_type data
Edge/face with sorted point ids (a, b, c, ...) is located at some index i in data[b], with data[b][i].first == [a, c] (for edges, third point id treated as -1).
nemId_t numPoints
number of points in mesh
Definition: meshBase.H:714
void refineMesh(const std::string &method, int arrayID, double dev_mult, bool maxIsmin, double edge_scale, const std::string &ofname, bool transferData, double sizeFactor=1., bool constrainBoundary=false)
perform sizefield-based h-refinement.
Definition: meshBase.C:1565
bool operator()(std::vector< nemId_t > lhs, std::vector< nemId_t > rhs) const
Definition: meshBase.C:1760
static meshBase * exportGmshToVtk(const std::string &fname)
construct vtkMesh from gmsh msh file (called in Create methods)
Definition: meshBase.C:409
static meshBase * exportVolToVtk(const std::string &fname)
construct vtkMesh from netgen vol file (called in Create methods)
Definition: meshBase.C:766
void setFileName(const std::string &fname)
set the file name.
Definition: meshBase.H:675
static std::vector< std::shared_ptr< meshBase > > partition(const meshBase *mbObj, int numPartitions)
mesh partitioning (with METIS)
Definition: meshBase.C:295
vtkSmartPointer< vtkDataSet > dataSet
mesh points, topology and data
Definition: meshBase.H:722
vtkSmartPointer< vtkStaticCellLocator > buildStaticCellLocator()
build locators for efficient search operations
Definition: meshBase.C:1640
static meshBase * exportPntToVtk(const std::string &fname)
construct vtkMesh from netgen vol file (called in Create methods)
Definition: meshBase.C:848
static meshBase * exportExoToVtk(const std::string &fname)
construct vtkMesh from exodusII files
Definition: meshBase.C:918
std::vector< std::map< nemId_t, nemId_t > > partToGlobNodeMap
A brief description of meshBase.
Definition: meshBase.H:64
std::size_t nemId_t
Definition: meshBase.H:51
VTKCellType getVtkCellTag(elementType et, int order) const
Definition: pntMesh.C:558
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
int getElmOrder(int id) const
Definition: pntMesh.C:547
elementType getElmType(int id) const
Definition: pntMesh.C:537
elementType elmTypeNum(std::string tag)
Convert string to EXODUS element type.
Definition: exoMesh.C:97
int IsArrayName(const std::string &name, bool pointOrCell=false) const
check for named array in vtk and return its integer id.
Definition: meshBase.C:267
void writePatchMap(const std::string &mapFile, const std::map< int, int > &patchMap)
write patch map file for roc prep (trivial identity mapping)
Definition: meshBase.C:1376
static meshBase * Create(const std::string &fname)
Construct vtkMesh from filename.
Definition: meshBase.C:78
void checkMesh(const std::string &ofname) const
<>
Definition: meshBase.C:1657
void checkMesh(std::ostream &outputStream)
Definition: MeshQuality.C:64
std::vector< std::vector< double > > integrateOverAllCells()
Integrate arrays specified by arrayIDs over all cells.
Definition: Cubature.C:697
nemId_t numCells
number of cells in mesh
Definition: meshBase.H:718
void setCellDataArray(const std::string &name, const std::vector< std::vector< double >> &data) override
register data to dataSet&#39;s cell data
Definition: vtkMesh.C:1007
std::vector< int > getArrayIDs(std::vector< std::string > arrayNames, bool fromPointArrays=false)
given array names, return corresponding ids
Definition: meshBase.C:1835
virtual std::vector< std::vector< double > > getCellVec(nemId_t id) const =0
get vector of coords of cell with id
std::vector< double > getPointCrd(int id) const
Definition: pntMesh.H:113
std::string trim_fname(const std::string &name, const std::string &ext)
vtkSmartPointer< vtkDataSet > getDataSet() const
get this meshes&#39; dataSet
Definition: meshBase.H:308
const std::string & getFileName() const
get the current file name
Definition: meshBase.H:680
nemId_t getNumberOfPoints() const
return the number of points
Definition: meshBase.H:545
void generateSizeField(const std::string &method, int arrayID, double dev_mlt, bool maxIsmin, double sizeFactor=1.0, int order=1)
generate size field based on method and given a point data array.
Definition: meshBase.C:396
vtkIdType id
id in .inp file
Definition: inpGeoMesh.C:128
sum comparison for vectors representing faces inserted into map
Definition: meshBase.H:765
VTKCellType cellType
Definition: inpGeoMesh.C:129
meshBase * convertQuads()
Definition: meshBase.C:1769
static meshBase * stitchMB(const std::vector< meshBase *> &mbObjs)
stitch together several meshBases
Definition: meshBase.C:196
std::shared_ptr< meshBase > mesh
static std::shared_ptr< meshBase > CreateShared(const std::string &fname)
Create shared ptr from fname.
Definition: meshBase.C:171
std::vector< vtkIdType > points
points given by id in .inp file
Definition: inpGeoMesh.C:133
virtual std::vector< std::vector< double > > getVertCrds() const =0
get 3 vecs with x,y and z coords
static std::unique_ptr< meshBase > CreateUnique(const std::string &fname)
create unique ptr from fname
Definition: meshBase.C:190
int diffMesh(meshBase *mesh1, meshBase *mesh2)
compares two meshBase classes.
Definition: meshBase.C:1665
std::vector< int > getElmConn(int id) const
Definition: pntMesh.H:114
void run(bool transferData, bool bndryConstraint=false)
Definition: Refine.C:161
std::vector< std::vector< double > > integrateOverMesh(const std::vector< int > &arrayIDs)
integrate arrays in arrayIDs over the mesh.
Definition: meshBase.C:387
vtkSmartPointer< vtkStaticPointLocator > buildStaticPointLocator()
build thread-safe point locator for efficient search operations
Definition: meshBase.C:1648
int getNumberOfPoints() const
Definition: pntMesh.H:109
static meshBase * extractSelectedCells(meshBase *mesh, const std::vector< nemId_t > &cellIds)
extract subset of mesh given list of cell ids and return meshBase obj
Definition: meshBase.C:226
nemId_t getNumberOfCells() const
return the number of cells
Definition: meshBase.H:550
VTKCellType e2vEMap(elementType et)
Convert EXODUS element type to VTK cell type.
Definition: exoMesh.C:50
void convertHexToTetVTK(vtkSmartPointer< vtkDataSet > meshdataSet)
Converts given hexahedral VTK dataset into tetrahedral mesh and stores it into dataSet variable...
Definition: meshBase.C:1826
void write() const override
write the mesh to file named after the private var &#39;filename&#39;.
Definition: vtkMesh.H:152
virtual std::vector< double > getPoint(nemId_t id) const =0
get point with id
void setSizeFactor(double sf)
Definition: SizeFieldGen.H:73
void wrnErrMsg(int errCode, const std::string &msg)
Logging method.
Definition: exoMesh.C:202
void writeCobalt(meshBase *surfWithPatch, const std::string &mapFile, std::ofstream &outputStream)
surfWithPatch must have patchNo array
Definition: meshBase.C:1407
static std::unique_ptr< GaussCubature > CreateUnique(vtkDataSet *_dataSet)
Definition: Cubature.C:135
int getNumberOfCells() const
Definition: pntMesh.H:110
void writeMSH(std::ofstream &outputStream)
convert to gmsh format without data
Definition: meshBase.C:1078