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-2022 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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
30#include "Pair.H"
31#include "IOmanip.H"
32#include "ListOps.H"
33#include "OSspecific.H"
36
37// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38
39namespace Foam
40{
41namespace surfaceWriters
42{
46}
47}
48
49// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
50
51// Field writing implementation
53
54// Field writing methods
56
57
58// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
59
60Foam::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
70void Foam::surfaceWriters::nastranWriter::writeCoord
71(
72 Ostream& os,
73 const point& p,
74 const label pointId
75) const
76{
77 fileFormats::NASCore::writeCoord(os, p, pointId, writeFormat_);
78}
79
80
81void Foam::surfaceWriters::nastranWriter::writeFace
82(
83 Ostream& os,
84 const word& faceType,
85 const labelUList& facePts,
86 const label elemId,
87 const label propId
88) const
89{
90 // Only valid surface elements are CTRIA3 and CQUAD4
91
92 // Fixed short/long formats:
93 // 1 CQUAD4
94 // 2 EID : element ID
95 // 3 PID : property element ID; default = EID (blank)
96 // 4 G1 : grid point index - requires starting index of 1
97 // 5 G2 : grid point index
98 // 6 G3 : grid point index
99 // 7 G4 : grid point index
100 // 8 onwards - not used
101
102 // For CTRIA3 elements, cols 7 onwards are not used
103
104 writeKeyword(os, faceType) << separator_;
105
106 os.setf(std::ios_base::right);
107
108 writeValue(os, elemId) << separator_;
109 writeValue(os, propId);
110
111 switch (writeFormat_)
112 {
113 case fieldFormat::SHORT :
114 {
115 for (const label pointi : facePts)
116 {
117 writeValue(os, pointi + 1);
118 }
119
120 break;
121 }
122
123 case fieldFormat::LONG :
124 {
125 forAll(facePts, i)
126 {
127 writeValue(os, facePts[i] + 1);
128 if (i == 1)
129 {
130 os << nl;
131 os.unsetf(std::ios_base::right);
132 writeKeyword(os, "");
133 os.setf(std::ios_base::right);
134 }
135 }
136
137 break;
138 }
139
140 case fieldFormat::FREE :
141 {
142 for (const label pointi : facePts)
143 {
144 os << separator_;
145 writeValue(os, pointi + 1);
146 }
147
148 break;
149 }
150 }
151
152 os << nl;
153 os.unsetf(std::ios_base::right);
154}
155
156
158(
159 Ostream& os,
160 const meshedSurf& surf,
161 labelList& decompOffsets,
162 DynamicList<face>& decompFaces
163) const
164{
165 const pointField& points = surf.points();
166 const faceList& faces = surf.faces();
167 const labelList& zones = surf.zoneIds();
168 const labelList& elemIds = surf.faceIds();
169
170 // Possible to use faceIds?
171 bool useOrigFaceIds =
172 (
173 elemIds.size() == faces.size()
174 && !ListOps::found(elemIds, lessOp1<label>(0))
175 );
176
177 // Not possible with on-the-fly face decomposition
178 if (useOrigFaceIds)
179 {
180 for (const auto& f : faces)
181 {
182 if (f.size() > 4)
183 {
184 useOrigFaceIds = false;
185 break;
186 }
187 }
188 }
189
190
191 // Write points
192
193 os << '$' << nl
194 << "$ Points" << nl
195 << '$' << nl;
196
197 forAll(points, pointi)
198 {
199 writeCoord(os, points[pointi], pointi);
200 }
201
202 // Write faces, with on-the-fly decomposition (triangulation)
203 decompOffsets.resize(faces.size()+1);
204 decompFaces.clear();
205
206 decompOffsets[0] = 0; // The first offset is always zero
207
208 os << '$' << nl
209 << "$ Faces" << nl
210 << '$' << nl;
211
212 label elemId = 0; // The element-id
213 forAll(faces, facei)
214 {
215 const face& f = faces[facei];
216
217 if (useOrigFaceIds)
218 {
219 elemId = elemIds[facei];
220 }
221
222 // 1-offset for PID
223 const label propId = 1 + (facei < zones.size() ? zones[facei] : 0);
224
225 if (f.size() == 3)
226 {
227 writeFace(os, "CTRIA3", f, ++elemId, propId);
228 }
229 else if (f.size() == 4)
230 {
231 writeFace(os, "CQUAD4", f, ++elemId, propId);
232 }
233 else
234 {
235 // Decompose into tris
236 f.triangles(points, decompFaces);
237
238 for
239 (
240 label decompi = decompOffsets[facei];
241 decompi < decompFaces.size();
242 ++decompi
243 )
244 {
245 writeFace
246 (
247 os,
248 "CTRIA3",
249 decompFaces[decompi],
250 ++elemId,
251 propId
252 );
253 }
254 }
255
256 // The end offset, which is the next begin offset
257 decompOffsets[facei+1] = decompFaces.size();
258 }
259
260
261 //
262 // SHELL/MAT information
263 //
264
265 // Zone id have been used for the PID. Find unique values.
266
267 labelList pidsUsed = labelHashSet(surf.zoneIds()).sortedToc();
268 if (pidsUsed.empty())
269 {
270 pidsUsed.resize(1, Zero); // fallback
271 }
272
273 for (auto pid : pidsUsed)
274 {
275 writeKeyword(os, "PSHELL") << separator_;
276 writeValue(os, pid+1); // 1-offset for PID
277
278 for (label i = 0; i < 7; ++i)
279 {
280 // Dummy values
281 os << separator_;
282 writeValue(os, 1);
283 }
284 os << nl;
285 }
286
287
288 // Use single material ID
289
290 const label MID = 1;
291
292 writeKeyword(os, "MAT1") << separator_;
293 writeValue(os, MID);
294
295 for (label i = 0; i < 7; ++i)
296 {
297 // Dummy values
298 os << separator_;
299 writeValue(os, "");
300 }
301 os << nl;
302}
303
304
305// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
306
308:
310 writeFormat_(fieldFormat::SHORT),
311 fieldMap_(),
312 commonGeometry_(false),
313 separator_()
314{
315 // if (writeFormat_ == fieldFormat::FREE)
316 // {
317 // separator_ = ",";
318 // }
319}
320
321
323(
324 const dictionary& options
325)
326:
327 surfaceWriter(options),
328 writeFormat_
329 (
330 fileFormats::NASCore::fieldFormatNames.getOrDefault
331 (
332 "format",
333 options,
334 fieldFormat::LONG
335 )
336 ),
337 fieldMap_(),
338 commonGeometry_(options.getOrDefault("commonGeometry", false)),
339 separator_()
340{
341 if (writeFormat_ == fieldFormat::FREE)
342 {
343 separator_ = ",";
344 }
345
346 List<Pair<word>> fieldPairs;
347 options.readEntry("fields", fieldPairs);
348
349 for (const Pair<word>& item : fieldPairs)
350 {
351 // (field name => load format)
352 fieldMap_.insert
353 (
354 item.first(),
356 );
357 }
358}
359
360
362(
363 const meshedSurf& surf,
364 const fileName& outputPath,
365 bool parallel,
366 const dictionary& options
367)
368:
369 nastranWriter(options)
370{
371 open(surf, outputPath, parallel);
372}
373
374
376(
377 const pointField& points,
378 const faceList& faces,
379 const fileName& outputPath,
380 bool parallel,
381 const dictionary& options
382)
383:
384 nastranWriter(options)
385{
386 open(points, faces, outputPath, parallel);
387}
388
389
390// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
391
393{
394 checkOpen();
395
396 // Geometry: rootdir/<TIME>/surfaceName.nas
397
398 fileName outputFile = outputPath_;
399 if (useTimeDir() && !timeName().empty())
400 {
401 // Splice in time-directory
402 outputFile = outputPath_.path() / timeName() / outputPath_.name();
403 }
404 outputFile.ext("nas");
405
406 if (verbose_)
407 {
408 Info<< "Writing nastran geometry to " << outputFile << endl;
409 }
410
411
412 // const meshedSurf& surf = surface();
413 const meshedSurfRef& surf = adjustSurface();
414
415 if (Pstream::master() || !parallel_)
416 {
417 if (!isDir(outputFile.path()))
418 {
419 mkDir(outputFile.path());
420 }
421
422 OFstream os(outputFile);
424
425 os << "TITLE=OpenFOAM " << outputPath_.name() << " geometry" << nl
426 << "BEGIN BULK" << nl;
427
428 labelList decompOffsets;
429 DynamicList<face> decompFaces;
430
431 writeGeometry(os, surf, decompOffsets, decompFaces);
432
433 os << "ENDDATA" << nl;
434 }
435
436 wroteGeom_ = true;
437 return outputFile;
438}
439
440
441// ************************************************************************* //
Istream and Ostream manipulators taking arguments.
Various functions to operate on Lists.
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
writer writeGeometry()
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
List< Key > sortedToc() const
The table of contents (the keys) in sorted order.
Definition: HashTable.C:137
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:180
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
Output to file stream, using an OSstream.
Definition: OFstream.H:57
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: Pair.H:69
void writeGeometry()
Write the mesh.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, bool mandatory=true) const
static Ostream & writeKeyword(Ostream &os, const word &keyword, const fieldFormat format)
Definition: NASCore.C:180
static void writeCoord(Ostream &os, const point &p, const label pointId, const fieldFormat format)
Write a GRID point.
Definition: NASCore.C:214
static void setPrecision(Ostream &os, const fieldFormat format)
Set output stream precision and format flags.
Definition: NASCore.C:146
fieldFormat
File field formats.
Definition: NASCore.H:64
static const Enum< loadFormat > loadFormatNames
Selection names for the NASTRAN file field formats.
Definition: NASCore.H:81
A class for handling file names.
Definition: fileName.H:76
word ext() const
Return file name extension (part after last .)
Definition: fileNameI.H:218
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:176
Implements a meshed surface by referencing another meshed surface or faces/points components.
Definition: meshedSurfRef.H:56
Abstract definition of a meshed surface defined by faces and points.
Definition: meshedSurf.H:50
splitCell * master() const
Definition: splitCell.H:113
Base class for surface writers.
virtual void open(const fileName &outputPath)
Open for output on specified path, using existing surface.
A surface writer for the Nastran file format - both surface mesh and fields.
nastranWriter()
Default construct. Default SHORT format.
virtual fileName write()
Write surface geometry to file.
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeName(Type)
Define the typeName.
Definition: className.H:96
volScalarField & p
OBJstream os(runTime.globalPath()/outputName)
const pointField & points
word timeName
Definition: getTimeIndex.H:3
bool found(const ListType &input, const UnaryPredicate &pred, const label start=0)
Same as found_if.
Definition: ListOps.H:679
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition: List.H:66
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:515
messageStream Info
Information stream (stdout output on master, null elsewhere)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
vector point
Point is a vector.
Definition: point.H:43
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
pid_t pid()
Return the PID of this process.
Definition: MSwindows.C:330
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
UList< label > labelUList
A UList of labels.
Definition: UList.H:85
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: MSwindows.C:651
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
labelList f(nPoints)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
Convenience macros for instantiating surfaceWriter methods.
#define defineSurfaceWriterWriteFields(ThisClass)