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.
cfmeshGen.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 <iostream>
30 #include <string>
33 #include "Mesh/geoMeshFactory.H"
34 #include "Mesh/geoMeshBase.H"
35 #include "Mesh/foamGeoMesh.H"
36 
37 // vtk
38 #include <vtkIdList.h>
39 
40 // openfoam headers
41 #include <fileName.H>
42 #include <getDicts.H>
43 
44 // cfmesh headers
45 #include <cartesian2DMeshGenerator.H>
46 #include <triSurfaceDetectFeatureEdges.H>
47 #include <triSurfacePatchManipulator.H>
48 #include <triSurf.H>
49 #include <tetMeshGenerator.H>
50 #include <polyMeshGenModifier.H>
51 #include <meshOptimizer.H>
52 #include <cartesianMeshGenerator.H>
53 #include <voronoiMeshGenerator.H>
54 
56  // default meshing parameters
57  params_ = new cfmeshParams();
58  defaults = true;
59 
60  // Initialization tasks
61  initialize();
62 }
63 
64 cfmeshGen::cfmeshGen(cfmeshParams *params) : defaults(false), params_(params) {
65  // Initialization tasks
66  initialize();
67 }
68 
70 
72  // surface feature edge treatment
73  if (params_->srfEdge.has_value())
75  std::cerr << "A problem occured during edge detection step!\n";
76  throw;
77  }
78 
79  // create dictionaries needed in memory
80  bool writeDicts;
81  if (params_->isPackMesh)
82  writeDicts = true;
83  else
84  writeDicts = false;
85  std::unique_ptr<getDicts> initFoam;
86  initFoam = std::unique_ptr<getDicts>(new getDicts());
87  controlDict_ = initFoam->createControlDict(writeDicts);
88  fvSchemes_ = initFoam->createFvSchemes(writeDicts);
89  fvSolution_ = initFoam->createFvSolution(writeDicts);
90  createMshDict(writeDicts);
91 
92  runTime_ =
93  std::unique_ptr<Foam::Time>(new Foam::Time(controlDict_.get(), ".", "."));
94 
95  //- 2d cartesian mesher cannot be run in parallel
96  Foam::argList::noParallel();
97 }
98 
99 int cfmeshGen::createMeshFromSTL(const char *fname) {
100  bool writeMsh;
101  if (params_->isPackMesh)
102  writeMsh = true;
103  else
104  writeMsh = false;
105 
106  // mesh generation and I/O
107  Foam::Info << "Generating mesh with cfMesh engine" << Foam::endl;
108  if (params_->generator == "cartesian2D") {
109  Foam::Module::cartesian2DMeshGenerator cmg(*runTime_);
110  std::cout << "ExecutionTime = " << runTime_->elapsedCpuTime() << " s\n"
111  << "ClockTime = " << runTime_->elapsedClockTime() << " s"
112  << std::endl;
113  cmg.writeMesh();
114  } else if (params_->generator == "tetMesh") {
115  Foam::Module::tetMeshGenerator tmg(*runTime_);
116  std::cout << "ExecutionTime = " << runTime_->elapsedCpuTime() << " s\n"
117  << "ClockTime = " << runTime_->elapsedClockTime() << " s"
118  << std::endl;
119  tmg.writeMesh();
120 
121  // post-processing steps
122  if (params_->improveMeshQuality.has_value()) improveMeshQuality();
123  } else if (params_->generator == "cartesian3D") {
124  Foam::Module::cartesianMeshGenerator cmg(*runTime_);
125  std::cout << "ExecutionTime = " << runTime_->elapsedCpuTime() << " s\n"
126  << "ClockTime = " << runTime_->elapsedClockTime() << " s"
127  << std::endl;
128  cmg.writeMesh();
129  } else if (params_->generator == "polyMesh") {
130  Foam::Module::voronoiMeshGenerator pmg(*runTime_);
131  std::cout << "ExecutionTime = " << runTime_->elapsedCpuTime() << " s\n"
132  << "ClockTime = " << runTime_->elapsedClockTime() << " s"
133  << std::endl;
134  pmg.writeMesh();
135  } else {
136  std::cerr << (params_->generator)
137  << " is not a supported mesh generator.\n";
138  throw;
139  }
140 
141  // Create foamGeoMesh
142  if (writeMsh) {
143  gmData.reset();
144  gmData = std::unique_ptr<NEM::MSH::geoMeshBase>(NEM::MSH::Read(".foam"));
145  } else {
146  auto fgm_ = std::unique_ptr<NEM::MSH::foamGeoMesh>(
147  new NEM::MSH::foamGeoMesh(fmesh_.get(), ""));
148  gmData = std::unique_ptr<NEM::MSH::geoMeshBase>(
149  dynamic_cast<NEM::MSH::geoMeshBase *>(fgm_.get()));
150  return 0;
151  }
152 
153  return 0;
154 }
155 
157  std::cout << "Performing surface feature edge detection.\n";
158  std::string of = "./" + caseName + "_feature.ftr";
159  Foam::fileName inFileName(params_->geomFilePath);
160  Foam::fileName outFileName(of);
161 
162  if (outFileName == inFileName) {
163  std::cerr << "Output file " << outFileName
164  << " would overwrite the input file.\n";
165  throw;
166  }
167 
168  double tol = params_->srfEdge.value().srfEdgAng;
169  std::cout << "Using " << tol << " deg angle\n";
170 
171  Foam::Module::triSurf originalSurface(inFileName);
172 
173  Foam::Module::triSurfaceDetectFeatureEdges edgeDetector(originalSurface, tol);
174  edgeDetector.detectFeatureEdges();
175 
176  if (outFileName.ext() == "fms" || outFileName.ext() == "FMS") {
177  std::cout << "Writing : " << outFileName << std::endl;
178  originalSurface.writeSurface(outFileName);
179  } else {
180  Foam::Module::triSurfacePatchManipulator manipulator(originalSurface);
181  const Foam::Module::triSurf *newSurfPtr = manipulator.surfaceWithPatches();
182 
183  std::cout << "Writing : " << outFileName << std::endl;
184  newSurfPtr->writeSurface(outFileName);
185  delete newSurfPtr;
186  }
187 
188  // change cad input file
189  params_->geomFilePath = of;
190 
191  return 0;
192 }
193 
195  std::cout << "Performing mesh quality improvements.\n";
196 
197  //- load the mesh from disk
198  Foam::Module::polyMeshGen pmg(*runTime_);
199  pmg.read();
200 
201  //- construct the smoother
202  Foam::Module::meshOptimizer mOpt(pmg);
203 
204  const auto &meshQual = params_->improveMeshQuality.value();
205 
206  if ((meshQual.qltConCelSet) != "none") {
207  //- lock cells in constrainedCellSet
208  mOpt.lockCellsInSubset((meshQual.qltConCelSet));
209 
210  //- find boundary faces which shall be locked
211  Foam::Module::labelLongList lockedBndFaces, selectedCells;
212 
213  const Foam::label sId = pmg.cellSubsetIndex((meshQual.qltConCelSet));
214  pmg.cellsInSubset(sId, selectedCells);
215 
216  Foam::boolList activeCell(pmg.cells().size(), false);
217  for (int iCl = 0; iCl < selectedCells.size(); iCl++)
218  activeCell[selectedCells[iCl]] = true;
219  }
220 
221  //- clear geometry information before volume smoothing
222  pmg.clearAddressingData();
223 
224  //- perform optimisation using the laplace smoother and
225  mOpt.optimizeMeshFV((meshQual.qltNLop), (meshQual.qltNLop),
226  (meshQual.qltNItr), (meshQual.qltNSrfItr));
227 
228  //- perform optimisation of worst quality faces
229  mOpt.optimizeMeshFVBestQuality((meshQual.qltNLop), (meshQual.qltQltThr));
230 
231  //- check the mesh again and untangl bad regions if any of them exist
232  mOpt.untangleMeshFV((meshQual.qltNLop), (meshQual.qltNItr),
233  (meshQual.qltNSrfItr));
234 
235  std::cout << "Finished optimization cycle\n";
236  pmg.write();
237 
238  return 0;
239 }
240 
241 void cfmeshGen::createMshDict(const bool &write) {
242  meshDict_ =
243  std::unique_ptr<Foam::dictionary>(new Foam::dictionary("meshDict"));
244 
245  Foam::dictionary fmfle("FoamFile");
246  fmfle.add("version", "2.0");
247  fmfle.add("format", "ascii");
248  fmfle.add("class", "dictionary");
249  fmfle.add("location", "\"system\"");
250  fmfle.add("object", "meshDict");
251  meshDict_->add("FoamFile", fmfle);
252 
253  if ((params_->maxCellSize) > 0)
254  meshDict_->add("maxCellSize", params_->maxCellSize);
255 
256  if ((params_->minCellSize) > 0)
257  meshDict_->add("minCellSize", params_->minCellSize);
258 
259  if ((params_->bndryCellSize) > 0)
260  meshDict_->add("boundaryCellSize", params_->bndryCellSize);
261 
262  if ((params_->bndryCellSizeRefThk) > 0)
263  meshDict_->add("boundaryCellSizeRefinementThickness",
265 
266  if (params_->keepCellIB) meshDict_->add("keepCellsIntersectingBoundary", "1");
267 
268  if (params_->chkGluMsh) meshDict_->add("checkForGluedMesh", "1");
269 
270  if ((params_->alwDiscDomains)) meshDict_->add("allowDisconnectedDomains", 1);
271 
272  meshDict_->add("surfaceFile", params_->geomFilePath);
273 
274  // boundary layer
275  if (params_->boundaryLayers.has_value()) {
276  const auto &boundaryLayer = params_->boundaryLayers.value();
277  Foam::dictionary boundaryLayrs("boundaryLayers");
278  boundaryLayrs.add("nLayers", boundaryLayer.blNLyr);
279  boundaryLayrs.add("thicknessRatio", boundaryLayer.blThkRto);
280  if (boundaryLayer.maxFrstLyrThk > 0.0)
281  boundaryLayrs.add("maxFirstLayerThickness", boundaryLayer.maxFrstLyrThk);
282 
283  if (boundaryLayer.alwDiscont) boundaryLayrs.add("allowDiscontinuity", 1);
284 
285  // boundary layer patches
286  if (!boundaryLayer.blPatches.empty()) {
287  Foam::dictionary patchBoundaryLayers("patchBoundaryLayers");
288  for (auto pt = (boundaryLayer.blPatches).begin();
289  pt != (boundaryLayer.blPatches).end(); pt++) {
290  Foam::dictionary tmpDict1(pt->patchName);
291  if (pt->alwDiscont) tmpDict1.add("allowDiscontinuity", 1);
292  if ((pt->maxFrstLyrThk) > 0)
293  tmpDict1.add("maxFirstLayerThickness", pt->maxFrstLyrThk);
294  if ((pt->blNLyr) > 0) tmpDict1.add("nLayers", pt->blNLyr);
295  if ((pt->blThkRto) > 0) tmpDict1.add("thicknessRatio", pt->blThkRto);
296  patchBoundaryLayers.add(Foam::word("\"" + pt->patchName + "\""),
297  tmpDict1);
298  }
299  boundaryLayrs.add("patchBoundaryLayers", patchBoundaryLayers);
300  }
301  meshDict_->add("boundaryLayers", boundaryLayrs);
302  }
303 
304  // object refinements
305  Foam::dictionary objectRefinements("objectRefinements");
306  if (!params_->objRefLst.empty()) {
307  for (auto ref = (params_->objRefLst).begin();
308  ref != (params_->objRefLst).end(); ref++) {
309  Foam::dictionary tmpDict1(ref->name);
310  for (auto prm = (ref->params).begin(); prm != (ref->params).end();
311  prm++) {
312  tmpDict1.add(Foam::word(prm->first), Foam::word(prm->second));
313  }
314  objectRefinements.add(Foam::word(ref->name), tmpDict1);
315  }
316  meshDict_->add("objectRefinements", objectRefinements);
317  }
318 
319  // local refinement
320  Foam::dictionary localRefinement("localRefinement");
321  if (!params_->refPatches.empty()) {
322  for (auto pt = (params_->refPatches).begin();
323  pt != (params_->refPatches).end(); pt++) {
324  Foam::dictionary tmpDict1(pt->patchName);
325  if ((pt->aditRefLvls) > 0)
326  tmpDict1.add("additionalRefinementLevels", pt->aditRefLvls);
327  if ((pt->refThickness) > 0)
328  tmpDict1.add("refinementThickness", pt->refThickness);
329  if ((pt->cellSize) > 0) tmpDict1.add("cellSize", pt->cellSize);
330  localRefinement.add(Foam::word("\"" + pt->patchName + "\""), tmpDict1);
331  }
332  meshDict_->add("localRefinement", localRefinement);
333  }
334 
335  // rename boundaries
336  Foam::dictionary renameBoundary("renameBoundary");
337  if (params_->renBndry.has_value()) {
338  const auto &renBndry = params_->renBndry.value();
339  renameBoundary.add("defaultName", Foam::word((renBndry).defName));
340  renameBoundary.add("defaultType", Foam::word((renBndry).defType));
341 
342  Foam::dictionary tmpDict1("newPatchNames");
343 
344  for (auto pt = (renBndry).newPatches.begin();
345  pt != (renBndry).newPatches.end(); pt++) {
346  Foam::dictionary tmpDict2(pt->name);
347  tmpDict2.add("newName", Foam::word(pt->newName));
348  tmpDict2.add("type", Foam::word(pt->newType));
349  tmpDict1.add(Foam::word("\"" + pt->name + "\""), tmpDict2);
350  }
351  renameBoundary.add("newPatchNames", tmpDict1);
352  meshDict_->add("renameBoundary", renameBoundary);
353  }
354 
355  if (write) {
356  // Write meshDict
357  Foam::fileName cfmeshDict_ = "system/meshDict";
358  Foam::OFstream outcfmeshDict_(cfmeshDict_);
359  Foam::IOobject::writeBanner(outcfmeshDict_);
360  meshDict_->write(outcfmeshDict_, false);
361  }
362 }
std::unique_ptr< Foam::dictionary > meshDict_
Definition: cfmeshGen.H:80
double bndryCellSize
Definition: cfmeshParams.H:108
std::unique_ptr< NEM::MSH::geoMeshBase > gmData
Definition: meshGen.H:54
jsoncons::optional< cfmBoundaryLayer > boundaryLayers
Definition: cfmeshParams.H:114
std::unique_ptr< Foam::dictionary > fvSchemes_
Definition: cfmeshGen.H:76
int createMeshFromSTL(const char *fname) override
Definition: cfmeshGen.C:99
geoMeshBase * Read(const std::string &fileName)
Read a mesh from file.
std::unique_ptr< Foam::fvMesh > fmesh_
Definition: cfmeshGen.H:79
void initialize()
Definition: cfmeshGen.C:71
jsoncons::optional< cfmRenBndry > renBndry
Definition: cfmeshParams.H:135
bool alwDiscDomains
Definition: cfmeshParams.H:103
~cfmeshGen() override
Definition: cfmeshGen.C:69
std::unique_ptr< Foam::dictionary > fvSolution_
Definition: cfmeshGen.H:77
std::string caseName
Definition: cfmeshGen.H:70
std::string generator
Definition: cfmeshParams.H:105
cfmeshGen()
Definition: cfmeshGen.C:55
bool defaults
Definition: cfmeshGen.H:69
double maxCellSize
Definition: cfmeshParams.H:106
cfmeshParams * params_
Definition: cfmeshGen.H:71
double bndryCellSizeRefThk
Definition: cfmeshParams.H:109
jsoncons::optional< cfmMeshQual > improveMeshQuality
Definition: cfmeshParams.H:129
std::vector< cfmLclRefPatch > refPatches
Definition: cfmeshParams.H:132
std::string geomFilePath
Definition: cfmeshParams.H:104
int improveMeshQuality()
Definition: cfmeshGen.C:194
std::vector< cfmObjRef > objRefLst
Definition: cfmeshParams.H:120
jsoncons::optional< cfmSrfFeatEdge > srfEdge
Definition: cfmeshParams.H:117
void createMshDict(const bool &write)
Definition: cfmeshGen.C:241
int surfaceFeatureEdgeDetect()
Definition: cfmeshGen.C:156
A concrete implementation of geoMeshBase representing a mesh in a fvMesh.
Definition: foamGeoMesh.H:52
std::unique_ptr< Foam::dictionary > controlDict_
Definition: cfmeshGen.H:75
std::unique_ptr< Foam::Time > runTime_
Definition: cfmeshGen.H:78
abstract class to specify geometry and mesh data
Definition: geoMeshBase.H:102
double minCellSize
Definition: cfmeshParams.H:107