ideasUnvToFoam.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) 2011-2017 OpenFOAM Foundation
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 Application
27  ideasUnvToFoam
28 
29 Group
30  grpMeshConversionUtilities
31 
32 Description
33  I-Deas unv format mesh conversion.
34 
35  Uses either
36  - DOF sets (757) or
37  - face groups (2452(Cubit), 2467)
38  to do patching.
39  Works without but then puts all faces in defaultFaces patch.
40 
41 \*---------------------------------------------------------------------------*/
42 
43 #include "argList.H"
44 #include "polyMesh.H"
45 #include "Time.H"
46 #include "IFstream.H"
47 #include "cellModel.H"
48 #include "cellSet.H"
49 #include "faceSet.H"
50 #include "DynamicList.H"
51 
52 #include <cassert>
53 #include "MeshedSurfaces.H"
54 
55 using namespace Foam;
56 
57 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
58 
59 const string SEPARATOR(" -1");
60 
61 bool isSeparator(const std::string& line)
62 {
63  return line.substr(0, 6) == SEPARATOR;
64 }
65 
66 
67 // Reads past -1 and reads element type
68 label readTag(IFstream& is)
69 {
70  string tag;
71  do
72  {
73  if (!is.good())
74  {
75  return -1;
76  }
77 
78  string line;
79 
80  is.getLine(line);
81 
82  if (line.size() < 6)
83  {
84  return -1;
85  }
86 
87  tag = line.substr(0, 6);
88 
89  } while (tag == SEPARATOR);
90 
91  return readLabel(tag);
92 }
93 
94 
95 // Reads and prints header
96 void readHeader(IFstream& is)
97 {
98  string line;
99 
100  while (is.good())
101  {
102  is.getLine(line);
103 
104  if (isSeparator(line))
105  {
106  break;
107  }
108  else
109  {
110  Info<< line << endl;
111  }
112  }
113 }
114 
115 
116 // Skip
117 void skipSection(IFstream& is)
118 {
119  Info<< "Skipping section at line " << is.lineNumber() << '.' << endl;
120 
121  string line;
122 
123  while (is.good())
124  {
125  is.getLine(line);
126 
127  if (isSeparator(line))
128  {
129  break;
130  }
131  }
132 }
133 
134 
135 scalar readUnvScalar(const std::string& unvString)
136 {
137  string s(unvString);
138 
139  s.replaceAll("d", "E");
140  s.replaceAll("D", "E");
141 
142  return readScalar(s);
143 }
144 
145 
146 // Reads unit section
147 void readUnits
148 (
149  IFstream& is,
150  scalar& lengthScale,
151  scalar& forceScale,
152  scalar& tempScale,
153  scalar& tempOffset
154 )
155 {
156  Info<< "Starting reading units at line " << is.lineNumber() << '.' << endl;
157 
158  string line;
159  is.getLine(line);
160 
161  label l = readLabel(line.substr(0, 10));
162  Info<< "l:" << l << endl;
163 
164  string units(line.substr(10, 20));
165  Info<< "units:" << units << endl;
166 
167  label unitType = readLabel(line.substr(30, 10));
168  Info<< "unitType:" << unitType << endl;
169 
170  // Read lengthscales
171  is.getLine(line);
172 
173  lengthScale = readUnvScalar(line.substr(0, 25));
174  forceScale = readUnvScalar(line.substr(25, 25));
175  tempScale = readUnvScalar(line.substr(50, 25));
176 
177  is.getLine(line);
178  tempOffset = readUnvScalar(line.substr(0, 25));
179 
180  Info<< "Unit factors:" << nl
181  << " Length scale : " << lengthScale << nl
182  << " Force scale : " << forceScale << nl
183  << " Temperature scale : " << tempScale << nl
184  << " Temperature offset : " << tempOffset << nl
185  << endl;
186 }
187 
188 
189 // Reads points section. Read region as well?
190 void readPoints
191 (
192  IFstream& is,
193  DynamicList<point>& points, // coordinates
194  DynamicList<label>& unvPointID // unv index
195 )
196 {
197  Info<< "Starting reading points at line " << is.lineNumber() << '.' << endl;
198 
199  static bool hasWarned = false;
200 
201  while (true)
202  {
203  string line;
204  is.getLine(line);
205 
206  label pointi = readLabel(line.substr(0, 10));
207 
208  if (pointi == -1)
209  {
210  break;
211  }
212  else if (pointi != points.size()+1 && !hasWarned)
213  {
214  hasWarned = true;
215 
217  << "Points not in order starting at point " << pointi
218  << endl;
219  }
220 
221  point pt;
222  is.getLine(line);
223  pt[0] = readUnvScalar(line.substr(0, 25));
224  pt[1] = readUnvScalar(line.substr(25, 25));
225  pt[2] = readUnvScalar(line.substr(50, 25));
226 
227  unvPointID.append(pointi);
228  points.append(pt);
229  }
230 
231  points.shrink();
232  unvPointID.shrink();
233 
234  Info<< "Read " << points.size() << " points." << endl;
235 }
236 
237 void addAndExtend
238 (
239  DynamicList<label>& indizes,
240  label celli,
241  label val
242 )
243 {
244  if (indizes.size() < (celli+1))
245  {
246  indizes.setSize(celli+1,-1);
247  }
248  indizes[celli] = val;
249 }
250 
251 // Reads cells section. Read region as well? Not handled yet but should just
252 // be a matter of reading corresponding to boundaryFaces the correct property
253 // and sorting it later on.
254 void readCells
255 (
256  IFstream& is,
257  DynamicList<cellShape>& cellVerts,
258  DynamicList<label>& cellMaterial,
259  DynamicList<label>& boundaryFaceIndices,
260  DynamicList<face>& boundaryFaces,
261  DynamicList<label>& cellCorrespondence,
262  DynamicList<label>& unvPointID // unv index
263 )
264 {
265  Info<< "Starting reading cells at line " << is.lineNumber() << '.' << endl;
266 
267  // Invert point numbering.
268  label maxUnvPoint = 0;
269  forAll(unvPointID, pointi)
270  {
271  maxUnvPoint = max(maxUnvPoint, unvPointID[pointi]);
272  }
273  labelList unvToFoam(invert(maxUnvPoint+1, unvPointID));
274 
275 
277  const cellModel& prism = cellModel::ref(cellModel::PRISM);
279 
280  labelHashSet skippedElements;
281 
282  labelHashSet foundFeType;
283 
284  while (true)
285  {
286  string line;
287  is.getLine(line);
288 
289  if (isSeparator(line))
290  {
291  break;
292  }
293 
294  label celli, feID, physProp, matProp, colour, nNodes;
295 
296  IStringStream lineStr(line);
297  lineStr
298  >> celli >> feID >> physProp >> matProp >> colour >> nNodes;
299 
300  if (foundFeType.insert(feID))
301  {
302  Info<< "First occurrence of element type " << feID
303  << " for cell " << celli << " at line "
304  << is.lineNumber() << endl;
305  }
306 
307  if (feID == 11)
308  {
309  // Rod. Skip.
310  is.getLine(line);
311  is.getLine(line);
312  }
313  else if (feID == 171)
314  {
315  // Rod. Skip.
316  is.getLine(line);
317  }
318  else if (feID == 41 || feID == 91)
319  {
320  // Triangle. Save - used for patching later on.
321  is.getLine(line);
322 
323  face cVerts(3);
324  IStringStream lineStr(line);
325  lineStr
326  >> cVerts[0] >> cVerts[1] >> cVerts[2];
327  boundaryFaces.append(cVerts);
328  boundaryFaceIndices.append(celli);
329  }
330  else if (feID == 44 || feID == 94)
331  {
332  // Quad. Save - used for patching later on.
333  is.getLine(line);
334 
335  face cVerts(4);
336  IStringStream lineStr(line);
337  lineStr
338  >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3];
339  boundaryFaces.append(cVerts);
340  boundaryFaceIndices.append(celli);
341  }
342  else if (feID == 111)
343  {
344  // Tet.
345  is.getLine(line);
346 
347  labelList cVerts(4);
348  IStringStream lineStr(line);
349  lineStr
350  >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3];
351 
352  cellVerts.append(cellShape(tet, cVerts, true));
353  cellMaterial.append(physProp);
354  addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
355 
356  if (cellVerts.last().size() != cVerts.size())
357  {
358  Info<< "Line:" << is.lineNumber()
359  << " element:" << celli
360  << " type:" << feID
361  << " collapsed from " << cVerts << nl
362  << " to:" << cellVerts.last()
363  << endl;
364  }
365  }
366  else if (feID == 112)
367  {
368  // Wedge.
369  is.getLine(line);
370 
371  labelList cVerts(6);
372  IStringStream lineStr(line);
373  lineStr
374  >> cVerts[0] >> cVerts[1] >> cVerts[2]
375  >> cVerts[3] >> cVerts[4] >> cVerts[5];
376 
377  cellVerts.append(cellShape(prism, cVerts, true));
378  cellMaterial.append(physProp);
379  addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
380 
381  if (cellVerts.last().size() != cVerts.size())
382  {
383  Info<< "Line:" << is.lineNumber()
384  << " element:" << celli
385  << " type:" << feID
386  << " collapsed from " << cVerts << nl
387  << " to:" << cellVerts.last()
388  << endl;
389  }
390  }
391  else if (feID == 115)
392  {
393  // Hex.
394  is.getLine(line);
395 
396  labelList cVerts(8);
397  IStringStream lineStr(line);
398  lineStr
399  >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3]
400  >> cVerts[4] >> cVerts[5] >> cVerts[6] >> cVerts[7];
401 
402  cellVerts.append(cellShape(hex, cVerts, true));
403  cellMaterial.append(physProp);
404  addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
405 
406  if (cellVerts.last().size() != cVerts.size())
407  {
408  Info<< "Line:" << is.lineNumber()
409  << " element:" << celli
410  << " type:" << feID
411  << " collapsed from " << cVerts << nl
412  << " to:" << cellVerts.last()
413  << endl;
414  }
415  }
416  else if (feID == 118)
417  {
418  // Parabolic Tet
419  is.getLine(line);
420 
421  labelList cVerts(4);
422  label dummy;
423  {
424  IStringStream lineStr(line);
425  lineStr
426  >> cVerts[0] >> dummy >> cVerts[1] >> dummy >> cVerts[2];
427  }
428  is.getLine(line);
429  {
430  IStringStream lineStr(line);
431  lineStr >> dummy>> cVerts[3];
432  }
433 
434  cellVerts.append(cellShape(tet, cVerts, true));
435  cellMaterial.append(physProp);
436  addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
437 
438  if (cellVerts.last().size() != cVerts.size())
439  {
440  Info<< "Line:" << is.lineNumber()
441  << " element:" << celli
442  << " type:" << feID
443  << " collapsed from " << cVerts << nl
444  << " to:" << cellVerts.last()
445  << endl;
446  }
447  }
448  else
449  {
450  if (skippedElements.insert(feID))
451  {
453  << "Cell type " << feID << " not supported" << endl;
454  }
455 
456  is.getLine(line);
457  }
458  }
459 
460  cellVerts.shrink();
461  cellMaterial.shrink();
462  boundaryFaces.shrink();
463  boundaryFaceIndices.shrink();
464  cellCorrespondence.shrink();
465 
466  Info<< "Read " << cellVerts.size() << " cells"
467  << " and " << boundaryFaces.size() << " boundary faces." << endl;
468 
469  if (!cellVerts.size())
470  {
472  << "There are no cells in the mesh." << endl
473  << " Note: 2D meshes are not supported."<< endl;
474  }
475 }
476 
477 
478 void readSets
479 (
480  IFstream& is,
482  DynamicList<labelList>& patchFaceIndices
483 )
484 {
485  Info<< "Starting reading patches at line " << is.lineNumber() << '.'
486  << endl;
487 
488  while (true)
489  {
490  string line;
491  is.getLine(line);
492 
493  if (isSeparator(line))
494  {
495  break;
496  }
497 
498  IStringStream lineStr(line);
499  label group, constraintSet, restraintSet, loadSet, dofSet,
500  tempSet, contactSet, nFaces;
501  lineStr
502  >> group >> constraintSet >> restraintSet >> loadSet
503  >> dofSet >> tempSet >> contactSet >> nFaces;
504 
505  is.getLine(line);
506  const word groupName = word::validate(line);
507 
508  Info<< "For group " << group
509  << " named " << groupName
510  << " trying to read " << nFaces << " patch face indices."
511  << endl;
512 
513  labelList groupIndices(nFaces);
514  label groupType = -1;
515  nFaces = 0;
516 
517  while (nFaces < groupIndices.size())
518  {
519  is.getLine(line);
520  IStringStream lineStr(line);
521 
522  // Read one (for last face) or two entries from line.
523  label nRead = 2;
524  if (nFaces == groupIndices.size()-1)
525  {
526  nRead = 1;
527  }
528 
529  for (label i = 0; i < nRead; i++)
530  {
531  label tag, nodeLeaf, component;
532 
533  lineStr >> groupType >> tag >> nodeLeaf >> component;
534 
535  groupIndices[nFaces++] = tag;
536  }
537  }
538 
539 
540  // Store
541  if (groupType == 8)
542  {
543  patchNames.append(groupName);
544  patchFaceIndices.append(groupIndices);
545  }
546  else
547  {
549  << "When reading patches expect entity type code 8"
550  << nl << " Skipping group code " << groupType
551  << endl;
552  }
553  }
554 
555  patchNames.shrink();
556  patchFaceIndices.shrink();
557 }
558 
559 
560 
561 // Read dof set (757)
562 void readDOFS
563 (
564  IFstream& is,
566  DynamicList<labelList>& dofVertices
567 )
568 {
569  Info<< "Starting reading constraints at line " << is.lineNumber() << '.'
570  << endl;
571 
572  string line;
573  is.getLine(line);
574  label group;
575  {
576  IStringStream lineStr(line);
577  lineStr >> group;
578  }
579 
580  is.getLine(line);
581  {
582  IStringStream lineStr(line);
583  word pName(lineStr);
584  patchNames.append(pName);
585  }
586 
587  Info<< "For DOF set " << group
588  << " named " << patchNames.last()
589  << " trying to read vertex indices."
590  << endl;
591 
593  while (true)
594  {
595  string line;
596  is.getLine(line);
597 
598  if (isSeparator(line))
599  {
600  break;
601  }
602 
603  IStringStream lineStr(line);
604  label pointi;
605  lineStr >> pointi;
606 
607  vertices.append(pointi);
608  }
609 
610  Info<< "For DOF set " << group
611  << " named " << patchNames.last()
612  << " read " << vertices.size() << " vertex indices." << endl;
613 
614  dofVertices.append(vertices.shrink());
615 
616  patchNames.shrink();
617  dofVertices.shrink();
618 }
619 
620 
621 // Returns -1 or group that all of the vertices of f are in,
622 label findPatch(const List<labelHashSet>& dofGroups, const face& f)
623 {
624  forAll(dofGroups, patchi)
625  {
626  if (dofGroups[patchi].found(f[0]))
627  {
628  bool allInGroup = true;
629 
630  // Check rest of face
631  for (label fp = 1; fp < f.size(); fp++)
632  {
633  if (!dofGroups[patchi].found(f[fp]))
634  {
635  allInGroup = false;
636  break;
637  }
638  }
639 
640  if (allInGroup)
641  {
642  return patchi;
643  }
644  }
645  }
646  return -1;
647 }
648 
649 
650 
651 int main(int argc, char *argv[])
652 {
654  (
655  "Convert I-Deas unv format to OpenFOAM"
656  );
658  argList::addArgument(".unv file");
660  (
661  "dump",
662  "Dump boundary faces as boundaryFaces.obj (for debugging)"
663  );
664 
665  #include "setRootCase.H"
666  #include "createTime.H"
667 
668  const fileName ideasName = args[1];
669  IFstream inFile(ideasName);
670 
671  if (!inFile.good())
672  {
674  << "Cannot open file " << ideasName
675  << exit(FatalError);
676  }
677 
678 
679  // Switch on additional debug info
680  const bool verbose = false; //true;
681 
682  // Unit scale factors
683  scalar lengthScale = 1;
684  scalar forceScale = 1;
685  scalar tempScale = 1;
686  scalar tempOffset = 0;
687 
688  // Points
690  // Original unv point label
691  DynamicList<label> unvPointID;
692 
693  // Cells
694  DynamicList<cellShape> cellVerts;
695  DynamicList<label> cellMat;
696  DynamicList<label> cellCorrespondence;
697 
698  // Boundary faces
699  DynamicList<label> boundaryFaceIndices;
700  DynamicList<face> boundaryFaces;
701 
702  // Patch names and patchFace indices.
704  DynamicList<labelList> patchFaceIndices;
705  DynamicList<labelList> dofVertIndices;
706 
707 
708  while (inFile.good())
709  {
710  label tag = readTag(inFile);
711 
712  if (tag == -1)
713  {
714  break;
715  }
716 
717  Info<< "Processing tag:" << tag << endl;
718 
719  switch (tag)
720  {
721  case 151:
722  readHeader(inFile);
723  break;
724 
725  case 164:
726  readUnits
727  (
728  inFile,
729  lengthScale,
730  forceScale,
731  tempScale,
732  tempOffset
733  );
734  break;
735 
736  case 2411:
737  readPoints(inFile, points, unvPointID);
738  break;
739 
740  case 2412:
741  readCells
742  (
743  inFile,
744  cellVerts,
745  cellMat,
746  boundaryFaceIndices,
747  boundaryFaces,
748  cellCorrespondence,
749  unvPointID
750  );
751  break;
752 
753  case 2452:
754  case 2467:
755  readSets
756  (
757  inFile,
758  patchNames,
759  patchFaceIndices
760  );
761  break;
762 
763  case 757:
764  readDOFS
765  (
766  inFile,
767  patchNames,
768  dofVertIndices
769  );
770  break;
771 
772  default:
773  Info<< "Skipping tag " << tag << " on line "
774  << inFile.lineNumber() << endl;
775  skipSection(inFile);
776  break;
777  }
778  Info<< endl;
779  }
780 
781 
782  // Invert point numbering.
783  label maxUnvPoint = 0;
784  forAll(unvPointID, pointi)
785  {
786  maxUnvPoint = max(maxUnvPoint, unvPointID[pointi]);
787  }
788  labelList unvToFoam(invert(maxUnvPoint+1, unvPointID));
789 
790 
791  // Renumber vertex numbers on cells
792 
793  forAll(cellVerts, celli)
794  {
795  labelList foamVerts
796  (
797  renumber
798  (
799  unvToFoam,
800  static_cast<labelList&>(cellVerts[celli])
801  )
802  );
803 
804  if (foamVerts.found(-1))
805  {
807  << "Cell " << celli
808  << " unv vertices " << cellVerts[celli]
809  << " has some undefined vertices " << foamVerts
810  << abort(FatalError);
811  }
812 
813  // Bit nasty: replace vertex list.
814  cellVerts[celli].transfer(foamVerts);
815  }
816 
817  // Renumber vertex numbers on boundaryFaces
818 
819  forAll(boundaryFaces, bFacei)
820  {
821  labelList foamVerts(renumber(unvToFoam, boundaryFaces[bFacei]));
822 
823  if (foamVerts.found(-1))
824  {
826  << "Boundary face " << bFacei
827  << " unv vertices " << boundaryFaces[bFacei]
828  << " has some undefined vertices " << foamVerts
829  << abort(FatalError);
830  }
831 
832  // Bit nasty: replace vertex list.
833  boundaryFaces[bFacei].transfer(foamVerts);
834  }
835 
836 
837 
838  // Patchify = create patchFaceVerts for use in cellShape construction
839  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
840 
841  // Works in one of two modes. Either has read boundaryFaces which
842  // just need to be sorted according to patch. Or has read point constraint
843  // sets (dofVertIndices).
844 
845  List<faceList> patchFaceVerts;
846 
847  labelList own(boundaryFaces.size(), -1);
848  labelList nei(boundaryFaces.size(), -1);
849  Map<label> faceToCell[2];
850 
851  {
852  HashTable<label, face, face::Hash<>> faceToFaceID(boundaryFaces.size());
853  forAll(boundaryFaces, facei)
854  {
855  SortableList<label> sortedVerts(boundaryFaces[facei]);
856  faceToFaceID.insert(face(sortedVerts), facei);
857  }
858 
859  forAll(cellVerts, celli)
860  {
861  faceList faces = cellVerts[celli].faces();
862  forAll(faces, i)
863  {
864  SortableList<label> sortedVerts(faces[i]);
865  const auto fnd = faceToFaceID.find(face(sortedVerts));
866 
867  if (fnd.found())
868  {
869  label facei = *fnd;
870  int stat = face::compare(faces[i], boundaryFaces[facei]);
871 
872  if (stat == 1)
873  {
874  // Same orientation. Cell is owner.
875  own[facei] = celli;
876  }
877  else if (stat == -1)
878  {
879  // Opposite orientation. Cell is neighbour.
880  nei[facei] = celli;
881  }
882  }
883  }
884  }
885 
886  label nReverse = 0;
887  forAll(own, facei)
888  {
889  if (own[facei] == -1 && nei[facei] != -1)
890  {
891  // Boundary face with incorrect orientation
892  boundaryFaces[facei] = boundaryFaces[facei].reverseFace();
893  Swap(own[facei], nei[facei]);
894  nReverse++;
895  }
896  }
897  if (nReverse > 0)
898  {
899  Info << "Found " << nReverse << " reversed boundary faces out of "
900  << boundaryFaces.size() << endl;
901  }
902 
903 
904  label cnt = 0;
905  forAll(own, facei)
906  {
907  if (own[facei] != -1 && nei[facei] != -1)
908  {
909  faceToCell[1].insert(facei, own[facei]);
910  faceToCell[0].insert(facei, nei[facei]);
911  cnt++;
912  }
913  }
914 
915  if (cnt > 0)
916  {
917  Info << "Of " << boundaryFaces.size() << " so-called"
918  << " boundary faces " << cnt << " belong to two cells "
919  << "and are therefore internal" << endl;
920  }
921  }
922 
923  HashTable<labelList> cellZones;
924  HashTable<labelList> faceZones;
925  List<bool> isAPatch(patchNames.size(),true);
926 
927  if (dofVertIndices.size())
928  {
929  // Use the vertex constraints to patch. Is of course bit dodgy since
930  // face goes on patch if all its vertices are on a constraint.
931  // Note: very inefficient since goes through all faces (including
932  // internal ones) twice. Should do a construct without patches
933  // and then repatchify.
934 
935  Info<< "Using " << dofVertIndices.size()
936  << " DOF sets to detect boundary faces."<< endl;
937 
938  // Renumber vertex numbers on constraints
939  forAll(dofVertIndices, patchi)
940  {
941  inplaceRenumber(unvToFoam, dofVertIndices[patchi]);
942  }
943 
944 
945  // Build labelHashSet of points per dofGroup/patch
946  List<labelHashSet> dofGroups(dofVertIndices.size());
947 
948  forAll(dofVertIndices, patchi)
949  {
950  const labelList& foamVerts = dofVertIndices[patchi];
951  dofGroups[patchi].insert(foamVerts);
952  }
953 
954  List<DynamicList<face>> dynPatchFaces(dofVertIndices.size());
955 
956  forAll(cellVerts, celli)
957  {
958  const cellShape& shape = cellVerts[celli];
959 
960  const faceList shapeFaces(shape.faces());
961 
962  forAll(shapeFaces, i)
963  {
964  label patchi = findPatch(dofGroups, shapeFaces[i]);
965 
966  if (patchi != -1)
967  {
968  dynPatchFaces[patchi].append(shapeFaces[i]);
969  }
970  }
971  }
972 
973  // Transfer
974  patchFaceVerts.setSize(dynPatchFaces.size());
975 
976  forAll(dynPatchFaces, patchi)
977  {
978  patchFaceVerts[patchi].transfer(dynPatchFaces[patchi]);
979  }
980  }
981  else
982  {
983  // Use the boundary faces.
984 
985  // Construct the patch faces by sorting the boundaryFaces according to
986  // patch.
987  patchFaceVerts.setSize(patchFaceIndices.size());
988 
989  Info<< "Sorting boundary faces according to group (patch)" << endl;
990 
991  // make sure that no face is used twice on the boundary
992  // (possible for boundary-only faceZones)
993  labelHashSet alreadyOnBoundary;
994 
995  // Construct map from boundaryFaceIndices
996  Map<label> boundaryFaceToIndex(boundaryFaceIndices.size());
997 
998  forAll(boundaryFaceIndices, i)
999  {
1000  boundaryFaceToIndex.insert(boundaryFaceIndices[i], i);
1001  }
1002 
1003  forAll(patchFaceVerts, patchi)
1004  {
1005  Info << patchi << ": " << patchNames[patchi] << " is " << flush;
1006 
1007  faceList& patchFaces = patchFaceVerts[patchi];
1008  const labelList& faceIndices = patchFaceIndices[patchi];
1009 
1010  patchFaces.setSize(faceIndices.size());
1011 
1012  bool duplicateFaces = false;
1013 
1014  label cnt = 0;
1015  forAll(patchFaces, i)
1016  {
1017  if (boundaryFaceToIndex.found(faceIndices[i]))
1018  {
1019  label bFacei = boundaryFaceToIndex[faceIndices[i]];
1020 
1021  if (own[bFacei] != -1 && nei[bFacei] == -1)
1022  {
1023  patchFaces[cnt] = boundaryFaces[bFacei];
1024  cnt++;
1025  if (alreadyOnBoundary.found(bFacei))
1026  {
1027  duplicateFaces = true;
1028  }
1029  }
1030  }
1031  }
1032 
1033  if (cnt != patchFaces.size() || duplicateFaces)
1034  {
1035  isAPatch[patchi] = false;
1036 
1037  if (verbose)
1038  {
1039  if (cnt != patchFaces.size())
1040  {
1042  << "For patch " << patchi << " there were "
1043  << patchFaces.size()-cnt
1044  << " faces not used because they seem"
1045  << " to be internal. "
1046  << "This seems to be a face or a cell-zone"
1047  << endl;
1048  }
1049  else
1050  {
1052  << "Patch "
1053  << patchi << " has faces that are already "
1054  << " in use on other boundary-patches,"
1055  << " Assuming faceZoneset." << endl;
1056  }
1057  }
1058 
1059  patchFaces.setSize(0); // Assume that this is no patch at all
1060 
1061  if (cellCorrespondence[faceIndices[0]] >= 0)
1062  {
1063  Info << "cellZone" << endl;
1064  labelList theCells(faceIndices.size());
1065  forAll(faceIndices, i)
1066  {
1067  if (cellCorrespondence[faceIndices[0]] < 0)
1068  {
1070  << "The face index " << faceIndices[i]
1071  << " was not found amongst the cells."
1072  << " This kills the theory that "
1073  << patchNames[patchi] << " is a cell zone"
1074  << endl
1075  << abort(FatalError);
1076  }
1077  theCells[i] = cellCorrespondence[faceIndices[i]];
1078  }
1079  cellZones.insert(patchNames[patchi], theCells);
1080  }
1081  else
1082  {
1083  Info << "faceZone" << endl;
1084  labelList theFaces(faceIndices.size());
1085  forAll(faceIndices, i)
1086  {
1087  theFaces[i] = boundaryFaceToIndex[faceIndices[i]];
1088  }
1089  faceZones.insert(patchNames[patchi],theFaces);
1090  }
1091  }
1092  else
1093  {
1094  Info << "patch" << endl;
1095 
1096  forAll(patchFaces, i)
1097  {
1098  label bFacei = boundaryFaceToIndex[faceIndices[i]];
1099  alreadyOnBoundary.insert(bFacei);
1100  }
1101  }
1102  }
1103  }
1104 
1105  pointField polyPoints;
1106  polyPoints.transfer(points);
1107 
1108  // Length scaling factor
1109  polyPoints /= lengthScale;
1110 
1111 
1112  // For debugging: dump boundary faces as OBJ surface mesh
1113  if (args.found("dump"))
1114  {
1115  Info<< "Writing boundary faces to OBJ file boundaryFaces.obj"
1116  << nl << endl;
1117 
1118  // Create globally numbered surface
1119  meshedSurface rawSurface(polyPoints, boundaryFaces);
1120 
1121  // Write locally numbered surface
1123  (
1124  rawSurface.localPoints(),
1125  rawSurface.localFaces()
1126  ).write(runTime.path()/"boundaryFaces.obj");
1127  }
1128 
1129 
1130  Info<< "\nConstructing mesh with non-default patches of size:" << nl;
1131  DynamicList<word> usedPatchNames;
1132  DynamicList<faceList> usedPatchFaceVerts;
1133 
1134  forAll(patchNames, patchi)
1135  {
1136  if (isAPatch[patchi])
1137  {
1138  Info<< " " << patchNames[patchi] << '\t'
1139  << patchFaceVerts[patchi].size() << nl;
1140  usedPatchNames.append(patchNames[patchi]);
1141  usedPatchFaceVerts.append(patchFaceVerts[patchi]);
1142  }
1143  }
1144  usedPatchNames.shrink();
1145  usedPatchFaceVerts.shrink();
1146 
1147  Info<< endl;
1148 
1149  // Construct mesh
1150  polyMesh mesh
1151  (
1152  IOobject
1153  (
1155  runTime.constant(),
1156  runTime
1157  ),
1158  std::move(polyPoints),
1159  cellVerts,
1160  usedPatchFaceVerts, // boundaryFaces,
1161  usedPatchNames, // boundaryPatchNames,
1162  wordList(patchNames.size(), polyPatch::typeName), // boundaryPatchTypes,
1163  "defaultFaces", // defaultFacesName
1164  polyPatch::typeName, // defaultFacesType,
1165  wordList() // boundaryPatchPhysicalTypes
1166  );
1167 
1168  // Remove files now, to ensure all mesh files written are consistent.
1169  mesh.removeFiles();
1170 
1171  if (faceZones.size() || cellZones.size())
1172  {
1173  Info << "Adding cell and face zones" << endl;
1174 
1176  List<faceZone*> fZones(faceZones.size());
1177  List<cellZone*> cZones(cellZones.size());
1178 
1179  if (cellZones.size())
1180  {
1181  forAll(cellZones.toc(), cnt)
1182  {
1183  word name = cellZones.toc()[cnt];
1184  Info<< " Cell Zone " << name << " " << tab
1185  << cellZones[name].size() << endl;
1186 
1187  cZones[cnt] = new cellZone
1188  (
1189  name,
1190  cellZones[name],
1191  cnt,
1192  mesh.cellZones()
1193  );
1194  }
1195  }
1196  if (faceZones.size())
1197  {
1198  const labelList& own = mesh.faceOwner();
1199  const labelList& nei = mesh.faceNeighbour();
1200  const pointField& centers = mesh.faceCentres();
1201  const pointField& points = mesh.points();
1202 
1203  forAll(faceZones.toc(), cnt)
1204  {
1205  word name = faceZones.toc()[cnt];
1206  const labelList& oldIndizes = faceZones[name];
1207  labelList indizes(oldIndizes.size());
1208 
1209  Info<< " Face Zone " << name << " " << tab
1210  << oldIndizes.size() << endl;
1211 
1212  forAll(indizes, i)
1213  {
1214  const label old = oldIndizes[i];
1215  label noveau = -1;
1216  label c1 = -1, c2 = -1;
1217  if (faceToCell[0].found(old))
1218  {
1219  c1 = faceToCell[0][old];
1220  }
1221  if (faceToCell[1].found(old))
1222  {
1223  c2 = faceToCell[1][old];
1224  }
1225  if (c1 < c2)
1226  {
1227  label tmp = c1;
1228  c1 = c2;
1229  c2 = tmp;
1230  }
1231  if (c2 == -1)
1232  {
1233  // Boundary face is part of the faceZone
1234  forAll(own, j)
1235  {
1236  if (own[j] == c1)
1237  {
1238  const face& f = boundaryFaces[old];
1239  if (mag(centers[j]- f.centre(points)) < SMALL)
1240  {
1241  noveau = j;
1242  break;
1243  }
1244  }
1245  }
1246  }
1247  else
1248  {
1249  forAll(nei, j)
1250  {
1251  if
1252  (
1253  (c1 == own[j] && c2 == nei[j])
1254  || (c2 == own[j] && c1 == nei[j])
1255  )
1256  {
1257  noveau = j;
1258  break;
1259  }
1260  }
1261  }
1262  assert(noveau > -1);
1263  indizes[i] = noveau;
1264  }
1265  fZones[cnt] = new faceZone
1266  (
1267  faceZones.toc()[cnt],
1268  indizes,
1269  false, // none are flipped
1270  cnt,
1271  mesh.faceZones()
1272  );
1273  }
1274  }
1275  mesh.addZones(pZones, fZones, cZones);
1276 
1277  Info << endl;
1278  }
1279 
1280  // Set the precision of the points data to 10
1282 
1283  mesh.write();
1284 
1285  Info<< "End\n" << endl;
1286 
1287  return 0;
1288 }
1289 
1290 
1291 // ************************************************************************* //
Foam::HashTable::size
label size() const noexcept
The number of elements in table.
Definition: HashTableI.H:52
runTime
engineTime & runTime
Definition: createEngineTime.H:13
Foam::polyMesh::points
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1038
Foam::IOobject
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:104
Foam::component
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
Definition: FieldFieldFunctions.C:44
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::ISstream::getLine
ISstream & getLine(std::string &str, char delim='\n')
Raw, low-level getline (until delimiter) into a string.
Definition: ISstreamI.H:76
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::fvMesh::write
virtual bool write(const bool valid=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:895
s
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Definition: gmvOutputSpray.H:25
Foam::constant::atomic::group
constexpr const char *const group
Group name for atomic constants.
Definition: atomicConstants.H:52
Foam::HashTable::toc
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition: HashTable.C:121
Foam::polyMesh::defaultRegion
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:312
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:59
Foam::IFstream
Input from file stream, using an ISstream.
Definition: IFstream.H:85
Foam::DynamicList< point >
Foam::cellModel::HEX
hex
Definition: cellModel.H:81
Foam::argList::addNote
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:413
Foam::HashTable::insert
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:168
Foam::polyMesh::cellZones
const cellZoneMesh & cellZones() const
Return cell zone mesh.
Definition: polyMesh.H:483
Foam::Map< label >
Foam::word::validate
static word validate(const std::string &s, const bool prefix=false)
Construct validated word (no invalid characters).
Definition: word.C:45
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:182
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::cellShape::faces
faceList faces() const
Faces of this cell.
Definition: cellShapeI.H:199
polyMesh.H
Foam::HashSet< label, Hash< label > >
Foam::DynamicList::shrink
DynamicList< T, SizeMin > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:376
Foam::Swap
void Swap(DynamicList< T, SizeMin1 > &a, DynamicList< T, SizeMin2 > &b)
Definition: DynamicListI.H:909
Foam::invert
labelList invert(const label len, const labelUList &map)
Create an inverse one-to-one mapping.
Definition: ListOps.C:36
Foam::cellModel::TET
tet
Definition: cellModel.H:85
Foam::inplaceRenumber
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:61
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::cellZone
A subset of mesh cells.
Definition: cellZone.H:62
Foam::polyMesh::faceZones
const faceZoneMesh & faceZones() const
Return face zone mesh.
Definition: polyMesh.H:477
Foam::face::compare
static int compare(const face &a, const face &b)
Compare faces.
Definition: face.C:300
pZones
IOporosityModelList pZones(mesh)
Foam::wordList
List< word > wordList
A List of words.
Definition: fileName.H:59
Foam::argList::addArgument
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:302
Foam::flush
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:342
Foam::constant::physicoChemical::c1
const dimensionedScalar c1
First radiation constant: default SI units: [W/m2].
Foam::Field< vector >
cellModel.H
Foam::faceZone
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:65
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::polyMesh::removeFiles
void removeFiles(const fileName &instanceDir) const
Remove all files from mesh instance.
Definition: polyMesh.C:1264
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:472
argList.H
Foam::polyMesh::faceOwner
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1076
faceSet.H
Foam::List::transfer
void transfer(List< T > &list)
Definition: List.C:459
Foam::cellModel::PRISM
prism
Definition: cellModel.H:83
patchNames
wordList patchNames(nPatches)
Foam::cellModel::ref
static const cellModel & ref(const modelType model)
Look up reference to cellModel by enumeration. Fatal on failure.
Definition: cellModels.C:157
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
IFstream.H
Foam::FatalError
error FatalError
Foam::vertices
pointField vertices(const blockVertexList &bvl)
Definition: blockVertexList.H:49
Foam::SortableList
A list that is sorted upon construction or when explicitly requested with the sort() method.
Definition: List.H:63
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::cellShape
An analytical geometric cellShape.
Definition: cellShape.H:71
Foam::IStringStream
Input from string buffer, using a ISstream.
Definition: StringStream.H:111
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
Foam::constant::physicoChemical::c2
const dimensionedScalar c2
Second radiation constant: default SI units: [m.K].
Foam::DynamicList::setSize
void setSize(const label nElem)
Alter addressable list size.
Definition: DynamicListI.H:282
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::hex
IOstream & hex(IOstream &io)
Definition: IOstream.H:437
Foam::HashTable
A HashTable similar to std::unordered_map.
Definition: HashTable.H:105
found
bool found
Definition: TABSMDCalcMethod2.H:32
Foam::argList::addBoolOption
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:325
Time.H
setRootCase.H
Foam::renumber
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:37
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:372
Foam::tab
constexpr char tab
Definition: Ostream.H:384
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::Time::path
fileName path() const
Return path.
Definition: Time.H:358
Foam::IOstream::defaultPrecision
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:333
Foam::meshedSurface
MeshedSurface< face > meshedSurface
Definition: MeshedSurfacesFwd.H:41
f
labelList f(nPoints)
Foam::Vector< scalar >
Foam::readLabel
label readLabel(const char *buf)
Parse entire buffer as a label, skipping leading/trailing whitespace.
Definition: label.H:66
Foam::List< label >
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::primitiveMesh::faceCentres
const vectorField & faceCentres() const
Definition: primitiveMeshFaceCentresAndAreas.C:144
MeshedSurfaces.H
Foam::DynamicList::transfer
void transfer(List< T > &lst)
Transfer contents of the argument List into this.
Definition: DynamicListI.H:426
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:181
createTime.H
Foam::line
A line primitive.
Definition: line.H:59
Foam::vtk::write
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
Definition: foamVtkOutputTemplates.C:35
Foam::IOstream::lineNumber
label lineNumber() const
Const access to the current stream line number.
Definition: IOstream.H:309
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
DynamicList.H
Foam::cellModel
Maps a geometry to a set of cell primitives.
Definition: cellModel.H:72
cellSet.H
IOWarningInFunction
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
Definition: messageStream.H:310
Foam::argList::noParallel
static void noParallel()
Remove the parallel options.
Definition: argList.C:491
Foam::IOstream::good
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:224
Foam::HashTable::found
bool found(const Key &key) const
Return true if hashed entry is found in table.
Definition: HashTableI.H:100
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::TimePaths::constant
const word & constant() const
Return constant name.
Definition: TimePathsI.H:88
Foam::MeshedSurface< face >
args
Foam::argList args(argc, argv)
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:298
Foam::polyMesh::addZones
void addZones(const List< pointZone * > &pz, const List< faceZone * > &fz, const List< cellZone * > &cz)
Add mesh zones.
Definition: polyMesh.C:968
Foam::polyMesh::faceNeighbour
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1082
Foam::argList::found
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:157