1 /*---------------------------------------------------------------------------*\
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 -------------------------------------------------------------------------------
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/>.
25 I-Deas unv format mesh conversion.
29 - face groups (2452(Cubit), 2467)
31 Works without but then puts all faces in defaultFaces patch.
33 \*---------------------------------------------------------------------------*/
39 #include "cellModeller.H"
42 #include "DynamicList.H"
43 #include "triSurface.H"
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)
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)
94 if (isSeparator(line))
107 void skipSection(IFstream& is)
109 Sout<< "Skipping section at line " << is.lineNumber() << '.' << endl;
117 if (isSeparator(line))
123 // Sout<< line << endl;
129 scalar readUnvScalar(const string& unvString)
133 s.replaceAll("d", "E");
134 s.replaceAll("D", "E");
136 return readScalar(IStringStream(s)());
140 // Reads unit section
150 Sout<< "Starting reading units at line " << is.lineNumber() << '.' << endl;
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;
167 lengthScale = readUnvScalar(line.substr(0, 25));
168 forceScale = readUnvScalar(line.substr(25, 25));
169 tempScale = readUnvScalar(line.substr(50, 25));
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
183 // Reads points section. Read region as well?
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;
200 label pointI = readLabel(IStringStream(line.substr(0, 10))());
206 else if (pointI != points.size()+1 && !hasWarned)
212 "readPoints(IFstream&, label&, DynamicList<point>"
213 ", DynamicList<label>&)",
215 ) << "Points not in order starting at point " << pointI
216 //<< " at line " << is.lineNumber()
217 //<< abort(FatalError);
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);
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.
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;
265 if (isSeparator(line))
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))
276 Info<< "First occurrence of element type " << feID
277 << " for cell " << cellI << " at line "
278 << is.lineNumber() << endl;
287 else if (feID == 171)
292 else if (feID == 41 || feID == 91)
294 // Triangle. Save - used for patching later on.
298 IStringStream lineStr(line);
299 lineStr >> cVerts[0] >> cVerts[1] >> cVerts[2];
300 boundaryFaces.append(cVerts);
301 boundaryFaceIndices.append(cellI);
303 else if (feID == 44 || feID == 94)
305 // Quad. Save - used for patching later on.
309 IStringStream lineStr(line);
310 lineStr >> cVerts[0] >> cVerts[1] >> cVerts[2] >> cVerts[3];
311 boundaryFaces.append(cVerts);
312 boundaryFaceIndices.append(cellI);
314 else if (feID == 111)
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())
328 Pout<< "Line:" << is.lineNumber()
329 << " element:" << cellI
331 << " collapsed from " << cVerts << nl
332 << " to:" << cellVerts[cellVerts.size()-1]
336 else if (feID == 112)
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())
351 Pout<< "Line:" << is.lineNumber()
352 << " element:" << cellI
354 << " collapsed from " << cVerts << nl
355 << " to:" << cellVerts[cellVerts.size()-1]
359 else if (feID == 115)
365 IStringStream lineStr(line);
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())
375 Pout<< "Line:" << is.lineNumber()
376 << " element:" << cellI
378 << " collapsed from " << cVerts << nl
379 << " to:" << cellVerts[cellVerts.size()-1]
385 if (skippedElements.insert(feID))
387 IOWarningIn("readCells(IFstream&, label&)", is)
388 << "Cell type " << feID << " not supported" << endl;
390 is.getLine(line); //Do nothing
395 cellMaterial.shrink();
396 boundaryFaces.shrink();
397 boundaryFaceIndices.shrink();
399 Sout<< "Read " << cellVerts.size() << " cells"
400 << " and " << boundaryFaces.size() << " boundary faces." << endl;
407 DynamicList<word>& patchNames,
408 DynamicList<labelList>& patchFaceIndices
411 Sout<< "Starting reading patches at line " << is.lineNumber() << '.'
419 if (isSeparator(line))
424 IStringStream lineStr(line);
425 label group, constraintSet, restraintSet, loadSet, dofSet,
426 tempSet, contactSet, nFaces;
428 >> group >> constraintSet >> restraintSet >> loadSet
429 >> dofSet >> tempSet >> contactSet >> nFaces;
432 word groupName = string::validate<word>(line);
434 Info<< "For group " << group
435 << " named " << groupName
436 << " trying to read " << nFaces << " patch face indices."
439 labelList groupIndices(nFaces);
440 label groupType = -1;
443 while (nFaces < groupIndices.size())
446 IStringStream lineStr(line);
448 // Read one (for last face) or two entries from line.
450 if (nFaces == groupIndices.size() - 1)
455 for (label i = 0; i < nRead; i++)
457 label tag, nodeLeaf, component;
459 lineStr >> groupType >> tag >> nodeLeaf >> component;
461 groupIndices[nFaces++] = tag;
469 patchNames.append(groupName);
470 patchFaceIndices.append(groupIndices);
474 IOWarningIn("readPatches(..)", is)
475 << "When reading patches expect entity type code 8"
476 << nl << " Skipping group code " << groupType
482 patchFaceIndices.shrink();
487 // Read dof set (757)
491 DynamicList<word>& patchNames,
492 DynamicList<labelList>& dofVertices
495 Sout<< "Starting reading contraints at line " << is.lineNumber() << '.'
502 IStringStream lineStr(line);
508 IStringStream lineStr(line);
509 patchNames.append(lineStr);
512 Info<< "For DOF set " << group
513 << " named " << patchNames[patchNames.size()-1]
514 << " trying to read vertex indices."
517 DynamicList<label> vertices;
523 if (isSeparator(line))
528 IStringStream lineStr(line);
532 vertices.append(pointI);
535 Info<< "For DOF set " << group
536 << " named " << patchNames[patchNames.size()-1]
537 << " read " << vertices.size() << " vertex indices." << endl;
539 dofVertices.append(vertices.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)
551 if (dofGroups[patchI].found(f[0]))
553 bool allInGroup = true;
555 // Check rest of face
556 for (label fp = 1; fp < f.size(); fp++)
558 if (!dofGroups[patchI].found(f[fp]))
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());
592 FatalErrorIn(args.executable())
593 << "Cannot open file " << ideasName
598 // Unit scale factors
599 scalar lengthScale = 1;
600 scalar forceScale = 1;
601 scalar tempScale = 1;
602 scalar tempOffset = 0;
605 DynamicList<point> points;
606 // Original unv point label
607 DynamicList<label> unvPointID;
610 DynamicList<cellShape> cellVerts;
611 DynamicList<label> cellMat;
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())
625 label tag = readTag(inFile);
632 Sout<< "Processing tag:" << tag << endl;
652 readPoints(inFile, points, unvPointID);
686 Sout<< "Skipping tag " << tag << " on line "
687 << inFile.lineNumber() << endl;
695 // Invert point numbering.
696 label maxUnvPoint = 0;
697 forAll(unvPointID, pointI)
699 maxUnvPoint = max(maxUnvPoint, unvPointID[pointI]);
701 labelList unvToFoam(invert(maxUnvPoint+1, unvPointID));
704 // Renumber vertex numbers on cells
706 forAll(cellVerts, cellI)
713 static_cast<labelList&>(cellVerts[cellI])
717 if (findIndex(foamVerts, -1) != -1)
719 FatalErrorIn(args.executable())
721 << " unv vertices " << cellVerts[cellI]
722 << " has some undefined vertices " << foamVerts
723 << abort(FatalError);
726 // Bit nasty: replace vertex list.
727 cellVerts[cellI].transfer(foamVerts);
730 // Renumber vertex numbers on boundaryFaces
732 forAll(boundaryFaces, bFaceI)
734 labelList foamVerts(renumber(unvToFoam, boundaryFaces[bFaceI]));
736 if (findIndex(foamVerts, -1) != -1)
738 FatalErrorIn(args.executable())
739 << "Boundary face " << bFaceI
740 << " unv vertices " << boundaryFaces[bFaceI]
741 << " has some undefined vertices " << foamVerts
742 << abort(FatalError);
745 // Bit nasty: replace vertex list.
746 boundaryFaces[bFaceI].transfer(foamVerts);
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())
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)
775 inplaceRenumber(unvToFoam, dofVertIndices[patchI]);
779 // Build labelHashSet of points per dofGroup/patch
780 List<labelHashSet> dofGroups(dofVertIndices.size());
782 forAll(dofVertIndices, patchI)
784 const labelList& foamVerts = dofVertIndices[patchI];
788 dofGroups[patchI].insert(foamVerts[i]);
792 List<DynamicList<face> > dynPatchFaces(dofVertIndices.size());
794 forAll(cellVerts, cellI)
796 const cellShape& shape = cellVerts[cellI];
798 const faceList shapeFaces(shape.faces());
800 forAll(shapeFaces, i)
802 label patchI = findPatch(dofGroups, shapeFaces[i]);
806 dynPatchFaces[patchI].append(shapeFaces[i]);
812 patchFaceVerts.setSize(dynPatchFaces.size());
814 forAll(dynPatchFaces, patchI)
816 patchFaceVerts[patchI].transfer(dynPatchFaces[patchI]);
821 // Use the boundary faces.
823 // Construct the patch faces by sorting the boundaryFaces according to
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)
834 boundaryFaceToIndex.insert(boundaryFaceIndices[i], i);
837 forAll(patchFaceVerts, patchI)
839 faceList& patchFaces = patchFaceVerts[patchI];
840 const labelList& faceIndices = patchFaceIndices[patchI];
842 patchFaces.setSize(faceIndices.size());
844 forAll(patchFaces, i)
846 label bFaceI = boundaryFaceToIndex[faceIndices[i]];
848 patchFaces[i] = boundaryFaces[bFaceI];
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"))
863 DynamicList<labelledTri> triangles(boundaryFaces.size());
865 forAll(boundaryFaces, i)
867 const face& f = boundaryFaces[i];
869 faceList triFaces(f.nTriangles(polyPoints));
871 f.triangles(polyPoints, nTri, triFaces);
873 forAll(triFaces, triFaceI)
875 const face& f = triFaces[triFaceI];
876 triangles.append(labelledTri(f[0], f[1], f[2], 0));
880 // Create globally numbered tri surface
881 triSurface rawSurface(triangles.shrink(), polyPoints);
883 // Create locally numbered tri surface
886 rawSurface.localFaces(),
887 rawSurface.localPoints()
890 Info<< "Writing boundary faces to STL file boundaryFaces.stl"
893 surface.write(runTime.path()/"boundaryFaces.stl");
897 Info<< "Constructing mesh with non-default patches of size:" << nl;
898 forAll(patchNames, patchI)
900 Info<< " " << patchNames[patchI] << '\t'
901 << patchFaceVerts[patchI].size() << nl;
912 polyMesh::defaultRegion,
916 xferMove(polyPoints),
918 patchFaceVerts, // boundaryFaces,
919 patchNames, // boundaryPatchNames,
920 wordList(patchNames.size(), polyPatch::typeName), // boundaryPatchTypes,
921 "defaultFaces", // defaultFacesName
922 polyPatch::typeName, // defaultFacesType,
923 wordList(0) // boundaryPatchPhysicalTypes
928 Info<< "End\n" << endl;
934 // ************************************************************************* //