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.
ConversionDriver.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 *******************************************************************************/
30 
31 #include <algorithm>
32 #include <iostream>
33 #include <map>
34 #include <set>
35 #include <string>
36 #include <vector>
37 #include <utility>
38 
39 #include <vtkCell.h>
40 #include <vtkCellData.h>
41 #include <vtkIdList.h>
42 #include <vtkModelMetadata.h>
43 #include <vtkPolyData.h>
44 #include <vtkStringArray.h>
45 #include <vtkUnstructuredGrid.h>
46 
47 #include "Mesh/cobalt.H"
48 #include "MeshOperation/meshSrch.H"
49 #include "Mesh/geoMeshFactory.H"
50 
51 namespace NEM {
52 namespace DRV {
53 
55  const int &ndeIdOffset, const int &elmIdOffset,
56  int &ins, int &ieb, int &iss, std::string mshName,
57  const bool &usePhys, int &ndeIdOffset_local,
58  int &elmIdOffset_local,
59  const bool &makeFreeSurfSS,
60  const bool &splitTopBotSS,
61  std::vector<std::string> sideSetNames) {
62  // add nodes to database
63  for (nemId_t iNde = 0; iNde < mb->getNumberOfPoints(); ++iNde)
64  em->addNde(mb->getPoint(iNde));
65 
66  // node coordinate to one nodeSet
68  ns.id = ++ins;
69  ns.nNde = mb->getNumberOfPoints();
70  ns.name = mshName;
71  ns.ndeIdOffset = ndeIdOffset;
72  for (int iNde = 0; iNde < ns.nNde; iNde++) {
73  ns.ndeIds.emplace_back(iNde + 1);
74  }
75  em->addNdeSet(ns);
76  ndeIdOffset_local += ns.nNde;
77 
78  // add element blocks
79 
80  // Element bucket where they will be sorted.
81  // Outer layer: Specifies grouping, such as physical groups. The 0th index
82  // is reserved for elements without a group.
83  // Inner layer: Sorted by element type. The 0th index is reserved for
84  // unsupported elements. The current support respects the ordering of the
85  // NEM::MSH::EXOMesh::elementType enum:
86  // OTHER, TRIANGLE, QUAD, TETRA, HEX
87  std::map<int, std::map<NEM::MSH::EXOMesh::elementType, std::vector<int>>>
88  elmBucket;
89  // map for VTK to EXO element ids
90  std::map<int, int> v2e_elemID_map;
91 
92  std::vector<double> grpIds(mb->getNumberOfCells(), 0.0);
93  if (usePhys) mb->getCellDataArray("PhysGrpId", grpIds);
94 
95  bool is3D = false;
96  // Loop through all elements
97  for (int iElm = 0; iElm < mb->getNumberOfCells(); iElm++) {
98  VTKCellType vtkType =
99  static_cast<VTKCellType>(mb->getDataSet()->GetCellType(iElm));
102 
103  // set the dimension of Exo database based on present elements
104  if (!is3D) {
105  if (exoType == NEM::MSH::EXOMesh::elementType::TETRA ||
108  is3D = true;
109  em->setDimension(3);
110  }
111  }
112 
113  elmBucket[static_cast<int>(grpIds[iElm])][exoType].emplace_back(iElm);
114  }
115 
116  // sanity check
117  int numUnsupported = 0;
118  for (const auto &elmGroup : elmBucket)
119  if (elmGroup.second.count(NEM::MSH::EXOMesh::elementType::OTHER) != 0)
120  numUnsupported +=
121  elmGroup.second.at(NEM::MSH::EXOMesh::elementType::OTHER).size();
122  if (numUnsupported > 0) {
123  std::cerr << "WARNING: Detected " << numUnsupported
124  << " unsupported elements.\n";
125  throw;
126  }
127 
128  // for each group and supported type, if existent, add an element block
129  for (const auto &elmGroup : elmBucket) {
130  for (const auto &elmIds : elmGroup.second) {
131  if (elmIds.second.empty()) continue; // skip if empty
132 
134  eb.id = ++ieb;
135  eb.ndeIdOffset = ndeIdOffset;
136  eb.nElm = elmIds.second.size();
137 
138  // populate VTK to EXO element id map for side set implementation
139  for (int i = 0; i < elmIds.second.size(); ++i) {
140  int vtkId = elmIds.second[i];
141  int exoId = i + elmIdOffset_local + 1;
142  v2e_elemID_map.insert(std::pair<int, int>(vtkId, exoId));
143  }
144 
145  if (usePhys)
146  eb.name = mshName + "_PhysGrp_" + std::to_string(ieb);
147  else
148  eb.name = mshName + "_" + std::to_string(ieb);
149 
150  switch (elmIds.first) {
152  std::cout << "Number of triangular elements = " << eb.nElm << "\n";
153  eb.ndePerElm = 3;
155  break;
157  std::cout << "Number of quadrilateral elements = " << eb.nElm << "\n";
158  eb.ndePerElm = 4;
160  break;
162  std::cout << "Number of tetrahedral elements = " << eb.nElm << "\n";
163  eb.ndePerElm = 4;
165  break;
167  std::cout << "Number of hexahedral elements = " << eb.nElm << "\n";
168  eb.ndePerElm = 8;
170  break;
172  std::cout << "Number of wedge elements = " << eb.nElm << "\n";
173  eb.ndePerElm = 6;
175  break;
176  case NEM::MSH::EXOMesh::elementType::OTHER:
177  default:
178  std::cerr << "WARNING: Processing unsupported element. Previous "
179  "sanity check failed!\n";
180  throw;
181  }
182 
183  eb.conn.reserve(eb.nElm * eb.ndePerElm);
184  vtkIdList *nids = vtkIdList::New();
185  for (const auto &iElm : elmIds.second) {
186  mb->getDataSet()->GetCellPoints(iElm, nids);
187  for (int in = 0; in < eb.ndePerElm; ++in) {
188  // offset node ids by 1
189  eb.conn.emplace_back(nids->GetId(in) + 1);
190  }
191  }
192 
193  // DEBUG
194  // std::cout << "Min node index = "
195  // << *min_element(eb.conn.begin(), eb.conn.end()) << "\n"
196  // << "Max node index = "
197  // << *max_element(eb.conn.begin(), eb.conn.end()) << "\n";
198  // std::cout << "Starting node offset = " << ndeIdOffset << std::endl;
199 
200  em->addElmBlk(eb);
201  elmIdOffset_local += eb.nElm;
202  }
203  }
204 
205  // add side set of the external surface(s) (free surface)
206  if (makeFreeSurfSS) {
207  freeSurfaceSideSet(mb, em, elmIdOffset, v2e_elemID_map, splitTopBotSS,
208  sideSetNames);
209  }
210 
211  // add side sets
212  if (mb->getMetadata()) {
213  // get side set metadata
214  vtkSmartPointer<vtkModelMetadata> metadata = mb->getMetadata();
215  vtkSmartPointer<vtkStringArray> sdeSetNames = metadata->GetSideSetNames();
216  int *sdeSetElmLst = metadata->GetSideSetElementList();
217  int *sdeSetSdeLst = metadata->GetSideSetSideList();
218  int *sdeSetSze = metadata->GetSideSetSize();
219 
220  for (int iSS = 0; iSS < metadata->GetNumberOfSideSets(); iSS++) {
222  ss.id = ++iss;
223  ss.name = sdeSetNames->GetValue(iSS);
224  ss.nSde = sdeSetSze[iSS];
225  ss.elmIds.assign(sdeSetElmLst, sdeSetElmLst + sdeSetSze[iSS]);
226  ss.sdeIds.assign(sdeSetSdeLst, sdeSetSdeLst + sdeSetSze[iSS]);
227  ss.elmIdOffset = elmIdOffset;
228  em->addSdeSet(ss);
229 
230  // Advance pointer for reading next side set.
231  sdeSetElmLst += sdeSetSze[iSS];
232  sdeSetSdeLst += sdeSetSze[iSS];
233  }
234  }
235 }
236 void ConversionDriver::genExo(std::vector<meshBase *> meshes,
237  const std::string &fname) {
238  bool usePhys = false;
239  bool makeFreeSurfSS = false;
240  bool splitTopBotSS = false;
241  std::vector<std::string> sideSetNames;
242 
243  std::cout << "Warning: this method does not support physical groups."
244  << std::endl;
245  std::cout << "Warning: this method does not support post-processing."
246  << std::endl;
247 
248  int nMsh = meshes.size();
249 
250  // sanity check
251  if (nMsh == 0) {
252  std::cerr << "Error: At least one mesh should be provided!\n";
253  exit(-1);
254  }
255 
256  // starting conversion operation
257  auto em = new NEM::MSH::EXOMesh::exoMesh(fname);
258 
259  // reading meshes
260  int ndeIdOffset = 0;
261  int elmIdOffset = 0;
262  int ins = 0;
263  int ieb = 0;
264  int iss = 0;
265  int ndeIdOffset_local = 0;
266  int elmIdOffset_local = 0;
267 
268  std::string mshName;
269 
270  for (auto itrMsh = meshes.begin(); itrMsh != meshes.end(); itrMsh++) {
271  mshName = (*itrMsh)->getFileName();
272  genExo(*itrMsh, em, ndeIdOffset, elmIdOffset, ins, ieb, iss, mshName,
273  usePhys, ndeIdOffset_local, elmIdOffset_local, makeFreeSurfSS,
274  splitTopBotSS, sideSetNames);
275  }
276 
277  // writing the file
278  em->write();
279  em->report();
280 
281  em->mergeNodes();
282 
283  // clean up
284  delete em;
285 }
286 
288  const meshBase *mb, NEM::MSH::EXOMesh::exoMesh *em, int elmIdOffset,
289  std::map<int, int> v2e_elemID_map, bool splitTopBotSS,
290  std::vector<std::string> sideSetNames) {
291  std::cout << "Creating side set from free surface." << std::endl;
292 
293  std::vector<std::pair<int, int>> freeSurfCellEdge;
294  std::vector<std::pair<int, int>> hexFreeSurfCellFace;
295  std::vector<std::pair<int, int>> wedgeFreeSurfCellFace;
296  std::vector<std::pair<int, int>> tetraFreeSurfCellFace;
297  std::vector<int> elementIds1, elementIds2, elementIds3, sideIds1, sideIds2,
298  sideIds3;
299  std::vector<std::vector<int>> splitElemIds, splitSideIds;
300 
301  // Maps for VTK to EXO face id conversion for hex and wedge
302  std::map<int, int> v2e_hexFace_map = {{1, 4}, {2, 2}, {3, 1},
303  {4, 3}, {5, 5}, {6, 6}};
304  std::map<int, int> v2e_wedgeFace_map = {
305  {1, 4}, {2, 5}, {3, 1}, {4, 2}, {5, 3}};
306  std::map<int, int> v2e_tetraFace_map = {{1, 1}, {2, 2}, {3, 3}, {4, 4}};
307 
308  // acquiring dataset
309  vtkSmartPointer<vtkDataSet> ds = mb->getDataSet();
310  if (!ds) {
311  std::cerr << "No dataset is associated to the meshbase." << std::endl;
312  throw;
313  }
314  bool tetWarning = false;
315  // loop through cells and obtain different quantities needed
316  int nCl = ds->GetNumberOfCells();
317  for (int cell_i = 0; cell_i < nCl; cell_i++) {
318  vtkCell *vc = ds->GetCell(cell_i);
319  if (vc->GetCellDimension() == 2) {
320  // for 2D cells
321  int ne = vc->GetNumberOfEdges();
322  for (int edge_i = 0; edge_i < ne; edge_i++) {
323  vtkCell *ve = vc->GetEdge(edge_i);
324  vtkIdList *pidl = ve->GetPointIds();
325 
326  std::pair<int, int> adjPair;
327 
328  // getting neighbour list
329  vtkSmartPointer<vtkIdList> cidl = vtkSmartPointer<vtkIdList>::New();
330  ds->GetCellNeighbors(cell_i, pidl, cidl);
331  if (cidl->GetNumberOfIds() == 0) {
332  adjPair.first = cell_i;
333  adjPair.second = edge_i + 1;
334  freeSurfCellEdge.push_back(adjPair);
335  }
336  }
337  } else if (vc->GetCellDimension() == 3) {
338  // for 3D cells
339  int nfc = vc->GetNumberOfFaces();
340  for (int face_i = 0; face_i < nfc; face_i++) {
341  vtkCell *vf = vc->GetFace(face_i);
342  vtkIdList *facePoints = vf->GetPointIds();
343 
344  std::pair<int, int> adjPair;
345 
346  // getting neighbour list
347  vtkSmartPointer<vtkIdList> cidl = vtkSmartPointer<vtkIdList>::New();
348  ds->GetCellNeighbors(cell_i, facePoints, cidl);
349  if (cidl->GetNumberOfIds() == 0) {
350  adjPair.first = cell_i;
351  adjPair.second = face_i + 1;
352  if (nfc == 6) hexFreeSurfCellFace.push_back(adjPair);
353  if (nfc == 5) wedgeFreeSurfCellFace.push_back(adjPair);
354  if (nfc == 4) {
355  tetraFreeSurfCellFace.push_back(adjPair);
356  if (splitTopBotSS && tetWarning == false) {
357  std::cerr
358  << "Warning: Tetrahedral element found on free surface.\n"
359  << " Cannot split top and bottom into separate side "
360  "sets.\n"
361  << " Creating single side set." << std::endl;
362  splitTopBotSS = false;
363  tetWarning = true;
364  }
365  }
366  }
367  }
368  }
369  }
370 
371  if (em->getDimension() == 3) {
372  // Iterate through *freeSurfCellFace to make lists of elements/faces
373  // Hexahedra
374  for (int i = 0; i < hexFreeSurfCellFace.size(); i++) {
375  int exoId = v2e_elemID_map[hexFreeSurfCellFace[i].first];
376  int sId = v2e_hexFace_map[hexFreeSurfCellFace[i].second];
377 
378  if (splitTopBotSS) {
379  if (sId == 5) {
380  // Top
381  elementIds2.push_back(exoId);
382  sideIds2.push_back(sId);
383  } else if (sId == 6) {
384  // Bottom
385  elementIds3.push_back(exoId);
386  sideIds3.push_back(sId);
387  } else {
388  elementIds1.push_back(exoId);
389  sideIds1.push_back(sId);
390  }
391  } else {
392  elementIds1.push_back(exoId);
393  sideIds1.push_back(sId);
394  }
395  }
396  // Wedges
397  for (int i = 0; i < wedgeFreeSurfCellFace.size(); i++) {
398  int exoId = v2e_elemID_map[wedgeFreeSurfCellFace[i].first];
399  int sId = v2e_wedgeFace_map[wedgeFreeSurfCellFace[i].second];
400 
401  if (splitTopBotSS) {
402  if (sId == 4) {
403  // Top
404  elementIds2.push_back(exoId);
405  sideIds2.push_back(sId);
406  } else if (sId == 5) {
407  // Bottom
408  elementIds3.push_back(exoId);
409  sideIds3.push_back(sId);
410  } else {
411  elementIds1.push_back(exoId);
412  sideIds1.push_back(sId);
413  }
414  } else {
415  elementIds1.push_back(exoId);
416  sideIds1.push_back(sId);
417  }
418  }
419  // Tetrahedra
420  for (int i = 0; i < tetraFreeSurfCellFace.size(); i++) {
421  int exoId = v2e_elemID_map[tetraFreeSurfCellFace[i].first];
422  int sId = v2e_tetraFace_map[tetraFreeSurfCellFace[i].second];
423  elementIds1.push_back(exoId);
424  sideIds1.push_back(sId);
425  }
426  }
427 
428  if (em->getDimension() == 2) {
429  // Iterate through freeSurfCellEdge to make lists of elements/faces
430  for (int i = 0; i < freeSurfCellEdge.size(); i++) {
431  // map from VTK element id to EXO element id
432  int exoId = v2e_elemID_map[freeSurfCellEdge[i].first];
433  elementIds1.push_back(exoId);
434  sideIds1.push_back(freeSurfCellEdge[i].second);
435  }
436  }
437 
438  if (splitTopBotSS && em->getDimension() == 3) {
439  splitElemIds = {elementIds1, elementIds2, elementIds3};
440  splitSideIds = {sideIds1, sideIds2, sideIds3};
441  } else {
442  splitElemIds = {elementIds1};
443  splitSideIds = {sideIds1};
444  }
445 
446  for (int i = 0; i < splitElemIds.size(); ++i) {
448 
449  // TODO: fix names, still not working correctly
450  if (sideSetNames.size() == 1 && splitElemIds.size() == 1) {
451  ss.name = sideSetNames[i];
452  }
453  if (sideSetNames.size() == 0) {
454  std::cout << "side set names size is zero" << std::endl;
455  ss.name = "side_set_000000" + std::to_string(i + 1);
456  }
457  if (sideSetNames.size() > 0 && sideSetNames.size() < 3 && splitTopBotSS) {
458  std::cerr << "Error: Expected 3 'Side Set Names', found "
459  << sideSetNames.size() << std::endl;
460  exit(1);
461  }
462  if (sideSetNames.size() == 3) {
463  ss.name = sideSetNames[i];
464  }
465 
466  // ss.id = ++iss;
467  ss.id = i + 1;
468  ss.nSde = (int)splitSideIds[i].size();
469  ss.elmIds = splitElemIds[i];
470  ss.sdeIds = splitSideIds[i];
471  ss.elmIdOffset = elmIdOffset;
472  em->addSdeSet(ss);
473  }
474 }
475 
476 void ConversionDriver::procExo(const jsoncons::json &ppJson,
477  const std::string &fname,
479  // converting to mesh base for geometric inquiry
480  meshBase *mb = meshBase::Create(fname);
481 
482  // performing requested operation
483  std::string opr = ppJson.get_with_default("Operation", "");
484  if (opr == "Material Assignment") {
485  meshSrch *ms = meshSrch::Create(mb);
486  // gathering information about all zones
487  // if densities are defined, materials with higher density will be
488  // prioritized
489  bool appDen = ppJson.get_with_default("Apply Density", false);
490 
491  std::map<std::pair<double, std::string>, std::set<int>> zoneGeom;
492 
493  // loop over all zones
494  for (const auto &zone : ppJson["Zones"].array_range()) {
495  // assuming first element is zone information keyed by zone name
496  // that we do not care about yet
497  std::string matName = zone[0].get_with_default("Material Name", "N/A");
498  std::string shape = zone[0].get_with_default("Shape", "N/A");
499  std::cout << "Processing zone: " << zone.object_range().begin()->key()
500  << " Material: " << matName << " Shape: " << shape;
501 
502  double density = 1.0; // Default density is 1.0
503  if (appDen) {
504  density = zone[0].get_with_default("Density", 1.0);
505  std::cout << " Density: " << density;
506  }
507  std::cout << std::endl;
508 
509  std::vector<nemId_t> lst;
510  if (shape == "Box") {
511  // Box shape. Requires 3-vector of Min and Max in x, y, and z, resp.
512  std::vector<double> bb;
513  bb.push_back(zone[0]["Params"]["Min"][0].as<double>());
514  bb.push_back(zone[0]["Params"]["Max"][0].as<double>());
515  bb.push_back(zone[0]["Params"]["Min"][1].as<double>());
516  bb.push_back(zone[0]["Params"]["Max"][1].as<double>());
517  bb.push_back(zone[0]["Params"]["Min"][2].as<double>());
518  bb.push_back(zone[0]["Params"]["Max"][2].as<double>());
519 
520  ms->FindCellsWithinBounds(bb, lst, true);
521  } else if (shape == "STL") {
522  // STL shape. Only supports Tri surface.
523  // Node Coordinates are given as 3-vector in an array.
524  // Connectivities are given as 3-vectors in an array.
525  // Tris are 0-indexed.
526  std::vector<std::vector<double>> crds;
527  std::vector<std::vector<vtkIdType>> conns;
528  for (const auto &crd :
529  zone[0]["Params"]["Node Coordinates"].array_range())
530  crds.push_back(crd.as<std::vector<double>>());
531  for (const auto &conn :
532  zone[0]["Params"]["Connectivities"].array_range())
533  conns.push_back(conn.as<std::vector<vtkIdType>>());
534 
535  ms->FindCellsInTriSrf(crds, conns, lst);
536  } else if (shape == "Sphere") {
537  // Sphere shape.
538  // Center is a 3-vector in an array.
539  // Radius is a double.
540  std::vector<double> center =
541  zone[0]["Params"]["Center"].as<std::vector<double>>();
542  auto radius = zone[0]["Params"]["Radius"].as<double>();
543 
544  ms->FindCellsInSphere(center, radius, lst);
545  } else {
546  std::cerr << "WARNING: Skipping unknown zone shape: " << shape
547  << std::endl;
548  continue;
549  }
550 
551  if (zone[0].contains("Only From Block")) {
552  std::string blkName = zone[0]["Only From Block"].as<std::string>();
553 
554  std::vector<std::string> elmBlkNames = em->getElmBlkNames();
555  auto elmBlkName =
556  std::find(elmBlkNames.begin(), elmBlkNames.end(), blkName);
557  if (elmBlkName == elmBlkNames.end()) {
558  std::cerr << "WARNING: Only From Block " << blkName
559  << " matches no available blocks. Continuing with no "
560  "restriction.\n";
561  } else {
562  std::vector<int> lst_int(lst.begin(), lst.end());
563  bool allIn = false;
564  lst_int = em->lstElmInBlk(
565  std::distance(elmBlkNames.begin(), elmBlkName), lst_int, allIn);
566  lst.assign(lst_int.begin(), lst_int.end());
567  }
568  }
569  zoneGeom[{1.0 / density, matName}].insert(lst.begin(), lst.end());
570  }
571 
572  if (appDen)
573  std::cout << "Applying material zones based on density ordering"
574  << std::endl;
575 
576  // adjusting exodus database accordingly
577  for (const auto &zone : zoneGeom) {
578  // zone is ((density, material name), ids)
579  std::vector<int> elmLst;
580  std::cout << "Manipulating ExodusDB for " << zone.first.second
581  << std::endl;
582  elmLst.insert(elmLst.end(), zone.second.begin(), zone.second.end());
583  em->addElmBlkByElmIdLst(zone.first.second, elmLst);
584  }
585  } else if (opr == "Check Duplicate Elements") {
586  std::cout << "Checking for existence of duplicate elements ... ";
587  meshSrch *ms = meshSrch::Create(mb);
588  bool ret = ms->chkDuplElm();
589  if (ret) {
590  std::cerr << " The exodus database contains duplicate elements."
591  << std::endl;
592  exit(-1);
593  } else {
594  std::cout << "False" << std::endl;
595  }
596  } else if (opr == "Remove Block") {
597  std::string blkName = ppJson.get_with_default("Block Name", "");
598  std::cout << "Removing Block " << blkName << std::endl;
599  em->removeElmBlkByName(blkName);
600  } else if (opr == "Snap Node Coords To Zero") {
601  double tol = ppJson.get_with_default("Tolerance", 0.0);
602  std::cout << "Snapping nodal coordinates to zero using tolerance: " << tol
603  << std::endl;
604  em->snapNdeCrdsZero(tol);
605  } else if (opr == "Boundary Condition Assignment") {
606  // For EP16 boundary conditions are simply translated to node sets. Node
607  // sets may have shared nodes. In that case a node the order of nodeset
608  // matter. A later node set supersedes an earlier one.
609  meshSrch *ms = meshSrch::Create(mb);
610 
611  // gathering information about all boundary node sets
612  jsoncons::json bcs = ppJson["Condition"];
613  for (const auto &bc : bcs.array_range()) {
614  std::set<nemId_t> pntIds;
615 
616  // identify node ids on each boundary
617  std::string bcName = bc["Name"].as<std::string>();
618  std::string bcTyp = bc["Boundary Type"].as<std::string>();
619  if (bcTyp == "Faces") {
620  std::vector<double> srfCrd;
621  std::vector<nemId_t> srfConn;
622  jsoncons::json nc = bc["Params"]["Node Coordinates"];
623  for (const auto &crds : nc.array_range())
624  for (const auto &cmp : crds.array_range())
625  srfCrd.push_back(cmp.as<double>());
626  jsoncons::json conn = bc["Params"]["Connectivities"];
627  for (const auto &tri : conn.array_range())
628  for (const auto &idx : tri.array_range())
629  srfConn.push_back(idx.as<nemId_t>());
630  ms->FindPntsOnTriSrf(srfCrd, srfConn, pntIds);
631  std::cout << "Number of points residing on the boundary " << bcName
632  << " is " << pntIds.size() << std::endl;
633  } else if (bcTyp == "Edges") {
634  std::vector<double> edgeCrd;
635  jsoncons::json ncs = bc["Params"]["Start"];
636  for (const auto &crds : ncs.array_range())
637  for (const auto &cmp : crds.array_range())
638  edgeCrd.push_back(cmp.as<double>());
639  jsoncons::json nce = bc["Params"]["End"];
640  for (const auto &crds : nce.array_range())
641  for (const auto &cmp : crds.array_range())
642  edgeCrd.push_back(cmp.as<double>());
643  ms->FindPntsOnEdge(edgeCrd, pntIds);
644  std::cout << "Number of points residing on the boundary " << bcName
645  << " is " << pntIds.size() << std::endl;
646  } else {
647  std::cerr << "Warning: unsupported boundary type " << bcTyp
648  << std::endl;
649  }
650 
651  // register node set in Exodus II database
652  if (!pntIds.empty()) {
653  std::vector<int> nv;
654  std::copy(pntIds.begin(), pntIds.end(), std::back_inserter(nv));
655  em->addNdeSetByNdeIdLst(bcName, nv);
656  }
657  }
658  } else if (opr == "Merge Nodes") {
659  em->mergeNodes();
660  } else if (opr == "Mesh Scaling") {
661  em->scaleNodes(ppJson["Scale"].as<double>());
662  } else {
663  std::cerr << "Unknown operation requested: " << opr << std::endl;
664  }
665 }
666 
667 jsoncons::string_view ConversionDriver::getProgramType() const {
668  return programType;
669 }
670 
671 } // namespace DRV
672 } // namespace NEM
jsoncons::string_view getProgramType() const override
void addElmBlkByElmIdLst(const std::string &name, std::vector< int > &idLst)
Creates a new element block and augments previous owners.
Definition: exoMesh.C:807
elementType v2eEMap(VTKCellType vt)
Convert VTK cell type to EXODUS element type.
Definition: exoMesh.C:61
const std::vector< std::string > & getElmBlkNames() const
Returns the names of registered element blocks.
Definition: exoMesh.H:391
static constexpr const char * programType
int getDimension() const
Returns problem dimension.
Definition: exoMesh.H:412
A complete I/O class for EXODUS II file format.
Definition: exoMesh.H:172
std::vector< int > sdeIds
Definition: exoMesh.H:102
A brief description of meshBase.
Definition: meshBase.H:64
std::size_t nemId_t
Definition: meshBase.H:51
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
static void freeSurfaceSideSet(const meshBase *mb, NEM::MSH::EXOMesh::exoMesh *em, int elmIdOffset, std::map< int, int > v2e_elemID_map, bool splitTopBotSS, std::vector< std::string > sideSetNames)
Creates side set(s) for the free surface, exterior surface, during conversion.
void addNde(double x, double y, double z)
Add nodes to the database.
Definition: exoMesh.H:487
std::vector< int > elmIds
Definition: exoMesh.H:101
static void procExo(const jsoncons::json &ppJson, const std::string &fname, NEM::MSH::EXOMesh::exoMesh *em)
bool chkDuplElm() const
Definition: meshSrch.C:212
static meshBase * Create(const std::string &fname)
Construct vtkMesh from filename.
Definition: meshBase.C:78
WEDGE
Definition: exoMesh.H:55
QUAD
Definition: exoMesh.H:55
HEX
Definition: exoMesh.H:55
vtkSmartPointer< vtkModelMetadata > getMetadata()
Definition: meshBase.H:443
void snapNdeCrdsZero(double tol=1e-5)
Filter nodal coordinates and snap to zero.
Definition: exoMesh.C:876
Stores side set information.
Definition: exoMesh.H:97
TETRA
Definition: exoMesh.H:55
void FindCellsInTriSrf(const std::vector< std::vector< double >> &crds, const std::vector< std::vector< vtkIdType >> &conns, std::vector< nemId_t > &ids, bool query3Donly=true, double tol=0.1e-15) const
Definition: meshSrch.C:256
vtkSmartPointer< vtkDataSet > getDataSet() const
get this meshes&#39; dataSet
Definition: meshBase.H:308
nemId_t getNumberOfPoints() const
return the number of points
Definition: meshBase.H:545
void FindPntsOnTriSrf(const std::vector< double > &crds, const std::vector< nemId_t > &conn, std::set< nemId_t > &ids, double tol=0.1e-15) const
Definition: meshSrch.C:119
void addNdeSetByNdeIdLst(const std::string &name, const std::vector< int > &idLst)
Creates a new node set and augments previous ones if needed.
Definition: exoMesh.C:857
Stores element block information.
Definition: exoMesh.H:82
std::vector< int > lstElmInBlk(int blkIdx, const std::vector< int > &elmIds, bool &allIn) const
Finds all elements that are within the block and generates a list of them.
Definition: exoMesh.C:967
void FindCellsWithinBounds(std::vector< double > &bb, std::vector< nemId_t > &ids, bool fulImrsd=true)
Definition: meshSrch.C:93
void addSdeSet(const sdeSetType &ss)
Add side set to the database.
Definition: exoMesh.H:520
static meshSrch * Create(meshBase *mb)
Definition: meshSrch.H:45
void FindCellsInSphere(const std::vector< double > &center, double radius, std::vector< nemId_t > &ids, bool query3Donly=true, double tol=0.1e-15) const
Definition: meshSrch.C:280
void addElmBlk(const elmBlkType &eb)
Add element block to the database.
Definition: exoMesh.H:504
void addNdeSet(const ndeSetType &ns)
Add node set to the database.
Definition: exoMesh.H:512
elementType
Definition: pntMesh.H:47
void setDimension(int dim)
Sets/changes the problem dimensionality.
Definition: exoMesh.H:477
TRIANGLE
Definition: exoMesh.H:55
Stores node set information.
Definition: exoMesh.H:71
void scaleNodes(double sc=1.0)
scales the nodal coordinates
Definition: exoMesh.C:1357
std::vector< int > ndeIds
Definition: exoMesh.H:75
virtual void getCellDataArray(const std::string &name, std::vector< double > &data)
<>
Definition: meshBase.H:369
void FindPntsOnEdge(std::vector< double > &crds, std::set< nemId_t > &ids, double tol=0.1e-15) const
Definition: meshSrch.C:167
nemId_t getNumberOfCells() const
return the number of cells
Definition: meshBase.H:550
void mergeNodes(double tol=1e-15)
Merges duplicated and nodes within given proximity.
Definition: exoMesh.C:1232
void removeElmBlkByName(const std::string &blkName)
Remove an element block by name.
Definition: exoMesh.C:901
virtual std::vector< double > getPoint(nemId_t id) const =0
get point with id
static void genExo(std::vector< meshBase *> meshes, const std::string &fname)
std::vector< int > conn
Definition: exoMesh.H:88