Loading...
Searching...
No Matches
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-2024 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"
37// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39namespace Foam
40{
41namespace surfaceWriters
42{
46}
47}
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
157void Foam::surfaceWriters::nastranWriter::writeGeometry
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, "");
301 os << nl;
302}
303
304
305// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
306
308:
310 writeFormat_(fieldFormat::FREE),
311 commonGeometry_(false),
312 separator_(",") // FREE format
313{}
314
315
317(
318 const dictionary& options
319)
320:
321 surfaceWriter(options),
322 writeFormat_
323 (
324 fileFormats::NASCore::fieldFormatNames.getOrDefault
325 (
326 "format",
327 options,
328 fieldFormat::FREE
329 )
330 ),
331 commonGeometry_(options.getOrDefault("commonGeometry", false))
332{
333 if (writeFormat_ == fieldFormat::FREE)
334 {
335 separator_ = ",";
336 }
337
338 // Explicit PLOAD2, PLOAD4 field specification
339 options.readIfPresent("PLOAD2", pload2_);
340 options.readIfPresent("PLOAD4", pload4_);
341
342 // Compatibility:
343 // Optional pairs of (field name => load format)
344 // Could make conditional on (pload2_.empty() && pload4_.empty())
345
346 List<Pair<word>> fieldPairs;
347 options.readIfPresent("fields", fieldPairs);
348
349 for (const Pair<word>& item : fieldPairs)
350 {
351 const loadFormat format =
353
354 if (format == loadFormat::PLOAD2)
355 {
356 pload2_.push_back(item.first());
357 }
358 else if (format == loadFormat::PLOAD4)
360 pload4_.push_back(item.first());
361 }
362 }
363}
364
365
367(
368 const meshedSurf& surf,
369 const fileName& outputPath,
370 bool parallel,
371 const dictionary& options
372)
374 nastranWriter(options)
375{
376 open(surf, outputPath, parallel);
377}
378
379
381(
382 const pointField& points,
383 const faceList& faces,
384 const fileName& outputPath,
385 bool parallel,
386 const dictionary& options
387)
388:
389 nastranWriter(options)
391 open(points, faces, outputPath, parallel);
392}
393
394
395// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
396
398{
399 checkOpen();
400
401 // Geometry: rootdir/<TIME>/surfaceName.nas
402
403 fileName outputFile = outputPath_;
404 if (useTimeDir() && !timeName().empty())
405 {
406 // Splice in time-directory
407 outputFile = outputPath_.path() / timeName() / outputPath_.name();
408 }
409 outputFile.ext("nas");
410
411 if (verbose_)
412 {
413 Info<< "Writing nastran geometry to " << outputFile << endl;
414 }
415
416
417 // const meshedSurf& surf = surface();
418 const meshedSurfRef& surf = adjustSurface();
419
420 if (UPstream::master() || !parallel_)
421 {
422 if (!Foam::isDir(outputFile.path()))
423 {
424 Foam::mkDir(outputFile.path());
425 }
426
427 OFstream os(IOstreamOption::ATOMIC, outputFile);
429
430 os << "TITLE=OpenFOAM " << outputPath_.name() << " geometry" << nl
431 << "BEGIN BULK" << nl;
432
433 labelList decompOffsets;
434 DynamicList<face> decompFaces;
435
436 writeGeometry(os, surf, decompOffsets, decompFaces);
437
438 os << "ENDDATA" << nl;
439 }
440
441 wroteGeom_ = true;
442 return outputFile;
443}
444
445
446// ************************************************************************* //
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:68
List< Key > sortedToc() const
The table of contents (the keys) in sorted order.
Definition HashTable.C:156
@ ATOMIC
atomic = true
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void push_back(const T &val)
Append an element at the end of the list.
Definition ListI.H:221
Output to file stream as an OSstream, normally using std::ofstream for the actual output.
Definition OFstream.H:75
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
An ordered pair of two objects of type <T> with first() and second() elements.
Definition Pair.H:66
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
static Ostream & writeKeyword(Ostream &os, const word &keyword, const fieldFormat format)
Write initial keyword (eg, 'GRID' or 'GRID*') followed by the requisite number of spaces for the fiel...
Definition NASCore.C:196
static void writeCoord(Ostream &os, const point &p, const label pointId, const fieldFormat format)
Write a GRID point.
Definition NASCore.C:230
static void setPrecision(Ostream &os, const fieldFormat format)
Set output stream precision and format flags.
Definition NASCore.C:162
static const Enum< loadFormat > loadFormatNames
Selection names for the NASTRAN load formats.
Definition NASCore.H:91
A class for handling file names.
Definition fileName.H:75
word ext() const
Return file name extension (part after last .).
Definition fileNameI.H:211
static std::string path(const std::string &str)
Return directory path name (part before last /).
Definition fileNameI.H:169
Implements a meshed surface by referencing another meshed surface or faces/points components.
Abstract definition of a meshed surface defined by faces and points.
Definition meshedSurf.H:44
Base class for surface writers.
surfaceWriter()
Default construct.
virtual void open(const fileName &outputPath)
Open for output on specified path, using existing surface.
bool wroteGeom_
Track if geometry has been written since the last open.
bool useTimeDir() const noexcept
Should a time directory be spliced into the output path?
void checkOpen() const
Verify that the outputPath_ has been set or FatalError.
bool parallel_
Writing in parallel (via master).
bool empty() const
The surface to write is empty if the global number of faces is zero.
bool verbose_
Additional output verbosity.
const meshedSurfRef & adjustSurface() const
Merge surfaces (if not upToDate) and return merged (parallel) or regular surface (non-parallel) and a...
fileName outputPath_
The full output directory and file (surface) name.
A surface writer for the Nastran file format - both surface mesh and fields.
Foam::fileFormats::NASCore::loadFormat loadFormat
Output load format.
Foam::fileFormats::NASCore::fieldFormat fieldFormat
File field formats.
nastranWriter()
Default construct. Default FREE format.
virtual fileName write()
Write surface geometry to file.
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeName(Type)
Define the typeName.
Definition className.H:113
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:886
Namespace to isolate specifics for file formats, and some common utilities.
Namespace for surface writers.
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition List.H:62
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition POSIX.C:616
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition HashSet.H:85
messageStream Info
Information stream (stdout output on master, null elsewhere).
List< face > faceList
List of faces.
Definition faceListFwd.H:41
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
vector point
Point is a vector.
Definition point.H:37
pid_t pid()
Return the PID of this process.
Definition POSIX.C:316
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
vectorField pointField
pointField is a vectorField.
UList< label > labelUList
A UList of labels.
Definition UList.H:75
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition POSIX.C:862
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
word format(conversionProperties.get< word >("format"))
labelList f(nPoints)
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
Convenience macros for instantiating surfaceWriter methods.
#define defineSurfaceWriterWriteFields(ThisClass)