1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
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
25 \*---------------------------------------------------------------------------*/
27 #include "NASsurfaceFormat.H"
29 #include "IStringStream.H"
31 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
34 Foam::fileFormats::NASsurfaceFormat<Face>::NASsurfaceFormat
36 const fileName& filename
43 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
46 bool Foam::fileFormats::NASsurfaceFormat<Face>::read
48 const fileName& filename
51 const bool mustTriangulate = this->isTri();
54 IFstream is(filename);
59 "fileFormats::NASsurfaceFormat::read(const fileName&)"
61 << "Cannot read file " << filename
65 // Nastran index of points
66 DynamicList<label> pointId;
67 DynamicList<point> dynPoints;
68 DynamicList<Face> dynFaces;
69 DynamicList<label> dynZones;
70 DynamicList<label> dynSizes;
73 // assume the types are not intermixed
74 // leave faces that didn't have a group in 0
78 // Name for face group
81 // Ansa tags. Denoted by $ANSA_NAME.
82 // These will appear just before the first use of a type.
83 // We read them and store the PSHELL types which are used to name
86 word ansaType, ansaName;
88 // A single warning per unrecognized command
89 HashSet<word> unhandledCmd;
97 if (line.substr(0, 10) == "$ANSA_NAME")
99 string::size_type sem0 = line.find (';', 0);
100 string::size_type sem1 = line.find (';', sem0+1);
101 string::size_type sem2 = line.find (';', sem1+1);
106 && sem1 != string::npos
107 && sem2 != string::npos
112 IStringStream(line.substr(sem0+1, sem1-sem0-1))()
114 ansaType = line.substr(sem1+1, sem2-sem1-1);
118 if (rawName[rawName.size()-1] == '\r')
120 rawName = rawName.substr(1, rawName.size()-2);
124 rawName = rawName.substr(1, rawName.size()-1);
127 string::stripInvalid<word>(rawName);
130 // Info<< "ANSA tag for NastranID:" << ansaId
131 // << " of type " << ansaType
132 // << " name " << ansaName << endl;
137 // Hypermesh extension
138 // $HMNAME COMP 1"partName"
141 line.substr(0, 12) == "$HMNAME COMP"
142 && line.find ('"') != string::npos
145 label groupId = readLabel
147 IStringStream(line.substr(16, 16))()
150 IStringStream lineStream(line.substr(32));
153 lineStream >> rawName;
154 string::stripInvalid<word>(rawName);
156 word groupName(rawName);
157 nameLookup.insert(groupId, groupName);
159 // Info<< "group " << groupId << " => " << groupName << endl;
163 // Skip empty or comment
164 if (line.empty() || line[0] == '$')
169 // Check if character 72 is continuation
170 if (line.size() > 72 && line[72] == '+')
172 line = line.substr(0, 72);
179 if (buf.size() > 72 && buf[72] == '+')
181 line += buf.substr(8, 64);
185 line += buf.substr(8, buf.size()-8);
193 IStringStream lineStream(line);
201 label groupId = readLabel(IStringStream(line.substr(16,8))());
202 fTri[0] = readLabel(IStringStream(line.substr(24,8))());
203 fTri[1] = readLabel(IStringStream(line.substr(32,8))());
204 fTri[2] = readLabel(IStringStream(line.substr(40,8))());
206 // Convert groupID into zoneId
207 Map<label>::const_iterator fnd = lookup.find(groupId);
208 if (fnd != lookup.end())
212 // pshell types are intermixed
219 zoneI = dynSizes.size();
220 lookup.insert(groupId, zoneI);
222 // Info<< "zone" << zoneI << " => group " << groupId <<endl;
225 dynFaces.append(fTri);
226 dynZones.append(zoneI);
229 else if (cmd == "CQUAD4")
232 UList<label>& f = static_cast<UList<label>&>(fQuad);
234 label groupId = readLabel(IStringStream(line.substr(16,8))());
235 fQuad[0] = readLabel(IStringStream(line.substr(24,8))());
236 fQuad[1] = readLabel(IStringStream(line.substr(32,8))());
237 fQuad[2] = readLabel(IStringStream(line.substr(40,8))());
238 fQuad[3] = readLabel(IStringStream(line.substr(48,8))());
240 // Convert groupID into zoneId
241 Map<label>::const_iterator fnd = lookup.find(groupId);
242 if (fnd != lookup.end())
246 // pshell types are intermixed
253 zoneI = dynSizes.size();
254 lookup.insert(groupId, zoneI);
256 // Info<< "zone" << zoneI << " => group " << groupId <<endl;
262 dynFaces.append(triFace(f[0], f[1], f[2]));
263 dynFaces.append(triFace(f[0], f[2], f[3]));
264 dynZones.append(zoneI);
265 dynZones.append(zoneI);
266 dynSizes[zoneI] += 2;
270 dynFaces.append(Face(f));
271 dynZones.append(zoneI);
275 else if (cmd == "GRID")
277 label index = readLabel(IStringStream(line.substr(8,8))());
278 scalar x = parseNASCoord(line.substr(24, 8));
279 scalar y = parseNASCoord(line.substr(32, 8));
280 scalar z = parseNASCoord(line.substr(40, 8));
282 pointId.append(index);
283 dynPoints.append(point(x, y, z));
285 else if (cmd == "GRID*")
287 // Long format is on two lines with '*' continuation symbol
288 // on start of second line.
289 // Typical line (spaces compacted)
290 // GRID* 126 0 -5.55999875E+02 -5.68730474E+02
293 label index = readLabel(IStringStream(line.substr(8,16))());
294 scalar x = parseNASCoord(line.substr(40, 16));
295 scalar y = parseNASCoord(line.substr(56, 16));
302 "fileFormats::NASsurfaceFormat::read(const fileName&)"
304 << "Expected continuation symbol '*' when reading GRID*"
305 << " (double precision coordinate) format" << nl
306 << "Read:" << line << nl
307 << "File:" << is.name() << " line:" << is.lineNumber()
310 scalar z = parseNASCoord(line.substr(8, 16));
312 pointId.append(index);
313 dynPoints.append(point(x, y, z));
315 else if (cmd == "PSHELL")
317 // pshell type for zone names with the Ansa extension
318 label groupId = readLabel(IStringStream(line.substr(8,8))());
320 if (groupId == ansaId && ansaType == "PSHELL")
322 nameLookup.insert(ansaId, ansaName);
323 // Info<< "group " << groupId << " => " << ansaName << endl;
326 else if (unhandledCmd.insert(cmd))
328 Info<< "Unhandled Nastran command " << line << nl
329 << "File:" << is.name() << " line:" << is.lineNumber()
334 // Info<< "Read faces:" << dynFaces.size()
335 // << " points:" << dynPoints.size()
338 // transfer to normal lists
339 this->storedPoints().transfer(dynPoints);
344 // Build inverse mapping (NASTRAN pointId -> index)
345 Map<label> mapPointId(2*pointId.size());
348 mapPointId.insert(pointId[i], i);
355 Face& f = dynFaces[i];
358 f[fp] = mapPointId[f[fp]];
361 pointId.clearStorage();
365 // create default zone names, or from ANSA/Hypermesh information
366 List<word> names(dynSizes.size());
367 forAllConstIter(Map<label>, lookup, iter)
369 const label zoneI = iter();
370 const label groupI = iter.key();
372 Map<word>::const_iterator fnd = nameLookup.find(groupI);
373 if (fnd != nameLookup.end())
375 names[zoneI] = fnd();
379 names[zoneI] = word("zone") + ::Foam::name(zoneI);
383 this->sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
385 // add zones, culling empty ones
386 this->addZones(dynSizes, names, true);
392 // ************************************************************************* //