Forward compatibility: flex
[foam-extend-3.2.git] / applications / utilities / mesh / conversion / ideasUnvToFoam / ideasUnvToFoam.C
blob1970264733a2b4970317cfa6826cdb0e098bf069
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend is free software: you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation, either version 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 Description
25     I-Deas unv format mesh conversion.
27     Uses either
28     - DOF sets (757) or
29     - face groups (2452(Cubit), 2467)
30     to do patching.
31     Works without but then puts all faces in defaultFaces patch.
33 \*---------------------------------------------------------------------------*/
35 #include "argList.H"
36 #include "polyMesh.H"
37 #include "foamTime.H"
38 #include "IFstream.H"
39 #include "cellModeller.H"
40 #include "cellSet.H"
41 #include "faceSet.H"
42 #include "DynamicList.H"
43 #include "triSurface.H"
45 using namespace Foam;
47 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 const string SEPARATOR("    -1");
51 bool isSeparator(const string& line)
53     return line.substr(0, 6) == SEPARATOR;
57 // Reads past -1 and reads element type
58 label readTag(IFstream& is)
60     string tag;
61     do
62     {
63         if (!is.good())
64         {
65             return -1;
66         }
68         string line;
70         is.getLine(line);
72         if (line.size() < 6)
73         {
74             return -1;
75         }
77         tag = line.substr(0, 6);
79     } while (tag == SEPARATOR);
81     return readLabel(IStringStream(tag)());
85 // Reads and prints header
86 void readHeader(IFstream& is)
88     string line;
90     while (is.good())
91     {
92         is.getLine(line);
94         if (isSeparator(line))
95         {
96             break;
97         }
98         else
99         {
100             Sout<< line << endl;
101         }
102     }
106 // Skip
107 void skipSection(IFstream& is)
109     Sout<< "Skipping section at line " << is.lineNumber() << '.' << endl;
111     string line;
113     while (is.good())
114     {
115         is.getLine(line);
117         if (isSeparator(line))
118         {
119             break;
120         }
121         else
122         {
123 //            Sout<< line << endl;
124         }
125     }
129 scalar readUnvScalar(const string& unvString)
131     string s(unvString);
133     s.replaceAll("d", "E");
134     s.replaceAll("D", "E");
136     return readScalar(IStringStream(s)());
140 // Reads unit section
141 void readUnits
143     IFstream& is,
144     scalar& lengthScale,
145     scalar& forceScale,
146     scalar& tempScale,
147     scalar& tempOffset
150     Sout<< "Starting reading units at line " << is.lineNumber() << '.' << endl;
152     string line;
153     is.getLine(line);
155     label l = readLabel(IStringStream(line.substr(0, 10))());
156     Sout<< "l:" << l << endl;
158     string units(line.substr(10, 20));
159     Sout<< "units:" << units << endl;
161     label unitType = readLabel(IStringStream(line.substr(30, 10))());
162     Sout<< "unitType:" << unitType << endl;
164     // Read lengthscales
165     is.getLine(line);
167     lengthScale = readUnvScalar(line.substr(0, 25));
168     forceScale = readUnvScalar(line.substr(25, 25));
169     tempScale = readUnvScalar(line.substr(50, 25));
171     is.getLine(line);
172     tempOffset = readUnvScalar(line.substr(0, 25));
174     Sout<< "Unit factors:" << nl
175         << "    Length scale       : " << lengthScale << nl
176         << "    Force scale        : " << forceScale << nl
177         << "    Temperature scale  : " << tempScale << nl
178         << "    Temperature offset : " << tempOffset << nl
179         << endl;
183 // Reads points section. Read region as well?
184 void readPoints
186     IFstream& is,
187     DynamicList<point>& points,     // coordinates
188     DynamicList<label>& unvPointID  // unv index
191     Sout<< "Starting reading points at line " << is.lineNumber() << '.' << endl;
193     static bool hasWarned = false;
195     while (true)
196     {
197         string line;
198         is.getLine(line);
200         label pointI = readLabel(IStringStream(line.substr(0, 10))());
202         if (pointI == -1)
203         {
204             break;
205         }
206         else if (pointI != points.size()+1 && !hasWarned)
207         {
208             hasWarned = true;
210             IOWarningIn
211             (
212                 "readPoints(IFstream&, label&, DynamicList<point>"
213                 ", DynamicList<label>&)",
214                 is
215             )   << "Points not in order starting at point " << pointI
216                 //<< " at line " << is.lineNumber()
217                 //<< abort(FatalError);
218                 << endl;
219         }
221         point pt;
222         is.getLine(line);
223         pt[0] = readUnvScalar(line.substr(0, 25));
224         pt[1] = readUnvScalar(line.substr(25, 25));
225         pt[2] = readUnvScalar(line.substr(50, 25));
227         unvPointID.append(pointI);
228         points.append(pt);
229     }
231     points.shrink();
232     unvPointID.shrink();
234     Sout<< "Read " << points.size() << " points." << endl;
238 // Reads cells section. Read region as well? Not handled yet but should just
239 // be a matter of reading corresponding to boundaryFaces the correct property
240 // and sorting it later on.
241 void readCells
243     IFstream& is,
244     DynamicList<cellShape>& cellVerts,
245     DynamicList<label>& cellMaterial,
246     DynamicList<label>& boundaryFaceIndices,
247     DynamicList<face>& boundaryFaces
250     Sout<< "Starting reading cells at line " << is.lineNumber() << '.' << endl;
252     const cellModel& hex = *(cellModeller::lookup("hex"));
253     const cellModel& prism = *(cellModeller::lookup("prism"));
254     const cellModel& tet = *(cellModeller::lookup("tet"));
256     labelHashSet skippedElements;
258     labelHashSet foundFeType;
260     while (true)
261     {
262         string line;
263         is.getLine(line);
265         if (isSeparator(line))
266         {
267             break;
268         }
270         IStringStream lineStr(line);
271         label cellI, feID, physProp, matProp, colour, nNodes;
272         lineStr >> cellI >> feID >> physProp >> matProp >> colour >> nNodes;
274         if (foundFeType.insert(feID))
275         {
276             Info<< "First occurrence of element type " << feID
277                 << " for cell " << cellI << " at line "
278                 << is.lineNumber() << endl;
279         }
281         if (feID == 11)
282         {
283             // Rod. Skip.
284             is.getLine(line);
285             is.getLine(line);
286         }
287         else if (feID == 171)
288         {
289             // Rod. Skip.
290             is.getLine(line);
291         }
292         else if (feID == 41 || feID == 91)
293         {
294             // Triangle. Save - used for patching later on.
295             is.getLine(line);
297             face cVerts(3);
298             IStringStream lineStr(line);
299             lineStr >> cVerts[0] >> cVerts[1] >> cVerts[2];
300             boundaryFaces.append(cVerts);
301             boundaryFaceIndices.append(cellI);
302         }
303         else if (feID == 44 || feID == 94)
304         {
305             // Quad. Save - used for patching later on.
306             is.getLine(line);
308             face cVerts(4);
309             IStringStream lineStr(line);
310             lineStr >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3];
311             boundaryFaces.append(cVerts);
312             boundaryFaceIndices.append(cellI);
313         }
314         else if (feID == 111)
315         {
316             // Tet.
317             is.getLine(line);
319             labelList cVerts(4);
320             IStringStream lineStr(line);
321             lineStr >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3];
323             cellVerts.append(cellShape(tet, cVerts, true));
324             cellMaterial.append(physProp);
326             if (cellVerts[cellVerts.size()-1].size() != cVerts.size())
327             {
328                 Pout<< "Line:" << is.lineNumber()
329                     << " element:" << cellI
330                     << " type:" << feID
331                     << " collapsed from " << cVerts << nl
332                     << " to:" << cellVerts[cellVerts.size()-1]
333                     << endl;
334             }
335         }
336         else if (feID == 112)
337         {
338             // Wedge.
339             is.getLine(line);
341             labelList cVerts(6);
342             IStringStream lineStr(line);
343             lineStr >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3]
344                     >> cVerts[4] >> cVerts[5];
346             cellVerts.append(cellShape(prism, cVerts, true));
347             cellMaterial.append(physProp);
349             if (cellVerts[cellVerts.size()-1].size() != cVerts.size())
350             {
351                 Pout<< "Line:" << is.lineNumber()
352                     << " element:" << cellI
353                     << " type:" << feID
354                     << " collapsed from " << cVerts << nl
355                     << " to:" << cellVerts[cellVerts.size()-1]
356                     << endl;
357             }
358         }
359         else if (feID == 115)
360         {
361             // Hex.
362             is.getLine(line);
364             labelList cVerts(8);
365             IStringStream lineStr(line);
366             lineStr
367                 >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3]
368                 >> cVerts[4] >> cVerts[5] >> cVerts[6] >> cVerts[7];
370             cellVerts.append(cellShape(hex, cVerts, true));
371             cellMaterial.append(physProp);
373             if (cellVerts[cellVerts.size()-1].size() != cVerts.size())
374             {
375                 Pout<< "Line:" << is.lineNumber()
376                     << " element:" << cellI
377                     << " type:" << feID
378                     << " collapsed from " << cVerts << nl
379                     << " to:" << cellVerts[cellVerts.size()-1]
380                     << endl;
381             }
382         }
383         else
384         {
385             if (skippedElements.insert(feID))
386             {
387                 IOWarningIn("readCells(IFstream&, label&)", is)
388                     << "Cell type " << feID << " not supported" << endl;
389             }
390             is.getLine(line);  //Do nothing
391         }
392     }
394     cellVerts.shrink();
395     cellMaterial.shrink();
396     boundaryFaces.shrink();
397     boundaryFaceIndices.shrink();
399     Sout<< "Read " << cellVerts.size() << " cells"
400         << " and " << boundaryFaces.size() << " boundary faces." << endl;
404 void readPatches
406     IFstream& is,
407     DynamicList<word>& patchNames,
408     DynamicList<labelList>& patchFaceIndices
411     Sout<< "Starting reading patches at line " << is.lineNumber() << '.'
412         << endl;
414     while(true)
415     {
416         string line;
417         is.getLine(line);
419         if (isSeparator(line))
420         {
421             break;
422         }
424         IStringStream lineStr(line);
425         label group, constraintSet, restraintSet, loadSet, dofSet,
426             tempSet, contactSet, nFaces;
427         lineStr
428             >> group >> constraintSet >> restraintSet >> loadSet
429             >> dofSet >> tempSet >> contactSet >> nFaces;
431         is.getLine(line);
432         word groupName = string::validate<word>(line);
434         Info<< "For group " << group
435             << " named " << groupName
436             << " trying to read " << nFaces << " patch face indices."
437             << endl;
439         labelList groupIndices(nFaces);
440         label groupType = -1;
441         nFaces = 0;
443         while (nFaces < groupIndices.size())
444         {
445             is.getLine(line);
446             IStringStream lineStr(line);
448             // Read one (for last face) or two entries from line.
449             label nRead = 2;
450             if (nFaces == groupIndices.size() - 1)
451             {
452                 nRead = 1;
453             }
455             for (label i = 0; i < nRead; i++)
456             {
457                 label tag, nodeLeaf, component;
459                 lineStr >> groupType >> tag >> nodeLeaf >> component;
461                 groupIndices[nFaces++] = tag;
462             }
463         }
466         // Store
467         if (groupType == 8)
468         {
469             patchNames.append(groupName);
470             patchFaceIndices.append(groupIndices);
471         }
472         else
473         {
474             IOWarningIn("readPatches(..)", is)
475                 << "When reading patches expect entity type code 8"
476                 << nl << "    Skipping group code " << groupType
477                 << endl;
478         }
479     }
481     patchNames.shrink();
482     patchFaceIndices.shrink();
487 // Read dof set (757)
488 void readDOFS
490     IFstream& is,
491     DynamicList<word>& patchNames,
492     DynamicList<labelList>& dofVertices
495     Sout<< "Starting reading contraints at line " << is.lineNumber() << '.'
496         << endl;
498     string line;
499     is.getLine(line);
500     label group;
501     {
502         IStringStream lineStr(line);
503         lineStr >> group;
504     }
506     is.getLine(line);
507     {
508         IStringStream lineStr(line);
509         patchNames.append(lineStr);
510     }
512     Info<< "For DOF set " << group
513         << " named " << patchNames[patchNames.size()-1]
514         << " trying to read vertex indices."
515         << endl;
517     DynamicList<label> vertices;
518     while (true)
519     {
520         string line;
521         is.getLine(line);
523         if (isSeparator(line))
524         {
525             break;
526         }
528         IStringStream lineStr(line);
529         label pointI;
530         lineStr >> pointI;
532         vertices.append(pointI);
533     }
535     Info<< "For DOF set " << group
536         << " named " << patchNames[patchNames.size()-1]
537         << " read " << vertices.size() << " vertex indices." << endl;
539     dofVertices.append(vertices.shrink());
541     patchNames.shrink();
542     dofVertices.shrink();
546 // Returns -1 or group that all of the vertices of f are in,
547 label findPatch(const List<labelHashSet>& dofGroups, const face& f)
549     forAll(dofGroups, patchI)
550     {
551         if (dofGroups[patchI].found(f[0]))
552         {
553             bool allInGroup = true;
555             // Check rest of face
556             for (label fp = 1; fp < f.size(); fp++)
557             {
558                 if (!dofGroups[patchI].found(f[fp]))
559                 {
560                     allInGroup = false;
561                     break;
562                 }
563             }
565             if (allInGroup)
566             {
567                 return patchI;
568             }
569         }
570     }
571     return -1;
575 // Main program:
577 int main(int argc, char *argv[])
579     argList::noParallel();
580     argList::validArgs.append(".unv file");
581     argList::validOptions.insert("dump", "");
583 #   include "setRootCase.H"
584 #   include "createTime.H"
586     fileName ideasName(args.additionalArgs()[0]);
588     IFstream inFile(ideasName.c_str());
590     if (!inFile.good())
591     {
592         FatalErrorIn(args.executable())
593             << "Cannot open file " << ideasName
594             << exit(FatalError);
595     }
598     // Unit scale factors
599     scalar lengthScale = 1;
600     scalar forceScale = 1;
601     scalar tempScale = 1;
602     scalar tempOffset = 0;
604     // Points
605     DynamicList<point> points;
606     // Original unv point label
607     DynamicList<label> unvPointID;
609     // Cells
610     DynamicList<cellShape> cellVerts;
611     DynamicList<label> cellMat;
613     // Boundary faces
614     DynamicList<label> boundaryFaceIndices;
615     DynamicList<face> boundaryFaces;
617     // Patch names and patchFace indices.
618     DynamicList<word> patchNames;
619     DynamicList<labelList> patchFaceIndices;
620     DynamicList<labelList> dofVertIndices;
623     while (inFile.good())
624     {
625         label tag = readTag(inFile);
627         if (tag == -1)
628         {
629             break;
630         }
632         Sout<< "Processing tag:" << tag << endl;
634         switch (tag)
635         {
636             case 151:
637                 readHeader(inFile);
638             break;
640             case 164:
641                 readUnits
642                 (
643                     inFile,
644                     lengthScale,
645                     forceScale,
646                     tempScale,
647                     tempOffset
648                 );
649             break;
651             case 2411:
652                 readPoints(inFile, points, unvPointID);
653             break;
655             case 2412:
656                 readCells
657                 (
658                     inFile,
659                     cellVerts,
660                     cellMat,
661                     boundaryFaceIndices,
662                     boundaryFaces
663                 );
664             break;
666             case 2452:
667             case 2467:
668                 readPatches
669                 (
670                     inFile,
671                     patchNames,
672                     patchFaceIndices
673                 );
674             break;
676             case 757:
677                 readDOFS
678                 (
679                     inFile,
680                     patchNames,
681                     dofVertIndices
682                 );
683             break;
685             default:
686                 Sout<< "Skipping tag " << tag << " on line "
687                     << inFile.lineNumber() << endl;
688                 skipSection(inFile);
689             break;
690         }
691         Sout<< endl;
692     }
695     // Invert point numbering.
696     label maxUnvPoint = 0;
697     forAll(unvPointID, pointI)
698     {
699         maxUnvPoint = max(maxUnvPoint, unvPointID[pointI]);
700     }
701     labelList unvToFoam(invert(maxUnvPoint+1, unvPointID));
704     // Renumber vertex numbers on cells
706     forAll(cellVerts, cellI)
707     {
708         labelList foamVerts
709         (
710             renumber
711             (
712                 unvToFoam,
713                 static_cast<labelList&>(cellVerts[cellI])
714             )
715         );
717         if (findIndex(foamVerts, -1) != -1)
718         {
719             FatalErrorIn(args.executable())
720                 << "Cell " << cellI
721                 << " unv vertices " << cellVerts[cellI]
722                 << " has some undefined vertices " << foamVerts
723                 << abort(FatalError);
724         }
726         // Bit nasty: replace vertex list.
727         cellVerts[cellI].transfer(foamVerts);
728     }
730     // Renumber vertex numbers on boundaryFaces
732     forAll(boundaryFaces, bFaceI)
733     {
734         labelList foamVerts(renumber(unvToFoam, boundaryFaces[bFaceI]));
736         if (findIndex(foamVerts, -1) != -1)
737         {
738             FatalErrorIn(args.executable())
739                 << "Boundary face " << bFaceI
740                 << " unv vertices " << boundaryFaces[bFaceI]
741                 << " has some undefined vertices " << foamVerts
742                 << abort(FatalError);
743         }
745         // Bit nasty: replace vertex list.
746         boundaryFaces[bFaceI].transfer(foamVerts);
747     }
751     // Patchify = create patchFaceVerts for use in cellShape construction
752     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
754     // Works in one of two modes. Either has read boundaryFaces which
755     // just need to be sorted according to patch. Or has read point constraint
756     // sets (dofVertIndices).
758     List<faceList> patchFaceVerts;
761     if (dofVertIndices.size())
762     {
763         // Use the vertex constraints to patch. Is of course bit dodgy since
764         // face goes on patch if all its vertices are on a constraint.
765         // Note: very inefficient since goes through all faces (including
766         // internal ones) twice. Should do a construct without patches
767         // and then repatchify.
769         Info<< "Using " << dofVertIndices.size()
770             << " DOF sets to detect boundary faces."<< endl;
772         // Renumber vertex numbers on contraints
773         forAll(dofVertIndices, patchI)
774         {
775             inplaceRenumber(unvToFoam, dofVertIndices[patchI]);
776         }
779         // Build labelHashSet of points per dofGroup/patch
780         List<labelHashSet> dofGroups(dofVertIndices.size());
782         forAll(dofVertIndices, patchI)
783         {
784             const labelList& foamVerts = dofVertIndices[patchI];
786             forAll(foamVerts, i)
787             {
788                 dofGroups[patchI].insert(foamVerts[i]);
789             }
790         }
792         List<DynamicList<face> > dynPatchFaces(dofVertIndices.size());
794         forAll(cellVerts, cellI)
795         {
796             const cellShape& shape = cellVerts[cellI];
798             const faceList shapeFaces(shape.faces());
800             forAll(shapeFaces, i)
801             {
802                 label patchI = findPatch(dofGroups, shapeFaces[i]);
804                 if (patchI != -1)
805                 {
806                     dynPatchFaces[patchI].append(shapeFaces[i]);
807                 }
808             }
809         }
811         // Transfer
812         patchFaceVerts.setSize(dynPatchFaces.size());
814         forAll(dynPatchFaces, patchI)
815         {
816             patchFaceVerts[patchI].transfer(dynPatchFaces[patchI]);
817         }
818     }
819     else
820     {
821         // Use the boundary faces.
823         // Construct the patch faces by sorting the boundaryFaces according to
824         // patch.
825         patchFaceVerts.setSize(patchFaceIndices.size());
827         Info<< "Sorting boundary faces according to group (patch)" << endl;
829         // Construct map from boundaryFaceIndices
830         Map<label> boundaryFaceToIndex(boundaryFaceIndices.size());
832         forAll(boundaryFaceIndices, i)
833         {
834             boundaryFaceToIndex.insert(boundaryFaceIndices[i], i);
835         }
837         forAll(patchFaceVerts, patchI)
838         {
839             faceList& patchFaces = patchFaceVerts[patchI];
840             const labelList& faceIndices = patchFaceIndices[patchI];
842             patchFaces.setSize(faceIndices.size());
844             forAll(patchFaces, i)
845             {
846                 label bFaceI = boundaryFaceToIndex[faceIndices[i]];
848                 patchFaces[i] = boundaryFaces[bFaceI];
849             }
850         }
851     }
853     pointField polyPoints;
854     polyPoints.transfer(points);
856     // Length scaling factor
857     polyPoints /= lengthScale;
860     // For debugging: dump boundary faces as triSurface
861     if (args.optionFound("dump"))
862     {
863         DynamicList<labelledTri> triangles(boundaryFaces.size());
865         forAll(boundaryFaces, i)
866         {
867             const face& f = boundaryFaces[i];
869             faceList triFaces(f.nTriangles(polyPoints));
870             label nTri = 0;
871             f.triangles(polyPoints, nTri, triFaces);
873             forAll(triFaces, triFaceI)
874             {
875                 const face& f = triFaces[triFaceI];
876                 triangles.append(labelledTri(f[0], f[1], f[2], 0));
877             }
878         }
880         // Create globally numbered tri surface
881         triSurface rawSurface(triangles.shrink(), polyPoints);
883         // Create locally numbered tri surface
884         triSurface surface
885         (
886             rawSurface.localFaces(),
887             rawSurface.localPoints()
888         );
890         Info<< "Writing boundary faces to STL file boundaryFaces.stl"
891             << nl << endl;
893         surface.write(runTime.path()/"boundaryFaces.stl");
894     }
897     Info<< "Constructing mesh with non-default patches of size:" << nl;
898     forAll(patchNames, patchI)
899     {
900         Info<< "    " << patchNames[patchI] << '\t'
901             << patchFaceVerts[patchI].size() << nl;
902     }
903     Info<< endl;
907     // Construct mesh
908     polyMesh mesh
909     (
910         IOobject
911         (
912             polyMesh::defaultRegion,
913             runTime.constant(),
914             runTime
915         ),
916         xferMove(polyPoints),
917         cellVerts,
918         patchFaceVerts,             // boundaryFaces,
919         patchNames,                 // boundaryPatchNames,
920         wordList(patchNames.size(), polyPatch::typeName), // boundaryPatchTypes,
921         "defaultFaces",             // defaultFacesName
922         polyPatch::typeName,        // defaultFacesType,
923         wordList(0)                 // boundaryPatchPhysicalTypes
924     );
926     mesh.write();
928     Info<< "End\n" << endl;
930     return 0;
934 // ************************************************************************* //