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.
oshGeoMesh.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 #if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
30 # define _USE_MATH_DEFINES
31 #endif
32 
33 #include "Mesh/oshGeoMesh.H"
34 
35 #include <array>
36 
37 #include <vtkCellIterator.h>
38 #include <vtkCellTypes.h>
39 #include <vtkCharArray.h>
40 #include <vtkDoubleArray.h>
41 #include <vtkFloatArray.h>
42 #include <vtkIdTypeArray.h>
43 #include <vtkIntArray.h>
44 #include <vtkLongArray.h>
45 #include <vtkLongLongArray.h>
46 #include <vtkShortArray.h>
47 #include <vtkSignedCharArray.h>
48 #include <vtkTypeFloat64Array.h>
49 #include <vtkTypeInt32Array.h>
50 #include <vtkTypeInt64Array.h>
51 #include <vtkTypeInt8Array.h>
52 #include <Omega_h_align.hpp>
53 #include <Omega_h_build.hpp>
54 #include <Omega_h_class.hpp>
55 #include <Omega_h_element.hpp>
56 #include <Omega_h_file.hpp>
57 #include <Omega_h_mesh.hpp>
58 
59 #include "AuxiliaryFunctions.H"
60 
61 namespace NEM {
62 namespace MSH {
63 
64 std::shared_ptr<Omega_h::Library> OmegaHInterface::GetLibrary() {
65  return instance->library;
66 }
67 
69  : library(std::make_shared<Omega_h::Library>()) {}
70 
71 std::shared_ptr<OmegaHInterface> OmegaHInterface::instance{new OmegaHInterface};
72 
74 
75 oshGeoMesh *oshGeoMesh::Read(const std::string &fileName,
76  Omega_h::Library *lib) {
77  if (!lib) {
78  lib = OmegaHInterface::GetLibrary().get();
79  }
80  Omega_h::Mesh oshMesh = Omega_h::read_mesh_file(fileName, lib->world());
81 
82  return new oshGeoMesh(&oshMesh, lib);
83 }
84 
86 
87 oshGeoMesh::oshGeoMesh(Omega_h::Mesh *oshMesh, Omega_h::Library *lib)
88  : geoMeshBase(osh2GM(oshMesh)), _oshMesh() {
89  if (!lib) lib = OmegaHInterface::GetLibrary().get();
90  std::cout << "oshGeoMesh constructed" << std::endl;
91  _oshMesh = std::unique_ptr<Omega_h::Mesh>(
92  oshMesh ? new Omega_h::Mesh(*oshMesh) : new Omega_h::Mesh());
93  _oshMesh->set_library(lib);
94 }
95 
96 oshGeoMesh::~oshGeoMesh() { std::cout << "oshGeoMesh destructed" << std::endl; }
97 
98 void oshGeoMesh::write(const std::string &fileName) {
99  std::string fileExt = nemAux::find_ext(fileName);
100 
101  if (fileExt == ".osh") {
102  Omega_h::binary::write(fileName, _oshMesh.get());
103  } else if (fileExt == ".msh") {
104  Omega_h::gmsh::write(fileName, _oshMesh.get());
105  } else if (fileExt == ".pvtu") {
106  Omega_h::vtk::write_parallel(fileName, _oshMesh.get());
107  } else if (fileExt == ".vtu") {
108  Omega_h::vtk::write_vtu(fileName, _oshMesh.get());
109  } else {
110  std::cerr << "Omega_h library does not support writing " << fileExt
111  << " format." << std::endl;
112  }
113 }
114 
115 void oshGeoMesh::report(std::ostream &out) const {
116  geoMeshBase::report(out);
117  out << "Family:\t"
118  << (_oshMesh->family() == OMEGA_H_SIMPLEX ? "SIMPLEX" : "HYPERCUBE")
119  << '\n';
120  out << "Dim:\t" << _oshMesh->dim() << '\n';
121 }
122 
124  auto otherOshGM = dynamic_cast<oshGeoMesh *>(otherGeoMesh);
125  if (otherOshGM) {
126  setGeoMesh(otherOshGM->getGeoMesh());
127  otherOshGM->setGeoMesh(
129  _oshMesh = std::move(otherOshGM->_oshMesh);
130  otherOshGM->resetNative();
131  } else {
132  geoMeshBase::takeGeoMesh(otherGeoMesh);
133  }
134 }
135 
138  auto mesh = getGeoMesh().mesh;
139  auto link = getGeoMesh().link;
140  auto sideSet = getGeoMesh().sideSet;
141  auto oshFamily = _oshMesh->family();
142  auto oshDim = _oshMesh->dim();
143  if (sideSet.sides && sideSet.sides->GetNumberOfCells() > 0) {
144  for (int i = 0; i <= oshDim; ++i) {
145  if (_oshMesh->has_tag(i, "class_dim")) {
146  _oshMesh->remove_tag(i, "class_dim");
147  }
148  if (_oshMesh->has_tag(i, "class_id")) {
149  _oshMesh->remove_tag(i, "class_id");
150  }
151  }
152  { // Set class_dim and class_id for dimension oshDim
153  Omega_h::HostWrite<Omega_h::ClassId> h_class_id(mesh->GetNumberOfCells());
154  auto linkArr = mesh->GetCellData()->GetArray(link.c_str());
155  if (linkArr) {
156  for (Omega_h::LO i = 0; i < h_class_id.size(); ++i) {
157  h_class_id[i] =
158  static_cast<Omega_h::ClassId>(linkArr->GetComponent(i, 0));
159  }
160  // Note we pass dummy because classify_equal_order just assumes that
161  // we pass in h_class_id in same order that we create cells.
162  // This is fine because reconstructGeo doesn't change the mesh.
163  auto dummyEqv2v = Omega_h::LOs(
164  mesh->GetNumberOfCells() *
165  Omega_h::element_degree(oshFamily, oshDim, Omega_h::VERT),
166  0);
167  Omega_h::classify_equal_order(_oshMesh.get(), oshDim, dummyEqv2v,
168  h_class_id.write());
169  }
170  }
171  { // Set class_dim and class_id for dimension oshDim - 1
172  auto it = vtkSmartPointer<vtkCellIterator>::Take(
173  sideSet.sides->NewCellIterator());
174  auto numNodes =
175  Omega_h::element_degree(oshFamily, oshDim - 1, Omega_h::VERT);
176  Omega_h::HostWrite<Omega_h::LO> ev2v(numNodes *
177  sideSet.sides->GetNumberOfCells());
178  for (int i = (it->InitTraversal(), 0); !it->IsDoneWithTraversal();
179  it->GoToNextCell(), ++i) {
180  auto ids = it->GetPointIds();
181  for (Omega_h::Int d = 0; d < numNodes; ++d) {
182  ev2v[numNodes * i + d] = ids->GetId(d);
183  }
184  }
185  Omega_h::LOs eqv2v(ev2v);
186  // If we have a non-empty sideSet, we should have a non-empty geo ent
187  // array
188  Omega_h::HostWrite<Omega_h::LO> h_class_id(
189  sideSet.sides->GetNumberOfCells());
190  auto geoEntArr = sideSet.getGeoEntArr();
191  for (Omega_h::LO i = 0; i < h_class_id.size(); ++i) {
192  h_class_id[i] = geoEntArr->GetValue(i);
193  }
194  Omega_h::classify_equal_order(_oshMesh.get(), oshDim - 1, eqv2v,
195  h_class_id.write());
196  }
197  }
198  Omega_h::finalize_classification(_oshMesh.get());
199 }
200 
201 VTKCellType getVTKTypeFromOmega_hFamilyDim(Omega_h_Family family,
202  Omega_h::Int dim) {
203  return (
204  family == OMEGA_H_SIMPLEX
205  ? (dim == 3 ? VTK_TETRA
206  : (dim == 2 ? VTK_TRIANGLE
207  : (dim == 1 ? VTK_LINE
208  : (dim == 0 ? VTK_VERTEX
209  : VTK_EMPTY_CELL))))
210  : (dim == 3 ? VTK_HEXAHEDRON
211  : (dim == 2 ? VTK_QUAD
212  : (dim == 1 ? VTK_LINE
213  : (dim == 0 ? VTK_VERTEX
214  : VTK_EMPTY_CELL)))));
215 }
216 
217 Omega_h_Family getOmega_hFamilyFromVTKType(VTKCellType vtkCellType) {
218  switch (vtkCellType) {
219  case VTK_EMPTY_CELL:
220  case VTK_VERTEX:
221  case VTK_LINE:
222  case VTK_TRIANGLE:
223  case VTK_TETRA: return OMEGA_H_SIMPLEX;
224 
225  case VTK_QUAD:
226  case VTK_HEXAHEDRON: return OMEGA_H_HYPERCUBE;
227 
228  default: {
229  std::cerr << "Omega_h supports only linear simplices and hypercubes. "
230  "VTKCellType "
231  << vtkCellType << " is not supported." << std::endl;
232  exit(1);
233  }
234  }
235 }
236 
237 Omega_h::Int getOmega_hDimFromVTKType(VTKCellType vtkCellType) {
238  switch (vtkCellType) {
239  case VTK_TETRA:
240  case VTK_HEXAHEDRON: return 3;
241 
242  case VTK_TRIANGLE:
243  case VTK_QUAD: return 2;
244 
245  case VTK_LINE: return 1;
246 
247  case VTK_VERTEX: return 0;
248  case VTK_EMPTY_CELL:
249  default: {
250  std::cerr << "Omega_h supports only linear simplices and hypercubes. "
251  "VTKCellType "
252  << vtkCellType << " is not supported." << std::endl;
253  exit(1);
254  }
255  }
256 }
257 
258 template <typename OT, typename VT>
259 void Otag2Varray(const Omega_h::TagBase *tagBase, VT *vtkArray) {
260  const Omega_h::Tag<OT> *tag = Omega_h::as<OT>(tagBase);
261  Omega_h::Int ncomps = tagBase->ncomps();
262  Omega_h::HostRead<OT> tagArray(tag->array());
263 
264  vtkArray->SetName(tagBase->name().c_str());
265  vtkArray->SetNumberOfComponents(ncomps);
266  vtkArray->SetNumberOfValues(tagArray.size());
267 
268  for (Omega_h::LO i = 0; i < tagArray.size(); ++i)
269  vtkArray->SetValue(i, tagArray.get(i));
270 }
271 
272 void getVtkDataArrayFromOmega_hTag(const Omega_h::TagBase *tagBase,
273  vtkSmartPointer<vtkDataArray> &vtkArray) {
274  switch (tagBase->type()) {
275  case OMEGA_H_I8: {
276  vtkSmartPointer<vtkTypeInt8Array> vtkArray_tmp =
278  Otag2Varray<Omega_h::I8, vtkTypeInt8Array>(tagBase, vtkArray_tmp);
279  vtkArray = vtkArray_tmp;
280  break;
281  }
282  case OMEGA_H_I32: {
283  vtkSmartPointer<vtkTypeInt32Array> vtkArray_tmp =
285  Otag2Varray<Omega_h::I32, vtkTypeInt32Array>(tagBase, vtkArray_tmp);
286  vtkArray = vtkArray_tmp;
287  break;
288  }
289  case OMEGA_H_I64: {
290  vtkSmartPointer<vtkTypeInt64Array> vtkArray_tmp =
292  Otag2Varray<Omega_h::I64, vtkTypeInt64Array>(tagBase, vtkArray_tmp);
293  vtkArray = vtkArray_tmp;
294  break;
295  }
296  case OMEGA_H_F64: {
297  vtkSmartPointer<vtkTypeFloat64Array> vtkArray_tmp =
299  Otag2Varray<Omega_h::Real, vtkTypeFloat64Array>(tagBase, vtkArray_tmp);
300  vtkArray = vtkArray_tmp;
301  break;
302  }
303  }
304 }
305 
306 int oshFace2vtkFace(int oshFace, Omega_h_Family oshFamily,
307  Omega_h::Int oshDim) {
308  switch (oshDim) {
309  case 2: return oshFace;
310  case 3:
311  switch (oshFamily) {
312  case OMEGA_H_SIMPLEX: return (oshFace + 3) % 4;
313  case OMEGA_H_HYPERCUBE:
314  switch (oshFace) {
315  case 0: return 4;
316  case 1: return 2;
317  case 2: return 1;
318  case 3: return 3;
319  case 4: return 0;
320  case 5: return 5;
321  default: return -1;
322  }
323  }
324  default: return -1;
325  }
326 }
327 
329  const std::string &geo,
330  const std::string &link) {
332 
333  if (!oshMesh || !oshMesh->is_valid()) return {vtkMesh, "", "", {}};
334  // Omega_h dimension is important to read its data.
335  //
336  // It stores 2D mesh without a z-coordinate while VTK always requires 3D. A
337  // "2D mesh" in VTK will have z-coordinates set to zero.
338  //
339  // Also, an Omega_h mesh contains the main element and all its lower-dimension
340  // constituents. E.g., a 3D mesh containing tetrahedrons will also contain the
341  // four triangles, six edges, and four vertices. When converting to VTK, we
342  // will only add the lower-dimensional elements if the classification of
343  // elements appears valid.
344  Omega_h::Int dim = oshMesh->dim();
345 
346  // An Omega_h mesh cannot have mixed elements. The family determines if the
347  // mesh is composed of simplices (tetrahedrons and triangles) or hypercubes
348  // (hexahedrons and quadrangles).
349  Omega_h_Family family = oshMesh->family();
350  VTKCellType vtk_type = getVTKTypeFromOmega_hFamilyDim(family, dim);
351 
352  auto linkName = link;
353  if (link.empty()) {
354  linkName = GEO_ENT_DEFAULT_NAME;
355  }
356  bool validSideSet = true;
357 
358  { // Add points
359  vtkSmartPointer<vtkPoints> points =
360  vtkSmartPointer<vtkPoints>::Take(vtkPoints::New(VTK_DOUBLE));
361  points->Allocate(oshMesh->nverts());
362  std::vector<double> nodes;
363 
364  Omega_h::HostRead<Omega_h::Real> h_coord(oshMesh->coords());
365 
366  for (Omega_h::LO i = 0; i < oshMesh->nverts(); ++i) {
367  points->InsertNextPoint(h_coord[i * dim + 0], h_coord[i * dim + 1],
368  dim == 2 ? 0 : h_coord[i * dim + 2]);
369  }
370  // Because we add them in order, the indices should be the same.
371  vtkMesh->SetPoints(points);
372  std::vector<size_t> nodeTags;
373  }
374 
375  { // Add cells
376  Omega_h::Int deg = Omega_h::element_degree(family, dim, OMEGA_H_VERT);
377  Omega_h::HostRead<Omega_h::LO> h_ev2v(oshMesh->ask_elem_verts());
378 
379  vtkMesh->Allocate(oshMesh->nelems());
380 
381  for (Omega_h::LO nelem = 0; nelem < oshMesh->nelems(); ++nelem) {
382  vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
383  ptIds->Allocate(deg);
384 
385  for (Omega_h::Int nvert = 0; nvert < deg; ++nvert)
386  ptIds->InsertNextId(h_ev2v[nelem * deg + nvert]);
387 
388  vtkMesh->InsertNextCell(vtk_type, ptIds);
389  }
390  }
391 
392  { // Add point data
393  for (Omega_h::Int itag = 0; itag < oshMesh->ntags(Omega_h::VERT); ++itag) {
394  vtkSmartPointer<vtkDataArray> vtkArray;
395  auto oshTagName = oshMesh->get_tag(Omega_h::VERT, itag)->name();
396  if (oshTagName != "class_dim" && oshTagName != "class_id" &&
397  oshTagName != "coordinates" && oshTagName != "global" &&
398  oshTagName != "local") {
399  getVtkDataArrayFromOmega_hTag(oshMesh->get_tag(Omega_h::VERT, itag),
400  vtkArray);
401  }
402 
403  vtkMesh->GetPointData()->AddArray(vtkArray);
404  }
405  }
406 
407  { // Add cell data
408  for (Omega_h::Int itag = 0; itag < oshMesh->ntags(dim); ++itag) {
409  vtkSmartPointer<vtkDataArray> vtkArray;
410  auto oshTagName = oshMesh->get_tag(dim, itag)->name();
411  if (oshTagName != "class_dim" && oshTagName != "class_id" &&
412  oshTagName != "global" && oshTagName != "local") {
413  getVtkDataArrayFromOmega_hTag(oshMesh->get_tag(dim, itag), vtkArray);
414  vtkMesh->GetCellData()->AddArray(vtkArray);
415  }
416  }
417  }
418 
419  // Add boundary elements (of one lower dimension), if they exist, so we don't
420  // have to reconstruct geometry.
421  auto sideSetPD = vtkSmartPointer<vtkPolyData>::New();
422  sideSetPD->SetPoints(vtkMesh->GetPoints());
423  sideSetPD->Allocate();
424  auto sideSetEntities = vtkSmartPointer<vtkIntArray>::New();
425  auto sideSetOrigCellId = vtkSmartPointer<vtkIdTypeArray>::New();
426  sideSetOrigCellId->SetNumberOfComponents(2);
427  auto sideSetCellFaceId = vtkSmartPointer<vtkIntArray>::New();
428  sideSetCellFaceId->SetNumberOfComponents(2);
429  // Map from highest dimensional entities to bounding entities of one lower
430  // dimension (by "class_id").
431  std::map<Omega_h::ClassId, std::set<Omega_h::ClassId>> entities;
432  // List of bounding entities of one lower dimension (by "class_id").
433  std::vector<Omega_h::ClassId> entities_boundary;
434  Omega_h::HostRead<Omega_h::ClassId> arr_id;
435  { // Add all entities of max dimension
436  if (oshMesh->has_tag(dim, "class_id")) {
437  arr_id = oshMesh->get_array<Omega_h::ClassId>(dim, "class_id");
438  } else {
439  validSideSet = false;
440  }
441  }
442  // Find boundary elements of dimension dim - 1. Also recover the bounding
443  // entities (of dimension dim - 1) for the entities of highest dimension
444  if (validSideSet && oshMesh->has_tag(dim - 1, "class_id") &&
445  oshMesh->has_tag(dim - 1, "class_dim")) {
446  Omega_h::HostRead<Omega_h::ClassId> arr_id_boundary =
447  oshMesh->get_array<Omega_h::ClassId>(dim - 1, "class_id");
448  Omega_h::HostRead<Omega_h::I8> arr_dim =
449  oshMesh->get_array<Omega_h::I8>(dim - 1, "class_dim");
450  auto parent = oshMesh->ask_up(dim - 1, dim);
451  Omega_h::HostRead<Omega_h::LO> parent_a2ab = parent.a2ab;
452  Omega_h::HostRead<Omega_h::LO> parent_ab2b = parent.ab2b;
453  Omega_h::HostRead<Omega_h::I8> parent_codes = parent.codes;
454  for (Omega_h::LO i = 0; i < arr_dim.size(); ++i) {
455  if (arr_dim[i] == dim - 1) {
456  bool newEntityBoundary = false;
457  auto oshEntity = arr_id_boundary[i];
458  auto entityIter = std::find(entities_boundary.begin(),
459  entities_boundary.end(), oshEntity);
460  if (entityIter == entities_boundary.end()) {
461  entities_boundary.emplace_back(oshEntity);
462  newEntityBoundary = true;
463  }
464  std::array<vtkIdType, 2> origCell{-1, -1};
465  std::array<int, 2> cellFace{-1, -1};
466  Omega_h::ClassId firstParentEnt = -1;
467  for (int j = 0; j < parent_a2ab[i + 1] - parent_a2ab[i]; ++j) {
468  auto ab = parent_ab2b[i + j];
469  auto b = parent_ab2b[ab];
470  if (j == 0) {
471  firstParentEnt = arr_id[b];
472  }
473  if (newEntityBoundary) {
474  entities[arr_id[b]].emplace(oshEntity);
475  }
476  auto code = parent_codes[ab];
477  auto oshFace = Omega_h::code_which_down(code);
478  if (j == 0 || (j == 1 && arr_id[b] < firstParentEnt)) {
479  origCell[1] = origCell[0];
480  cellFace[1] = cellFace[0];
481  origCell[0] = b;
482  cellFace[0] = oshFace2vtkFace(oshFace, family, dim);
483  } else {
484  origCell[1] = b;
485  cellFace[1] = oshFace2vtkFace(oshFace, family, dim);
486  }
487  }
488  auto side = dim == 2
489  ? vtkMesh->GetCell(origCell[0])->GetEdge(cellFace[0])
490  : vtkMesh->GetCell(origCell[0])->GetFace(cellFace[0]);
491  sideSetPD->InsertNextCell(side->GetCellType(), side->GetPointIds());
492  sideSetOrigCellId->InsertNextTypedTuple(origCell.data());
493  sideSetCellFaceId->InsertNextTypedTuple(cellFace.data());
494  sideSetEntities->InsertNextValue(oshEntity);
495  }
496  }
497  Omega_h::HostRead<Omega_h::LO> point_id = oshMesh->ask_verts_of(dim - 1);
498  // It might be more efficient to get the underlying array pointer
499  // and use std::copy.
500  auto vtkEntities = vtkSmartPointer<vtkIntArray>::New();
501  vtkEntities->SetName(linkName.c_str());
502  vtkEntities->SetNumberOfValues(vtkMesh->GetNumberOfCells());
503  for (vtkIdType i = 0; i < vtkMesh->GetNumberOfCells(); ++i) {
504  // The physical group name matches the class_id
505  vtkEntities->SetValue(i, arr_id[i]);
506  }
507  vtkMesh->GetCellData()->AddArray(vtkEntities);
508  return {vtkMesh,
509  {},
510  linkName,
511  {sideSetPD, sideSetEntities, sideSetOrigCellId, sideSetCellFaceId}};
512  } else {
513  return {vtkMesh, {}, "", {}};
514  }
515 }
516 
517 template <typename VT, typename OT>
518 void Varray2Otag(Omega_h::Mesh *oshMesh, VT *vtkArray, Omega_h::Int oshDim) {
519  Omega_h::HostWrite<OT> h_oshArray;
520  h_oshArray = Omega_h::HostWrite<OT>(vtkArray->GetNumberOfValues(),
521  vtkArray->GetClassName());
522 
523  for (vtkIdType i = 0; i < vtkArray->GetNumberOfValues(); ++i)
524  h_oshArray.set(i, vtkArray->GetValue(i));
525 
526  Omega_h::Read<OT> oshArray(h_oshArray);
527 
528  oshMesh->add_tag(oshDim, vtkArray->GetName(),
529  vtkArray->GetNumberOfComponents(), oshArray);
530 }
531 
532 template <typename VT>
533 void Varray2Otag2(Omega_h::Mesh *oshMesh, VT *vtkArray, Omega_h::Int oshDim) {
534  Varray2Otag<
535  VT, typename std::conditional<
536  sizeof(typename VT::ValueType) <= 1, Omega_h::I8,
537  typename std::conditional<
538  sizeof(typename VT::ValueType) <= 4, Omega_h::I32,
539  typename std::enable_if<sizeof(typename VT::ValueType) <= 8,
540  Omega_h::I64>::type>::type>::type>(
541  oshMesh, vtkArray, oshDim);
542 }
543 
544 void getOmega_hArrayFromVtkDataArray(Omega_h::Mesh *oshMesh,
545  vtkSmartPointer<vtkDataArray> &vtkArray,
546  Omega_h::Int oshDim) {
547  switch (vtkArray->GetDataType()) {
548  case VTK_FLOAT: {
549  vtkSmartPointer<vtkFloatArray> vtkArray_tmp =
550  vtkFloatArray::FastDownCast(vtkArray);
551  Varray2Otag<vtkFloatArray, Omega_h::Real>(oshMesh, vtkArray_tmp, oshDim);
552  vtkArray = vtkArray_tmp;
553  break;
554  }
555  case VTK_DOUBLE: {
556  vtkSmartPointer<vtkDoubleArray> vtkArray_tmp =
557  vtkDoubleArray::FastDownCast(vtkArray);
558  Varray2Otag<vtkDoubleArray, Omega_h::Real>(oshMesh, vtkArray_tmp, oshDim);
559  vtkArray = vtkArray_tmp;
560  break;
561  }
562  case VTK_CHAR: {
563  vtkSmartPointer<vtkCharArray> vtkArray_tmp =
564  vtkCharArray::FastDownCast(vtkArray);
565  Varray2Otag2<vtkCharArray>(oshMesh, vtkArray_tmp, oshDim);
566  vtkArray = vtkArray_tmp;
567  break;
568  }
569  case VTK_SIGNED_CHAR: {
570  vtkSmartPointer<vtkSignedCharArray> vtkArray_tmp =
571  vtkSignedCharArray::FastDownCast(vtkArray);
572  Varray2Otag2<vtkSignedCharArray>(oshMesh, vtkArray_tmp, oshDim);
573  vtkArray = vtkArray_tmp;
574  break;
575  }
576  case VTK_SHORT: {
577  vtkSmartPointer<vtkShortArray> vtkArray_tmp =
578  vtkShortArray::FastDownCast(vtkArray);
579  Varray2Otag2<vtkShortArray>(oshMesh, vtkArray_tmp, oshDim);
580  vtkArray = vtkArray_tmp;
581  break;
582  }
583  case VTK_INT: {
584  vtkSmartPointer<vtkIntArray> vtkArray_tmp =
585  vtkIntArray::FastDownCast(vtkArray);
586  Varray2Otag2<vtkIntArray>(oshMesh, vtkArray_tmp, oshDim);
587  vtkArray = vtkArray_tmp;
588  break;
589  }
590  case VTK_LONG: {
591  vtkSmartPointer<vtkLongArray> vtkArray_tmp =
592  vtkLongArray::FastDownCast(vtkArray);
593  Varray2Otag2<vtkLongArray>(oshMesh, vtkArray_tmp, oshDim);
594  vtkArray = vtkArray_tmp;
595  break;
596  }
597  case VTK_ID_TYPE: {
598  vtkSmartPointer<vtkIdTypeArray> vtkArray_tmp =
599  vtkIdTypeArray::FastDownCast(vtkArray);
600  Varray2Otag2<vtkIdTypeArray>(oshMesh, vtkArray_tmp, oshDim);
601  vtkArray = vtkArray_tmp;
602  break;
603  }
604  case VTK_LONG_LONG: {
605  vtkSmartPointer<vtkLongLongArray> vtkArray_tmp =
606  vtkLongLongArray::FastDownCast(vtkArray);
607  Varray2Otag2<vtkLongLongArray>(oshMesh, vtkArray_tmp, oshDim);
608  vtkArray = vtkArray_tmp;
609  break;
610  }
611  /*
612  case VTK_VOID:
613  case VTK_BIT:
614  case VTK_UNSIGNED_CHAR:
615  case VTK_UNSIGNED_SHORT:
616  case VTK_UNSIGNED_INT:
617  case VTK_UNSIGNED_LONG:
618  case VTK_STRING:
619  case VTK_OPAQUE:
620  case VTK_UNSIGNED_LONG_LONG:
621  case VTK___INT64:
622  case VTK_UNSIGNED___INT64:
623  case VTK_VARIANT:
624  case VTK_OBJECT:
625  case VTK_UNICODE_STRING:
626  */
627  default: {
628  std::cerr << "VTK type " << vtkArray->GetDataTypeAsString()
629  << " is not supported as an Omega_h type." << std::endl;
630  exit(1);
631  }
632  }
633 }
634 
635 Omega_h::Mesh *oshGeoMesh::GM2osh(const GeoMesh &geoMesh,
636  Omega_h::Library *lib) {
637  if (!lib) {
638  lib = OmegaHInterface::GetLibrary().get();
639  }
640  auto *oshMesh = new Omega_h::Mesh(lib);
641 
642  auto vtkMesh = geoMesh.mesh;
643  if (vtkMesh->GetNumberOfCells() == 0) {
644  return oshMesh;
645  }
646  auto link = geoMesh.link;
647  auto sideSet = geoMesh.sideSet;
648  vtkSmartPointer<vtkCellTypes> ct = vtkSmartPointer<vtkCellTypes>::New();
649  vtkMesh->GetCellTypes(ct);
650  if (ct->GetNumberOfTypes() != 1) {
651  std::cerr << "Error: Omega_h mesh does not support mixed meshes. Received "
652  "mesh with "
653  << ct->GetNumberOfTypes() << " different cell types."
654  << std::endl;
655  exit(1);
656  }
657  Omega_h_Family oshFamily =
658  getOmega_hFamilyFromVTKType(static_cast<VTKCellType>(ct->GetCellType(0)));
659  Omega_h::Int oshDim =
660  getOmega_hDimFromVTKType(static_cast<VTKCellType>(ct->GetCellType(0)));
661 
662  { // Add points and cells (needs both for build_from_elems_and_coords)
663  // Add points
664  Omega_h::HostWrite<Omega_h::Real> h_oshCoords(oshDim *
665  vtkMesh->GetNumberOfPoints());
666  vtkSmartPointer<vtkPoints> vtkPoints = vtkMesh->GetPoints();
667 
668  std::array<double, 3> point{};
669  for (vtkIdType i = 0; i < vtkPoints->GetNumberOfPoints(); ++i) {
670  vtkPoints->GetPoint(i, point.data());
671 
672  h_oshCoords[i * oshDim] = point[0];
673  h_oshCoords[i * oshDim + 1] = point[1];
674  if (oshDim >= 3) h_oshCoords[i * oshDim + 2] = point[2];
675  }
676 
677  Omega_h::Reals oshCoords(h_oshCoords);
678 
679  { // Add cells of dimension oshDim
680  auto it = vtkMesh->NewCellIterator();
681  auto numNodes = Omega_h::element_degree(oshFamily, oshDim, Omega_h::VERT);
682  Omega_h::HostWrite<Omega_h::LO> ev2v(numNodes *
683  vtkMesh->GetNumberOfCells());
684  int i = 0;
685  for (it->InitTraversal(); !it->IsDoneWithTraversal();
686  it->GoToNextCell()) {
687  auto ids = it->GetPointIds();
688  for (Omega_h::Int d = 0; d < numNodes; ++d) {
689  ev2v[numNodes * i + d] = ids->GetId(d);
690  }
691  ++i;
692  }
693  it->Delete();
694  Omega_h::LOs eqv2v(ev2v);
695  Omega_h::build_from_elems_and_coords(oshMesh, oshFamily, oshDim, eqv2v,
696  Omega_h::Reals(h_oshCoords));
697  if (!link.empty()) {
698  Omega_h::HostWrite<Omega_h::ClassId> h_class_id(
699  vtkMesh->GetNumberOfCells());
700  auto linkArr = vtkMesh->GetCellData()->GetArray(link.c_str());
701  if (linkArr) {
702  for (i = 0; i < h_class_id.size(); ++i) {
703  h_class_id[i] =
704  static_cast<Omega_h::ClassId>(linkArr->GetComponent(i, 0));
705  }
706  Omega_h::classify_equal_order(oshMesh, oshDim, eqv2v,
707  h_class_id.write());
708  }
709  }
710  }
711  // Add cells of dimension oshDim - 1 from the sideSet
712  if (sideSet.sides && sideSet.sides->GetNumberOfCells() > 0) {
713  auto it = sideSet.sides->NewCellIterator();
714  auto numNodes =
715  Omega_h::element_degree(oshFamily, oshDim - 1, Omega_h::VERT);
716  Omega_h::HostWrite<Omega_h::LO> ev2v(numNodes *
717  sideSet.sides->GetNumberOfCells());
718  int i = 0;
719  for (it->InitTraversal(); !it->IsDoneWithTraversal();
720  it->GoToNextCell()) {
721  auto ids = it->GetPointIds();
722  for (Omega_h::Int d = 0; d < numNodes; ++d) {
723  ev2v[numNodes * i + d] = ids->GetId(d);
724  }
725  ++i;
726  }
727  it->Delete();
728  Omega_h::LOs eqv2v(ev2v);
729  // If we have a non-empty sideSet, we should have a non-empty geo ent
730  // array
731  Omega_h::HostWrite<Omega_h::LO> h_class_id(
732  sideSet.sides->GetNumberOfCells());
733  auto geoEntArr = geoMesh.sideSet.getGeoEntArr();
734  for (i = 0; i < h_class_id.size(); ++i) {
735  h_class_id[i] = geoEntArr->GetValue(i);
736  }
737  Omega_h::classify_equal_order(oshMesh, oshDim - 1, eqv2v,
738  h_class_id.write());
739  }
740  }
741 
742  { // Add point data
743  for (int a = 0; a < vtkMesh->GetPointData()->GetNumberOfArrays(); ++a) {
744  vtkSmartPointer<vtkDataArray> da = vtkMesh->GetPointData()->GetArray(a);
745  if (da) {
746  getOmega_hArrayFromVtkDataArray(oshMesh, da, Omega_h::VERT);
747  }
748  }
749  }
750 
751  { // Add cell data
752  for (int a = 0; a < vtkMesh->GetCellData()->GetNumberOfArrays(); ++a) {
753  vtkSmartPointer<vtkDataArray> da = vtkMesh->GetCellData()->GetArray(a);
754  if (da && strcmp(da->GetName(), link.c_str()) != 0) {
755  getOmega_hArrayFromVtkDataArray(oshMesh, da, oshDim);
756  }
757  }
758  }
759  Omega_h::finalize_classification(oshMesh);
760  return oshMesh;
761 }
762 
763 void oshGeoMesh::setOshMesh(Omega_h::Mesh *oshMesh) {
764  this->setGeoMesh(osh2GM(oshMesh, getGeoMesh().geo, getGeoMesh().link));
765  _oshMesh = std::unique_ptr<Omega_h::Mesh>(new Omega_h::Mesh(*oshMesh));
766 }
767 
769  _oshMesh = std::unique_ptr<Omega_h::Mesh>(GM2osh(getGeoMesh()));
770 }
771 
772 } // namespace MSH
773 } // namespace NEM
A concrete implementation of geoMeshBase representing a Omega_h::Mesh.
Definition: oshGeoMesh.H:79
int oshFace2vtkFace(int oshFace, Omega_h_Family oshFamily, Omega_h::Int oshDim)
Definition: oshGeoMesh.C:306
void setOshMesh(Omega_h::Mesh *oshMesh)
Set the mesh to an existing Omega_h::Mesh.
Definition: oshGeoMesh.C:763
virtual void report(std::ostream &out) const =0
Print a report about the mesh.
Definition: geoMeshBase.C:97
static std::shared_ptr< Omega_h::Library > GetLibrary()
Initialize Omega_h.
Definition: oshGeoMesh.C:64
std::vector< std::pair< vtkIdType, std::vector< double > > > nodes
Each entry stores (node ID in .inp file, coordinates)
Definition: inpGeoMesh.C:139
Omega_h_Family getOmega_hFamilyFromVTKType(VTKCellType vtkCellType)
Definition: oshGeoMesh.C:217
vtkSmartPointer< vtkUnstructuredGrid > mesh
Definition: geoMeshBase.H:419
void Otag2Varray(const Omega_h::TagBase *tagBase, VT *vtkArray)
Definition: oshGeoMesh.C:259
geoMeshBase * Read(const std::string &fileName)
Read a mesh from file.
std::unique_ptr< Omega_h::Mesh > _oshMesh
Definition: oshGeoMesh.H:140
virtual void reconstructGeo()
Construct the geometry from the mesh alone.
static constexpr auto GEO_ENT_DEFAULT_NAME
Definition: geoMeshBase.H:446
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
void reconstructGeo() override
Construct the geometry from the mesh alone.
Definition: oshGeoMesh.C:136
STL namespace.
void write(const std::string &fileName) override
Write mesh to file.
Definition: oshGeoMesh.C:98
void resetNative() override
Definition: oshGeoMesh.C:768
static GeoMesh osh2GM(Omega_h::Mesh *oshMesh, const std::string &geo="", const std::string &link="")
Definition: oshGeoMesh.C:328
void setGeoMesh(const geoMeshBase::GeoMesh &geoMesh)
Set the underlying geometry object.
Definition: geoMeshBase.H:538
std::string find_ext(const std::string &fname)
static std::shared_ptr< OmegaHInterface > instance
Definition: oshGeoMesh.H:71
void getVtkDataArrayFromOmega_hTag(const Omega_h::TagBase *tagBase, vtkSmartPointer< vtkDataArray > &vtkArray)
Definition: oshGeoMesh.C:272
void takeGeoMesh(geoMeshBase *otherGeoMesh) override
Take the GeoMesh of another geoMeshBase.
Definition: oshGeoMesh.C:123
void getOmega_hArrayFromVtkDataArray(Omega_h::Mesh *oshMesh, vtkSmartPointer< vtkDataArray > &vtkArray, Omega_h::Int oshDim)
Definition: oshGeoMesh.C:544
~oshGeoMesh() override
Definition: oshGeoMesh.C:96
std::shared_ptr< meshBase > mesh
oshGeoMesh()
Create a oshGeoMesh from a file.
Definition: oshGeoMesh.C:85
VTKCellType getVTKTypeFromOmega_hFamilyDim(Omega_h_Family family, Omega_h::Int dim)
Definition: oshGeoMesh.C:201
std::vector< vtkIdType > points
points given by id in .inp file
Definition: inpGeoMesh.C:133
void report(std::ostream &out) const override
Print a report about the mesh.
Definition: oshGeoMesh.C:115
vtkSmartPointer< vtkIntArray > getGeoEntArr() const
Definition: geoMeshBase.C:252
static Omega_h::Mesh * GM2osh(const GeoMesh &geoMesh, Omega_h::Library *lib=nullptr)
Definition: oshGeoMesh.C:635
vtkStandardNewMacro(exoGeoMesh)
Definition: exoGeoMesh.C:247
std::shared_ptr< Omega_h::Library > library
Definition: oshGeoMesh.H:72
Omega_h::Int getOmega_hDimFromVTKType(VTKCellType vtkCellType)
Definition: oshGeoMesh.C:237
void Varray2Otag2(Omega_h::Mesh *oshMesh, VT *vtkArray, Omega_h::Int oshDim)
Definition: oshGeoMesh.C:533
management class for Omega_h::Library
Definition: oshGeoMesh.H:49
abstract class to specify geometry and mesh data
Definition: geoMeshBase.H:102
void Varray2Otag(Omega_h::Mesh *oshMesh, VT *vtkArray, Omega_h::Int oshDim)
Definition: oshGeoMesh.C:518
const GeoMesh & getGeoMesh() const
Get the underlying geometry object.
Definition: geoMeshBase.H:533
virtual void takeGeoMesh(geoMeshBase *otherGeoMesh)
Take the GeoMesh of another geoMeshBase.
Definition: geoMeshBase.C:104