readNAS.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
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.
15 
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
19  for more details.
20 
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/>.
23 
24 Description
25  Nastran surface reader.
26 
27  - Uses the Ansa "$ANSA_NAME" or the Hypermesh "$HMNAME COMP" extensions
28  to obtain patch names.
29  - Handles Nastran short, long, and comma-separated free formats.
30  - Properly handles the Nastran compact floating point notation: \n
31  \verbatim
32  GRID 28 10.20269-.030265-2.358-8
33  \endverbatim
34 
35 
36 \*---------------------------------------------------------------------------*/
37 
38 #include "triSurface.H"
39 #include "IFstream.H"
40 #include "IStringStream.H"
41 
42 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
43 
44 namespace Foam
45 {
46 
47 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
48 
49 // Do weird things to extract number
50 static scalar parseNASCoord(const string& s)
51 {
52  size_t expSign = s.find_last_of("+-");
53 
54  if (expSign != string::npos && expSign > 0 && !isspace(s[expSign-1]))
55  {
56  scalar mantissa = readScalar(IStringStream(s.substr(0, expSign))());
57  scalar exponent = readScalar(IStringStream(s.substr(expSign+1))());
58 
59  if (s[expSign] == '-')
60  {
61  exponent = -exponent;
62  }
63  return mantissa*pow(10, exponent);
64  }
65  else
66  {
67  return readScalar(IStringStream(s)());
68  }
69 }
70 
71 
72 // Read a column of a given width from either a fixed-format NAS file, or a
73 // comma-separated free-format NAS file
74 static std::string readNASToken
75 (
76  const string& line,
77  const size_t& width,
78  size_t& index
79 )
80 {
81  size_t indexStart, indexEnd;
82 
83  indexStart = index;
84 
85  indexEnd = line.find(',', indexStart);
86  index = indexEnd + 1;
87 
88  if (indexEnd == std::string::npos)
89  {
90  indexEnd = indexStart + width;
91  index = indexEnd;
92  }
93 
94  return line.substr(indexStart, indexEnd - indexStart);
95 }
96 
97 
98 bool triSurface::readNAS(const fileName& fName)
99 {
100  IFstream is(fName);
101 
102  if (!is.good())
103  {
105  << "Cannot read file " << fName
106  << exit(FatalError);
107  }
108 
109  // coordinates of point
110  DynamicList<point> points;
111  // Nastran index of point
112  DynamicList<label> indices;
113  // Faces in terms of Nastran point indices
114  DynamicList<labelledTri> faces;
115  // From face group to patch
116  Map<label> groupToPatch;
117  label nPatches = 0;
118  // Name for face group
119  Map<word> groupToName;
120 
121  // Ansa tags. Denoted by $ANSA_NAME. These will appear just before the
122  // first use of a type. We read them and store the pshell types which
123  // are used to name the patches.
124  label ansaId = -1;
125  word ansaType;
126  string ansaName;
127 
128  // A single warning per unrecognized command
129  HashSet<word> unhandledCmd;
130 
131  while (is.good())
132  {
133  size_t linei = 0;
134  string line;
135  is.getLine(line);
136 
137  // Ansa extension
138  if (line.substr(0, 10) == "$ANSA_NAME")
139  {
140  string::size_type sem0 = line.find (';', 0);
141  string::size_type sem1 = line.find (';', sem0+1);
142  string::size_type sem2 = line.find (';', sem1+1);
143 
144  if
145  (
146  sem0 != string::npos
147  && sem1 != string::npos
148  && sem2 != string::npos
149  )
150  {
151  ansaId = readLabel
152  (
153  IStringStream(line.substr(sem0+1, sem1-sem0-1))()
154  );
155  ansaType = line.substr(sem1+1, sem2-sem1-1);
156 
157  string nameString;
158  is.getLine(ansaName);
159  if (ansaName[ansaName.size()-1] == '\r')
160  {
161  ansaName = ansaName.substr(1, ansaName.size()-2);
162  }
163  else
164  {
165  ansaName = ansaName.substr(1, ansaName.size()-1);
166  }
167 
168  // Info<< "ANSA tag for NastranID:" << ansaId
169  // << " of type " << ansaType
170  // << " name " << ansaName << endl;
171  }
172  }
173 
174 
175  // Hypermesh extension
176  // $HMNAME COMP 1"partName"
177  if
178  (
179  line.substr(0, 12) == "$HMNAME COMP"
180  && line.find ('"') != string::npos
181  )
182  {
183  label groupId = readLabel
184  (
185  IStringStream(line.substr(16, 16))()
186  );
187 
188  IStringStream lineStream(line.substr(32));
189 
190  string rawName;
191  lineStream >> rawName;
192 
193  groupToName.insert(groupId, string::validate<word>(rawName));
194  Info<< "group " << groupId << " => " << rawName << endl;
195  }
196 
197 
198  if (line.empty() || line[0] == '$')
199  {
200  // Skip empty or comment
201  continue;
202  }
203 
204  // Check if character 72 is continuation
205  if (line.size() > 72 && line[72] == '+')
206  {
207  line = line.substr(0, 72);
208 
209  while (true)
210  {
211  string buf;
212  is.getLine(buf);
213 
214  if (buf.size() > 72 && buf[72]=='+')
215  {
216  line += buf.substr(8, 64);
217  }
218  else
219  {
220  line += buf.substr(8, buf.size()-8);
221  break;
222  }
223  }
224  }
225 
226  // Read first word
227  word cmd(IStringStream(readNASToken(line, 8, linei))());
228 
229  if (cmd == "CTRIA3")
230  {
231  readNASToken(line, 8, linei);
232  label groupId =
233  readLabel(IStringStream(readNASToken(line, 8, linei))());
234  label a = readLabel(IStringStream(readNASToken(line, 8, linei))());
235  label b = readLabel(IStringStream(readNASToken(line, 8, linei))());
236  label c = readLabel(IStringStream(readNASToken(line, 8, linei))());
237 
238  // Convert group into patch
239  Map<label>::const_iterator iter = groupToPatch.find(groupId);
240 
241  label patchI;
242  if (iter == groupToPatch.end())
243  {
244  patchI = nPatches++;
245  groupToPatch.insert(groupId, patchI);
246  Info<< "patch " << patchI << " => group " << groupId << endl;
247  }
248  else
249  {
250  patchI = iter();
251  }
252 
253  faces.append(labelledTri(a, b, c, patchI));
254  }
255  else if (cmd == "CQUAD4")
256  {
257  readNASToken(line, 8, linei);
258  label groupId =
259  readLabel(IStringStream(readNASToken(line, 8, linei))());
260  label a = readLabel(IStringStream(readNASToken(line, 8, linei))());
261  label b = readLabel(IStringStream(readNASToken(line, 8, linei))());
262  label c = readLabel(IStringStream(readNASToken(line, 8, linei))());
263  label d = readLabel(IStringStream(readNASToken(line, 8, linei))());
264 
265  // Convert group into patch
266  Map<label>::const_iterator iter = groupToPatch.find(groupId);
267 
268  label patchI;
269  if (iter == groupToPatch.end())
270  {
271  patchI = nPatches++;
272  groupToPatch.insert(groupId, patchI);
273  Info<< "patch " << patchI << " => group " << groupId << endl;
274  }
275  else
276  {
277  patchI = iter();
278  }
279 
280  faces.append(labelledTri(a, b, c, patchI));
281  faces.append(labelledTri(c, d, a, patchI));
282  }
283  else if (cmd == "PSHELL")
284  {
285  // Read shell type since group gives patchnames
286  label groupId =
287  readLabel(IStringStream(readNASToken(line, 8, linei))());
288  if (groupId == ansaId && ansaType == "PSHELL")
289  {
290  groupToName.insert(groupId, string::validate<word>(ansaName));
291  Info<< "group " << groupId << " => " << ansaName << endl;
292  }
293  }
294  else if (cmd == "GRID")
295  {
296  label index =
297  readLabel(IStringStream(readNASToken(line, 8, linei))());
298  readNASToken(line, 8, linei);
299  scalar x = parseNASCoord(readNASToken(line, 8, linei));
300  scalar y = parseNASCoord(readNASToken(line, 8, linei));
301  scalar z = parseNASCoord(readNASToken(line, 8, linei));
302 
303  indices.append(index);
304  points.append(point(x, y, z));
305  }
306  else if (cmd == "GRID*")
307  {
308  // Long format is on two lines with '*' continuation symbol
309  // on start of second line.
310  // Typical line (spaces compacted)
311  // GRID* 126 0 -5.55999875E+02 -5.68730474E+02
312  // * 2.14897901E+02
313  label index =
314  readLabel(IStringStream(readNASToken(line, 8, linei))());
315  readNASToken(line, 8, linei);
316  scalar x = parseNASCoord(readNASToken(line, 16, linei));
317  scalar y = parseNASCoord(readNASToken(line, 16, linei));
318 
319  linei = 0;
320  is.getLine(line);
321  if (line[0] != '*')
322  {
324  << "Expected continuation symbol '*' when reading GRID*"
325  << " (double precision coordinate) output" << nl
326  << "Read:" << line << nl
327  << "File:" << is.name()
328  << " line:" << is.lineNumber()
329  << exit(FatalError);
330  }
331  readNASToken(line, 8, linei);
332  scalar z = parseNASCoord(readNASToken(line, 16, linei));
333 
334  indices.append(index);
335  points.append(point(x, y, z));
336  }
337  else if (unhandledCmd.insert(cmd))
338  {
339  Info<< "Unhandled Nastran command " << line << nl
340  << "File:" << is.name() << " line:" << is.lineNumber() << endl;
341  }
342  }
343 
344  points.shrink();
345  indices.shrink();
346  faces.shrink();
347 
348 
349  Info<< "Read triangles:" << faces.size() << " points:" << points.size()
350  << endl;
351 
352  {
353  // Build inverse mapping (index to point)
354  Map<label> indexToPoint(2*indices.size());
355  forAll(indices, i)
356  {
357  indexToPoint.insert(indices[i], i);
358  }
359 
360  // Relabel faces
361  forAll(faces, i)
362  {
363  labelledTri& f = faces[i];
364 
365  f[0] = indexToPoint[f[0]];
366  f[1] = indexToPoint[f[1]];
367  f[2] = indexToPoint[f[2]];
368  }
369  }
370 
371 
372  // Convert groupToPatch to patchList.
374 
375  forAllConstIter(Map<word>, groupToName, iter)
376  {
377  label patchI = groupToPatch[iter.key()];
378 
379  patches[patchI] = geometricSurfacePatch
380  (
381  "empty",
382  iter(),
383  patchI
384  );
385  }
386 
387  Info<< "patches:" << patches << endl;
388 
389  // Transfer DynamicLists to straight ones.
390  pointField allPoints(points.xfer());
391 
392  // Create triSurface
393  *this = triSurface(faces, patches, allPoints, true);
394 
395  return true;
396 }
397 
398 
399 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
400 
401 } // End namespace Foam
402 
403 // ************************************************************************* //
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Foam::PrimitivePatch< labelledTri, List, pointField, point >::points
const Field< point > & points() const
Return reference to global points.
Definition: PrimitivePatchTemplate.H:282
nPatches
label nPatches
Definition: readKivaGrid.H:402
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::geometricSurfacePatchList
List< geometricSurfacePatch > geometricSurfacePatchList
Definition: geometricSurfacePatchList.H:44
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::triSurface::patches
const geometricSurfacePatchList & patches() const
Definition: triSurface.H:301
IStringStream.H
forAllConstIter
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:39
Foam::parseNASCoord
static scalar parseNASCoord(const string &s)
Definition: readNAS.C:50
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::constant::physicoChemical::b
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:28
Foam::nl
static const char nl
Definition: Ostream.H:260
Foam::Info
messageStream Info
Foam::triSurface::triSurface
triSurface()
Construct null.
Definition: triSurface.C:608
size_type
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
Foam::pow
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Definition: dimensionedScalar.C:73
IFstream.H
Foam::triSurface::readNAS
bool readNAS(const fileName &)
Definition: readNAS.C:72
Foam::FatalError
error FatalError
Foam::IStringStream
Input from memory buffer stream.
Definition: IStringStream.H:49
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
s
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::readNASToken
static std::string readNASToken(const string &line, const size_t &width, size_t &index)
Definition: readNAS.C:75
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:318
Foam::readScalar
bool readScalar(const char *buf, doubleScalar &s)
Read whole of buf as a scalar. Return true if succesful.
Definition: doubleScalar.H:63
f
labelList f(nPoints)
x
x
Definition: LISASMDCalcMethod2.H:52
Foam::readLabel
label readLabel(Istream &is)
Definition: label.H:64
Foam::line
A line primitive.
Definition: line.H:56
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
Foam::DelaunayMeshTools::allPoints
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
Foam::point
vector point
Point is a vector.
Definition: point.H:41
Foam::isspace
bool isspace(char c)
Definition: char.H:53
y
scalar y
Definition: LISASMDCalcMethod1.H:14
Foam::Map< label >::const_iterator
HashTable< T, label, Hash< label > >::const_iterator const_iterator
Definition: Map.H:59