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.
pntMesh.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 "Mesh/pntMesh.H"
30 
31 #include "AuxiliaryFunctions.H"
32 
33 #include <vtkCell.h>
34 
35 #include <sstream>
36 #include <type_traits>
37 
39 {
40  std::map<elementType, VTKCellType> eMap =
41  {
42  {elementType::BAR, VTK_LINE},
43  {elementType::QUADRILATERAL, VTK_QUAD},
44  {elementType::TRIANGLE, VTK_TRIANGLE},
45  {elementType::HEXAGON, VTK_HEXAHEDRON},
46  {elementType::SPHERICAL, VTK_EMPTY_CELL},
47  {elementType::CYLINDRICAL, VTK_EMPTY_CELL},
48  {elementType::BRICK, VTK_HEXAHEDRON},
49  {elementType::LAGRANGE_BRICK, VTK_HEXAHEDRON},
50  {elementType::TETRAHEDRON, VTK_TETRA},
51  {elementType::HEXPRISM, VTK_HEXAGONAL_PRISM},
52  {elementType::PRISMATIC, VTK_WEDGE},
53  {elementType::OTHER, VTK_EMPTY_CELL}
54  };
55  return eMap[et];
56 }
57 
59 {
60  std::map<VTKCellType, elementType> eMap =
61  {
62  {VTK_LINE, elementType::BAR},
63  {VTK_QUAD, elementType::QUADRILATERAL},
64  {VTK_QUADRATIC_QUAD, elementType::QUADRILATERAL},
65  {VTK_TRIANGLE, elementType::TRIANGLE},
66  {VTK_QUADRATIC_TRIANGLE, elementType::TRIANGLE},
67  {VTK_HEXAHEDRON, elementType::HEXAGON},
68  {VTK_QUADRATIC_HEXAHEDRON, elementType::HEXAGON},
69  {VTK_TETRA, elementType::TETRAHEDRON},
70  {VTK_QUADRATIC_TETRA, elementType::TETRAHEDRON},
71  {VTK_HEXAGONAL_PRISM, elementType::HEXPRISM},
72  {VTK_WEDGE, elementType::PRISMATIC},
73  {VTK_EMPTY_CELL, elementType::OTHER}
74  };
75  return eMap[vt];
76 }
77 
78 PNTMesh::surfaceBCTag PNTMesh::bcTagNum(const std::string &_tag)
79 {
80  std::string tag = _tag;
81  nemAux::toLower(tag);
82  if (tag == "reflective") return surfaceBCTag::REFLECTIVE;
83  if (tag == "void") return surfaceBCTag::VOID;
84  std::cerr << "Unknown surface tag " << tag << std::endl;
85  throw;
86 }
87 
89 {
90  switch (tag) {
91  case surfaceBCTag::REFLECTIVE: return "REFLECTIVE";
92  case surfaceBCTag::VOID: return "VOID";
93  }
94  throw;
95 }
96 
97 PNTMesh::elementType PNTMesh::elmTypeNum(const std::string &_tag)
98 {
99  std::string tag = _tag;
100  nemAux::toLower(tag);
101  if (tag == "bar") return elementType::BAR;
102  if (tag == "quadrilateral") return elementType::QUADRILATERAL;
103  if (tag == "triangle") return elementType::TRIANGLE;
104  if (tag == "hexagon") return elementType::HEXAGON;
105  if (tag == "spherical") return elementType::SPHERICAL;
106  if (tag == "cylindrical") return elementType::CYLINDRICAL;
107  if (tag == "brick") return elementType::BRICK;
108  if (tag == "lagrange_brick") return elementType::LAGRANGE_BRICK;
109  if (tag == "tetrahedron") return elementType::TETRAHEDRON;
110  if (tag == "hexprism") return elementType::HEXPRISM;
111  if (tag == "prismatic") return elementType::PRISMATIC;
112  std::cout << "Warning : Element type " << tag << " may be not supported"
113  << std::endl;
114  return elementType::OTHER;
115 }
116 
118 {
119  if (tag == elementType::BAR) return "BAR";
120  if (tag == elementType::QUADRILATERAL) return "QUADRILATERAL";
121  if (tag == elementType::TRIANGLE) return "TRIANGLE";
122  if (tag == elementType::HEXAGON) return "HEXAGON";
123  if (tag == elementType::SPHERICAL) return "SPHERICAL";
124  if (tag == elementType::CYLINDRICAL) return "CYLINDRICAL";
125  if (tag == elementType::BRICK) return "BRICK";
126  if (tag == elementType::LAGRANGE_BRICK) return "LAGRANGE_BRICK";
127  if (tag == elementType::TETRAHEDRON) return "TETRAHEDRON";
128  if (tag == elementType::HEXPRISM) return "HEXPRISM";
129  if (tag == elementType::PRISMATIC) return "PRISMATIC";
130  return "OTHER";
131 }
132 
133 int PNTMesh::elmNumNde(elementType tag, int order)
134 {
135  if (tag == elementType::BAR) return (2 + order - 1);
136  if (tag == elementType::QUADRILATERAL && order == 1) return 4;
137  if (tag == elementType::QUADRILATERAL && order == 2) return 8;
138  if (tag == elementType::TRIANGLE && order == 1) return 3;
139  if (tag == elementType::TRIANGLE && order == 2) return 6;
140  if (tag == elementType::HEXAGON && order == 1) return 8;
141  if (tag == elementType::HEXAGON && order == 2) return 27;
142  if (tag == elementType::BRICK && order == 1) return 8;
143  if (tag == elementType::BRICK && order == 2) return 27;
144  if (tag == elementType::LAGRANGE_BRICK && order == 1) return 8;
145  if (tag == elementType::LAGRANGE_BRICK && order == 2) return 27;
146  if (tag == elementType::TETRAHEDRON && order == 1) return 4;
147  if (tag == elementType::TETRAHEDRON && order == 2) return 10;
148  if (tag == elementType::HEXPRISM && order == 1) return 16;
149  if (tag == elementType::PRISMATIC && order == 1) return 6;
150  if (tag == elementType::PRISMATIC && order == 2) return 15;
151  std::cerr << "Unknown element/order combination\n";
152  throw;
153 }
154 
156 {
157  if (tag == elementType::BAR) return 2;
158  if (tag == elementType::QUADRILATERAL) return 4;
159  if (tag == elementType::TRIANGLE) return 3;
160  if (tag == elementType::HEXAGON) return 8;
161  if (tag == elementType::BRICK) return 6;
162  if (tag == elementType::LAGRANGE_BRICK) return 6;
163  if (tag == elementType::TETRAHEDRON) return 4;
164  if (tag == elementType::HEXPRISM) return 10;
165  if (tag == elementType::PRISMATIC) return 6;
166  std::cerr << "Unknown element type\n";
167  throw;
168 }
169 //////////////////////////////////
170 // pntMesh class
171 //////////////////////////////////
172 
174  : ifname(""), isSupported(true)
175 {}
176 
178  : ifname(ifname), isSupported(true)
179 {
180 
181  // NOTE: If file is very large different means are needed
182  // current implementation is focused on the speed of reading
183  // information from the file.
184 
185  std::ifstream fs(ifname);
186  if (!fs.good())
187  {
188  std::cout << "Error opening file " << ifname << std::endl;
189  exit(1);
190  }
191 
192  // read entire file into buffer and then pass to stream
193  std::stringstream ss;
194  ss << fs.rdbuf();
195 
196  /////////////////////////////
197  // processing CARD 01
198  // //////////////////////////
199  // header
200  int dmi;
201  std::string dms;
202 
203  ss >> numVertices;
204  ss >> numElements;
205  ss >> numDimensions;
206  ss >> numBlocks;
207  ss >> numSurfaces;
208  ss >> numSurfInternal;
209  ss >> numSurfBoundary;
210  ss >> dmi; // dummy
211  ss >> dmi;
212  ss >> dmi;
213 
214  std::cout << "Reading PNT Mesh..." << std::endl;
215  std::cout << "Number of vertices : " << numVertices << std::endl;
216  std::cout << "Number of eLements : " << numElements << std::endl;
217  std::cout << "Number of dimensions : " << numDimensions << std::endl;
218  std::cout << "Number of blocks : " << numBlocks << std::endl;
219  std::cout << "Number of surfaces : " << numSurfaces << std::endl;
220  std::cout << "Number of internals surface : " << numSurfInternal << std::endl;
221  std::cout << "Number of boundary surface : " << numSurfBoundary << std::endl;
222 
223  /////////////////////////////
224  // processing CARD 02
225  // //////////////////////////
226  // nodal coords
227  pntCrds.resize(numVertices, std::vector<double>(3, 0));
228  for (int id = 0; id < numDimensions; id++)
229  for (int iv = 0; iv < numVertices; iv++)
230  ss >> pntCrds[iv][id];
231 
232  /////////////////////////////
233  // processing CARD 03
234  // //////////////////////////
235  // block data
236  elmBlks.resize(numBlocks);
237  for (int iBlk = 0; iBlk < numBlocks; iBlk++)
238  {
239  blockType nb;
240 
241  // block header
242  ss >> nb.numElementsInBlock;
244  ss >> nb.nodesPerElement;
245  ss >> dmi;
246  ss >> nb.ordIntrp;
247  ss >> nb.ordEquat;
248  ss >> dms;
249  std::cout << dms << std::endl;
250  nb.eTpe = elmTypeNum(dms);
251  ss >> nb.regionName;
252 
253  std::cout << "================================================"
254  << std::endl;
255  std::cout << "Processing block " << nb.regionName << std::endl;
256  std::cout << "Num Elements : " << nb.numElementsInBlock << std::endl;
257  std::cout << "Num Boundary Surfaces : " << nb.numBoundarySurfacesInBlock
258  << std::endl;
259  std::cout << "Num Nodes/Element : " << nb.nodesPerElement << std::endl;
260  std::cout << "Element order : " << nb.ordIntrp << std::endl;
261  std::cout << "Equation order : " << nb.ordEquat << std::endl;
262  std::cout << "Element Type : " << elmTypeStr(nb.eTpe) << std::endl;
263 
264  // make sure all blocks are tetrahedral or triangular
266  && nb.eTpe != elementType::TRIANGLE)
267  isSupported = false;
268 
269  // element connectivity array
270  std::cout << "Reading block...";
271  nb.eConn.resize(nb.numElementsInBlock);
272  for (int ibe = 0; ibe < nb.numElementsInBlock; ibe++)
273  {
274  std::vector<idTyp> conn;
275  conn.resize(nb.nodesPerElement);
276  for (int ine = 0; ine < nb.nodesPerElement; ine++)
277  {
278  ss >> conn[ine];
279  --conn[ine]; // pnt mesh is 1-indexed
280  }
281  nb.eConn[ibe] = conn;
282  elmConn.push_back(conn);
283  elmTyp.push_back(nb.eTpe);
284  elmOrd.push_back(nb.ordIntrp);
285  }
286 
287  // surface boundary tags
288  std::cout << "...";
289  nb.srfBCTag.resize(nb.numBoundarySurfacesInBlock);
290  for (int ist = 0; ist < nb.numBoundarySurfacesInBlock; ist++)
291  {
292  ss >> dms;
293  nb.srfBCTag[ist] = bcTagNum(dms);
294  }
295 
296  // element surface reference number
297  std::cout << "...";
298  nb.srfBCEleRef.resize(2 * nb.numBoundarySurfacesInBlock);
299  for (int ise = 0; ise < nb.numBoundarySurfacesInBlock; ise++)
300  {
301  idTyp er;
302  ss >> er;
303  nb.srfBCEleRef.push_back(er);
304  ss >> er;
305  nb.srfBCEleRef.push_back(er);
306  }
307 
308  // adjacancy header
309  std::cout << "...";
310  ss >> dmi;
311  ss >> nb.numSurfPerEleInBlock;
312  int ni = nb.numSurfPerEleInBlock * nb.numElementsInBlock;
313  nb.glbSrfId.resize(ni);
314  nb.adjBlkId.resize(ni);
315  nb.adjElmId.resize(ni);
316  nb.adjRefId.resize(ni);
317 
318  // global surface ids
319  std::cout << "...";
320  for (int i = 0; i < ni; i++)
321  ss >> nb.glbSrfId[i];
322 
323  // adjacent block ids
324  std::cout << "...";
325  for (int i = 0; i < ni; i++)
326  ss >> nb.adjBlkId[i];
327 
328  // adjacent element ids
329  std::cout << "...";
330  for (int i = 0; i < ni; i++)
331  ss >> nb.adjElmId[i];
332 
333  // adjacent reference ids
334  std::cout << "..." << std::endl;
335  for (int i = 0; i < ni; i++)
336  ss >> nb.adjRefId[i];
337 
338  // block finishes
339  elmBlks[iBlk] = nb;
340  }
341 
342  // closing the file
343  fs.close();
344 }
345 
346 // constructor from meshBase object
347 // reads a meshBase object and populates internal database
348 // assumes all elements of certain type reside in separate blocks,
349 // TODO: Should be extended to get block data, BCs, etc.
350 // and prepare internal data structure properly based on these information
351 PNTMesh::pntMesh::pntMesh(const meshBase *imb, int dim, int nBlk,
352  const BlockMap &elmBlkMap)
353  : numDimensions(dim), numBlocks(nBlk), numSurfaces(0), numSurfInternal(0),
354  numSurfBoundary(0)
355 {
357  numElements = imb->getNumberOfCells();
358 
359  // populating point coordinates
360  pntCrds.resize(numVertices);
361  for (int ipt = 0; ipt < numVertices; ipt++)
362  {
363  std::vector<double> crds;
364  crds.resize(3, 0.);
365  imb->getDataSet()->GetPoint(ipt, &crds[0]);
366  pntCrds[ipt] = crds;
367  }
368 
369  // populating cell connectivity
370  elmConn.resize(numElements);
371  elmTyp.resize(numElements);
372  for (int i = 0; i < numElements; ++i)
373  {
374  vtkIdList *point_ids = imb->getDataSet()->GetCell(i)->GetPointIds();
375  int numComponent = point_ids->GetNumberOfIds();
376  std::vector<int> cn;
377  cn.resize(numComponent);
378  for (int j = 0; j < numComponent; ++j)
379  cn[j] = point_ids->GetId(j);
380  elmConn[i] = cn;
381 
382  VTKCellType type_id = static_cast<VTKCellType>(imb->getDataSet()->GetCellType(i));
383  elmTyp[i] = v2pEMap(type_id);
384  }
385 
386  // populating element block ids, and order
387  elmBlkId.resize(numElements, -1);
388  elmLocalId.resize(numElements, -1);
389  elmOrd.resize(numElements, -1);
390  for (int iBlk = 0; iBlk < numBlocks; iBlk++)
391  {
392  int lid = 0;
393  for (auto it = elmBlkMap[iBlk].elmIds.begin();
394  it != elmBlkMap[iBlk].elmIds.end();
395  it++)
396  {
397  elmBlkId[*it] = iBlk;
398  elmLocalId[*it] = lid++;
399  elmOrd[*it] = elmBlkMap[iBlk].ordIntrp;
400  }
401  }
402 
403  // analyzing element blocks and populating some of the
404  // fileds
405  elmBlks = elmBlkMap;
406  for (int iBlk = 0; iBlk < numBlocks; iBlk++)
407  {
408  elmBlks[iBlk].numElementsInBlock = elmBlks[iBlk].elmIds.size();
409  elmBlks[iBlk].nodesPerElement = elmNumNde(elmBlks[iBlk].eTpe,
410  elmBlks[iBlk].ordIntrp);
411  elmBlks[iBlk].numSurfPerEleInBlock = elmNumSrf(elmBlks[iBlk].eTpe);
412  std::cout << "Block Name = " << elmBlks[iBlk].regionName << std::endl;
413  std::cout << "Block size = " << elmBlks[iBlk].numElementsInBlock
414  << std::endl;
415  }
416 
417  //populate remaining fields
418  pntPopulate(imb);
419 }
420 
421 std::vector<int> PNTMesh::pntMesh::getElmConn(int id, VTKCellType vct) const
422 {
423  std::vector<int> ci = getElmConn(id);
424  std::vector<int> co;
425  co = ci;
426  if (vct == VTK_QUADRATIC_TRIANGLE)
427  {
428  co[0] = ci[0];
429  co[1] = ci[2];
430  co[2] = ci[4];
431  co[3] = ci[1];
432  co[4] = ci[3];
433  co[5] = ci[5];
434  }
435  else if (vct == VTK_QUADRATIC_HEXAHEDRON)
436  {
437  co[0] = ci[0];
438  co[1] = ci[2];
439  co[2] = ci[8];
440  co[3] = ci[6];
441  co[4] = ci[18];
442  co[5] = ci[20];
443  co[6] = ci[26];
444  co[7] = ci[24];
445  co[8] = ci[1];
446  co[9] = ci[5];
447  co[10] = ci[7];
448  co[11] = ci[3];
449  co[12] = ci[19];
450  co[13] = ci[23];
451  co[14] = ci[25];
452  co[15] = ci[21];
453  co[16] = ci[9];
454  co[17] = ci[11];
455  co[18] = ci[17];
456  co[19] = ci[15];
457  co[20] = ci[12];
458  co[21] = ci[14];
459  co[22] = ci[10];
460  co[23] = ci[16];
461  co[24] = ci[4];
462  co[25] = ci[22];
463  co[26] = ci[13];
464  }
465  return co;
466 }
467 
468 std::vector<int>
469 PNTMesh::pntMesh::getPntConn(std::vector<int> &ci, elementType et, int eo) const
470 {
471  std::vector<int> co;
472  co = ci;
473  if (et == elementType::TRIANGLE && eo == 2)
474  {
475  co[0] = ci[0];
476  co[2] = ci[1];
477  co[4] = ci[2];
478  co[1] = ci[3];
479  co[3] = ci[4];
480  co[5] = ci[5];
481  }
482  else if ((et == elementType::HEXAGON || et == elementType::LAGRANGE_BRICK ||
483  et == elementType::BRICK) &&
484  eo == 2)
485  {
486  co[0] = ci[0];
487  co[2] = ci[1];
488  co[8] = ci[2];
489  co[6] = ci[3];
490  co[18] = ci[4];
491  co[20] = ci[5];
492  co[26] = ci[6];
493  co[24] = ci[7];
494  co[1] = ci[8];
495  co[5] = ci[9];
496  co[7] = ci[10];
497  co[3] = ci[11];
498  co[19] = ci[12];
499  co[23] = ci[13];
500  co[25] = ci[14];
501  co[21] = ci[15];
502  co[9] = ci[16];
503  co[11] = ci[17];
504  co[17] = ci[18];
505  co[15] = ci[19];
506  co[12] = ci[20];
507  co[14] = ci[21];
508  co[10] = ci[22];
509  co[16] = ci[23];
510  co[4] = ci[24];
511  co[22] = ci[25];
512  co[13] = ci[26];
513  }
514  return co;
515 }
516 
517 std::string PNTMesh::pntMesh::getBlockName(int id) const
518 {
519  if (id >= numBlocks || id < 0)
520  {
521  std::cerr << "Invalid Block Id " << std::endl;
522  throw;
523  }
524  return elmBlks[id].regionName;
525 }
526 
528 {
529  if (id >= numBlocks || id < 0)
530  {
531  std::cerr << "Invalid Block Id " << std::endl;
532  throw;
533  }
534  return elmBlks[id].eTpe;
535 }
536 
538 {
539  if (id >= numElements || id < 0)
540  {
541  std::cerr << "Invalid Element ID " << std::endl;
542  throw;
543  }
544  return elmTyp[id];
545 }
546 
548 {
549  if (id >= numElements || id < 0)
550  {
551  std::cerr << "Invalid Element ID " << std::endl;
552  throw;
553  }
554  return elmOrd[id];
555 }
556 
557 
558 VTKCellType PNTMesh::pntMesh::getVtkCellTag(elementType et, int order) const
559 {
560  if (et == elementType::TRIANGLE)
561  switch (order)
562  {
563  case 1: return VTK_TRIANGLE;
564  case 2: return VTK_QUADRATIC_TRIANGLE;
565  default: return VTK_HIGHER_ORDER_TRIANGLE;
566  }
567 
568  if (et == elementType::QUADRILATERAL)
569  switch (order)
570  {
571  case 1: return VTK_QUAD;
572  case 2: return VTK_QUADRATIC_QUAD;
573  default: return VTK_HIGHER_ORDER_QUAD;
574  }
575 
576  if (et == elementType::TETRAHEDRON)
577  switch (order)
578  {
579  case 1: return VTK_TETRA;
580  case 2: return VTK_QUADRATIC_TETRA;
581  default: return VTK_HIGHER_ORDER_TETRAHEDRON;
582  }
583 
584  if (et == elementType::HEXAGON
585  || et == elementType::BRICK
587  switch (order)
588  {
589  case 1: return VTK_HEXAHEDRON;
590  case 2: return VTK_QUADRATIC_HEXAHEDRON;
591  default: return VTK_HIGHER_ORDER_HEXAHEDRON;
592  }
593 
594  if (et == elementType::PRISMATIC)
595  switch (order)
596  {
597  case 1: return VTK_WEDGE;
598  case 2: return VTK_QUADRATIC_WEDGE;
599  default: return VTK_HIGHER_ORDER_WEDGE;
600  }
601 
602  std::cerr << "Unknown element type "
603  << static_cast<std::underlying_type<elementType>::type>(et)
604  << " order " << order << std::endl;
605  throw;
606 }
607 
608 // writes PNT mesh data into file
609 void PNTMesh::pntMesh::write(const std::string &fname) const
610 {
611  std::ofstream outputStream(fname.c_str());
612  if (!outputStream.good())
613  {
614  std::cout << "Output file stream is bad" << std::endl;
615  exit(1);
616  }
617 
618  // --------- writing pntmesh header ----------- //
619  outputStream << std::setw(10) << numVertices
620  << std::setw(10) << numElements
621  << std::setw(10) << numDimensions
622  << std::setw(10) << numBlocks
623  << std::setw(10) << numSurfaces
624  << std::setw(10) << numSurfInternal
625  << std::setw(10) << numSurfBoundary
626  << std::setw(10) << 0
627  << std::setw(10) << 0
628  << std::setw(10) << 0
629  << std::endl;
630 
631  // --------- writing node coords ----------- //
632  int lb = 0;
633  for (int id = 0; id < numDimensions; id++)
634  {
635  for (int iv = 0; iv < numVertices; iv++)
636  {
637  outputStream << std::setw(15)
638  << std::scientific
639  << std::setprecision(8)
640  << pntCrds[iv][id];
641  if (++lb == 8)
642  {
643  outputStream << std::endl;
644  lb = 0;
645  }
646  }
647  }
648  outputStream << std::endl;
649 
650  // --------- writing element blocks ----------- //
651  for (int ib = 0; ib < numBlocks; ib++)
652  {
653  // block header
654  outputStream << std::setw(10) << elmBlks[ib].numElementsInBlock
655  << std::setw(10) << elmBlks[ib].numBoundarySurfacesInBlock
656  << std::setw(10) << elmBlks[ib].nodesPerElement
657  << std::setw(10) << 0
658  << std::setw(10) << elmBlks[ib].ordIntrp
659  << std::setw(10) << elmBlks[ib].ordEquat
660  << std::endl;
661 
662  // element type and region name
663  outputStream << std::setw(16) << std::left << elmTypeStr(elmBlks[ib].eTpe)
664  << std::setw(16) << std::left << elmBlks[ib].regionName
665  << std::endl;
666 
667  // element connectivity
668  lb = 1;
669  for (int ie = 0; ie < elmBlks[ib].numElementsInBlock; ie++)
670  {
671  std::vector<int> econn;
672  econn = elmBlks[ib].eConn[ie];
673  econn = getPntConn(econn, elmBlks[ib].eTpe, elmBlks[ib].ordIntrp);
674  for (int im = 0; im < econn.size(); im++, lb++)
675  {
676  outputStream << std::setw(10) << std::right << econn[im] + 1;
677  if (lb == 12)
678  {
679  lb = 0;
680  outputStream << std::endl;
681  }
682  }
683  }
684  if (lb != 1)
685  outputStream << std::endl;
686 
687  // BC tags
688  lb = 1;
689  for (auto it = elmBlks[ib].srfBCTag.begin();
690  it != elmBlks[ib].srfBCTag.end(); it++, lb++)
691  {
692  outputStream << std::setw(16) << std::left << bcTagStr(*it);
693  if (lb == 7)
694  {
695  lb = 0;
696  outputStream << std::endl;
697  }
698  }
699  if (lb != 1)
700  outputStream << std::endl;
701 
702  // element number/ref number pairs
703  lb = 1;
704  for (auto it = elmBlks[ib].srfBCEleRef.begin();
705  it != elmBlks[ib].srfBCEleRef.end();
706  it++, lb++)
707  {
708  outputStream << std::setw(10) << std::right << *it;
709  if (lb == 12)
710  {
711  lb = 0;
712  outputStream << std::endl;
713  }
714  }
715  if (lb != 1)
716  outputStream << std::endl;
717 
718  // adjacency header
719  outputStream << std::setw(10) << elmBlks[ib].numElementsInBlock
720  << std::setw(10) << elmBlks[ib].numSurfPerEleInBlock
721  << std::endl;
722 
723  // global surface array
724  lb = 1;
725  for (auto it = elmBlks[ib].glbSrfId.begin();
726  it != elmBlks[ib].glbSrfId.end();
727  it++, lb++)
728  {
729  outputStream << std::setw(10) << std::right << *it;
730  if (lb == 12)
731  {
732  lb = 0;
733  outputStream << std::endl;
734  }
735  }
736  if (lb != 1)
737  outputStream << std::endl;
738 
739  // adjacency block array
740  lb = 1;
741  for (auto it = elmBlks[ib].adjBlkId.begin();
742  it != elmBlks[ib].adjBlkId.end();
743  it++, lb++)
744  {
745  outputStream << std::setw(10) << std::right << *it;
746  if (lb == 12)
747  {
748  lb = 0;
749  outputStream << std::endl;
750  }
751  }
752  if (lb != 1)
753  outputStream << std::endl;
754 
755  // adjacency element array
756  lb = 1;
757  for (auto it = elmBlks[ib].adjElmId.begin();
758  it != elmBlks[ib].adjElmId.end();
759  it++, lb++)
760  {
761  outputStream << std::setw(10) << std::right << *it;
762  if (lb == 12)
763  {
764  lb = 0;
765  outputStream << std::endl;
766  }
767  }
768  if (lb != 1)
769  outputStream << std::endl;
770 
771  // adjacency reference array
772  lb = 1;
773  for (auto it = elmBlks[ib].adjRefId.begin();
774  it != elmBlks[ib].adjRefId.end();
775  it++, lb++)
776  {
777  outputStream << std::setw(10) << std::right << *it;
778  if (lb == 12)
779  {
780  lb = 0;
781  outputStream << std::endl;
782  }
783  }
784  if (lb != 1)
785  outputStream << std::endl;
786  }
787 
788  // closing the stream
789  outputStream.close();
790 }
791 
792 
794 {
795  // acquiring dataset
796  vtkSmartPointer<vtkDataSet> ds = imb->getDataSet();
797  if (!ds) {
798  std::cerr << "No dataset is associated to the meshbase." << std::endl;
799  exit(1);
800  }
801 
802  // loop through cells and obtain different quantities needed
803  int srfId = 0;
804  int nCl = ds->GetNumberOfCells();
805  elmSrfId.resize(nCl);
806  for (int ic = 0; ic < nCl; ic++)
807  {
808  vtkCell *vc = ds->GetCell(ic);
809  if (vc->GetCellDimension() == 2)
810  {
811  //for 2D cells
812  int ne = vc->GetNumberOfEdges();
813  for (int ie = 0; ie < ne; ie++)
814  {
815  numSurfInternal++;
816  vtkCell *ve = vc->GetEdge(ie);
817  vtkIdList *pidl = ve->GetPointIds();
818 
819  // edge connectivity
820  std::set<int> econn;
821  std::map<std::set<int>, int>::const_iterator itSrfId;
822  std::pair<int, int> adjPair;
823  std::vector<int> adjCellId;
824  for (int ipt = 0; ipt < pidl->GetNumberOfIds(); ipt++)
825  econn.insert(pidl->GetId(ipt));
826  auto ret1 = connSet.insert(econn);
827  bool isNew = ret1.second;
828  if (isNew)
829  {
830  // global surface connectivity
831  surfConnToId[econn] = srfId;
832  surfIdToConn[srfId] = econn;
833  // global reference number
834  adjPair.first = ic;
835  adjPair.second = ie + 1;
836  }
837  else
838  {
839  // if edge is already accounted update reference
840  // number for its second neighbor cell
841  itSrfId = surfConnToId.find(econn);
842  if (itSrfId != surfConnToId.end())
843  {
844  adjPair.first = ic;
845  adjPair.second = ie + 1;
846  }
847  else
848  {
849  std::cerr << "Found a repeated surface connectivity without id.";
850  exit(1);
851  }
852  }
853 
854  // getting neighbour list
855  bool isBndrSrf = false;
856  adjCellId.push_back(ic + 1);
857  vtkSmartPointer<vtkIdList> cidl = vtkSmartPointer<vtkIdList>::New();
858  ds->GetCellNeighbors(ic, pidl, cidl);
859  if (cidl->GetNumberOfIds() == 0)
860  {
861  isBndrSrf = true;
862  adjPair.second = 0;
863  adjCellId.push_back(0);
864  numSurfBoundary++;
865  }
866 
867  // updating adjacency information
868  if (isNew)
869  {
870  // element global surface id
871  elmSrfId[ic].push_back(srfId);
872  surfOnBndr.push_back(isBndrSrf);
873  surfAdjRefNum[srfId].push_back(adjPair);
874  surfAdjElmNum[srfId].insert(surfAdjElmNum[srfId].end(),
875  adjCellId.begin(),
876  adjCellId.end());
877  }
878  else
879  {
880  // element global surface id
881  elmSrfId[ic].push_back(itSrfId->second);
882  surfAdjRefNum[itSrfId->second].push_back(adjPair);
883  surfAdjElmNum[itSrfId->second].insert(
884  surfAdjElmNum[itSrfId->second].end(),
885  adjCellId.begin(),
886  adjCellId.end());
887  }
888 
889  // finally increment surface id number if needed
890  if (isNew) srfId++;
891  }
892  }
893  else if (vc->GetCellDimension() == 3)
894  {
895  //for 3D cells
896  int nfc = vc->GetNumberOfFaces();
897  for (int ifc = 0; ifc < nfc; ifc++)
898  {
899  numSurfInternal++;
900  vtkCell *vf = vc->GetFace(ifc);
901  vtkIdList *pidl = vf->GetPointIds();
902 
903  // surface connectivity
904  std::set<int> econn;
905  std::map<std::set<int>, int>::const_iterator itSrfId;
906  std::pair<int, int> adjPair;
907  std::vector<int> adjCellId;
908  for (int ipt = 0; ipt < pidl->GetNumberOfIds(); ipt++)
909  econn.insert(pidl->GetId(ipt));
910  auto ret1 = connSet.insert(econn);
911  bool isNew = ret1.second;
912  if (isNew)
913  {
914  // global surface connectivity
915  surfConnToId[econn] = srfId;
916  surfIdToConn[srfId] = econn;
917  // global reference number
918  adjPair.first = ic;
919  adjPair.second = ifc + 1;
920  }
921  else
922  {
923  // if edge is already accounted update reference
924  // number for its second neighbor cell
925  itSrfId = surfConnToId.find(econn);
926  if (itSrfId != surfConnToId.end())
927  {
928  adjPair.first = ic;
929  adjPair.second = ifc + 1;
930  }
931  else
932  {
933  std::cerr << "Found a repeated surface connectivity without id.";
934  exit(1);
935  }
936  }
937 
938  // getting neighbour list
939  bool isBndrSrf = false;
940  adjCellId.push_back(ic + 1);
941  vtkSmartPointer<vtkIdList> cidl = vtkSmartPointer<vtkIdList>::New();
942  ds->GetCellNeighbors(ic, pidl, cidl);
943  if (cidl->GetNumberOfIds() == 0)
944  {
945  isBndrSrf = true;
946  adjPair.second = 0;
947  adjCellId.push_back(0);
948  numSurfBoundary++;
949  }
950 
951  // updating adjacency information
952  if (isNew)
953  {
954  // element global surface id
955  elmSrfId[ic].push_back(srfId);
956  surfOnBndr.push_back(isBndrSrf);
957  surfAdjRefNum[srfId].push_back(adjPair);
958  surfAdjElmNum[srfId].insert(surfAdjElmNum[srfId].end(),
959  adjCellId.begin(),
960  adjCellId.end());
961  }
962  else
963  {
964  // element global surface id
965  elmSrfId[ic].push_back(itSrfId->second);
966  surfAdjRefNum[itSrfId->second].push_back(adjPair);
967  surfAdjElmNum[itSrfId->second].insert(
968  surfAdjElmNum[itSrfId->second].end(),
969  adjCellId.begin(),
970  adjCellId.end());
971  }
972  // finally increment surface id number if needed
973  if (isNew) srfId++;
974  }
975  }
976  }
978  numSurfInternal /= 2;
981  std::cout << "Number of boundary surfaces (edges) = " << numSurfBoundary
982  << std::endl;
983  std::cout << "Number of internal surfaces (edges) = " << numSurfInternal
984  << std::endl;
985  std::cout << "Total number of surfaces (edges) = " << numSurfaces
986  << std::endl;
987  std::cout << "Srf ID = " << srfId << std::endl;
988 
989  // testing
990  /*
991  for (auto itt1 = surfAdjElmNum.begin(); itt1 != surfAdjElmNum.end(); itt1++)
992  {
993  std::cout << "/////////\n";
994  for (auto itt2 = (itt1->second).begin(); itt2 != (itt1->second).end(); itt2++)
995  std::cout << *itt2 << std::endl;
996  }
997  */
998 
999  /*
1000  for (auto it = elmSrfId.begin(); it!=elmSrfId.end(); it++)
1001  std::cout << "Number of element surfaces = " << it->size() << std::endl;
1002  */
1003 
1004  // preparing element blocks
1005  for (int iBlk = 0; iBlk < numBlocks; iBlk++)
1006  updElmBlk(iBlk);
1007  std::cout << "Finished processing blocks." << std::endl;
1008 }
1009 
1010 
1012 {
1013  std::cout << "Working on block " << blkId << std::endl;
1014  elmBlks[blkId].numBoundarySurfacesInBlock = 0;
1015  // block's first element global index
1016  int frstElmGlbIdx = elmBlks[blkId].elmIds[0];
1017  // TODO: Removing the first element to avoid additional tag
1018  surfaceBCTag sbc = elmBlks[blkId].srfBCTag[0];
1019  elmBlks[blkId].srfBCTag.pop_back();
1020  // looping through elements in block
1021  for (auto ie = elmBlks[blkId].elmIds.begin();
1022  ie != elmBlks[blkId].elmIds.end();
1023  ie++)
1024  {
1025  // connectivity
1026  std::cout << "Working on element " << *ie << std::endl;
1027  elmBlks[blkId].eConn.push_back(elmConn[*ie]);
1028 
1029  // surface related calculations
1030  // looping through element surfaces
1031  int srfRefId = 0;
1032  for (auto is = elmSrfId[*ie].begin();
1033  is != elmSrfId[*ie].end();
1034  is++)
1035  {
1036  // incrementing reference id
1037  srfRefId++;
1038  // adjacent element information
1039  int adjElmId = surfAdjRefNum[*is][0].first == *ie
1040  ? surfAdjRefNum[*is][1].first
1041  : surfAdjRefNum[*is][0].first;
1042  int adjRefId = surfAdjRefNum[*is][0].first == *ie
1043  ? surfAdjRefNum[*is][1].second
1044  : surfAdjRefNum[*is][0].second;
1045 
1046  if (surfOnBndr[*is])
1047  {
1048  // number of boundary surfaces
1049  elmBlks[blkId].numBoundarySurfacesInBlock++;
1050  // TODO: duplicating surface boundary condition tag
1051  // with index 0 for now
1052  elmBlks[blkId].srfBCTag.push_back(sbc);
1053  // element's boundary surface reference number
1054  elmBlks[blkId].srfBCEleRef.push_back(*ie + 1 - frstElmGlbIdx); // local element indx
1055  elmBlks[blkId].srfBCEleRef.push_back(srfRefId); // ref surface number
1056  // adjacency information
1057  elmBlks[blkId].adjElmId.push_back(0);
1058  elmBlks[blkId].adjBlkId.push_back(0);
1059  elmBlks[blkId].adjRefId.push_back(0);
1060  }
1061  else
1062  {
1063  // adjacency information
1064  elmBlks[blkId].adjElmId.push_back(elmLocalId[adjElmId] + 1);
1065  elmBlks[blkId].adjBlkId.push_back(elmBlkId[adjElmId] + 1);
1066  elmBlks[blkId].adjRefId.push_back(adjRefId);
1067  }
1068 
1069  // global surface id
1070  elmBlks[blkId].glbSrfId.push_back(*is + 1);
1071  }
1072  }
1073 }
std::vector< int > adjRefId
Definition: pntMesh.H:82
surfaceBCTag
Definition: pntMesh.H:62
std::vector< int > elmLocalId
Definition: pntMesh.H:148
std::string regionName
Definition: pntMesh.H:75
A brief description of meshBase.
Definition: meshBase.H:64
VTKCellType getVtkCellTag(elementType et, int order) const
Definition: pntMesh.C:558
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
int numElementsInBlock
Definition: pntMesh.H:68
int getElmOrder(int id) const
Definition: pntMesh.C:547
bool isSupported
Definition: pntMesh.H:152
std::string ifname
Definition: pntMesh.H:135
elementType getElmType(int id) const
Definition: pntMesh.C:537
std::vector< int > adjElmId
Definition: pntMesh.H:81
std::string elmTypeStr(elementType tag)
Definition: pntMesh.C:117
void pntPopulate(const meshBase *imb)
Definition: pntMesh.C:793
int elmNumSrf(elementType et)
Definition: pntMesh.C:155
std::map< int, std::set< int > > surfIdToConn
Definition: pntMesh.H:157
std::string getBlockName(int id) const
Definition: pntMesh.C:517
std::vector< std::vector< int > > elmSrfId
Definition: pntMesh.H:149
std::vector< int > elmOrd
Definition: pntMesh.H:146
std::set< std::set< int > > connSet
Definition: pntMesh.H:155
int idTyp
Definition: pntMesh.H:45
std::vector< int > srfBCEleRef
Definition: pntMesh.H:78
int numSurfInternal
Definition: pntMesh.H:141
std::vector< int > glbSrfId
Definition: pntMesh.H:79
std::vector< int > adjBlkId
Definition: pntMesh.H:80
std::vector< elementType > elmTyp
Definition: pntMesh.H:145
vtkSmartPointer< vtkDataSet > getDataSet() const
get this meshes&#39; dataSet
Definition: meshBase.H:308
std::vector< std::vector< int > > elmConn
Definition: pntMesh.H:144
nemId_t getNumberOfPoints() const
return the number of points
Definition: meshBase.H:545
int numBoundarySurfacesInBlock
Definition: pntMesh.H:69
void toLower(std::string &str)
std::vector< blockType > elmBlks
Definition: pntMesh.H:150
void updElmBlk(int blkId)
Definition: pntMesh.C:1011
vtkIdType id
id in .inp file
Definition: inpGeoMesh.C:128
surfaceBCTag bcTagNum(const std::string &tag)
Definition: pntMesh.C:78
elementType getBlockElmType(int id) const
Definition: pntMesh.C:527
std::vector< int > elmBlkId
Definition: pntMesh.H:147
std::map< int, std::vector< int > > surfAdjElmNum
Definition: pntMesh.H:160
std::vector< bool > surfOnBndr
Definition: pntMesh.H:158
std::map< std::set< int >, int > surfConnToId
Definition: pntMesh.H:156
elementType v2pEMap(VTKCellType vt)
Definition: pntMesh.C:58
int numSurfBoundary
Definition: pntMesh.H:142
elementType eTpe
Definition: pntMesh.H:74
VTKCellType p2vEMap(elementType et)
Definition: pntMesh.C:38
elementType
Definition: pntMesh.H:47
std::vector< std::vector< int > > eConn
Definition: pntMesh.H:83
std::vector< int > getElmConn(int id) const
Definition: pntMesh.H:114
int numSurfPerEleInBlock
Definition: pntMesh.H:73
TRIANGLE
Definition: exoMesh.H:55
std::map< int, std::vector< std::pair< int, int > > > surfAdjRefNum
Definition: pntMesh.H:159
std::vector< blockType > BlockMap
Definition: pntMesh.H:86
std::vector< std::vector< double > > pntCrds
Definition: pntMesh.H:143
void write(const std::string &fname) const
Definition: pntMesh.C:609
int elmNumNde(elementType et, int order)
Definition: pntMesh.C:133
nemId_t getNumberOfCells() const
return the number of cells
Definition: meshBase.H:550
elementType elmTypeNum(const std::string &tag)
Definition: pntMesh.C:97
std::vector< surfaceBCTag > srfBCTag
Definition: pntMesh.H:77
std::string bcTagStr(surfaceBCTag tag)
Definition: pntMesh.C:88
std::vector< int > getPntConn(std::vector< int > &ci, elementType et, int eo) const
Definition: pntMesh.C:469