vtkWrite.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) 2017-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 "vtkWrite.H"
29 #include "dictionary.H"
30 #include "Time.H"
31 #include "areaFields.H"
32 #include "stringListOps.H"
33 #include "foamVtkInternalWriter.H"
34 #include "foamVtkPatchWriter.H"
35 #include "foamVtkSeriesWriter.H"
36 #include "foamVtmWriter.H"
38 
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 
41 namespace Foam
42 {
43 namespace functionObjects
44 {
45  defineTypeNameAndDebug(vtkWrite, 0);
46  addToRunTimeSelectionTable(functionObject, vtkWrite, dictionary);
47 }
48 }
49 
50 
51 // Implementation
52 #include "vtkWriteImpl.C"
53 
54 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55 
56 Foam::label Foam::functionObjects::vtkWrite::writeAllVolFields
57 (
58  autoPtr<vtk::internalWriter>& internalWriter,
59  UPtrList<vtk::patchWriter>& patchWriters,
60  const fvMeshSubset& proxy,
61  const wordHashSet& candidateNames
62 ) const
63 {
64  label count = 0;
65 
66  {
67  #undef doLocalCode
68  #define doLocalCode(FieldType) \
69  count += writeVolFieldsImpl<FieldType> \
70  ( \
71  internalWriter, \
72  patchWriters, \
73  proxy, \
74  candidateNames \
75  );
76 
82 
83  #undef doLocalCode
84  }
85 
86  return count;
87 }
88 
89 
90 Foam::label Foam::functionObjects::vtkWrite::writeAllVolFields
91 (
92  autoPtr<vtk::internalWriter>& internalWriter,
93  const autoPtr<volPointInterpolation>& pInterp,
94 
95  UPtrList<vtk::patchWriter>& patchWriters,
96  const UPtrList<PrimitivePatchInterpolation<primitivePatch>>& patchInterps,
97  const fvMeshSubset& proxy,
98  const wordHashSet& candidateNames
99 ) const
100 {
101  label count = 0;
102 
103  {
104  #undef doLocalCode
105  #define doLocalCode(FieldType) \
106  count += writeVolFieldsImpl<FieldType> \
107  ( \
108  internalWriter, pInterp, \
109  patchWriters, patchInterps, \
110  proxy, \
111  candidateNames \
112  );
113 
119 
120  #undef doLocalCode
121  }
122 
123  return count;
124 }
125 
126 
127 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
128 
129 Foam::functionObjects::vtkWrite::vtkWrite
130 (
131  const word& name,
132  const Time& runTime,
133  const dictionary& dict
134 )
135 :
137  outputDir_(),
138  printf_(),
139  writeOpts_(vtk::formatType::INLINE_BASE64),
140  verbose_(true),
141  doInternal_(true),
142  doBoundary_(true),
143  oneBoundary_(false),
144  interpolate_(false),
145  decompose_(false),
146  writeIds_(false),
147  meshState_(polyMesh::TOPO_CHANGE),
148  selectRegions_(),
149  selectPatches_(),
150  blockPatches_(),
151  selectFields_(),
152  blockFields_(),
153  selection_(),
154  meshes_(),
155  meshSubsets_(),
156  vtuMappings_(),
157  series_()
158 {
159  // May still want this? (OCT-2018)
160  // if (postProcess)
161  // {
162  // // Disable for post-process mode.
163  // // Emit as FatalError for the try/catch in the caller.
164  // FatalError
165  // << type() << " disabled in post-process mode"
166  // << exit(FatalError);
167  // }
169  read(dict);
170 }
171 
172 
173 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
174 
176 {
178 
179  readSelection(dict);
180 
181  // We probably cannot trust old information after a reread
182  series_.clear();
183 
184  // verbose_ = dict.getOrDefault("verbose", true);
185  doInternal_ = dict.getOrDefault("internal", true);
186  doBoundary_ = dict.getOrDefault("boundary", true);
187  oneBoundary_ = dict.getOrDefault("single", false);
188  interpolate_ = dict.getOrDefault("interpolate", false);
189 
190  //
191  // Writer options - default is xml base64
192  //
193  writeOpts_ = vtk::formatType::INLINE_BASE64;
194 
195  writeOpts_.ascii
196  (
199  );
200 
201  writeOpts_.legacy(dict.getOrDefault("legacy", false));
202 
203  writeOpts_.precision
204  (
205  dict.getOrDefault("precision", IOstream::defaultPrecision())
206  );
207 
208  // Info<< type() << " " << name() << " output-format: "
209  // << writeOpts_.description() << nl;
210 
211  const int padWidth = dict.getOrDefault<int>("width", 8);
212 
213  // Appropriate printf format - Enforce min/max sanity limits
214  if (padWidth < 1 || padWidth > 31)
215  {
216  printf_.clear();
217  }
218  else
219  {
220  printf_ = "%0" + std::to_string(padWidth) + "d";
221  }
222 
223  //
224  // Other options
225  //
226 
227  decompose_ = dict.getOrDefault("decompose", false);
228  writeIds_ = dict.getOrDefault("writeIds", false);
229 
230 
231  // Output directory
232 
233  outputDir_.clear();
234  dict.readIfPresent("directory", outputDir_);
235 
236  if (outputDir_.size())
237  {
238  // User-defined output directory
239  outputDir_.expand();
240  if (!outputDir_.isAbsolute())
241  {
242  outputDir_ = time_.globalPath()/outputDir_;
243  }
244  }
245  else
246  {
247  // Standard postProcessing/ naming
248  outputDir_ = time_.globalPath()/functionObject::outputPrefix/name();
249  }
250  outputDir_.clean(); // Remove unneeded ".."
251 
252  return true;
253 }
254 
257 {
258  return true;
259 }
260 
261 
263 {
264  // const word timeDesc =
265  // useTimeName ? time_.timeName() : Foam::name(time_.timeIndex());
266 
267  const word timeDesc = "_" +
268  (
269  printf_.empty()
270  ? Foam::name(time_.timeIndex())
271  : word::printf(printf_, time_.timeIndex())
272  );
273 
274  const scalar timeValue = time_.value();
275 
276  update();
277 
278  if (meshes_.empty() || (!doInternal_ && !doBoundary_))
279  {
280  // Skip
281  return true;
282  }
283 
284 
285  fileName vtkName = time_.globalCaseName();
286 
287  vtk::vtmWriter vtmMultiRegion;
288 
289  Info<< name() << " output Time: " << time_.timeName() << nl;
290 
291  label regioni = 0;
292  for (const word& regionName : meshes_.sortedToc())
293  {
295 
296  auto& meshProxy = meshSubsets_[regioni];
297  auto& vtuMeshCells = vtuMappings_[regioni];
298  ++regioni;
299 
300  const fvMesh& baseMesh = meshProxy.baseMesh();
301 
302 
303  // Output fields MUST be specified to avoid accidentally
304  // writing everything. Can still use ".*" for everything
305 
306  wordHashSet candidateNames(0);
307 
308  if (!selectFields_.empty())
309  {
310  if (!blockFields_.empty())
311  {
312  // With 'allow' and 'deny' filters
313  wordRes::filter filter(selectFields_, blockFields_);
314 
315  candidateNames = baseMesh.names<void>(filter);
316  }
317  else
318  {
319  // With 'allow' filter only
320  candidateNames = baseMesh.names<void>(selectFields_);
321  }
322  }
323 
324  // Prune restart fields
325  candidateNames.filterKeys
326  (
327  [](const word& k){ return k.ends_with("_0"); },
328  true // prune
329  );
330 
331  const label nVolFields =
332  (
333  (doInternal_ || doBoundary_)
334  ? baseMesh.count
335  (
336  stringListOps::foundOp<word>(fieldTypes::volume),
337  candidateNames
338  )
339  : 0
340  );
341 
342  // Undecided if we want to automatically support DimensionedFields
343  // or only on demand:
344  const label nDimFields = 0;
345  // (
346  // (doInternal_ || doBoundary_)
347  // ? baseMesh.count
348  // (
349  // stringListOps::foundOp<word>(fieldTypes::internal),
350  // candidateNames
351  // )
352  // : 0
353  // );
354 
355 
356  // Setup for the vtm writer.
357  // For legacy format, the information added is simply ignored.
358 
359  fileName vtmOutputBase
360  (
361  outputDir_/regionDir/vtkName + timeDesc
362  );
363 
364  // Combined internal + boundary in a vtm file
366 
367  // Collect individual boundaries into a vtm file
369 
370  // Setup the internal writer
371  autoPtr<vtk::internalWriter> internalWriter;
372 
373  // Interpolator for volume and dimensioned fields
374  autoPtr<volPointInterpolation> pInterp;
375 
376  if (doInternal_)
377  {
378  if (vtuMeshCells.empty())
379  {
380  // Use the appropriate mesh (baseMesh or subMesh)
381  vtuMeshCells.reset(meshProxy.mesh());
382 
383  if (interpolate_ && vtuMeshCells.manifold())
384  {
385  interpolate_ = false;
387  << "Manifold cells detected - disabling PointData"
388  << endl;
389  }
390  }
391 
393  (
394  meshProxy.mesh(),
395  vtuMeshCells,
396  writeOpts_,
397  // Output name for internal
398  (
399  writeOpts_.legacy()
400  ? vtmOutputBase
401  : (vtmOutputBase / "internal")
402  ),
404  );
405 
406  Info<< " Internal : "
407  << time_.relativePath(internalWriter->output())
408  << endl;
409 
410  // No sub-block for internal
411  vtmWriter.append_vtu
412  (
413  "internal",
414  vtmOutputBase.name()/"internal"
415  );
416 
417  internalWriter->writeTimeValue(timeValue);
418  internalWriter->writeGeometry();
419 
420  if (interpolate_)
421  {
422  pInterp.reset(new volPointInterpolation(meshProxy.mesh()));
423  }
424  }
425 
426 
427  // Setup the patch writers
428 
429  const polyBoundaryMesh& patches = meshProxy.mesh().boundaryMesh();
430 
431  PtrList<vtk::patchWriter> patchWriters;
432  PtrList<PrimitivePatchInterpolation<primitivePatch>> patchInterps;
433 
435  if (doBoundary_)
436  {
437  patchIds = getSelectedPatches(patches);
438  }
439 
440  if (oneBoundary_ && patchIds.size())
441  {
443  (
444  meshProxy.mesh(),
445  patchIds,
446  writeOpts_,
447  // Output name for one patch: "boundary"
448  (
449  writeOpts_.legacy()
450  ? (outputDir_/regionDir/"boundary"/"boundary" + timeDesc)
451  : (vtmOutputBase / "boundary")
452  ),
454  );
455 
456  // No sub-block for one-patch
457  vtmWriter.append_vtp
458  (
459  "boundary",
460  vtmOutputBase.name()/"boundary"
461  );
462 
463  Info<< " Boundaries: "
464  << time_.relativePath(writer->output()) << nl;
465 
466 
467  writer->writeTimeValue(timeValue);
468  writer->writeGeometry();
469 
470  // Transfer writer to list for later use
471  patchWriters.resize(1);
472  patchWriters.set(0, writer);
473 
474  // Avoid patchInterpolation for each sub-patch
475  patchInterps.resize(1); // == nullptr
476  }
477  else if (patchIds.size())
478  {
479  patchWriters.resize(patchIds.size());
480  if (interpolate_)
481  {
482  patchInterps.resize(patchIds.size());
483  }
484 
485  label nPatchWriters = 0;
486  label nPatchInterps = 0;
487 
488  for (const label patchId : patchIds)
489  {
490  const polyPatch& pp = patches[patchId];
491 
493  (
494  meshProxy.mesh(),
495  labelList(one{}, pp.index()),
496  writeOpts_,
497  // Output name for patch: "boundary"/name
498  (
499  writeOpts_.legacy()
500  ?
501  (
502  outputDir_/regionDir/pp.name()
503  / (pp.name()) + timeDesc
504  )
505  : (vtmOutputBase / "boundary" / pp.name())
506  ),
508  );
509 
510  if (!nPatchWriters)
511  {
512  vtmWriter.beginBlock("boundary");
513  vtmBoundaries.beginBlock("boundary");
514  }
515 
516  vtmWriter.append_vtp
517  (
518  pp.name(),
519  vtmOutputBase.name()/"boundary"/pp.name()
520  );
521 
522  vtmBoundaries.append_vtp
523  (
524  pp.name(),
525  "boundary"/pp.name()
526  );
527 
528  Info<< " Boundary : "
529  << time_.relativePath(writer->output()) << nl;
530 
531  writer->writeTimeValue(timeValue);
532  writer->writeGeometry();
533 
534  // Transfer writer to list for later use
536 
537  if (patchInterps.size())
538  {
539  patchInterps.set
540  (
541  nPatchInterps++,
542  new PrimitivePatchInterpolation<primitivePatch>(pp)
543  );
544  }
545  }
546 
547  if (nPatchWriters)
548  {
549  vtmWriter.endBlock("boundary");
550  vtmBoundaries.endBlock("boundary");
551  }
552 
553  patchWriters.resize(nPatchWriters);
554  patchInterps.resize(nPatchInterps);
555  }
556 
557  // CellData
558  {
559  if (internalWriter)
560  {
561  // Optionally with cellID and procID fields
562  internalWriter->beginCellData
563  (
564  (writeIds_ ? 1 + (internalWriter->parallel() ? 1 : 0) : 0)
566  );
567 
568  if (writeIds_)
569  {
570  internalWriter->writeCellIDs();
571  internalWriter->writeProcIDs(); // parallel only
572  }
573  }
574 
575  if (nVolFields)
576  {
577  for (vtk::patchWriter& writer : patchWriters)
578  {
579  // Optionally with patchID field
580  writer.beginCellData
581  (
582  (writeIds_ ? 1 : 0)
583  + nVolFields
584  );
585 
586  if (writeIds_)
587  {
588  writer.writePatchIDs();
589  }
590  }
591  }
592 
594  (
596  patchWriters,
597  meshProxy,
598  candidateNames
599  );
600 
601  // writeAllDimFields
602  // (
603  // internalWriter,
604  // meshProxy,
605  // candidateNames
606  // );
607 
608  // End CellData is implicit
609  }
610 
611 
612  // PointData
613  // - only construct pointMesh on request since it constructs
614  // edge addressing
615  if (interpolate_)
616  {
617  // Begin PointData
618  if (internalWriter)
619  {
620  internalWriter->beginPointData
621  (
623  );
624  }
625 
626  forAll(patchWriters, writeri)
627  {
628  const label nPatchFields =
629  (
630  writeri < patchInterps.size() && patchInterps.set(writeri)
631  ? nVolFields
632  : 0
633  );
634 
635  if (nPatchFields)
636  {
637  patchWriters[writeri].beginPointData(nPatchFields);
638  }
639  }
640 
642  (
645  meshProxy,
646  candidateNames
647  );
648 
649  // writeAllDimFields
650  // (
651  // internalWriter, pInterp,
652  // meshProxy,
653  // candidateNames
654  // );
655 
656  // writeAllPointFields
657  // (
658  // internalWriter,
659  // patchWriters,
660  // meshProxy,
661  // candidateNames
662  // );
663 
664  // End PointData is implicit
665  }
666 
667 
668  // Finish writers
669  if (internalWriter)
670  {
671  internalWriter->close();
672  }
673 
674  for (vtk::patchWriter& writer : patchWriters)
675  {
676  writer.close();
677  }
678 
679  pInterp.clear();
680  patchWriters.clear();
681  patchInterps.clear();
682 
683 
684  // Collective output
685 
686  if (Pstream::master())
687  {
688  // Naming for vtm, file series etc.
689  fileName outputName(vtmOutputBase);
690 
691  if (writeOpts_.legacy())
692  {
693  if (doInternal_)
694  {
695  // Add to file-series and emit as JSON
696 
698 
699  fileName seriesName(vtk::seriesWriter::base(outputName));
700 
701  vtk::seriesWriter& series = series_(seriesName);
702 
703  // First time?
704  // Load from file, verify against filesystem,
705  // prune time >= currentTime
706  if (series.empty())
707  {
708  series.load(seriesName, true, timeValue);
709  }
710 
711  series.append(timeValue, timeDesc);
712  series.write(seriesName);
713  }
714  }
715  else
716  {
717  if (vtmWriter.size())
718  {
719  // Emit ".vtm"
720 
721  outputName.ext(vtmWriter.ext());
722 
723  vtmWriter.setTime(timeValue);
724  vtmWriter.write(outputName);
725 
726  fileName seriesName(vtk::seriesWriter::base(outputName));
727 
728  vtk::seriesWriter& series = series_(seriesName);
729 
730  // First time?
731  // Load from file, verify against filesystem,
732  // prune time >= currentTime
733  if (series.empty())
734  {
735  series.load(seriesName, true, timeValue);
736  }
737 
738  series.append(timeValue, outputName);
739  series.write(seriesName);
740 
741  // Add to multi-region vtm
742  vtmMultiRegion.add(regionName, regionDir, vtmWriter);
743  }
744 
745  if (vtmBoundaries.size())
746  {
747  // Emit "boundary.vtm" with collection of boundaries
748 
749  // Naming for vtm
750  fileName outputName(vtmOutputBase / "boundary");
751  outputName.ext(vtmBoundaries.ext());
752 
753  vtmBoundaries.setTime(timeValue);
754  vtmBoundaries.write(outputName);
755  }
756  }
757  }
758  }
759 
760 
761  // Emit multi-region vtm
762  if (Pstream::master() && meshes_.size() > 1)
763  {
764  fileName outputName
765  (
766  outputDir_/vtkName + "-regions" + timeDesc + ".vtm"
767  );
768 
769  vtmMultiRegion.setTime(timeValue);
770  vtmMultiRegion.write(outputName);
771 
772  fileName seriesName(vtk::seriesWriter::base(outputName));
773 
774  vtk::seriesWriter& series = series_(seriesName);
775 
776  // First time?
777  // Load from file, verify against filesystem,
778  // prune time >= currentTime
779  if (series.empty())
780  {
781  series.load(seriesName, true, timeValue);
782  }
783 
784  series.append(timeValue, outputName);
785  series.write(seriesName);
786  }
787 
788  return true;
789 }
790 
791 
793 {
794  meshSubsets_.clear();
795  vtuMappings_.clear();
796  meshes_.clear();
797 
798  return true;
799 }
800 
801 
802 // ************************************************************************* //
label patchId(-1)
Provides a means of accumulating file entries for generating a vtkMultiBlockDataSet (...
Definition: foamVtmWriter.H:87
GeometricField< symmTensor, fvPatchField, volMesh > volSymmTensorField
Definition: volFieldsFwd.H:88
labelList patchIds
dictionary dict
defineTypeNameAndDebug(ObukhovLength, 0)
A class for handling file names.
Definition: fileName.H:71
static fileName base(const fileName &outputName, char sep='_')
Extract the base name for a file series.
virtual bool write()
Write fields.
Definition: vtkWrite.C:255
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
const word & regionName() const
The mesh region name or word::null if polyMesh::defaultRegion.
Definition: polyMesh.C:841
const word fileExtension
Legacy file extension ("vtk")
GeometricField< tensor, fvPatchField, volMesh > volTensorField
Definition: volFieldsFwd.H:89
label writeAllVolFields(ensightCase &ensCase, const ensightMesh &ensMesh, const IOobjectList &objects, const bool nearCellValue=false)
label write(const fileName &file)
Open file for writing (creates parent directory) and write the blocks and TimeValue.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
"ascii" (normal default)
wordList names() const
The unsorted names of all objects.
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:639
static unsigned int defaultPrecision() noexcept
Return the default precision.
Definition: IOstream.H:416
fileName vtmOutputBase(outputDir/regionDir/vtkName+timeDesc)
const label nDimFields
Operations on lists of strings.
label k
Boltzmann constant.
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:85
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
GeometricField< sphericalTensor, fvPatchField, volMesh > volSphericalTensorField
Definition: volFieldsFwd.H:87
Macros for easy insertion into run-time selection tables.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:84
static streamFormat formatEnum(const word &formatName, const streamFormat deflt=streamFormat::ASCII)
The stream format enum corresponding to the string (ascii | binary).
Foam::word regionName(Foam::polyMesh::defaultRegion)
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
word outputName("finiteArea-edges.obj")
label count(const char *clsName) const
The number of objects of the given class name.
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
A class for handling words, derived from Foam::string.
Definition: word.H:63
Functor wrapper of allow/deny lists of wordRe for filtering.
Definition: wordRes.H:210
void setTime(scalar timeValue)
Define "TimeValue" for FieldData (name as per Catalyst output)
formatType
The output format type for file contents.
Definition: foamVtkCore.H:66
label nPatchWriters
const label nVolFields
autoPtr< vtk::internalWriter > internalWriter
HashSet< word, Hash< word > > wordHashSet
A HashSet of words, uses string hasher.
Definition: HashSet.H:73
static word printf(const char *fmt, const PrimitiveType &val)
Use a printf-style formatter for a primitive.
const wordList volume
Standard volume field types (scalar, vector, tensor, etc)
vtk::internalMeshWriter writer(topoMesh, topoCells, vtk::formatType::INLINE_ASCII, runTime.path()/"blockTopology")
mesh update()
addToRunTimeSelectionTable(functionObject, ObukhovLength, dictionary)
PtrList< PrimitivePatchInterpolation< primitivePatch > > patchInterps
#define WarningInFunction
Report a warning using Foam::Warning.
vtk::vtmWriter vtmBoundaries
const word & regionDir
virtual bool read(const dictionary &dict)
Read and set the function object if its data have changed.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:79
static bool master(const label communicator=worldComm)
Am I the master rank.
Definition: UPstream.H:672
const polyBoundaryMesh & patches
vtk::vtmWriter vtmWriter
static word outputPrefix
Directory prefix.
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual bool execute()
Execute - does nothing.
Definition: vtkWrite.C:249
XML inline base64, base64Formatter.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:73
List< label > labelList
A List of labels.
Definition: List.H:62
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
virtual bool read(const dictionary &dict)
Read the vtkWrite specification.
Definition: vtkWrite.C:168
virtual bool end()
On end - cleanup internal allocations.
Definition: vtkWrite.C:785
void add(const word &blockName, const vtmWriter &other)
Add in content from another vtm and place under the given block name.
PtrList< vtk::patchWriter > patchWriters
Virtual base class for function objects with a reference to Time.
Namespace for OpenFOAM.
autoPtr< volPointInterpolation > pInterp
#define doLocalCode(FieldType)