ensightOutputTemplates.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) 2019-2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "ensightOutput.H"
29 #include "ensightPTraits.H"
30 #include "globalIndex.H"
31 
32 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
33 
34 template<class LabelListListType>
36 (
38  const LabelListListType& listOfLists,
39  const label pointOffset
40 )
41 {
42  const label off = (pointOffset + 1); // 1-based for Ensight
43 
44  forAll(listOfLists, listi)
45  {
46  for (const label pointi : listOfLists[listi])
47  {
48  os.write(pointi + off);
49  }
50  os.newline(); // One list (cell/faces) per line (ASCII)
51  }
52 }
53 
54 
55 template<template<typename> class FieldContainer, class Type>
57 (
58  const FieldContainer<Type>& input,
59  const direction cmpt,
60  UList<float>& cmptBuffer
61 )
62 {
63  if (cmptBuffer.size() < input.size())
64  {
66  << "Component buffer too small: "
67  << cmptBuffer.size() << " < " << input.size() << nl
68  << exit(FatalError);
69  }
70 
71  auto iter = cmptBuffer.begin();
72 
73  if (std::is_same<float, typename pTraits<Type>::cmptType>::value)
74  {
75  // Direct copy
76  for (const Type& val : input)
77  {
78  *iter = component(val, cmpt);
79  ++iter;
80  }
81  }
82  else
83  {
84  // Copy with narrowing
85  for (const Type& val : input)
86  {
87  *iter = narrowFloat(component(val, cmpt));
88  ++iter;
89  }
90  }
91 }
92 
93 
94 template<template<typename> class FieldContainer, class Type>
96 (
98  ensightFile& os,
99  const char* key,
100  const FieldContainer<Type>& fld,
101  bool parallel
102 )
103 {
104  parallel = parallel && Pstream::parRun();
105 
106  const label localSize = fld.size();
107 
108  // Gather sizes (offsets irrelevant)
109  const globalIndex procAddr
110  (
111  parallel
112  ? globalIndex(globalIndex::gatherOnly{}, localSize)
113  : globalIndex(globalIndex::gatherNone{}, localSize)
114  );
115 
116  if (Pstream::master() && key)
117  {
118  os.writeKeyword(key);
119  }
120 
121  if (Pstream::master())
122  {
123  // Scratch buffer:
124  // - allocate enough space to process an individual rank
125  // - potentially enough to process multiple ranks before writing
126  // - permit use of the full buffer capacity
127 
128  // Buffer size needed for an individual rank
129  const label minSize(max(localSize, procAddr.maxSize()));
130 
131  // Maximum off-processor transfer size
132  const label maxSize =
133  (
135  ? min
136  (
137  static_cast<label>(ensightOutput::maxChunk_),
138  (procAddr.totalSize() - localSize)
139  )
140  : scratch.capacity()
141  );
142 
143  scratch.resize_nocopy
144  (
145  max(max(minSize, maxSize), scratch.capacity())
146  );
147 
148  if (Pstream::master() && debug > 1)
149  {
150  Info<< "ensight";
151  if (key)
152  {
153  Info<< " (" << key << ')';
154  }
155 
156  Info<< " total-size:" << procAddr.totalSize()
157  << " buf-size:" << scratch.size() << "/" << scratch.capacity()
158  << " any-proc:" << minSize
159  << " off-proc:" << (procAddr.totalSize() - localSize) << endl;
160 
161  Info<< "proc-sends: (";
162 
163  label nPending = localSize;
164 
165  Info<< (localSize ? '0' : '_');
166 
167  // Receive others, writing as needed
168  for (const label proci : procAddr.subProcs())
169  {
170  const label procSize = procAddr.localSize(proci);
171 
172  if (procSize)
173  {
174  if (nPending + procSize > scratch.size())
175  {
176  // Flush buffer
177  nPending = 0;
178  Info<< ") (";
179  }
180  else
181  {
182  Info<< ' ';
183  }
184 
185  Info<< proci;
186  nPending += procSize;
187  }
188  }
189 
190  Info<< ')' << endl;
191  }
192 
194  {
195  const direction cmpt = ensightPTraits<Type>::componentOrder[d];
196 
197  // Master
198  copyComponent(fld, cmpt, scratch);
199  label nPending = localSize;
200 
201  // Receive others, writing as needed
202  for (const label proci : procAddr.subProcs())
203  {
204  const label procSize = procAddr.localSize(proci);
205 
206  if (procSize)
207  {
208  if (nPending + procSize > scratch.size())
209  {
210  // Flush buffer
211  os.writeList(SubList<float>(scratch, nPending));
212  nPending = 0;
213  }
214 
215  SubList<float> slot(scratch, procSize, nPending);
216  nPending += procSize;
217 
219  (
220  UPstream::commsTypes::scheduled,
221  proci,
222  slot.data_bytes(),
223  slot.size_bytes()
224  );
225  }
226  }
227 
228  if (nPending)
229  {
230  // Flush buffer
231  os.writeList(SubList<float>(scratch, nPending));
232  }
233  }
234  }
235  else if (parallel && localSize)
236  {
237  scratch.resize_nocopy(localSize);
238 
240  {
241  const direction cmpt = ensightPTraits<Type>::componentOrder[d];
242 
243  copyComponent(fld, cmpt, scratch);
244 
246  (
247  UPstream::commsTypes::scheduled,
248  UPstream::masterNo(),
249  scratch.cdata_bytes(),
250  scratch.size_bytes()
251  );
252  }
253  }
254 }
255 
256 
257 template<template<typename> class FieldContainer>
259 (
260  ensightGeoFile& os,
261  const label partId,
262  const word& partName,
263  const label nPoints,
264  const FieldContainer<Foam::point>& fld,
265  bool parallel
266 )
267 {
268  if (Pstream::master())
269  {
270  os.beginPart(partId, partName);
271  os.beginCoordinates(nPoints);
272  }
273 
274  bool ok = (Pstream::master() && (nPoints > 0));
275  if (parallel)
276  {
277  Pstream::broadcast(ok);
278  }
279 
280  if (ok)
281  {
284  (
285  scratch,
286  os,
287  nullptr, // (no element type)
288  fld,
289  parallel
290  );
291  }
293  return true;
294 }
295 
296 
297 template<class Type>
299 (
301  ensightFile& os,
302  const Field<Type>& fld,
303  const ensightFaces& part,
304  bool parallel
305 )
306 {
307  parallel = parallel && Pstream::parRun();
308 
309  // Need geometry and field. part.total() is already reduced
310  const bool good =
311  (
312  parallel
313  ? (part.total() && returnReduceOr(fld.size()))
314  : (part.size() && fld.size())
315  );
316 
317  if (!good)
318  {
319  return false;
320  }
321 
322 
323  if (Pstream::master())
324  {
325  os.beginPart(part.index());
326  }
327 
328  for (int typei=0; typei < ensightFaces::nTypes; ++typei)
329  {
330  const auto etype = ensightFaces::elemType(typei);
331 
332  // Write elements of this type
333  if (parallel ? part.total(etype) : part.size(etype))
334  {
336  (
337  scratch,
338  os,
339  ensightFaces::key(etype),
340  SubField<Type>(fld, part.range(etype)),
341  parallel
342  );
343  }
344  }
346  return true;
347 }
348 
349 
350 template<class Type>
352 (
354  ensightFile& os,
355  const Field<Type>& fld,
356  const ensightFaces& part,
357  bool parallel
358 )
359 {
360  parallel = parallel && Pstream::parRun();
361 
362  // Need geometry and field. part.total() is already reduced
363  const bool good =
364  (
365  parallel
366  ? (part.total() && returnReduceOr(fld.size()))
367  : (part.size() && fld.size())
368  );
369 
370  if (!good)
371  {
372  return false;
373  }
374 
375 
376  bool validAddressing = (part.size() == part.faceOrder().size());
377 
378  if (parallel)
379  {
380  Pstream::reduceOr(validAddressing);
381  }
382 
383  if (!validAddressing)
384  {
386  << "Called without faceOrder having been set" << nl
387  << exit(FatalError);
388  }
389 
390 
391  if (Pstream::master())
392  {
393  os.beginPart(part.index());
394  }
395 
396  for (int typei=0; typei < ensightFaces::nTypes; ++typei)
397  {
398  const auto etype = ensightFaces::elemType(typei);
399 
400  // Write elements of this type
401  if (parallel ? part.total(etype) : part.size(etype))
402  {
404  (
405  scratch,
406  os,
407  ensightFaces::key(etype),
408  UIndirectList<Type>(fld, part.faceOrder(etype)),
409  parallel
410  );
411  }
412  }
413 
414  return true;
415 }
416 
417 
418 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
419 
420 template<class Type>
422 (
424  ensightFile& os,
425  const Field<Type>& fld,
426  const ensightCells& part,
427  bool parallel
428 )
429 {
430  parallel = parallel && Pstream::parRun();
431 
432  // Need geometry and field. part.total() is already reduced
433  const bool good =
434  (
435  parallel
436  ? (part.total() && returnReduceOr(fld.size()))
437  : (part.size() && fld.size())
438  );
439 
440  if (!good)
441  {
442  return false;
443  }
444 
445 
446  if (Pstream::master())
447  {
448  os.beginPart(part.index());
449  }
450 
451  for (int typei=0; typei < ensightCells::nTypes; ++typei)
452  {
453  const auto etype = ensightCells::elemType(typei);
454 
455  // Write elements of this type
456  if (parallel ? part.total(etype) : part.size(etype))
457  {
459  (
460  scratch,
461  os,
462  ensightCells::key(etype),
463  UIndirectList<Type>(fld, part.cellIds(etype)),
464  parallel
465  );
466  }
467  }
469  return true;
470 }
471 
472 
473 template<class Type>
475 (
477  ensightFile& os,
478  const Field<Type>& fld,
479  const ensightFaces& part,
480  bool parallel
481 )
482 {
483  parallel = parallel && Pstream::parRun();
484 
485  // Need geometry and field. part.total() is already reduced
486  const bool good =
487  (
488  parallel
489  ? (part.total() && returnReduceOr(fld.size()))
490  : (part.size() && fld.size())
491  );
492 
493  if (!good)
494  {
495  return false;
496  }
497 
498 
499  if (Pstream::master())
500  {
501  os.beginPart(part.index());
502  }
503 
504  for (int typei=0; typei < ensightFaces::nTypes; ++typei)
505  {
506  const auto etype = ensightFaces::elemType(typei);
507 
508  // Write elements of this type
509  if (parallel ? part.total(etype) : part.size(etype))
510  {
512  (
513  scratch,
514  os,
515  ensightFaces::key(etype),
516  UIndirectList<Type>(fld, part.faceIds(etype)),
517  parallel
518  );
519  }
520  }
521 
522  return true;
523 }
524 
525 
526 // ************************************************************************* //
Ensight output with specialized write() for strings, integers and floats. Correctly handles binary wr...
Definition: ensightFile.H:46
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
uint8_t direction
Definition: direction.H:46
float narrowFloat(const double val)
Type narrowing from double to float.
Definition: scalar.H:240
label total() const noexcept
Same as totalSize.
Definition: ensightFaces.H:203
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
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
Specialized Ensight output with extra geometry file header.
labelRange range(const elemType etype) const
Processor-local offset/size of element type.
Definition: ensightFacesI.H:66
Sorting/classification of faces (2D) into corresponding ensight types.
Definition: ensightFaces.H:66
bool writeFaceSubField(ensightOutput::floatBufferType &scratch, ensightFile &os, const Field< Type > &fld, const ensightFaces &part, bool parallel)
Write a sub-field of faces values as an indirect list, using the sub-list sizing information from ens...
const labelList & faceOrder() const noexcept
Processor-local face order (where applicable)
Definition: ensightFacesI.H:98
bool writeFaceLocalField(ensightOutput::floatBufferType &scratch, ensightFile &os, const Field< Type > &fld, const ensightFaces &part, bool parallel)
Write a field of faces values as an indirect list, using the face order from ensightFaces.
::Foam::direction nComponents(const expressions::valueTypeCode) noexcept
The number of components associated with given valueTypeCode.
Definition: exprTraits.C:40
bool writeField(ensightOutput::floatBufferType &scratch, ensightFile &os, const Field< Type > &fld, const ensightCells &part, bool parallel)
Write a field of cell values as an indirect list, using the cell ids from ensightCells.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
void copyComponent(const FieldContainer< Type > &input, const direction cmpt, UList< float > &cmptBuffer)
Copy specified field component into a scalar buffer. Works for various lists types. Must be adequately sized before calling.
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
label total() const noexcept
Same as totalSize()
Definition: ensightCells.H:231
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:51
void writeFieldComponents(ensightOutput::floatBufferType &scratch, ensightFile &os, const char *key, const FieldContainer< Type > &fld, bool parallel)
Write field content (component-wise) for the given ensight element type.
Generic templated field type.
Definition: Field.H:62
label size(const elemType etype) const
Processor-local size of the specified element type.
Definition: ensightFacesI.H:60
label nPoints
Sorting/classification of cells (3D) into corresponding ensight element types.
Definition: ensightCells.H:49
static Istream & input(Istream &is, IntRange< T > &range)
Definition: IntRanges.C:33
label size(const elemType etype) const
Processor-local size of the specified element type.
Definition: ensightCellsI.H:60
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition: UListI.H:391
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
DynamicList< float > floatBufferType
The list type used for component-wise buffering.
const labelList & faceIds() const noexcept
Processor-local face ids of all elements.
Definition: ensightFacesI.H:72
void read(Istream &, label &val, const dictionary &)
In-place read with dictionary lookup.
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
label index() const noexcept
The index in a list (0-based)
Definition: ensightPart.H:153
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
void writeLabelListList(ensightGeoFile &os, const labelUList &offsets, const labelUList &values, const label pointOffset)
Write CompactListList<label> by components.
globalIndex procAddr(aMesh.nFaces())
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
messageStream Info
Information stream (stdout output on master, null elsewhere)
int maxChunk_
Upper limit on number of items for bundled off-processor field transfers. The component-wise transfer...
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
bool writeCoordinates(ensightGeoFile &os, const label partId, const word &partName, const label nPoints, const FieldContainer< Foam::point > &fld, bool parallel)
Write coordinates (component-wise) for the given part.
const labelList & cellIds() const
Processor-local cell ids of all elements.
Definition: ensightCellsI.H:72