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