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 -------------------------------------------------------------------------------
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 "IOmanip.H"
30 #include "ListOps.H"
31 #include "OFstream.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
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;
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  {
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 (UPstream::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);
255  fileFormats::NASCore::setPrecision(os, writeFormat_);
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 // ************************************************************************* //
uint8_t direction
Definition: direction.H:46
A class for handling file names.
Definition: fileName.H:72
writer writeGeometry()
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
bool found(const ListType &input, const UnaryPredicate &pred, const label start=0)
Same as found_if.
Definition: ListOps.H:826
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static const Enum< loadFormat > loadFormatNames
Selection names for the NASTRAN file field formats.
Definition: NASCore.H:92
A traits class, which is primarily used for primitives and vector-space.
Definition: pTraits.H:75
::Foam::direction nComponents(const expressions::valueTypeCode) noexcept
The number of components associated with given valueTypeCode.
Definition: exprTraits.C:40
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
word ext() const
Return file name extension (part after last .)
Definition: wordI.H:171
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:860
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:164
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
word timeName
Definition: getTimeIndex.H:3
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
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:614
static void setPrecision(Ostream &os, const fieldFormat format)
Set output stream precision and format flags.
Definition: NASCore.C:153
Generic templated field type.
Definition: Field.H:62
A class for handling words, derived from Foam::string.
Definition: word.H:63
Space [isspace].
Definition: token.H:131
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
Istream and Ostream manipulators taking arguments.
OBJstream os(runTime.globalPath()/outputName)
labelList f(nPoints)
word format(conversionProperties.get< word >("format"))
#define WarningInFunction
Report a warning using Foam::Warning.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1082
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:287
messageStream Info
Information stream (stdout output on master, null elsewhere)
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
List< label > labelList
A List of labels.
Definition: List.H:62
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127