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 "ListOps.H"
33 #include "OSspecific.H"
34 #include "surfaceWriterMethods.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41 namespace surfaceWriters
42 {
43  defineTypeName(nastranWriter);
44  addToRunTimeSelectionTable(surfaceWriter, nastranWriter, word);
45  addToRunTimeSelectionTable(surfaceWriter, nastranWriter, wordDict);
46 }
47 }
48 
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
50 
51 // Field writing implementation
53 
54 // Field writing methods
56 
57 
58 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
59 
60 Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeKeyword
61 (
62  Ostream& os,
63  const word& keyword
64 ) const
65 {
66  return fileFormats::NASCore::writeKeyword(os, keyword, writeFormat_);
67 }
68 
69 
70 void Foam::surfaceWriters::nastranWriter::writeCoord
71 (
72  Ostream& os,
73  const point& pt,
74  const label pointI
75 ) const
76 {
77  // Fixed short/long formats:
78  // 1 GRID
79  // 2 ID : point ID - requires starting index of 1
80  // 3 CP : coordinate system ID (blank)
81  // 4 X1 : point x coordinate
82  // 5 X2 : point x coordinate
83  // 6 X3 : point x coordinate
84  // 7 CD : coordinate system for displacements (blank)
85  // 8 PS : single point constraints (blank)
86  // 9 SEID : super-element ID
87 
88  writeKeyword(os, "GRID") << separator_;
89 
90  os.setf(std::ios_base::right);
91 
92  writeValue(os, pointI+1) << separator_;
93  writeValue(os, "") << separator_;
94  writeValue(os, pt.x()) << separator_;
95  writeValue(os, pt.y()) << separator_;
96 
97  switch (writeFormat_)
98  {
99  case fieldFormat::SHORT :
100  {
101  os << setw(8) << pt.z() << nl;
102  os.unsetf(std::ios_base::right);
103  break;
104  }
105 
106  case fieldFormat::LONG :
107  {
108  os << nl;
109  os.unsetf(std::ios_base::right);
110  writeKeyword(os, "");
111  os.setf(std::ios_base::right);
112 
113  writeValue(os, pt.z()) << nl;
114  break;
115  }
116 
117  case fieldFormat::FREE :
118  {
119  writeValue(os, pt.z()) << nl;
120  break;
121  }
122  }
123 
124  os.unsetf(std::ios_base::right);
125 }
126 
127 
128 void Foam::surfaceWriters::nastranWriter::writeFace
129 (
130  Ostream& os,
131  const word& faceType,
132  const labelUList& facePts,
133  const label elemId,
134  const label propId
135 ) const
136 {
137  // Only valid surface elements are CTRIA3 and CQUAD4
138 
139  // Fixed short/long formats:
140  // 1 CQUAD4
141  // 2 EID : element ID
142  // 3 PID : property element ID; default = EID (blank)
143  // 4 G1 : grid point index - requires starting index of 1
144  // 5 G2 : grid point index
145  // 6 G3 : grid point index
146  // 7 G4 : grid point index
147  // 8 onwards - not used
148 
149  // For CTRIA3 elements, cols 7 onwards are not used
150 
151  writeKeyword(os, faceType) << separator_;
152 
153  os.setf(std::ios_base::right);
154 
155  writeValue(os, elemId) << separator_;
156  writeValue(os, propId);
157 
158  switch (writeFormat_)
159  {
160  case fieldFormat::SHORT :
161  {
162  for (const label pointi : facePts)
163  {
164  writeValue(os, pointi + 1);
165  }
166 
167  break;
168  }
169 
170  case fieldFormat::LONG :
171  {
172  forAll(facePts, i)
173  {
174  writeValue(os, facePts[i] + 1);
175  if (i == 1)
176  {
177  os << nl;
178  os.unsetf(std::ios_base::right);
179  writeKeyword(os, "");
180  os.setf(std::ios_base::right);
181  }
182  }
183 
184  break;
185  }
186 
187  case fieldFormat::FREE :
188  {
189  for (const label pointi : facePts)
190  {
191  os << separator_;
192  writeValue(os, pointi + 1);
193  }
194 
195  break;
196  }
197  }
198 
199  os << nl;
200  os.unsetf(std::ios_base::right);
201 }
202 
203 
204 void Foam::surfaceWriters::nastranWriter::writeGeometry
205 (
206  Ostream& os,
207  const meshedSurf& surf,
208  labelList& decompOffsets,
209  DynamicList<face>& decompFaces
210 ) const
211 {
212  const pointField& points = surf.points();
213  const faceList& faces = surf.faces();
214  const labelList& zones = surf.zoneIds();
215  const labelList& elemIds = surf.faceIds();
216 
217  // Possible to use faceIds?
218  bool useOrigFaceIds =
219  (
220  elemIds.size() == faces.size()
221  && !ListOps::found(elemIds, lessOp1<label>(0))
222  );
223 
224  // Not possible with on-the-fly face decomposition
225  if (useOrigFaceIds)
226  {
227  for (const auto& f : faces)
228  {
229  if (f.size() > 4)
230  {
231  useOrigFaceIds = false;
232  break;
233  }
234  }
235  }
236 
237 
238  // Write points
239 
240  os << '$' << nl
241  << "$ Points" << nl
242  << '$' << nl;
243 
244  forAll(points, pointi)
245  {
246  writeCoord(os, points[pointi]*geometryScale_, pointi);
247  }
248 
249  // Write faces, with on-the-fly decomposition (triangulation)
250  decompOffsets.resize(faces.size()+1);
251  decompFaces.clear();
252 
253  decompOffsets[0] = 0; // The first offset is always zero
254 
255  os << '$' << nl
256  << "$ Faces" << nl
257  << '$' << nl;
258 
259  label elemId = 0; // The element-id
260  forAll(faces, facei)
261  {
262  const face& f = faces[facei];
263 
264  if (useOrigFaceIds)
265  {
266  elemId = elemIds[facei];
267  }
268 
269  // 1-offset for PID
270  const label propId = 1 + (facei < zones.size() ? zones[facei] : 0);
271 
272  if (f.size() == 3)
273  {
274  writeFace(os, "CTRIA3", f, ++elemId, propId);
275  }
276  else if (f.size() == 4)
277  {
278  writeFace(os, "CQUAD4", f, ++elemId, propId);
279  }
280  else
281  {
282  // Decompose into tris
283  f.triangles(points, decompFaces);
284 
285  for
286  (
287  label decompi = decompOffsets[facei];
288  decompi < decompFaces.size();
289  ++decompi
290  )
291  {
292  writeFace
293  (
294  os,
295  "CTRIA3",
296  decompFaces[decompi],
297  ++elemId,
298  propId
299  );
300  }
301  }
302 
303  // The end offset, which is the next begin offset
304  decompOffsets[facei+1] = decompFaces.size();
305  }
306 
307 
308  //
309  // SHELL/MAT information
310  //
311 
312  // Zone id have been used for the PID. Find unique values.
313 
314  labelList pidsUsed = labelHashSet(surf.zoneIds()).sortedToc();
315  if (pidsUsed.empty())
316  {
317  pidsUsed.resize(1, Zero); // fallback
318  }
319 
320  for (auto pid : pidsUsed)
321  {
322  writeKeyword(os, "PSHELL") << separator_;
323  writeValue(os, pid+1); // 1-offset for PID
324 
325  for (label i = 0; i < 7; ++i)
326  {
327  // Dummy values
328  os << separator_;
329  writeValue(os, 1);
330  }
331  os << nl;
332  }
333 
334 
335  // Use single material ID
336 
337  const label MID = 1;
338 
339  writeKeyword(os, "MAT1") << separator_;
340  writeValue(os, MID);
341 
342  for (label i = 0; i < 7; ++i)
343  {
344  // Dummy values
345  os << separator_;
346  writeValue(os, "");
347  }
348  os << nl;
349 }
350 
351 
352 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
353 
355 :
356  surfaceWriter(),
357  writeFormat_(fieldFormat::SHORT),
358  fieldMap_(),
359  commonGeometry_(false),
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  commonGeometry_(options.getOrDefault("commonGeometry", false)),
383  geometryScale_(options.getOrDefault<scalar>("scale", 1)),
384  fieldScale_(options.subOrEmptyDict("fieldScale")),
385  separator_()
386 {
387  if (writeFormat_ == fieldFormat::FREE)
388  {
389  separator_ = ",";
390  }
391 
392  List<Pair<word>> fieldPairs;
393  options.readEntry("fields", fieldPairs);
394 
395  for (const Pair<word>& item : fieldPairs)
396  {
397  // (field name => load format)
398  fieldMap_.insert
399  (
400  item.first(),
402  );
403  }
404 }
405 
406 
408 (
409  const meshedSurf& surf,
410  const fileName& outputPath,
411  bool parallel,
412  const dictionary& options
413 )
414 :
415  nastranWriter(options)
416 {
417  open(surf, outputPath, parallel);
418 }
419 
420 
422 (
423  const pointField& points,
424  const faceList& faces,
425  const fileName& outputPath,
426  bool parallel,
427  const dictionary& options
428 )
429 :
430  nastranWriter(options)
431 {
432  open(points, faces, outputPath, parallel);
433 }
434 
435 
436 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
437 
439 {
440  checkOpen();
441 
442  // Geometry: rootdir/<TIME>/surfaceName.nas
443 
444  fileName outputFile = outputPath_;
445  if (useTimeDir() && !timeName().empty())
446  {
447  // Splice in time-directory
448  outputFile = outputPath_.path() / timeName() / outputPath_.name();
449  }
450  outputFile.ext("nas");
451 
452  if (verbose_)
453  {
454  Info<< "Writing nastran geometry to " << outputFile << endl;
455  }
456 
457 
458  const meshedSurf& surf = surface();
459 
460  if (Pstream::master() || !parallel_)
461  {
462  if (!isDir(outputFile.path()))
463  {
464  mkDir(outputFile.path());
465  }
466 
467  OFstream os(outputFile);
468  fileFormats::NASCore::setPrecision(os, writeFormat_);
469 
470  os << "TITLE=OpenFOAM " << outputPath_.name() << " geometry" << nl
471  << "BEGIN BULK" << nl;
472 
473  labelList decompOffsets;
474  DynamicList<face> decompFaces;
475 
476  writeGeometry(os, surf, decompOffsets, decompFaces);
477 
478  os << "ENDDATA" << nl;
479  }
480 
481  wroteGeom_ = true;
482  return outputFile;
483 }
484 
485 
486 // ************************************************************************* //
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
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:114
Foam::fileName
A class for handling file names.
Definition: fileName.H:73
Foam::surfaceWriters::defineTypeName
defineTypeName(abaqusWriter)
Foam::fileName::path
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:176
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::UPstream::master
static bool master(const label communicator=worldComm)
Am I the master process.
Definition: UPstream.H:457
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
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
writeGeometry
writer writeGeometry()
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
nastranSurfaceWriter.H
Foam::surfaceWriters::addToRunTimeSelectionTable
addToRunTimeSelectionTable(surfaceWriter, abaqusWriter, word)
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 (stdout output on master, null elsewhere)
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:302
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:123
os
OBJstream os(runTime.globalPath()/outputName)
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:218
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:540
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:53
Foam::nl
constexpr char nl
Definition: Ostream.H:404
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:438
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::ListOps::found
bool found(const ListType &input, const UnaryPredicate &pred, const label start=0)
True if there is a value in the list that satisfies the predicate.
Definition: ListOpsTemplates.C:1156
ListOps.H
Various functions to operate on Lists.
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:85
Foam::surfaceWriters::nastranWriter
A surface writer for the Nastran file format - both surface mesh and fields.
Definition: nastranSurfaceWriter.H:149
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
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:148
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:354
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