1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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.
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
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/>.
25 Converts neutral file format as written by Netgen v4.4.
30 1.000000 1.000000 1.000000
31 0.000000 1.000000 1.000000
32 0.000000 0.000000 1.000000
33 1.000000 0.000000 1.000000
34 0.000000 1.000000 0.000000
35 1.000000 1.000000 0.000000
36 1.000000 0.000000 0.000000
37 0.000000 0.000000 0.000000
38 0.500000 0.500000 0.500000
67 - reverse order of boundary faces using geometric test.
68 (not very space efficient)
69 - order of tet vertices only tested on one file.
70 - all patch/cell/vertex numbers offset by one.
72 \*---------------------------------------------------------------------------*/
78 #include "polyPatch.H"
79 #include "cellModeller.H"
84 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
88 int main(int argc, char *argv[])
90 argList::validArgs.append("Neutral file");
92 # include "setRootCase.H"
93 # include "createTime.H"
95 IFstream str(args[1]);
100 label nNodes(readLabel(str));
102 Info<< "nNodes:" << nNodes << endl;
104 pointField points(nNodes);
106 forAll(points, pointI)
112 points[pointI] = point(x, y, z);
118 label nTets(readLabel(str));
120 Info<< "nTets:" << nTets << endl;
122 const cellModel& tet = *(cellModeller::lookup("tet"));
124 cellShapeList cells(nTets);
126 labelList tetPoints(4);
130 label domain(readLabel(str));
134 WarningIn(args.executable())
135 << "Cannot handle multiple domains"
136 << nl << "Ignoring domain " << domain << " setting on line "
137 << str.lineNumber() << endl;
140 tetPoints[1] = readLabel(str) - 1;
141 tetPoints[0] = readLabel(str) - 1;
142 tetPoints[2] = readLabel(str) - 1;
143 tetPoints[3] = readLabel(str) - 1;
145 cells[cellI] = cellShape(tet, tetPoints);
150 label nFaces(readLabel(str));
152 Info<< "nFaces:" << nFaces << endl;
154 // Unsorted boundary faces
155 faceList boundaryFaces(nFaces);
157 // For each boundary faces the Foam patchID
158 labelList boundaryPatch(nFaces, -1);
163 // Boundary faces as three vertices
164 HashTable<label, triFace, Hash<triFace> > vertsToBoundary(nFaces);
166 forAll(boundaryFaces, faceI)
168 label patchI(readLabel(str));
172 FatalErrorIn(args.executable())
173 << "Invalid boundary region number " << patchI
174 << " on line " << str.lineNumber()
179 maxPatch = max(maxPatch, patchI);
181 triFace tri(readLabel(str)-1, readLabel(str)-1, readLabel(str)-1);
183 // Store boundary face as is for now. Later on reverse it.
184 boundaryFaces[faceI].setSize(3);
185 boundaryFaces[faceI][0] = tri[0];
186 boundaryFaces[faceI][1] = tri[1];
187 boundaryFaces[faceI][2] = tri[2];
188 boundaryPatch[faceI] = patchI;
190 vertsToBoundary.insert(tri, faceI);
193 label nPatches = maxPatch + 1;
196 // Use hash of points to get owner cell and orient the boundary face.
197 // For storage reasons I store the triangles and loop over the cells instead
198 // of the other way around (store cells and loop over triangles) though
199 // that would be faster.
202 const cellShape& cll = cells[cellI];
204 // Get the four (outwards pointing) faces of the cell
205 faceList tris(cll.faces());
209 const face& f = tris[i];
211 // Is there any boundary face with same vertices?
212 // (uses commutative hash)
213 HashTable<label, triFace, Hash<triFace> >::iterator iter =
214 vertsToBoundary.find(triFace(f[0], f[1], f[2]));
216 if (iter != vertsToBoundary.end())
218 label faceI = iter();
219 const triFace& tri = iter.key();
221 // Determine orientation of tri v.s. cell centre.
222 point cc(cll.centre(points));
223 point fc(tri.centre(points));
224 vector fn(tri.normal(points));
226 if (((fc - cc) & fn) < 0)
228 // Boundary face points inwards. Flip.
229 boundaryFaces[faceI].flip();
232 // Done this face so erase from hash
233 vertsToBoundary.erase(iter);
239 if (vertsToBoundary.size())
241 // Didn't find cells connected to boundary faces.
242 WarningIn(args.executable())
243 << "There are boundary faces without attached cells."
244 << "Boundary faces (as triFaces):" << vertsToBoundary.toc()
249 // Storage for boundary faces sorted into patches
251 faceListList patchFaces(nPatches);
253 wordList patchNames(nPatches);
255 forAll(patchNames, patchI)
257 patchNames[patchI] = word("patch") + name(patchI);
260 wordList patchTypes(nPatches, polyPatch::typeName);
261 word defaultFacesName = "defaultFaces";
262 word defaultFacesType = polyPatch::typeName;
263 wordList patchPhysicalTypes(nPatches, polyPatch::typeName);
266 // Sort boundaryFaces by patch.
267 List<DynamicList<face> > allPatchFaces(nPatches);
269 forAll(boundaryPatch, faceI)
271 label patchI = boundaryPatch[faceI];
273 allPatchFaces[patchI].append(boundaryFaces[faceI]);
276 Info<< "Patches:" << nl
277 << "\tNeutral Boundary\tPatch name\tSize" << nl
278 << "\t----------------\t----------\t----" << endl;
280 forAll(allPatchFaces, patchI)
282 Info<< '\t' << patchI << "\t\t\t"
283 << patchNames[patchI] << "\t\t"
284 << allPatchFaces[patchI].size() << endl;
286 patchFaces[patchI].transfer(allPatchFaces[patchI]);
297 polyMesh::defaultRegion,
311 Info<< "Writing mesh to " << runTime.constant() << endl << endl;
316 Info<< "End\n" << endl;
322 // ************************************************************************* //