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.
MeshManipulationFoam.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 "AuxiliaryFunctions.H"
30 #include <vtkAppendFilter.h>
31 #include <vtkCell.h>
32 #include <vtkCell3D.h>
33 #include <vtkDataSetTriangleFilter.h>
34 #include <vtkGeometryFilter.h>
35 #include <vtkPolyDataNormals.h>
36 #include <vtkUnstructuredGrid.h>
37 
38 #include <boost/filesystem.hpp>
39 #include <iostream>
40 #include <set>
41 #include <string>
42 #include <unordered_map>
43 #include <vector>
44 
46 
47 // New
48 #include <vtkProperty.h>
49 #include <vtkRenderWindowInteractor.h>
50 #include <vtkRenderer.h>
51 #include <vtkSmartPointer.h>
52 
53 // openfoam headers
54 #include <fileName.H>
55 #include <fvMesh.H>
56 #include <foamVtkVtuAdaptor.H>
57 #include <getDicts.H>
58 #include <surfaceLambdaMuSmooth.H> // SurfLambdaMuSmooth
59 #include <splitMeshRegions.H> // splitMeshByRegions
60 #include <mergeMeshes.H> // mergeMeshes
61 #include <createPatch.H> // createPatch
62 #include <surfaceSplitByTopology.H> // surfaceSplitByTopology
63 #include <foamToSurface.H> // foamToSurface
64 
65 // third party
66 #include <ANN/ANN.h>
67 
68 // TODO
69 // 1. Two of these methods (mergeMesh and CreatePatch) are little bit pack
70 // mesh specific but can be modified to accept very broad user
71 // arguments and perform mesh manipulations.
72 
73 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
74 
76  // class destructor
77 }
78 
79 /*
80  SurfaceLambdaMuSmooth takes input surface file and user defined values of
81  lambda, mu, and surface smoothing iterations to perform laplacian smoothing
82  on surface of geometry. This utility accepts following extensions as input:
83  .ofs, .obj, .inp, .stl, .tri, .off, .stlb, .nas, .bdf, .gts, .vtk, and .ac.
84  It will write output file at userdefined path
85 */
87  const auto &surfLMSmoothParams = _mshMnipPrms->surfLMSmoothParams;
88  const Foam::fileName surfFileName = (surfLMSmoothParams.slmssurfaceFile);
89  const Foam::fileName outFileName = (surfLMSmoothParams.slmsoutputFile);
90  const Foam::scalar lambda = (surfLMSmoothParams.lambda_);
91  const Foam::scalar mu = (surfLMSmoothParams.mu);
92  const Foam::label iters = (surfLMSmoothParams.slmsIterations);
93  const bool addFtrFl = (surfLMSmoothParams.addFeatureFile);
94  auto slmsObj = surfaceLambdaMuSmooth();
95  slmsObj.execute(surfFileName, outFileName, lambda, mu, iters, addFtrFl);
96 }
97 
98 /*
99  SplitMeshRegions utility splits mesh into multiple regions. It takes cell-face
100  -cell walk through the mesh, separates different cellZones into domains, and
101  writes them into constant directory. Currently it supports splitting of mesh
102  using cellZones. This function returns an integer to be used in mergeMeshes
103  utility. SplitMeshRegions utility assigns random numbering to split domains
104  from 0 to number of domains and skips a number automatically. This number is
105  returned and used in mergeMeshes function so that it knows which directory is
106  missing from constant folder.
107 */
108 std::pair<std::vector<int>, std::vector<std::string>>
110  const auto &spltMshRegions = _mshMnipPrms->splitMeshRegParams;
111  const bool useCellZones = (spltMshRegions.cellZones);
112  auto smrObj = splitMeshRegions();
113  return smrObj.execute(useCellZones);
114 }
115 
116 /*
117 MergeMeshes utility takes master region and slave region names/paths from user
118 and merges the slave regions to master region one by one.
119 */
120 void MeshManipulationFoam::mergeMesh(int dirStat, int nDomains) {
121  auto mmObj = mergeMeshes();
122  const auto &mergeMeshesParams = _mshMnipPrms->mergeMeshesParams;
123 
124  std::vector<std::string> addCases;
125 
126  // Collecting all domain names for automatic merging of all mesh regions.
127  // Directory number obtained from splitMeshRegions is used here. Also
128  // number of packs are passed through this function for use in loop.
129 
130  if (nDomains == 2) {
131  addCases.push_back(mergeMeshesParams.addCase);
132  } else {
133  for (int i = 2; i < (nDomains + 1); i++) {
134  if (i == dirStat) i++;
135  addCases.push_back("domain" + (std::to_string(i)));
136  }
137  addCases.push_back(mergeMeshesParams.addCase);
138  }
139  mmObj.execute(mergeMeshesParams.masterCasePath, mergeMeshesParams.addCasePath,
140  addCases, nDomains, dirStat);
141 }
142 
143 /*
144 CreatePatch utility merges multiple patches of certain mesh in a single patch.
145 It reads createPatchDict from system/mesh_reg_name/createPatchDict. Currently
146 the utility implementation is wrapped with for loop to execute it twice for
147 Pack Mesh Generation service.
148 */
150  const auto &createPatchParams = _mshMnipPrms->createPatchParams;
151  auto cpObj = createPatch();
152  createPatchDict(dirStat, true);
153  cpObj.execute(dirStat, createPatchParams.pathSurrounding, cpDict_);
154 }
155 
156 /*
157 This utility converts OpenFoam mesh into STL file. Filename is user-input.
158 It can take paths for output file location and name.
159 */
161  const auto &foamToSurfaceParams = _mshMnipPrms->foamToSurfParams;
162  auto ftsObj = foamToSurface();
163  ftsObj.execute(foamToSurfaceParams.outSurfName);
164 }
165 
166 /*
167 surfaceSplitByTopology is a surface file manipulation utility which aims at
168 splitting multiple disconnected regions in geometry into separate surfaces and
169 outputs a single surface file containing all regions as well as separate STL
170 files for all regions. User inputs are input file name and output file name.
171 */
173  const auto &surfSplitParams = _mshMnipPrms->surfSplitParams;
174  Foam::fileName surfFileName(surfSplitParams.surfFile);
175  Foam::Info << "Reading surface from " << surfFileName << Foam::endl;
176  Foam::fileName outFileName(surfSplitParams.outSurfFile);
177  auto ssbtObj = surfaceSplitByTopology();
178  return ssbtObj.execute(surfFileName, outFileName);
179 }
180 
181 /*
182 CreatePatchDict function creates dictionary file for createPatch utility and
183 puts them in defined path (i.e system/domainX). Currently this function has
184 customizations for Pack Mesh Generation service. More general methods could be
185 added in future.
186 */
188  const bool &write) {
189  const auto &createPatchParams = _mshMnipPrms->createPatchParams;
190 
191  // creating a base system directory
192  std::string dir_path = "./system/" + createPatchParams.pathSurrounding;
193 
194  if (write) {
195  boost::filesystem::path dir(dir_path);
196  try {
197  boost::filesystem::create_directory(dir);
198  } catch (boost::filesystem::filesystem_error &e) {
199  std::cerr << "Problem in creating system directory for the snappyHexMesh"
200  << "\n";
201  std::cerr << e.what() << std::endl;
202  throw;
203  }
204  }
205 
206  // header
207  std::string contText =
208  "\
209 /*--------------------------------*- C++ -*----------------------------------*\n\
210 | ========= | |\n\
211 | \\\\ / F ield | NEMoSys: snappyHexMesh interface |\n\
212 | \\\\ / O peration | |\n\
213 | \\\\ / A nd | |\n\
214 | \\\\/ M anipulation | |\n\
215 \\*---------------------------------------------------------------------------*/\n\
216 \n\
217 FoamFile\n\
218 {\n\
219  version 2.0;\n\
220  format ascii;\n\
221  class dictionary;\n\
222  location \"system\";\n\
223  object createPatchDict;\n\
224 }\n\n";
225 
226  contText =
227  contText +
228  "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //\n\n";
229 
230  contText = contText + "\n\npointSync true;\n";
231  contText = contText + "\n\npatches\n";
232  contText = contText + "(\n";
233  contText = contText + "\t{\n";
234  contText =
235  contText + "\t\tname " + (createPatchParams.surroundingName) + ";\n";
236  contText = contText + "\n\t\tpatchInfo\n";
237  contText = contText + "\t\t{\n";
238  contText =
239  contText + "\t\t\ttype " + (createPatchParams.srrndngPatchType) + ";\n";
240  contText = contText + "\t\t}\n";
241  contText = contText + "\n\t\tconstructFrom patches;\n";
242  contText = contText + "\n\t\tpatches (\"domain0_to_domain.*\");";
243  contText = contText + "\n\t}\n";
244  contText = contText + ");\n";
245 
246  contText = contText +
247  "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * "
248  "*//\n\n";
249 
250  // creating mesh dictionary file
251  std::ofstream contDict;
252  if (write) {
253  contDict.open(std::string(dir_path) + "/createPatchDict");
254  contDict << contText;
255  contDict.close();
256  }
257 
258  // Keep this dictionary in memory
259  Foam::dictionary tmptmpDuc =
260  new Foam::dictionary(Foam::IStringStream(contText)(), true);
261  cpDict_ = std::unique_ptr<Foam::dictionary>(
262  new Foam::dictionary("createPatchDict"));
263  cpDict_->merge(tmptmpDuc);
264 
265  if (dirStat == 1) {
266  const char dir_path2[] = "./system/domain2";
267 
268  if (write) {
269  boost::filesystem::path dir2(dir_path2);
270  try {
271  boost::filesystem::create_directory(dir2);
272  } catch (boost::filesystem::filesystem_error &e) {
273  std::cerr << "Problem in creating system directory for createPatch"
274  << "\n";
275  std::cerr << e.what() << std::endl;
276  throw;
277  }
278  }
279 
280  // header
281  std::string contText2 =
282  "\
283 /*--------------------------------*- C++ -*----------------------------------*\n\
284 | ========= | |\n\
285 | \\\\ / F ield | NEMoSys: snappyHexMesh interface |\n\
286 | \\\\ / O peration | |\n\
287 | \\\\ / A nd | |\n\
288 | \\\\/ M anipulation | |\n\
289 \\*---------------------------------------------------------------------------*/\n\
290 \n\
291 FoamFile\n\
292 {\n\
293  version 2.0;\n\
294  format ascii;\n\
295  class dictionary;\n\
296  location \"system\";\n\
297  object createPatchDict;\n\
298 }\n\n";
299 
300  contText2 = contText2 +
301  "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * "
302  "* * //\n\n";
303 
304  contText2 = contText2 + "\n\npointSync true;\n";
305  contText2 = contText2 + "\n\npatches\n";
306  contText2 = contText2 + "(\n";
307  contText2 = contText2 + "\t{\n";
308  contText2 = contText2 + "\t\tname " + (createPatchParams.packsName) + ";\n";
309  contText2 = contText2 + "\n\t\tpatchInfo\n";
310  contText2 = contText2 + "\t\t{\n";
311  contText2 =
312  contText2 + "\t\t\ttype " + (createPatchParams.packsPatchType) + ";\n";
313  contText2 = contText2 + "\t\t}\n";
314  contText2 = contText2 + "\n\t\tconstructFrom patches;\n";
315  contText2 = contText2 + "\n\t\tpatches (\"domain.*_to_domain0\");";
316  contText2 = contText2 + "\n\t}\n";
317  contText2 = contText2 + ");\n";
318 
319  contText2 = contText2 +
320  "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * "
321  "* * //\n\n";
322 
323  // creating mesh dictionary file
324  std::ofstream contDict2;
325  if (write) {
326  contDict2.open(std::string(dir_path2) + "/createPatchDict");
327  contDict2 << contText2;
328  contDict2.close();
329  }
330 
331  // Keep this dictionary in memory
332  cpDict_.reset();
333  Foam::dictionary tmptmpDuc2 =
334  new Foam::dictionary(Foam::IStringStream(contText2)(), true);
335  cpDict_ = std::unique_ptr<Foam::dictionary>(
336  new Foam::dictionary("createPatchDict"));
337  cpDict_->merge(tmptmpDuc2);
338  } else {
339  const char dir_path2[] = "./system/domain1";
340  if (write) {
341  boost::filesystem::path dir2(dir_path2);
342  try {
343  boost::filesystem::create_directory(dir2);
344  } catch (boost::filesystem::filesystem_error &e) {
345  std::cerr << "Problem in creating system directory for createPatch"
346  << "\n";
347  std::cerr << e.what() << std::endl;
348  throw;
349  }
350  }
351 
352  // header
353  std::string contText2 =
354  "\
355 /*--------------------------------*- C++ -*----------------------------------*\n\
356 | ========= | |\n\
357 | \\\\ / F ield | NEMoSys: snappyHexMesh interface |\n\
358 | \\\\ / O peration | |\n\
359 | \\\\ / A nd | |\n\
360 | \\\\/ M anipulation | |\n\
361 \\*---------------------------------------------------------------------------*/\n\
362 \n\
363 FoamFile\n\
364 {\n\
365  version 2.0;\n\
366  format ascii;\n\
367  class dictionary;\n\
368  location \"system\";\n\
369  object createPatchDict;\n\
370 }\n\n";
371 
372  contText2 = contText2 +
373  "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * "
374  "* * //\n\n";
375 
376  contText2 = contText2 + "\n\npointSync true;\n";
377  contText2 = contText2 + "\n\npatches\n";
378  contText2 = contText2 + "(\n";
379  contText2 = contText2 + "\t{\n";
380  contText2 = contText2 + "\t\tname " + (createPatchParams.packsName) + ";\n";
381  contText2 = contText2 + "\n\t\tpatchInfo\n";
382  contText2 = contText2 + "\t\t{\n";
383  contText2 =
384  contText2 + "\t\t\ttype " + (createPatchParams.packsPatchType) + ";\n";
385  contText2 = contText2 + "\t\t}\n";
386  contText2 = contText2 + "\n\t\tconstructFrom patches;\n";
387  contText2 = contText2 + "\n\t\tpatches (\"domain.*_to_domain0\");";
388  contText2 = contText2 + "\n\t}\n";
389  contText2 = contText2 + ");\n";
390 
391  contText2 = contText2 +
392  "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * "
393  "* * //\n\n";
394 
395  // creating mesh dictionary file
396  std::ofstream contDict2;
397  if (write) {
398  contDict2.open(std::string(dir_path2) + "/createPatchDict");
399  contDict2 << contText2;
400  contDict2.close();
401  }
402 
403  // Keep this dictionary in memory
404  Foam::dictionary tmptmpDuc2 =
405  new Foam::dictionary(Foam::IStringStream(contText2)(), true);
406  cpDict_.reset();
407  cpDict_ = std::unique_ptr<Foam::dictionary>(
408  new Foam::dictionary("createPatchDict"));
409  cpDict_->merge(tmptmpDuc2);
410  }
411 }
412 
413 // Adds connectivity information at shared interfaces.
415  const std::string &outName) {
416  bool writeDicts = true;
417  std::unique_ptr<getDicts> initFoam;
418  initFoam = std::unique_ptr<getDicts>(new getDicts());
419  auto controlDict_ = initFoam->createControlDict(writeDicts);
420 
421  Foam::Time runTime(controlDict_.get(), ".", ".");
422 
423  auto _fmeshSurr = std::unique_ptr<NEM::MSH::foamGeoMesh>(
424  NEM::MSH::foamGeoMesh::Read("domain0.foam"));
425 
426  auto _fmeshPacks = std::unique_ptr<NEM::MSH::foamGeoMesh>(
427  NEM::MSH::foamGeoMesh::Read("domain1.foam"));
428 
429  // declare vtk datasets
430  vtkSmartPointer<vtkUnstructuredGrid> dataSetSurr =
432 
433  vtkSmartPointer<vtkUnstructuredGrid> surrTmp =
435  auto objVfoamSurr = Foam::vtk::vtuAdaptor();
436  surrTmp = objVfoamSurr.internal(_fmeshSurr->getFoamMesh());
437 
438  int impPts = (int)(surrTmp->GetNumberOfPoints());
439 
440  vtkSmartPointer<vtkUnstructuredGrid> pckTmp =
442  auto objVfoamPck = Foam::vtk::vtuAdaptor();
443  pckTmp = objVfoamPck.internal(_fmeshPacks->getFoamMesh());
444 
445  // Merge two foam meshes
446  vtkSmartPointer<vtkAppendFilter> appendFilter =
448  appendFilter->AddInputData(surrTmp);
449  appendFilter->AddInputData(pckTmp);
450  appendFilter->MergePointsOn();
451  appendFilter->Update();
452  dataSetSurr = appendFilter->GetOutput();
453 
454  int numPoints = (int)(dataSetSurr->GetNumberOfPoints());
455 
456  int nDim = 3;
457  ANNpointArray pntCrd;
458  pntCrd = annAllocPts(numPoints, nDim);
459  for (int iPnt = 0; iPnt < numPoints; iPnt++) {
460  std::vector<double> getPt = std::vector<double>(3);
461  dataSetSurr->GetPoint(iPnt, &getPt[0]);
462  pntCrd[iPnt][0] = getPt[0];
463  pntCrd[iPnt][1] = getPt[1];
464  pntCrd[iPnt][2] = getPt[2];
465  }
466 
467  ANNkd_tree *kdTree = new ANNkd_tree(pntCrd, numPoints, nDim);
468 
469  // Finding duplicate nodes
470  double rad = 1e-05;
471  std::map<int, int> dupNdeMap;
472  ANNpoint qryPnt; // Query point.
473  int nNib = 2; // Number of neighbours to return (including query pt. itself).
474  ANNidxArray nnIdx = new ANNidx[nNib]; // Nearest neighbour ID array.
475  ANNdistArray dists = new ANNdist[nNib]; // Neighbour distance array.
476  qryPnt = annAllocPt(nDim); // Initializing query point
477 
478  for (int iNde = 0; iNde < impPts; iNde++) {
479  std::vector<double> getPt = std::vector<double>(3);
480  dataSetSurr->GetPoint(iNde, &getPt[0]);
481  qryPnt[0] = getPt[0];
482  qryPnt[1] = getPt[1];
483  qryPnt[2] = getPt[2];
484  kdTree->annkFRSearch(qryPnt, rad, nNib, nnIdx, dists, 0);
485  if (dists[1] <= tol) {
486  if ((nnIdx[1]) >= impPts)
487  dupNdeMap[nnIdx[0]] = nnIdx[1]; // Format Surrounding::Pack
488  else
489  dupNdeMap[nnIdx[1]] = nnIdx[0]; // Format Surrounding::Pack
490  }
491  }
492 
493  int numDupPnts = (int)dupNdeMap.size();
494  std::cout << "Found " << numDupPnts << " duplicate nodes.\n";
495 
496  // Getting cells in packs
497  std::map<int, int>::iterator it = dupNdeMap.begin();
498  std::vector<int> cellID;
499  for (int i = 0; i < (int)(dupNdeMap.size()); i++) {
500  int nCells, cellNum;
501  vtkIdList *cells = vtkIdList::New();
502 
503  // get cells the point belongs to
504  dataSetSurr->GetPointCells(it->second, cells);
505  nCells = (int)cells->GetNumberOfIds();
506 
507  for (cellNum = 0; cellNum < nCells; cellNum++) {
508  cellID.push_back((int)(cells->GetId(cellNum))); // get cell id from list
509  }
510  it++;
511  }
512 
513  sort(cellID.begin(), cellID.end());
514  cellID.erase(unique(cellID.begin(), cellID.end()), cellID.end());
515 
516  int know = (int)cellID.size();
517 
518  // std::cout << "Total Cells Found Are " << know << std::endl;
519 
520  // Determines which cells are useful
521  std::vector<int> newCellIds;
522  std::vector<int> debugCellIds;
523 
524  for (int i = 0; i < know; i++) {
525  // Getting all cell defining points
526  std::vector<int> ptIdzz(8);
527  int cntr = 0;
528  vtkCell *cell;
529  cell = dataSetSurr->GetCell(cellID[i]);
530 
531  vtkIdList *pts = cell->GetPointIds();
532 
533  for (int j = 0; j < 8; j++) { ptIdzz[j] = (int)(pts->GetId(j)); }
534 
535  // Checking if any cell contains any 4 or more of duplicate nodes.
536  std::map<int, int>::iterator it2 = dupNdeMap.begin();
537  while (it2 != dupNdeMap.end()) {
538  for (int k = 0; k < 8; k++) {
539  if ((it2->second) == ptIdzz[k]) {
540  cntr++;
541  } else {
542  // Nothing
543  }
544  }
545  it2++;
546  }
547 
548  if (cntr >= 4) {
549  newCellIds.push_back(cellID[i]);
550  } else {
551  debugCellIds.push_back(cellID[i]);
552  }
553  }
554 
555  int size2 = (int)newCellIds.size();
556 
557  // Getting useful faces from cells
558  std::vector<int> globalPtIds;
559  std::vector<int> surroundingArray;
560  std::vector<int> packArray;
561  for (int i = 0; i < size2; i++) {
562  vtkCell *cell;
563  cell = dataSetSurr->GetCell(newCellIds[i]);
564  vtkIdList *pts = cell->GetPointIds();
565 
566  for (int j = 0; j < 6; j++) {
567  int isFour = 0;
568  int *ptFaces = nullptr;
569  vtkCell3D *cell3d = static_cast<vtkCell3D *>(cell);
570  cell3d->GetFacePoints(j, ptFaces);
571  std::vector<int> keysDupMap = std::vector<int>(4);
572  std::map<int, int>::iterator it3 = dupNdeMap.begin();
573  while (it3 != dupNdeMap.end()) {
574  for (int h = 0; h < 4; h++) {
575  if ((it3->second) == (pts->GetId(ptFaces[h]))) {
576  isFour++;
577  keysDupMap[h] = it3->first;
578  } else {
579  // Nothing
580  }
581  }
582 
583  it3++;
584  }
585 
586  if (isFour == 4) {
587  for (int k = 0; k < 4; k++) { globalPtIds.push_back(keysDupMap[k]); }
588  }
589  }
590  }
591 
592  std::map<int, int>::iterator it5;
593 
594  // Creating node map with sequence.
595  std::unordered_multimap<int, int> cohesiveMap;
596 
597  for (int i = 0; i < (int)globalPtIds.size(); i++) {
598  it5 = dupNdeMap.find(globalPtIds[i]);
599 
600  if (it5 == dupNdeMap.end()) {
601  // Nothing
602  } else {
603  surroundingArray.push_back(it5->first);
604  packArray.push_back(it5->second);
605  }
606  }
607 
608  // std::cout << "Size = " << packArray.size() << std::endl;
609  int newCells = (int)(packArray.size() / 4);
610  int startNum = (int)(dataSetSurr->GetNumberOfCells());
611 
612  // Finally, creating VTK cells
613  int it7 = 0;
614  std::vector<int> pntCohesiveIds;
615  int nCelCohesivePnts;
616  for (int icl = 0; icl < newCells; icl++) {
617  nCelCohesivePnts = 4;
618  pntCohesiveIds.resize((nCelCohesivePnts * 2), -1);
619  for (int ip = 0; ip < nCelCohesivePnts; ip++) {
620  pntCohesiveIds[ip] = packArray[it7];
621  pntCohesiveIds[ip + 4] = surroundingArray[it7];
622  it7++;
623  }
624  vtkSmartPointer<vtkIdList> vtkCellIds = vtkSmartPointer<vtkIdList>::New();
625  vtkCellIds->SetNumberOfIds(pntCohesiveIds.size());
626  for (auto pit = pntCohesiveIds.begin(); pit != pntCohesiveIds.end(); pit++)
627  vtkCellIds->SetId(pit - pntCohesiveIds.begin(), *pit);
628  dataSetSurr->InsertNextCell(12, vtkCellIds);
629  }
630 
631  int endNum = (int)(dataSetSurr->GetNumberOfCells());
632 
633  // ****************************** //
634  // Zero volume cells visualization method for debugging purpose.
635  std::vector<int> cohCellIds;
636  for (int i = startNum; i < endNum; i++) { cohCellIds.push_back(i); }
637 
638  int size3 = (int)cohCellIds.size();
639  // Takes cell Ids as input and writes VTK mesh
640  vtkSmartPointer<vtkUnstructuredGrid> visDataSet =
642 
643  std::vector<int> ptIdzz2;
644  for (int i = 0; i < size3; i++) {
645  vtkCell *cell;
646 
647  cell = dataSetSurr->GetCell(cohCellIds[i]);
648 
649  vtkIdList *pts = cell->GetPointIds();
650 
651  for (int j = 0; j < 8; j++) { ptIdzz2.push_back((int)(pts->GetId(j))); }
652  }
653 
654  int lvar = 0;
655 
656  vtkSmartPointer<vtkPoints> pointsViz = vtkSmartPointer<vtkPoints>::New();
657 
658  for (int i = 0; i < (size3 * 8); i++) {
659  std::vector<double> getPt = std::vector<double>(3);
660  dataSetSurr->GetPoint(ptIdzz2[i], &getPt[0]);
661  pointsViz->InsertNextPoint(getPt[0], getPt[1], getPt[2]);
662  }
663 
664  visDataSet->SetPoints(pointsViz);
665 
666  for (int i = 0; i < size3; i++) {
667  std::vector<int> ptnewIdz;
668  for (int j = 0; j < 8; j++) {
669  ptnewIdz.push_back(lvar);
670  lvar++;
671  }
672  vtkSmartPointer<vtkIdList> vtkCellIds = vtkSmartPointer<vtkIdList>::New();
673  vtkCellIds->SetNumberOfIds(ptnewIdz.size());
674  for (auto pit = ptnewIdz.begin(); pit != ptnewIdz.end(); pit++)
675  vtkCellIds->SetId(pit - ptnewIdz.begin(), *pit);
676  visDataSet->InsertNextCell(12, vtkCellIds);
677  }
678 
679  auto vm = std::unique_ptr<NEM::MSH::vtkGeoMesh>(
680  new NEM::MSH::vtkGeoMesh(visDataSet));
681  vm->write("CohesiveElements.vtu");
682 
683  // ********************************************* //
684  auto vm2 = std::unique_ptr<NEM::MSH::vtkGeoMesh>(
685  new NEM::MSH::vtkGeoMesh(dataSetSurr));
686  vm2->write(outName);
687 
688  // Convert final mesh to tetrahedral
689  bool tetra = false;
690  std::string ofnameTet = "Tetra" + outName;
691 
692  if (tetra) {
693  vtkSmartPointer<vtkDataSetTriangleFilter> triFilter =
695  triFilter->SetInputData(dataSetSurr);
696  triFilter->Update();
697 
698  auto newData_tet = triFilter->GetOutput();
699 
700  auto vm3 = std::unique_ptr<NEM::MSH::vtkGeoMesh>(
701  new NEM::MSH::vtkGeoMesh(newData_tet));
702  vm3->write(ofnameTet);
703  }
704  // **************************************************************************
705 }
706 
708  double &tol, const std::string &outName, double &thickness) {
709  // Initializing FOAM
710  bool writeDicts = true;
711  std::unique_ptr<getDicts> initFoam;
712  initFoam = std::unique_ptr<getDicts>(new getDicts());
713  auto controlDict_ = initFoam->createControlDict(writeDicts);
714 
715  Foam::Time runTime(controlDict_.get(), ".", ".");
716 
717  auto _fmeshSurr = std::unique_ptr<NEM::MSH::foamGeoMesh>(
718  NEM::MSH::foamGeoMesh::Read("domain0.foam"));
719 
720  auto _fmeshPacks = std::unique_ptr<NEM::MSH::foamGeoMesh>(
721  NEM::MSH::foamGeoMesh::Read("domain1.foam"));
722 
723  // declare vtk datasets
724  vtkSmartPointer<vtkUnstructuredGrid> dataSetSurr =
726 
727  vtkSmartPointer<vtkUnstructuredGrid> surrTmp =
729  auto objVfoamSurr = Foam::vtk::vtuAdaptor();
730  surrTmp = objVfoamSurr.internal(_fmeshSurr->getFoamMesh());
731 
732  int impPts = (surrTmp->GetNumberOfPoints());
733 
734  vtkSmartPointer<vtkUnstructuredGrid> pckTmp =
736  auto objVfoamPck = Foam::vtk::vtuAdaptor();
737  pckTmp = objVfoamPck.internal(_fmeshPacks->getFoamMesh());
738 
739  // Merge two foam meshes
740  vtkSmartPointer<vtkAppendFilter> appendFilter =
742  appendFilter->AddInputData(surrTmp);
743  appendFilter->AddInputData(surrTmp);
744  appendFilter->MergePointsOn();
745  appendFilter->Update();
746  dataSetSurr = appendFilter->GetOutput();
747 
748  int numPoints = (int)(dataSetSurr->GetNumberOfPoints());
749 
750  int nDim = 3;
751  ANNpointArray pntCrd;
752  pntCrd = annAllocPts(numPoints, nDim);
753  for (int iPnt = 0; iPnt < numPoints; iPnt++) {
754  std::vector<double> getPt = std::vector<double>(3);
755  dataSetSurr->GetPoint(iPnt, &getPt[0]);
756  pntCrd[iPnt][0] = getPt[0];
757  pntCrd[iPnt][1] = getPt[1];
758  pntCrd[iPnt][2] = getPt[2];
759  }
760 
761  ANNkd_tree *kdTree = new ANNkd_tree(pntCrd, numPoints, nDim);
762 
763  // Finding duplicate nodes
764  double rad = 1e-05;
765  std::map<int, int> dupNdeMap;
766  ANNpoint qryPnt; // Query point.
767  int nNib = 2; // Number of neighbours to return (including query pt. itself).
768  ANNidxArray nnIdx = new ANNidx[nNib]; // Nearest neighbour ID array.
769  ANNdistArray dists = new ANNdist[nNib]; // Neighbour distance array.
770  qryPnt = annAllocPt(nDim); // Initializing query point
771 
772  for (int iNde = 0; iNde < impPts; iNde++) {
773  std::vector<double> getPt = std::vector<double>(3);
774  dataSetSurr->GetPoint(iNde, &getPt[0]);
775  qryPnt[0] = getPt[0];
776  qryPnt[1] = getPt[1];
777  qryPnt[2] = getPt[2];
778  kdTree->annkFRSearch(qryPnt, rad, nNib, nnIdx, dists, 0);
779  if (dists[1] <= tol) {
780  if ((nnIdx[1]) >= impPts) {
781  dupNdeMap[nnIdx[0]] = nnIdx[1]; // Format Surrounding::Pack
782  } else {
783  dupNdeMap[nnIdx[1]] = nnIdx[0]; // Format Surrounding::Pack
784  }
785  }
786  }
787 
788  int numDupPnts = (int)dupNdeMap.size();
789  std::cout << "Found " << numDupPnts << " duplicate nodes.\n";
790 
791  // Getting cells in packs
792  std::map<int, int>::iterator it = dupNdeMap.begin();
793  std::vector<int> cellID;
794  for (int i = 0; i < (int)(dupNdeMap.size()); i++) {
795  int nCells, cellNum;
796  vtkIdList *cells = vtkIdList::New();
797 
798  // get cells the point belongs to
799  dataSetSurr->GetPointCells(it->second, cells);
800  nCells = (int)(cells->GetNumberOfIds());
801 
802  for (cellNum = 0; cellNum < nCells; cellNum++) {
803  cellID.push_back(
804  (int)(cells->GetId(cellNum))); // get cell id from the list
805  }
806  it++;
807  }
808 
809  sort(cellID.begin(), cellID.end());
810  cellID.erase(unique(cellID.begin(), cellID.end()), cellID.end());
811 
812  int know = cellID.size();
813 
814  // Determines which cells are useful
815  std::vector<int> newCellIds;
816  std::vector<int> debugCellIds;
817 
818  for (int i = 0; i < know; i++) {
819  // Getting all cell defining points
820  std::vector<int> ptIdzz(8);
821  int cntr = 0;
822  vtkCell *cell;
823  cell = dataSetSurr->GetCell(cellID[i]);
824 
825  vtkIdList *pts = cell->GetPointIds();
826 
827  for (int j = 0; j < 8; j++) { ptIdzz[j] = pts->GetId(j); }
828 
829  // Checking if any cell contains any 4 or more of duplicate nodes.
830  std::map<int, int>::iterator it2 = dupNdeMap.begin();
831  while (it2 != dupNdeMap.end()) {
832  for (int k = 0; k < 8; k++) {
833  if ((it2->second) == ptIdzz[k]) {
834  cntr++;
835  } else {
836  // Nothing
837  }
838  }
839  it2++;
840  }
841 
842  if (cntr >= 4) {
843  newCellIds.push_back(cellID[i]);
844  } else {
845  debugCellIds.push_back(cellID[i]);
846  }
847  }
848 
849  int size2 = (int)(newCellIds.size());
850 
851  // Getting useful faces from cells
852  std::vector<int> globalPtIds;
853  std::vector<int> surroundingArray;
854  std::vector<int> packArray;
855  for (int i = 0; i < size2; i++) {
856  vtkCell *cell;
857  cell = dataSetSurr->GetCell(newCellIds[i]);
858  vtkIdList *pts = cell->GetPointIds();
859 
860  for (int j = 0; j < 6; j++) {
861  int isFour = 0;
862  int *ptFaces = nullptr;
863  vtkCell3D *cell3d = static_cast<vtkCell3D *>(cell);
864  cell3d->GetFacePoints(j, ptFaces);
865  std::vector<int> keysDupMap = std::vector<int>(4);
866  std::map<int, int>::iterator it3 = dupNdeMap.begin();
867  while (it3 != dupNdeMap.end()) {
868  for (int h = 0; h < 4; h++) {
869  if ((it3->second) == (pts->GetId(ptFaces[h]))) {
870  isFour++;
871  keysDupMap[h] = it3->first;
872  } else {
873  // Nothing
874  }
875  }
876 
877  it3++;
878  }
879 
880  if (isFour == 4) {
881  for (int k = 0; k < 4; k++) { globalPtIds.push_back(keysDupMap[k]); }
882  }
883  }
884  }
885 
886  std::map<int, int>::iterator it5;
887 
888  // Creating node map with sequence.
889  std::unordered_multimap<int, int> cohesiveMap;
890 
891  for (int i = 0; i < (int)globalPtIds.size(); i++) {
892  it5 = dupNdeMap.find(globalPtIds[i]);
893 
894  if (it5 == dupNdeMap.end()) {
895  // Nothing
896  } else {
897  surroundingArray.push_back(it5->first);
898  packArray.push_back(it5->second);
899  }
900  }
901 
902  std::cout << "End of previous method" << std::endl;
903 
904  // Converting vtkUnstructuredData to vtkPolyData
905  vtkSmartPointer<vtkGeometryFilter> geometryFilter =
907  geometryFilter->SetInputData(dataSetSurr);
908  geometryFilter->Update();
909 
910  vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
911  polydata = geometryFilter->GetOutput();
912 
913  vtkSmartPointer<vtkPolyDataNormals> polyDataNormal =
915 
916  polyDataNormal->SetInputData(polydata);
917 
918  // Setting points normals calculation to ON with other options
919  polyDataNormal->ComputePointNormalsOn();
920  polyDataNormal->ComputeCellNormalsOff();
921  // polyDataNormal->SetNonManifoldTraversal(1);
922  // polyDataNormal->SetAutoOrientNormals(0);
923  polyDataNormal->SetSplitting(0);
924  // polyDataNormal->SetFeatureAngle(0.1);
925  polyDataNormal->SetConsistency(1);
926  // polyDataNormal->SetFlipNormals(0);
927  polyDataNormal->Update();
928 
929  // Extracting point normals from polyDataNormal
930  polydata = polyDataNormal->GetOutput();
931 
932  // Count points
933  vtkIdType numPointsNew = polydata->GetNumberOfPoints();
934  std::cout << "There are " << numPointsNew << " points." << std::endl;
935 
936  vtkDataArray *normalsGeneric = polydata->GetPointData()->GetNormals();
937 
938  // Number of normals should match number of points
939  std::cout << "There are " << normalsGeneric->GetNumberOfTuples()
940  << " normals in normalsGeneric" << std::endl;
941 
942  // Changing point coordinates for adding artificial thickness;
943 
944  // Surrounding cells
945  for (int i = 0; i < (int)surroundingArray.size(); i++) {
946  double normalOfPt[3];
947  normalsGeneric->GetTuple(surroundingArray[i], normalOfPt);
948 
949  std::vector<double> getPt = std::vector<double>(3);
950  dataSetSurr->GetPoint(surroundingArray[i], &getPt[0]);
951 
952  // TODO : Need to figure out thickness formula considering pack and
953  // surrounding mesh cell size and unit normal scale.
954  double newCoords[3];
955  newCoords[0] = getPt[0] + 0.001 * normalOfPt[0];
956  newCoords[1] = getPt[1] + 0.001 * normalOfPt[1];
957  newCoords[2] = getPt[2] + 0.001 * normalOfPt[2];
958 
959  dataSetSurr->GetPoints()->SetPoint(surroundingArray[i], newCoords);
960  }
961 
962  // Pack cells
963  for (int i = 0; i < (int)packArray.size(); i++) {
964  double normalOfPt[3];
965  normalsGeneric->GetTuple(packArray[i], normalOfPt);
966 
967  std::vector<double> getPt = std::vector<double>(3);
968  dataSetSurr->GetPoint(packArray[i], &getPt[0]);
969 
970  double newCoords[3];
971  newCoords[0] = (getPt[0] + 0.001 * normalOfPt[0]);
972  newCoords[1] = (getPt[1] + 0.001 * normalOfPt[1]);
973  newCoords[2] = (getPt[2] + 0.001 * normalOfPt[2]);
974 
975  dataSetSurr->GetPoints()->SetPoint(packArray[i], newCoords);
976  }
977 
978  // Making cells now and plotting them
979  int newCells = (int)(packArray.size() / 4);
980  int startNum = (int)(dataSetSurr->GetNumberOfCells());
981 
982  // Finally, creating VTK cells
983  int it7 = 0;
984  std::vector<int> pntCohesiveIds;
985  int nCelCohesivePnts = 0;
986  for (int icl = 0; icl < newCells; icl++) {
987  nCelCohesivePnts = 4;
988  pntCohesiveIds.resize((nCelCohesivePnts * 2), -1);
989  for (int ip = 0; ip < nCelCohesivePnts; ip++) {
990  pntCohesiveIds[ip] = packArray[it7];
991  pntCohesiveIds[ip + 4] = surroundingArray[it7];
992  it7++;
993  }
994  vtkSmartPointer<vtkIdList> vtkCellIds = vtkSmartPointer<vtkIdList>::New();
995  vtkCellIds->SetNumberOfIds(pntCohesiveIds.size());
996  for (auto pit = pntCohesiveIds.begin(); pit != pntCohesiveIds.end(); pit++)
997  vtkCellIds->SetId(pit - pntCohesiveIds.begin(), *pit);
998  dataSetSurr->InsertNextCell(12, vtkCellIds);
999  }
1000 
1001  int endNum = dataSetSurr->GetNumberOfCells();
1002 
1003  // ****************************** //
1004  // Zero volume cells visualization method for debugging purpose.
1005  std::vector<int> cohCellIds;
1006  for (int i = startNum; i < endNum; i++) { cohCellIds.push_back(i); }
1007 
1008  int size3 = cohCellIds.size();
1009  // Takes cell Ids as input and writes VTK mesh
1010  vtkSmartPointer<vtkUnstructuredGrid> visDataSet =
1012 
1013  std::vector<int> ptIdzz2;
1014  for (int i = 0; i < size3; i++) {
1015  vtkCell *cell;
1016  cell = dataSetSurr->GetCell(cohCellIds[i]);
1017 
1018  vtkIdList *pts = cell->GetPointIds();
1019 
1020  for (int j = 0; j < 8; j++) { ptIdzz2.push_back(pts->GetId(j)); }
1021  }
1022 
1023  int lvar = 0;
1024 
1025  vtkSmartPointer<vtkPoints> pointsViz = vtkSmartPointer<vtkPoints>::New();
1026 
1027  for (int i = 0; i < (size3 * 8); i++) {
1028  std::vector<double> getPt = std::vector<double>(3);
1029  dataSetSurr->GetPoint(ptIdzz2[i], &getPt[0]);
1030  pointsViz->InsertNextPoint(getPt[0], getPt[1], getPt[2]);
1031  }
1032 
1033  visDataSet->SetPoints(pointsViz);
1034 
1035  for (int i = 0; i < size3; i++) {
1036  std::vector<int> ptnewIdz;
1037  for (int j = 0; j < 8; j++) {
1038  ptnewIdz.push_back(lvar);
1039  lvar++;
1040  }
1041  vtkSmartPointer<vtkIdList> vtkCellIds = vtkSmartPointer<vtkIdList>::New();
1042  vtkCellIds->SetNumberOfIds(ptnewIdz.size());
1043  for (auto pit = ptnewIdz.begin(); pit != ptnewIdz.end(); pit++)
1044  vtkCellIds->SetId(pit - ptnewIdz.begin(), *pit);
1045  visDataSet->InsertNextCell(12, vtkCellIds);
1046  }
1047 
1048  auto vm = std::unique_ptr<NEM::MSH::vtkGeoMesh>(
1049  new NEM::MSH::vtkGeoMesh(visDataSet));
1050  vm->write("ArtificialElements.vtu");
1051 
1052  // ********************************************* //
1053  auto vm2 = std::unique_ptr<NEM::MSH::vtkGeoMesh>(
1054  new NEM::MSH::vtkGeoMesh(dataSetSurr));
1055  vm2->write(outName);
1056 
1057  // Convert final mesh to tetrahedra
1058  bool tetra = false;
1059  std::string ofnameTet = "Tetra" + outName;
1060 
1061  if (tetra) {
1062  vtkSmartPointer<vtkDataSetTriangleFilter> triFilter =
1064  triFilter->SetInputData(dataSetSurr);
1065  triFilter->Update();
1066 
1067  auto newData_tet = triFilter->GetOutput();
1068 
1069  auto vm3 = std::unique_ptr<NEM::MSH::vtkGeoMesh>(
1070  new NEM::MSH::vtkGeoMesh(newData_tet));
1071  vm3->write(ofnameTet);
1072  }
1073 }
1074 
1075 // Generates Periodic Mesh
1077  std::string &patch2) {
1078  bool writeDicts = false;
1079  std::unique_ptr<getDicts> initFoam;
1080  initFoam = std::unique_ptr<getDicts>(new getDicts());
1081  auto controlDict_ = initFoam->createControlDict(writeDicts);
1082 
1083  Foam::fileName one = ".";
1084  Foam::fileName two = ".";
1085  Foam::Time runTime(controlDict_.get(), one, two);
1086 
1087  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
1088 
1089  // Foam::word regionName = Foam::polyMesh::defaultRegion;
1090 
1091  // auto _fmeshPacks = new Foam::polyMesh(Foam::IOobject(
1092  // regionName, runTime.timeName(), runTime, Foam::IOobject::MUST_READ));
1093 
1094  auto fm = std::unique_ptr<NEM::MSH::foamGeoMesh>(
1095  NEM::MSH::foamGeoMesh::Read(".foam"));
1096 
1097  const auto &_fmeshPacks = fm->getFoamMesh();
1098 
1099  // Creating patch objects for periodic boundary patches
1100  int patchIDIn = _fmeshPacks.boundaryMesh().findPatchID(patch1);
1101  int patchIDOut = _fmeshPacks.boundaryMesh().findPatchID(patch2);
1102 
1103  const Foam::polyPatch &InPolyPatch = _fmeshPacks.boundaryMesh()[patchIDIn];
1104  const Foam::polyPatch &OutPolyPatch = _fmeshPacks.boundaryMesh()[patchIDOut];
1105 
1106  // Point IDs from periodic patches.
1107  Foam::labelList inPts(InPolyPatch.meshPoints());
1108  Foam::labelList outPts(OutPolyPatch.meshPoints());
1109 
1110  if (inPts.size() != outPts.size()) {
1111  std::cerr << "Selected boundaries are not periodic!"
1112  << "\nExiting!" << std::endl;
1113  throw;
1114  }
1115 
1116  Foam::pointField packsPF = _fmeshPacks.points();
1117 
1118  // Creating map of IDs on both patches
1119  std::map<int, int> periodicMap;
1120 
1121  for (int i = 0; i < inPts.size(); i++) { periodicMap[inPts[i]] = outPts[i]; }
1122 
1123  ofstream myfile;
1124  myfile.open("PeriodicMap.csv");
1125  for (int i = 0; i < inPts.size(); i++) {
1126  myfile << inPts[i] << "," << outPts[i] << std::endl;
1127  }
1128  myfile.close();
1129 
1130  // Method test using VTK unstructured writer
1131  // Very useful for extracting face node orders. Might use this in
1132  // cohesive elements. Also, Foam::facePointPatch::pointNormals()
1133  // can be useful for artificial thickness elements
1134  vtkSmartPointer<vtkUnstructuredGrid> dataSetTest =
1136  vtkSmartPointer<vtkPoints> pointsMesh = vtkSmartPointer<vtkPoints>::New();
1137 
1138  for (int i = 0; i < packsPF.size(); i++) {
1139  pointsMesh->InsertNextPoint(packsPF[i].x(), packsPF[i].y(), packsPF[i].z());
1140  }
1141 
1142  dataSetTest->SetPoints(pointsMesh);
1143 
1144  forAll (_fmeshPacks.boundaryMesh()[patchIDIn], facei) {
1145  const Foam::label &faceID =
1146  _fmeshPacks.boundaryMesh()[patchIDIn].start() + facei;
1147  std::vector<int> pntIds;
1148  pntIds.resize(4, -1);
1149  int g = 0;
1150  forAll (_fmeshPacks.faces()[faceID], nodei) {
1151  const Foam::label &nodeID = _fmeshPacks.faces()[faceID][nodei];
1152  pntIds[g] = nodeID;
1153  g++;
1154  }
1155  vtkSmartPointer<vtkIdList> vtkCellIds = vtkSmartPointer<vtkIdList>::New();
1156  vtkCellIds->SetNumberOfIds(pntIds.size());
1157  for (auto pit = pntIds.begin(); pit != pntIds.end(); pit++)
1158  vtkCellIds->SetId(pit - pntIds.begin(), *pit);
1159  dataSetTest->InsertNextCell(9, vtkCellIds);
1160  }
1161 
1162  forAll (_fmeshPacks.boundaryMesh()[patchIDOut], facei) {
1163  const Foam::label &faceID =
1164  _fmeshPacks.boundaryMesh()[patchIDOut].start() + facei;
1165  std::vector<int> pntIds;
1166  pntIds.resize(4, -1);
1167  int g = 0;
1168  forAll (_fmeshPacks.faces()[faceID], nodei) {
1169  const Foam::label &nodeID = _fmeshPacks.faces()[faceID][nodei];
1170  pntIds[g] = nodeID;
1171  g++;
1172  }
1173  vtkSmartPointer<vtkIdList> vtkCellIds = vtkSmartPointer<vtkIdList>::New();
1174  vtkCellIds->SetNumberOfIds(pntIds.size());
1175  for (auto pit = pntIds.begin(); pit != pntIds.end(); pit++)
1176  vtkCellIds->SetId(pit - pntIds.begin(), *pit);
1177  dataSetTest->InsertNextCell(9, vtkCellIds);
1178  }
1179 
1180  auto vm = std::unique_ptr<NEM::MSH::vtkGeoMesh>(
1181  new NEM::MSH::vtkGeoMesh(dataSetTest));
1182  vm->write("PeriodicMesh.vtu");
1183 }
void createPtch(int dirStat)
createPtch utility creates user-defined patches in Foam mesh.
std::unique_ptr< Foam::dictionary > cpDict_
geoMeshBase * Read(const std::string &fileName)
Read a mesh from file.
std::pair< std::vector< int >, std::vector< std::string > > splitMshRegions()
splitMshRegions walks through mesh using cell-face-cell walk and identifies different cellZones as di...
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
MeshManipulationFoamParams * _mshMnipPrms
MeshManipulationFoam object.
SurfaceLambdaMuSmooth surfLMSmoothParams
A concrete implementation of geoMeshBase representing a mesh in a vtkUnstructuredGrid.
Definition: vtkGeoMesh.H:42
void surfLambdaMuSmooth()
surfLambdaMuSmooth performs laplacian smoothing over surface and writes it into output surface file...
std::string pathSurrounding
Defines surrounding mesh path from main directory.
void mergeMesh(int dirStat, int nDomains)
mergeMesh method merges two fvMesh datasets into one fvMesh including the patches and domain informat...
void foamToSurf()
foamToSurf utility reads Foam mesh, extracts its surface and writes into an STL file.
~MeshManipulationFoam()
Standard MeshManipulationFoam Destructor.
SurfaceSplitByManifold surfSplitParams
int surfSpltByTopology()
surfSpltByTopology utility takes a surface file as an input and automatically divides disconnected re...
const Foam::fvMesh & getFoamMesh() const
Copy the mesh.
Definition: foamGeoMesh.H:105
std::vector< vtkIdType > points
points given by id in .inp file
Definition: inpGeoMesh.C:133
void createPatchDict(const int &dirStat, const bool &write)
createPatchDict utility creates a dictionary needed for createPatch method.
void addArtificialThicknessElements(double &tol, const std::string &outName, double &thickness)
This method adds connectivity elements with finite thickness at shared interface between two conforma...
void addCohesiveElements(double tol, const std::string &outName)
addCohesiveElements method supports addition of zero-sized connectivity elements at conformal shared ...
void periodicMeshMapper(std::string &patch1, std::string &patch2)
periodicMeshMapper method generates map of nodes on periodic mesh interfaces at boundaries for FEM an...