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-2019 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  {
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  (
384  dict.found("format")
385  && (IOstream::formatEnum(dict.get<word>("format")) == IOstream::ASCII)
386  );
387 
388  writeOpts_.append(false); // No append supported
389  writeOpts_.legacy(false); // No legacy supported
390 
391  writeOpts_.precision
392  (
393  dict.lookupOrDefault
394  (
395  "precision",
397  )
398  );
399 
400  // Info<< type() << " " << name() << " output-format: "
401  // << writeOpts_.description() << nl;
402 
403  const int padWidth = dict.lookupOrDefault<int>("width", 8);
404 
405  // Appropriate printf format - Enforce min/max sanity limits
406  if (padWidth < 1 || padWidth > 31)
407  {
408  printf_.clear();
409  }
410  else
411  {
412  printf_ = "%0" + std::to_string(padWidth) + "d";
413  }
414 
415  // useTimeName_ = dict.lookupOrDefault<bool>("useTimeName", false);
416 
417  useVerts_ = dict.lookupOrDefault<bool>("cellData", false);
418  pruneEmpty_ = dict.lookupOrDefault<bool>("prune", false);
419 
420  selectClouds_.clear();
421  dict.readIfPresent("clouds", selectClouds_);
422 
423  if (selectClouds_.empty())
424  {
425  selectClouds_.resize(1);
426  selectClouds_.first() =
427  dict.lookupOrDefault<word>("cloud", cloud::defaultName);
428  }
429 
430  selectFields_.clear();
431  dict.readIfPresent("fields", selectFields_);
432  selectFields_.uniq();
433 
434  // Actions to define selection
435  parcelSelect_ = dict.subOrEmptyDict("selection");
436 
437  // Output directory
438 
439  directory_.clear();
440  dict.readIfPresent("directory", directory_);
441 
442  if (directory_.size())
443  {
444  // User-defined output directory
445  directory_.expand();
446  if (!directory_.isAbsolute())
447  {
448  directory_ = time_.globalPath()/directory_;
449  }
450  }
451  else
452  {
453  // Standard postProcessing/ naming
454  directory_ = time_.globalPath()/functionObject::outputPrefix/name();
455  }
456  directory_.clean();
457 
458  return true;
459 }
460 
461 
463 {
464  return true;
465 }
466 
467 
469 {
470  const wordList cloudNames(mesh_.sortedNames<cloud>(selectClouds_));
471 
472  if (cloudNames.empty())
473  {
474  return true; // skip - not available
475  }
476 
477  const scalar timeValue = time_.value();
478 
479  const word timeDesc = "_" +
480  (
481  printf_.empty()
482  ? Foam::name(time_.timeIndex())
483  : word::printf(printf_, time_.timeIndex())
484  );
485 
486  Log << name() << " output Time: " << time_.timeName() << nl;
487 
488  // Each cloud separately
489  for (const word& cloudName : cloudNames)
490  {
491  // Legacy is not to be supported
492 
493  const fileName outputName
494  (
495  directory_/cloudName + timeDesc + ".vtp"
496  );
497 
498  // writeCloud() includes mkDir (on master)
499 
500  if (writeCloud(outputName, cloudName))
501  {
502  Log << " cloud : "
503  << time_.relativePath(outputName) << endl;
504 
505  if (Pstream::master())
506  {
507  // Add to file-series and emit as JSON
508  fileName seriesName(vtk::seriesWriter::base(outputName));
509 
510  vtk::seriesWriter& series = series_(seriesName);
511 
512  // First time?
513  // Load from file, verify against filesystem,
514  // prune time >= currentTime
515  if (series.empty())
516  {
517  series.load(seriesName, true, timeValue);
518  }
519 
520  series.append(timeValue, outputName);
521  series.write(seriesName);
522  }
523  }
524  }
525 
526  return true;
527 }
528 
529 
530 // ************************************************************************* //
Foam::IOobject::NO_WRITE
Definition: IOobject.H:130
runTime
engineTime & runTime
Definition: createEngineTime.H:13
Foam::vtk::writeListParallel
void writeListParallel(vtk::formatter &fmt, const UList< uint8_t > &values)
Write a list of uint8_t values.
Definition: foamVtkOutput.C:126
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:62
cloudName
const word cloudName(propsDict.get< word >("cloud"))
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
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:94
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:462
Cloud.H
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
Foam::functionObjects::fvMeshFunctionObject
Specialization of Foam::functionObject for an Foam::fvMesh, providing a reference to the Foam::fvMesh...
Definition: fvMeshFunctionObject.H:64
Foam::functionObjects::addToRunTimeSelectionTable
addToRunTimeSelectionTable(functionObject, add, dictionary)
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::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:62
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::vtk::fileAttr::NUMBER_OF_POINTS
"NumberOfPoints"
Foam::functionObjects::vtkCloud::write
virtual bool write()
Write fields.
Definition: vtkCloud.C:468
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:259
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:369
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:121
Foam::functionObjects::regionFunctionObject::read
virtual bool read(const dictionary &dict)
Read optional controls.
Definition: regionFunctionObject.C:166
Foam::log
dimensionedScalar log(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:262
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:236
Foam::vtk::fileTag::POINTS
"Points"
fvMesh.H
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
cloudNames
const wordList cloudNames(cloudFields.sortedToc())
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::UPstream::master
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:438
Foam::functionObjects::defineTypeNameAndDebug
defineTypeNameAndDebug(fvMeshFunctionObject, 0)
Foam::cloud
A cloud is a registry collection of lagrangian particles.
Definition: cloud.H:57
Foam::IOstreamOption::ASCII
"ascii"
Definition: IOstreamOption.H:66
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::IOstream::defaultPrecision
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:325
Foam::IOstreamOption::formatEnum
static streamFormat formatEnum(const word &formatName)
The stream format enum corresponding to the string.
Definition: IOstreamOption.C:56
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::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::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::IOobject::NO_READ
Definition: IOobject.H:123
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
Log
#define Log
Report write to Foam::Info if the local log switch is true.
Definition: messageStream.H:332