ensightMeshReader.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "ensightMeshReader.H"
29 #include "cellModel.H"
30 #include "ensightReadFile.H"
31 #include "matchPoints.H"
32 #include "mergePoints.H"
33 #include "ListListOps.H"
34 #include "stringOps.H"
35 
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40 namespace fileFormats
41 {
42  defineTypeNameAndDebug(ensightMeshReader, 0);
43 }
44 }
45 
46 
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
48 
50 (
51  const face& f,
52  face& rotatedFace
53 ) const
54 {
55  label fp = findMin(f);
56 
57  rotatedFace.setSize(f.size());
58  forAll(rotatedFace, i)
59  {
60  rotatedFace[i] = f[fp];
61  fp = f.fcIndex(fp);
62  }
63  return rotatedFace;
64 }
65 
66 
68 (
69  ensightReadFile& is,
70  const label nVerts,
71  const Map<label>& nodeIdToPoints,
72  DynamicList<label>& verts
73 ) const
74 {
75  verts.clear();
76  for (label i = 0; i < nVerts; i++)
77  {
78  label verti;
79  is.read(verti);
80  //if (nodeIdToPoints.size())
81  //{
82  // verts.append(nodeIdToPoints[verti]);
83  //}
84  //else
85  {
86  verts.append(verti-1);
87  }
88  }
89 }
90 
91 
93 (
94  ensightReadFile& is,
95  const bool doRead,
96  const label nShapes,
97  labelList& foamToElem,
98  Map<label>& elemToFoam
99 ) const
100 {
101  const label sz = foamToElem.size();
102  foamToElem.resize(sz+nShapes);
103  if (doRead)
104  {
105  elemToFoam.resize(sz+nShapes);
106  for (label shapei = 0; shapei < nShapes; shapei++)
107  {
108  label elemi;
109  is.read(elemi);
110  foamToElem[sz+shapei] = elemi;
111  elemToFoam.insert(elemi, sz+shapei);
112  }
113  }
114  else
115  {
116  for (label shapei = 0; shapei < nShapes; shapei++)
117  {
118  foamToElem[sz+shapei] = sz+shapei;
119  }
120  }
121 }
122 
123 
125 (
126  const cellModel& model,
127  DynamicList<label>& verts,
128  const pointField& points
129 ) const
130 {
131 // // From plot3dToFoam/hexBlock.C
132 // const vector x(points[verts[1]]-points[verts[0]]);
133 // const scalar xMag(mag(x));
134 //
135 // const vector y(points[verts[3]]-points[verts[0]]);
136 // const scalar yMag(mag(y));
137 //
138 // const vector z(points[verts[4]]-points[verts[0]]);
139 // const scalar zMag(mag(z));
140 //
141 // if (xMag > SMALL && yMag > SMALL && zMag > SMALL)
142 // {
143 // if (((x ^ y) & z) < 0)
144 // {
145 // // Flipped hex
146 // Swap(verts[0], verts[4]);
147 // Swap(verts[1], verts[5]);
148 // Swap(verts[2], verts[6]);
149 // Swap(verts[3], verts[7]);
150 // }
151 // }
152 
153  if (model.mag(verts, points) < 0)
154  {
155  if (verts.size() == 8)
156  {
157  // Flipped hex
158  Swap(verts[0], verts[4]);
159  Swap(verts[1], verts[5]);
160  Swap(verts[2], verts[6]);
161  Swap(verts[3], verts[7]);
162  }
163  else if (verts.size() == 4)
164  {
165  // Flipped tet. Change orientation of base
166  Swap(verts[0], verts[1]);
167  }
168  else if (verts.size() == 5)
169  {
170  // Flipped pyr. Change orientation of base
171  Swap(verts[1], verts[3]);
172  }
173  else if (verts.size() == 6)
174  {
175  // Flipped prism.
176  Swap(verts[0], verts[3]);
177  Swap(verts[1], verts[4]);
178  Swap(verts[2], verts[5]);
179  }
180  }
181 }
182 
183 
185 (
186  ensightReadFile& is,
187  const bool read_node_ids,
188  const bool read_elem_ids,
189 
191  labelList& pointToNodeIds,
192  Map<label>& nodeIdToPoints,
193 
194  // 3D-elems : cells (cell-to-faces)
196  labelList& cellToElemIds,
197  Map<label>& elemIdToCells,
198 
199  // 2D-elems : faces
200  faceList& faces,
201  labelList& faceToElemIDs,
202  Map<label>& elemIdToFaces
203 ) const
204 {
205  //- Read a single part. Return true if end-of-file reached. Return false
206  // if reaching next 'part'.
207 
208 
209  // Work
210  DynamicList<label> verts;
211 
212  string line;
213  while (is.good())
214  {
215  do
216  {
217  is.readKeyword(line);
218  }
219  while (line.empty() && is.good());
220 
221  const auto split = stringOps::splitSpace(line);
222 
223  if (split.size() == 0)
224  {
225  continue;
226  }
227 
228  if (split[0] == "part")
229  {
230  return false;
231  }
232  else if (split[0] == "node_ids")
233  {
234  const label nPoints = points.size();
235  // Ignore for now
236  for (label i = 0; i < nPoints; i++)
237  {
238  label index;
239  is.read(index);
240  }
241  }
242  else if (split[0] == "coordinates")
243  {
244  label nPoints;
245  is.read(nPoints);
246 
247  Pout<< indent << "coordinates " << nPoints
248  << " starting at line " << is.lineNumber()
249  << " position " << is.stdStream().tellg() << endl;
250 
251  readIDs
252  (
253  is,
254  read_node_ids,
255  nPoints,
256  pointToNodeIds,
257  nodeIdToPoints
258  );
259 
260  points.setSize(nPoints);
261 
262  for (label pointi = 0; pointi < nPoints; pointi++)
263  {
264  is.read(points[pointi].x());
265  }
266  for (label pointi = 0; pointi < nPoints; pointi++)
267  {
268  is.read(points[pointi].y());
269  }
270  for (label pointi = 0; pointi < nPoints; pointi++)
271  {
272  is.read(points[pointi].z());
273  }
274  }
275  else if (split[0] == "tetra4")
276  {
277  label nShapes;
278  is.read(nShapes);
279 
280  Pout<< indent<< "tetra4 " << nShapes
281  << " starting at line " << is.lineNumber()
282  << " position " << is.stdStream().tellg() << endl;
283 
284  const label celli = cells.size();
285  cells.resize(celli+nShapes);
286 
287  readIDs
288  (
289  is,
290  read_elem_ids,
291  nShapes,
292  cellToElemIds,
293  elemIdToCells
294  );
295 
296  const auto& model = cellModel::ref(cellModel::TET);
297  for (label shapei = 0; shapei < nShapes; shapei++)
298  {
299  readVerts(is, 4, nodeIdToPoints, verts);
300  if (setHandedness_)
301  {
302  setHandedness(model, verts, points);
303  }
304  const cellShape cellVerts(model, verts);
305  cells[celli+shapei] = cellVerts.faces();
306  }
307  }
308  else if (split[0] == "pyramid5")
309  {
310  label nShapes;
311  is.read(nShapes);
312 
313  Pout<< indent<< "pyramid5 " << nShapes
314  << " starting at line " << is.lineNumber()
315  << " position " << is.stdStream().tellg() << endl;
316 
317  const label celli = cells.size();
318  cells.resize(celli+nShapes);
319 
320  readIDs
321  (
322  is,
323  read_elem_ids,
324  nShapes,
325  cellToElemIds,
326  elemIdToCells
327  );
328 
329  const auto& model = cellModel::ref(cellModel::PYR);
330  for (label shapei = 0; shapei < nShapes; shapei++)
331  {
332  readVerts(is, 5, nodeIdToPoints, verts);
333  if (setHandedness_)
334  {
335  setHandedness(model, verts, points);
336  }
337  const cellShape cellVerts(model, verts);
338  cells[celli+shapei] = cellVerts.faces();
339  }
340  }
341  else if (split[0] == "penta6")
342  {
343  label nShapes;
344  is.read(nShapes);
345 
346  Pout<< indent<< "penta6 " << nShapes
347  << " starting at line " << is.lineNumber()
348  << " position " << is.stdStream().tellg() << endl;
349 
350  const label celli = cells.size();
351  cells.resize(celli+nShapes);
352 
353  readIDs
354  (
355  is,
356  read_elem_ids,
357  nShapes,
358  cellToElemIds,
359  elemIdToCells
360  );
361 
362  const auto& model = cellModel::ref(cellModel::PRISM);
363  for (label shapei = 0; shapei < nShapes; shapei++)
364  {
365  readVerts(is, 6, nodeIdToPoints, verts);
366  if (setHandedness_)
367  {
368  setHandedness(model, verts, points);
369  }
370  const cellShape cellVerts(model, verts);
371  cells[celli+shapei] = cellVerts.faces();
372  }
373  }
374  else if (split[0] == "hexa8")
375  {
376  label nShapes;
377  is.read(nShapes);
378 
379  Pout<< indent<< "hexa8 " << nShapes
380  << " starting at line " << is.lineNumber()
381  << " position " << is.stdStream().tellg() << endl;
382 
383  const label celli = cells.size();
384  cells.resize(celli+nShapes);
385 
386  readIDs
387  (
388  is,
389  read_elem_ids,
390  nShapes,
391  cellToElemIds,
392  elemIdToCells
393  );
394 
395  const auto& model = cellModel::ref(cellModel::HEX);
396  for (label shapei = 0; shapei < nShapes; shapei++)
397  {
398  readVerts(is, 8, nodeIdToPoints, verts);
399  if (setHandedness_)
400  {
401  setHandedness(model, verts, points);
402  }
403  const cellShape cellVerts(model, verts);
404  cells[celli+shapei] = cellVerts.faces();
405  }
406  }
407  else if (split[0] == "nfaced")
408  {
409  label nShapes;
410  is.read(nShapes);
411 
412  Pout<< indent<< "nfaced " << nShapes
413  << " starting at line " << is.lineNumber()
414  << " position " << is.stdStream().tellg() << endl;
415 
416  const label celli = cells.size();
417  cells.resize(celli+nShapes);
418 
419  readIDs
420  (
421  is,
422  read_elem_ids,
423  nShapes,
424  cellToElemIds,
425  elemIdToCells
426  );
427 
428  for (label shapei = 0; shapei < nShapes; shapei++)
429  {
430  label nFaces;
431  is.read(nFaces);
432  faceList& cellFaces = cells[celli+shapei];
433  cellFaces.setSize(nFaces);
434  }
435 
436  for (label shapei = 0; shapei < nShapes; shapei++)
437  {
438  faceList& cellFaces = cells[celli+shapei];
439  forAll(cellFaces, cellFacei)
440  {
441  label nVerts;
442  is.read(nVerts);
443  cellFaces[cellFacei].setSize(nVerts);
444  }
445  }
446 
447  for (label shapei = 0; shapei < nShapes; shapei++)
448  {
449  faceList& cellFaces = cells[celli+shapei];
450  forAll(cellFaces, cellFacei)
451  {
452  face& f = cellFaces[cellFacei];
453  readVerts(is, f.size(), nodeIdToPoints, verts);
454  f.labelList::operator=(verts);
455 
456  forAll(f, fp)
457  {
458  if (f[fp] < 0 || f[fp] >= points.size())
459  {
460  FatalErrorInFunction<< "Face:" << shapei
461  << " verts:" << f
462  << " indexes outside points:" << points.size()
463  << exit(FatalError);
464  }
465  }
466  }
467  }
468  }
469  else if (split[0] == "tria3")
470  {
471  label nShapes;
472  is.read(nShapes);
473 
474  Pout<< indent << "tria3 " << nShapes
475  << " starting at line " << is.lineNumber()
476  << " position " << is.stdStream().tellg() << endl;
477 
478  const label facei = faces.size();
479 
480  readIDs
481  (
482  is,
483  read_elem_ids,
484  nShapes,
485  faceToElemIDs,
486  elemIdToFaces
487  );
488 
489  faces.setSize(facei+nShapes);
490 
491  for (label shapei = 0; shapei < nShapes; shapei++)
492  {
493  auto& f = faces[facei+shapei];
494  f.setSize(3);
495  readVerts(is, f.size(), nodeIdToPoints, verts);
496  f.labelList::operator=(verts);
497  }
498  }
499  else if (split[0] == "quad4")
500  {
501  label nShapes;
502  is.read(nShapes);
503 
504  Pout<< indent << "quad4 " << nShapes
505  << " starting at line " << is.lineNumber()
506  << " position " << is.stdStream().tellg() << endl;
507 
508  const label facei = faces.size();
509 
510  readIDs
511  (
512  is,
513  read_elem_ids,
514  nShapes,
515  faceToElemIDs,
516  elemIdToFaces
517  );
518 
519  faces.setSize(facei+nShapes);
520 
521  for (label shapei = 0; shapei < nShapes; shapei++)
522  {
523  auto& f = faces[facei+shapei];
524  f.setSize(4);
525  readVerts(is, f.size(), nodeIdToPoints, verts);
526  f.labelList::operator=(verts);
527  }
528  }
529  else if (split[0] == "nsided")
530  {
531  label nShapes;
532  is.read(nShapes);
533 
534  Pout<< indent << "nsided " << nShapes
535  << " starting at line " << is.lineNumber()
536  << " position " << is.stdStream().tellg() << endl;
537 
538  const label facei = faces.size();
539 
540  readIDs
541  (
542  is,
543  read_elem_ids,
544  nShapes,
545  faceToElemIDs,
546  elemIdToFaces
547  );
548 
549  faces.setSize(facei+nShapes);
550 
551  for (label shapei = 0; shapei < nShapes; shapei++)
552  {
553  auto& f = faces[facei+shapei];
554  label nVerts;
555  is.read(nVerts);
556  f.setSize(nVerts);
557  }
558 
559  for (label shapei = 0; shapei < nShapes; shapei++)
560  {
561  auto& f = faces[facei+shapei];
562  readVerts(is, f.size(), nodeIdToPoints, verts);
563  f.labelList::operator=(verts);
564  }
565  }
566  else
567  {
568  WarningInFunction << "Unhandled key " << string(split[0])
569  << " from line " << line
570  << " starting at line " << is.lineNumber()
571  << " position " << is.stdStream().tellg() << endl;
572  }
573  }
574 
575  // EOF
576  return true;
577 }
578 
579 
580 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
581 
583 (
584  const scalar scaleFactor
585 )
586 {
587  ensightReadFile is(geometryFile_);
588 
589  // Skip 'binary' tag
590  is.readBinaryHeader();
591 
592  string header;
593  is.read(header);
594  Info<< "Ensight : " << header << endl;
595  is.read(header);
596  Info<< "Ensight : " << header << endl;
597 
598 
599  bool read_node_ids = false;
600  bool read_elem_ids = false;
601 
602  // Storage for all the parts
603  // ~~~~~~~~~~~~~~~~~~~~~~~~~
604 
605  List<string> partNames;
606 
607  DynamicList<label> partIDs; // per part the original Ensight part no
608  PtrList<pointField> partPoints;
609  PtrList<labelList> partNodeIDs;
610  PtrList<Map<label>> partPointIDs;
611 
612  // Cells (cell-to-faces)
613  // Note: only one internal mesh supported.
614  PtrList<faceListList> partCells;
615  // Element ID for cells
616  PtrList<labelList> partCellIDs;
617  PtrList<Map<label>> partCellElemIDs;
618  // Boundary faces
619  PtrList<faceList> partFaces;
620  // Element IDs for faces
621  PtrList<labelList> partFaceIDs;
622  PtrList<Map<label>> partFaceElemIDs;
623 
624 
625  // Parse all
626  string line;
627  while (is.good())
628  {
629  do
630  {
631  is.readKeyword(line);
632  }
633  while (line.empty() && is.good());
634  const auto split = stringOps::splitSpace(line);
635 
636  if (split[0] == "extents")
637  {
638  point min;
639  point max;
640  is.read(min.x());
641  is.read(max.x());
642  is.read(min.y());
643  is.read(max.y());
644  is.read(min.z());
645  is.read(max.z());
646  Pout<< indent
647  << "Read extents " << boundBox(min, max)
648  << endl;
649  }
650  else if (split[0] == "node")
651  {
652  word id(split[1]);
653  word op(split[2]);
654  if (op == "given" || op == "ignore")
655  {
656  Pout<< indent << "Reading node ids" << endl;
657  read_node_ids = true;
658  }
659  }
660  else if (split[0] == "element")
661  {
662  word id(split[1]);
663  word op(split[2]);
664  if (op == "given" || op == "ignore")
665  {
666  Pout<< indent << "Reading element ids" << endl;
667  read_elem_ids = true;
668  }
669  }
670  else if (split[0] == "part")
671  {
672  bool finished = false;
673  do
674  {
675  label partIndex;
676  is.read(partIndex);
677  partIDs.append(partIndex);
678 
679  // Make space
680  partNames.setSize(partIDs.size());
681  partPoints.append(new pointField(0));
682  partNodeIDs.append(new labelList(0));
683  partPointIDs.append(new Map<label>());
684 
685  partCells.append(new faceListList(0));
686  partCellIDs.append(new labelList(0));
687  partCellElemIDs.append(new Map<label>());
688 
689  partFaces.append(new faceList(0));
690  partFaceIDs.append(new labelList(0));
691  partFaceElemIDs.append(new Map<label>());
692 
693  is.read(partNames.last());
694 
695  Pout<< indent
696  << "Reading part " << partIndex
697  << " name " << partNames.last()
698  << " starting at line " << is.lineNumber()
699  << " position " << is.stdStream().tellg() << endl;
700 
701  Pout<< incrIndent;
702  finished = readGoldPart
703  (
704  is,
705  read_node_ids,
706  read_elem_ids,
707 
708  partPoints.last(),
709  partNodeIDs.last(),
710  partPointIDs.last(),
711 
712  // Cells (cell-to-faces)
713  partCells.last(),
714  partCellIDs.last(),
715  partCellElemIDs.last(),
716 
717  // Faces
718  partFaces.last(),
719  partFaceIDs.last(),
720  partFaceElemIDs.last()
721  );
722 
723  partPoints.last() *= scaleFactor;
724 
725  Pout<< indent
726  << "For part " << partIndex
727  << " read cells " << partCells.last().size()
728  << " faces " << partFaces.last().size()
729  << endl;
730 
731  Pout<< decrIndent;
732  }
733  while (!finished);
734 
735  break;
736  }
737  }
738 
739 
740  // Merge all coordinates
741  labelListList pointToMerged(partPoints.size());
742 
743  //- Use point merging - also merges points inside a part which might upset
744  //- e.g. ami
745  //{
746  // label nPoints = 0;
747  // forAll(partPoints, parti)
748  // {
749  // nPoints += partPoints[parti].size();
750  // }
751  //
752  // points_.setSize(nPoints);
753  // nodeIds_.setSize(nPoints, -1);
754  // nPoints = 0;
755  // forAll(partPoints, parti)
756  // {
757  // const auto& pts = partPoints[parti];
758  //
759  // SubList<point>(points_, pts.size(), nPoints) = pts;
760  // SubList<label>(nodeIds_, pts.size(), nPoints) =
761  // partNodeIDs[parti];
762  //
763  // auto& map = pointToMerged[parti];
764  // map = nPoints + identity(pts.size());
765  //
766  // nPoints += pts.size();
767  // }
768  //
769  // if (mergeTol_ > 0)
770  // {
771  // const scalar mergeDist = mergeTol_*boundBox(points_, true).mag();
772  //
773  // labelList sharedToMerged;
774  // const label nMerged = inplaceMergePoints
775  // (
776  // points_,
777  // mergeDist,
778  // false,
779  // sharedToMerged
780  // );
781  // Pout<< "Merged " << nMerged << " points out of " << nPoints
782  // << " using merge tolerance " << mergeTol_
783  // << ", distance " << mergeDist
784  // << endl;
785  //
786  // forAll(partNodeIDs, parti)
787  // {
788  // inplaceRenumber(sharedToMerged, pointToMerged[parti]);
789  //
790  // // Now pointToMerged contains the numbering from original,
791  // // partwise to global points
792  // UIndirectList<label>(nodeIds_, pointToMerged[parti]) =
793  // partNodeIDs[parti];
794  // }
795  // }
796  //}
797 
798  // Merge all coordinates
799  {
800  boundBox extents;
801  label nPoints = 0;
802  forAll(partPoints, parti)
803  {
804  extents.add(partPoints[parti]);
805  nPoints += partPoints[parti].size();
806  }
807  const scalar mergeDist = mergeTol_*extents.mag();
808 
809  Pout<< "Merging points closer than " << mergeDist
810  << " calculated from bounding box " << extents
811  << " and mergeTol " << mergeTol_
812  << endl;
813 
814  forAll(partPoints, parti)
815  {
816  const auto& pPoints = partPoints[parti];
817  auto& pPointMap = pointToMerged[parti];
818  pPointMap.setSize(pPoints.size(), -1);
819 
820  Pout<< "Matching part " << parti
821  << " name " << partNames[parti]
822  << " points " << pPoints.size()
823  << " to current merged points " << points_.size()
824  << endl;
825 
826  if (points_.empty())
827  {
828  points_ = pPoints;
829  pPointMap = identity(pPoints.size());
830  }
831  else
832  {
833  // Match to existing
834  labelList from0To1;
836  (
837  pPoints,
838  points_,
839  scalarField(pPoints.size(), mergeDist),
840  false,
841  from0To1
842  );
843  label nAdded = 0;
844 
845  forAll(from0To1, partPointi)
846  {
847  const label pointi = from0To1[partPointi];
848  if (pointi != -1)
849  {
850  pPointMap[partPointi] = pointi;
851  }
852  else
853  {
854  nAdded++;
855  }
856  }
857 
858  const label nOldPoints = points_.size();
859  points_.setSize(nOldPoints+nAdded);
860  nAdded = 0;
861  forAll(from0To1, partPointi)
862  {
863  if (from0To1[partPointi] == -1)
864  {
865  const label newPointi = nOldPoints+nAdded++;
866  points_[newPointi] = pPoints[partPointi];
867  pPointMap[partPointi] = newPointi;
868  }
869  }
870  }
871  }
872 
873  // Now we have complete points. Take over element IDs.
874  nodeIds_.setSize(points_.size());
875  forAll(partNodeIDs, parti)
876  {
877  const auto& pPointMap = pointToMerged[parti];
878  UIndirectList<label>(nodeIds_, pPointMap) = partNodeIDs[parti];
879  }
880 
881  Pout<< "Merged from " << nPoints << " down to " << points_.size()
882  << " points" << endl;
883  }
884 
885 
886  // Merge all cells
887  labelList cellOffsets(partCells.size()+1);
888  cellOffsets[0] = 0;
889  {
890  label nCells = 0;
891  forAll(partCells, parti)
892  {
893  nCells += partCells[parti].size();
894  cellOffsets[parti+1] = nCells;
895  }
896 
897  cellFaces_.setSize(nCells);
898  cellTableId_.setSize(nCells);
899  elementIds_.setSize(nCells, -1);
900 
901  forAll(partCells, parti)
902  {
903  // Copy cells into position
904  const auto& cells = partCells[parti];
905 
906  SubList<faceList> cellSlice
907  (
908  cellFaces_,
909  cells.size(),
910  cellOffsets[parti]
911  );
912  cellSlice = cells;
913 
914  SubList<label>
915  (
916  cellTableId_,
917  cells.size(),
918  cellOffsets[parti]
919  ) = parti;
920 
921  SubList<label>
922  (
923  elementIds_,
924  cells.size(),
925  cellOffsets[parti]
926  ) = partCellIDs[parti];
927 
928  // Renumber faces
929  const auto& pointMap = pointToMerged[parti];
930 
931  for (auto& cellFaces : cellSlice)
932  {
933  for (auto& f : cellFaces)
934  {
935  inplaceRenumber(pointMap, f);
936  }
937  }
938  }
939  }
940 
941 
942  // Add cells to separate zones
943  forAll(partCells, parti)
944  {
945  cellTable_.setMaterial(parti, "fluid");
946  cellTable_.setName(parti, "part" + Foam::name(partIDs[parti]));
947  }
948 
949 
950  // Build map from face to cell and index. Note: use exact match
951  // - no circular equivalence
952  // - but instead pass in ordered faces (lowest numbered vertex first)
953  HashTable<cellFaceIdentifier, face, face::symmHasher> vertsToCell
954  (
955  2*cellOffsets.last()
956  );
957 
958  // Insert cell's faces into hashtable
959  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
960 
961  face rotatedFace;
962  forAll(cellFaces_, celli)
963  {
964  const auto& cFaces = cellFaces_[celli];
965  forAll(cFaces, cFacei)
966  {
967  const face& f = rotateFace(cFaces[cFacei], rotatedFace);
968 
969  const auto fFnd = vertsToCell.find(f);
970  if (fFnd)
971  {
972  // Already inserted. Internal face.
973  vertsToCell.erase(fFnd);
974  }
975  else
976  {
977  vertsToCell.insert(f, cellFaceIdentifier(celli, cFacei));
978  }
979  }
980  }
981 
982 
983  labelList patchToPart(partNames.size());
984  label nPatches = 0;
985  forAll(partFaces, parti)
986  {
987  if (partFaces[parti].size())
988  {
989  Pout<< "Using part " << parti
990  << " name " << partNames[parti]
991  << " as patch " << nPatches
992  << endl;
993 
994  patchToPart[nPatches++] = parti;
995  }
996  }
997  patchToPart.setSize(nPatches);
998  boundaryIds_.setSize(nPatches);
999  patchTypes_.setSize(nPatches, "wall");
1000  patchNames_.setSize(nPatches);
1001  forAll(patchNames_, patchi)
1002  {
1003  const label parti = patchToPart[patchi];
1004 
1005  Pout<< "Matching part " << parti
1006  << " name " << partNames[parti]
1007  << " faces " << partFaces[parti].size()
1008  //<< " points " << partPoints[parti].size()
1009  << " to merged faces " << vertsToCell.size()
1010  << ", merged points " << points_.size()
1011  << endl;
1012 
1013  patchNames_[patchi] = word::validate(partNames[parti]);
1014 
1015  const auto& pointMap = pointToMerged[parti];
1016  const auto& faces = partFaces[parti];
1017 
1018  auto& partCellAndFace = boundaryIds_[patchi];
1019  partCellAndFace.setSize(faces.size());
1020 
1021  label patchFacei = 0;
1022  forAll(faces, facei)
1023  {
1024  if (faces[facei].empty())
1025  {
1026  Pout<< "Ignoring empty face:" << facei << endl;
1027  continue;
1028  }
1029 
1030  // Rewrite into mesh-point ordering
1031  const face newF(pointMap, faces[facei]);
1032  // Lookup cell and face on cell using the vertices
1033  const auto cAndF = vertsToCell.find
1034  (
1035  rotateFace
1036  (
1037  newF,
1038  rotatedFace
1039  )
1040  );
1041 
1042  if (!cAndF)
1043  {
1044  //WarningInFunction
1045  // << "Did not find face " << facei
1046  // << " verts:" << faces[facei]
1047  // << " renumbered:" << newF
1048  // << " rotated:" << rotatedFace
1049  // << " in part " << parti
1050  // << endl;
1051  }
1052  else
1053  {
1054  partCellAndFace[patchFacei++] = cAndF();
1055  vertsToCell.erase(cAndF);
1056  }
1057  }
1058  partCellAndFace.setSize(patchFacei);
1059  }
1060  patchPhysicalTypes_.setSize(nPatches, "wall");
1061  patchStarts_.setSize(nPatches, 0);
1062  patchSizes_.setSize(nPatches, 0);
1063 
1064  if (vertsToCell.size())
1065  {
1066  // Unused internal or boundary faces
1067  boundaryIds_.append(List<cellFaceIdentifier>(0));
1068  {
1069  auto& cellAndFaces = boundaryIds_.last();
1070  cellAndFaces.setSize(vertsToCell.size());
1071  label i = 0;
1072  for (const auto& e : vertsToCell)
1073  {
1074  cellAndFaces[i++] = e;
1075  }
1076  }
1077  patchTypes_.append("empty");
1078  patchNames_.append("defaultFaces");
1079  patchPhysicalTypes_.append("empty");
1080  patchStarts_.append(0);
1081  patchSizes_.append(0);
1082 
1083  Pout<< "Introducing default patch " << patchNames_.size()-1
1084  << " name " << patchNames_.last() << endl;
1085  }
1086 
1087  return true;
1088 }
1089 
1090 
1091 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1092 
1094 (
1095  const fileName& geomFile,
1096  const objectRegistry& registry,
1097  const scalar mergeTol,
1098  const scalar scaleFactor,
1099  const bool setHandedness
1100 )
1101 :
1102  meshReader(geomFile, scaleFactor),
1103  mergeTol_(mergeTol),
1104  setHandedness_(setHandedness)
1105 {}
1106 
1107 
1108 // ************************************************************************* //
label nPatches
Definition: readKivaGrid.H:396
static word validate(const std::string &s, const bool prefix=false)
Construct validated word (no invalid characters).
Definition: word.C:38
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:51
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:449
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
List< face > faceList
A List of faces.
Definition: faceListFwd.H:41
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
void readIDs(ensightReadFile &is, const bool doRead, const label nShapes, labelList &foamToElem, Map< label > &elemToFoam) const
Read set of element/node IDs.
Determine correspondence between points. See below.
List< faceList > faceListList
A List of faceList.
Definition: faceListFwd.H:43
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
const face & rotateFace(const face &f, face &rotatedFace) const
Rotate face so lowest vertex is first.
static const cellModel & ref(const modelType model)
Look up reference to cellModel by enumeration. Fatal on failure.
Definition: cellModels.C:150
void readVerts(ensightReadFile &is, const label nVerts, const Map< label > &nodeIdToPoints, DynamicList< label > &verts) const
Read set of vertices. Optional mapping.
label findMin(const ListType &input, label start=0)
Linear search for the index of the min element, similar to std::min_element but for lists and returns...
scalar y
bool matchPoints(const UList< point > &pts0, const UList< point > &pts1, const UList< scalar > &matchDistance, const bool verbose, labelList &from0To1, const point &origin=point::zero)
Determine correspondence between pointFields. Gets passed.
Definition: matchPoints.C:29
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
const cellShapeList & cells
const pointField & points
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:31
label nPoints
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
defineTypeNameAndDebug(combustionModel, 0)
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:467
Geometric merging of points. See below.
labelList f(nPoints)
Foam::SubStrings< StringType > splitSpace(const StringType &str)
Split string into sub-strings at whitespace (TAB, NL, VT, FF, CR, SPC)
label lineNumber() const noexcept
Const access to the current stream line number.
Definition: IOstream.H:383
static bool split(const std::string &line, std::string &key, std::string &val)
Definition: cpuInfo.C:32
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
vector point
Point is a vector.
Definition: point.H:37
ensightMeshReader(const fileName &geomFile, const objectRegistry &registry, const scalar mergeTol=SMALL, const scalar scaleFactor=1.0, const bool setHandedness=true)
Construct from case name.
#define WarningInFunction
Report a warning using Foam::Warning.
label newPointi
Definition: readKivaGrid.H:496
void setHandedness(const cellModel &model, DynamicList< label > &verts, const pointField &points) const
Swap handedness of hex if needed.
bool readGoldPart(ensightReadFile &is, const bool read_node_ids, const bool read_elem_ids, pointField &points, labelList &pointToNodeIds, Map< label > &nodeIdToPoints, faceListList &cellFaces, labelList &cellToElemIds, Map< label > &elemIdToCells, faceList &faces, labelList &faceToElemIDs, Map< label > &elemIdToFaces) const
Read a single part until eof (return true) or until start of next.
void Swap(DynamicList< T, SizeMinA > &a, DynamicList< T, SizeMinB > &b)
Definition: DynamicList.H:647
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual bool readGeometry(const scalar scaleFactor=1.0)
Read the mesh from the file(s)
List< label > labelList
A List of labels.
Definition: List.H:62
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:458
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Namespace for OpenFOAM.