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 | Copyright (C) 2011-2017 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  //<< " at line " << is.lineNumber()
230  //<< abort(FatalError);
231  << endl;
232  }
233 
234  point pt;
235  is.getLine(line);
236  pt[0] = readUnvScalar(line.substr(0, 25));
237  pt[1] = readUnvScalar(line.substr(25, 25));
238  pt[2] = readUnvScalar(line.substr(50, 25));
239 
240  unvPointID.append(pointi);
241  points.append(pt);
242  }
243 
244  points.shrink();
245  unvPointID.shrink();
246 
247  Info<< "Read " << points.size() << " points." << endl;
248 }
249 
250 void addAndExtend
251 (
252  DynamicList<label>& indizes,
253  label celli,
254  label val
255 )
256 {
257  if (indizes.size() < (celli+1))
258  {
259  indizes.setSize(celli+1,-1);
260  }
261  indizes[celli] = val;
262 }
263 
264 // Reads cells section. Read region as well? Not handled yet but should just
265 // be a matter of reading corresponding to boundaryFaces the correct property
266 // and sorting it later on.
267 void readCells
268 (
269  IFstream& is,
270  DynamicList<cellShape>& cellVerts,
271  DynamicList<label>& cellMaterial,
272  DynamicList<label>& boundaryFaceIndices,
273  DynamicList<face>& boundaryFaces,
274  DynamicList<label>& cellCorrespondence,
275  DynamicList<label>& unvPointID // unv index
276 )
277 {
278  Info<< "Starting reading cells at line " << is.lineNumber() << '.' << endl;
279 
280  // Invert point numbering.
281  label maxUnvPoint = 0;
282  forAll(unvPointID, pointi)
283  {
284  maxUnvPoint = max(maxUnvPoint, unvPointID[pointi]);
285  }
286  labelList unvToFoam(invert(maxUnvPoint+1, unvPointID));
287 
288 
289  const cellModel& hex = *(cellModeller::lookup("hex"));
290  const cellModel& prism = *(cellModeller::lookup("prism"));
291  const cellModel& tet = *(cellModeller::lookup("tet"));
292 
293  labelHashSet skippedElements;
294 
295  labelHashSet foundFeType;
296 
297  while (true)
298  {
299  string line;
300  is.getLine(line);
301 
302  if (isSeparator(line))
303  {
304  break;
305  }
306 
307  label celli, feID, physProp, matProp, colour, nNodes;
308 
309  IStringStream lineStr(line);
310  lineStr
311  >> celli >> feID >> physProp >> matProp >> colour >> nNodes;
312 
313  if (foundFeType.insert(feID))
314  {
315  Info<< "First occurrence of element type " << feID
316  << " for cell " << celli << " at line "
317  << is.lineNumber() << endl;
318  }
319 
320  if (feID == 11)
321  {
322  // Rod. Skip.
323  is.getLine(line);
324  is.getLine(line);
325  }
326  else if (feID == 171)
327  {
328  // Rod. Skip.
329  is.getLine(line);
330  }
331  else if (feID == 41 || feID == 91)
332  {
333  // Triangle. Save - used for patching later on.
334  is.getLine(line);
335 
336  face cVerts(3);
337  IStringStream lineStr(line);
338  lineStr
339  >> cVerts[0] >> cVerts[1] >> cVerts[2];
340  boundaryFaces.append(cVerts);
341  boundaryFaceIndices.append(celli);
342  }
343  else if (feID == 44 || feID == 94)
344  {
345  // Quad. Save - used for patching later on.
346  is.getLine(line);
347 
348  face cVerts(4);
349  IStringStream lineStr(line);
350  lineStr
351  >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3];
352  boundaryFaces.append(cVerts);
353  boundaryFaceIndices.append(celli);
354  }
355  else if (feID == 111)
356  {
357  // Tet.
358  is.getLine(line);
359 
360  labelList cVerts(4);
361  IStringStream lineStr(line);
362  lineStr
363  >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3];
364 
365  cellVerts.append(cellShape(tet, cVerts, true));
366  cellMaterial.append(physProp);
367  addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
368 
369  if (cellVerts.last().size() != cVerts.size())
370  {
371  Info<< "Line:" << is.lineNumber()
372  << " element:" << celli
373  << " type:" << feID
374  << " collapsed from " << cVerts << nl
375  << " to:" << cellVerts.last()
376  << endl;
377  }
378  }
379  else if (feID == 112)
380  {
381  // Wedge.
382  is.getLine(line);
383 
384  labelList cVerts(6);
385  IStringStream lineStr(line);
386  lineStr
387  >> cVerts[0] >> cVerts[1] >> cVerts[2]
388  >> cVerts[3] >> cVerts[4] >> cVerts[5];
389 
390  cellVerts.append(cellShape(prism, cVerts, true));
391  cellMaterial.append(physProp);
392  addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
393 
394  if (cellVerts.last().size() != cVerts.size())
395  {
396  Info<< "Line:" << is.lineNumber()
397  << " element:" << celli
398  << " type:" << feID
399  << " collapsed from " << cVerts << nl
400  << " to:" << cellVerts.last()
401  << endl;
402  }
403  }
404  else if (feID == 115)
405  {
406  // Hex.
407  is.getLine(line);
408 
409  labelList cVerts(8);
410  IStringStream lineStr(line);
411  lineStr
412  >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3]
413  >> cVerts[4] >> cVerts[5] >> cVerts[6] >> cVerts[7];
414 
415  cellVerts.append(cellShape(hex, cVerts, true));
416  cellMaterial.append(physProp);
417  addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
418 
419  if (cellVerts.last().size() != cVerts.size())
420  {
421  Info<< "Line:" << is.lineNumber()
422  << " element:" << celli
423  << " type:" << feID
424  << " collapsed from " << cVerts << nl
425  << " to:" << cellVerts.last()
426  << endl;
427  }
428  }
429  else if (feID == 118)
430  {
431  // Parabolic Tet
432  is.getLine(line);
433 
434  labelList cVerts(4);
435  label dummy;
436  {
437  IStringStream lineStr(line);
438  lineStr
439  >> cVerts[0] >> dummy >> cVerts[1] >> dummy >> cVerts[2];
440  }
441  is.getLine(line);
442  {
443  IStringStream lineStr(line);
444  lineStr >> dummy>> cVerts[3];
445  }
446 
447  cellVerts.append(cellShape(tet, cVerts, true));
448  cellMaterial.append(physProp);
449  addAndExtend(cellCorrespondence,celli,cellMaterial.size()-1);
450 
451  if (cellVerts.last().size() != cVerts.size())
452  {
453  Info<< "Line:" << is.lineNumber()
454  << " element:" << celli
455  << " type:" << feID
456  << " collapsed from " << cVerts << nl
457  << " to:" << cellVerts.last()
458  << endl;
459  }
460  }
461  else
462  {
463  if (skippedElements.insert(feID))
464  {
466  << "Cell type " << feID << " not supported" << endl;
467  }
468 
469  is.getLine(line);
470  }
471  }
472 
473  cellVerts.shrink();
474  cellMaterial.shrink();
475  boundaryFaces.shrink();
476  boundaryFaceIndices.shrink();
477  cellCorrespondence.shrink();
478 
479  Info<< "Read " << cellVerts.size() << " cells"
480  << " and " << boundaryFaces.size() << " boundary faces." << endl;
481 }
482 
483 
484 void readSets
485 (
486  IFstream& is,
487  DynamicList<word>& patchNames,
488  DynamicList<labelList>& patchFaceIndices
489 )
490 {
491  Info<< "Starting reading patches at line " << is.lineNumber() << '.'
492  << endl;
493 
494  while (true)
495  {
496  string line;
497  is.getLine(line);
498 
499  if (isSeparator(line))
500  {
501  break;
502  }
503 
504  IStringStream lineStr(line);
505  label group, constraintSet, restraintSet, loadSet, dofSet,
506  tempSet, contactSet, nFaces;
507  lineStr
508  >> group >> constraintSet >> restraintSet >> loadSet
509  >> dofSet >> tempSet >> contactSet >> nFaces;
510 
511  is.getLine(line);
512  word groupName = string::validate<word>(line);
513 
514  Info<< "For group " << group
515  << " named " << groupName
516  << " trying to read " << nFaces << " patch face indices."
517  << endl;
518 
519  labelList groupIndices(nFaces);
520  label groupType = -1;
521  nFaces = 0;
522 
523  while (nFaces < groupIndices.size())
524  {
525  is.getLine(line);
526  IStringStream lineStr(line);
527 
528  // Read one (for last face) or two entries from line.
529  label nRead = 2;
530  if (nFaces == groupIndices.size()-1)
531  {
532  nRead = 1;
533  }
534 
535  for (label i = 0; i < nRead; i++)
536  {
537  label tag, nodeLeaf, component;
538 
539  lineStr >> groupType >> tag >> nodeLeaf >> component;
540 
541  groupIndices[nFaces++] = tag;
542  }
543  }
544 
545 
546  // Store
547  if (groupType == 8)
548  {
549  patchNames.append(groupName);
550  patchFaceIndices.append(groupIndices);
551  }
552  else
553  {
555  << "When reading patches expect entity type code 8"
556  << nl << " Skipping group code " << groupType
557  << endl;
558  }
559  }
560 
561  patchNames.shrink();
562  patchFaceIndices.shrink();
563 }
564 
565 
566 
567 // Read dof set (757)
568 void readDOFS
569 (
570  IFstream& is,
571  DynamicList<word>& patchNames,
572  DynamicList<labelList>& dofVertices
573 )
574 {
575  Info<< "Starting reading contraints at line " << is.lineNumber() << '.'
576  << endl;
577 
578  string line;
579  is.getLine(line);
580  label group;
581  {
582  IStringStream lineStr(line);
583  lineStr >> group;
584  }
585 
586  is.getLine(line);
587  {
588  IStringStream lineStr(line);
589  patchNames.append(lineStr);
590  }
591 
592  Info<< "For DOF set " << group
593  << " named " << patchNames.last()
594  << " trying to read vertex indices."
595  << endl;
596 
598  while (true)
599  {
600  string line;
601  is.getLine(line);
602 
603  if (isSeparator(line))
604  {
605  break;
606  }
607 
608  IStringStream lineStr(line);
609  label pointi;
610  lineStr >> pointi;
611 
612  vertices.append(pointi);
613  }
614 
615  Info<< "For DOF set " << group
616  << " named " << patchNames.last()
617  << " read " << vertices.size() << " vertex indices." << endl;
618 
619  dofVertices.append(vertices.shrink());
620 
621  patchNames.shrink();
622  dofVertices.shrink();
623 }
624 
625 
626 // Returns -1 or group that all of the vertices of f are in,
627 label findPatch(const List<labelHashSet>& dofGroups, const face& f)
628 {
629  forAll(dofGroups, patchi)
630  {
631  if (dofGroups[patchi].found(f[0]))
632  {
633  bool allInGroup = true;
634 
635  // Check rest of face
636  for (label fp = 1; fp < f.size(); fp++)
637  {
638  if (!dofGroups[patchi].found(f[fp]))
639  {
640  allInGroup = false;
641  break;
642  }
643  }
644 
645  if (allInGroup)
646  {
647  return patchi;
648  }
649  }
650  }
651  return -1;
652 }
653 
654 
655 
656 int main(int argc, char *argv[])
657 {
659  argList::validArgs.append(".unv file");
661  (
662  "dump",
663  "dump boundary faces as boundaryFaces.obj (for debugging)"
664  );
665 
666  #include "setRootCase.H"
667  #include "createTime.H"
668 
669  const fileName ideasName = args[1];
670  IFstream inFile(ideasName);
671 
672  if (!inFile.good())
673  {
675  << "Cannot open file " << ideasName
676  << exit(FatalError);
677  }
678 
679 
680  // Switch on additional debug info
681  const bool verbose = false; //true;
682 
683  // Unit scale factors
684  scalar lengthScale = 1;
685  scalar forceScale = 1;
686  scalar tempScale = 1;
687  scalar tempOffset = 0;
688 
689  // Points
691  // Original unv point label
692  DynamicList<label> unvPointID;
693 
694  // Cells
695  DynamicList<cellShape> cellVerts;
696  DynamicList<label> cellMat;
697  DynamicList<label> cellCorrespondence;
698 
699  // Boundary faces
700  DynamicList<label> boundaryFaceIndices;
701  DynamicList<face> boundaryFaces;
702 
703  // Patch names and patchFace indices.
705  DynamicList<labelList> patchFaceIndices;
706  DynamicList<labelList> dofVertIndices;
707 
708 
709  while (inFile.good())
710  {
711  label tag = readTag(inFile);
712 
713  if (tag == -1)
714  {
715  break;
716  }
717 
718  Info<< "Processing tag:" << tag << endl;
719 
720  switch (tag)
721  {
722  case 151:
723  readHeader(inFile);
724  break;
725 
726  case 164:
727  readUnits
728  (
729  inFile,
730  lengthScale,
731  forceScale,
732  tempScale,
733  tempOffset
734  );
735  break;
736 
737  case 2411:
738  readPoints(inFile, points, unvPointID);
739  break;
740 
741  case 2412:
742  readCells
743  (
744  inFile,
745  cellVerts,
746  cellMat,
747  boundaryFaceIndices,
748  boundaryFaces,
749  cellCorrespondence,
750  unvPointID
751  );
752  break;
753 
754  case 2452:
755  case 2467:
756  readSets
757  (
758  inFile,
759  patchNames,
760  patchFaceIndices
761  );
762  break;
763 
764  case 757:
765  readDOFS
766  (
767  inFile,
768  patchNames,
769  dofVertIndices
770  );
771  break;
772 
773  default:
774  Info<< "Skipping tag " << tag << " on line "
775  << inFile.lineNumber() << endl;
776  skipSection(inFile);
777  break;
778  }
779  Info<< endl;
780  }
781 
782 
783  // Invert point numbering.
784  label maxUnvPoint = 0;
785  forAll(unvPointID, pointi)
786  {
787  maxUnvPoint = max(maxUnvPoint, unvPointID[pointi]);
788  }
789  labelList unvToFoam(invert(maxUnvPoint+1, unvPointID));
790 
791 
792  // Renumber vertex numbers on cells
793 
794  forAll(cellVerts, celli)
795  {
796  labelList foamVerts
797  (
798  renumber
799  (
800  unvToFoam,
801  static_cast<labelList&>(cellVerts[celli])
802  )
803  );
804 
805  if (findIndex(foamVerts, -1) != -1)
806  {
808  << "Cell " << celli
809  << " unv vertices " << cellVerts[celli]
810  << " has some undefined vertices " << foamVerts
811  << abort(FatalError);
812  }
813 
814  // Bit nasty: replace vertex list.
815  cellVerts[celli].transfer(foamVerts);
816  }
817 
818  // Renumber vertex numbers on boundaryFaces
819 
820  forAll(boundaryFaces, bFacei)
821  {
822  labelList foamVerts(renumber(unvToFoam, boundaryFaces[bFacei]));
823 
824  if (findIndex(foamVerts, -1) != -1)
825  {
827  << "Boundary face " << bFacei
828  << " unv vertices " << boundaryFaces[bFacei]
829  << " has some undefined vertices " << foamVerts
830  << abort(FatalError);
831  }
832 
833  // Bit nasty: replace vertex list.
834  boundaryFaces[bFacei].transfer(foamVerts);
835  }
836 
837 
838 
839  // Patchify = create patchFaceVerts for use in cellShape construction
840  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
841 
842  // Works in one of two modes. Either has read boundaryFaces which
843  // just need to be sorted according to patch. Or has read point constraint
844  // sets (dofVertIndices).
845 
846  List<faceList> patchFaceVerts;
847 
848  labelList own(boundaryFaces.size(), -1);
849  labelList nei(boundaryFaces.size(), -1);
850  HashTable<label, label> faceToCell[2];
851 
852  {
853  HashTable<label, face, Hash<face>> faceToFaceID(boundaryFaces.size());
854  forAll(boundaryFaces, facei)
855  {
856  SortableList<label> sortedVerts(boundaryFaces[facei]);
857  faceToFaceID.insert(face(sortedVerts), facei);
858  }
859 
860  forAll(cellVerts, celli)
861  {
862  faceList faces = cellVerts[celli].faces();
863  forAll(faces, i)
864  {
865  SortableList<label> sortedVerts(faces[i]);
866  HashTable<label, face, Hash<face>>::const_iterator fnd =
867  faceToFaceID.find(face(sortedVerts));
868 
869  if (fnd != faceToFaceID.end())
870  {
871  label facei = fnd();
872  int stat = face::compare(faces[i], boundaryFaces[facei]);
873 
874  if (stat == 1)
875  {
876  // Same orientation. Cell is owner.
877  own[facei] = celli;
878  }
879  else if (stat == -1)
880  {
881  // Opposite orientation. Cell is neighbour.
882  nei[facei] = celli;
883  }
884  }
885  }
886  }
887 
888  label nReverse = 0;
889  forAll(own, facei)
890  {
891  if (own[facei] == -1 && nei[facei] != -1)
892  {
893  // Boundary face with incorrect orientation
894  boundaryFaces[facei] = boundaryFaces[facei].reverseFace();
895  Swap(own[facei], nei[facei]);
896  nReverse++;
897  }
898  }
899  if (nReverse > 0)
900  {
901  Info << "Found " << nReverse << " reversed boundary faces out of "
902  << boundaryFaces.size() << endl;
903  }
904 
905 
906  label cnt = 0;
907  forAll(own, facei)
908  {
909  if (own[facei] != -1 && nei[facei] != -1)
910  {
911  faceToCell[1].insert(facei, own[facei]);
912  faceToCell[0].insert(facei, nei[facei]);
913  cnt++;
914  }
915  }
916 
917  if (cnt > 0)
918  {
919  Info << "Of " << boundaryFaces.size() << " so-called"
920  << " boundary faces " << cnt << " belong to two cells "
921  << "and are therefore internal" << endl;
922  }
923  }
924 
925  HashTable<labelList,word> cellZones;
926  HashTable<labelList,word> faceZones;
927  List<bool> isAPatch(patchNames.size(),true);
928 
929  if (dofVertIndices.size())
930  {
931  // Use the vertex constraints to patch. Is of course bit dodgy since
932  // face goes on patch if all its vertices are on a constraint.
933  // Note: very inefficient since goes through all faces (including
934  // internal ones) twice. Should do a construct without patches
935  // and then repatchify.
936 
937  Info<< "Using " << dofVertIndices.size()
938  << " DOF sets to detect boundary faces."<< endl;
939 
940  // Renumber vertex numbers on contraints
941  forAll(dofVertIndices, patchi)
942  {
943  inplaceRenumber(unvToFoam, dofVertIndices[patchi]);
944  }
945 
946 
947  // Build labelHashSet of points per dofGroup/patch
948  List<labelHashSet> dofGroups(dofVertIndices.size());
949 
950  forAll(dofVertIndices, patchi)
951  {
952  const labelList& foamVerts = dofVertIndices[patchi];
953 
954  forAll(foamVerts, i)
955  {
956  dofGroups[patchi].insert(foamVerts[i]);
957  }
958  }
959 
960  List<DynamicList<face>> dynPatchFaces(dofVertIndices.size());
961 
962  forAll(cellVerts, celli)
963  {
964  const cellShape& shape = cellVerts[celli];
965 
966  const faceList shapeFaces(shape.faces());
967 
968  forAll(shapeFaces, i)
969  {
970  label patchi = findPatch(dofGroups, shapeFaces[i]);
971 
972  if (patchi != -1)
973  {
974  dynPatchFaces[patchi].append(shapeFaces[i]);
975  }
976  }
977  }
978 
979  // Transfer
980  patchFaceVerts.setSize(dynPatchFaces.size());
981 
982  forAll(dynPatchFaces, patchi)
983  {
984  patchFaceVerts[patchi].transfer(dynPatchFaces[patchi]);
985  }
986  }
987  else
988  {
989  // Use the boundary faces.
990 
991  // Construct the patch faces by sorting the boundaryFaces according to
992  // patch.
993  patchFaceVerts.setSize(patchFaceIndices.size());
994 
995  Info<< "Sorting boundary faces according to group (patch)" << endl;
996 
997  // make sure that no face is used twice on the boundary
998  // (possible for boundary-only faceZones)
999  labelHashSet alreadyOnBoundary;
1000 
1001  // Construct map from boundaryFaceIndices
1002  Map<label> boundaryFaceToIndex(boundaryFaceIndices.size());
1003 
1004  forAll(boundaryFaceIndices, i)
1005  {
1006  boundaryFaceToIndex.insert(boundaryFaceIndices[i], i);
1007  }
1008 
1009  forAll(patchFaceVerts, patchi)
1010  {
1011  Info << patchi << ": " << patchNames[patchi] << " is " << flush;
1012 
1013  faceList& patchFaces = patchFaceVerts[patchi];
1014  const labelList& faceIndices = patchFaceIndices[patchi];
1015 
1016  patchFaces.setSize(faceIndices.size());
1017 
1018  bool duplicateFaces = false;
1019 
1020  label cnt = 0;
1021  forAll(patchFaces, i)
1022  {
1023  if (boundaryFaceToIndex.found(faceIndices[i]))
1024  {
1025  label bFacei = boundaryFaceToIndex[faceIndices[i]];
1026 
1027  if (own[bFacei] != -1 && nei[bFacei] == -1)
1028  {
1029  patchFaces[cnt] = boundaryFaces[bFacei];
1030  cnt++;
1031  if (alreadyOnBoundary.found(bFacei))
1032  {
1033  duplicateFaces = true;
1034  }
1035  }
1036  }
1037  }
1038 
1039  if (cnt != patchFaces.size() || duplicateFaces)
1040  {
1041  isAPatch[patchi] = false;
1042 
1043  if (verbose)
1044  {
1045  if (cnt != patchFaces.size())
1046  {
1048  << "For patch " << patchi << " there were "
1049  << patchFaces.size()-cnt
1050  << " faces not used because they seem"
1051  << " to be internal. "
1052  << "This seems to be a face or a cell-zone"
1053  << endl;
1054  }
1055  else
1056  {
1058  << "Patch "
1059  << patchi << " has faces that are already "
1060  << " in use on other boundary-patches,"
1061  << " Assuming faceZoneset." << endl;
1062  }
1063  }
1064 
1065  patchFaces.setSize(0); // Assume that this is no patch at all
1066 
1067  if (cellCorrespondence[faceIndices[0]] >= 0)
1068  {
1069  Info << "cellZone" << endl;
1070  labelList theCells(faceIndices.size());
1071  forAll(faceIndices, i)
1072  {
1073  if (cellCorrespondence[faceIndices[0]] < 0)
1074  {
1076  << "The face index " << faceIndices[i]
1077  << " was not found amongst the cells."
1078  << " This kills the theory that "
1079  << patchNames[patchi] << " is a cell zone"
1080  << endl
1081  << abort(FatalError);
1082  }
1083  theCells[i] = cellCorrespondence[faceIndices[i]];
1084  }
1085  cellZones.insert(patchNames[patchi], theCells);
1086  }
1087  else
1088  {
1089  Info << "faceZone" << endl;
1090  labelList theFaces(faceIndices.size());
1091  forAll(faceIndices, i)
1092  {
1093  theFaces[i] = boundaryFaceToIndex[faceIndices[i]];
1094  }
1095  faceZones.insert(patchNames[patchi],theFaces);
1096  }
1097  }
1098  else
1099  {
1100  Info << "patch" << endl;
1101 
1102  forAll(patchFaces, i)
1103  {
1104  label bFacei = boundaryFaceToIndex[faceIndices[i]];
1105  alreadyOnBoundary.insert(bFacei);
1106  }
1107  }
1108  }
1109  }
1110 
1111  pointField polyPoints;
1112  polyPoints.transfer(points);
1113 
1114  // Length scaling factor
1115  polyPoints /= lengthScale;
1116 
1117 
1118  // For debugging: dump boundary faces as OBJ surface mesh
1119  if (args.optionFound("dump"))
1120  {
1121  Info<< "Writing boundary faces to OBJ file boundaryFaces.obj"
1122  << nl << endl;
1123 
1124  // Create globally numbered surface
1125  meshedSurface rawSurface
1126  (
1127  xferCopy(polyPoints),
1128  xferCopyTo<faceList>(boundaryFaces)
1129  );
1130 
1131  // Write locally numbered surface
1133  (
1134  xferCopy(rawSurface.localPoints()),
1135  xferCopy(rawSurface.localFaces())
1136  ).write(runTime.path()/"boundaryFaces.obj");
1137  }
1138 
1139 
1140  Info<< "\nConstructing mesh with non-default patches of size:" << nl;
1141  DynamicList<word> usedPatchNames;
1142  DynamicList<faceList> usedPatchFaceVerts;
1143 
1144  forAll(patchNames, patchi)
1145  {
1146  if (isAPatch[patchi])
1147  {
1148  Info<< " " << patchNames[patchi] << '\t'
1149  << patchFaceVerts[patchi].size() << nl;
1150  usedPatchNames.append(patchNames[patchi]);
1151  usedPatchFaceVerts.append(patchFaceVerts[patchi]);
1152  }
1153  }
1154  usedPatchNames.shrink();
1155  usedPatchFaceVerts.shrink();
1156 
1157  Info<< endl;
1158 
1159 
1160 
1161  // Construct mesh
1162  polyMesh mesh
1163  (
1164  IOobject
1165  (
1167  runTime.constant(),
1168  runTime
1169  ),
1170  xferMove(polyPoints),
1171  cellVerts,
1172  usedPatchFaceVerts, // boundaryFaces,
1173  usedPatchNames, // boundaryPatchNames,
1174  wordList(patchNames.size(), polyPatch::typeName), // boundaryPatchTypes,
1175  "defaultFaces", // defaultFacesName
1176  polyPatch::typeName, // defaultFacesType,
1177  wordList(0) // boundaryPatchPhysicalTypes
1178  );
1179 
1180 
1181  if (faceZones.size() > 0 || cellZones.size() > 0)
1182  {
1183  Info << "Adding cell and face zones" << endl;
1184 
1186  List<faceZone*> fZones(faceZones.size());
1187  List<cellZone*> cZones(cellZones.size());
1188 
1189  if (cellZones.size() > 0)
1190  {
1191  forAll(cellZones.toc(), cnt)
1192  {
1193  word name = cellZones.toc()[cnt];
1194  Info<< " Cell Zone " << name << " " << tab
1195  << cellZones[name].size() << endl;
1196 
1197  cZones[cnt] = new cellZone
1198  (
1199  name,
1200  cellZones[name],
1201  cnt,
1202  mesh.cellZones()
1203  );
1204  }
1205  }
1206  if (faceZones.size() > 0)
1207  {
1208  const labelList& own = mesh.faceOwner();
1209  const labelList& nei = mesh.faceNeighbour();
1210  const pointField& centers = mesh.faceCentres();
1211  const pointField& points = mesh.points();
1212 
1213  forAll(faceZones.toc(), cnt)
1214  {
1215  word name = faceZones.toc()[cnt];
1216  const labelList& oldIndizes = faceZones[name];
1217  labelList indizes(oldIndizes.size());
1218 
1219  Info<< " Face Zone " << name << " " << tab
1220  << oldIndizes.size() << endl;
1221 
1222  forAll(indizes, i)
1223  {
1224  const label old = oldIndizes[i];
1225  label noveau = -1;
1226  label c1 = -1, c2 = -1;
1227  if (faceToCell[0].found(old))
1228  {
1229  c1 = faceToCell[0][old];
1230  }
1231  if (faceToCell[1].found(old))
1232  {
1233  c2 = faceToCell[1][old];
1234  }
1235  if (c1 < c2)
1236  {
1237  label tmp = c1;
1238  c1 = c2;
1239  c2 = tmp;
1240  }
1241  if (c2 == -1)
1242  {
1243  // Boundary face is part of the faceZone
1244  forAll(own, j)
1245  {
1246  if (own[j] == c1)
1247  {
1248  const face& f = boundaryFaces[old];
1249  if (mag(centers[j]- f.centre(points)) < SMALL)
1250  {
1251  noveau = j;
1252  break;
1253  }
1254  }
1255  }
1256  }
1257  else
1258  {
1259  forAll(nei, j)
1260  {
1261  if
1262  (
1263  (c1 == own[j] && c2 == nei[j])
1264  || (c2 == own[j] && c1 == nei[j])
1265  )
1266  {
1267  noveau = j;
1268  break;
1269  }
1270  }
1271  }
1272  assert(noveau > -1);
1273  indizes[i] = noveau;
1274  }
1275  fZones[cnt] = new faceZone
1276  (
1277  faceZones.toc()[cnt],
1278  indizes,
1279  boolList(indizes.size(),false),
1280  cnt,
1281  mesh.faceZones()
1282  );
1283  }
1284  }
1285  mesh.addZones(pZones, fZones, cZones);
1286 
1287  Info << endl;
1288  }
1289 
1290  mesh.write();
1291 
1292  Info<< "End\n" << endl;
1293 
1294  return 0;
1295 }
1296 
1297 
1298 // ************************************************************************* //
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:428
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:88
A class for handling file names.
Definition: fileName.H:69
void inplaceRenumber(const labelUList &oldToNew, ListType &)
Inplace renumber the values of a list.
const faceZoneMesh & faceZones() const
Return face zone mesh.
Definition: polyMesh.H:466
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:110
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
static const char tab
Definition: Ostream.H:261
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:1055
A list that is sorted upon construction or when explicitly requested with the sort() method...
Definition: List.H:73
virtual bool write(const bool valid=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:877
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].
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:309
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
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:148
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:154
Xfer< T > xferCopy(const T &)
Construct by copying the contents of the arg.
label lineNumber() const
Return current stream line number.
Definition: IOstream.H:438
unsigned operator()(const PrimitiveType &p, unsigned seed) const
Definition: Hash.H:61
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116
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:1011
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
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:163
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
Xfer< T > xferMove(T &)
Construct by transferring the contents of the arg.
A class for handling words, derived from string.
Definition: word.H:59
const cellZoneMesh & cellZones() const
Return cell zone mesh.
Definition: polyMesh.H:472
MeshedSurface< face > meshedSurface
static int compare(const face &, const face &)
Compare faces.
Definition: face.C:298
wordList patchNames(nPatches)
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1049
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:292
bool readScalar(const char *buf, doubleScalar &s)
Read whole of buf as a scalar. Return true if succesful.
Definition: doubleScalar.H:63
An STL-conforming hash table.
Definition: HashTable.H:62
void addZones(const List< pointZone *> &pz, const List< faceZone *> &fz, const List< cellZone *> &cz)
Add mesh zones.
Definition: polyMesh.C:954
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:240
static const char nl
Definition: Ostream.H:262
Input from file stream.
Definition: IFstream.H:81
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurence 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:245
#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/m2].
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:85
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:259
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