1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 Nastran surface reader.
28 - Uses the Ansa "$ANSA_NAME" or the Hypermesh "$HMNAME COMP" extensions
29 to obtain patch names.
30 - Handles Nastran short and long formats, but not free format.
31 - Properly handles the Nastran compact floating point notation: \n
33 GRID 28 10.20269-.030265-2.358-8
37 \*---------------------------------------------------------------------------*/
39 #include "triSurface.H"
41 #include "IStringStream.H"
43 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
48 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
50 // Do weird things to extract number
51 static scalar parseNASCoord(const string& s)
53 size_t expSign = s.find_last_of("+-");
55 if (expSign != string::npos && expSign > 0 && !isspace(s[expSign-1]))
57 scalar mantissa = readScalar(IStringStream(s.substr(0, expSign))());
58 scalar exponent = readScalar(IStringStream(s.substr(expSign+1))());
60 if (s[expSign] == '-')
64 return mantissa*pow(10, exponent);
68 return readScalar(IStringStream(s)());
73 bool triSurface::readNAS(const fileName& fName)
79 FatalErrorIn("triSurface::readNAS(const fileName&)")
80 << "Cannot read file " << fName
84 // coordinates of point
85 DynamicList<point> points;
86 // Nastran index of point
87 DynamicList<label> indices;
88 // Faces in terms of Nastran point indices
89 DynamicList<labelledTri> faces;
90 // From face group to patch
91 Map<label> groupToPatch;
93 // Name for face group
94 Map<word> groupToName;
96 // Ansa tags. Denoted by $ANSA_NAME. These will appear just before the
97 // first use of a type. We read them and store the pshell types which
98 // are used to name the patches.
103 // A single warning per unrecognized command
104 HashSet<word> unhandledCmd;
112 if (line.substr(0, 10) == "$ANSA_NAME")
114 string::size_type sem0 = line.find (';', 0);
115 string::size_type sem1 = line.find (';', sem0+1);
116 string::size_type sem2 = line.find (';', sem1+1);
121 && sem1 != string::npos
122 && sem2 != string::npos
127 IStringStream(line.substr(sem0+1, sem1-sem0-1))()
129 ansaType = line.substr(sem1+1, sem2-sem1-1);
132 is.getLine(ansaName);
133 if (ansaName[ansaName.size()-1] == '\r')
135 ansaName = ansaName.substr(1, ansaName.size()-2);
139 ansaName = ansaName.substr(1, ansaName.size()-1);
142 // Info<< "ANSA tag for NastranID:" << ansaId
143 // << " of type " << ansaType
144 // << " name " << ansaName << endl;
149 // Hypermesh extension
150 // $HMNAME COMP 1"partName"
153 line.substr(0, 12) == "$HMNAME COMP"
154 && line.find ('"') != string::npos
157 label groupId = readLabel
159 IStringStream(line.substr(16, 16))()
162 IStringStream lineStream(line.substr(32));
165 lineStream >> rawName;
167 groupToName.insert(groupId, string::validate<word>(rawName));
168 Info<< "group " << groupId << " => " << rawName << endl;
172 if (line.empty() || line[0] == '$')
174 // Skip empty or comment
178 // Check if character 72 is continuation
179 if (line.size() > 72 && line[72] == '+')
181 line = line.substr(0, 72);
188 if (buf.size() > 72 && buf[72]=='+')
190 line += buf.substr(8, 64);
194 line += buf.substr(8, buf.size()-8);
201 IStringStream lineStream(line);
207 label groupId = readLabel(IStringStream(line.substr(16,8))());
208 label a = readLabel(IStringStream(line.substr(24,8))());
209 label b = readLabel(IStringStream(line.substr(32,8))());
210 label c = readLabel(IStringStream(line.substr(40,8))());
213 // Convert group into patch
214 Map<label>::const_iterator iter = groupToPatch.find(groupId);
217 if (iter == groupToPatch.end())
220 groupToPatch.insert(groupId, patchI);
221 Info<< "patch " << patchI << " => group " << groupId << endl;
228 faces.append(labelledTri(a, b, c, patchI));
230 else if (cmd == "CQUAD4")
232 label groupId = readLabel(IStringStream(line.substr(16,8))());
233 label a = readLabel(IStringStream(line.substr(24,8))());
234 label b = readLabel(IStringStream(line.substr(32,8))());
235 label c = readLabel(IStringStream(line.substr(40,8))());
236 label d = readLabel(IStringStream(line.substr(48,8))());
238 // Convert group into patch
239 Map<label>::const_iterator iter = groupToPatch.find(groupId);
242 if (iter == groupToPatch.end())
245 groupToPatch.insert(groupId, patchI);
246 Info<< "patch " << patchI << " => group " << groupId << endl;
253 faces.append(labelledTri(a, b, c, patchI));
254 faces.append(labelledTri(c, d, a, patchI));
256 else if (cmd == "PSHELL")
258 // Read shell type since group gives patchnames
259 label groupId = readLabel(IStringStream(line.substr(8,8))());
260 if (groupId == ansaId && ansaType == "PSHELL")
262 groupToName.insert(groupId, string::validate<word>(ansaName));
263 Info<< "group " << groupId << " => " << ansaName << endl;
266 else if (cmd == "GRID")
268 label index = readLabel(IStringStream(line.substr(8,8))());
269 scalar x = parseNASCoord(line.substr(24, 8));
270 scalar y = parseNASCoord(line.substr(32, 8));
271 scalar z = parseNASCoord(line.substr(40, 8));
273 indices.append(index);
274 points.append(point(x, y, z));
276 else if (cmd == "GRID*")
278 // Long format is on two lines with '*' continuation symbol
279 // on start of second line.
280 // Typical line (spaces compacted)
281 // GRID* 126 0 -5.55999875E+02 -5.68730474E+02
284 label index = readLabel(IStringStream(line.substr(8,16))());
285 scalar x = parseNASCoord(line.substr(40, 16));
286 scalar y = parseNASCoord(line.substr(56, 16));
291 FatalErrorIn("triSurface::readNAS(const fileName&)")
292 << "Expected continuation symbol '*' when reading GRID*"
293 << " (double precision coordinate) output" << nl
294 << "Read:" << line << nl
295 << "File:" << is.name()
296 << " line:" << is.lineNumber()
299 scalar z = parseNASCoord(line.substr(8, 16));
301 indices.append(index);
302 points.append(point(x, y, z));
304 else if (unhandledCmd.insert(cmd))
306 Info<< "Unhandled Nastran command " << line << nl
307 << "File:" << is.name() << " line:" << is.lineNumber() << endl;
316 Info<< "Read triangles:" << faces.size() << " points:" << points.size()
320 // Build inverse mapping (index to point)
321 Map<label> indexToPoint(2*indices.size());
324 indexToPoint.insert(indices[i], i);
330 labelledTri& f = faces[i];
332 f[0] = indexToPoint[f[0]];
333 f[1] = indexToPoint[f[1]];
334 f[2] = indexToPoint[f[2]];
339 // Convert groupToPatch to patchList.
340 geometricSurfacePatchList patches(nPatches);
342 forAllConstIter(Map<word>, groupToName, iter)
344 label patchI = groupToPatch[iter.key()];
346 patches[patchI] = geometricSurfacePatch
354 Info<< "patches:" << patches << endl;
356 // Transfer DynamicLists to straight ones.
357 pointField allPoints(points.xfer());
360 *this = triSurface(faces, patches, allPoints, true);
366 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
368 } // End namespace Foam
370 // ************************************************************************* //