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 "OSspecific.H"
32 
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34 
35 template<class Type>
36 Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeValue
37 (
38  Ostream& os,
39  const Type& value
40 ) const
41 {
42  switch (writeFormat_)
43  {
44  case fieldFormat::SHORT :
45  {
46  os << setw(8) << value;
47  break;
48  }
49 
50  case fieldFormat::LONG :
51  {
52  os << setw(16) << value;
53  break;
54  }
55 
56  case fieldFormat::FREE :
57  {
58  os << value;
59  break;
60  }
61  }
62 
63  return os;
64 }
65 
66 
67 template<class Type>
68 Foam::Ostream& Foam::surfaceWriters::nastranWriter::writeFaceValue
69 (
70  Ostream& os,
71  const loadFormat format,
72  const Type& value,
73  const label elemId
74 ) const
75 {
76  // Fixed short/long formats supporting PLOAD2 and PLOAD4:
77 
78  // PLOAD2:
79  // 1 descriptor : PLOAD2
80  // 2 SID : load set ID
81  // 3 data value : load value - MUST be singular
82  // 4 EID : element ID
83 
84  // PLOAD4:
85  // 1 descriptor : PLOAD4
86  // 2 SID : load set ID
87  // 3 EID : element ID
88  // 4 onwards : load values
89 
90  const label setId = 1;
91 
92  // Write keyword
93  writeKeyword(os, fileFormats::NASCore::loadFormatNames[format])
94  << separator_;
95 
96  // Write load set ID
97  os.setf(std::ios_base::right);
98 
99  writeValue(os, setId) << separator_;
100 
101  switch (format)
102  {
103  case loadFormat::PLOAD2 :
104  {
106  {
107  writeValue(os, value);
108  }
109  else
110  {
111  writeValue(os, mag(value));
112  }
113 
114  os << separator_;
115  writeValue(os, elemId);
116  break;
117  }
118 
119  case loadFormat::PLOAD4 :
120  {
121  writeValue(os, elemId);
122 
123  for (direction d = 0; d < pTraits<Type>::nComponents; ++d)
124  {
125  os << separator_;
126  writeValue(os, component(value, d));
127  }
128  break;
129  }
130  }
131 
132  os.unsetf(std::ios_base::right);
133 
134  os << nl;
135 
136  return os;
137 }
138 
139 
140 template<class Type>
141 Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate
142 (
143  const word& fieldName,
144  const Field<Type>& localValues
145 )
146 {
147  checkOpen();
148 
149  if (!fieldMap_.found(fieldName))
150  {
152  << "No mapping found between field " << fieldName
153  << " and corresponding Nastran field. Available types are:"
154  << fieldMap_
155  << exit(FatalError);
156 
157  return fileName::null;
158  }
159 
160  const loadFormat format(fieldMap_[fieldName]);
161 
162  // Field: rootdir/<TIME>/field/surfaceName.nas
163 
164  fileName outputFile = outputPath_.path();
165  if (useTimeDir() && !timeName().empty())
166  {
167  // Splice in time-directory
168  outputFile /= timeName();
169  }
170  outputFile /= fieldName / outputPath_.name();
171  outputFile.ext("nas");
172 
173 
174  // Output scaling for the variable, but not for integer types.
175  // could also solve with clever templating
176 
177  const scalar varScale =
178  (
179  std::is_integral<Type>::value
180  ? scalar(1)
181  : fieldScale_.getOrDefault<scalar>(fieldName, 1)
182  );
183 
184  if (verbose_)
185  {
186  Info<< "Writing field " << fieldName;
187  if (!equal(varScale, 1))
188  {
189  Info<< " (scaling " << varScale << ')';
190  }
191  Info<< " to " << outputFile << endl;
192  }
193 
194  // Emit any common warnings
195  if (format == loadFormat::PLOAD2 && pTraits<Type>::nComponents != 1)
196  {
198  << fileFormats::NASCore::loadFormatNames[format]
199  << " cannot be used for higher rank values"
200  << " - reverting to mag()" << endl;
201  }
202 
203 
204  // geometry merge() implicit
205  tmp<Field<Type>> tfield = mergeField(localValues);
206 
207  const meshedSurf& surf = surface();
208 
209  if (Pstream::master() || !parallel_)
210  {
211  const auto& values = tfield();
212 
213  if (!isDir(outputFile.path()))
214  {
215  mkDir(outputFile.path());
216  }
217 
218  const scalar timeValue(0);
219 
220  // Additional bookkeeping for decomposing non tri/quad
221  labelList decompOffsets;
222  DynamicList<face> decompFaces;
223 
224 
225  // Could handle separate geometry here
226 
227  OFstream os(outputFile);
228  fileFormats::NASCore::setPrecision(os, writeFormat_);
229 
230  os << "TITLE=OpenFOAM " << outputFile.name()
231  << token::SPACE << fieldName << " data" << nl;
232 
233  if (useTimeDir() && !timeName().empty())
234  {
235  os << '$' << nl
236  << "$ TIME " << timeName() << nl;
237  }
238 
239  os << '$' << nl
240  << "TIME " << timeValue << nl
241  << '$' << nl
242  << "BEGIN BULK" << nl;
243 
244 
245  writeGeometry(os, surf, decompOffsets, decompFaces);
246 
247 
248  // Write field
249 
250  os << '$' << nl
251  << "$ Field data" << nl
252  << '$' << nl;
253 
254 
255  // Regular (undecomposed) faces
256  const faceList& faces = surf.faces();
257  const labelList& elemIds = surf.faceIds();
258 
259  // Possible to use faceIds?
260  // Not possible with on-the-fly face decomposition
261  const bool useOrigFaceIds =
262  (
263  elemIds.size() == faces.size()
264  && decompFaces.empty()
265  );
266 
267 
268  label elemId = 0;
269 
270  if (this->isPointData())
271  {
272  forAll(faces, facei)
273  {
274  if (useOrigFaceIds)
275  {
276  // When available and not decomposed
277  elemId = elemIds[facei];
278  }
279 
280  const label beginElemId = elemId;
281 
282  // Any face decomposition
283  for
284  (
285  label decompi = decompOffsets[facei];
286  decompi < decompOffsets[facei+1];
287  ++decompi
288  )
289  {
290  const face& f = decompFaces[decompi];
291 
292  Type v = Zero;
293  for (const label verti : f)
294  {
295  v += values[verti];
296  }
297  v *= (varScale / f.size());
298 
299  writeFaceValue(os, format, v, ++elemId);
300  }
301 
302 
303  // Face not decomposed
304  if (beginElemId == elemId)
305  {
306  const face& f = faces[facei];
307 
308  Type v = Zero;
309  for (const label verti : f)
310  {
311  v += values[verti];
312  }
313  v *= (varScale / f.size());
314 
315  writeFaceValue(os, format, v, ++elemId);
316  }
317  }
318  }
319  else
320  {
321  auto valIter = values.cbegin();
322 
323  forAll(faces, facei)
324  {
325  if (useOrigFaceIds)
326  {
327  // When available and not decomposed
328  elemId = elemIds[facei];
329  }
330 
331  const Type v(varScale * *valIter);
332  ++valIter;
333 
334  label nValues =
335  max
336  (
337  label(1),
338  (decompOffsets[facei+1] - decompOffsets[facei])
339  );
340 
341  while (nValues--)
342  {
343  writeFaceValue(os, format, v, ++elemId);
344  }
345  }
346  }
347 
348  writeFooter(os, surf)
349  << "ENDDATA" << endl;
350  }
351 
352  wroteGeom_ = true;
353  return outputFile;
354 }
355 
356 
357 // ************************************************************************* //
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:62
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::fileName::path
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:186
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:59
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:209
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:350
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
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 (uses stdout - output is on the master only)
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
timeName
word timeName
Definition: getTimeIndex.H:3
Foam::FatalError
error FatalError
Foam::fileName::ext
word ext() const
Return file name extension (part after last .)
Definition: fileNameI.H:228
Foam::setw
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:87
Foam::IOstream::setf
ios_base::fmtflags setf(const ios_base::fmtflags f)
Set flags of stream.
Definition: IOstream.H:369
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::IOstream::unsetf
void unsetf(const ios_base::fmtflags f)
Unset flags of stream.
Definition: IOstream.H:385
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:372
Foam::nl
constexpr char nl
Definition: Ostream.H:385
f
labelList f(nPoints)
Foam::List< label >
Foam::pTraits
Traits class for primitives.
Definition: pTraits.H:54
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::direction
uint8_t direction
Definition: direction.H:47
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
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:298
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