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-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 "OFstream.H"
30 #include "IOmanip.H"
31 #include "ListOps.H"
32 #include "OSspecific.H"
33 
34 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35 
36 template<class Type>
37 Foam::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 
68 template<class Type>
69 Foam::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
94  writeKeyword(os, fileFormats::NASCore::loadFormatNames[format])
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 
141 template<class Type>
142 Foam::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  {
190  << fileFormats::NASCore::loadFormatNames[format]
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 
227  // Output scaling for the variable, but not for integer types.
228  // could also solve with clever templating
229 
230  const scalar varScale =
231  (
232  std::is_integral<Type>::value
233  ? scalar(1)
234  : fieldScale_.getOrDefault<scalar>(fieldName, 1)
235  );
236 
237  if (verbose_)
238  {
239  Info<< "Writing field " << fieldName;
240  if (!equal(varScale, 1))
241  {
242  Info<< " (scaling " << varScale << ')';
243  }
244  Info<< " to " << outputFile << endl;
245  }
246 
247 
248  // Implicit geometry merge()
249  tmp<Field<Type>> tfield = mergeField(localValues) * varScale;
250 
251  const meshedSurf& surf = surface();
252 
253  if (Pstream::master() || !parallel_)
254  {
255  const auto& values = tfield();
256 
257  if (!isDir(outputFile.path()))
258  {
259  mkDir(outputFile.path());
260  }
261 
262  const scalar timeValue(0);
263 
264  // Additional bookkeeping for decomposing non tri/quad
265  labelList decompOffsets;
266  DynamicList<face> decompFaces;
267 
268 
269  OFstream os(outputFile);
270  fileFormats::NASCore::setPrecision(os, writeFormat_);
271 
272  os << "TITLE=OpenFOAM " << outputFile.name()
273  << token::SPACE << fieldName << " data" << nl;
274 
275  if (useTimeDir() && !timeName().empty())
276  {
277  os << '$' << nl
278  << "$ TIME " << timeName() << nl;
279  }
280 
281  os << "TIME " << timeValue << nl
282  << nl
283  << "BEGIN BULK" << nl;
284 
285  if (commonGeometry_)
286  {
287  os << "INCLUDE '" << geomFileName.c_str() << "'" << nl;
288 
289  // Geometry already written (or suppressed)
290  // - still need decomposition information
291  fileFormats::NASCore::faceDecomposition
292  (
293  surf.points(),
294  surf.faces(),
295  decompOffsets,
296  decompFaces
297  );
298  }
299  else
300  {
301  // Write geometry
302  writeGeometry(os, surf, decompOffsets, decompFaces);
303  }
304 
305  // Write field
306  os << '$' << nl
307  << "$ Field data" << nl
308  << '$' << nl;
309 
310 
311  // Regular (undecomposed) faces
312  const faceList& faces = surf.faces();
313  const labelUList& elemIds = surf.faceIds();
314 
315  // Possible to use faceIds?
316  const bool useOrigFaceIds =
317  (
318  elemIds.size() == faces.size()
319  && !ListOps::found(elemIds, lessOp1<label>(0))
320  && decompFaces.empty()
321  );
322 
323 
324  label elemId = 0;
325 
326  if (this->isPointData())
327  {
328  forAll(faces, facei)
329  {
330  if (useOrigFaceIds)
331  {
332  elemId = elemIds[facei];
333  }
334 
335  const label beginElemId = elemId;
336 
337  // Any face decomposition
338  for
339  (
340  label decompi = decompOffsets[facei];
341  decompi < decompOffsets[facei+1];
342  ++decompi
343  )
344  {
345  const face& f = decompFaces[decompi];
346 
347  Type v = Zero;
348  for (const label verti : f)
349  {
350  v += values[verti];
351  }
352  v /= f.size();
353 
354  writeFaceValue(os, format, v, ++elemId);
355  }
356 
357 
358  // Face not decomposed
359  if (beginElemId == elemId)
360  {
361  const face& f = faces[facei];
362 
363  Type v = Zero;
364  for (const label verti : f)
365  {
366  v += values[verti];
367  }
368  v /= f.size();
369 
370  writeFaceValue(os, format, v, ++elemId);
371  }
372  }
373  }
374  else
375  {
376  auto valIter = values.cbegin();
377 
378  forAll(faces, facei)
379  {
380  if (useOrigFaceIds)
381  {
382  elemId = elemIds[facei];
383  }
384 
385  const Type v(*valIter);
386  ++valIter;
387 
388  label nValues =
389  max
390  (
391  label(1),
392  (decompOffsets[facei+1] - decompOffsets[facei])
393  );
394 
395  while (nValues--)
396  {
397  writeFaceValue(os, format, v, ++elemId);
398  }
399  }
400  }
401 
402  os << "ENDDATA" << endl;
403  }
404 
405  wroteGeom_ = true;
406  return outputFile;
407 }
408 
409 
410 // ************************************************************************* //
OSspecific.H
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Foam::component
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
Definition: FieldFieldFunctions.C:44
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:65
Foam::fileName
A class for handling file names.
Definition: fileName.H:73
Foam::fileName::path
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:176
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:61
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::HashTableOps::values
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:149
Foam::fileName::name
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:199
Foam::meshedSurf::faces
virtual const faceList & faces() const =0
The faces used for the surface.
Foam::meshedSurf
Abstract definition of a meshed surface defined by faces and points.
Definition: meshedSurf.H:49
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::MatrixTools::equal
bool equal(const Matrix< Form1, Type > &A, const Matrix< Form2, Type > &B, const bool verbose=false, const label maxDiffs=10, const scalar relTol=1e-5, const scalar absTol=1e-8)
Compare matrix elements for absolute or relative equality.
Definition: MatrixTools.C:34
writeGeometry
writer writeGeometry()
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
OFstream.H
format
word format(conversionProperties.get< word >("format"))
Foam::Field
Generic templated field type.
Definition: Field.H:63
Foam::Info
messageStream Info
Information stream (stdout output on master, null elsewhere)
IOmanip.H
Istream and Ostream manipulators taking arguments.
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::meshedSurf::points
virtual const pointField & points() const =0
The points used for the surface.
timeName
word timeName
Definition: getTimeIndex.H:3
os
OBJstream os(runTime.globalPath()/outputName)
Foam::fileName::ext
word ext() const
Return file name extension (part after last .)
Definition: fileNameI.H:218
Foam::setw
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:53
found
bool found
Definition: TABSMDCalcMethod2.H:32
Foam::meshedSurf::faceIds
virtual const labelList & faceIds() const
Per-face identifier (eg, element Id)
Definition: meshedSurf.H:83
Foam::fileFormats::NASCore::loadFormat
loadFormat
Output load format.
Definition: NASCore.H:74
Foam::nl
constexpr char nl
Definition: Ostream.H:404
f
labelList f(nPoints)
Foam::List< label >
Foam::pTraits
A traits class, which is primarily used for primitives.
Definition: pTraits.H:56
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::UList< label >
Foam::lessOp1
Definition: ops.H:245
Foam::direction
uint8_t direction
Definition: direction.H:52
Foam::vtk::write
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
Definition: foamVtkOutputTemplates.C:36
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
ListOps.H
Various functions to operate on Lists.
Foam::UList::size
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
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
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328
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