NASsurfaceFormat.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2018 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 \*---------------------------------------------------------------------------*/
25 
26 #include "NASsurfaceFormat.H"
27 #include "IFstream.H"
28 #include "IStringStream.H"
29 
30 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
31 
32 template<class Face>
34 (
35  const fileName& filename
36 )
37 {
38  read(filename);
39 }
40 
41 
42 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
43 
44 template<class Face>
46 (
47  const fileName& filename
48 )
49 {
50  const bool mustTriangulate = this->isTri();
51  this->clear();
52 
53  IFstream is(filename);
54  if (!is.good())
55  {
57  << "Cannot read file " << filename
58  << exit(FatalError);
59  }
60 
61  // Nastran index of points
62  DynamicList<label> pointId;
63  DynamicList<point> dynPoints;
64  DynamicList<Face> dynFaces;
65  DynamicList<label> dynZones;
66  DynamicList<label> dynSizes;
68 
69  // assume the types are not intermixed
70  // leave faces that didn't have a group in 0
71  bool sorted = true;
72  label zoneI = 0;
73 
74  // Name for face group
75  Map<word> nameLookup;
76 
77  // Ansa tags. Denoted by $ANSA_NAME.
78  // These will appear just before the first use of a type.
79  // We read them and store the PSHELL types which are used to name
80  // the zones.
81  label ansaId = -1;
82  word ansaType, ansaName;
83 
84  // A single warning per unrecognized command
85  HashSet<word> unhandledCmd;
86 
87  while (is.good())
88  {
89  string line;
90  is.getLine(line);
91 
92  // Ansa extension
93  if (line.substr(0, 10) == "$ANSA_NAME")
94  {
95  string::size_type sem0 = line.find (';', 0);
96  string::size_type sem1 = line.find (';', sem0+1);
97  string::size_type sem2 = line.find (';', sem1+1);
98 
99  if
100  (
101  sem0 != string::npos
102  && sem1 != string::npos
103  && sem2 != string::npos
104  )
105  {
106  ansaId = readLabel
107  (
108  IStringStream(line.substr(sem0+1, sem1-sem0-1))()
109  );
110  ansaType = line.substr(sem1+1, sem2-sem1-1);
111 
112  string rawName;
113  is.getLine(rawName);
114  if (rawName[rawName.size()-1] == '\r')
115  {
116  rawName = rawName.substr(1, rawName.size()-2);
117  }
118  else
119  {
120  rawName = rawName.substr(1, rawName.size()-1);
121  }
122 
123  string::stripInvalid<word>(rawName);
124  ansaName = rawName;
125 
126  // Info<< "ANSA tag for NastranID:" << ansaId
127  // << " of type " << ansaType
128  // << " name " << ansaName << endl;
129  }
130  }
131 
132 
133  // Hypermesh extension
134  // $HMNAME COMP 1"partName"
135  if
136  (
137  line.substr(0, 12) == "$HMNAME COMP"
138  && line.find ('"') != string::npos
139  )
140  {
141  label groupId = readLabel
142  (
143  IStringStream(line.substr(16, 16))()
144  );
145 
146  IStringStream lineStream(line.substr(32));
147 
148  string rawName;
149  lineStream >> rawName;
150  string::stripInvalid<word>(rawName);
151 
152  word groupName(rawName);
153  nameLookup.insert(groupId, groupName);
154 
155  // Info<< "group " << groupId << " => " << groupName << endl;
156  }
157 
158 
159  // Skip empty or comment
160  if (line.empty() || line[0] == '$')
161  {
162  continue;
163  }
164 
165  // Check if character 72 is continuation
166  if (line.size() > 72 && line[72] == '+')
167  {
168  line = line.substr(0, 72);
169 
170  while (true)
171  {
172  string buf;
173  is.getLine(buf);
174 
175  if (buf.size() > 72 && buf[72] == '+')
176  {
177  line += buf.substr(8, 64);
178  }
179  else
180  {
181  line += buf.substr(8, buf.size()-8);
182  break;
183  }
184  }
185  }
186 
187 
188  // Read first word
189  IStringStream lineStream(line);
190  word cmd;
191  lineStream >> cmd;
192 
193  if (cmd == "CTRIA3")
194  {
195  triFace fTri;
196 
197  label groupId = readLabel(IStringStream(line.substr(16,8))());
198  fTri[0] = readLabel(IStringStream(line.substr(24,8))());
199  fTri[1] = readLabel(IStringStream(line.substr(32,8))());
200  fTri[2] = readLabel(IStringStream(line.substr(40,8))());
201 
202  // Convert groupID into zoneId
203  Map<label>::const_iterator fnd = lookup.find(groupId);
204  if (fnd != lookup.end())
205  {
206  if (zoneI != fnd())
207  {
208  // pshell types are intermixed
209  sorted = false;
210  }
211  zoneI = fnd();
212  }
213  else
214  {
215  zoneI = dynSizes.size();
216  lookup.insert(groupId, zoneI);
217  dynSizes.append(0);
218  // Info<< "zone" << zoneI << " => group " << groupId <<endl;
219  }
220 
221  dynFaces.append(fTri);
222  dynZones.append(zoneI);
223  dynSizes[zoneI]++;
224  }
225  else if (cmd == "CQUAD4")
226  {
227  face fQuad(4);
228  labelUList& f = static_cast<labelUList&>(fQuad);
229 
230  label groupId = readLabel(IStringStream(line.substr(16,8))());
231  fQuad[0] = readLabel(IStringStream(line.substr(24,8))());
232  fQuad[1] = readLabel(IStringStream(line.substr(32,8))());
233  fQuad[2] = readLabel(IStringStream(line.substr(40,8))());
234  fQuad[3] = readLabel(IStringStream(line.substr(48,8))());
235 
236  // Convert groupID into zoneId
237  Map<label>::const_iterator fnd = lookup.find(groupId);
238  if (fnd != lookup.end())
239  {
240  if (zoneI != fnd())
241  {
242  // pshell types are intermixed
243  sorted = false;
244  }
245  zoneI = fnd();
246  }
247  else
248  {
249  zoneI = dynSizes.size();
250  lookup.insert(groupId, zoneI);
251  dynSizes.append(0);
252  // Info<< "zone" << zoneI << " => group " << groupId <<endl;
253  }
254 
255 
256  if (mustTriangulate)
257  {
258  dynFaces.append(triFace(f[0], f[1], f[2]));
259  dynFaces.append(triFace(f[0], f[2], f[3]));
260  dynZones.append(zoneI);
261  dynZones.append(zoneI);
262  dynSizes[zoneI] += 2;
263  }
264  else
265  {
266  dynFaces.append(Face(f));
267  dynZones.append(zoneI);
268  dynSizes[zoneI]++;
269  }
270  }
271  else if (cmd == "GRID")
272  {
273  label index = readLabel(IStringStream(line.substr(8,8))());
274  scalar x = parseNASCoord(line.substr(24, 8));
275  scalar y = parseNASCoord(line.substr(32, 8));
276  scalar z = parseNASCoord(line.substr(40, 8));
277 
278  pointId.append(index);
279  dynPoints.append(point(x, y, z));
280  }
281  else if (cmd == "GRID*")
282  {
283  // Long format is on two lines with '*' continuation symbol
284  // on start of second line.
285  // Typical line (spaces compacted)
286  // GRID* 126 0 -5.55999875E+02 -5.68730474E+02
287  // * 2.14897901E+02
288 
289  label index = readLabel(IStringStream(line.substr(8,16))());
290  scalar x = parseNASCoord(line.substr(40, 16));
291  scalar y = parseNASCoord(line.substr(56, 16));
292 
293  is.getLine(line);
294  if (line[0] != '*')
295  {
297  << "Expected continuation symbol '*' when reading GRID*"
298  << " (double precision coordinate) format" << nl
299  << "Read:" << line << nl
300  << "File:" << is.name() << " line:" << is.lineNumber()
301  << exit(FatalError);
302  }
303  scalar z = parseNASCoord(line.substr(8, 16));
304 
305  pointId.append(index);
306  dynPoints.append(point(x, y, z));
307  }
308  else if (cmd == "PSHELL")
309  {
310  // pshell type for zone names with the Ansa extension
311  label groupId = readLabel(IStringStream(line.substr(8,8))());
312 
313  if (groupId == ansaId && ansaType == "PSHELL")
314  {
315  nameLookup.insert(ansaId, ansaName);
316  // Info<< "group " << groupId << " => " << ansaName << endl;
317  }
318  }
319  else if (unhandledCmd.insert(cmd))
320  {
321  Info<< "Unhandled Nastran command " << line << nl
322  << "File:" << is.name() << " line:" << is.lineNumber()
323  << endl;
324  }
325  }
326 
327  // Info<< "Read faces:" << dynFaces.size()
328  // << " points:" << dynPoints.size()
329  // << endl;
330 
331  // transfer to normal lists
332  this->storedPoints().transfer(dynPoints);
333 
334  pointId.shrink();
335  dynFaces.shrink();
336 
337  // Build inverse mapping (NASTRAN pointId -> index)
338  Map<label> mapPointId(2*pointId.size());
339  forAll(pointId, i)
340  {
341  mapPointId.insert(pointId[i], i);
342  }
343 
344  // Relabel faces
345  // ~~~~~~~~~~~~~
346  forAll(dynFaces, i)
347  {
348  Face& f = dynFaces[i];
349  forAll(f, fp)
350  {
351  f[fp] = mapPointId[f[fp]];
352  }
353  }
354  pointId.clearStorage();
355  mapPointId.clear();
356 
357 
358  // create default zone names, or from ANSA/Hypermesh information
359  List<word> names(dynSizes.size());
360  forAllConstIter(Map<label>, lookup, iter)
361  {
362  const label zoneI = iter();
363  const label groupI = iter.key();
364 
365  Map<word>::const_iterator fnd = nameLookup.find(groupI);
366  if (fnd != nameLookup.end())
367  {
368  names[zoneI] = fnd();
369  }
370  else
371  {
372  names[zoneI] = word("zone") + ::Foam::name(zoneI);
373  }
374  }
375 
376  this->sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
377 
378  // add zones, culling empty ones
379  this->addZones(dynSizes, names, true);
380 
381  return true;
382 }
383 
384 
385 // ************************************************************************* //
A HashTable with keys but without contents.
Definition: HashSet.H:59
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
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
A line primitive.
Definition: line.H:56
A class for handling file names.
Definition: fileName.H:69
An STL-conforming const_iterator.
Definition: HashTable.H:481
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
static iteratorEnd end()
iteratorEnd set to beyond the end of any HashTable
Definition: HashTable.H:110
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
tUEqn clear()
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
label lineNumber() const
Return current stream line number.
Definition: IOstream.H:438
void read(Istream &, label &, const dictionary &)
In-place read with dictionary lookup.
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
bool insert(const label &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
iterator find(const Key &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:142
scalar y
stressControl lookup("compactNormalStress") >> compactNormalStress
virtual bool read(const fileName &)
Read from a file.
A class for handling words, derived from string.
Definition: word.H:59
A triangular face using a FixedList of labels corresponding to mesh vertices.
Definition: triFace.H:68
face triFace(3)
const fileName & name() const
Return the name of the stream.
Definition: IFstream.H:116
Xfer< List< T > > xfer()
Transfer contents to the Xfer container as a plain List.
Definition: DynamicListI.H:283
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:292
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
label readLabel(Istream &is)
Definition: label.H:64
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:61
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:240
static const char nl
Definition: Ostream.H:265
Input from file stream.
Definition: IFstream.H:81
labelList f(nPoints)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
vector point
Point is a vector.
Definition: point.H:41
Input from memory buffer stream.
Definition: IStringStream.H:49
void clearStorage()
Clear the list and delete storage.
Definition: DynamicListI.H:231
messageStream Info
static scalar parseNASCoord(const string &s)
Definition: readNAS.C:50
ISstream & getLine(string &)
Raw, low-level getline into a string function.
Definition: ISstreamI.H:77