nastranSurfaceWriter.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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2012-2016 OpenFOAM Foundation
9  Copyright (C) 2015-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "nastranSurfaceWriter.H"
30 #include "Pair.H"
31 #include "IOmanip.H"
32 #include "OSspecific.H"
33 #include "surfaceWriterMethods.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40 namespace surfaceWriters
41 {
42  defineTypeName(nastranWriter);
43  addToRunTimeSelectionTable(surfaceWriter, nastranWriter, word);
44  addToRunTimeSelectionTable(surfaceWriter, nastranWriter, wordDict);
45 }
46 }
47 
48 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 
50 // Field writing implementation
52 
53 // Field writing methods
55 
56 
57 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
58 
59 Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeKeyword
60 (
61  Ostream& os,
62  const word& keyword
63 ) const
64 {
65  return fileFormats::NASCore::writeKeyword(os, keyword, writeFormat_);
66 }
67 
68 
69 void Foam::surfaceWriters::nastranWriter::writeCoord
70 (
71  Ostream& os,
72  const point& pt,
73  const label pointI
74 ) const
75 {
76  // Fixed short/long formats:
77  // 1 GRID
78  // 2 ID : point ID - requires starting index of 1
79  // 3 CP : coordinate system ID (blank)
80  // 4 X1 : point x coordinate
81  // 5 X2 : point x coordinate
82  // 6 X3 : point x coordinate
83  // 7 CD : coordinate system for displacements (blank)
84  // 8 PS : single point constraints (blank)
85  // 9 SEID : super-element ID
86 
87  writeKeyword(os, "GRID") << separator_;
88 
89  os.setf(std::ios_base::right);
90 
91  writeValue(os, pointI+1) << separator_;
92  writeValue(os, "") << separator_;
93  writeValue(os, pt.x()) << separator_;
94  writeValue(os, pt.y()) << separator_;
95 
96  switch (writeFormat_)
97  {
98  case fieldFormat::SHORT :
99  {
100  os << setw(8) << pt.z() << nl;
101  os.unsetf(std::ios_base::right);
102  break;
103  }
104 
105  case fieldFormat::LONG :
106  {
107  os << nl;
108  os.unsetf(std::ios_base::right);
109  writeKeyword(os, "");
110  os.setf(std::ios_base::right);
111 
112  writeValue(os, pt.z()) << nl;
113  break;
114  }
115 
116  case fieldFormat::FREE :
117  {
118  writeValue(os, pt.z()) << nl;
119  break;
120  }
121  }
122 
123  os.unsetf(std::ios_base::right);
124 }
125 
126 
127 void Foam::surfaceWriters::nastranWriter::writeFace
128 (
129  Ostream& os,
130  const word& faceType,
131  const labelUList& facePts,
132  const label elemId,
133  const label propId
134 ) const
135 {
136  // Only valid surface elements are CTRIA3 and CQUAD4
137 
138  // Fixed short/long formats:
139  // 1 CQUAD4
140  // 2 EID : element ID
141  // 3 PID : property element ID; default = EID (blank)
142  // 4 G1 : grid point index - requires starting index of 1
143  // 5 G2 : grid point index
144  // 6 G3 : grid point index
145  // 7 G4 : grid point index
146  // 8 onwards - not used
147 
148  // For CTRIA3 elements, cols 7 onwards are not used
149 
150  writeKeyword(os, faceType) << separator_;
151 
152  os.setf(std::ios_base::right);
153 
154  writeValue(os, elemId) << separator_;
155  writeValue(os, propId);
156 
157  switch (writeFormat_)
158  {
159  case fieldFormat::SHORT :
160  {
161  for (const label pointi : facePts)
162  {
163  writeValue(os, pointi + 1);
164  }
165 
166  break;
167  }
168 
169  case fieldFormat::LONG :
170  {
171  forAll(facePts, i)
172  {
173  writeValue(os, facePts[i] + 1);
174  if (i == 1)
175  {
176  os << nl;
177  os.unsetf(std::ios_base::right);
178  writeKeyword(os, "");
179  os.setf(std::ios_base::right);
180  }
181  }
182 
183  break;
184  }
185 
186  case fieldFormat::FREE :
187  {
188  for (const label pointi : facePts)
189  {
190  os << separator_;
191  writeValue(os, pointi + 1);
192  }
193 
194  break;
195  }
196  }
197 
198  os << nl;
199  os.unsetf(std::ios_base::right);
200 }
201 
202 
203 void Foam::surfaceWriters::nastranWriter::writeGeometry
204 (
205  Ostream& os,
206  const meshedSurf& surf,
207  labelList& decompOffsets,
208  DynamicList<face>& decompFaces
209 ) const
210 {
211  const pointField& points = surf.points();
212  const faceList& faces = surf.faces();
213  const labelList& zones = surf.zoneIds();
214  const labelList& elemIds = surf.faceIds();
215 
216  // Possible to use faceIds?
217  bool useOrigFaceIds = (elemIds.size() == faces.size());
218 
219  if (useOrigFaceIds)
220  {
221  // Not possible with on-the-fly face decomposition
222  for (const auto& f : faces)
223  {
224  if (f.size() > 4)
225  {
226  useOrigFaceIds = false;
227  break;
228  }
229  }
230  }
231 
232 
233  // Write points
234 
235  os << '$' << nl
236  << "$ Points" << nl
237  << '$' << nl;
238 
239  forAll(points, pointi)
240  {
241  writeCoord(os, points[pointi]*geometryScale_, pointi);
242  }
243 
244  // Write faces, with on-the-fly decomposition (triangulation)
245  decompOffsets.resize(faces.size()+1);
246  decompFaces.clear();
247 
248  decompOffsets[0] = 0; // The first offset is always zero
249 
250  os << '$' << nl
251  << "$ Faces" << nl
252  << '$' << nl;
253 
254  label elemId = 0; // The element-id
255  forAll(faces, facei)
256  {
257  const face& f = faces[facei];
258 
259  if (useOrigFaceIds)
260  {
261  // When available and not decomposed
262  elemId = elemIds[facei];
263  }
264 
265  // 1-offset for PID
266  const label propId = 1 + (facei < zones.size() ? zones[facei] : 0);
267 
268  if (f.size() == 3)
269  {
270  writeFace(os, "CTRIA3", f, ++elemId, propId);
271  }
272  else if (f.size() == 4)
273  {
274  writeFace(os, "CQUAD4", f, ++elemId, propId);
275  }
276  else
277  {
278  // Decompose into tris
279  f.triangles(points, decompFaces);
280 
281  for
282  (
283  label decompi = decompOffsets[facei];
284  decompi < decompFaces.size();
285  ++decompi
286  )
287  {
288  writeFace
289  (
290  os,
291  "CTRIA3",
292  decompFaces[decompi],
293  ++elemId,
294  propId
295  );
296  }
297  }
298 
299  // The end offset, which is the next begin offset
300  decompOffsets[facei+1] = decompFaces.size();
301  }
302 }
303 
304 
305 Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeFooter
306 (
307  Ostream& os,
308  const meshedSurf& surf
309 ) const
310 {
311  // Zone id have been used for the PID. Find unique values.
312 
313  labelList pidsUsed = labelHashSet(surf.zoneIds()).sortedToc();
314  if (pidsUsed.empty())
315  {
316  pidsUsed.resize(1, Zero); // fallback
317  }
318 
319  for (auto pid : pidsUsed)
320  {
321  writeKeyword(os, "PSHELL") << separator_;
322  writeValue(os, pid+1); // 1-offset for PID
323 
324  for (label i = 0; i < 7; ++i)
325  {
326  // Dummy values
327  os << separator_;
328  writeValue(os, 1);
329  }
330  os << nl;
331  }
332 
333 
334  // Use single material ID
335 
336  const label MID = 1;
337 
338  writeKeyword(os, "MAT1") << separator_;
339  writeValue(os, MID);
340 
341  for (label i = 0; i < 7; ++i)
342  {
343  // Dummy values
344  os << separator_;
345  writeValue(os, "");
346  }
347  os << nl;
348 
349  return os;
350 }
351 
352 
353 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
354 
356 :
357  surfaceWriter(),
358  writeFormat_(fieldFormat::SHORT),
359  fieldMap_(),
360  geometryScale_(1),
361  fieldScale_(),
362  separator_()
363 {}
364 
365 
367 (
368  const dictionary& options
369 )
370 :
371  surfaceWriter(options),
372  writeFormat_
373  (
375  (
376  "format",
377  options,
378  fieldFormat::LONG
379  )
380  ),
381  fieldMap_(),
382  geometryScale_(options.getOrDefault<scalar>("scale", 1)),
383  fieldScale_(options.subOrEmptyDict("fieldScale")),
384  separator_()
385 {
386  if (writeFormat_ == fieldFormat::FREE)
387  {
388  separator_ = ",";
389  }
390 
391  List<Pair<word>> fieldPairs;
392  options.readEntry("fields", fieldPairs);
393 
394  for (const Pair<word>& item : fieldPairs)
395  {
396  // (field name => load format)
397  fieldMap_.insert
398  (
399  item.first(),
401  );
402  }
403 }
404 
405 
407 (
408  const meshedSurf& surf,
409  const fileName& outputPath,
410  bool parallel,
411  const dictionary& options
412 )
413 :
414  nastranWriter(options)
415 {
416  open(surf, outputPath, parallel);
417 }
418 
419 
421 (
422  const pointField& points,
423  const faceList& faces,
424  const fileName& outputPath,
425  bool parallel,
426  const dictionary& options
427 )
428 :
429  nastranWriter(options)
430 {
431  open(points, faces, outputPath, parallel);
432 }
433 
434 
435 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
436 
438 {
439  checkOpen();
440 
441  // Geometry: rootdir/<TIME>/surfaceName.nas
442 
443  fileName outputFile = outputPath_;
444  if (useTimeDir() && !timeName().empty())
445  {
446  // Splice in time-directory
447  outputFile = outputPath_.path() / timeName() / outputPath_.name();
448  }
449  outputFile.ext("nas");
450 
451  if (verbose_)
452  {
453  Info<< "Writing nastran geometry to " << outputFile << endl;
454  }
455 
456 
457  const meshedSurf& surf = surface();
458 
459  if (Pstream::master() || !parallel_)
460  {
461  if (!isDir(outputFile.path()))
462  {
463  mkDir(outputFile.path());
464  }
465 
466  OFstream os(outputFile);
467  fileFormats::NASCore::setPrecision(os, writeFormat_);
468 
469  os << "TITLE=OpenFOAM " << outputPath_.name()
470  << " mesh" << nl
471  << '$' << nl
472  << "BEGIN BULK" << nl;
473 
474  labelList decompOffsets;
475  DynamicList<face> decompFaces;
476 
477  writeGeometry(os, surf, decompOffsets, decompFaces);
478 
479  writeFooter(os, surf)
480  << "ENDDATA" << nl;
481  }
482 
483  wroteGeom_ = true;
484  return outputFile;
485 }
486 
487 
488 // ************************************************************************* //
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
OSspecific.H
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Foam::surfaceWriter
Base class for surface writers.
Definition: surfaceWriter.H:111
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::OFstream::name
virtual const fileName & name() const
Read/write access to the name of the stream.
Definition: OSstream.H:107
Foam::fileName::path
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:186
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::DynamicList
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:55
Foam::fileFormats::NASCore::loadFormatNames
static const Enum< loadFormat > loadFormatNames
Selection names for the NASTRAN file field formats.
Definition: NASCore.H:81
Foam::meshedSurf
Abstract definition of a meshed surface defined by faces and points.
Definition: meshedSurf.H:49
Foam::surfaceWriters::defineTypeName
defineTypeName(boundaryDataWriter)
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Pair.H
surfaceWriterMethods.H
Convenience macros for instantiating surfaceWriter methods.
Foam::fileFormats::NASCore::setPrecision
static void setPrecision(Ostream &os, const fieldFormat format)
Set output stream precision and format flags.
Definition: NASCore.C:131
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
nastranSurfaceWriter.H
Foam::fileFormats::NASCore::writeKeyword
static Ostream & writeKeyword(Ostream &os, const word &keyword, const fieldFormat format)
Definition: NASCore.C:165
Foam::Field< vector >
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::pid
pid_t pid()
Return the PID of this process.
Definition: MSwindows.C:330
IOmanip.H
Istream and Ostream manipulators taking arguments.
Foam::dictionary::readEntry
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, bool mandatory=true) const
Definition: dictionaryTemplates.C:314
timeName
word timeName
Definition: getTimeIndex.H:3
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
addToRunTimeSelectionTable.H
Macros for easy insertion into run-time selection tables.
Foam::fileName::ext
word ext() const
Return file name extension (part after last .)
Definition: fileNameI.H:228
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::setw
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
Foam::dictionary::subOrEmptyDict
dictionary subOrEmptyDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX, const bool mandatory=false) const
Definition: dictionary.C:608
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:87
Foam::UPstream::master
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:439
Foam::surfaceWriters::addToRunTimeSelectionTable
addToRunTimeSelectionTable(surfaceWriter, boundaryDataWriter, word)
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::Pair< word >
f
labelList f(nPoints)
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::surfaceWriters::nastranWriter::write
virtual fileName write()
Write surface geometry to file.
Definition: nastranSurfaceWriter.C:437
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:102
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::labelUList
UList< label > labelUList
A UList of labels.
Definition: UList.H:80
Foam::surfaceWriters::nastranWriter
A surface writer for the Nastran file format - both surface mesh and fields.
Definition: nastranSurfaceWriter.H:142
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys and label hasher.
Definition: HashSet.H:410
Foam::fileFormats::NASCore::fieldFormatNames
static const Enum< fieldFormat > fieldFormatNames
Selection names for the NASTRAN file field formats.
Definition: NASCore.H:71
Foam::dictionary::getOrDefault
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:122
Foam::mkDir
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: MSwindows.C:507
nastranSurfaceWriterImpl.C
Foam::surfaceWriters::nastranWriter::nastranWriter
nastranWriter()
Default construct. Default SHORT format.
Definition: nastranSurfaceWriter.C:355
defineSurfaceWriterWriteFields
defineSurfaceWriterWriteFields(Foam::surfaceWriters::nastranWriter)
Foam::fileFormats::NASCore::fieldFormat
fieldFormat
File field formats.
Definition: NASCore.H:63
Foam::isDir
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: MSwindows.C:643