vtkCloud.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) 2018-2020 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 "vtkCloud.H"
29 #include "Cloud.H"
30 #include "dictionary.H"
31 #include "fvMesh.H"
32 #include "foamVtkOutputOptions.H"
34 #include "pointList.H"
35 #include "stringOps.H"
36 #include <fstream>
37 
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
42 namespace functionObjects
43 {
44  defineTypeNameAndDebug(vtkCloud, 0);
45  addToRunTimeSelectionTable(functionObject, vtkCloud, dictionary);
46 }
47 }
48 
49 
50 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
51 
52 void Foam::functionObjects::vtkCloud::writeVerts
53 (
54  autoPtr<vtk::formatter>& format,
55  const label nTotParcels
56 ) const
57 {
58  // No collectives - can skip on slave processors
59  if (!format) return;
60 
61  // Same payload for connectivity and offsets
62  const uint64_t payLoad = vtk::sizeofData<label>(nTotParcels);
63 
65 
66  //
67  // 'connectivity'
68  // = linear mapping onto points
69  //
70  {
71  format().beginDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY);
72  format().writeSize(payLoad);
73 
74  vtk::writeIdentity(format(), nTotParcels);
75 
76  format().flush();
77  format().endDataArray();
78  }
79 
80  //
81  // 'offsets' (connectivity offsets)
82  // = linear mapping onto points (with 1 offset)
83  //
84  {
85  format().beginDataArray<label>(vtk::dataArrayAttr::OFFSETS);
86  format().writeSize(payLoad);
87 
88  vtk::writeIdentity(format(), nTotParcels, 1);
89 
90  format().flush();
91  format().endDataArray();
92  }
93 
94  format().endTag(vtk::fileTag::VERTS);
95 }
96 
97 
98 bool Foam::functionObjects::vtkCloud::writeCloud
99 (
100  const fileName& file,
101  const word& cloudName
102 )
103 {
104  const auto* objPtr = mesh_.findObject<cloud>(cloudName);
105  if (!objPtr)
106  {
107  return false;
108  }
109 
110  objectRegistry obrTmp
111  (
112  IOobject
113  (
114  "vtk::vtkCloud::" + cloudName,
115  mesh_.time().constant(),
116  mesh_,
119  false
120  )
121  );
122 
123  objPtr->writeObjects(obrTmp);
124 
125  const auto* pointsPtr = cloud::findIOPosition(obrTmp);
126 
127  if (!pointsPtr)
128  {
129  // This should be impossible
130  return false;
131  }
132 
133  applyFilter_ = calculateFilter(obrTmp, log);
134  reduce(applyFilter_, orOp<bool>());
135 
136 
137  // Number of parcels (locally)
138  label nParcels = (applyFilter_ ? parcelAddr_.count() : pointsPtr->size());
139 
140  // Total number of parcels on all processes
141  const label nTotParcels = returnReduce(nParcels, sumOp<label>());
142 
143  if (applyFilter_)
144  {
145  // Report filtered/unfiltered count
146  Log << "After filtering using " << nTotParcels << '/'
147  << (returnReduce(pointsPtr->size(), sumOp<label>()))
148  << " parcels" << nl;
149  }
150 
151  if (pruneEmpty_ && !nTotParcels)
152  {
153  return false;
154  }
155 
156  std::ofstream os;
157  autoPtr<vtk::formatter> format;
158 
159  if (!file.hasExt("vtp"))
160  {
162  << type() << " File missing .vtp extension!" << nl << endl
163  << exit(FatalError);
164  }
165 
166  if (Pstream::master())
167  {
168  mkDir(file.path());
169  os.open(file);
170 
171  format = writeOpts_.newFormatter(os);
172 
173  // beginFile()
174 
175  // XML (inline)
176  format()
177  .xmlHeader()
178  .xmlComment
179  (
180  "case='" + time_.globalCaseName()
181  + "' cloud='" + cloudName
182  + "' time='" + time_.timeName()
183  + "' index='" + Foam::name(time_.timeIndex())
184  + "'"
185  )
186  .beginVTKFile<vtk::fileTag::POLY_DATA>();
187 
188 
189  // FieldData with TimeValue
190  format()
191  .beginFieldData()
192  .writeTimeValue(time_.value())
193  .endFieldData();
194 
195 
196  // writeGeometry()
197 
198  // beginPiece()
199  if (useVerts_)
200  {
201  format()
202  .tag
203  (
205  vtk::fileAttr::NUMBER_OF_POINTS, nTotParcels,
206  vtk::fileAttr::NUMBER_OF_VERTS, nTotParcels
207  );
208  }
209  else
210  {
211  format()
212  .tag
213  (
216  );
217  }
218 
219  // writePoints()
220  {
221  const uint64_t payLoad = vtk::sizeofData<float,3>(nTotParcels);
222 
224  .beginDataArray<float,3>(vtk::dataArrayAttr::POINTS);
225 
226  format().writeSize(payLoad);
227  }
228  }
229 
230 
231  if (applyFilter_)
232  {
233  vtk::writeListParallel(format.ref(), *pointsPtr, parcelAddr_);
234  }
235  else
236  {
237  vtk::writeListParallel(format.ref(), *pointsPtr);
238  }
239 
240 
241  if (Pstream::master())
242  {
243  format().flush();
244  format().endDataArray();
245  format().endTag(vtk::fileTag::POINTS);
246 
247  if (useVerts_)
248  {
249  writeVerts(format, nTotParcels);
250  }
251  }
252 
253 
254  // Prevent any possible conversion of positions as a field
255  obrTmp.filterKeys
256  (
257  [](const word& k)
258  {
259  return k.starts_with("position") || k.starts_with("coordinate");
260  },
261  true // prune
262  );
263 
264  // Restrict to specified fields
265  if (selectFields_.size())
266  {
267  obrTmp.filterKeys(selectFields_);
268  }
269 
270 
271  // Write fields
272 
273  if (Pstream::master())
274  {
275  if (useVerts_)
276  {
277  format().beginCellData();
278  }
279  else
280  {
281  format().beginPointData();
282  }
283  }
284 
285  DynamicList<word> written(obrTmp.size());
286 
287  written.append(writeFields<label>(format, obrTmp, nTotParcels));
288  written.append(writeFields<scalar>(format, obrTmp, nTotParcels));
289  written.append(writeFields<vector>(format, obrTmp, nTotParcels));
290 
291  if (Pstream::master())
292  {
293  if (useVerts_)
294  {
295  format().endCellData();
296  }
297  else
298  {
299  format().endPointData();
300  }
301 
302  format().endPiece();
304  .endVTKFile();
305  }
306 
307 
308  // Record information into the state (all processors)
309  //
310  // foName
311  // {
312  // cloudName
313  // {
314  // file "<case>/postProcessing/name/cloud1_0001.vtp";
315  // fields (U T rho);
316  // }
317  // }
318 
319  // Case-local file name with "<case>" to make relocatable
320  dictionary propsDict;
321  propsDict.add
322  (
323  "file",
324  time_.relativePath(file, true)
325  );
326  propsDict.add("fields", written);
327 
328  setObjectProperty(name(), cloudName, propsDict);
329 
330  return true;
331 }
332 
333 
334 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
335 
336 Foam::functionObjects::vtkCloud::vtkCloud
337 (
338  const word& name,
339  const Time& runTime,
340  const dictionary& dict
341 )
342 :
344  writeOpts_(vtk::formatType::INLINE_BASE64),
345  printf_(),
346  useVerts_(false),
347  pruneEmpty_(false),
348  applyFilter_(false),
349  selectClouds_(),
350  selectFields_(),
351  directory_(),
352  series_()
353 {
354  // May still want this? (OCT-2018)
355  // if (postProcess)
356  // {
357  // // Disable for post-process mode.
358  // // Emit as FatalError for the try/catch in the caller.
359  // FatalError
360  // << type() << " disabled in post-process mode"
361  // << exit(FatalError);
362  // }
363 
364  read(dict);
365 }
366 
367 
368 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
369 
371 {
373 
374  // We probably cannot trust old information after a reread
375  series_.clear();
376 
377  //
378  // Default format is xml base64. Legacy is not desired.
379  //
380  writeOpts_ = vtk::formatType::INLINE_BASE64;
381 
382  writeOpts_.ascii
383  (
386  );
387 
388  writeOpts_.append(false); // No append supported
389  writeOpts_.legacy(false); // No legacy supported
390 
391  writeOpts_.precision
392  (
393  dict.getOrDefault("precision", IOstream::defaultPrecision())
394  );
395 
396  // Info<< type() << " " << name() << " output-format: "
397  // << writeOpts_.description() << nl;
398 
399  const int padWidth = dict.getOrDefault<int>("width", 8);
400 
401  // Appropriate printf format - Enforce min/max sanity limits
402  if (padWidth < 1 || padWidth > 31)
403  {
404  printf_.clear();
405  }
406  else
407  {
408  printf_ = "%0" + std::to_string(padWidth) + "d";
409  }
410 
411  // useTimeName_ = dict.getOrDefault("useTimeName", false);
412 
413  useVerts_ = dict.getOrDefault("cellData", false);
414  pruneEmpty_ = dict.getOrDefault("prune", false);
415 
416  selectClouds_.clear();
417  dict.readIfPresent("clouds", selectClouds_);
418 
419  if (selectClouds_.empty())
420  {
421  selectClouds_.resize(1);
422  selectClouds_.first() =
423  dict.getOrDefault<word>("cloud", cloud::defaultName);
424  }
425 
426  selectFields_.clear();
427  dict.readIfPresent("fields", selectFields_);
428  selectFields_.uniq();
429 
430  // Actions to define selection
431  parcelSelect_ = dict.subOrEmptyDict("selection");
432 
433  // Output directory
434 
435  directory_.clear();
436  dict.readIfPresent("directory", directory_);
437 
438  if (directory_.size())
439  {
440  // User-defined output directory
441  directory_.expand();
442  if (!directory_.isAbsolute())
443  {
444  directory_ = time_.globalPath()/directory_;
445  }
446  }
447  else
448  {
449  // Standard postProcessing/ naming
450  directory_ = time_.globalPath()/functionObject::outputPrefix/name();
451  }
452  directory_.clean(); // Remove unneeded ".."
453 
454  return true;
455 }
456 
457 
459 {
460  return true;
461 }
462 
463 
465 {
466  const wordList cloudNames(mesh_.sortedNames<cloud>(selectClouds_));
467 
468  if (cloudNames.empty())
469  {
470  return true; // skip - not available
471  }
472 
473  const scalar timeValue = time_.value();
474 
475  const word timeDesc = "_" +
476  (
477  printf_.empty()
478  ? Foam::name(time_.timeIndex())
479  : word::printf(printf_, time_.timeIndex())
480  );
481 
482  Log << name() << " output Time: " << time_.timeName() << nl;
483 
484  // Each cloud separately
485  for (const word& cloudName : cloudNames)
486  {
487  // Legacy is not to be supported
488 
489  const fileName outputName
490  (
491  directory_/cloudName + timeDesc + ".vtp"
492  );
493 
494  // writeCloud() includes mkDir (on master)
495 
496  if (writeCloud(outputName, cloudName))
497  {
498  Log << " cloud : "
499  << time_.relativePath(outputName) << endl;
500 
501  if (Pstream::master())
502  {
503  // Add to file-series and emit as JSON
505 
506  vtk::seriesWriter& series = series_(seriesName);
507 
508  // First time?
509  // Load from file, verify against filesystem,
510  // prune time >= currentTime
511  if (series.empty())
512  {
513  series.load(seriesName, true, timeValue);
514  }
515 
516  series.append(timeValue, outputName);
517  series.write(seriesName);
518  }
519  }
520  }
521 
522  return true;
523 }
524 
525 
526 // ************************************************************************* //
Foam::IOobject::NO_WRITE
Definition: IOobject.H:195
runTime
engineTime & runTime
Definition: createEngineTime.H:13
Log
#define Log
Definition: PDRblock.C:35
Foam::Time
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:73
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:65
cloudName
const word cloudName(propsDict.get< word >("cloud"))
Foam::fileName
A class for handling file names.
Definition: fileName.H:73
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
Foam::vtk::seriesWriter::base
static fileName base(const fileName &outputName, char sep='_')
Extract the base name for a file series.
Definition: foamVtkSeriesWriter.C:91
Foam::vtk::dataArrayAttr::OFFSETS
"offsets"
Foam::functionObjects::vtkCloud::read
virtual bool read(const dictionary &dict)
Read the vtkCloud specification.
Definition: vtkCloud.C:370
Foam::read
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:108
Foam::vtk::fileTag::POLY_DATA
"PolyData"
Foam::vtk::writeIdentity
void writeIdentity(vtk::formatter &fmt, const label len, label start=0)
Write an identity list of labels.
Definition: foamVtkOutput.C:96
Foam::functionObjects::vtkCloud::execute
virtual bool execute()
Execute, currently does nothing.
Definition: vtkCloud.C:458
Cloud.H
Foam::UPstream::master
static bool master(const label communicator=worldComm)
Am I the master process.
Definition: UPstream.H:457
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::functionObjects::fvMeshFunctionObject
Specialization of Foam::functionObject for an Foam::fvMesh, providing a reference to the Foam::fvMesh...
Definition: fvMeshFunctionObject.H:64
outputName
word outputName("finiteArea-edges.obj")
format
word format(conversionProperties.get< word >("format"))
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::vtk::fileAttr::NUMBER_OF_POINTS
"NumberOfPoints"
Foam::functionObjects::vtkCloud::write
virtual bool write()
Write fields.
Definition: vtkCloud.C:464
vtkCloud.H
pointList.H
propsDict
IOdictionary propsDict(IOobject("particleTrackProperties", runTime.constant(), mesh, IOobject::MUST_READ_IF_MODIFIED))
Foam::vtk::fileTag::VERTS
"Verts"
Foam::functionObject::outputPrefix
static word outputPrefix
Directory prefix.
Definition: functionObject.H:376
Foam::vtk::seriesWriter::load
label load(const fileName &seriesName, const bool checkFiles=false, const scalar restartTime=ROOTVGREAT)
Clear contents and reload by parsing the specified file.
Definition: foamVtkSeriesWriter.C:366
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
Foam::functionObjects::regionFunctionObject::read
virtual bool read(const dictionary &dict)
Read optional controls.
Definition: regionFunctionObject.C:173
Foam::log
dimensionedScalar log(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:262
os
OBJstream os(runTime.globalPath()/outputName)
addToRunTimeSelectionTable.H
Macros for easy insertion into run-time selection tables.
Foam::vtk::formatType::INLINE_BASE64
XML inline base64, base64Formatter.
Foam::vtk::seriesWriter
Provides a means of accumulating and generating VTK file series.
Definition: foamVtkSeriesWriter.H:75
Foam::vtk::seriesWriter::write
static void write(const fileName &base, const UList< instant > &series, const char sep='_')
Write file series (JSON format) to disk, for specified instances.
Definition: foamVtkSeriesWriter.C:233
Foam::vtk::fileTag::POINTS
"Points"
fvMesh.H
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::cloud::defaultName
static word defaultName
The default cloud name: defaultCloud.
Definition: cloud.H:90
foamVtkOutputOptions.H
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::IOstream::defaultPrecision
static unsigned int defaultPrecision() noexcept
Return the default precision.
Definition: IOstream.H:342
Foam::cloud
A cloud is a registry collection of lagrangian particles.
Definition: cloud.H:57
Foam::IOstreamOption::BINARY
"binary"
Definition: IOstreamOption.H:73
Foam::IOstreamOption::ASCII
"ascii" (normal default)
Definition: IOstreamOption.H:72
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::functionObjects::addToRunTimeSelectionTable
addToRunTimeSelectionTable(functionObject, ObukhovLength, dictionary)
Foam::IOstreamOption::formatEnum
static streamFormat formatEnum(const word &formatName, const streamFormat deflt=streamFormat::ASCII)
Definition: IOstreamOption.C:53
Foam::List< word >
Foam::vtk::seriesWriter::empty
bool empty() const noexcept
True if there are no data sets.
Definition: foamVtkSeriesWriterI.H:30
Foam::type
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:590
k
label k
Boltzmann constant.
Definition: LISASMDCalcMethod2.H:41
dictionary.H
Foam::functionObjects::defineTypeNameAndDebug
defineTypeNameAndDebug(ObukhovLength, 0)
Foam::cloud::findIOPosition
static const IOField< point > * findIOPosition(const objectRegistry &obr)
Locate the "position" IOField within object registry.
Definition: cloud.H:153
Foam::vtk::dataArrayAttr::CONNECTIVITY
"connectivity"
Foam::vtk::fileAttr::NUMBER_OF_VERTS
"NumberOfVerts"
Foam::name
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
Foam::word::printf
static word printf(const char *fmt, const PrimitiveType &val)
Use a printf-style formatter for a primitive.
Foam::vtk::fileTag::PIECE
"Piece"
Foam::vtk::seriesWriter::append
bool append(const fileNameInstant &inst)
Append the specified file instant.
Definition: foamVtkSeriesWriterI.H:49
Foam::vtk::dataArrayAttr::POINTS
"Points"
Foam::vtk::writeListParallel
void writeListParallel(vtk::formatter &fmt, const UList< Type > &values)
Write a list of values.
Definition: foamVtkOutputTemplates.C:164
Foam::IOobject::NO_READ
Definition: IOobject.H:188
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
stringOps.H