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-2019 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>& indizes,
251  label celli,
252  label val
253 )
254 {
255  if (indizes.size() < (celli+1))
256  {
257  indizes.setSize(celli+1,-1);
258  }
259  indizes[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  );
670 
671  #include "setRootCase.H"
672  #include "createTime.H"
673 
674  const fileName ideasName = args[1];
675  IFstream inFile(ideasName);
676 
677  if (!inFile.good())
678  {
680  << "Cannot open file " << ideasName
681  << exit(FatalError);
682  }
683 
684 
685  // Switch on additional debug info
686  const bool verbose = false; // true;
687 
688  // Unit scale factors
689  scalar lengthScale = 1;
690  scalar forceScale = 1;
691  scalar tempScale = 1;
692  scalar tempOffset = 0;
693 
694  // Points
696  // Original unv point label
697  DynamicList<label> unvPointID;
698 
699  // Cells
700  DynamicList<cellShape> cellVerts;
701  DynamicList<label> cellMat;
702  DynamicList<label> cellCorrespondence;
703 
704  // Boundary faces
705  DynamicList<label> boundaryFaceIndices;
706  DynamicList<face> boundaryFaces;
707 
708  // Patch names and patchFace indices.
710  DynamicList<labelList> patchFaceIndices;
711  DynamicList<labelList> dofVertIndices;
712 
713 
714  while (inFile.good())
715  {
716  label tag = readTag(inFile);
717 
718  if (tag == -1)
719  {
720  break;
721  }
722 
723  Info<< "Processing tag:" << tag << endl;
724 
725  switch (tag)
726  {
727  case 151:
728  readHeader(inFile);
729  break;
730 
731  case 164:
732  readUnits
733  (
734  inFile,
735  lengthScale,
736  forceScale,
737  tempScale,
738  tempOffset
739  );
740  break;
741 
742  case 2411:
743  readPoints(inFile, points, unvPointID);
744  break;
745 
746  case 2412:
747  readCells
748  (
749  inFile,
750  cellVerts,
751  cellMat,
752  boundaryFaceIndices,
753  boundaryFaces,
754  cellCorrespondence,
755  unvPointID
756  );
757  break;
758 
759  case 2452:
760  case 2467:
761  readSets
762  (
763  inFile,
764  patchNames,
765  patchFaceIndices
766  );
767  break;
768 
769  case 757:
770  readDOFS
771  (
772  inFile,
773  patchNames,
774  dofVertIndices
775  );
776  break;
777 
778  default:
779  Info<< "Skipping tag " << tag << " on line "
780  << inFile.lineNumber() << endl;
781  skipSection(inFile);
782  break;
783  }
784  Info<< endl;
785  }
786 
787 
788  // Invert point numbering.
789  label maxUnvPoint = 0;
790  forAll(unvPointID, pointi)
791  {
792  maxUnvPoint = max(maxUnvPoint, unvPointID[pointi]);
793  }
794  labelList unvToFoam(invert(maxUnvPoint+1, unvPointID));
795 
796 
797  // Renumber vertex numbers on cells
798 
799  forAll(cellVerts, celli)
800  {
801  labelList foamVerts
802  (
803  renumber
804  (
805  unvToFoam,
806  static_cast<labelList&>(cellVerts[celli])
807  )
808  );
809 
810  if (findIndex(foamVerts, -1) != -1)
811  {
813  << "Cell " << celli
814  << " unv vertices " << cellVerts[celli]
815  << " has some undefined vertices " << foamVerts
816  << abort(FatalError);
817  }
818 
819  // Bit nasty: replace vertex list.
820  cellVerts[celli].transfer(foamVerts);
821  }
822 
823  // Renumber vertex numbers on boundaryFaces
824 
825  forAll(boundaryFaces, bFacei)
826  {
827  labelList foamVerts(renumber(unvToFoam, boundaryFaces[bFacei]));
828 
829  if (findIndex(foamVerts, -1) != -1)
830  {
832  << "Boundary face " << bFacei
833  << " unv vertices " << boundaryFaces[bFacei]
834  << " has some undefined vertices " << foamVerts
835  << abort(FatalError);
836  }
837 
838  // Bit nasty: replace vertex list.
839  boundaryFaces[bFacei].transfer(foamVerts);
840  }
841 
842 
843 
844  // Patchify = create patchFaceVerts for use in cellShape construction
845  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
846 
847  // Works in one of two modes. Either has read boundaryFaces which
848  // just need to be sorted according to patch. Or has read point constraint
849  // sets (dofVertIndices).
850 
851  List<faceList> patchFaceVerts;
852 
853  labelList own(boundaryFaces.size(), -1);
854  labelList nei(boundaryFaces.size(), -1);
855  HashTable<label, label> faceToCell[2];
856 
857  {
858  HashTable<label, face, Hash<face>> faceToFaceID(boundaryFaces.size());
859  forAll(boundaryFaces, facei)
860  {
861  SortableList<label> sortedVerts(boundaryFaces[facei]);
862  faceToFaceID.insert(face(sortedVerts), facei);
863  }
864 
865  forAll(cellVerts, celli)
866  {
867  faceList faces = cellVerts[celli].faces();
868  forAll(faces, i)
869  {
870  SortableList<label> sortedVerts(faces[i]);
871  HashTable<label, face, Hash<face>>::const_iterator fnd =
872  faceToFaceID.find(face(sortedVerts));
873 
874  if (fnd != faceToFaceID.end())
875  {
876  label facei = fnd();
877  int stat = face::compare(faces[i], boundaryFaces[facei]);
878 
879  if (stat == 1)
880  {
881  // Same orientation. Cell is owner.
882  own[facei] = celli;
883  }
884  else if (stat == -1)
885  {
886  // Opposite orientation. Cell is neighbour.
887  nei[facei] = celli;
888  }
889  }
890  }
891  }
892 
893  label nReverse = 0;
894  forAll(own, facei)
895  {
896  if (own[facei] == -1 && nei[facei] != -1)
897  {
898  // Boundary face with incorrect orientation
899  boundaryFaces[facei] = boundaryFaces[facei].reverseFace();
900  Swap(own[facei], nei[facei]);
901  nReverse++;
902  }
903  }
904  if (nReverse > 0)
905  {
906  Info << "Found " << nReverse << " reversed boundary faces out of "
907  << boundaryFaces.size() << endl;
908  }
909 
910 
911  label cnt = 0;
912  forAll(own, facei)
913  {
914  if (own[facei] != -1 && nei[facei] != -1)
915  {
916  faceToCell[1].insert(facei, own[facei]);
917  faceToCell[0].insert(facei, nei[facei]);
918  cnt++;
919  }
920  }
921 
922  if (cnt > 0)
923  {
924  Info << "Of " << boundaryFaces.size() << " so-called"
925  << " boundary faces " << cnt << " belong to two cells "
926  << "and are therefore internal" << endl;
927  }
928  }
929 
930  HashTable<labelList,word> cellZones;
931  HashTable<labelList,word> faceZones;
932  List<bool> isAPatch(patchNames.size(),true);
933 
934  if (dofVertIndices.size())
935  {
936  // Use the vertex constraints to patch. Is of course bit dodgy since
937  // face goes on patch if all its vertices are on a constraint.
938  // Note: very inefficient since goes through all faces (including
939  // internal ones) twice. Should do a construct without patches
940  // and then repatchify.
941 
942  Info<< "Using " << dofVertIndices.size()
943  << " DOF sets to detect boundary faces."<< endl;
944 
945  // Renumber vertex numbers on constraints
946  forAll(dofVertIndices, patchi)
947  {
948  inplaceRenumber(unvToFoam, dofVertIndices[patchi]);
949  }
950 
951 
952  // Build labelHashSet of points per dofGroup/patch
953  List<labelHashSet> dofGroups(dofVertIndices.size());
954 
955  forAll(dofVertIndices, patchi)
956  {
957  const labelList& foamVerts = dofVertIndices[patchi];
958 
959  forAll(foamVerts, i)
960  {
961  dofGroups[patchi].insert(foamVerts[i]);
962  }
963  }
964 
965  List<DynamicList<face>> dynPatchFaces(dofVertIndices.size());
966 
967  forAll(cellVerts, celli)
968  {
969  const cellShape& shape = cellVerts[celli];
970 
971  const faceList shapeFaces(shape.faces());
972 
973  forAll(shapeFaces, i)
974  {
975  label patchi = findPatch(dofGroups, shapeFaces[i]);
976 
977  if (patchi != -1)
978  {
979  dynPatchFaces[patchi].append(shapeFaces[i]);
980  }
981  }
982  }
983 
984  // Transfer
985  patchFaceVerts.setSize(dynPatchFaces.size());
986 
987  forAll(dynPatchFaces, patchi)
988  {
989  patchFaceVerts[patchi].transfer(dynPatchFaces[patchi]);
990  }
991  }
992  else
993  {
994  // Use the boundary faces.
995 
996  // Construct the patch faces by sorting the boundaryFaces according to
997  // patch.
998  patchFaceVerts.setSize(patchFaceIndices.size());
999 
1000  Info<< "Sorting boundary faces according to group (patch)" << endl;
1001 
1002  // make sure that no face is used twice on the boundary
1003  // (possible for boundary-only faceZones)
1004  labelHashSet alreadyOnBoundary;
1005 
1006  // Construct map from boundaryFaceIndices
1007  Map<label> boundaryFaceToIndex(boundaryFaceIndices.size());
1008 
1009  forAll(boundaryFaceIndices, i)
1010  {
1011  boundaryFaceToIndex.insert(boundaryFaceIndices[i], i);
1012  }
1013 
1014  forAll(patchFaceVerts, patchi)
1015  {
1016  Info << patchi << ": " << patchNames[patchi] << " is " << flush;
1017 
1018  faceList& patchFaces = patchFaceVerts[patchi];
1019  const labelList& faceIndices = patchFaceIndices[patchi];
1020 
1021  patchFaces.setSize(faceIndices.size());
1022 
1023  bool duplicateFaces = false;
1024 
1025  label cnt = 0;
1026  forAll(patchFaces, i)
1027  {
1028  if (boundaryFaceToIndex.found(faceIndices[i]))
1029  {
1030  label bFacei = boundaryFaceToIndex[faceIndices[i]];
1031 
1032  if (own[bFacei] != -1 && nei[bFacei] == -1)
1033  {
1034  patchFaces[cnt] = boundaryFaces[bFacei];
1035  cnt++;
1036  if (alreadyOnBoundary.found(bFacei))
1037  {
1038  duplicateFaces = true;
1039  }
1040  }
1041  }
1042  }
1043 
1044  if (cnt != patchFaces.size() || duplicateFaces)
1045  {
1046  isAPatch[patchi] = false;
1047 
1048  if (verbose)
1049  {
1050  if (cnt != patchFaces.size())
1051  {
1053  << "For patch " << patchi << " there were "
1054  << patchFaces.size()-cnt
1055  << " faces not used because they seem"
1056  << " to be internal. "
1057  << "This seems to be a face or a cell-zone"
1058  << endl;
1059  }
1060  else
1061  {
1063  << "Patch "
1064  << patchi << " has faces that are already "
1065  << " in use on other boundary-patches,"
1066  << " Assuming faceZoneset." << endl;
1067  }
1068  }
1069 
1070  patchFaces.setSize(0); // Assume that this is no patch at all
1071 
1072  if (cellCorrespondence[faceIndices[0]] >= 0)
1073  {
1074  Info << "cellZone" << endl;
1075  labelList theCells(faceIndices.size());
1076  forAll(faceIndices, i)
1077  {
1078  if (cellCorrespondence[faceIndices[0]] < 0)
1079  {
1081  << "The face index " << faceIndices[i]
1082  << " was not found amongst the cells."
1083  << " This kills the theory that "
1084  << patchNames[patchi] << " is a cell zone"
1085  << endl
1086  << abort(FatalError);
1087  }
1088  theCells[i] = cellCorrespondence[faceIndices[i]];
1089  }
1090  cellZones.insert(patchNames[patchi], theCells);
1091  }
1092  else
1093  {
1094  Info << "faceZone" << endl;
1095  labelList theFaces(faceIndices.size());
1096  forAll(faceIndices, i)
1097  {
1098  theFaces[i] = boundaryFaceToIndex[faceIndices[i]];
1099  }
1100  faceZones.insert(patchNames[patchi],theFaces);
1101  }
1102  }
1103  else
1104  {
1105  Info << "patch" << endl;
1106 
1107  forAll(patchFaces, i)
1108  {
1109  label bFacei = boundaryFaceToIndex[faceIndices[i]];
1110  alreadyOnBoundary.insert(bFacei);
1111  }
1112  }
1113  }
1114  }
1115 
1116  pointField polyPoints;
1117  polyPoints.transfer(points);
1118 
1119  // Length scaling factor
1120  polyPoints /= lengthScale;
1121 
1122 
1123  // For debugging: dump boundary faces as OBJ surface mesh
1124  if (args.optionFound("dump"))
1125  {
1126  Info<< "Writing boundary faces to OBJ file boundaryFaces.obj"
1127  << nl << endl;
1128 
1129  // Create globally numbered surface
1130  meshedSurface rawSurface
1131  (
1132  clone(polyPoints),
1133  clone(boundaryFaces)
1134  );
1135 
1136  // Write locally numbered surface
1138  (
1139  clone(rawSurface.localPoints()),
1140  clone(rawSurface.localFaces())
1141  ).write(runTime.path()/"boundaryFaces.obj");
1142  }
1143 
1144 
1145  Info<< "\nConstructing mesh with non-default patches of size:" << nl;
1146  DynamicList<word> usedPatchNames;
1147  DynamicList<faceList> usedPatchFaceVerts;
1148 
1149  forAll(patchNames, patchi)
1150  {
1151  if (isAPatch[patchi])
1152  {
1153  Info<< " " << patchNames[patchi] << '\t'
1154  << patchFaceVerts[patchi].size() << nl;
1155  usedPatchNames.append(patchNames[patchi]);
1156  usedPatchFaceVerts.append(patchFaceVerts[patchi]);
1157  }
1158  }
1159  usedPatchNames.shrink();
1160  usedPatchFaceVerts.shrink();
1161 
1162  Info<< endl;
1163 
1164 
1165 
1166  // Construct mesh
1167  polyMesh mesh
1168  (
1169  IOobject
1170  (
1172  runTime.constant(),
1173  runTime
1174  ),
1175  move(polyPoints),
1176  cellVerts,
1177  usedPatchFaceVerts, // boundaryFaces,
1178  usedPatchNames, // boundaryPatchNames,
1179  wordList(patchNames.size(), polyPatch::typeName), // boundaryPatchTypes,
1180  "defaultFaces", // defaultFacesName
1181  polyPatch::typeName, // defaultFacesType,
1182  wordList(0) // boundaryPatchPhysicalTypes
1183  );
1184 
1185 
1186  if (faceZones.size() > 0 || cellZones.size() > 0)
1187  {
1188  Info << "Adding cell and face zones" << endl;
1189 
1191  List<faceZone*> fZones(faceZones.size());
1192  List<cellZone*> cZones(cellZones.size());
1193 
1194  if (cellZones.size() > 0)
1195  {
1196  forAll(cellZones.toc(), cnt)
1197  {
1198  word name = cellZones.toc()[cnt];
1199  Info<< " Cell Zone " << name << " " << tab
1200  << cellZones[name].size() << endl;
1201 
1202  cZones[cnt] = new cellZone
1203  (
1204  name,
1205  cellZones[name],
1206  cnt,
1207  mesh.cellZones()
1208  );
1209  }
1210  }
1211  if (faceZones.size() > 0)
1212  {
1213  const labelList& own = mesh.faceOwner();
1214  const labelList& nei = mesh.faceNeighbour();
1215  const pointField& centers = mesh.faceCentres();
1216  const pointField& points = mesh.points();
1217 
1218  forAll(faceZones.toc(), cnt)
1219  {
1220  word name = faceZones.toc()[cnt];
1221  const labelList& oldIndizes = faceZones[name];
1222  labelList indizes(oldIndizes.size());
1223 
1224  Info<< " Face Zone " << name << " " << tab
1225  << oldIndizes.size() << endl;
1226 
1227  forAll(indizes, i)
1228  {
1229  const label old = oldIndizes[i];
1230  label nouveau = -1;
1231  label c1 = -1, c2 = -1;
1232  if (faceToCell[0].found(old))
1233  {
1234  c1 = faceToCell[0][old];
1235  }
1236  if (faceToCell[1].found(old))
1237  {
1238  c2 = faceToCell[1][old];
1239  }
1240  if (c1 < c2)
1241  {
1242  label tmp = c1;
1243  c1 = c2;
1244  c2 = tmp;
1245  }
1246  if (c2 == -1)
1247  {
1248  // Boundary face is part of the faceZone
1249  forAll(own, j)
1250  {
1251  if (own[j] == c1)
1252  {
1253  const face& f = boundaryFaces[old];
1254  if (mag(centers[j]- f.centre(points)) < small)
1255  {
1256  nouveau = j;
1257  break;
1258  }
1259  }
1260  }
1261  }
1262  else
1263  {
1264  forAll(nei, j)
1265  {
1266  if
1267  (
1268  (c1 == own[j] && c2 == nei[j])
1269  || (c2 == own[j] && c1 == nei[j])
1270  )
1271  {
1272  nouveau = j;
1273  break;
1274  }
1275  }
1276  }
1277  assert(nouveau > -1);
1278  indizes[i] = nouveau;
1279  }
1280  fZones[cnt] = new faceZone
1281  (
1282  faceZones.toc()[cnt],
1283  indizes,
1284  boolList(indizes.size(),false),
1285  cnt,
1286  mesh.faceZones()
1287  );
1288  }
1289  }
1290  mesh.addZones(pZones, fZones, cZones);
1291 
1292  Info << endl;
1293  }
1294 
1295  mesh.write();
1296 
1297  Info<< "End\n" << endl;
1298 
1299  return 0;
1300 }
1301 
1302 
1303 // ************************************************************************* //
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
fileName path() const
Return path.
Definition: Time.H:266
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
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.
const faceZoneMesh & faceZones() const
Return face zone mesh.
Definition: polyMesh.H:476
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
static const char tab
Definition: Ostream.H:264
error FatalError
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1175
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:163
const dimensionedScalar c2
Second radiation constant: default SI units: [m K].
engineTime & runTime
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:309
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:108
point centre(const pointField &) const
Centre point of face.
Definition: face.C:488
static void noParallel()
Remove the parallel options.
Definition: argList.C:174
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:438
unsigned operator()(const PrimitiveType &p, unsigned seed) const
Definition: Hash.H:61
virtual bool write(const bool write=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1035
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:108
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1131
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
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
dynamicFvMesh & mesh
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
const cellZoneMesh & cellZones() const
Return cell zone mesh.
Definition: polyMesh.H:482
MeshedSurface< face > meshedSurface
static int compare(const face &, const face &)
Compare faces.
Definition: face.C:298
wordList patchNames(nPatches)
const word & constant() const
Return constant name.
Definition: TimePaths.H:124
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1169
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:68
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:953
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:265
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
label patchi
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:248
#define WarningInFunction
Report a warning using Foam::Warning.
Input from memory buffer stream.
Definition: IStringStream.H:49
Maps a geometry to a set of cell primitives, which enables geometric cell data to be calculated witho...
Definition: cellModel.H:64
const dimensionedScalar c1
First radiation constant: default SI units: [W/m^2].
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:74
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:117
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:64
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:92
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
Namespace for OpenFOAM.
IOporosityModelList pZones(mesh)
ISstream & getLine(string &)
Raw, low-level getline into a string function.
Definition: ISstreamI.H:77