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.
MeshGenDriver.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 "MeshGenDriver.H"
30 
31 #include "AuxiliaryFunctions.H"
32 
33 #include "gmshGen.H"
34 #include "geoMeshFactory.H"
35 #include "gmshParams.H"
36 #ifdef HAVE_NGEN
37 # include "netgenGen.H"
38 # include "netgenParams.H"
39 #endif
40 #ifdef HAVE_CFMSH
41 # include "blockMeshGen.H"
42 # include "blockMeshParams.H"
43 # include "cfmeshGen.H"
44 # include "cfmeshParams.H"
45 # include "snappymeshGen.H"
46 # include "snappymeshParams.H"
47 #endif
48 
49 // std c++
50 #include <iostream>
51 #include <memory>
52 #include <tuple>
53 #include <vector>
54 
55 namespace NEM {
56 namespace DRV {
57 
58 // ----------------------------- MeshGen Driver
59 // -----------------------------------//
60 
61 MeshGenDriver::MeshGenDriver(const std::string &ifname,
62  const std::string &meshEngine,
63  meshingParams *_params,
64  const std::string &ofname) {
65  std::cout << "MeshGenDriver created" << std::endl;
66  params = _params;
67 
68  meshGen *generator = nullptr;
69 
70  if (meshEngine == "netgen") {
71 #ifdef HAVE_NGEN
72  generator = new netgenGen(dynamic_cast<netgenParams *>(params));
73  std::string newname = nemAux::trim_fname(ifname, ".vol");
74 #else
75  std::cerr << "NETGEN is not enabled during build."
76  << " Build NEMoSys with ENABLE_NETGEN to use this method."
77  << std::endl;
78  exit(1);
79 #endif
80  } else if (meshEngine == "gmsh") {
81  generator =
82  new NEM::GEN::gmshGen(dynamic_cast<NEM::GEN::gmshParams *>(params));
83  std::string newname = nemAux::trim_fname(ifname, ".msh");
84 #ifdef HAVE_CFMSH
85  } else if (meshEngine == "cfmesh") {
86  generator = new cfmeshGen(dynamic_cast<cfmeshParams *>(params));
87  std::string newname = nemAux::trim_fname(ifname, ".vtu");
88  } else if (meshEngine == "snappyHexMesh") {
89  generator = new snappymeshGen(dynamic_cast<snappymeshParams *>(params));
90  std::string newname = nemAux::trim_fname(ifname, ".vtu");
91  } else if (meshEngine == "blockMesh") {
92  generator = new blockMeshGen(dynamic_cast<blockMeshParams *>(params));
93  std::string newname = nemAux::trim_fname(ifname, ".vtu");
94 #endif
95  } else {
96  std::cerr << meshEngine << " is not a supported meshing engine"
97  << std::endl;
98  exit(1);
99  }
100 
101  if (!generator) {
102  std::cerr << "Meshing with engine " << meshEngine << " failed. Aborting."
103  << std::endl;
104  exit(1);
105  }
106 
107  int status = generator->createMeshFromSTL(ifname.c_str());
108 
109  if (status) {
110  std::cerr << "Mesh Engine " << meshEngine << " not recognized" << std::endl;
111  exit(1);
112  }
113 
114  // output file type
115  std::string outputType = nemAux::find_ext(ofname);
116  std::shared_ptr<meshBase> mesh;
117  if (outputType == ".msh" && meshEngine == "gmsh") {
118  // createMeshFromSTL (in this case) outputs a .msh file by default
119  return;
120  }
121 
122  // otherwise, resort to meshBase
123 
124  if (meshEngine == "netgen") {
125  std::string newname = nemAux::trim_fname(ifname, ".vol");
127  } else if (meshEngine == "gmsh") {
128  std::string newname = nemAux::trim_fname(ifname, ".msh");
129  // conversion from STL using gmsh engine writes a ".msh" file by default
130  if (outputType == ".msh") return;
132  } else {
133  // default
134  std::string newname = nemAux::trim_fname(ifname, ".vtu");
135  mesh = meshBase::CreateShared(
136  meshBase::Create(generator->getDataSet(), newname));
137  }
138 
139  if (meshEngine == "cfmesh" || meshEngine == "snappyHexMesh" ||
140  meshEngine == "blockMesh") {
141  geoMesh = NEM::MSH::New(ofname);
142  geoMesh->takeGeoMesh(generator->gmData.get());
143  geoMesh->write(ofname);
144  geoMesh->Delete();
145  } else {
146  mesh->setFileName(ofname);
147  mesh->report();
148  mesh->write();
149  }
150 }
151 
152 std::shared_ptr<meshBase> MeshGenDriver::getNewMesh() const {
153  return mesh ? mesh : nullptr;
154 }
155 
156 MeshGenDriver::~MeshGenDriver() {
157  std::cout << "MeshGenDriver destroyed" << std::endl;
158 }
159 
160 MeshGenDriver *MeshGenDriver::readJSON(const jsoncons::json &inputjson) {
161  std::string ifname =
162  inputjson["Mesh File Options"]["Input Geometry File"].as<std::string>();
163  std::string ofname =
164  inputjson["Mesh File Options"]["Output Mesh File"].as<std::string>();
165  return readJSON(ifname, ofname, inputjson);
166 }
167 
168 MeshGenDriver *MeshGenDriver::readJSON(const std::string &ifname,
169  const std::string &ofname,
170  const jsoncons::json &inputjson) {
171  std::string meshEngine =
172  inputjson["Mesh Generation Engine"].as<std::string>();
173  if (meshEngine == "netgen") {
174 #ifdef HAVE_NGEN
175  std::string defaults =
176  inputjson["Meshing Parameters"]["Netgen Parameters"].as<std::string>();
177  if (defaults == "default") {
178  auto *params = new netgenParams();
179  auto *mshgndrvobj = new MeshGenDriver(ifname, meshEngine, params, ofname);
180  return mshgndrvobj;
181  } else {
182  jsoncons::json ngparams =
183  inputjson["Meshing Parameters"]["Netgen Parameters"];
184 
185  auto *params = new netgenParams();
186 
187  if (ngparams.contains("uselocalh"))
188  params->uselocalh = ngparams["uselocalh"].as<bool>();
189  if (ngparams.contains("maxh"))
190  params->maxh = ngparams["maxh"].as<double>();
191  if (ngparams.contains("fineness"))
192  params->fineness = ngparams["fineness"].as<double>();
193  if (ngparams.contains("grading"))
194  params->grading = ngparams["grading"].as<double>();
195  if (ngparams.contains("elementsperedge"))
196  params->elementsperedge = ngparams["elementsperedge"].as<double>();
197  if (ngparams.contains("elementspercurve"))
198  params->elementspercurve = ngparams["elementspercurve"].as<double>();
199  if (ngparams.contains("closeedgeenable"))
200  params->closeedgeenable = ngparams["closeedgeenable"].as<bool>();
201  if (ngparams.contains("closeedgefact"))
202  params->closeedgefact = ngparams["closeedgefact"].as<double>();
203  if (ngparams.contains("second_order"))
204  params->second_order = ngparams["second_order"].as<bool>();
205  if (ngparams.contains("meshsize_filename"))
206  params->meshsize_filename =
207  ngparams["meshsize_filename"].as<std::string>();
208  if (ngparams.contains("quad_dominated"))
209  params->quad_dominated = ngparams["quad_dominated"].as<bool>();
210  if (ngparams.contains("optvolmeshenable"))
211  params->optvolmeshenable = ngparams["optvolmeshenable"].as<bool>();
212  if (ngparams.contains("optsteps_2d"))
213  params->optsteps_2d = ngparams["optsteps_2d"].as<int>();
214  if (ngparams.contains("optsteps_3d"))
215  params->optsteps_3d = ngparams["optsteps_3d"].as<int>();
216  if (ngparams.contains("invert_tets"))
217  params->invert_tets = ngparams["invert_tets"].as<bool>();
218  if (ngparams.contains("invert_trigs"))
219  params->invert_trigs = ngparams["invert_trigs"].as<bool>();
220  if (ngparams.contains("check_overlap"))
221  params->check_overlap = ngparams["check_overlap"].as<bool>();
222  if (ngparams.contains("check_overlapping_boundary"))
223  params->check_overlapping_boundary =
224  ngparams["check_overlapping_boundary"].as<bool>();
225  if (ngparams.contains("refine_with_geometry_adaptation"))
226  params->refine_with_geom =
227  ngparams["refine_with_geometry_adaptation"].as<bool>();
228  if (ngparams.contains("refine_without_geometry_adaptation"))
229  params->refine_without_geom =
230  ngparams["refine_without_geometry_adaptation"].as<bool>();
231 
232  auto *mshgndrvobj = new MeshGenDriver(ifname, meshEngine, params, ofname);
233  return mshgndrvobj;
234  }
235 #else
236  return nullptr;
237 #endif
238  } else if (meshEngine == "gmsh") {
239  std::cout << "Gmsh mesh engine selected" << std::endl;
240 
241  std::string defaults;
242  if (inputjson.contains("Meshing Parameters")) {
243  if (inputjson["Meshing Parameters"].contains("Gmsh Parameters")) {
244  defaults =
245  inputjson["Meshing Parameters"]["Gmsh Parameters"].as_string();
246  } else {
247  std::cerr << "Error: 'Gmsh Parameters' not found in JSON" << std::endl;
248  exit(-1);
249  }
250  } else {
251  std::cerr << "Error: 'Meshing Parameters' not found in JSON" << std::endl;
252  exit(-1);
253  }
254  if (defaults == "default") {
255  auto *params = new NEM::GEN::gmshParams();
256  auto *mshgndrvobj = new MeshGenDriver(ifname, meshEngine, params, ofname);
257  return mshgndrvobj;
258  } else {
259  jsoncons::json gparams =
260  inputjson["Meshing Parameters"]["Gmsh Parameters"];
261 
262  auto params = new NEM::GEN::gmshParams();
263 
264  // Get the output file name for later
265  std::string ofname =
266  inputjson["Mesh File Options"]["Output Mesh File"].as_string();
267  params->ofname = ofname;
268 
269  if (gparams.contains("minSize"))
270  params->minSize = gparams["minSize"].as_double();
271  if (gparams.contains("maxSize"))
272  params->maxSize = gparams["maxSize"].as_double();
273  if (gparams.contains("surfaceAlgorithm"))
274  params->algo2D = gparams["surfaceAlgorithm"].as_string();
275  if (gparams.contains("volumeAlgorithm"))
276  params->algo3D = gparams["volumeAlgorithm"].as_string();
277  if (gparams.contains("extendSizeFromBoundary"))
278  params->extSizeFromBoundary =
279  gparams["extendSizeFromBoundary"].as<bool>();
280  if (gparams.contains("sizeFromCurvature"))
281  params->sizeFromCurvature = gparams["sizeFromCurvature"].as<bool>();
282  if (gparams.contains("minElementsPer2Pi"))
283  params->minElePer2Pi = gparams["minElementsPer2Pi"].as<int>();
284  if (gparams.contains("optimize"))
285  params->optimize = gparams["optimize"].as<bool>();
286  if (gparams.contains("optimizeThreshold"))
287  params->optimizeThreshold = gparams["optimizeThreshold"].as_double();
288  if (gparams.contains("elementOrder"))
289  params->elementOrder = gparams["elementOrder"].as<int>();
290  if (gparams.contains("subdivisionAlgorithm"))
291  params->subdivisionAlg = gparams["subdivisionAlgorithm"].as<int>();
292  if (gparams.contains("saveAll"))
293  params->saveAll = gparams["saveAll"].as<bool>();
294  if (gparams.contains("fragment"))
295  params->fragmentAll = gparams["fragment"].as<bool>();
296 
297  if (gparams.contains("ColorMap")) {
298  std::map<std::string, std::string> color2groupMap;
299  for (const auto &cm : gparams["ColorMap"].array_range()) {
300  std::string color;
301  std::string name;
302  if (cm.contains("Color")) {
303  int r, g, b;
304  r = cm["Color"].at(0).as<int>();
305  g = cm["Color"].at(1).as<int>();
306  b = cm["Color"].at(2).as<int>();
307  color = std::to_string(r) + "," + std::to_string(g) + "," +
308  std::to_string(b);
309  } else {
310  std::cerr << "Error: Keyword 'Color' for Color Map not found."
311  << std::endl;
312  throw;
313  }
314  if (cm.contains("Group")) {
315  name = cm["Group"].as<std::string>();
316  } else {
317  std::cerr << "Error: Keyword 'Group' for Color Map not found."
318  << std::endl;
319  throw;
320  }
321  color2groupMap[color] = name;
322  }
323  params->mColorMap = true;
324  params->color2groupMap = color2groupMap;
325  }
326 
327  if (gparams.contains("TransfiniteBlocks")) {
328  for (const auto &tb : gparams["TransfiniteBlocks"].array_range()) {
330  if (tb.contains("Volume")) {
331  block.id = tb["Volume"].as<int>();
332  } else {
333  std::cerr << "Error: Keyword 'id' for transfinite block not found."
334  << std::endl;
335  throw;
336  }
337  if (tb.contains("Axis")) {
338  // normalize and store each direction vector
339  for (int i = 0; i < 3; ++i) {
340  double x = tb["Axis"].at(i).at(0).as<double>();
341  double y = tb["Axis"].at(i).at(1).as<double>();
342  double z = tb["Axis"].at(i).at(2).as<double>();
343  double axis_len = std::sqrt(x * x + y * y + z * z);
344  if (axis_len < 1e-3) {
345  std::cerr << "Axis " << i << " for block " << block.id
346  << " is too small. Please prescribe an axis with "
347  "length > 1e-3"
348  << std::endl;
349  exit(1);
350  }
351  block.axis[i][0] = x / axis_len;
352  block.axis[i][1] = y / axis_len;
353  block.axis[i][2] = z / axis_len;
354  }
355  } else {
356  std::cerr
357  << "Error: Keyword 'axis' for transfinite block not found."
358  << std::endl;
359  throw;
360  }
361 
362  auto setTransfiniteCurve = [&tb,
363  &block](const std::string &axis) -> void {
364  int idx = -1;
365  if (axis == "x") idx = 0;
366  if (axis == "y") idx = 1;
367  if (axis == "z") idx = 2;
368  if (idx == -1) {
369  std::cerr << "Invalid axis name '" << axis
370  << "'. Valid axis names are : "
371  << "'x', 'y', and 'z'. Aborting." << std::endl;
372  exit(1);
373  }
374  if (tb.contains(axis)) {
375  block.vert[idx] = tb[axis]["Vertices"].as<int>();
376  if (tb[axis].contains("Bump")) {
377  block.type[idx] = "Bump";
378  block.coef[idx] = tb[axis]["Bump"].as<double>();
379  } else if (tb[axis].contains("Progression")) {
380  block.type[idx] = "Progression";
381  block.coef[idx] = tb[axis]["Progression"].as<double>();
382  }
383  } else {
384  std::cerr << "Error : Keyword '" << axis
385  << "' for transfinite block not found." << std::endl;
386  throw;
387  }
388  };
389 
390  setTransfiniteCurve("x");
391  setTransfiniteCurve("y");
392  setTransfiniteCurve("z");
393 
394  params->transfiniteBlocks[block.id] = block;
395  }
396  params->mTransfiniteVolumes = true;
397  }
398 
399  // Size Fields parsing
400  std::string cap = "SizeFields";
401  if (gparams.contains(cap)) {
402  std::cout << "Parsing SizeFields ...";
403  params->mSizeField = true;
404  for (const auto &sf : gparams[cap].array_range()) {
405  // Instantiate volSizeField struct object
406  NEM::GEN::volSizeField sizeField;
407 
408  // Get the size field Type
409  if (sf.contains("Type"))
410  sizeField.type = sf["Type"].as_string();
411  else {
412  std::cerr << "Error: Keyword 'Type' for Size Field not found."
413  << std::endl;
414  throw;
415  }
416 
417  // Get the size field ID
418  if (sf.contains("ID"))
419  sizeField.id = sf["ID"].as<int>();
420  else {
421  std::cerr << "Error: Keyword 'ID' for Size Field not found."
422  << std::endl;
423  throw;
424  }
425 
426  // Get the size field Params
427  if (sf.contains("Params")) {
428  std::string key;
429  double val;
430  std::pair<std::string, double> p;
431 
432  for (const auto &prm : sf["Params"].object_range()) {
433  key = std::string(prm.key());
434 
435  // Check what type of data each object has
436  if (prm.value().is_array()) {
437  if (prm.value()[0].is_string()) {
438  std::pair<std::string, std::vector<std::string>> p_strg;
439  p_strg.first = key;
440  for (int i = 0; i < prm.value().size(); i++) {
441  p_strg.second.push_back(prm.value()[i].as_string());
442  // std::cout << prm.value()[i].as_string() << std::endl;
443  }
444  sizeField.strg_list_params.push_back(p_strg);
445  } else {
446  std::pair<std::string, std::vector<double>> p_num;
447  p_num.first = key;
448  for (int i = 0; i < prm.value().size(); i++) {
449  p_num.second.push_back(prm.value()[i].as_double());
450  // std::cout << prm.value()[i].as<int>() << std::endl;
451  }
452  sizeField.num_list_params.push_back(p_num);
453  }
454  } else {
455  val = prm.value().as_double();
456  p = {key, val};
457  sizeField.params.push_back(p);
458  }
459  }
460  (params->sizeFields).push_back(sizeField);
461  } else {
462  std::cerr << "Error: Size Field of Type " << sizeField.type
463  << " and ID " << sizeField.id
464  << " has no 'Params' keyword" << std::endl;
465  throw;
466  }
467  }
468  }
469  // Background Field specification
470  if (gparams.contains("BackgroundField")) {
471  params->bgField = gparams["BackgroundField"].as<int>();
472  } else if (params->mSizeField && !gparams.contains("BackgroundField") &&
473  gparams[cap].size() > 1) {
474  std::cout << "Warning: Mesh Background Field not specified."
475  << " Using size field with highest ID." << std::endl;
476  }
477  std::cout << " Done." << std::endl;
478 
479  auto *mshgndrvobj = new MeshGenDriver(ifname, meshEngine, params, ofname);
480  return mshgndrvobj;
481  }
482  } else if (meshEngine == "cfmesh") {
483 #ifndef HAVE_CFMSH
484  std::cerr << "NEMoSys must be recompiled with cfMesh support." << std::endl;
485  exit(1);
486 #else
487  auto *params = new cfmeshParams();
488  std::string defaults =
489  inputjson["Meshing Parameters"]["CFMesh Parameters"].as<std::string>();
490  if (defaults == "default") {
491  auto *mshgndrvobj = new MeshGenDriver(ifname, meshEngine, params, ofname);
492  return mshgndrvobj;
493  } else {
494  jsoncons::json cfmparams =
495  inputjson["Meshing Parameters"]["CFMesh Parameters"];
496 
497  // required params here
498  // cad file
499  if (inputjson["Mesh File Options"].contains("Input Geometry File"))
500  params->geomFilePath =
501  inputjson["Mesh File Options"]["Input Geometry File"]
502  .as<std::string>();
503  else {
504  std::cerr << "A geometry file should be supplied.\n";
505  throw;
506  }
507 
508  // mesh generator
509  if (cfmparams.contains("Generator"))
510  params->generator = cfmparams["Generator"].as<std::string>();
511  else {
512  std::cerr << "A mesh generation method should be selected.\n";
513  std::cerr << "Options: cartesian2D tetMesh\n";
514  throw;
515  }
516 
517  // rest of params are optional
518  if (cfmparams.contains("MaxCellSize"))
519  params->maxCellSize = cfmparams["MaxCellSize"].as<double>();
520  if (cfmparams.contains("MinCellSize"))
521  params->minCellSize = cfmparams["MinCellSize"].as<double>();
522  if (cfmparams.contains("BoundaryCellSize"))
523  params->bndryCellSize = cfmparams["BoundaryCellSize"].as<double>();
524  if (cfmparams.contains("BoundaryCellSizeRefinementThickness"))
525  params->bndryCellSizeRefThk =
526  cfmparams["BoundaryCellSizeRefinementThickness"].as<double>();
527  if (cfmparams.contains("KeepCellsIntersectingBoundary"))
528  params->keepCellIB =
529  cfmparams["KeepCellsIntersectingBoundary"].as<bool>();
530  if (cfmparams.contains("CheckForGluedMesh"))
531  params->chkGluMsh = cfmparams["CheckForGluedMesh"].as<bool>();
532  if (cfmparams.contains("AllowDisconnectedDomains"))
533  params->_alwDiscDomains =
534  cfmparams["AllowDisconnectedDomains"].as<bool>();
535  else
536  params->_alwDiscDomains = false;
537 
538  // optional capability
539  std::string cap = "BoundaryLayers";
540  if (cfmparams.contains(cap)) {
541  params->_withBndLyr = true;
542  params->blNLyr = cfmparams[cap]["NLayers"].as<int>();
543  params->blThkRto = cfmparams[cap]["ThicknessRatio"].as<double>();
544  if (cfmparams[cap].contains("MaxFirstLayerThickness"))
545  params->maxFrstLyrThk =
546  cfmparams[cap]["MaxFirstLayerThickness"].as<double>();
547  if (cfmparams[cap].contains("AllowDiscontinuity"))
548  params->alwDiscont = cfmparams[cap]["AllowDiscontinuity"].as<bool>();
549 
550  // patch boundary layers
551  std::string subcap = "PatchBoundaryLayers";
552  if (cfmparams[cap].contains(subcap)) {
553  params->_withBndLyrPtch = true;
554  for (const auto &jptch : cfmparams[cap][subcap].array_range()) {
555  cfmPtchBndLyr blPatch;
556  blPatch.patchName = jptch["PatchName"].as<std::string>();
557  if (jptch.contains("AllowDiscontinuity"))
558  blPatch.alwDiscont = jptch["AllowDiscontinuity"].as<bool>();
559  else
560  blPatch.alwDiscont = false;
561  if (jptch.contains("MaxFirstLayerThickness"))
562  blPatch.maxFrstLyrThk = jptch["MaxFirstLayerThickness"].as<int>();
563  else
564  blPatch.maxFrstLyrThk = -1;
565  if (jptch.contains("NLayers"))
566  blPatch.blNLyr = jptch["NLayers"].as<int>();
567  else
568  blPatch.blNLyr = -1;
569  if (jptch.contains("ThicknessRatio"))
570  blPatch.blThkRto = jptch["ThicknessRatio"].as<double>();
571  else
572  blPatch.blThkRto = -1.;
573  (params->blPatches).push_back(blPatch);
574  }
575  }
576  }
577 
578  // optional capability
579  cap = "SurfaceFeatureEdges";
580  if (cfmparams.contains(cap)) {
581  params->_withSrfEdg = true;
582  params->srfEdgAng = cfmparams[cap]["Angle"].as<double>();
583  }
584 
585  // optional capability
586  cap = "ObjectRefinements";
587  if (cfmparams.contains(cap)) {
588  params->_withObjRfn = true;
589  for (const auto &refObj : cfmparams[cap].array_range()) {
590  cfmObjRef objRef;
591  objRef.name = refObj["Name"].as<std::string>();
592  for (const auto &prm : refObj["Params"].object_range()) {
593  std::string key = std::string(prm.key());
594  std::string val = prm.value().as<std::string>();
595  objRef.params[key] = val;
596  }
597  (params->objRefLst).push_back(objRef);
598  }
599  }
600 
601  // optional capability
602  cap = "ImproveMeshQuality";
603  if (cfmparams.contains(cap)) {
604  params->_withMshQlt = true;
605  params->qltNItr = cfmparams[cap]["NIterations"].as<int>();
606  params->qltNLop = cfmparams[cap]["NLoops"].as<int>();
607  params->qltQltThr = cfmparams[cap]["QualityThreshold"].as<double>();
608  params->qltNSrfItr = cfmparams[cap]["NSurfaceIterations"].as<int>();
609  params->qltConCelSet =
610  cfmparams[cap].get_with_default("ConstrainedCellsSet", "none");
611  }
612 
613  // optional capability
614  cap = "LocalRefinement";
615  if (cfmparams.contains(cap)) {
616  params->_withLclRef = true;
617  for (const auto &jptch : cfmparams[cap].array_range()) {
618  cfmLclRefPatch refPatch;
619  refPatch.patchName = jptch["PatchName"].as<std::string>();
620  if (jptch.contains("AdditionalRefinementLevels"))
621  refPatch.aditRefLvls =
622  jptch["AdditionalRefinementLevels"].as<int>();
623  else
624  refPatch.aditRefLvls = -1;
625  if (jptch.contains("RefinementThickness"))
626  refPatch.refThickness = jptch["RefinementThickness"].as<double>();
627  else
628  refPatch.refThickness = -1;
629  if (jptch.contains("CellSize"))
630  refPatch.cellSize = jptch["CellSize"].as<double>();
631  else
632  refPatch.cellSize = -1.;
633  (params->refPatches).push_back(refPatch);
634  }
635  }
636 
637  // optional capability
638  cap = "RenameBoundary";
639  if (cfmparams.contains(cap)) {
640  params->_withRenBndry = true;
641  cfmRenBndry renBndry;
642  renBndry.defName = cfmparams[cap]["DefaultName"].as<std::string>();
643  renBndry.defType = cfmparams[cap]["DefaultType"].as<std::string>();
644  for (const auto &jnw : cfmparams[cap]["NewPatchNames"].array_range()) {
645  cfmNewPatch nwPatch = std::make_tuple(
646  jnw["Name"].as<std::string>(), jnw["NewName"].as<std::string>(),
647  jnw["NewType"].as<std::string>());
648  renBndry.newPatches.push_back(nwPatch);
649  }
650  (params->renBndry) = renBndry;
651  }
652 
653  auto *mshgndrvobj = new MeshGenDriver(ifname, meshEngine, params, ofname);
654  return mshgndrvobj;
655  }
656 #endif
657  } else if (!meshEngine.compare("snappyHexMesh")) {
658 #ifndef HAVE_CFMSH
659  std::cerr << "Nemosys must be recompiled with cfMesh support" << std::endl;
660  exit(1);
661 #else
662  snappymeshParams *params = new snappymeshParams();
663  std::string defaults =
664  inputjson["Meshing Parameters"]["snappyHexMesh Parameters"]
665  .as<std::string>();
666  if (!defaults.compare("default")) {
667  MeshGenDriver *mshgndrvobj =
668  new MeshGenDriver(ifname, meshEngine, params, ofname);
669  return mshgndrvobj;
670  } else {
671  jsoncons::json shmparams =
672  inputjson["Meshing Parameters"]["snappyHexMesh Parameters"];
673 
674  jsoncons::json geomParams = shmparams["Geometry Definition"];
675  jsoncons::json castMeshParams = shmparams["Castellated Mesh Controls"];
676  jsoncons::json snapParams = shmparams["Snapping Controls"];
677  jsoncons::json layerParams = shmparams["Mesh Layers Controls"];
678  jsoncons::json qcMeshParams = shmparams["Mesh Quality Controls"];
679 
680  if (inputjson["Mesh File Options"].contains("Input Geometry File"))
681  params->geomFileName =
682  inputjson["Mesh File Options"]["Input Geometry File"]
683  .as<std::string>();
684  else {
685  std::cerr << "A geometry file should be supplied.\n";
686  throw;
687  }
688 
689  // General booleans
690  if (shmparams.contains("Castellated Mesh"))
691  params->_withCastMesh = shmparams["Castellated Mesh"].as<bool>();
692  else {
693  std::cerr << "Please specify on/off choice using \"Castellated Mesh\""
694  << "\n"
695  << std::endl;
696  throw;
697  }
698  if (shmparams.contains("Snapping"))
699  params->_withSnap = shmparams["Snapping"].as<bool>();
700  else {
701  std::cerr << "Please specify on/off choice using \"Snapping\""
702  << "Keyword!\n"
703  << std::endl;
704  throw;
705  }
706  if (shmparams.contains("Layer Addition"))
707  params->_withLayers = shmparams["Layer Addition"].as<bool>();
708  else {
709  std::cerr << "Please specify on/off choice using \"Layer Addition\""
710  << "Keyword!\n"
711  << std::endl;
712  throw;
713  }
714 
715  // Geometry definition with patch defining ability
716  bool multiPatches = false;
717  if (geomParams.contains("Enable Multi Patches"))
718  multiPatches = geomParams["Enable Multi Patches"].as<bool>();
719  else {
720  std::cerr << "Please provide boolean \"Enable Multi Patches\".\n";
721  throw;
722  }
723 
724  if (!multiPatches) {
725  if (geomParams.contains("InputPatchName"))
726  params->singleSolidPatch =
727  geomParams["InputPatchName"].as<std::string>();
728  else {
729  std::cerr << "A patch name for input geometry must be defined.\n";
730  throw;
731  }
732  } else {
733  // Geometry STL Patch Definition
734  std::string cap4 = "Geometry Patches";
735  if (geomParams.contains(cap4)) {
736  params->_withMultiPatches = true;
737 
738  for (auto jptch3 : geomParams[cap4].array_range()) {
739  shmSTLDefinition stlPatches;
740 
741  if (jptch3.contains("Geometry Patch Name"))
742  stlPatches.STLPatchName =
743  jptch3["Geometry Patch Name"].as<std::string>();
744  else {
745  std::cerr
746  << "Please provide Output Patch Name for STL file provided"
747  << std::endl;
748  throw;
749  }
750 
751  if (jptch3.contains("Output Patch Name"))
752  stlPatches.snappyPatchName =
753  jptch3["Output Patch Name"].as<std::string>();
754  else {
755  std::cerr
756  << "Please provide Output Patch Name for STL file provided"
757  << std::endl;
758  throw;
759  }
760 
761  (params->stlPatchDefs).push_back(stlPatches);
762  }
763  } else {
764  std::cerr
765  << "User has selected to define multiple geometry patches.\n"
766  << "Please define them using \"Geometry Patches\" keyword"
767  << std::endl;
768  throw;
769  }
770  }
771 
772  // Define searchable shapes with whatever patch name user wants
773  std::string cap5 = "Custom Patches";
774  if (geomParams.contains(cap5)) {
775  for (auto jptch3 : geomParams[cap5].array_range()) {
776  shmSearchableShapes SSS;
777  if (jptch3.contains("Custom Patch Name"))
778  SSS.patchNm = jptch3["Custom Patch Name"].as<std::string>();
779  else {
780  std::cerr << "Please provide Custom Patch Name" << std::endl;
781  throw;
782  }
783 
784  if (jptch3.contains("Searchable Shape"))
785  SSS.searchableName = jptch3["Searchable Shape"].as<std::string>();
786  else {
787  std::cerr << "Please provide Searchable Shape Name" << std::endl;
788  throw;
789  }
790 
791  if (SSS.searchableName == "searchableBox") {
792  if (jptch3.contains("minimum bound"))
793  SSS.shapeParameters1 = jptch3["minimum bound"].as<std::string>();
794  else {
795  std::cerr << "Please provide minimum bound (i.e (-1 -1 -1))"
796  << std::endl;
797  throw;
798  }
799  if (jptch3.contains("maximum bound"))
800  SSS.shapeParameters2 = jptch3["maximum bound"].as<std::string>();
801  else {
802  std::cerr << "Please provide maximum bound (i.e (1 1 1))"
803  << std::endl;
804  throw;
805  }
806  } else if (SSS.searchableName == "searchableCylinder") {
807  if (jptch3.contains("Axis Point 1"))
808  SSS.shapeParameters1 = jptch3["Axis Point 1"].as<std::string>();
809  else {
810  std::cerr << "Please provide Axis Point 1 (i.e (-1 -1 -1))"
811  << std::endl;
812  throw;
813  }
814  if (jptch3.contains("Axis Point 2"))
815  SSS.shapeParameters2 = jptch3["Axis Point 2"].as<std::string>();
816  else {
817  std::cerr << "Please provide Axis Point 2 (i.e (1 1 1))"
818  << std::endl;
819  throw;
820  }
821  if (jptch3.contains("Radius"))
822  SSS.rad = jptch3["Radius"].as<double>();
823  else {
824  std::cerr << "Please provide Radius" << std::endl;
825  throw;
826  }
827  } else if (SSS.searchableName == "searchableSphere") {
828  if (jptch3.contains("Center"))
829  SSS.shapeParameters1 = jptch3["Center"].as<std::string>();
830  else {
831  std::cerr << "Please provide Center (i.e (1 1 1))" << std::endl;
832  throw;
833  }
834  if (jptch3.contains("Radius"))
835  SSS.rad = jptch3["Radius"].as<double>();
836  else {
837  std::cerr << "Please provide Radius" << std::endl;
838  throw;
839  }
840  } else {
841  std::cerr << SSS.searchableName << " is not supported yet!"
842  << std::endl;
843  throw;
844  }
845  (params->srchShape).push_back(SSS);
846  }
847  }
848 
849  // Castellated Mesh Controls Inputs
850  if (castMeshParams.contains("CellZones"))
851  params->_withCellZones = castMeshParams["CellZones"].as<bool>();
852  else {
853  std::cerr << "Please specify on/off choice using \"CellZones\""
854  << "Keyword!\n"
855  << std::endl;
856  throw;
857  }
858  if (castMeshParams.contains("RegionRefine"))
859  params->_withGeomRefReg = castMeshParams["RegionRefine"].as<bool>();
860  else {
861  std::cerr << "Please specify on/off choice using \"RegionRefine\""
862  << "Keyword!\n"
863  << std::endl;
864  throw;
865  }
866  if (castMeshParams.contains("SurfaceRefine"))
867  params->_withSurfRefReg = castMeshParams["SurfaceRefine"].as<bool>();
868  else {
869  std::cerr << "Please specify on/off choice using \"SurfaceRefine\""
870  << "Keyword!\n"
871  << std::endl;
872  throw;
873  }
874  if (castMeshParams.contains("GeneralGapLevelIncrement"))
875  params->castMeshGpLvl =
876  castMeshParams["GeneralGapLevelIncrement"].as<int>();
877  else {
878  params->castMeshGpLvl = 1;
879  }
880  if (castMeshParams.contains("maxLocalCells"))
881  params->maxLCells = castMeshParams["maxLocalCells"].as<int>();
882  else {
883  params->maxLCells = 2000000;
884  }
885  if (castMeshParams.contains("maxGlobalCells"))
886  params->maxGCells = castMeshParams["maxGlobalCells"].as<int>();
887  else {
888  params->maxGCells = 4000000;
889  }
890  if (castMeshParams.contains("minRefCells"))
891  params->minRefCells = castMeshParams["minRefCells"].as<int>();
892  else {
893  params->minRefCells = 0;
894  }
895  if (castMeshParams.contains("nCellsBetweenLevels"))
896  params->cellsBetnLvls = castMeshParams["nCellsBetweenLevels"].as<int>();
897  else {
898  params->cellsBetnLvls = 3;
899  }
900  if (castMeshParams.contains("surfaceRefinementLvlMin"))
901  params->refSurfLvlMin =
902  castMeshParams["surfaceRefinementLvlMin"].as<int>();
903  else {
904  params->refSurfLvlMin = 0;
905  }
906  if (castMeshParams.contains("surfaceRefinementLvlMax"))
907  params->refSurfLvlMax =
908  castMeshParams["surfaceRefinementLvlMax"].as<int>();
909  else {
910  params->refSurfLvlMax = 0;
911  }
912  if (castMeshParams.contains("resolveFeatureAngle"))
913  params->featAngle = castMeshParams["resolveFeatureAngle"].as<double>();
914  else {
915  params->featAngle = 60;
916  }
917  if (castMeshParams.contains("gapLevelIncrement"))
918  params->gPLvlInc = castMeshParams["gapLevelIncrement"].as<int>();
919  else
920  params->gPLvlInc = 1;
921  if (castMeshParams.contains("planarAngle"))
922  params->planarAngle = castMeshParams["planarAngle"].as<int>();
923  else
924  params->planarAngle = 1;
925  if (castMeshParams.contains("locationInMeshX"))
926  params->locMeshX = castMeshParams["locationInMeshX"].as<double>();
927  else {
928  std::cerr << "Location of a point in region you want to"
929  << "keep cells is needed!" << std::endl;
930  throw;
931  }
932  if (castMeshParams.contains("locationInMeshY"))
933  params->locMeshY = castMeshParams["locationInMeshY"].as<double>();
934  else {
935  std::cerr << "Location of a point in region you want to"
936  << "keep cells is needed!" << std::endl;
937  throw;
938  }
939  if (castMeshParams.contains("locationInMeshZ"))
940  params->locMeshZ = castMeshParams["locationInMeshZ"].as<double>();
941  else {
942  std::cerr << "Location of a point in region you want to"
943  << "keep cells is needed!" << std::endl;
944  throw;
945  }
946  if (castMeshParams.contains("allowFreeStandingZoneFaces"))
947  params->_alwFreeZone =
948  castMeshParams["allowFreeStandingZoneFaces"].as<bool>();
949  else {
950  params->_alwFreeZone = true;
951  }
952 
953  // Refinement Surfaces
954  std::string cap3 = "SurfaceRefinementRegions";
955  if (castMeshParams.contains(cap3)) {
956  // params->_withSurfRefReg = true;
957 
958  for (auto jptch3 : castMeshParams[cap3].array_range()) {
959  shmSurfRefine surfRef;
960 
961  if (jptch3.contains("Patch Name"))
962  surfRef.refPatchNm = jptch3["Patch Name"].as<std::string>();
963  else {
964  surfRef.refPatchNm = params->singleSolidPatch;
965  }
966 
967  if (jptch3.contains("Patch Type"))
968  surfRef.patchType = jptch3["Patch Type"].as<std::string>();
969  else {
970  surfRef.patchType = "NO";
971  }
972 
973  if (jptch3.contains("MinLevel"))
974  surfRef.minLvl = jptch3["MinLevel"].as<double>();
975  else {
976  surfRef.minLvl = 1;
977  }
978 
979  if (jptch3.contains("MaxLevel"))
980  surfRef.maxLvl = jptch3["MaxLevel"].as<int>();
981  else {
982  std::cerr << "Please define maximum surface refinement"
983  << "\"MaxLevel\"\n"
984  << std::endl;
985  throw;
986  }
987  (params->surfRefs).push_back(surfRef);
988  }
989  }
990 
991  // Region Refinement
992  std::string cap2 = "GeomRefinementRegions";
993  if (castMeshParams.contains(cap2)) {
994  // params->_withGeomRefReg = true;
995 
996  for (auto jptch2 : castMeshParams[cap2].array_range()) {
997  shmRegionRefine geomRef;
998 
999  if (jptch2.contains("Patch Name"))
1000  geomRef.patchNm = jptch2["Patch Name"].as<std::string>();
1001  else {
1002  std::cerr << "Please define \"PatchName\"\n" << std::endl;
1003  throw;
1004  }
1005  if (jptch2.contains("Mode"))
1006  geomRef.mode = jptch2["Mode"].as<std::string>();
1007  else {
1008  std::cerr << "Please define \"Mode\"\n" << std::endl;
1009  throw;
1010  }
1011  if (jptch2.contains("MinLevel"))
1012  geomRef.minLvl = jptch2["MinLevel"].as<double>();
1013  else {
1014  std::cerr << "Please define \"MinLevel\"\n" << std::endl;
1015  throw;
1016  }
1017  if (jptch2.contains("MaxLevel"))
1018  geomRef.maxLvl = jptch2["MaxLevel"].as<int>();
1019  else {
1020  std::cerr << "Please define \"MaxLevel\"\n" << std::endl;
1021  throw;
1022  }
1023 
1024  (params->geomRefs).push_back(geomRef);
1025  }
1026  }
1027 
1028  // Features
1029  std::string cap6 = "Feature File";
1030  if (castMeshParams.contains(cap6)) {
1031  params->_withFeatureEdgeFile = true;
1032  for (auto jptch3 : castMeshParams[cap6].array_range()) {
1033  shmFeatureEdgeRef ftrOne;
1034  if (jptch3.contains("File Name"))
1035  ftrOne.fileName = jptch3["File Name"].as<std::string>();
1036  else {
1037  std::cerr << "Please provide feature file name" << std::endl;
1038  throw;
1039  }
1040 
1041  if (jptch3.contains("MinLevel"))
1042  ftrOne.minLvl = jptch3["MinLevel"].as<double>();
1043  else {
1044  ftrOne.minLvl = 1;
1045  }
1046 
1047  if (jptch3.contains("MaxLevel"))
1048  ftrOne.maxLvl = jptch3["MaxLevel"].as<int>();
1049  else {
1050  std::cerr << "Please define maximum surface refinement"
1051  << "\"MaxLevel\"\n"
1052  << std::endl;
1053  throw;
1054  }
1055  (params->ftrEdge).push_back(ftrOne);
1056  }
1057  }
1058 
1059  // Snapping Controls
1060  if (snapParams.contains("nSmoothPatch"))
1061  params->snapSmthPatch = snapParams["nSmoothPatch"].as<int>();
1062  else {
1063  params->snapSmthPatch = 4;
1064  }
1065  if (snapParams.contains("tolerance"))
1066  params->snapTol = snapParams["tolerance"].as<double>();
1067  else {
1068  params->snapTol = 0.5;
1069  }
1070  if (snapParams.contains("snapSolveIter"))
1071  params->solveSnapIter = snapParams["snapSolveIter"].as<int>();
1072  else {
1073  params->solveSnapIter = 200;
1074  }
1075  if (snapParams.contains("snapRelaxIter"))
1076  params->relaxSnapIter = snapParams["snapRelaxIter"].as<int>();
1077  else {
1078  params->relaxSnapIter = 6;
1079  }
1080  if (snapParams.contains("nFeatureSnapIter"))
1081  params->nFeatureSnapIter = snapParams["nFeatureSnapIter"].as<int>();
1082  else
1083  params->nFeatureSnapIter = 10;
1084  if (snapParams.contains("implicitFeatureSnap"))
1085  params->implicitFeatureSnap =
1086  snapParams["implicitFeatureSnap"].as<bool>();
1087  else
1088  params->implicitFeatureSnap = false;
1089  if (snapParams.contains("explicitFeatureSnap"))
1090  params->explicitFeatureSnap =
1091  snapParams["explicitFeatureSnap"].as<bool>();
1092  else
1093  params->explicitFeatureSnap = true;
1094  if (snapParams.contains("multiRegionFeatureSnap"))
1095  params->multiRegionFeatureSnap =
1096  snapParams["multiRegionFeatureSnap"].as<bool>();
1097  else
1098  params->multiRegionFeatureSnap = false;
1099 
1100  // Layer controls
1101  if (layerParams.contains("relativeSizes"))
1102  params->_relSize = layerParams["relativeSizes"].as<bool>();
1103  else {
1104  params->_relSize = 1;
1105  }
1106  if (layerParams.contains("expansionRatio"))
1107  params->expRatio = layerParams["expansionRatio"].as<double>();
1108  else {
1109  params->expRatio = 1.3;
1110  }
1111  if (layerParams.contains("finalLayerThickness"))
1112  params->finLThick = layerParams["finalLayerThickness"].as<double>();
1113  else {
1114  params->finLThick = 1.0;
1115  }
1116  if (layerParams.contains("minThickness"))
1117  params->minThick = layerParams["minThickness"].as<double>();
1118  else {
1119  params->minThick = 0.1;
1120  }
1121  if (layerParams.contains("firstLayerThickness"))
1122  params->firstLyrThickness =
1123  layerParams["firstLayerThickness"].as<double>();
1124  else
1125  params->firstLyrThickness = -1.0;
1126  if (layerParams.contains("thickness"))
1127  params->thickness = layerParams["thickness"].as<double>();
1128  else
1129  params->thickness = -1.0;
1130  if (layerParams.contains("nGrow"))
1131  params->nGrow = layerParams["nGrow"].as<int>();
1132  else {
1133  params->nGrow = 0;
1134  }
1135  if (layerParams.contains("featureAngle"))
1136  params->lyrFeatAngle = layerParams["featureAngle"].as<double>();
1137  else {
1138  params->lyrFeatAngle = 30;
1139  }
1140  if (layerParams.contains("nRelaxIter"))
1141  params->lyrRelaxIter = layerParams["nRelaxIter"].as<int>();
1142  else {
1143  params->lyrRelaxIter = 3;
1144  }
1145  if (layerParams.contains("nSmoothSurfaceNormals"))
1146  params->lyrSmthSurfNorm =
1147  layerParams["nSmoothSurfaceNormals"].as<int>();
1148  else {
1149  params->lyrSmthSurfNorm = 1;
1150  }
1151  if (layerParams.contains("nSmoothNormals"))
1152  params->lyrSmthNorm = layerParams["nSmoothNormals"].as<int>();
1153  else {
1154  params->lyrSmthNorm = 3;
1155  }
1156  if (layerParams.contains("nSmoothThickness"))
1157  params->lyrSmthThick = layerParams["nSmoothThickness"].as<int>();
1158  else {
1159  params->lyrSmthThick = 2;
1160  }
1161  if (layerParams.contains("maxFaceThicknessRatio"))
1162  params->lyrMaxFcTR = layerParams["maxFaceThicknessRatio"].as<double>();
1163  else {
1164  params->lyrMaxFcTR = 0.5;
1165  }
1166  if (layerParams.contains("maxThicknessToMedialRatio"))
1167  params->lyrMaxThickTMR =
1168  layerParams["maxThicknessToMedialRatio"].as<double>();
1169  else {
1170  params->lyrMaxThickTMR = 1.0;
1171  }
1172  if (layerParams.contains("minMedialAxisAngle"))
1173  params->lyrMinMedAngl = layerParams["minMedialAxisAngle"].as<double>();
1174  else {
1175  params->lyrMinMedAngl = 90;
1176  }
1177  if (layerParams.contains("nBufferCellsNoExtrude"))
1178  params->lyrBuffrCells = layerParams["nBufferCellsNoExtrude"].as<int>();
1179  else {
1180  params->lyrBuffrCells = 0;
1181  }
1182  if (layerParams.contains("nLayerIter"))
1183  params->lyrIter = layerParams["nLayerIter"].as<int>();
1184  else {
1185  params->lyrIter = 50;
1186  }
1187  if (layerParams.contains("nRelaxedIter"))
1188  params->nRelaxedIter = layerParams["nRelaxedIter"].as<int>();
1189  else {
1190  params->nRelaxedIter = 20;
1191  }
1192  if (layerParams.contains("slipFeatureAngle"))
1193  params->slipFeatureAngle = layerParams["slipFeatureAngle"].as<int>();
1194  else {
1195  params->slipFeatureAngle = 20;
1196  }
1197  if (layerParams.contains("nMedialAxisIter"))
1198  params->nMedialAxisIter = layerParams["nMedialAxisIter"].as<int>();
1199  else
1200  params->nMedialAxisIter = -1;
1201  if (layerParams.contains("nSmoothDisplacement"))
1202  params->nSmoothDisplacement =
1203  layerParams["nSmoothDisplacement"].as<int>();
1204  else
1205  params->nSmoothDisplacement = -1;
1206 
1207  // Layers
1208  std::string cap7 = "Layers";
1209  if (layerParams.contains(cap7)) {
1210  for (auto jptch3 : layerParams[cap7].array_range()) {
1211  shmLayers lyrOne;
1212  if (jptch3.contains("Patch Name"))
1213  lyrOne.patchName = jptch3["Patch Name"].as<std::string>();
1214  else {
1215  std::cerr << "Please provide patch name for layers" << std::endl;
1216  throw;
1217  }
1218 
1219  if (jptch3.contains("nSurfaceLayers"))
1220  lyrOne.nSurfaceLayers = jptch3["nSurfaceLayers"].as<int>();
1221  else {
1222  lyrOne.nSurfaceLayers = 1;
1223  }
1224 
1225  if (jptch3.contains("expansionRatio"))
1226  lyrOne.expansionRatio = jptch3["expansionRatio"].as<double>();
1227  else {
1228  lyrOne.expansionRatio = 1;
1229  }
1230 
1231  if (jptch3.contains("finalLayerThickness"))
1232  lyrOne.finalLayerThickness =
1233  jptch3["finalLayerThickness"].as<double>();
1234  else {
1235  lyrOne.finalLayerThickness = 1;
1236  }
1237 
1238  if (jptch3.contains("firstLayerThickness"))
1239  lyrOne.firstLyrThickness =
1240  jptch3["firstLayerThickness"].as<double>();
1241  else {
1242  lyrOne.firstLyrThickness = -1.0;
1243  }
1244 
1245  if (jptch3.contains("thickness"))
1246  lyrOne.finalLayerThickness = jptch3["thickness"].as<double>();
1247  else {
1248  lyrOne.thickness = -1.0;
1249  }
1250 
1251  if (jptch3.contains("minThickness"))
1252  lyrOne.minThickness = jptch3["minThickness"].as<double>();
1253  else {
1254  lyrOne.minThickness = 1;
1255  }
1256  params->layerVec.push_back(lyrOne);
1257  }
1258  }
1259 
1260  // Mesh Quality Controls
1261  if (qcMeshParams.contains("maxNonOrtho"))
1262  params->qcMaxNOrtho = qcMeshParams["maxNonOrtho"].as<int>();
1263  else {
1264  params->qcMaxNOrtho = 65;
1265  }
1266  if (qcMeshParams.contains("maxBoundarySkewness"))
1267  params->qcMaxBndrySkew =
1268  qcMeshParams["maxBoundarySkewness"].as<double>();
1269  else {
1270  params->qcMaxBndrySkew = 20;
1271  }
1272  if (qcMeshParams.contains("maxInternalSkewness"))
1273  params->qcMaxIntSkew = qcMeshParams["maxInternalSkewness"].as<double>();
1274  else {
1275  params->qcMaxIntSkew = 4;
1276  }
1277  if (qcMeshParams.contains("maxConcave"))
1278  params->qcMaxConc = qcMeshParams["maxConcave"].as<double>();
1279  else {
1280  params->qcMaxConc = 80;
1281  }
1282  if (qcMeshParams.contains("minVol"))
1283  params->qcMinVol = qcMeshParams["minVol"].as<double>();
1284  else {
1285  params->qcMinVol = 1e-13;
1286  }
1287  if (qcMeshParams.contains("minTetQuality"))
1288  params->qcMinTetQ = qcMeshParams["minTetQuality"].as<double>();
1289  else {
1290  params->qcMinTetQ = 1e-15;
1291  }
1292  if (qcMeshParams.contains("minArea"))
1293  params->qcMinArea = qcMeshParams["minArea"].as<double>();
1294  else {
1295  params->qcMinArea = -1;
1296  }
1297  if (qcMeshParams.contains("minTwist"))
1298  params->qcMinTwist = qcMeshParams["minTwist"].as<double>();
1299  else {
1300  params->qcMinTwist = 0.02;
1301  }
1302  if (qcMeshParams.contains("minFaceWeight"))
1303  params->qcMinFaceW = qcMeshParams["minFaceWeight"].as<double>();
1304  else {
1305  params->qcMinFaceW = 0.05;
1306  }
1307  if (qcMeshParams.contains("minVolRatio"))
1308  params->qcMinVolRto = qcMeshParams["minVolRatio"].as<double>();
1309  else {
1310  params->qcMinVolRto = 0.01;
1311  }
1312  if (qcMeshParams.contains("minDeterminant"))
1313  params->qcMinDet = qcMeshParams["minDeterminant"].as<double>();
1314  else {
1315  params->qcMinDet = 0.001;
1316  }
1317  if (qcMeshParams.contains("minTriangleTwist"))
1318  params->qcMinTrTwist = qcMeshParams["minTriangleTwist"].as<double>();
1319  else {
1320  params->qcMinTrTwist = -1;
1321  }
1322  if (qcMeshParams.contains("qcnSmoothScale"))
1323  params->qcSmthScale = qcMeshParams["qcnSmoothScale"].as<int>();
1324  else {
1325  params->qcSmthScale = 5;
1326  }
1327  if (qcMeshParams.contains("errorReduction"))
1328  params->qcErrRedctn = qcMeshParams["errorReduction"].as<double>();
1329  else {
1330  params->qcErrRedctn = 0.75;
1331  }
1332  if (shmparams.contains("mergeTolerance"))
1333  params->mergeTol = shmparams["mergeTolerance"].as<double>();
1334  else {
1335  params->mergeTol = 1e-06;
1336  }
1337 
1338  auto *mshgndrvobj = new MeshGenDriver(ifname, meshEngine, params, ofname);
1339  return mshgndrvobj;
1340  }
1341 #endif
1342  } else if (!meshEngine.compare("blockMesh")) {
1343 #ifndef HAVE_CFMSH
1344  std::cerr << "Nemosys must be recompiled with cfMesh support" << std::endl;
1345  exit(1);
1346 #else
1347  blockMeshParams *params = new blockMeshParams();
1348  std::string defaults =
1349  inputjson["Meshing Parameters"]["blockMesh Parameters"]
1350  .as<std::string>();
1351  if (!defaults.compare("default")) {
1352  MeshGenDriver *mshgndrvobj =
1353  new MeshGenDriver(ifname, meshEngine, params, ofname);
1354  return mshgndrvobj;
1355  } else {
1356  jsoncons::json bmshparams =
1357  inputjson["Meshing Parameters"]["blockMesh Parameters"];
1358 
1359  if (inputjson["Mesh File Options"].contains("Input Dict File"))
1360  params->_ownBlockMshDict =
1361  inputjson["Mesh File Options"]["Input Dict File"].as<bool>();
1362 
1363  // Parameter parsing starts here
1364  if (bmshparams.contains("Block Geometry"))
1365  params->_isBlock = bmshparams["Block Geometry"].as<bool>();
1366  else {
1367  std::cerr << "Define your choice of geometry using bool keys"
1368  << "\n"
1369  << std::endl;
1370  throw;
1371  }
1372  if (bmshparams.contains("Sphere Geometry"))
1373  params->_isSphere = bmshparams["Sphere Geometry"].as<bool>();
1374  else {
1375  std::cerr << "Define your choice of geometry using bool keys"
1376  << "\n"
1377  << std::endl;
1378  throw;
1379  }
1380  if (bmshparams.contains("Cylinder/Tapered_Cone Geometry"))
1381  params->_isCylinder_TCone =
1382  bmshparams["Cylinder/Tapered_Cone Geometry"].as<bool>();
1383  else {
1384  std::cerr << "Define your choice of geometry using bool keys"
1385  << "\n"
1386  << std::endl;
1387  throw;
1388  }
1389  if (bmshparams.contains("scaleToMeters"))
1390  params->cnvrtToMeters = bmshparams["scaleToMeters"].as<double>();
1391  else {
1392  std::cerr << "Define your choice of geometry using bool keys"
1393  << "\n"
1394  << std::endl;
1395  throw;
1396  }
1397 
1398  if (bmshparams.contains("Cell_Size")) {
1399  params->_cellSizeDefined = true;
1400  params->cellSize = bmshparams["Cell_Size"].as<double>();
1401  } else {
1402  params->cellSize = -1;
1403  params->_cellSizeDefined = false;
1404  }
1405 
1406  if (bmshparams.contains("XdirectionCells"))
1407  params->cellsXDir = bmshparams["XdirectionCells"].as<int>();
1408  else {
1409  if (params->_cellSizeDefined) {
1410  // Nothing
1411  } else {
1412  std::cerr << "Define cell numbers in X direction"
1413  << "\n"
1414  << std::endl;
1415  throw;
1416  }
1417  }
1418  if (bmshparams.contains("YdirectionCells"))
1419  params->cellsYDir = bmshparams["YdirectionCells"].as<int>();
1420  else {
1421  if (params->_cellSizeDefined) {
1422  // Nothing
1423  } else {
1424  std::cerr << "Define cell numbers in Y direction"
1425  << "\n"
1426  << std::endl;
1427  throw;
1428  }
1429  }
1430  if (bmshparams.contains("ZdirectionCells"))
1431  params->cellsZDir = bmshparams["ZdirectionCells"].as<int>();
1432  else {
1433  if (params->_cellSizeDefined) {
1434  // Nothing
1435  } else {
1436  std::cerr << "Define cell size for mesh"
1437  << "\n"
1438  << std::endl;
1439  throw;
1440  }
1441  }
1442 
1443  if (bmshparams.contains("Block Parameters")) {
1444  if (bmshparams["Block Parameters"].contains("Auto_Generate")) {
1445  params->_autoGenerateBox = true;
1446 
1447  if (inputjson["Mesh File Options"].contains("Input Geometry File"))
1448  params->packFileName =
1449  inputjson["Mesh File Options"]["Input Geometry File"]
1450  .as<std::string>();
1451  else {
1452  std::cerr << "A geometry file should be supplied.\n";
1453  throw;
1454  }
1455 
1456  if (bmshparams["Block Parameters"]["Auto_Generate"].contains(
1457  "Offset_XDir"))
1458  params->offsetX =
1459  bmshparams["Block Parameters"]["Auto_Generate"]["Offset_XDir"]
1460  .as<double>();
1461  else {
1462  params->offsetX = 0.1;
1463  }
1464  if (bmshparams["Block Parameters"]["Auto_Generate"].contains(
1465  "Offset_YDir"))
1466  params->offsetY =
1467  bmshparams["Block Parameters"]["Auto_Generate"]["Offset_YDir"]
1468  .as<double>();
1469  else {
1470  params->offsetY = 0.1;
1471  }
1472  if (bmshparams["Block Parameters"]["Auto_Generate"].contains(
1473  "Offset_ZDir"))
1474  params->offsetZ =
1475  bmshparams["Block Parameters"]["Auto_Generate"]["Offset_ZDir"]
1476  .as<double>();
1477  else {
1478  params->offsetZ = 0.1;
1479  }
1480 
1481  } else {
1482  params->_autoGenerateBox = false;
1483  }
1484 
1485  if (bmshparams["Block Parameters"].contains("X1"))
1486  params->initX = bmshparams["Block Parameters"]["X1"].as<double>();
1487  else {
1488  if (!(params->_autoGenerateBox)) {
1489  std::cerr << "Define initial point for block (X Y Z)!\n"
1490  << std::endl;
1491  throw;
1492  } else {
1493  std::cout << "Box will be generated automatically" << std::endl;
1494  }
1495  }
1496  if (bmshparams["Block Parameters"].contains("Y1"))
1497  params->initY = bmshparams["Block Parameters"]["Y1"].as<double>();
1498  else {
1499  if (!(params->_autoGenerateBox)) {
1500  std::cerr << "Define initial point for block (X Y Z)!\n"
1501  << std::endl;
1502  throw;
1503  } else {
1504  std::cout << "Box will be generated automatically" << std::endl;
1505  }
1506  }
1507  if (bmshparams["Block Parameters"].contains("Z1"))
1508  params->initZ = bmshparams["Block Parameters"]["Z1"].as<double>();
1509  else {
1510  if (!(params->_autoGenerateBox)) {
1511  std::cerr << "Define initial point for block (X Y Z)!\n"
1512  << std::endl;
1513  throw;
1514  } else {
1515  std::cout << "Box will be generated automatically" << std::endl;
1516  }
1517  }
1518  if (bmshparams["Block Parameters"].contains("LengthX"))
1519  params->lenX = bmshparams["Block Parameters"]["LengthX"].as<double>();
1520  else {
1521  if (!(params->_autoGenerateBox)) {
1522  std::cerr << "Define desired box length in X,Y,Z direction\n"
1523  << std::endl;
1524  throw;
1525  } else {
1526  std::cout << "Box will be generated automatically" << std::endl;
1527  }
1528  }
1529  if (bmshparams["Block Parameters"].contains("LengthY"))
1530  params->lenY = bmshparams["Block Parameters"]["LengthY"].as<double>();
1531  else {
1532  if (!(params->_autoGenerateBox)) {
1533  std::cerr << "Define desired box length in X,Y,Z direction\n"
1534  << std::endl;
1535  throw;
1536  } else {
1537  std::cout << "Box will be generated automatically" << std::endl;
1538  }
1539  }
1540  if (bmshparams["Block Parameters"].contains("LengthZ"))
1541  params->lenZ = bmshparams["Block Parameters"]["LengthZ"].as<double>();
1542  else {
1543  if (!(params->_autoGenerateBox)) {
1544  std::cerr << "Define desired box length in X,Y,Z direction\n"
1545  << std::endl;
1546  throw;
1547  } else {
1548  std::cout << "Box will be generated automatically" << std::endl;
1549  }
1550  }
1551  if (bmshparams["Block Parameters"].contains("GradingXdir"))
1552  params->smplGradingX =
1553  bmshparams["Block Parameters"]["GradingXdir"].as<double>();
1554  else {
1555  params->smplGradingX = 1;
1556  }
1557  if (bmshparams["Block Parameters"].contains("GradingYdir"))
1558  params->smplGradingY =
1559  bmshparams["Block Parameters"]["GradingYdir"].as<double>();
1560  else {
1561  params->smplGradingY = 1;
1562  }
1563  if (bmshparams["Block Parameters"].contains("GradingZdir"))
1564  params->smplGradingZ =
1565  bmshparams["Block Parameters"]["GradingZdir"].as<double>();
1566  else {
1567  params->smplGradingZ = 1;
1568  }
1569  }
1570 
1571  if (bmshparams.contains("Sphere Parameters")) {
1572  if (bmshparams["Sphere Parameters"].contains("Center X"))
1573  params->centerX =
1574  bmshparams["Sphere Parameters"]["Center X"].as<double>();
1575  else {
1576  std::cerr << "Define sphere center!\n" << std::endl;
1577  throw;
1578  }
1579  if (bmshparams["Sphere Parameters"].contains("Center Y"))
1580  params->centerY =
1581  bmshparams["Sphere Parameters"]["Center Y"].as<double>();
1582  else {
1583  std::cerr << "Define sphere center!\n" << std::endl;
1584  throw;
1585  }
1586  if (bmshparams["Sphere Parameters"].contains("Center Z"))
1587  params->centerZ =
1588  bmshparams["Sphere Parameters"]["Center Z"].as<double>();
1589  else {
1590  std::cerr << "Define sphere center!\n" << std::endl;
1591  throw;
1592  }
1593  if (bmshparams["Sphere Parameters"].contains("Radius"))
1594  params->radius =
1595  bmshparams["Sphere Parameters"]["Radius"].as<double>();
1596  else {
1597  std::cerr << "Define sphere radius!\n" << endl;
1598  throw;
1599  }
1600  if (bmshparams["Sphere Parameters"].contains("GradingXdir"))
1601  params->sphrGradingX =
1602  bmshparams["Sphere Parameters"]["GradingXdir"].as<double>();
1603  else {
1604  params->sphrGradingX = 1;
1605  }
1606  if (bmshparams["Sphere Parameters"].contains("GradingYdir"))
1607  params->sphrGradingY =
1608  bmshparams["Sphere Parameters"]["GradingYdir"].as<double>();
1609  else {
1610  params->sphrGradingY = 1;
1611  }
1612  if (bmshparams["Sphere Parameters"].contains("GradingXdir"))
1613  params->sphrGradingZ =
1614  bmshparams["Sphere Parameters"]["GradingZdir"].as<double>();
1615  else {
1616  params->sphrGradingZ = 1;
1617  }
1618  }
1619 
1620  if (bmshparams.contains("Cylinder/Tapered_Cone Parameters")) {
1621  if (bmshparams["Cylinder/Tapered_Cone Parameters"].contains("Center X"))
1622  params->centerCyl[0] =
1623  bmshparams["Cylinder/Tapered_Cone Parameters"]["Center X"]
1624  .as<double>();
1625  else {
1626  std::cerr << "Define center point for cylinder axis\n" << std::endl;
1627  throw;
1628  }
1629  if (bmshparams["Cylinder/Tapered_Cone Parameters"].contains("Center Y"))
1630  params->centerCyl[1] =
1631  bmshparams["Cylinder/Tapered_Cone Parameters"]["Center Y"]
1632  .as<double>();
1633  else {
1634  std::cerr << "Define center point for cylinder axis\n" << std::endl;
1635  throw;
1636  }
1637  if (bmshparams["Cylinder/Tapered_Cone Parameters"].contains("Center Z"))
1638  params->centerCyl[2] =
1639  bmshparams["Cylinder/Tapered_Cone Parameters"]["Center Z"]
1640  .as<double>();
1641  else {
1642  std::cerr << "Define center point for cylinder axis\n" << std::endl;
1643  throw;
1644  }
1645  if (bmshparams["Cylinder/Tapered_Cone Parameters"].contains("Radius1"))
1646  params->radius1 =
1647  bmshparams["Cylinder/Tapered_Cone Parameters"]["Radius1"]
1648  .as<double>();
1649 
1650  if (bmshparams["Cylinder/Tapered_Cone Parameters"].contains(
1651  "Radius2")) {
1652  params->radius2 =
1653  bmshparams["Cylinder/Tapered_Cone Parameters"]["Radius2"]
1654  .as<double>();
1655  } else {
1656  params->radius2 =
1657  bmshparams["Cylinder/Tapered_Cone Parameters"]["Radius1"]
1658  .as<double>();
1659  }
1660 
1661  if (bmshparams["Cylinder/Tapered_Cone Parameters"].contains(
1662  "GradingXdir"))
1663  params->cylGrading[0] =
1664  bmshparams["Cylinder/Tapered_Cone Parameters"]["GradingXdir"]
1665  .as<double>();
1666  else {
1667  params->cylGrading[0] = 1;
1668  }
1669  if (bmshparams["Cylinder/Tapered_Cone Parameters"].contains(
1670  "GradingYdir"))
1671  params->cylGrading[1] =
1672  bmshparams["Cylinder/Tapered_Cone Parameters"]["GradingYdir"]
1673  .as<double>();
1674  else {
1675  params->cylGrading[1] = 1;
1676  }
1677  if (bmshparams["Cylinder/Tapered_Cone Parameters"].contains(
1678  "GradingXdir"))
1679  params->cylGrading[2] =
1680  bmshparams["Cylinder/Tapered_Cone Parameters"]["GradingZdir"]
1681  .as<double>();
1682  else {
1683  params->cylGrading[2] = 1;
1684  }
1685 
1686  if (bmshparams["Cylinder/Tapered_Cone Parameters"].contains("Height"))
1687  params->height =
1688  bmshparams["Cylinder/Tapered_Cone Parameters"]["Height"]
1689  .as<double>();
1690  else {
1691  std::cerr << "Define cylinder height\n" << endl;
1692  }
1693  }
1694 
1695  auto *mshgndrvobj = new MeshGenDriver(ifname, meshEngine, params, ofname);
1696  return mshgndrvobj;
1697  }
1698 
1699 #endif
1700  }
1701 
1702  else {
1703  std::cerr << "Mesh generation engine " << meshEngine << " is not supported"
1704  << std::endl;
1705  exit(1);
1706  }
1707 }
1708 
1709 } // namespace DRV
1710 } // namespace NEM
snappymeshGen facilitates full-hexahedral/hex-dominent meshing of complex geometries with surface...
Definition: snappymeshGen.H:55
blockMeshGen <– meshGen <– meshBase This class incorporates mesh generating method of blockMesh uti...
Definition: blockMeshGen.H:54
snappymeshParams contains all parameters essential for mesh generation using snappymeshGen class meth...
A structure for STL definition.
std::unique_ptr< NEM::MSH::geoMeshBase > gmData
Definition: meshGen.H:54
std::string defType
Definition: cfmeshParams.H:71
double cnvrtToMeters
Defines mesh scale to meters.
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
std::string type
Type of size field, eg.
Definition: gmshParams.H:51
double refThickness
Definition: cfmeshParams.H:52
double minLvl
Minimum refinement level.
std::string defName
Definition: cfmeshParams.H:70
std::array< int, 3 > vert
Definition: gmshParams.H:75
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
std::vector< std::pair< std::string, double > > params
Vector of pairs to store list of numbers.
Definition: gmshParams.H:54
std::vector< std::pair< std::string, std::vector< std::string > > > strg_list_params
Definition: gmshParams.H:61
A structure to respresent regions refining capability in snappymeshGen.
blockMeshParams contains the parameters important for automatic meshing using blockMeshGen class...
static meshBase * Create(const std::string &fname)
Construct vtkMesh from filename.
Definition: meshBase.C:78
A struct for defining hexahedral transfinite volumes.
Definition: gmshParams.H:67
std::array< std::string, 3 > type
Definition: gmshParams.H:79
std::string find_ext(const std::string &fname)
int maxLvl
Maximum refinement level.
std::string patchName
Definition: cfmeshParams.H:56
std::string snappyPatchName
std::string geomFileName
Input geometry STL name.
std::string patchName
Definition: cfmeshParams.H:49
std::string trim_fname(const std::string &name, const std::string &ext)
jsoncons::optional< double > cellSize
user can define mesh cell size here (if not set, nCells used instead).
double maxFrstLyrThk
Definition: cfmeshParams.H:59
std::array< double, 3 > coef
Definition: gmshParams.H:82
double finalLayerThickness
std::string patchType
gmshParams contains all parameters essential for mesh generation using gmshGen class methods...
Definition: gmshParams.H:92
std::array< std::array< double, 3 >, 3 > axis
Definition: gmshParams.H:72
std::vector< std::pair< std::string, std::vector< double > > > num_list_params
Vector of pairs to store list of strings.
Definition: gmshParams.H:57
std::shared_ptr< meshBase > mesh
static std::shared_ptr< meshBase > CreateShared(const std::string &fname)
Create shared ptr from fname.
Definition: meshBase.C:171
double firstLyrThickness
int maxLvl
Maximum refinement level.
int id
Size Field ID.
Definition: gmshParams.H:52
double thickness
std::string name
Definition: cfmeshParams.H:44
double minLvl
< Patch Type in Mesh
std::vector< cfmNewPatch > newPatches
Definition: cfmeshParams.H:72
A structure for feature edge refinement.
A structure to represent geometry surface refining capability in snappymeshgGen.
double blThkRto
Definition: cfmeshParams.H:58
double mergeTol
merge tolerance for mesh
std::map< std::string, std::string > params
Definition: cfmeshParams.H:45
std::string mode
Inside, Outside.
std::string STLPatchName
static std::unique_ptr< NemDriver > readJSON(const jsoncons::json &inputjson)
Factory method for all drivers.
Definition: NemDriver.C:37
std::string patchName
double expansionRatio
virtual int createMeshFromSTL(const char *fname)=0
A structure for defining volumetric mesh size fields.
Definition: gmshParams.H:50
double minThickness
vtkSmartPointer< vtkDataSet > getDataSet() const
Definition: meshGen.H:53
A struct for layer addition.