nastranSurfaceWriterImpl.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
29#include "IOmanip.H"
30#include "ListOps.H"
31#include "OFstream.H"
32#include "OSspecific.H"
33
34// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35
36template<class Type>
37Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeValue
38(
39 Ostream& os,
40 const Type& value
41) const
42{
43 switch (writeFormat_)
44 {
45 case fieldFormat::SHORT :
46 {
47 os << setw(8) << value;
48 break;
49 }
50
51 case fieldFormat::LONG :
52 {
53 os << setw(16) << value;
54 break;
55 }
56
57 case fieldFormat::FREE :
58 {
59 os << value;
60 break;
61 }
62 }
63
64 return os;
65}
66
67
68template<class Type>
69Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeFaceValue
70(
71 Ostream& os,
72 const loadFormat format,
73 const Type& value,
74 const label elemId
75) const
76{
77 // Fixed short/long formats supporting PLOAD2 and PLOAD4:
78
79 // PLOAD2:
80 // 1 descriptor : PLOAD2
81 // 2 SID : load set ID
82 // 3 data value : load value - MUST be singular
83 // 4 EID : element ID
84
85 // PLOAD4:
86 // 1 descriptor : PLOAD4
87 // 2 SID : load set ID
88 // 3 EID : element ID
89 // 4 onwards : load values
90
91 const label setId = 1;
92
93 // Write keyword
95 << separator_;
96
97 // Write load set ID
98 os.setf(std::ios_base::right);
99
100 writeValue(os, setId) << separator_;
101
102 switch (format)
103 {
104 case loadFormat::PLOAD2 :
105 {
107 {
108 writeValue(os, value);
109 }
110 else
111 {
112 writeValue(os, mag(value));
113 }
114
115 os << separator_;
116 writeValue(os, elemId);
117 break;
118 }
119
120 case loadFormat::PLOAD4 :
121 {
122 writeValue(os, elemId);
123
124 for (direction d = 0; d < pTraits<Type>::nComponents; ++d)
125 {
126 os << separator_;
127 writeValue(os, component(value, d));
128 }
129 break;
130 }
131 }
132
133 os.unsetf(std::ios_base::right);
134
135 os << nl;
136
137 return os;
138}
139
140
141template<class Type>
142Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate
143(
144 const word& fieldName,
145 const Field<Type>& localValues
146)
147{
148 // Geometry changed since last output? Capture now before any merging.
150
151 // Separate geometry, when commonGeometry = true
152 if (!wroteGeom_ && commonGeometry_)
153 {
154 write();
155 }
156
157 checkOpen();
158
159 const loadFormat format
160 (
161 fieldMap_.lookup
162 (
163 fieldName,
164 // Default format
165 (
167 ? loadFormat::PLOAD2
168 : loadFormat::PLOAD4
169 )
170 )
171 );
172
173 if
174 (
175 !std::is_integral<Type>::value // Handle 'Ids' etc silently
176 && !fieldMap_.empty()
177 && !fieldMap_.found(fieldName)
178 )
179 {
181 << "No mapping found between field " << fieldName
182 << " and corresponding Nastran field. Available types:"
183 << fieldMap_ << nl;
184 }
185
186 // Emit any common warnings
187 if (format == loadFormat::PLOAD2 && pTraits<Type>::nComponents != 1)
188 {
191 << " cannot be used for higher rank values"
192 << " - reverting to mag()" << endl;
193 }
194
195
196 // Common geometry
197 // Field: rootdir/<TIME>/<field>_surfaceName.bdf
198
199 // Embedded geometry
200 // Field: rootdir/<TIME>/<field>/surfaceName.bdf
201
202 fileName outputFile = outputPath_.path();
203 if (useTimeDir() && !timeName().empty())
204 {
205 // Splice in time-directory
206 outputFile /= timeName();
207 }
208
209 fileName geomFileName;
210 if (commonGeometry_)
211 {
212 // Common geometry
213 geomFileName = outputPath_.name().ext("nas");
214
215 // Append <field>_surfaceName.bdf
216 outputFile /= fieldName + '_' + outputPath_.name();
217 }
218 else
219 {
220 // Embedded geometry
221 // Use sub-directory
222 outputFile /= fieldName / outputPath_.name();
223 }
224 outputFile.ext("bdf");
225
226 // Implicit geometry merge()
227 tmp<Field<Type>> tfield = adjustField(fieldName, mergeField(localValues));
228
229 if (verbose_)
230 {
231 Info<< " to " << outputFile << endl;
232 }
233
234
235 // const meshedSurf& surf = surface();
236 const meshedSurfRef& surf = adjustSurface();
237
238 if (Pstream::master() || !parallel_)
239 {
240 const auto& values = tfield();
241
242 if (!isDir(outputFile.path()))
243 {
244 mkDir(outputFile.path());
245 }
246
247 const scalar timeValue(0);
248
249 // Additional bookkeeping for decomposing non tri/quad
250 labelList decompOffsets;
251 DynamicList<face> decompFaces;
252
253
254 OFstream os(outputFile);
256
257 os << "TITLE=OpenFOAM " << outputFile.name()
258 << token::SPACE << fieldName << " data" << nl;
259
260 if (useTimeDir() && !timeName().empty())
261 {
262 os << '$' << nl
263 << "$ TIME " << timeName() << nl;
264 }
265
266 os << "TIME " << timeValue << nl
267 << nl
268 << "BEGIN BULK" << nl;
269
270 if (commonGeometry_)
271 {
272 os << "INCLUDE '" << geomFileName.c_str() << "'" << nl;
273
274 // Geometry already written (or suppressed)
275 // - still need decomposition information
277 (
278 surf.points(),
279 surf.faces(),
280 decompOffsets,
281 decompFaces
282 );
283 }
284 else
285 {
286 // Write geometry
287 writeGeometry(os, surf, decompOffsets, decompFaces);
288 }
289
290 // Write field
291 os << '$' << nl
292 << "$ Field data" << nl
293 << '$' << nl;
294
295
296 // Regular (undecomposed) faces
297 const faceList& faces = surf.faces();
298 const labelUList& elemIds = surf.faceIds();
299
300 // Possible to use faceIds?
301 const bool useOrigFaceIds =
302 (
303 elemIds.size() == faces.size()
304 && !ListOps::found(elemIds, lessOp1<label>(0))
305 && decompFaces.empty()
306 );
307
308
309 label elemId = 0;
310
311 if (this->isPointData())
312 {
313 forAll(faces, facei)
314 {
315 if (useOrigFaceIds)
316 {
317 elemId = elemIds[facei];
318 }
319
320 const label beginElemId = elemId;
321
322 // Any face decomposition
323 for
324 (
325 label decompi = decompOffsets[facei];
326 decompi < decompOffsets[facei+1];
327 ++decompi
328 )
329 {
330 const face& f = decompFaces[decompi];
331
332 Type v = Zero;
333 for (const label verti : f)
334 {
335 v += values[verti];
336 }
337 v /= f.size();
338
339 writeFaceValue(os, format, v, ++elemId);
340 }
341
342
343 // Face not decomposed
344 if (beginElemId == elemId)
345 {
346 const face& f = faces[facei];
347
348 Type v = Zero;
349 for (const label verti : f)
350 {
351 v += values[verti];
352 }
353 v /= f.size();
354
355 writeFaceValue(os, format, v, ++elemId);
356 }
357 }
358 }
359 else
360 {
361 auto valIter = values.cbegin();
362
363 forAll(faces, facei)
364 {
365 if (useOrigFaceIds)
366 {
367 elemId = elemIds[facei];
368 }
369
370 const Type v(*valIter);
371 ++valIter;
372
373 label nValues =
374 max
375 (
376 label(1),
377 (decompOffsets[facei+1] - decompOffsets[facei])
378 );
379
380 while (nValues--)
381 {
382 writeFaceValue(os, format, v, ++elemId);
383 }
384 }
385 }
386
387 os << "ENDDATA" << endl;
388 }
389
390 wroteGeom_ = true;
391 return outputFile;
392}
393
394
395// ************************************************************************* //
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...
writer writeGeometry()
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
Generic templated field type.
Definition: Field.H:82
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
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:427
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
static void setPrecision(Ostream &os, const fieldFormat format)
Set output stream precision and format flags.
Definition: NASCore.C:146
static const Enum< loadFormat > loadFormatNames
Selection names for the NASTRAN file field formats.
Definition: NASCore.H:81
loadFormat
Output load format.
Definition: NASCore.H:75
static label faceDecomposition(const UList< point > &points, const UList< face > &faces, labelList &decompOffsets, DynamicList< face > &decompFaces)
Calculate face decomposition for non tri/quad faces.
Definition: NASCore.C:280
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
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:199
Implements a meshed surface by referencing another meshed surface or faces/points components.
Definition: meshedSurfRef.H:56
virtual const pointField & points() const
The points used for the surface.
virtual const labelList & faceIds() const
Per-face identifier (eg, element Id)
virtual const faceList & faces() const
The faces used for the surface.
A traits class, which is primarily used for primitives.
Definition: pTraits.H:59
splitCell * master() const
Definition: splitCell.H:113
A class for managing temporary objects.
Definition: tmp.H:65
@ SPACE
Space [isspace].
Definition: token.H:125
A class for handling words, derived from Foam::string.
Definition: word.H:68
OBJstream os(runTime.globalPath()/outputName)
word timeName
Definition: getTimeIndex.H:3
#define WarningInFunction
Report a warning using Foam::Warning.
bool found(const ListType &input, const UnaryPredicate &pred, const label start=0)
Same as found_if.
Definition: ListOps.H:679
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
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
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
messageStream Info
Information stream (stdout output on master, null elsewhere)
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
uint8_t direction
Definition: direction.H:56
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
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
runTime write()
word format(conversionProperties.get< word >("format"))
labelList f(nPoints)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333