Loading...
Searching...
No Matches
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-2025 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 {
106 if constexpr (pTraits_nComponents<Type>::value > 1)
107 {
108 writeValue(os, Foam::mag(value));
109 }
110 else
111 {
112 writeValue(os, 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 // NOTE: these should actually be vertex values,
125 // but misused here to provide vector quantities!
126
127 for (direction d = 0; d < pTraits<Type>::nComponents; ++d)
128 {
129 os << separator_;
130 writeValue(os, component(value, d));
131 }
132 break;
133 }
134 }
135
136 os.unsetf(std::ios_base::right);
137
138 os << nl;
139
140 return os;
141}
142
143
144template<class Type>
145Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate
146(
147 const word& fieldName,
148 const Field<Type>& localValues
149)
150{
151 // Geometry changed since last output? Capture now before any merging.
153
154 // Separate geometry, when commonGeometry = true
155 if (!wroteGeom_ && commonGeometry_)
156 {
157 write();
158 }
159
160 checkOpen();
161
162 // Default is PLOAD2
163 loadFormat format = loadFormat::PLOAD2;
164
165 if constexpr (std::is_integral_v<Type>)
166 {
167 // Handle 'Ids' etc silently
168 }
169 else if (!pload4_.empty())
170 {
171 const wordRes::filter matcher(pload4_, pload2_);
172
173 if (matcher(fieldName))
174 {
175 format = loadFormat::PLOAD4;
176 }
177 }
178
179 // Common geometry
180 // Field: rootdir/<TIME>/<field>_surfaceName.bdf
181
182 // Embedded geometry
183 // Field: rootdir/<TIME>/<field>/surfaceName.bdf
184
185 fileName outputFile = outputPath_.path();
186 if (useTimeDir() && !timeName().empty())
187 {
188 // Splice in time-directory
189 outputFile /= timeName();
190 }
191
192 fileName geomFileName;
193 if (commonGeometry_)
194 {
195 // Common geometry
196 geomFileName = outputPath_.name().ext("nas");
197
198 // Append <field>_surfaceName.bdf
199 outputFile /= fieldName + '_' + outputPath_.name();
200 }
201 else
202 {
203 // Embedded geometry
204 // Use sub-directory
205 outputFile /= fieldName / outputPath_.name();
206 }
207 outputFile.ext("bdf");
208
209 // Implicit geometry merge()
210 tmp<Field<Type>> tfield = adjustField(fieldName, mergeField(localValues));
211
212 if (verbose_)
213 {
214 Info<< " to " << outputFile << endl;
215 }
216
217
218 // const meshedSurf& surf = surface();
219 const meshedSurfRef& surf = adjustSurface();
220
221 if (UPstream::master() || !parallel_)
222 {
223 const auto& values = tfield();
224
225 if (!Foam::isDir(outputFile.path()))
226 {
227 Foam::mkDir(outputFile.path());
228 }
229
230 const scalar timeValue(0);
231
232 // Additional bookkeeping for decomposing non tri/quad
233 labelList decompOffsets;
234 DynamicList<face> decompFaces;
235
236
237 OFstream os(IOstreamOption::ATOMIC, outputFile);
239
240 os << "TITLE=OpenFOAM " << outputFile.name()
241 << token::SPACE << fieldName << " data" << nl;
242
243 if (useTimeDir() && !timeName().empty())
244 {
245 os << '$' << nl
246 << "$ TIME " << timeName() << nl;
247 }
248
249 os << "TIME " << timeValue << nl
250 << nl
251 << "BEGIN BULK" << nl;
252
253 if (commonGeometry_)
254 {
255 os << "INCLUDE '" << geomFileName.c_str() << "'" << nl;
256
257 // Geometry already written (or suppressed)
258 // - still need decomposition information
260 (
261 surf.points(),
262 surf.faces(),
263 decompOffsets,
264 decompFaces
265 );
266 }
267 else
268 {
269 // Write geometry
270 writeGeometry(os, surf, decompOffsets, decompFaces);
271 }
272
273 // Write field
274 os << '$' << nl
275 << "$ Field data" << nl
276 << '$' << nl;
277
278
279 // Regular (undecomposed) faces
280 const faceList& faces = surf.faces();
281 const labelUList& elemIds = surf.faceIds();
282
283 // Possible to use faceIds?
284 const bool useOrigFaceIds =
285 (
286 elemIds.size() == faces.size()
287 && !ListOps::found(elemIds, lessOp1<label>(0))
288 && decompFaces.empty()
289 );
290
291
292 label elemId = 0;
293
294 if (this->isPointData())
295 {
296 forAll(faces, facei)
297 {
298 if (useOrigFaceIds)
299 {
300 elemId = elemIds[facei];
301 }
302
303 const label beginElemId = elemId;
304
305 // Any face decomposition
306 for
307 (
308 label decompi = decompOffsets[facei];
309 decompi < decompOffsets[facei+1];
310 ++decompi
311 )
312 {
313 const face& f = decompFaces[decompi];
314
315 Type v = Zero;
316 for (const label verti : f)
317 {
318 v += values[verti];
319 }
320 v /= f.size();
321
322 writeFaceValue(os, format, v, ++elemId);
323 }
324
325
326 // Face not decomposed
327 if (beginElemId == elemId)
328 {
329 const face& f = faces[facei];
330
331 Type v = Zero;
332 for (const label verti : f)
333 {
334 v += values[verti];
335 }
336 v /= f.size();
337
338 writeFaceValue(os, format, v, ++elemId);
339 }
340 }
341 }
342 else
343 {
344 auto valIter = values.cbegin();
345
346 forAll(faces, facei)
347 {
348 if (useOrigFaceIds)
349 {
350 elemId = elemIds[facei];
351 }
352
353 const Type v(*valIter);
354 ++valIter;
355
356 label nValues =
357 max
358 (
359 label(1),
360 (decompOffsets[facei+1] - decompOffsets[facei])
361 );
362
363 while (nValues--)
364 {
365 writeFaceValue(os, format, v, ++elemId);
366 }
367 }
368 }
369
370 os << "ENDDATA" << endl;
371 }
372
373 wroteGeom_ = true;
374 return outputFile;
375}
376
377
378// ************************************************************************* //
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:68
Generic templated field type that is much like a Foam::List except that it is expected to hold numeri...
Definition Field.H:172
@ ATOMIC
atomic = true
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
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
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 empty() const
Writer is not associated with content.
bool verbose_
Additional output verbosity.
scalar timeValue() const
The current time value/name.
fileName outputPath_
The full output directory and file (coords) name.
Foam::fileFormats::NASCore::loadFormat loadFormat
Output load format.
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
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
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:296
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
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition fileNameI.H:192
Implements a meshed surface by referencing another meshed surface or faces/points components.
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.
Foam::fileFormats::NASCore::loadFormat loadFormat
Output load format.
A class for managing temporary objects.
Definition tmp.H:75
@ SPACE
Space [isspace].
Definition token.H:144
A class for handling words, derived from Foam::string.
Definition word.H:66
OBJstream os(runTime.globalPath()/outputName)
word timeName
Definition getTimeIndex.H:3
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition HashOps.H:164
bool found(const ListType &input, const UnaryPredicate &pred, const label start=0)
Same as found_if.
Definition ListOps.H:886
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
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
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).
List< face > faceList
List of faces.
Definition faceListFwd.H:41
Omanip< int > setw(const int i)
Definition IOmanip.H:199
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
uint8_t direction
Definition direction.H:49
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
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
runTime write()
word format(conversionProperties.get< word >("format"))
labelList f(nPoints)
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
The vector-space number of components: default is 1.
Definition pTraits.H:140
Functor wrapper of allow/deny lists of wordRe for filtering.
Definition wordRes.H:275