ENH: refactor coordSet writers (#2347)

- the very old 'writer' class was fully stateless and always templated
  on an particular output type.

  This is now replaced with a 'coordSetWriter' with similar concepts
  as previously introduced for surface writers (#1206).

  - writers change from being a generic state-less set of routines to
    more properly conforming to the normal notion of a writer.

  - Parallel data is done *outside* of the writers, since they are used
    in a wide variety of contexts and the caller is currently still in
    a better position for deciding how to combine parallel data.

ENH: update sampleSets to sample on per-field basis (#2347)

- sample/write a field in a single step.

- support for 'sampleOnExecute' to obtain values at execution
  intervals without writing.

- support 'sets' input as a dictionary entry (as well as a list),
  which is similar to the changes for sampled-surface and permits use
  of changeDictionary to modify content.

- globalIndex for gather to reduce parallel communication, less code

- qualify the sampleSet results (properties) with the name of the set.
  The sample results were previously without a qualifier, which meant
  that only the last property value was actually saved (previous ones
  overwritten).

  For example,
  ```
    sample1
    {
        scalar
        {
            average(line,T) 349.96521;
            min(line,T)     349.9544281;
            max(line,T)     350;
            average(cells,T) 349.9854619;
            min(cells,T)    349.6589286;
            max(cells,T)    350.4967271;
            average(line,epsilon) 0.04947733869;
            min(line,epsilon) 0.04449639927;
            max(line,epsilon) 0.06452856475;
        }
        label
        {
            size(line,T)    79;
            size(cells,T)   1720;
            size(line,epsilon) 79;
        }
    }
  ```

ENH: update particleTracks application

- use globalIndex to manage original parcel addressing and
  for gathering. Simplify code by introducing a helper class,
  storing intermediate fields in hash tables instead of
  separate lists.

ADDITIONAL NOTES:

- the regionSizeDistribution largely retains separate writers since
  the utility of placing sum/dev/count for all fields into a single file
  is questionable.

- the streamline writing remains a "soft" upgrade, which means that
  scalar and vector fields are still collected a priori and not
  on-the-fly.  This is due to how the streamline infrastructure is
  currently handled (should be upgraded in the future).
This commit is contained in:
Mark Olesen
2022-02-25 14:50:01 +01:00
parent 8a9ae839ce
commit c3e14ffdd5
96 changed files with 8735 additions and 5178 deletions

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -40,7 +40,7 @@ Description
#include "IOdictionary.H" #include "IOdictionary.H"
#include "searchableSurfaces.H" #include "searchableSurfaces.H"
#include "conformalVoronoiMesh.H" #include "conformalVoronoiMesh.H"
#include "vtkSetWriter.H" #include "vtkCoordSetWriter.H"
using namespace Foam; using namespace Foam;
@ -106,8 +106,10 @@ int main(int argc, char *argv[])
foamyHexMeshDict.getOrDefault("singleRegionName", true) foamyHexMeshDict.getOrDefault("singleRegionName", true)
); );
autoPtr<coordSetWriter> setWriterPtr(new coordSetWriters::vtkWriter());
// Write some stats // Write some stats
allGeometry.writeStats(List<wordList>(0), Info); allGeometry.writeStats(List<wordList>(), Info);
// Check topology // Check topology
allGeometry.checkTopology(true); allGeometry.checkTopology(true);
// Check geometry // Check geometry
@ -115,7 +117,7 @@ int main(int argc, char *argv[])
( (
100.0, // max size ratio 100.0, // max size ratio
1e-9, // intersection tolerance 1e-9, // intersection tolerance
autoPtr<writer<scalar>>(new vtkSetWriter<scalar>()), setWriterPtr,
0.01, // min triangle quality 0.01, // min triangle quality
true true
); );

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2021 OpenCFD Ltd. Copyright (C) 2015-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -51,7 +51,7 @@ Description
#include "refinementParameters.H" #include "refinementParameters.H"
#include "snapParameters.H" #include "snapParameters.H"
#include "layerParameters.H" #include "layerParameters.H"
#include "vtkSetWriter.H" #include "vtkCoordSetWriter.H"
#include "faceSet.H" #include "faceSet.H"
#include "motionSmoother.H" #include "motionSmoother.H"
#include "polyTopoChange.H" #include "polyTopoChange.H"
@ -854,19 +854,25 @@ int main(int argc, char *argv[])
const bool keepPatches(meshDict.getOrDefault("keepPatches", false)); const bool keepPatches(meshDict.getOrDefault("keepPatches", false));
// format to be used for writing lines // Writer for writing lines
autoPtr<coordSetWriter> setFormatter;
{
const word setFormat const word setFormat
( (
meshDict.getOrDefault<word> meshDict.getOrDefault<word>
( (
"setFormat", "setFormat",
vtkSetWriter<scalar>::typeName coordSetWriters::vtkWriter::typeName // Default: "vtk"
) )
); );
const autoPtr<writer<scalar>> setFormatter
setFormatter = coordSetWriter::New
( (
writer<scalar>::New(setFormat) setFormat,
meshDict.subOrEmptyDict("formatOptions").optionalSubDict(setFormat)
); );
}
const scalar maxSizeRatio const scalar maxSizeRatio
( (

View File

@ -11,7 +11,7 @@
#include "checkTools.H" #include "checkTools.H"
#include "functionObject.H" #include "functionObject.H"
#include "vtkSetWriter.H" #include "vtkCoordSetWriter.H"
#include "vtkSurfaceWriter.H" #include "vtkSurfaceWriter.H"
#include "cyclicACMIPolyPatch.H" #include "cyclicACMIPolyPatch.H"
@ -537,7 +537,7 @@ Foam::label Foam::checkGeometry
const polyMesh& mesh, const polyMesh& mesh,
const bool allGeometry, const bool allGeometry,
autoPtr<surfaceWriter>& surfWriter, autoPtr<surfaceWriter>& surfWriter,
const autoPtr<writer<scalar>>& setWriter autoPtr<coordSetWriter>& setWriter
) )
{ {
label noFailedChecks = 0; label noFailedChecks = 0;
@ -594,7 +594,7 @@ Foam::label Foam::checkGeometry
<< nonAlignedPoints.name() << endl; << nonAlignedPoints.name() << endl;
nonAlignedPoints.instance() = mesh.pointsInstance(); nonAlignedPoints.instance() = mesh.pointsInstance();
nonAlignedPoints.write(); nonAlignedPoints.write();
if (setWriter) if (setWriter && setWriter->enabled())
{ {
mergeAndWrite(*setWriter, nonAlignedPoints); mergeAndWrite(*setWriter, nonAlignedPoints);
} }
@ -628,7 +628,7 @@ Foam::label Foam::checkGeometry
<< " non closed cells to set " << cells.name() << endl; << " non closed cells to set " << cells.name() << endl;
cells.instance() = mesh.pointsInstance(); cells.instance() = mesh.pointsInstance();
cells.write(); cells.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, cells); mergeAndWrite(*surfWriter, cells);
} }
@ -644,7 +644,7 @@ Foam::label Foam::checkGeometry
<< aspectCells.name() << endl; << aspectCells.name() << endl;
aspectCells.instance() = mesh.pointsInstance(); aspectCells.instance() = mesh.pointsInstance();
aspectCells.write(); aspectCells.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, aspectCells); mergeAndWrite(*surfWriter, aspectCells);
} }
@ -665,7 +665,7 @@ Foam::label Foam::checkGeometry
<< " zero area faces to set " << faces.name() << endl; << " zero area faces to set " << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -687,7 +687,7 @@ Foam::label Foam::checkGeometry
<< " zero volume cells to set " << cells.name() << endl; << " zero volume cells to set " << cells.name() << endl;
cells.instance() = mesh.pointsInstance(); cells.instance() = mesh.pointsInstance();
cells.write(); cells.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, cells); mergeAndWrite(*surfWriter, cells);
} }
@ -710,7 +710,7 @@ Foam::label Foam::checkGeometry
<< " non-orthogonal faces to set " << faces.name() << endl; << " non-orthogonal faces to set " << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -732,7 +732,7 @@ Foam::label Foam::checkGeometry
<< faces.name() << endl; << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -754,7 +754,7 @@ Foam::label Foam::checkGeometry
<< " skew faces to set " << faces.name() << endl; << " skew faces to set " << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -778,7 +778,7 @@ Foam::label Foam::checkGeometry
<< faces.name() << endl; << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -811,7 +811,7 @@ Foam::label Foam::checkGeometry
<< "decomposition tets to set " << faces.name() << endl; << "decomposition tets to set " << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -836,7 +836,7 @@ Foam::label Foam::checkGeometry
<< endl; << endl;
points.instance() = mesh.pointsInstance(); points.instance() = mesh.pointsInstance();
points.write(); points.write();
if (setWriter) if (setWriter && setWriter->enabled())
{ {
mergeAndWrite(*setWriter, points); mergeAndWrite(*setWriter, points);
} }
@ -859,7 +859,7 @@ Foam::label Foam::checkGeometry
<< " apart) points to set " << nearPoints.name() << endl; << " apart) points to set " << nearPoints.name() << endl;
nearPoints.instance() = mesh.pointsInstance(); nearPoints.instance() = mesh.pointsInstance();
nearPoints.write(); nearPoints.write();
if (setWriter) if (setWriter && setWriter->enabled())
{ {
mergeAndWrite(*setWriter, nearPoints); mergeAndWrite(*setWriter, nearPoints);
} }
@ -883,7 +883,7 @@ Foam::label Foam::checkGeometry
<< endl; << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -906,7 +906,7 @@ Foam::label Foam::checkGeometry
<< " warped faces to set " << faces.name() << endl; << " warped faces to set " << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -927,7 +927,7 @@ Foam::label Foam::checkGeometry
<< " under-determined cells to set " << cells.name() << endl; << " under-determined cells to set " << cells.name() << endl;
cells.instance() = mesh.pointsInstance(); cells.instance() = mesh.pointsInstance();
cells.write(); cells.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, cells); mergeAndWrite(*surfWriter, cells);
} }
@ -947,7 +947,7 @@ Foam::label Foam::checkGeometry
<< " concave cells to set " << cells.name() << endl; << " concave cells to set " << cells.name() << endl;
cells.instance() = mesh.pointsInstance(); cells.instance() = mesh.pointsInstance();
cells.write(); cells.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, cells); mergeAndWrite(*surfWriter, cells);
} }
@ -968,7 +968,7 @@ Foam::label Foam::checkGeometry
<< faces.name() << endl; << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -989,7 +989,7 @@ Foam::label Foam::checkGeometry
<< faces.name() << endl; << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }

View File

@ -7,7 +7,7 @@ namespace Foam
// Forward Declarations // Forward Declarations
class polyMesh; class polyMesh;
class wedgePolyPatch; class wedgePolyPatch;
template<class T> class writer; class coordSetWriter;
class surfaceWriter; class surfaceWriter;
label findOppositeWedge(const polyMesh&, const wedgePolyPatch&); label findOppositeWedge(const polyMesh&, const wedgePolyPatch&);
@ -47,6 +47,6 @@ namespace Foam
const polyMesh& mesh, const polyMesh& mesh,
const bool allGeometry, const bool allGeometry,
autoPtr<surfaceWriter>& surfWriter, autoPtr<surfaceWriter>& surfWriter,
const autoPtr<writer<scalar>>& setWriter autoPtr<coordSetWriter>& setWriter
); );
} }

View File

@ -74,7 +74,7 @@ Usage
#include "Time.H" #include "Time.H"
#include "fvMesh.H" #include "fvMesh.H"
#include "globalMeshData.H" #include "globalMeshData.H"
#include "vtkSetWriter.H" #include "vtkCoordSetWriter.H"
#include "vtkSurfaceWriter.H" #include "vtkSurfaceWriter.H"
#include "IOdictionary.H" #include "IOdictionary.H"
#include "regionProperties.H" #include "regionProperties.H"
@ -262,11 +262,11 @@ int main(int argc, char *argv[])
autoPtr<surfaceWriter> surfWriter; autoPtr<surfaceWriter> surfWriter;
autoPtr<writer<scalar>> setWriter; autoPtr<coordSetWriter> setWriter;
if (writeSets) if (writeSets)
{ {
surfWriter = surfaceWriter::New(surfaceFormat); surfWriter = surfaceWriter::New(surfaceFormat);
setWriter = writer<scalar>::New(vtkSetWriter<scalar>::typeName); setWriter = coordSetWriter::New(coordSetWriters::vtkWriter::typeName);
} }

View File

@ -41,7 +41,7 @@ License
#include "faceSet.H" #include "faceSet.H"
#include "cellSet.H" #include "cellSet.H"
#include "Time.H" #include "Time.H"
#include "writer.H" #include "coordSetWriter.H"
#include "surfaceWriter.H" #include "surfaceWriter.H"
#include "syncTools.H" #include "syncTools.H"
#include "globalIndex.H" #include "globalIndex.H"
@ -417,7 +417,7 @@ void Foam::mergeAndWrite
void Foam::mergeAndWrite void Foam::mergeAndWrite
( (
const writer<scalar>& writer, coordSetWriter& writer,
const pointSet& set const pointSet& set
) )
{ {
@ -441,39 +441,26 @@ void Foam::mergeAndWrite
} }
// Write with scalar pointID // Write with pointID
if (Pstream::master()) if (Pstream::master())
{ {
scalarField scalarPointIDs(mergedIDs.size()); coordSet coords(set.name(), "distance", mergedPts, mag(mergedPts));
forAll(mergedIDs, i)
{
scalarPointIDs[i] = 1.0*mergedIDs[i];
}
coordSet points(set.name(), "distance", mergedPts, mag(mergedPts)); // Output. E.g. pointSet p0 -> postProcessing/<time>/p0.vtk
List<const scalarField*> flds(1, &scalarPointIDs); fileName outputPath
wordList fldNames(1, "pointID");
// Output e.g. pointSet p0 to
// postProcessing/<time>/p0.vtk
fileName outputDir
( (
set.time().globalPath() set.time().globalPath()
/ functionObject::outputPrefix / functionObject::outputPrefix
/ mesh.pointsInstance() / mesh.pointsInstance()
// set.name() / set.name()
); );
outputDir.clean(); // Remove unneeded ".." outputPath.clean(); // Remove unneeded ".."
mkDir(outputDir);
fileName outputFile(outputDir/writer.getFileName(points, wordList())); writer.open(coords, outputPath);
//fileName outputFile(outputDir/set.name()); writer.nFields(1);
writer.write("pointID", mergedIDs);
OFstream os(outputFile); writer.close(true);
writer.write(points, fldNames, flds, os);
} }
} }

View File

@ -10,7 +10,7 @@ namespace Foam
class cellSet; class cellSet;
class fileName; class fileName;
class polyMesh; class polyMesh;
template<class T> class writer; class coordSetWriter;
class surfaceWriter; class surfaceWriter;
void printMeshStats(const polyMesh& mesh, const bool allTopology); void printMeshStats(const polyMesh& mesh, const bool allTopology);
@ -36,7 +36,7 @@ namespace Foam
//- Write vtk representation of (assembled) pointSet to 'set' file in //- Write vtk representation of (assembled) pointSet to 'set' file in
// postProcessing/ directory // postProcessing/ directory
void mergeAndWrite(const writer<scalar>& writer, const pointSet& set); void mergeAndWrite(coordSetWriter& writer, const pointSet& set);
} }

View File

@ -36,7 +36,7 @@ License
#include "IOmanip.H" #include "IOmanip.H"
#include "emptyPolyPatch.H" #include "emptyPolyPatch.H"
#include "processorPolyPatch.H" #include "processorPolyPatch.H"
#include "vtkSetWriter.H" #include "vtkCoordSetWriter.H"
#include "vtkSurfaceWriter.H" #include "vtkSurfaceWriter.H"
#include "checkTools.H" #include "checkTools.H"
#include "treeBoundBox.H" #include "treeBoundBox.H"
@ -117,7 +117,7 @@ Foam::label Foam::checkTopology
const bool allTopology, const bool allTopology,
const bool allGeometry, const bool allGeometry,
autoPtr<surfaceWriter>& surfWriter, autoPtr<surfaceWriter>& surfWriter,
const autoPtr<writer<scalar>>& setWriter autoPtr<coordSetWriter>& setWriter
) )
{ {
label noFailedChecks = 0; label noFailedChecks = 0;
@ -203,7 +203,7 @@ Foam::label Foam::checkTopology
<< " illegal cells to set " << cells.name() << endl; << " illegal cells to set " << cells.name() << endl;
cells.instance() = mesh.pointsInstance(); cells.instance() = mesh.pointsInstance();
cells.write(); cells.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, cells); mergeAndWrite(*surfWriter, cells);
} }
@ -227,7 +227,7 @@ Foam::label Foam::checkTopology
<< " unused points to set " << points.name() << endl; << " unused points to set " << points.name() << endl;
points.instance() = mesh.pointsInstance(); points.instance() = mesh.pointsInstance();
points.write(); points.write();
if (setWriter) if (setWriter && setWriter->enabled())
{ {
mergeAndWrite(*setWriter, points); mergeAndWrite(*setWriter, points);
} }
@ -249,7 +249,7 @@ Foam::label Foam::checkTopology
<< " unordered faces to set " << faces.name() << endl; << " unordered faces to set " << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -269,7 +269,7 @@ Foam::label Foam::checkTopology
<< faces.name() << endl; << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -290,11 +290,10 @@ Foam::label Foam::checkTopology
<< endl; << endl;
cells.instance() = mesh.pointsInstance(); cells.instance() = mesh.pointsInstance();
cells.write(); cells.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, cells); mergeAndWrite(*surfWriter, cells);
} }
} }
} }
@ -314,7 +313,7 @@ Foam::label Foam::checkTopology
<< faces.name() << endl; << faces.name() << endl;
faces.instance() = mesh.pointsInstance(); faces.instance() = mesh.pointsInstance();
faces.write(); faces.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, faces); mergeAndWrite(*surfWriter, faces);
} }
@ -369,7 +368,7 @@ Foam::label Foam::checkTopology
<< endl; << endl;
oneCells.instance() = mesh.pointsInstance(); oneCells.instance() = mesh.pointsInstance();
oneCells.write(); oneCells.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, oneCells); mergeAndWrite(*surfWriter, oneCells);
} }
@ -385,7 +384,7 @@ Foam::label Foam::checkTopology
<< endl; << endl;
twoCells.instance() = mesh.pointsInstance(); twoCells.instance() = mesh.pointsInstance();
twoCells.write(); twoCells.write();
if (surfWriter) if (surfWriter && surfWriter->enabled())
{ {
mergeAndWrite(*surfWriter, twoCells); mergeAndWrite(*surfWriter, twoCells);
} }
@ -530,7 +529,7 @@ Foam::label Foam::checkTopology
<< " points that are in multiple regions to set " << " points that are in multiple regions to set "
<< points.name() << endl; << points.name() << endl;
points.write(); points.write();
if (setWriter) if (setWriter && setWriter->enabled())
{ {
mergeAndWrite(*setWriter, points); mergeAndWrite(*setWriter, points);
} }
@ -641,7 +640,7 @@ Foam::label Foam::checkTopology
<< " conflicting points to set " << points.name() << endl; << " conflicting points to set " << points.name() << endl;
points.instance() = mesh.pointsInstance(); points.instance() = mesh.pointsInstance();
points.write(); points.write();
if (setWriter) if (setWriter && setWriter->enabled())
{ {
mergeAndWrite(*setWriter, points); mergeAndWrite(*setWriter, points);
} }

View File

@ -6,7 +6,7 @@ namespace Foam
// Forward Declarations // Forward Declarations
class polyMesh; class polyMesh;
class pointSet; class pointSet;
template<class T> class writer; class coordSetWriter;
class surfaceWriter; class surfaceWriter;
template<class PatchType> template<class PatchType>
@ -24,6 +24,6 @@ namespace Foam
const bool allTopology, const bool allTopology,
const bool allGeometry, const bool allGeometry,
autoPtr<surfaceWriter>& surfWriter, autoPtr<surfaceWriter>& surfWriter,
const autoPtr<writer<scalar>>& setWriter autoPtr<coordSetWriter>& setWriter
); );
} }

View File

@ -17,7 +17,12 @@ label maxTracks(propsDict.getOrDefault<label>("maxTracks", -1));
word setFormat(propsDict.getOrDefault<word>("setFormat", "vtk")); word setFormat(propsDict.getOrDefault<word>("setFormat", "vtk"));
// Optional - if empty, select all // Optional - if empty, select all
const wordRes fieldNames(propsDict.getOrDefault<wordRes>("fields", wordRes())); wordRes acceptFields;
propsDict.readIfPresent("fields", acceptFields);
// Optional
wordRes excludeFields;
propsDict.readIfPresent("exclude", excludeFields);
const word UName(propsDict.getOrDefault<word>("U", "U")); const word UName(propsDict.getOrDefault<word>("U", "U"));

View File

@ -42,201 +42,36 @@ Description
#include "fvMesh.H" #include "fvMesh.H"
#include "Time.H" #include "Time.H"
#include "timeSelector.H" #include "timeSelector.H"
#include "OFstream.H" #include "coordSetWriter.H"
#include "passiveParticleCloud.H" #include "passiveParticleCloud.H"
#include "writer.H" #include "particleTracksSampler.H"
#include "ListOps.H"
#define createTrack(field, trackValues) \ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
createTrackField \
( \
field, \
sampleFrequency, \
maxPositions, \
startIds, \
allOrigProcs, \
allOrigIds, \
trackValues \
);
#define setFields(fields, fieldNames) \
setTrackFields \
( \
obr, \
fields, \
fieldNames, \
nTracks, \
startIds, \
allOrigProcs, \
allOrigIds, \
maxPositions, \
sampleFrequency \
);
#define writeFields(fields, fieldNames, tracks, times, dirs) \
writeTrackFields \
( \
fields, \
fieldNames, \
tracks, \
times, \
dirs, \
setFormat, \
formatOptions, \
cloudName \
);
using namespace Foam; using namespace Foam;
template<class Type>
void createTrackField
(
const Field<Type>& values,
const label sampleFrequency,
const label maxPositions,
const labelList& startIds,
const List<labelField>& allOrigProcs,
const List<labelField>& allOrigIds,
List<DynamicList<Type>>& trackValues
)
{
List<Field<Type>> procField(Pstream::nProcs());
procField[Pstream::myProcNo()] = values;
Pstream::gatherList(procField);
if (!Pstream::master())
{
return;
}
const label nTracks = trackValues.size();
forAll(procField, proci)
{
forAll(procField[proci], i)
{
const label globalId =
startIds[allOrigProcs[proci][i]] + allOrigIds[proci][i];
if (globalId % sampleFrequency == 0)
{
const label trackId = globalId/sampleFrequency;
if
(
trackId < nTracks
&& trackValues[trackId].size() < maxPositions
)
{
trackValues[trackId].append(procField[proci][i]);
}
}
}
}
}
template<class Type> template<class Type>
void writeTrackFields void writeTrackFields
( (
List<List<DynamicList<Type>>>& fieldValues, coordSetWriter& writer,
const wordList& fieldNames, HashTable<List<DynamicList<Type>>>& fieldTable
const PtrList<coordSet>& tracks,
const List<scalarField>& times,
const List<vectorField>& dirs,
const word& setFormat,
const dictionary& formatOptions,
const word& cloudName
) )
{ {
if (fieldValues.empty()) for (const word& fieldName : fieldTable.sortedToc())
{ {
return; // Steal and reshape from List<DynamicList> to List<Field>
auto& input = fieldTable[fieldName];
List<Field<Type>> fields(input.size());
forAll(input, tracki)
{
fields[tracki].transfer(input[tracki]);
} }
auto writerPtr = writer<Type>::New(setFormat, formatOptions); writer.write(fieldName, fields);
const fileName outFile(writerPtr().getFileName(tracks[0], wordList(0)));
const fileName outPath
(
functionObject::outputPrefix/cloud::prefix/cloudName/"particleTracks"
);
mkDir(outPath);
OFstream os(outPath/(pTraits<Type>::typeName & "tracks." + outFile.ext()));
Info<< "Writing " << pTraits<Type>::typeName << " particle tracks in "
<< setFormat << " format to " << os.name() << endl;
List<List<Field<Type>>> fields(fieldValues.size());
forAll(fields, fieldi)
{
fields[fieldi].setSize(fieldValues[fieldi].size());
forAll(fields[fieldi], tracki)
{
fields[fieldi][tracki].transfer(fieldValues[fieldi][tracki]);
} }
} }
writerPtr().write(true, times, tracks, fieldNames, fields, os);
}
template<class Type>
Foam::label setTrackFields
(
const objectRegistry& obr,
List<List<DynamicList<Type>>>& fields,
List<word>& fieldNames,
const label nTracks,
const labelList& startIds,
const List<labelField>& allOrigProcs,
const List<labelField>& allOrigIds,
const label maxPositions,
const label sampleFrequency
)
{
const auto availableFieldPtrs = obr.lookupClass<IOField<Type>>();
fieldNames = availableFieldPtrs.toc();
if (Pstream::parRun())
{
Pstream::combineGather(fieldNames, ListOps::uniqueEqOp<word>());
Pstream::combineScatter(fieldNames);
Foam::sort(fieldNames);
}
const label nFields = fieldNames.size();
if (fields.empty())
{
fields.setSize(nFields);
fieldNames.setSize(nFields);
forAll(fields, i)
{
fields[i].setSize(nTracks);
}
}
forAll(fieldNames, fieldi)
{
const word& fieldName = fieldNames[fieldi];
const auto* fldPtr = obr.cfindObject<IOField<Type>>(fieldName);
createTrack
(
fldPtr ? static_cast<const Field<Type>>(*fldPtr) : Field<Type>(),
fields[fieldi]
);
}
return nFields;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -267,6 +102,14 @@ int main(int argc, char *argv[])
"Override the sample-frequency" "Override the sample-frequency"
); );
argList::addOption argList::addOption
(
"fields",
"wordRes",
"Specify single or multiple fields to write "
"(default: all or 'fields' from dictionary)\n"
"Eg, 'T' or '( \"U.*\" )'"
);
argList::addOption
( (
"format", "format",
"name", "name",
@ -285,26 +128,41 @@ int main(int argc, char *argv[])
#include "createControls.H" #include "createControls.H"
args.readListIfPresent<wordRe>("fields", acceptFields);
args.readIfPresent("format", setFormat); args.readIfPresent("format", setFormat);
args.readIfPresent("stride", sampleFrequency); args.readIfPresent("stride", sampleFrequency);
sampleFrequency = max(1, sampleFrequency); // sanity sampleFrequency = max(1, sampleFrequency); // sanity
// Setup the writer
auto writerPtr =
coordSetWriter::New
(
setFormat,
formatOptions.optionalSubDict(setFormat, keyType::LITERAL)
);
writerPtr().useTracks(true);
if (args.verbose())
{
writerPtr().verbose(true);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
const fileName vtkPath(runTime.rootPath()/runTime.globalCaseName()/"VTK"); particleTracksSampler trackSampler;
mkDir(vtkPath);
Info<< "Scanning times to determine track data for cloud " << cloudName Info<< "Scanning times to determine track data for cloud " << cloudName
<< nl << endl; << nl << endl;
{
labelList maxIds(Pstream::nProcs(), -1); labelList maxIds(Pstream::nProcs(), -1);
forAll(timeDirs, timei) forAll(timeDirs, timei)
{ {
runTime.setTime(timeDirs[timei], timei); runTime.setTime(timeDirs[timei], timei);
Info<< "Time = " << runTime.timeName() << endl; Info<< "Time = " << runTime.timeName() << endl;
Info<< " Reading particle positions" << endl;
passiveParticleCloud myCloud(mesh, cloudName); passiveParticleCloud myCloud(mesh, cloudName);
Info<< " Read " << returnReduce(myCloud.size(), sumOp<label>()) Info<< " Read " << returnReduce(myCloud.size(), sumOp<label>())
@ -315,107 +173,102 @@ int main(int argc, char *argv[])
const label origId = p.origId(); const label origId = p.origId();
const label origProc = p.origProc(); const label origProc = p.origProc();
// Handle case where we are processing particle data generated in // Handle case where processing particle data generated in
// parallel using more cores than when running this application. // parallel using more cores than for this application.
if (origProc >= maxIds.size()) if (origProc >= maxIds.size())
{ {
maxIds.setSize(origProc+1, -1); maxIds.resize(origProc+1, -1);
} }
maxIds[origProc] = max(maxIds[origProc], origId); maxIds[origProc] = max(maxIds[origProc], origId);
} }
} }
label maxNProcs = returnReduce(maxIds.size(), maxOp<label>()); const label maxNProcs = returnReduce(maxIds.size(), maxOp<label>());
maxIds.resize(maxNProcs, -1);
Info<< "Detected particles originating from " << maxNProcs
<< " processors." << nl << endl;
maxIds.setSize(maxNProcs, -1);
Pstream::listCombineGather(maxIds, maxEqOp<label>()); Pstream::listCombineGather(maxIds, maxEqOp<label>());
Pstream::listCombineScatter(maxIds); Pstream::listCombineScatter(maxIds);
labelList numIds = maxIds + 1; // From ids to count
const labelList numIds = maxIds + 1;
Info<< nl << "Particle statistics:" << endl; // Set parcel addressing
forAll(maxIds, proci) trackSampler.reset(numIds);
Info<< nl
<< "Detected particles originating from "
<< maxNProcs << " processors." << nl
<< "Particle statistics:" << endl;
if (Pstream::master())
{ {
Info<< " Found " << numIds[proci] << " particles originating" const globalIndex& parcelAddr = trackSampler.parcelAddr();
<< " from processor " << proci << endl;
}
Info<< nl << endl;
for (const label proci : parcelAddr.allProcs())
// Calculate starting ids for particles on each processor
labelList startIds(numIds.size(), Zero);
for (label i = 0; i < numIds.size()-1; ++i)
{ {
startIds[i+1] += startIds[i] + numIds[i]; Info<< " Found " << parcelAddr.localSize(proci)
<< " particles originating"
<< " from processor " << proci << nl;
} }
label nParticle = startIds.last() + numIds[startIds.size()-1]; }
}
trackSampler.setSampleRate(sampleFrequency, maxPositions, maxTracks);
// Number of tracks to generate // Number of tracks to generate
const label nTracks = const label nTracks = trackSampler.nTracks();
maxTracks > 0
? min(nParticle/sampleFrequency, maxTracks)
: nParticle/sampleFrequency;
// Storage for all particle tracks // Storage for all particle tracks
List<DynamicList<vector>> allTracks(nTracks); List<DynamicList<point>> allTrackPos(nTracks);
List<DynamicList<scalar>> allTrackTimes(nTracks); List<DynamicList<scalar>> allTrackTimes(nTracks);
// Lists of field, tracki, trackValues // Track field values by name/type
//List<List<DynamicList<label>>> labelFields; HashTable<List<DynamicList<label>>> labelFields; // <- mostly unused
List<List<DynamicList<scalar>>> scalarFields; HashTable<List<DynamicList<scalar>>> scalarFields;
List<List<DynamicList<vector>>> vectorFields; HashTable<List<DynamicList<vector>>> vectorFields;
List<List<DynamicList<sphericalTensor>>> sphTensorFields; HashTable<List<DynamicList<sphericalTensor>>> sphericalTensorFields;
List<List<DynamicList<symmTensor>>> symTensorFields; HashTable<List<DynamicList<symmTensor>>> symmTensorFields;
List<List<DynamicList<tensor>>> tensorFields; HashTable<List<DynamicList<tensor>>> tensorFields;
//List<word> labelFieldNames;
List<word> scalarFieldNames;
List<word> vectorFieldNames;
List<word> sphTensorFieldNames;
List<word> symTensorFieldNames;
List<word> tensorFieldNames;
Info<< "\nGenerating " << nTracks << " particle tracks for cloud " Info<< nl
<< cloudName << nl << endl; << "Generating " << nTracks
<< " particle tracks for cloud " << cloudName << nl << endl;
forAll(timeDirs, timei) forAll(timeDirs, timei)
{ {
runTime.setTime(timeDirs[timei], timei); runTime.setTime(timeDirs[timei], timei);
Info<< "Time = " << runTime.timeName() << endl; Info<< "Time = " << runTime.timeName() << " (processing)" << endl;
// Read particles. Will be size 0 if no particles. // Read particles. Will be size 0 if no particles.
Info<< " Reading particle positions" << endl;
passiveParticleCloud myCloud(mesh, cloudName); passiveParticleCloud myCloud(mesh, cloudName);
pointField localPositions(myCloud.size(), Zero); pointField localPositions(myCloud.size());
scalarField localTimes(myCloud.size(), Zero); scalarField localTimes(myCloud.size(), runTime.value());
List<labelField> allOrigIds(Pstream::nProcs()); // Gather track data from all processors that have positions
List<labelField> allOrigProcs(Pstream::nProcs()); trackSampler.resetCloud(myCloud.size());
{
labelField& origIds = trackSampler.origParcelIds_;
labelField& origProcs = trackSampler.origProcIds_;
// Collect the track data on all processors that have positions label np = 0;
allOrigIds[Pstream::myProcNo()].setSize(myCloud.size(), Zero);
allOrigProcs[Pstream::myProcNo()].setSize(myCloud.size(), Zero);
label i = 0;
for (const passiveParticle& p : myCloud) for (const passiveParticle& p : myCloud)
{ {
allOrigIds[Pstream::myProcNo()][i] = p.origId(); origIds[np] = p.origId();
allOrigProcs[Pstream::myProcNo()][i] = p.origProc(); origProcs[np] = p.origProc();
localPositions[i] = p.position(); localPositions[np] = p.position();
localTimes[i] = runTime.value(); ++np;
++i;
} }
// Collect the track data on the master processor trackSampler.gatherInplace(origIds);
Pstream::gatherList(allOrigIds); trackSampler.gatherInplace(origProcs);
Pstream::gatherList(allOrigProcs); }
// Read cloud fields (from disk) into object registry
objectRegistry obr objectRegistry obr
( (
IOobject IOobject
@ -426,63 +279,122 @@ int main(int argc, char *argv[])
) )
); );
myCloud.readFromFiles(obr, fieldNames); myCloud.readFromFiles(obr, acceptFields, excludeFields);
// Create track positions and track time fields // Create track positions and track time fields
// (not registered as IOFields) // (not registered as IOFields)
// Note: createTrack is a local #define to reduce arg count...
createTrack(localPositions, allTracks); trackSampler.createTrackField(localPositions, allTrackPos);
createTrack(localTimes, allTrackTimes); trackSampler.createTrackField(localTimes, allTrackTimes);
// Create the track fields // Create the track fields
// Note: setFields is a local #define to reduce arg count... ///trackSampler.setTrackFields(obr, labelFields);
//setFields(labelFields, labelFieldNames); trackSampler.setTrackFields(obr, scalarFields);
setFields(scalarFields, scalarFieldNames); trackSampler.setTrackFields(obr, vectorFields);
setFields(vectorFields, vectorFieldNames); trackSampler.setTrackFields(obr, sphericalTensorFields);
setFields(sphTensorFields, sphTensorFieldNames); trackSampler.setTrackFields(obr, symmTensorFields);
setFields(symTensorFields, symTensorFieldNames); trackSampler.setTrackFields(obr, tensorFields);
setFields(tensorFields, tensorFieldNames);
} }
const label nFields =
(
labelFields.size()
+ scalarFields.size()
+ vectorFields.size()
+ sphericalTensorFields.size()
+ symmTensorFields.size()
+ tensorFields.size()
);
Info<< nl
<< "Extracted " << nFields << " cloud fields" << nl;
if (nFields)
{
#undef doLocalCode
#define doLocalCode(FieldContent) \
if (!FieldContent.empty()) \
{ \
Info<< " "; \
for (const word& fieldName : FieldContent.sortedToc()) \
{ \
Info<< ' ' << fieldName; \
} \
Info<< nl; \
}
doLocalCode(labelFields);
doLocalCode(scalarFields);
doLocalCode(vectorFields);
doLocalCode(sphericalTensorFields);
doLocalCode(symmTensorFields);
doLocalCode(tensorFields);
#undef doLocalCode
}
Info<< nl
<< "Writing particle tracks (" << setFormat << " format)" << nl;
if (Pstream::master()) if (Pstream::master())
{ {
PtrList<coordSet> tracks(allTracks.size()); PtrList<coordSet> tracks(allTrackPos.size());
List<scalarField> times(tracks.size()); List<scalarField> times(allTrackPos.size());
forAll(tracks, tracki) forAll(tracks, tracki)
{ {
tracks.set tracks.set
( (
tracki, tracki,
new coordSet("track" + Foam::name(tracki), "distance") new coordSet("track" + Foam::name(tracki), "xyz")
); );
tracks[tracki].transfer(allTracks[tracki]); tracks[tracki].transfer(allTrackPos[tracki]);
times[tracki].transfer(allTrackTimes[tracki]); times[tracki].transfer(allTrackTimes[tracki]);
if (!tracki) tracks[0].rename("tracks");
} }
Info<< nl; /// Currently unused
/// List<vectorField> dirs(nTracks);
/// const auto Uiter = vectorFields.cfind(UName);
/// if (Uiter.found())
/// {
/// const auto& UTracks = *Uiter;
/// forAll(UTracks, tracki)
/// {
/// const auto& U = UTracks[tracki];
/// dirs[tracki] = U/(mag(U) + ROOTVSMALL);
/// }
/// }
const label Uid = vectorFieldNames.find(UName);
List<vectorField> dirs(nTracks);
if (Uid != -1) // Write tracks with fields
if (nFields)
{ {
const auto& UTracks = vectorFields[Uid]; auto& writer = *writerPtr;
forAll(UTracks, tracki)
{
const auto& U = UTracks[tracki];
dirs[tracki] = U/(mag(U) + ROOTVSMALL);
}
}
// Write track fields const fileName outputPath
// Note: writeFields is a local #define to reduce arg count... (
//writeFields(allLabelFields, labelFieldNames, tracks); functionObject::outputPrefix/cloud::prefix/cloudName
writeFields(scalarFields, scalarFieldNames, tracks, times, dirs); / "particleTracks" / "tracks"
writeFields(vectorFields, vectorFieldNames, tracks, times, dirs); );
writeFields(sphTensorFields, sphTensorFieldNames, tracks, times, dirs);
writeFields(symTensorFields, symTensorFieldNames, tracks, times, dirs); Info<< " "
writeFields(tensorFields, tensorFieldNames, tracks, times, dirs); << runTime.relativePath(outputPath) << endl;
writer.open(tracks, outputPath);
writer.setTrackTimes(times);
writer.nFields(nFields);
///writeTrackFields(writer, labelFields);
writeTrackFields(writer, scalarFields);
writeTrackFields(writer, vectorFields);
writeTrackFields(writer, sphericalTensorFields);
writeTrackFields(writer, symmTensorFields);
writeTrackFields(writer, tensorFields);
}
else
{
Info<< "Warning: no fields, did not write" << endl;
}
} }
Info<< nl << "End\n" << endl; Info<< nl << "End\n" << endl;

View File

@ -0,0 +1,190 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::particleTracksSampler
Description
Helper class when generating particle tracks.
The interface is fairly rudimentary.
SourceFiles
particleTracksSamplerTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_particleTracksSampler_H
#define Foam_particleTracksSampler_H
#include "globalIndex.H"
#include "fieldTypes.H"
#include "IOField.H"
#include "labelField.H"
#include "DynamicList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class objectRegistry;
/*---------------------------------------------------------------------------*\
Class particleTracksSampler Declaration
\*---------------------------------------------------------------------------*/
class particleTracksSampler
{
// Private Data
//- The sampling interval
label stride_ = 1;
//- The number of tracks
label nTracks_ = 1;
//- Upper limit for number of track positions
label maxPositions_ = 10000;
//- The bin for sampled parcels.
labelField trackIds_;
//- The addressing for gathering cloud fields etc
globalIndex cloudGather_;
//- The originating parcel addressing
globalIndex origParcelAddr_;
public:
// Data Members
//- The originating parcel ids
labelField origParcelIds_;
//- The originating processor ids
labelField origProcIds_;
// Member Functions
//- The original parcel addressing
const globalIndex& parcelAddr() const noexcept
{
return origParcelAddr_;
}
//- Total number of particles
label nParticle() const
{
return origParcelAddr_.totalSize();
}
//- Number of tracks to generate
label nTracks() const noexcept
{
return nTracks_;
}
//- Define the orig parcel mappings
void reset(const labelUList& origParcelCounts)
{
origParcelAddr_.reset(origParcelCounts);
origParcelIds_.clear();
origProcIds_.clear();
trackIds_.clear();
}
//- Set the sampling stride, upper limits
// \return Number of tracks to generate
label setSampleRate
(
const label sampleFreq,
const label maxPositions,
const label maxTracks = -1
)
{
// numTracks = numParticles/stride
stride_ = max(1, sampleFreq);
maxPositions_ = maxPositions;
nTracks_ = (origParcelAddr_.totalSize()/stride_);
if (maxTracks > 0)
{
nTracks_ = min(nTracks_, maxTracks);
}
return nTracks_;
}
void resetCloud(const label localCloudSize)
{
cloudGather_.reset(localCloudSize, globalIndex::gatherOnly{});
origParcelIds_.resize_nocopy(localCloudSize);
origProcIds_.resize_nocopy(localCloudSize);
}
template<class Type>
void gatherInplace(List<Type>& fld) const
{
cloudGather_.gatherInplace(fld);
}
template<class Type>
void createTrackField
(
const UList<Type>& values,
List<DynamicList<Type>>& trackValues
) const;
template<class Type>
label setTrackFields
(
const objectRegistry& obr,
HashTable<List<DynamicList<Type>>>& fieldTable
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "particleTracksSamplerTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,108 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "objectRegistry.H"
#include "ListOps.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
void Foam::particleTracksSampler::createTrackField
(
const UList<Type>& values,
List<DynamicList<Type>>& trackValues
) const
{
List<Type> allValues(cloudGather_.gather(values));
const label nTracks = trackValues.size();
forAll(allValues, i)
{
const label globalId =
origParcelAddr_.toGlobal(origProcIds_[i], origParcelIds_[i]);
if (globalId % stride_ == 0)
{
const label trackId = globalId/stride_;
if
(
trackId < nTracks
&& trackValues[trackId].size() < maxPositions_
)
{
trackValues[trackId].append(allValues[i]);
}
}
}
}
template<class Type>
Foam::label Foam::particleTracksSampler::setTrackFields
(
const objectRegistry& obr,
HashTable<List<DynamicList<Type>>>& fieldTable
) const
{
// First time - obtain field names and populate storage locations
if (fieldTable.empty())
{
wordList fieldNames = obr.names<IOField<Type>>();
if (Pstream::parRun())
{
Pstream::combineGather(fieldNames, ListOps::uniqueEqOp<word>());
Pstream::combineScatter(fieldNames);
}
for (const word& fieldName : fieldNames)
{
fieldTable(fieldName).resize(nTracks());
}
}
// Process in parallel-consistent order
for (const word& fieldName : fieldTable.sortedToc())
{
auto& output = fieldTable[fieldName];
const auto* ptr = obr.cfindObject<IOField<Type>>(fieldName);
this->createTrackField
(
ptr ? static_cast<const UList<Type>&>(*ptr) : UList<Type>::null(),
output
);
}
return fieldTable.size();
}
// ************************************************************************* //

View File

@ -8,7 +8,12 @@ IOdictionary propsDict(dictIO);
const word cloudName(propsDict.get<word>("cloud")); const word cloudName(propsDict.get<word>("cloud"));
List<word> userFields(propsDict.lookup("fields")); // Mandatory - if empty, select none
wordRes acceptFields(propsDict.get<wordRes>("fields"));
// Optional
wordRes excludeFields;
propsDict.readIfPresent("exclude", excludeFields);
const dictionary formatOptions const dictionary formatOptions
( (

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -45,74 +46,113 @@ Description
#include "Time.H" #include "Time.H"
#include "timeSelector.H" #include "timeSelector.H"
#include "OFstream.H" #include "OFstream.H"
#include "passiveParticleCloud.H"
#include "labelPairHashes.H" #include "labelPairHashes.H"
#include "SortableList.H" #include "IOField.H"
#include "IOobjectList.H" #include "IOobjectList.H"
#include "PtrList.H" #include "SortableList.H"
#include "Field.H" #include "passiveParticleCloud.H"
#include "steadyParticleTracksTemplates.H" #include "steadyParticleTracksTemplates.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
using namespace Foam;
namespace Foam namespace Foam
{ {
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
label validateFields // Extract list of IOobjects, modifying the input IOobjectList in the
// process
IOobjectList preFilterFields
( (
const List<word>& userFields, IOobjectList& cloudObjects,
const IOobjectList& cloudObjs const wordRes& acceptFields,
const wordRes& excludeFields
) )
{ {
List<bool> ok(userFields.size(), false); IOobjectList filteredObjects(cloudObjects.capacity());
DynamicList<label> missed(acceptFields.size());
forAll(userFields, i) // Selection here is slighly different than usual
// - an empty accept filter means "ignore everything"
if (!acceptFields.empty())
{ {
ok[i] = ok[i] || fieldOk<label>(cloudObjs, userFields[i]); const wordRes::filter pred(acceptFields, excludeFields);
ok[i] = ok[i] || fieldOk<scalar>(cloudObjs, userFields[i]);
ok[i] = ok[i] || fieldOk<vector>(cloudObjs, userFields[i]);
ok[i] = ok[i] || fieldOk<sphericalTensor>(cloudObjs, userFields[i]);
ok[i] = ok[i] || fieldOk<symmTensor>(cloudObjs, userFields[i]);
ok[i] = ok[i] || fieldOk<tensor>(cloudObjs, userFields[i]);
}
label nOk = 0; const wordList allNames(cloudObjects.sortedNames());
forAll(ok, i)
// Detect missing fields
forAll(acceptFields, i)
{ {
if (ok[i]) if
(
acceptFields[i].isLiteral()
&& !allNames.found(acceptFields[i])
)
{ {
++nOk; missed.append(i);
} }
else }
for (const word& fldName : allNames)
{ {
Info << "\n*** Warning: user specified field '" << userFields[i] const auto iter = cloudObjects.cfind(fldName);
<< "' unavailable" << endl; if (!pred(fldName) || !iter.found())
}
}
return nOk;
}
template<>
void writeVTK(OFstream& os, const label& value)
{ {
os << value; continue; // reject
} }
const IOobject& io = *(iter.val());
template<> if
void writeVTK(OFstream& os, const scalar& value) (
//OR: fieldTypes::basic.found(io.headerClassName())
io.headerClassName() == IOField<label>::typeName
|| io.headerClassName() == IOField<scalar>::typeName
|| io.headerClassName() == IOField<vector>::typeName
|| io.headerClassName() == IOField<sphericalTensor>::typeName
|| io.headerClassName() == IOField<symmTensor>::typeName
|| io.headerClassName() == IOField<tensor>::typeName
)
{ {
os << value; // Transfer from cloudObjects -> filteredObjects
filteredObjects.add(cloudObjects.remove(fldName));
}
}
} }
if (missed.size())
{
WarningInFunction
<< nl
<< "Cannot find field file matching "
<< UIndirectList<wordRe>(acceptFields, missed) << endl;
} }
return filteredObjects;
}
void readFieldsAndWriteVTK
(
OFstream& os,
const List<labelList>& particleMap,
const IOobjectList& filteredObjects
)
{
processFields<label>(os, particleMap, filteredObjects);
processFields<scalar>(os, particleMap, filteredObjects);
processFields<vector>(os, particleMap, filteredObjects);
processFields<sphericalTensor>(os, particleMap, filteredObjects);
processFields<symmTensor>(os, particleMap, filteredObjects);
processFields<tensor>(os, particleMap, filteredObjects);
}
} // End namespace Foam
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -153,37 +193,31 @@ int main(int argc, char *argv[])
const fileName vtkTimePath(vtkPath/runTime.timeName()); const fileName vtkTimePath(vtkPath/runTime.timeName());
mkDir(vtkTimePath); mkDir(vtkTimePath);
Info<< " Reading particle positions" << endl; pointField particlePosition;
labelList particleToTrack;
PtrList<passiveParticle> particles(0); label nTracks = 0;
// Transfer particles to (more convenient) list // Transfer particles to (more convenient) list
{ {
passiveParticleCloud ppc(mesh, cloudName); Info<< " Reading particle positions" << endl;
Info<< "\n Read " << returnReduce(ppc.size(), sumOp<label>())
passiveParticleCloud myCloud(mesh, cloudName);
Info<< "\n Read " << returnReduce(myCloud.size(), sumOp<label>())
<< " particles" << endl; << " particles" << endl;
particles.setSize(ppc.size()); const label nParticles = myCloud.size();
label i = 0; particlePosition.resize(nParticles);
forAllIters(ppc, iter) particleToTrack.resize(nParticles);
LabelPairMap<label> trackTable;
label np = 0;
for (const passiveParticle& p : myCloud)
{ {
particles.set(i++, ppc.remove(&iter())); const label origId = p.origId();
} const label origProc = p.origProc();
particlePosition[np] = p.position();
// myCloud should now be empty
}
List<label> particleToTrack(particles.size());
label nTracks = 0;
{
labelPairLookup trackTable;
forAll(particles, i)
{
const label origProc = particles[i].origProc();
const label origId = particles[i].origId();
const labelPair key(origProc, origId); const labelPair key(origProc, origId);
@ -191,17 +225,19 @@ int main(int argc, char *argv[])
if (iter.found()) if (iter.found())
{ {
particleToTrack[i] = *iter; particleToTrack[np] = *iter;
} }
else else
{ {
particleToTrack[i] = nTracks; particleToTrack[np] = trackTable.size();
trackTable.insert(key, nTracks); trackTable.insert(key, trackTable.size());
++nTracks;
}
}
} }
++np;
}
nTracks = trackTable.size();
}
if (nTracks == 0) if (nTracks == 0)
{ {
@ -230,7 +266,7 @@ int main(int argc, char *argv[])
} }
// Store the particle age per track // Store the particle age per track
IOobjectList cloudObjs IOobjectList cloudObjects
( (
mesh, mesh,
runTime.timeName(), runTime.timeName(),
@ -239,25 +275,30 @@ int main(int argc, char *argv[])
// TODO: gather age across all procs // TODO: gather age across all procs
{ {
tmp<scalarField> tage = tmp<IOField<scalar>> tage =
readParticleField<scalar>("age", cloudObjs); readParticleField<scalar>("age", cloudObjects);
const scalarField& age = tage(); const auto& age = tage();
labelList trackSamples(nTracks, Zero); labelList trackSamples(nTracks, Zero);
forAll(particleToTrack, i) forAll(particleToTrack, i)
{ {
const label trackI = particleToTrack[i]; const label tracki = particleToTrack[i];
const label sampleI = trackSamples[trackI]; const label samplei = trackSamples[tracki];
agePerTrack[trackI][sampleI] = age[i]; agePerTrack[tracki][samplei] = age[i];
particleMap[trackI][sampleI] = i; particleMap[tracki][samplei] = i;
trackSamples[trackI]++; ++trackSamples[tracki];
} }
tage.clear();
} }
const IOobjectList filteredObjects
(
preFilterFields(cloudObjects, acceptFields, excludeFields)
);
if (Pstream::master()) if (Pstream::master())
{ {
OFstream os(vtkTimePath/"particleTracks.vtk"); OFstream os(vtkTimePath/"particleTracks.vtk");
@ -295,7 +336,7 @@ int main(int argc, char *argv[])
forAll(ids, j) forAll(ids, j)
{ {
const label localId = particleIds[j]; const label localId = particleIds[j];
const vector pos(particles[localId].position()); const point& pos = particlePosition[localId];
os << pos.x() << ' ' << pos.y() << ' ' << pos.z() os << pos.x() << ' ' << pos.y() << ' ' << pos.z()
<< nl; << nl;
} }
@ -330,22 +371,14 @@ int main(int argc, char *argv[])
} }
const label nFields = validateFields(userFields, cloudObjs); const label nFields = filteredObjects.size();
os << "POINT_DATA " << nPoints << nl os << "POINT_DATA " << nPoints << nl
<< "FIELD attributes " << nFields << nl; << "FIELD attributes " << nFields << nl;
Info<< "\n Processing fields" << nl << endl; Info<< "\n Processing fields" << nl << endl;
processFields<label>(os, particleMap, userFields, cloudObjs); readFieldsAndWriteVTK(os, particleMap, filteredObjects);
processFields<scalar>(os, particleMap, userFields, cloudObjs);
processFields<vector>(os, particleMap, userFields, cloudObjs);
processFields<sphericalTensor>
(os, particleMap, userFields, cloudObjs);
processFields<symmTensor>
(os, particleMap, userFields, cloudObjs);
processFields<tensor>(os, particleMap, userFields, cloudObjs);
} }
} }
Info<< endl; Info<< endl;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -31,98 +31,57 @@ License
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type> template<class Type>
bool Foam::fieldOk(const IOobjectList& cloudObjs, const word& name) Foam::tmp<Foam::IOField<Type>> Foam::readParticleField
{
return cloudObjs.cfindObject<IOField<Type>>(name) != nullptr;
}
template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::readParticleField
( (
const word& name, const word& fieldName,
const IOobjectList cloudObjs const IOobjectList& cloudObjects
) )
{ {
const IOobject* obj = cloudObjs.cfindObject<IOField<Type>>(name); const IOobject* io = cloudObjects.cfindObject<IOField<Type>>(fieldName);
if (obj != nullptr) if (io)
{ {
IOField<Type> newField(*obj); return tmp<IOField<Type>>::New(*io);
return tmp<Field<Type>>::New(std::move(newField));
} }
FatalErrorInFunction FatalErrorInFunction
<< "Error: cloud field name " << name << "Cloud field name " << fieldName
<< " not found or the wrong type" << " not found or the incorrect type"
<< abort(FatalError); << abort(FatalError);
return Field<Type>::null(); return nullptr;
}
template<class Type>
void Foam::readFields
(
PtrList<List<Type>>& values,
const List<word>& fieldNames,
const IOobjectList& cloudObjs
)
{
forAll(fieldNames, fieldi)
{
const word& fieldName = fieldNames[fieldi];
const IOobject* obj = cloudObjs.cfindObject<IOField<Type>>(fieldName);
if (obj != nullptr)
{
Info<< " reading field " << fieldName << endl;
IOField<Type> newField(*obj);
values.set(fieldi, new List<Type>(std::move(newField)));
}
else
{
FatalErrorInFunction
<< "Unable to read field " << fieldName
<< abort(FatalError);
}
}
} }
template<class Type> template<class Type>
void Foam::writeVTK(OFstream& os, const Type& value) void Foam::writeVTK(OFstream& os, const Type& value)
{ {
os << value.component(0); os << component(value, 0);
for (label i=1; i<pTraits<Type>::nComponents; i++) for (label d=1; d < pTraits<Type>::nComponents; ++d)
{ {
os << ' ' << value.component(i); os << ' ' << component(value, d);
} }
} }
template<class Type> template<class Type>
void Foam::writeVTKFields void Foam::writeVTKField
( (
OFstream& os, OFstream& os,
const PtrList<List<Type>>& values, const IOField<Type>& field,
const List<List<label>>& addr, const List<labelList>& addr
const List<word>& fieldNames
) )
{ {
label step = max(floor(8/pTraits<Type>::nComponents), 1); const label step = max(1, floor(8/pTraits<Type>::nComponents));
forAll(values, fieldi) Info<< " writing field " << field.name() << endl;
{ os << nl << field.name() << ' '
Info<< " writing field " << fieldNames[fieldi] << endl;
os << nl << fieldNames[fieldi] << ' '
<< int(pTraits<Type>::nComponents) << ' ' << int(pTraits<Type>::nComponents) << ' '
<< values[fieldi].size() << " float" << nl; << field.size() << " float" << nl;
label offset = 0;
forAll(addr, tracki)
{
const List<label> ids(addr[tracki]);
List<Type> data(UIndirectList<Type>(values[fieldi], ids)); ///label offset = 0;
for (const labelList& ids : addr)
{
List<Type> data(UIndirectList<Type>(field, ids));
label nData = data.size() - 1; label nData = data.size() - 1;
forAll(data, i) forAll(data, i)
{ {
@ -136,8 +95,7 @@ void Foam::writeVTKFields
os << ' '; os << ' ';
} }
} }
offset += ids.size(); /// offset += ids.size();
}
} }
} }
@ -146,36 +104,28 @@ template<class Type>
void Foam::processFields void Foam::processFields
( (
OFstream& os, OFstream& os,
const List<List<label>>& addr, const List<labelList>& addr,
const List<word>& userFieldNames, const IOobjectList& cloudObjects
const IOobjectList& cloudObjs
) )
{ {
IOobjectList objects(cloudObjs.lookupClass(IOField<Type>::typeName)); for (const word& fldName : cloudObjects.sortedNames<IOField<Type>>())
{
const IOobject* io = cloudObjects.cfindObject<IOField<Type>>(fldName);
if (objects.size()) if (!io)
{ {
DynamicList<word> fieldNames(objects.size()); FatalErrorInFunction
forAll(userFieldNames, i) << "Could not read field:" << fldName
{ << " type:" << IOField<Type>::typeName
const IOobject* obj = objects.findObject(userFieldNames[i]); << abort(FatalError);
if (obj != nullptr)
{
fieldNames.append(obj->name());
} }
else
{
Info<< " reading field " << fldName << endl;
IOField<Type> field(*io);
writeVTKField<Type>(os, field, addr);
} }
fieldNames.shrink();
PtrList<List<Type>> values(fieldNames.size());
readFields<Type>(values, fieldNames, cloudObjs);
writeVTKFields<Type>
(
os,
values,
addr,
fieldNames
);
} }
} }

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -25,13 +26,12 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef steadyParticleTracksTemplates_H #ifndef Foam_steadyParticleTracksTemplates_H
#define steadyParticleTracksTemplates_H #define Foam_steadyParticleTracksTemplates_H
#include "OFstream.H" #include "OFstream.H"
#include "IOobjectList.H" #include "IOobjectList.H"
#include "PtrList.H" #include "IOField.H"
#include "Field.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -41,42 +41,29 @@ namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type> template<class Type>
bool fieldOk(const IOobjectList& cloudObjs, const word& name); tmp<IOField<Type>> readParticleField
template<class Type>
tmp<Field<Type>> readParticleField
( (
const word& name, const word& fieldName,
const IOobjectList cloudObjs const IOobjectList& cloudObjects
);
template<class Type>
void readFields
(
PtrList<List<Type>>& values,
const List<word>& fields,
const IOobjectList& cloudObjs
); );
template<class Type> template<class Type>
void writeVTK(OFstream& os, const Type& value); void writeVTK(OFstream& os, const Type& value);
template<class Type> template<class Type>
void writeVTKFields void writeVTKField
( (
OFstream& os, OFstream& os,
const PtrList<List<Type>>& values, const IOField<Type>& field,
const List<List<label>>& addr, const List<labelList>& addr
const List<word>& fieldNames
); );
template<class Type> template<class Type>
void processFields void processFields
( (
OFstream& os, OFstream& os,
const List<List<label>>& addr, const List<labelList>& addr,
const List<word>& userFieldNames, const IOobjectList& cloudObjects
const IOobjectList& cloudObjs
); );
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -482,6 +482,7 @@ DebugSwitches
constantAbsorptionEmission 0; constantAbsorptionEmission 0;
constantAlphaContactAngle 0; constantAlphaContactAngle 0;
constantScatter 0; constantScatter 0;
coordSetWriter 0;
coordinateSystem 0; coordinateSystem 0;
corrected 0; corrected 0;
coupled 0; coupled 0;
@ -983,7 +984,6 @@ DebugSwitches
wedge 0; wedge 0;
weighted 0; weighted 0;
word 0; word 0;
writer 0;
xmgr 0; xmgr 0;
zeroGradient 0; zeroGradient 0;
zoneToCell 0; zoneToCell 0;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016 OpenFOAM Foundation Copyright (C) 2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -28,6 +28,7 @@ License
#include "histogram.H" #include "histogram.H"
#include "volFields.H" #include "volFields.H"
#include "ListOps.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -42,41 +43,6 @@ namespace functionObjects
} }
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::functionObjects::histogram::writeGraph
(
const coordSet& coords,
const word& fieldName,
const scalarField& normalizedValues,
const scalarField& absoluteValues
) const
{
fileName outputPath = baseTimeDir();
mkDir(outputPath);
OFstream graphFile
(
outputPath
/formatterPtr_().getFileName
(
coords,
wordList(1, fieldName)
)
);
Log << " Writing histogram of " << fieldName
<< " to " << graphFile.name() << endl;
wordList fieldNames(2);
fieldNames[0] = fieldName;
fieldNames[1] = fieldName + "Count";
List<const scalarField*> yPtrs(2);
yPtrs[0] = &normalizedValues;
yPtrs[1] = &absoluteValues;
formatterPtr_().write(coords, fieldNames, yPtrs, graphFile);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::histogram::histogram Foam::functionObjects::histogram::histogram
@ -86,10 +52,11 @@ Foam::functionObjects::histogram::histogram
const dictionary& dict const dictionary& dict
) )
: :
fvMeshFunctionObject(name, runTime, dict), functionObjects::fvMeshFunctionObject(name, runTime, dict),
writeFile(obr_, name), functionObjects::writeFile(obr_, name),
max_(-GREAT), max_(-GREAT),
min_(GREAT) min_(GREAT),
setWriterPtr_(nullptr)
{ {
read(dict); read(dict);
} }
@ -116,8 +83,13 @@ bool Foam::functionObjects::histogram::read(const dictionary& dict)
<< abort(FatalError); << abort(FatalError);
} }
const word format(dict.get<word>("setFormat")); const word writeType(dict.get<word>("setFormat"));
formatterPtr_ = writer<scalar>::New(format);
setWriterPtr_ = coordSetWriter::New
(
writeType,
dict.subOrEmptyDict("formatOptions").optionalSubDict(writeType)
);
return true; return true;
} }
@ -133,17 +105,17 @@ bool Foam::functionObjects::histogram::write()
{ {
Log << type() << " " << name() << " write:" << nl; Log << type() << " " << name() << " write:" << nl;
autoPtr<volScalarField> fieldPtr; tmp<volScalarField> tfield;
if (obr_.foundObject<volScalarField>(fieldName_)) tfield.cref(obr_.cfindObject<volScalarField>(fieldName_));
if (tfield)
{ {
Log << " Looking up field " << fieldName_ << endl; Log << " Looking up field " << fieldName_ << endl;
} }
else else
{ {
Log << " Reading field " << fieldName_ << endl; Log << " Reading field " << fieldName_ << endl;
fieldPtr.reset tfield = tmp<volScalarField>::New
(
new volScalarField
( (
IOobject IOobject
( (
@ -154,17 +126,9 @@ bool Foam::functionObjects::histogram::write()
IOobject::NO_WRITE IOobject::NO_WRITE
), ),
mesh_ mesh_
)
); );
} }
const auto& field = tfield();
const volScalarField& field =
(
fieldPtr
? fieldPtr()
: obr_.lookupObject<volScalarField>(fieldName_)
);
scalar histMax = max_; scalar histMax = max_;
scalar histMin = min_; scalar histMin = min_;
@ -188,15 +152,17 @@ bool Foam::functionObjects::histogram::write()
} }
// Calculate the mid-points of bins for the graph axis // Calculate the mid-points of bins for the graph axis
pointField xBin(nBins_); pointField xBin(nBins_, Zero);
const scalar delta = (histMax - histMin)/nBins_; const scalar delta = (histMax - histMin)/nBins_;
scalar x = histMin + 0.5*delta;
forAll(xBin, i)
{ {
xBin[i] = point(x, 0, 0); scalar x = histMin + 0.5*delta;
for (point& p : xBin)
{
p.x() = x;
x += delta; x += delta;
} }
}
scalarField dataNormalized(nBins_, Zero); scalarField dataNormalized(nBins_, Zero);
labelField dataCount(nBins_, Zero); labelField dataCount(nBins_, Zero);
@ -223,23 +189,27 @@ bool Foam::functionObjects::histogram::write()
{ {
dataNormalized /= sumData; dataNormalized /= sumData;
const coordSet coords const coordSet coords(fieldName_, "x", xBin, mag(xBin));
auto& writer = *setWriterPtr_;
writer.open
( (
fieldName_, coords,
"x", (
xBin, writeFile::baseTimeDir()
mag(xBin) / (coords.name() + coordSetWriter::suffix(fieldName_))
)
); );
Log << " Writing histogram of " << fieldName_
<< " to " << writer.path() << endl;
// Convert count field from labelField to scalarField writer.nFields(2);
scalarField count(dataCount.size()); writer.write(fieldName_, dataNormalized);
forAll(count, i) writer.write(fieldName_ + "Count", dataCount);
{
count[i] = 1.0*dataCount[i];
}
writeGraph(coords, fieldName_, dataNormalized, count); writer.close(true);
} }
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016 OpenFOAM Foundation Copyright (C) 2016 OpenFOAM Foundation
Copyright (C) 2017-2020 OpenCFD Ltd. Copyright (C) 2017-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -100,12 +100,12 @@ SourceFiles
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef functionObjects_histogram_H #ifndef Foam_functionObjects_histogram_H
#define functionObjects_histogram_H #define Foam_functionObjects_histogram_H
#include "fvMeshFunctionObject.H" #include "fvMeshFunctionObject.H"
#include "writeFile.H" #include "writeFile.H"
#include "writer.H" #include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -120,8 +120,8 @@ namespace functionObjects
class histogram class histogram
: :
public fvMeshFunctionObject, public functionObjects::fvMeshFunctionObject,
public writeFile public functionObjects::writeFile
{ {
// Private Data // Private Data
@ -138,18 +138,7 @@ class histogram
scalar min_; scalar min_;
//- Output formatter to write //- Output formatter to write
autoPtr<writer<scalar>> formatterPtr_; mutable autoPtr<coordSetWriter> setWriterPtr_;
// Private Member Functions
void writeGraph
(
const coordSet& coords,
const word& valueName,
const scalarField& normalizedValues,
const scalarField& absoluteValues
) const;
public: public:

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -78,8 +78,13 @@ bool Foam::functionObjects::particleDistribution::read(const dictionary& dict)
dict.readEntry("cloud", cloudName_); dict.readEntry("cloud", cloudName_);
dict.readIfPresent("tagField", tagFieldName_); dict.readIfPresent("tagField", tagFieldName_);
dict.readEntry("nameVsBinWidth", nameVsBinWidth_); dict.readEntry("nameVsBinWidth", nameVsBinWidth_);
const word format(dict.get<word>("setFormat"));
writerPtr_ = writer<scalar>::New(format); const word setFormat(dict.get<word>("setFormat"));
writerPtr_ = coordSetWriter::New
(
setFormat,
dict.subOrEmptyDict("formatOptions").optionalSubDict(setFormat)
);
Info<< type() << " " << name() << " output:" << nl Info<< type() << " " << name() << " output:" << nl
<< " Processing cloud : " << cloudName_ << nl << " Processing cloud : " << cloudName_ << nl
@ -104,12 +109,10 @@ bool Foam::functionObjects::particleDistribution::write()
if (!mesh_.foundObject<cloud>(cloudName_)) if (!mesh_.foundObject<cloud>(cloudName_))
{ {
wordList cloudNames(mesh_.names<cloud>());
WarningInFunction WarningInFunction
<< "Unable to find cloud " << cloudName_ << "Unable to find cloud " << cloudName_
<< " in the mesh database. Available clouds include:" << " in the mesh database. Available clouds include:"
<< cloudNames << endl; << flatOutput(mesh_.sortedNames<cloud>()) << endl;
return false; return false;
} }
@ -153,16 +156,17 @@ bool Foam::functionObjects::particleDistribution::write()
} }
bool ok = false;
forAll(nameVsBinWidth_, i) forAll(nameVsBinWidth_, i)
{ {
ok = false; const bool ok
ok = ok || processField<scalar>(cloudObr, i, tagAddr); (
ok = ok || processField<vector>(cloudObr, i, tagAddr); processField<scalar>(cloudObr, i, tagAddr)
ok = ok || processField<tensor>(cloudObr, i, tagAddr); || processField<vector>(cloudObr, i, tagAddr)
ok = ok || processField<sphericalTensor>(cloudObr, i, tagAddr); || processField<tensor>(cloudObr, i, tagAddr)
ok = ok || processField<symmTensor>(cloudObr, i, tagAddr); || processField<sphericalTensor>(cloudObr, i, tagAddr)
ok = ok || processField<tensor>(cloudObr, i, tagAddr); || processField<symmTensor>(cloudObr, i, tagAddr)
|| processField<tensor>(cloudObr, i, tagAddr)
);
if (log && !ok) if (log && !ok)
{ {
@ -189,10 +193,10 @@ void Foam::functionObjects::particleDistribution::generateDistribution
return; return;
} }
word fName(fieldName); word fldName(fieldName);
if (tag != -1) if (tag != -1)
{ {
fName = fName + '_' + Foam::name(tag); fldName += '_' + Foam::name(tag);
} }
distributionModels::general distribution distributionModels::general distribution
@ -202,31 +206,20 @@ void Foam::functionObjects::particleDistribution::generateDistribution
rndGen_ rndGen_
); );
const Field<scalar> distX(distribution.x()); Field<scalar> distX(distribution.x());
const Field<scalar> distY(distribution.y()); Field<scalar> distY(distribution.y());
pointField xBin(distX.size(), Zero); pointField xBin(distX.size(), Zero);
xBin.replace(0, distX); xBin.replace(vector::X, distX);
const coordSet coords
(
fName,
"x",
xBin,
distX
);
const wordList fieldNames(1, fName); const coordSet coords(fldName, "x", std::move(xBin), std::move(distX));
fileName outputPath(baseTimeDir()); writerPtr_->open(coords, baseTimeDir() / fldName);
mkDir(outputPath); fileName outFile = writerPtr_->write(fldName, distY);
OFstream graphFile(outputPath/writerPtr_->getFileName(coords, fieldNames)); writerPtr_->close(true);
Log << " Writing distribution of " << fieldName Log << " Wrote distribution of " << fieldName
<< " to " << graphFile.name() << endl; << " to " << time_.relativePath(outFile) << endl;
List<const scalarField*> yPtrs(1);
yPtrs[0] = &distY;
writerPtr_->write(coords, fieldNames, yPtrs, graphFile);
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -103,7 +103,7 @@ SourceFiles
#include "scalarField.H" #include "scalarField.H"
#include "Random.H" #include "Random.H"
#include "Tuple2.H" #include "Tuple2.H"
#include "writer.H" #include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -118,7 +118,7 @@ namespace functionObjects
class particleDistribution class particleDistribution
: :
public fvMeshFunctionObject, public functionObjects::fvMeshFunctionObject,
public writeFile public writeFile
{ {
protected: protected:
@ -138,7 +138,7 @@ protected:
List<Tuple2<word, scalar>> nameVsBinWidth_; List<Tuple2<word, scalar>> nameVsBinWidth_;
//- Writer //- Writer
autoPtr<writer<scalar>> writerPtr_; mutable autoPtr<coordSetWriter> writerPtr_;
// Protected Member Functions // Protected Member Functions

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2013-2016 OpenFOAM Foundation Copyright (C) 2013-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -27,6 +27,8 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "regionSizeDistribution.H" #include "regionSizeDistribution.H"
#include "regionSplit.H"
#include "volFields.H"
#include "fvcVolumeIntegrate.H" #include "fvcVolumeIntegrate.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
@ -47,30 +49,46 @@ namespace Foam
} }
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
void Foam::functionObjects::regionSizeDistribution::writeGraph namespace Foam
(
const coordSet& coords,
const word& valueName,
const scalarField& values
) const
{ {
const wordList valNames(1, valueName);
fileName outputPath = baseTimeDir(); template<class Type>
mkDir(outputPath); static Map<Type> regionSum(const regionSplit& regions, const Field<Type>& fld)
{
// Per region the sum of fld
Map<Type> regionToSum(regions.nRegions()/Pstream::nProcs());
OFstream str(outputPath/formatterPtr_().getFileName(coords, valNames)); forAll(fld, celli)
{
Log << " Writing distribution of " << valueName << " to " << str.name() const label regioni = regions[celli];
<< endl; regionToSum(regioni, Type(Zero)) += fld[celli];
List<const scalarField*> valPtrs(1);
valPtrs[0] = &values;
formatterPtr_().write(coords, valNames, valPtrs, str);
} }
Pstream::mapCombineGather(regionToSum, plusEqOp<Type>());
Pstream::mapCombineScatter(regionToSum);
return regionToSum;
}
template<class Type>
static List<Type> extractData(const labelUList& keys, const Map<Type>& regionData)
{
List<Type> sortedData(keys.size());
forAll(keys, i)
{
sortedData[i] = regionData[keys[i]];
}
return sortedData;
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::functionObjects::regionSizeDistribution::writeAlphaFields void Foam::functionObjects::regionSizeDistribution::writeAlphaFields
( (
@ -222,7 +240,7 @@ Foam::functionObjects::regionSizeDistribution::divide
} }
else else
{ {
result[i] = 0.0; result[i] = 0;
} }
} }
return tresult; return tresult;
@ -232,8 +250,9 @@ Foam::functionObjects::regionSizeDistribution::divide
void Foam::functionObjects::regionSizeDistribution::writeGraphs void Foam::functionObjects::regionSizeDistribution::writeGraphs
( (
const word& fieldName, // name of field const word& fieldName, // name of field
const labelList& indices, // index of bin for each region
const scalarField& sortedField, // per region field data const scalarField& sortedField, // per region field data
const labelList& indices, // index of bin for each region
const scalarField& binCount, // per bin number of regions const scalarField& binCount, // per bin number of regions
const coordSet& coords // graph data for bins const coordSet& coords // graph data for bins
) const ) const
@ -260,12 +279,44 @@ void Foam::functionObjects::regionSizeDistribution::writeGraphs
sqrt(divide(binSqrSum, binCount) - Foam::sqr(binAvg)) sqrt(divide(binSqrSum, binCount) - Foam::sqr(binAvg))
); );
// Write average
writeGraph(coords, fieldName + "_sum", binSum); auto& writer = formatterPtr_();
// Write average
writeGraph(coords, fieldName + "_avg", binAvg); word outputName;
// Write deviation if (writer.buffering())
writeGraph(coords, fieldName + "_dev", binDev); {
outputName =
(
coords.name()
+ coordSetWriter::suffix
(
wordList
({
fieldName + "_sum",
fieldName + "_avg",
fieldName + "_dev"
})
)
);
}
else
{
outputName = coords.name();
}
writer.open
(
coords,
(baseTimeDir() / outputName)
);
Log << " Writing distribution of "
<< fieldName << " to " << writer.path() << endl;
writer.write(fieldName + "_sum", binSum);
writer.write(fieldName + "_avg", binAvg);
writer.write(fieldName + "_dev", binDev);
writer.close(true);
} }
} }
@ -290,18 +341,15 @@ void Foam::functionObjects::regionSizeDistribution::writeGraphs
scalarField sortedField scalarField sortedField
( (
sortedNormalisation sortedNormalisation
* extractData * extractData(sortedRegions, regionField)
(
sortedRegions,
regionField
)
); );
writeGraphs writeGraphs
( (
fieldName, // name of field fieldName, // name of field
indices, // index of bin for each region
sortedField, // per region field data sortedField, // per region field data
indices, // index of bin for each region
binCount, // per bin number of regions binCount, // per bin number of regions
coords // graph data for bins coords // graph data for bins
); );
@ -343,8 +391,12 @@ bool Foam::functionObjects::regionSizeDistribution::read(const dictionary& dict)
dict.readEntry("patches", patchNames_); dict.readEntry("patches", patchNames_);
dict.readEntry("fields", fields_); dict.readEntry("fields", fields_);
const word format(dict.get<word>("setFormat")); const word setFormat(dict.get<word>("setFormat"));
formatterPtr_ = writer<scalar>::New(format); formatterPtr_ = coordSetWriter::New
(
setFormat,
dict.subOrEmptyDict("formatOptions").optionalSubDict(setFormat)
);
if (dict.found(coordinateSystem::typeName_())) if (dict.found(coordinateSystem::typeName_()))
{ {
@ -385,15 +437,16 @@ bool Foam::functionObjects::regionSizeDistribution::write()
{ {
Log << type() << " " << name() << " write:" << nl; Log << type() << " " << name() << " write:" << nl;
autoPtr<volScalarField> alphaPtr; tmp<volScalarField> talpha;
if (obr_.foundObject<volScalarField>(alphaName_)) talpha.cref(obr_.cfindObject<volScalarField>(alphaName_));
if (talpha)
{ {
Log << " Looking up field " << alphaName_ << endl; Log << " Looking up field " << alphaName_ << endl;
} }
else else
{ {
Info<< " Reading field " << alphaName_ << endl; Info<< " Reading field " << alphaName_ << endl;
alphaPtr.reset talpha.reset
( (
new volScalarField new volScalarField
( (
@ -409,14 +462,7 @@ bool Foam::functionObjects::regionSizeDistribution::write()
) )
); );
} }
const auto& alpha = talpha();
const volScalarField& alpha =
(
alphaPtr
? *alphaPtr
: obr_.lookupObject<volScalarField>(alphaName_)
);
Log << " Volume of alpha = " Log << " Volume of alpha = "
<< fvc::domainIntegrate(alpha).value() << fvc::domainIntegrate(alpha).value()
@ -460,10 +506,9 @@ bool Foam::functionObjects::regionSizeDistribution::write()
if (fvp.coupled()) if (fvp.coupled())
{ {
tmp<scalarField> townFld(fvp.patchInternalField()); tmp<scalarField> townFld(fvp.patchInternalField());
const scalarField& ownFld = townFld();
tmp<scalarField> tnbrFld(fvp.patchNeighbourField()); tmp<scalarField> tnbrFld(fvp.patchNeighbourField());
const scalarField& nbrFld = tnbrFld(); const auto& ownFld = townFld();
const auto& nbrFld = tnbrFld();
label start = fvp.patch().patch().start(); label start = fvp.patch().patch().start();
@ -663,14 +708,16 @@ bool Foam::functionObjects::regionSizeDistribution::write()
if (allRegionVolume.size()) if (allRegionVolume.size())
{ {
// Construct mids of bins for plotting // Construct mids of bins for plotting
pointField xBin(nBins_); pointField xBin(nBins_, Zero);
scalar x = 0.5*delta;
forAll(xBin, i)
{ {
xBin[i] = point(x, 0, 0); scalar x = 0.5*delta;
for (point& p : xBin)
{
p.x() = x;
x += delta; x += delta;
} }
}
const coordSet coords("diameter", "x", xBin, mag(xBin)); const coordSet coords("diameter", "x", xBin, mag(xBin));
@ -682,11 +729,7 @@ bool Foam::functionObjects::regionSizeDistribution::write()
scalarField sortedVols scalarField sortedVols
( (
extractData extractData(sortedRegions, allRegionAlphaVolume)
(
sortedRegions,
allRegionAlphaVolume
)
); );
vectorField centroids(sortedVols.size(), Zero); vectorField centroids(sortedVols.size(), Zero);
@ -712,11 +755,7 @@ bool Foam::functionObjects::regionSizeDistribution::write()
// 2. centroid // 2. centroid
vectorField sortedMoment vectorField sortedMoment
( (
extractData extractData(sortedRegions, allRegionAlphaDistance)
(
sortedRegions,
allRegionAlphaDistance
)
); );
centroids = sortedMoment/sortedVols + origin_; centroids = sortedMoment/sortedVols + origin_;
@ -756,17 +795,30 @@ bool Foam::functionObjects::regionSizeDistribution::write()
if (Pstream::master()) if (Pstream::master())
{ {
// Construct mids of bins for plotting // Construct mids of bins for plotting
pointField xBin(nDownstreamBins_); pointField xBin(nDownstreamBins_, Zero);
scalar x = 0.5*deltaX;
forAll(xBin, i)
{ {
xBin[i] = point(x, 0, 0); scalar x = 0.5*deltaX;
for (point& p : xBin)
{
p.x() = x;
x += deltaX; x += deltaX;
} }
}
const coordSet coords("distance", "x", xBin, mag(xBin)); const coordSet coords("distance", "x", xBin, mag(xBin));
writeGraph(coords, "isoPlanes", binDownCount);
auto& writer = formatterPtr_();
writer.nFields(1);
writer.open
(
coords,
writeFile::baseTimeDir() / (coords.name() + "_isoPlanes")
);
writer.write("isoPlanes", binDownCount);
writer.close(true);
} }
// Write to log // Write to log
@ -819,7 +871,17 @@ bool Foam::functionObjects::regionSizeDistribution::write()
// Write counts // Write counts
if (Pstream::master()) if (Pstream::master())
{ {
writeGraph(coords, "count", binCount); auto& writer = formatterPtr_();
writer.nFields(1);
writer.open
(
coords,
writeFile::baseTimeDir() / (coords.name() + "_count")
);
writer.write("count", binCount);
writer.close(true);
} }
// Write to log // Write to log
@ -849,28 +911,28 @@ bool Foam::functionObjects::regionSizeDistribution::write()
writeGraphs writeGraphs
( (
"volume", // name of field "volume", // name of field
indices, // per region the bin index
sortedVols, // per region field data sortedVols, // per region field data
indices, // per region the bin index
binCount, // per bin number of regions binCount, // per bin number of regions
coords // graph data for bins coords // graph data for bins
); );
// Collect some more field // Collect some more fields
{ {
wordList scalarNames(obr_.names(volScalarField::typeName)); for
(
const labelList selected(fields_.matching(scalarNames)); const word& fldName
: obr_.sortedNames<volScalarField>(fields_)
for (const label fieldi : selected) )
{ {
const word& fldName = scalarNames[fieldi];
Log << " Scalar field " << fldName << endl; Log << " Scalar field " << fldName << endl;
const scalarField& fld = obr_.lookupObject tmp<Field<scalar>> tfld
< (
volScalarField obr_.lookupObject<volScalarField>(fldName).primitiveField()
>(fldName).primitiveField(); );
const auto& fld = tfld();
writeGraphs writeGraphs
( (
@ -887,21 +949,20 @@ bool Foam::functionObjects::regionSizeDistribution::write()
); );
} }
} }
{ {
wordList vectorNames(obr_.names(volVectorField::typeName)); for
(
const labelList selected(fields_.matching(vectorNames)); const word& fldName
: obr_.sortedNames<volVectorField>(fields_)
for (const label fieldi : selected) )
{ {
const word& fldName = vectorNames[fieldi];
Log << " Vector field " << fldName << endl; Log << " Vector field " << fldName << endl;
vectorField fld = obr_.lookupObject tmp<Field<vector>> tfld
< (
volVectorField obr_.lookupObject<volVectorField>(fldName).primitiveField()
>(fldName).primitiveField(); );
if (csysPtr_) if (csysPtr_)
{ {
@ -910,18 +971,18 @@ bool Foam::functionObjects::regionSizeDistribution::write()
<< csysPtr_->name() << csysPtr_->name()
<< endl; << endl;
fld = csysPtr_->localVector(fld); tfld = csysPtr_->localVector(tfld());
} }
const auto& fld = tfld();
// Components // Components
for (direction cmp = 0; cmp < vector::nComponents; cmp++) for (direction cmpt = 0; cmpt < vector::nComponents; ++cmpt)
{ {
writeGraphs writeGraphs
( (
fldName + vector::componentNames[cmp], fldName + vector::componentNames[cmpt],
alphaVol*fld.component(cmp),// per cell field data alphaVol*fld.component(cmpt),// per cell field data
regions, // per cell the region(=droplet) regions, // per cell the region(=droplet)
sortedRegions, // valid regions in sorted order sortedRegions, // valid regions in sorted order

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2013-2016 OpenFOAM Foundation Copyright (C) 2013-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -169,17 +169,16 @@ SourceFiles
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef functionObjects_regionSizeDistribution_H #ifndef Foam_functionObjects_regionSizeDistribution_H
#define functionObjects_regionSizeDistribution_H #define Foam_functionObjects_regionSizeDistribution_H
#include "fvMeshFunctionObject.H" #include "fvMeshFunctionObject.H"
#include "writeFile.H" #include "writeFile.H"
#include "writer.H" #include "coordSetWriter.H"
#include "Map.H" #include "Map.H"
#include "volFieldsFwd.H" #include "volFieldsFwd.H"
#include "wordRes.H" #include "wordRes.H"
#include "coordinateSystem.H" #include "coordinateSystem.H"
#include "Switch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -197,7 +196,7 @@ namespace functionObjects
class regionSizeDistribution class regionSizeDistribution
: :
public fvMeshFunctionObject, public functionObjects::fvMeshFunctionObject,
public writeFile public writeFile
{ {
// Private Data // Private Data
@ -224,7 +223,7 @@ class regionSizeDistribution
wordRes fields_; wordRes fields_;
//- Output formatter to write //- Output formatter to write
autoPtr<writer<scalar>> formatterPtr_; mutable autoPtr<coordSetWriter> formatterPtr_;
//- Optional coordinate system //- Optional coordinate system
autoPtr<coordinateSystem> csysPtr_; autoPtr<coordinateSystem> csysPtr_;
@ -253,20 +252,6 @@ class regionSizeDistribution
// Private Member Functions // Private Member Functions
template<class Type>
Map<Type> regionSum(const regionSplit&, const Field<Type>&) const;
//- Get data in order
template<class Type>
List<Type> extractData(const labelUList& keys, const Map<Type>&) const;
void writeGraph
(
const coordSet& coords,
const word& valueName,
const scalarField& values
) const;
//- Write volfields with the parts of alpha which are not //- Write volfields with the parts of alpha which are not
//- droplets (liquidCore, backGround) //- droplets (liquidCore, backGround)
void writeAlphaFields void writeAlphaFields
@ -287,8 +272,9 @@ class regionSizeDistribution
void writeGraphs void writeGraphs
( (
const word& fieldName, // name of field const word& fieldName, // name of field
const labelList& indices, // index of bin for each region
const scalarField& sortedField, // per region field data const scalarField& sortedField, // per region field data
const labelList& indices, // index of bin for each region
const scalarField& binCount, // per bin number of regions const scalarField& binCount, // per bin number of regions
const coordSet& coords // graph data for bins const coordSet& coords // graph data for bins
) const; ) const;
@ -301,6 +287,7 @@ class regionSizeDistribution
const regionSplit& regions, // per cell the region(=droplet) const regionSplit& regions, // per cell the region(=droplet)
const labelList& sortedRegions, // valid regions in sorted order const labelList& sortedRegions, // valid regions in sorted order
const scalarField& sortedNormalisation, const scalarField& sortedNormalisation,
const labelList& indices, // index of bin for each region const labelList& indices, // index of bin for each region
const scalarField& binCount, // per bin number of regions const scalarField& binCount, // per bin number of regions
const coordSet& coords // graph data for bins const coordSet& coords // graph data for bins
@ -355,12 +342,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "regionSizeDistributionTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif #endif
// ************************************************************************* // // ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2015 OpenFOAM Foundation Copyright (C) 2015 OpenFOAM Foundation
Copyright (C) 2015-2021 OpenCFD Ltd. Copyright (C) 2015-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -29,6 +29,7 @@ License
#include "streamLineBase.H" #include "streamLineBase.H"
#include "fvMesh.H" #include "fvMesh.H"
#include "ReadFields.H" #include "ReadFields.H"
#include "OFstream.H"
#include "sampledSet.H" #include "sampledSet.H"
#include "globalIndex.H" #include "globalIndex.H"
#include "mapDistribute.H" #include "mapDistribute.H"
@ -626,8 +627,7 @@ bool Foam::functionObjects::streamLineBase::writeToFile()
// Note: filenames scattered below since used in global call // Note: filenames scattered below since used in global call
fileName scalarVtkFile; HashTable<fileName> outputFileNames;
fileName vectorVtkFile;
if (Pstream::master()) if (Pstream::master())
{ {
@ -706,16 +706,37 @@ bool Foam::functionObjects::streamLineBase::writeToFile()
} }
} }
// Convert scalar values
if (!allScalars_.empty() && !tracks.empty()) const bool canWrite =
(
!tracks.empty()
&& trackWriterPtr_
&& trackWriterPtr_->enabled()
&& (!allScalars_.empty() || !allVectors_.empty())
);
if (canWrite)
{
auto& writer = trackWriterPtr_();
writer.nFields(allScalars_.size() + allVectors_.size());
writer.open
(
tracks,
(vtkPath / tracks[0].name())
);
// Temporary measure
if (!allScalars_.empty())
{ {
List<List<scalarField>> scalarValues(allScalars_.size()); List<List<scalarField>> scalarValues(allScalars_.size());
forAll(allScalars_, scalari) forAll(allScalars_, scalari)
{ {
DynamicList<scalarList>& allTrackVals = allScalars_[scalari]; DynamicList<scalarList>& allTrackVals = allScalars_[scalari];
scalarValues[scalari].setSize(nTracks); scalarValues[scalari].resize(nTracks);
forAll(allTrackVals, tracki) forAll(allTrackVals, tracki)
{ {
@ -728,32 +749,20 @@ bool Foam::functionObjects::streamLineBase::writeToFile()
} }
} }
scalarVtkFile = fileName forAll(scalarNames_, i)
( {
vtkPath fileName outFile =
/ scalarFormatterPtr_().getFileName writer.write(scalarNames_[i], scalarValues[i]);
(
tracks[0],
scalarNames_
)
);
Log << " Writing data to " << scalarVtkFile.path() << endl; outputFileNames.insert
scalarFormatterPtr_().write
( (
true, // writeTracks scalarNames_[i],
List<scalarField>(), // times time_.relativePath(outFile, true)
tracks,
scalarNames_,
scalarValues,
OFstream(scalarVtkFile)()
); );
} }
}
// Convert vector values if (!allVectors_.empty())
if (!allVectors_.empty() && !tracks.empty())
{ {
List<List<vectorField>> vectorValues(allVectors_.size()); List<List<vectorField>> vectorValues(allVectors_.size());
@ -773,50 +782,36 @@ bool Foam::functionObjects::streamLineBase::writeToFile()
} }
} }
vectorVtkFile = fileName forAll(vectorNames_, i)
(
vtkPath
/ vectorFormatterPtr_().getFileName(tracks[0], vectorNames_)
);
//Info<< " Writing vector data to " << vectorVtkFile << endl;
vectorFormatterPtr_().write
(
true, // writeTracks
List<scalarField>(), // times
tracks,
vectorNames_,
vectorValues,
OFstream(vectorVtkFile)()
);
}
}
// File names are generated on the master but setProperty needs to
// be across all procs
Pstream::scatter(scalarVtkFile);
for (const word& fieldName : scalarNames_)
{ {
dictionary propsDict; fileName outFile =
propsDict.add writer.write(vectorNames_[i], vectorValues[i]);
outputFileNames.insert
( (
"file", scalarNames_[i],
time_.relativePath(scalarVtkFile, true) time_.relativePath(outFile, true)
); );
setProperty(fieldName, propsDict); }
} }
Pstream::scatter(vectorVtkFile); writer.close(true);
for (const word& fieldName : vectorNames_) }
// Log << " Writing data to " << scalarVtkFile.path() << endl;
}
// File names generated on the master but setProperty needed everywher
Pstream::scatter(outputFileNames);
forAllConstIters(outputFileNames, iter)
{ {
const word& fieldName = iter.key();
const fileName& outputName = iter.val();
dictionary propsDict; dictionary propsDict;
propsDict.add propsDict.add("file", outputName);
(
"file",
time_.relativePath(vectorVtkFile, true)
);
setProperty(fieldName, propsDict); setProperty(fieldName, propsDict);
} }
@ -844,7 +839,7 @@ Foam::functionObjects::streamLineBase::streamLineBase
const dictionary& dict const dictionary& dict
) )
: :
fvMeshFunctionObject(name, runTime, dict), functionObjects::fvMeshFunctionObject(name, runTime, dict),
dict_(dict), dict_(dict),
fields_() fields_()
{} {}
@ -858,7 +853,7 @@ Foam::functionObjects::streamLineBase::streamLineBase
const wordList& fieldNames const wordList& fieldNames
) )
: :
fvMeshFunctionObject(name, runTime, dict), functionObjects::fvMeshFunctionObject(name, runTime, dict),
dict_(dict), dict_(dict),
fields_(fieldNames) fields_(fieldNames)
{} {}
@ -959,8 +954,13 @@ bool Foam::functionObjects::streamLineBase::read(const dictionary& dict)
sampledSetPtr_.clear(); sampledSetPtr_.clear();
sampledSetAxis_.clear(); sampledSetAxis_.clear();
scalarFormatterPtr_ = writer<scalar>::New(dict.get<word>("setFormat")); const word setFormat(dict.get<word>("setFormat"));
vectorFormatterPtr_ = writer<vector>::New(dict.get<word>("setFormat"));
trackWriterPtr_ = coordSetWriter::New
(
setFormat,
dict.subOrEmptyDict("formatOptions").optionalSubDict(setFormat)
);
return true; return true;
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2015 OpenFOAM Foundation Copyright (C) 2015 OpenFOAM Foundation
Copyright (C) 2016 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -36,14 +36,14 @@ SourceFiles
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef streamLineBase_H #ifndef Foam_functionObjects_streamLineBase_H
#define streamLineBase_H #define Foam_functionObjects_streamLineBase_H
#include "fvMeshFunctionObject.H" #include "fvMeshFunctionObject.H"
#include "DynamicList.H" #include "DynamicList.H"
#include "scalarList.H" #include "scalarList.H"
#include "vectorList.H" #include "vectorList.H"
#include "writer.H" #include "coordSetWriter.H"
#include "indirectPrimitivePatch.H" #include "indirectPrimitivePatch.H"
#include "interpolation.H" #include "interpolation.H"
#include "Enum.H" #include "Enum.H"
@ -53,6 +53,7 @@ SourceFiles
namespace Foam namespace Foam
{ {
// Forward Declarations
class meshSearch; class meshSearch;
class sampledSet; class sampledSet;
@ -65,7 +66,7 @@ namespace functionObjects
class streamLineBase class streamLineBase
: :
public fvMeshFunctionObject public functionObjects::fvMeshFunctionObject
{ {
public: public:
@ -130,14 +131,11 @@ protected:
// Demand driven // Demand driven
//- File writer for scalar data //- File writer for tracks data
autoPtr<writer<scalar>> scalarFormatterPtr_; mutable autoPtr<coordSetWriter> trackWriterPtr_;
//- File writer for vector data
autoPtr<writer<vector>> vectorFormatterPtr_;
// Generated data // Generated Data
//- All tracks. Per track the points it passed through //- All tracks. Per track the points it passed through
DynamicList<List<point>> allTracks_; DynamicList<List<point>> allTracks_;

View File

@ -2808,23 +2808,19 @@ Foam::fileName Foam::meshRefinement::writeLeakPath
const polyMesh& mesh, const polyMesh& mesh,
const pointField& locationsInMesh, const pointField& locationsInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const writer<scalar>& leakPathFormatter, const boolList& blockedFace,
const boolList& blockedFace coordSetWriter& writer
) )
{ {
const polyBoundaryMesh& pbm = mesh.boundaryMesh(); const polyBoundaryMesh& pbm = mesh.boundaryMesh();
fileName outputDir; fileName outputDir
if (Pstream::master()) (
{
outputDir =
mesh.time().globalPath() mesh.time().globalPath()
/ functionObject::outputPrefix / functionObject::outputPrefix
/ mesh.pointsInstance(); / mesh.pointsInstance()
outputDir.clean(); );
mkDir(outputDir); outputDir.clean(); // Remove unneeded ".."
}
// Write the leak path // Write the leak path
@ -2877,7 +2873,7 @@ Foam::fileName Foam::meshRefinement::writeLeakPath
label& n = nElemsPerSegment[segmenti]; label& n = nElemsPerSegment[segmenti];
points[n] = leakPath[elemi]; points[n] = leakPath[elemi];
dist[n] = leakPath.curveDist()[elemi]; dist[n] = leakPath.distance()[elemi];
n++; n++;
} }
} }
@ -2887,13 +2883,11 @@ Foam::fileName Foam::meshRefinement::writeLeakPath
{ {
// Collect data from all processors // Collect data from all processors
List<pointList> gatheredPts(Pstream::nProcs()); List<pointList> gatheredPts(Pstream::nProcs());
gatheredPts[Pstream::myProcNo()] = gatheredPts[Pstream::myProcNo()] = std::move(segmentPoints[segmenti]);
std::move(segmentPoints[segmenti]);
Pstream::gatherList(gatheredPts); Pstream::gatherList(gatheredPts);
List<scalarList> gatheredDist(Pstream::nProcs()); List<scalarList> gatheredDist(Pstream::nProcs());
gatheredDist[Pstream::myProcNo()] = gatheredDist[Pstream::myProcNo()] = std::move(segmentDist[segmenti]);
std::move(segmentDist[segmenti]);
Pstream::gatherList(gatheredDist); Pstream::gatherList(gatheredDist);
// Combine processor lists into one big list. // Combine processor lists into one big list.
@ -2912,7 +2906,7 @@ Foam::fileName Foam::meshRefinement::writeLeakPath
) )
); );
// Sort according to curveDist // Sort according to distance
labelList indexSet(Foam::sortedOrder(allDist)); labelList indexSet(Foam::sortedOrder(allDist));
allLeakPaths.set allLeakPaths.set
@ -2932,42 +2926,28 @@ Foam::fileName Foam::meshRefinement::writeLeakPath
fileName fName; fileName fName;
if (Pstream::master()) if (Pstream::master())
{ {
List<List<scalarField>> allLeakData(1); List<scalarField> allLeakData(allLeakPaths.size());
List<scalarField>& varData = allLeakData[0];
varData.setSize(allLeakPaths.size());
forAll(allLeakPaths, segmenti) forAll(allLeakPaths, segmenti)
{ {
varData[segmenti] = allLeakPaths[segmenti].curveDist(); allLeakData[segmenti] = allLeakPaths[segmenti].distance();
} }
const wordList valueSetNames(1, "leakPath"); writer.nFields(1);
fName = writer.open
outputDir
/leakPathFormatter.getFileName
( (
allLeakPaths[0],
valueSetNames
);
// Note scope to force writing to finish before
// FatalError exit
OFstream ofs(fName);
if (ofs.opened())
{
leakPathFormatter.write
(
true, // write tracks
List<scalarField>(), // times
allLeakPaths, allLeakPaths,
valueSetNames, (outputDir / allLeakPaths[0].name())
allLeakData,
ofs
); );
}
fName = writer.write("leakPath", allLeakData);
// Force writing to finish before FatalError exit
writer.close(true);
} }
Pstream::scatter(fName); // Probably do not need to broadcast name (only written on master anyhow)
UPstream::broadcast(fName);
return fName; return fName;
} }
@ -2982,11 +2962,12 @@ Foam::label Foam::meshRefinement::findRegions
const vector& perturbVec, const vector& perturbVec,
const pointField& locationsInMesh, const pointField& locationsInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const bool exitIfLeakPath,
const refPtr<writer<scalar>>& leakPathFormatter,
const label nRegions, const label nRegions,
labelList& cellRegion, labelList& cellRegion,
const boolList& blockedFace const boolList& blockedFace,
// Leak-path
const bool exitIfLeakPath,
const refPtr<coordSetWriter>& leakPathFormatter
) )
{ {
bitSet insideCell(mesh.nCells()); bitSet insideCell(mesh.nCells());
@ -3022,7 +3003,10 @@ Foam::label Foam::meshRefinement::findRegions
// mesh do not conflict with those inside // mesh do not conflict with those inside
forAll(locationsOutsideMesh, i) forAll(locationsOutsideMesh, i)
{ {
// Find the region containing the point // Find the region containing the point,
// and the corresponding inside region index
label indexi;
label regioni = findRegion label regioni = findRegion
( (
mesh, mesh,
@ -3031,14 +3015,9 @@ Foam::label Foam::meshRefinement::findRegions
locationsOutsideMesh[i] locationsOutsideMesh[i]
); );
if (regioni != -1) if (regioni == -1 && (indexi = insideRegions.find(regioni)) != -1)
{ {
// Do a quick check for locationsOutsideMesh overlapping with if (leakPathFormatter)
// inside ones.
label index = insideRegions.find(regioni);
if (index != -1)
{
if (leakPathFormatter.valid())
{ {
const fileName fName const fileName fName
( (
@ -3047,30 +3026,28 @@ Foam::label Foam::meshRefinement::findRegions
mesh, mesh,
locationsInMesh, locationsInMesh,
locationsOutsideMesh, locationsOutsideMesh,
leakPathFormatter, blockedFace,
blockedFace leakPathFormatter.constCast()
) )
); );
Info<< "Dumped leak path to " << fName << endl; Info<< "Dumped leak path to " << fName << endl;
} }
if (exitIfLeakPath) auto& err =
{ (
FatalErrorInFunction exitIfLeakPath
<< "Location in mesh " << locationsInMesh[index] ? FatalErrorInFunction
<< " is inside same mesh region " << regioni : WarningInFunction
<< " as one of the locations outside mesh " );
<< locationsOutsideMesh
<< exit(FatalError); err << "Location in mesh " << locationsInMesh[indexi]
}
else
{
WarningInFunction
<< "Location in mesh " << locationsInMesh[index]
<< " is inside same mesh region " << regioni << " is inside same mesh region " << regioni
<< " as one of the locations outside mesh " << " as one of the locations outside mesh "
<< locationsOutsideMesh << endl; << locationsOutsideMesh << endl;
}
if (exitIfLeakPath)
{
FatalError << exit(FatalError);
} }
} }
} }
@ -3103,7 +3080,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMeshRegions
const pointField& locationsInMesh, const pointField& locationsInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const bool exitIfLeakPath, const bool exitIfLeakPath,
const refPtr<writer<scalar>>& leakPathFormatter const refPtr<coordSetWriter>& leakPathFormatter
) )
{ {
// Force calculation of face decomposition (used in findCell) // Force calculation of face decomposition (used in findCell)
@ -3120,14 +3097,15 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMeshRegions
label nRemove = findRegions label nRemove = findRegions
( (
mesh_, mesh_,
mergeDistance_ * vector::one, // perturbVec vector::uniform(mergeDistance_), // perturbVec
locationsInMesh, locationsInMesh,
locationsOutsideMesh, locationsOutsideMesh,
exitIfLeakPath,
leakPathFormatter,
cellRegion.nRegions(), cellRegion.nRegions(),
cellRegion, cellRegion,
blockedFace blockedFace,
// Leak-path
exitIfLeakPath,
leakPathFormatter
); );
// Subset // Subset

View File

@ -60,7 +60,7 @@ SourceFiles
#include "surfaceZonesInfo.H" #include "surfaceZonesInfo.H"
#include "volumeType.H" #include "volumeType.H"
#include "DynamicField.H" #include "DynamicField.H"
#include "writer.H" #include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -587,7 +587,7 @@ private:
const pointField& locationsInMesh, const pointField& locationsInMesh,
const wordList& regionsInMesh, const wordList& regionsInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const refPtr<writer<scalar>>& leakPathFormatter, const refPtr<coordSetWriter>& leakPathFormatter,
const labelList& neiLevel, const labelList& neiLevel,
const pointField& neiCc, const pointField& neiCc,
@ -622,8 +622,8 @@ private:
const polyMesh& mesh, const polyMesh& mesh,
const pointField& locationsInMesh, const pointField& locationsInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const writer<scalar>& leakPathFormatter, const boolList& blockedFace,
const boolList& blockedFace coordSetWriter& leakPathWriter
); );
@ -846,7 +846,7 @@ private:
const pointField& locationsInMesh, const pointField& locationsInMesh,
const wordList& zonesInMesh, const wordList& zonesInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const refPtr<writer<scalar>>& leakPathFormatter, const refPtr<coordSetWriter>& leakPathFormatter,
labelList& cellToZone, labelList& cellToZone,
labelList& unnamedRegion1, labelList& unnamedRegion1,
@ -1303,7 +1303,7 @@ public:
const pointField& locationsInMesh, const pointField& locationsInMesh,
const wordList& regionsInMesh, const wordList& regionsInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const refPtr<writer<scalar>>& leakPathFormatter const refPtr<coordSetWriter>& leakPathFormatter
); );
//- Merge free-standing baffles //- Merge free-standing baffles
@ -1334,7 +1334,7 @@ public:
const pointField& locationsInMesh, const pointField& locationsInMesh,
const wordList& regionsInMesh, const wordList& regionsInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const writer<scalar>& leakPathFormatter const refPtr<coordSetWriter>& leakPathFormatter
); );
//- Remove cells from limitRegions if level -1 //- Remove cells from limitRegions if level -1
@ -1436,7 +1436,7 @@ public:
const pointField& locationsInMesh, const pointField& locationsInMesh,
const wordList& regionsInMesh, const wordList& regionsInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const refPtr<writer<scalar>>& leakPathFormatter, const refPtr<coordSetWriter>& leakPathFormatter,
wordPairHashTable& zonesToFaceZone wordPairHashTable& zonesToFaceZone
); );
@ -1543,11 +1543,12 @@ public:
const vector& perturbVec, const vector& perturbVec,
const pointField& locationsInMesh, const pointField& locationsInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const bool exitIfLeakPath,
const refPtr<writer<scalar>>& leakPathFormatter,
const label nRegions, const label nRegions,
labelList& cellRegion, labelList& cellRegion,
const boolList& blockedFace const boolList& blockedFace,
// Leak-path
const bool exitIfLeakPath,
const refPtr<coordSetWriter>& leakPathFormatter
); );
//- Split mesh. Keep part containing point. Return empty map if //- Split mesh. Keep part containing point. Return empty map if
@ -1558,8 +1559,9 @@ public:
const labelList& globalToSlavePatch, const labelList& globalToSlavePatch,
const pointField& locationsInMesh, const pointField& locationsInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
// Leak-path
const bool exitIfLeakPath, const bool exitIfLeakPath,
const refPtr<writer<scalar>>& leakPathFormatter const refPtr<coordSetWriter>& leakPathFormatter
); );
//- Split faces into two //- Split faces into two

View File

@ -292,7 +292,7 @@ void Foam::meshRefinement::getBafflePatches
const pointField& locationsInMesh, const pointField& locationsInMesh,
const wordList& zonesInMesh, const wordList& zonesInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const refPtr<writer<scalar>>& leakPathFormatter, const refPtr<coordSetWriter>& leakPathFormatter,
const labelList& neiLevel, const labelList& neiLevel,
const pointField& neiCc, const pointField& neiCc,
@ -1688,7 +1688,7 @@ void Foam::meshRefinement::findCellZoneInsideWalk
( (
mesh_, mesh_,
cellRegion, cellRegion,
mergeDistance_ * vector::one, vector::uniform(mergeDistance_),
insidePoint insidePoint
); );
@ -1959,7 +1959,7 @@ void Foam::meshRefinement::findCellZoneTopo
( (
mesh_, mesh_,
cellRegion, cellRegion,
mergeDistance_ * vector::one, vector::uniform(mergeDistance_),
keepPoint keepPoint
); );
@ -2843,7 +2843,7 @@ void Foam::meshRefinement::zonify
const pointField& locationsInMesh, const pointField& locationsInMesh,
const wordList& zonesInMesh, const wordList& zonesInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const refPtr<writer<scalar>>& leakPathFormatter, const refPtr<coordSetWriter>& leakPathFormatter,
labelList& cellToZone, labelList& cellToZone,
labelList& unnamedRegion1, labelList& unnamedRegion1,
@ -2961,7 +2961,7 @@ void Foam::meshRefinement::zonify
<< endl; << endl;
// Dump leak path // Dump leak path
if (leakPathFormatter.valid()) if (leakPathFormatter)
{ {
boolList blockedFace(mesh_.nFaces(), false); boolList blockedFace(mesh_.nFaces(), false);
UIndirectList<bool>(blockedFace, unnamedFaces) = true; UIndirectList<bool>(blockedFace, unnamedFaces) = true;
@ -2972,8 +2972,8 @@ void Foam::meshRefinement::zonify
mesh_, mesh_,
locationsInMesh, locationsInMesh,
locationsOutsideMesh, locationsOutsideMesh,
leakPathFormatter(), blockedFace,
blockedFace leakPathFormatter.constCast()
) )
); );
Info<< "Dumped leak path to " << fName << endl; Info<< "Dumped leak path to " << fName << endl;
@ -3065,7 +3065,7 @@ void Foam::meshRefinement::zonify
<< endl; << endl;
// Dump leak path // Dump leak path
if (leakPathFormatter.valid()) if (leakPathFormatter)
{ {
boolList blockedFace(mesh_.nFaces(), false); boolList blockedFace(mesh_.nFaces(), false);
UIndirectList<bool>(blockedFace, unnamedFaces) = true; UIndirectList<bool>(blockedFace, unnamedFaces) = true;
@ -3077,8 +3077,8 @@ void Foam::meshRefinement::zonify
mesh_, mesh_,
locationsInMesh, locationsInMesh,
locationsOutsideMesh, locationsOutsideMesh,
leakPathFormatter(), blockedFace,
blockedFace leakPathFormatter.constCast()
) )
); );
Info<< "Dumped leak path to " << fName << endl; Info<< "Dumped leak path to " << fName << endl;
@ -4509,7 +4509,7 @@ void Foam::meshRefinement::baffleAndSplitMesh
const pointField& locationsInMesh, const pointField& locationsInMesh,
const wordList& zonesInMesh, const wordList& zonesInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const refPtr<writer<scalar>>& leakPathFormatter const refPtr<coordSetWriter>& leakPathFormatter
) )
{ {
// Introduce baffles // Introduce baffles
@ -4536,7 +4536,7 @@ void Foam::meshRefinement::baffleAndSplitMesh
locationsInMesh, locationsInMesh,
zonesInMesh, zonesInMesh,
locationsOutsideMesh, locationsOutsideMesh,
refPtr<writer<scalar>>(nullptr), refPtr<coordSetWriter>(nullptr),
neiLevel, neiLevel,
neiCc, neiCc,
@ -4610,7 +4610,7 @@ void Foam::meshRefinement::baffleAndSplitMesh
locationsInMesh, locationsInMesh,
zonesInMesh, zonesInMesh,
locationsOutsideMesh, locationsOutsideMesh,
refPtr<writer<scalar>>(nullptr), refPtr<coordSetWriter>(nullptr),
neiLevel, neiLevel,
neiCc, neiCc,
@ -4760,7 +4760,7 @@ void Foam::meshRefinement::mergeFreeStandingBaffles
locationsInMesh, locationsInMesh,
locationsOutsideMesh, locationsOutsideMesh,
true, // Exit if any connection between inside and outside true, // Exit if any connection between inside and outside
refPtr<writer<scalar>>(nullptr) //leakPathFormatter refPtr<coordSetWriter>(nullptr) // leakPathFormatter
); );
@ -4785,7 +4785,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMesh
const pointField& locationsInMesh, const pointField& locationsInMesh,
const wordList& zonesInMesh, const wordList& zonesInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const writer<scalar>& leakPathFormatter const refPtr<coordSetWriter>& leakPathFormatter
) )
{ {
// Determine patches to put intersections into // Determine patches to put intersections into
@ -4834,14 +4834,15 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMesh
findRegions findRegions
( (
mesh_, mesh_,
mergeDistance_ * vector::one, // perturbVec vector::uniform(mergeDistance_), // perturbVec
locationsInMesh, locationsInMesh,
locationsOutsideMesh, locationsOutsideMesh,
false, // do not exit if outside location found
leakPathFormatter,
cellRegion.nRegions(), cellRegion.nRegions(),
cellRegion, cellRegion,
blockedFace blockedFace,
// Leak-path
false, // do not exit if outside location found
leakPathFormatter
); );
return splitMesh return splitMesh
@ -5272,7 +5273,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::removeLimitShells
locationsInMesh, locationsInMesh,
zonesInMesh, zonesInMesh,
locationsOutsideMesh, locationsOutsideMesh,
refPtr<writer<scalar>>(nullptr), refPtr<coordSetWriter>(nullptr),
neiLevel, neiLevel,
neiCc, neiCc,
@ -5574,7 +5575,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
const pointField& locationsInMesh, const pointField& locationsInMesh,
const wordList& zonesInMesh, const wordList& zonesInMesh,
const pointField& locationsOutsideMesh, const pointField& locationsOutsideMesh,
const refPtr<writer<scalar>>& leakPathFormatter, const refPtr<coordSetWriter>& leakPathFormatter,
wordPairHashTable& zonesToFaceZone wordPairHashTable& zonesToFaceZone
) )
{ {

View File

@ -67,7 +67,7 @@ Foam::snappyRefineDriver::snappyRefineDriver
fvMeshDistribute& distributor, fvMeshDistribute& distributor,
const labelUList& globalToMasterPatch, const labelUList& globalToMasterPatch,
const labelUList& globalToSlavePatch, const labelUList& globalToSlavePatch,
const writer<scalar>& setFormatter, coordSetWriter& setFormatter,
const bool dryRun const bool dryRun
) )
: :

View File

@ -41,7 +41,7 @@ SourceFiles
#include "labelList.H" #include "labelList.H"
#include "scalarField.H" #include "scalarField.H"
#include "Tuple2.H" #include "Tuple2.H"
#include "writer.H" #include "coordSetWriter.H"
#include "DynamicList.H" #include "DynamicList.H"
#include "labelVector.H" #include "labelVector.H"
#include "meshRefinement.H" #include "meshRefinement.H"
@ -83,7 +83,7 @@ class snappyRefineDriver
const labelList globalToSlavePatch_; const labelList globalToSlavePatch_;
//- How to write lines. Used e.g. when writing leak-paths //- How to write lines. Used e.g. when writing leak-paths
const writer<scalar>& setFormatter_; coordSetWriter& setFormatter_;
//- Are we operating in test mode? //- Are we operating in test mode?
const bool dryRun_; const bool dryRun_;
@ -275,7 +275,7 @@ public:
fvMeshDistribute& distributor, fvMeshDistribute& distributor,
const labelUList& globalToMasterPatch, const labelUList& globalToMasterPatch,
const labelUList& globalToSlavePatch, const labelUList& globalToSlavePatch,
const writer<scalar>& setFormatter, coordSetWriter& setFormatter,
const bool dryRun = false const bool dryRun = false
); );

View File

@ -136,16 +136,19 @@ coordSet/coordSet.C
setWriters = coordSet/writers setWriters = coordSet/writers
$(setWriters)/common/writers.C $(setWriters)/common/coordSetWriter.C
$(setWriters)/csv/csvSetWriterRunTime.C $(setWriters)/common/coordSetWriterBuffers.C
$(setWriters)/ensight/ensightSetWriterRunTime.C $(setWriters)/common/coordSetWriterNew.C
$(setWriters)/gltf/gltfSetWriterRunTime.C $(setWriters)/csv/csvCoordSetWriter.C
$(setWriters)/gnuplot/gnuplotSetWriterRunTime.C $(setWriters)/ensight/ensightCoordSetWriter.C
$(setWriters)/nastran/nastranSetWriterRunTime.C $(setWriters)/gltf/gltfCoordSetWriter.C
$(setWriters)/raw/rawSetWriterRunTime.C $(setWriters)/gnuplot/gnuplotCoordSetWriter.C
$(setWriters)/nastran/nastranCoordSetWriter.C
$(setWriters)/null/nullCoordSetWriter.C
$(setWriters)/raw/rawCoordSetWriter.C
$(setWriters)/vtk/foamVtkCoordSetWriter.C $(setWriters)/vtk/foamVtkCoordSetWriter.C
$(setWriters)/vtk/vtkSetWriterRunTime.C $(setWriters)/vtk/vtkCoordSetWriter.C
$(setWriters)/xmgrace/xmgraceSetWriterRunTime.C $(setWriters)/xmgrace/xmgraceCoordSetWriter.C
graph/curve.C graph/curve.C
graph/graph.C graph/graph.C

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2018 OpenCFD Ltd. Copyright (C) 2017-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -27,6 +27,7 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "coordSet.H" #include "coordSet.H"
#include "globalIndex.H"
// * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * * // // * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * * //
@ -36,11 +37,13 @@ const Foam::Enum
> >
Foam::coordSet::coordFormatNames Foam::coordSet::coordFormatNames
({ ({
{ coordFormat::XYZ, "xyz" },
{ coordFormat::X, "x" }, { coordFormat::X, "x" },
{ coordFormat::Y, "y" }, { coordFormat::Y, "y" },
{ coordFormat::Z, "z" }, { coordFormat::Z, "z" },
{ coordFormat::RADIUS, "radius" },
{ coordFormat::DISTANCE, "distance" }, { coordFormat::DISTANCE, "distance" },
{ coordFormat::XYZ, "xyz" },
/// { coordFormat::DEFAULT, "default" },
}); });
@ -48,12 +51,12 @@ Foam::coordSet::coordFormatNames
void Foam::coordSet::checkDimensions() const void Foam::coordSet::checkDimensions() const
{ {
if (size() != curveDist_.size()) if (points().size() != distance().size())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Size of points and curve distance must be the same" << nl << "Size not equal :" << nl
<< " points size : " << size() << " points:" << points().size()
<< " curve size : " << curveDist_.size() << " distance:" << distance().size()
<< abort(FatalError); << abort(FatalError);
} }
} }
@ -61,6 +64,15 @@ void Foam::coordSet::checkDimensions() const
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Foam::coordSet::coordSet()
// :
// pointField(),
// name_(),
// distance_(),
// axis_(coordFormat::DEFAULT)
// {}
Foam::coordSet::coordSet Foam::coordSet::coordSet
( (
const word& name, const word& name,
@ -69,8 +81,8 @@ Foam::coordSet::coordSet
: :
pointField(), pointField(),
name_(name), name_(name),
axis_(axisType), distance_(),
curveDist_() axis_(axisType)
{} {}
@ -80,10 +92,7 @@ Foam::coordSet::coordSet
const word& axis const word& axis
) )
: :
pointField(), coordSet(name, coordFormatNames.get(axis))
name_(name),
axis_(coordFormatNames[axis]),
curveDist_()
{} {}
@ -92,13 +101,13 @@ Foam::coordSet::coordSet
const word& name, const word& name,
const word& axis, const word& axis,
const List<point>& points, const List<point>& points,
const scalarList& curveDist const scalarList& dist
) )
: :
pointField(points), pointField(points),
name_(name), name_(name),
axis_(coordFormatNames[axis]), distance_(dist),
curveDist_(curveDist) axis_(coordFormatNames[axis])
{ {
checkDimensions(); checkDimensions();
} }
@ -109,13 +118,13 @@ Foam::coordSet::coordSet
const word& name, const word& name,
const word& axis, const word& axis,
List<point>&& points, List<point>&& points,
scalarList&& curveDist scalarList&& dist
) )
: :
pointField(std::move(points)), pointField(std::move(points)),
name_(name), name_(name),
axis_(coordFormatNames[axis]), distance_(std::move(dist)),
curveDist_(std::move(curveDist)) axis_(coordFormatNames.get(axis))
{ {
checkDimensions(); checkDimensions();
} }
@ -123,7 +132,7 @@ Foam::coordSet::coordSet
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::coordSet::hasVectorAxis() const bool Foam::coordSet::hasVectorAxis() const noexcept
{ {
return axis_ == coordFormat::XYZ; return axis_ == coordFormat::XYZ;
} }
@ -131,72 +140,105 @@ bool Foam::coordSet::hasVectorAxis() const
Foam::scalar Foam::coordSet::scalarCoord(const label index) const Foam::scalar Foam::coordSet::scalarCoord(const label index) const
{ {
const point& p = operator[](index);
switch (axis_) switch (axis_)
{ {
case coordFormat::X: case coordFormat::X:
{ {
return p.x(); return points()[index].x();
} }
case coordFormat::Y: case coordFormat::Y:
{ {
return p.y(); return points()[index].y();
} }
case coordFormat::Z: case coordFormat::Z:
{ {
return p.z(); return points()[index].z();
}
case coordFormat::RADIUS:
{
return mag(points()[index]);
} }
case coordFormat::DISTANCE: case coordFormat::DISTANCE:
{ {
// Note: If this has been constructed from the 'name' and 'axis' // Note: the distance will unset it constructed from
// constructor the curveDist list will not have been set // 'name' and 'axis' only
if (curveDist_.empty()) if (distance().empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Axis type '" << coordFormatNames[axis_] << "Axis type '" << coordFormatNames[axis_]
<< "' requested but curve distance has not been set" << "' requested but curve distance has not been set"
<< abort(FatalError); << abort(FatalError);
} }
return distance()[index];
return curveDist_[index];
} }
default: default:
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Illegal axis specification '" << coordFormatNames[axis_] << "Illegal axis specification '" << coordFormatNames[axis_]
<< "' for sampling line " << name_ << "' for sampling " << name_
<< exit(FatalError); << exit(FatalError);
}
}
return 0; return 0;
} }
}
}
Foam::point Foam::coordSet::vectorCoord(const label index) const const Foam::point& Foam::coordSet::vectorCoord(const label index) const
{ {
const point& p = operator[](index); return points()[index];
return p;
} }
Foam::Ostream& Foam::coordSet::write(Ostream& os) const Foam::Ostream& Foam::coordSet::write(Ostream& os) const
{ {
os << "name:" << name_ << " axis:" << coordFormatNames[axis_] os << "name:" << name_ << " axis:" << coordFormatNames[axis_] << nl
<< nl << nl
<< nl << "\t(coord)" << "\t(coord)" << nl;
<< endl;
for (const point& pt : *this) for (const point& p : *this)
{ {
os << '\t' << pt << endl; os << '\t' << p << nl;
} }
return os; return os;
} }
Foam::autoPtr<Foam::coordSet> Foam::coordSet::gatherSort
(
labelList& sortOrder
) const
{
// Combine sampleSet from processors. Sort by distance.
// Return ordering in indexSet.
// Note: only master results are valid
List<point> allPoints(globalIndex::gatherOp(points()));
List<scalar> allDistance(globalIndex::gatherOp(distance()));
if (Pstream::master() && allDistance.empty())
{
WarningInFunction
<< "Gathered empty coordSet: " << name() << endl;
}
// Sort according to distance
Foam::sortedOrder(allDistance, sortOrder); // uses stable sort
// Repopulate gathered points/distances in the correct order
allPoints = List<point>(allPoints, sortOrder);
allDistance = List<scalar>(allDistance, sortOrder);
return autoPtr<coordSet>::New
(
name(),
axis(),
std::move(allPoints),
std::move(allDistance)
);
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation Copyright (C) 2011-2012 OpenFOAM Foundation
Copyright (C) 2017-2018 OpenCFD Ltd. Copyright (C) 2017-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -35,11 +35,11 @@ SourceFiles
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef coordSet_H #ifndef Foam_coordSet_H
#define coordSet_H #define Foam_coordSet_H
#include "pointField.H" #include "pointField.H"
#include "word.H" #include "scalarList.H"
#include "Enum.H" #include "Enum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -57,49 +57,55 @@ class coordSet
{ {
public: public:
// Public data types // Public Data Types
//- Enumeration defining the output format for coordinates //- Enumeration defining the output format for coordinates
enum class coordFormat enum class coordFormat
{ {
XYZ, X, //!< Use 'x' component of points for (scalar) axis
X, Y, //!< Use 'y' component of points for (scalar) axis
Y, Z, //!< Use 'z' component of points for (scalar) axis
Z, RADIUS, //!< Use mag of points for (scalar) axis
DISTANCE DISTANCE, //!< Use additional distance field for (scalar) axis
XYZ, //!< Use x,y,z point values
/// DEFAULT
}; };
//- String representation of coordFormat enum //- String representation of coordFormat enum
static const Enum<coordFormat> coordFormatNames; static const Enum<coordFormat> coordFormatNames;
private:
//- Check for consistent dimensions of points and curve distance
void checkDimensions() const;
protected: protected:
// Protected Data
//- Name //- Name
const word name_; word name_;
//- Axis write type //- Cumulative distance for "distance" write specifier.
const coordFormat axis_; scalarList distance_;
//- Cumulative distance "distance" write specifier. //- Axis type
scalarList curveDist_; coordFormat axis_;
// Protected Member Functions
//- Check for consistent dimensions of points and curve distance
void checkDimensions() const;
public: public:
// Constructors // Constructors
//- Construct from components /// //- Default construct
// Note: curveDist will be empty /// coordSet();
//- Default construct with name and axis type
coordSet(const word& name, const coordFormat axisType); coordSet(const word& name, const coordFormat axisType);
//- Construct from components //- Default construct with name and axis type
// Note: curveDist will be empty
coordSet(const word& name, const word& axis); coordSet(const word& name, const word& axis);
//- Copy construct from components //- Copy construct from components
@ -108,7 +114,7 @@ public:
const word& name, const word& name,
const word& axis, const word& axis,
const List<point>& points, const List<point>& points,
const scalarList& curveDist const scalarList& dist
); );
//- Move construct from components //- Move construct from components
@ -117,66 +123,116 @@ public:
const word& name, const word& name,
const word& axis, const word& axis,
List<point>&& points, List<point>&& points,
scalarList&& curveDist scalarList&& dist
); );
// Member functions // Member Functions
const word& name() const // Access
//- The coord-set name
const word& name() const noexcept
{ {
return name_; return name_;
} }
word axis() const //- The sort axis name
const word& axis() const
{ {
return coordFormatNames[axis_]; return coordFormatNames[axis_];
} }
//- Set the points //- Return the points
const pointField& points() const noexcept
{
return static_cast<const pointField&>(*this);
}
//- Return the cumulative distance
const scalarList& distance() const noexcept
{
return distance_;
}
//- Return the number of points
label nPoints() const noexcept
{
return pointField::size();
}
// Edit
//- Rename the coordinate set
void rename(const word& newName)
{
name_ = newName;
}
//- Copy assign new points
void setPoints(const List<point>& newPoints) void setPoints(const List<point>& newPoints)
{ {
static_cast<pointField&>(*this) = newPoints; static_cast<pointField&>(*this) = newPoints;
} }
//- Set the points //- Move assign new points
void setPoints(List<point>&& newPoints) void setPoints(List<point>&& newPoints)
{ {
static_cast<pointField&>(*this) = std::move(newPoints); static_cast<pointField&>(*this) = std::move(newPoints);
} }
//- Return the cumulative distance //- Copy assign the cumulative distance
const scalarList& curveDist() const void setDistance(const scalarList& dist, const bool check=true)
{ {
return curveDist_; distance_ = dist;
if (check) checkDimensions();
} }
//- Set the cumulative distance //- Move assign the cumulative distance
void setCurveDist(const scalarList& curveDist) void setDistance(scalarList&& dist, const bool check=true)
{ {
curveDist_ = curveDist; distance_ = std::move(dist);
checkDimensions(); if (check) checkDimensions();
} }
//- Set the cumulative distance
void setCurveDist(scalarList&& curveDist)
{
curveDist_ = std::move(curveDist);
checkDimensions();
}
//- Is axis specification a vector // Output-related
bool hasVectorAxis() const;
//- True if axis specification is a vector
bool hasVectorAxis() const noexcept;
//- Get coordinate of point according to axis specification. //- Get coordinate of point according to axis specification.
// If axis="distance" is the curveDist[index] // If axis="distance" is the distance[index]
scalar scalarCoord(const label index) const; scalar scalarCoord(const label index) const;
//- Get point according to axis="xyz" specification //- Get point according to axis="xyz" specification
vector vectorCoord(const label index) const; const vector& vectorCoord(const label index) const;
//- Write to stream //- Write to stream
Ostream& write(Ostream& os) const; Ostream& write(Ostream& os) const;
// Other
//- Gather and sort.
// \return (on master) gathered set and overall sort order
autoPtr<coordSet> gatherSort(labelList& sortOrder) const;
// Housekeeping
//- Return the cumulative distance
const scalarList& curveDist() const noexcept
{
return distance_;
}
//- Copy assign the cumulative distance
void setCurveDist(const scalarList& dist)
{
setDistance(dist);
}
}; };

View File

@ -0,0 +1,455 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "coordSet.H"
#include "coordSetWriter.H"
#include "Time.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(coordSetWriter, 0);
defineRunTimeSelectionTable(coordSetWriter, word);
defineRunTimeSelectionTable(coordSetWriter, wordDict);
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::word Foam::coordSetWriter::suffix
(
const word& fldName,
const word& fileExt
)
{
word result;
if (!fldName.empty())
{
result += '_' + fldName;
}
return result.ext(fileExt);
}
Foam::word Foam::coordSetWriter::suffix
(
const wordList& fieldNames,
const word& fileExt
)
{
word result;
for (const word& fldName : fieldNames)
{
if (!fldName.empty())
{
result += '_' + fldName;
}
}
return result.ext(fileExt);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::coordSetWriter::coordSetWriter()
:
coords_(),
trackTimes_(),
upToDate_(false),
wroteGeom_(false),
/// parallel_(true),
buffering_(false),
useTracks_(false),
useTimeDir_(false),
verbose_(false),
nFields_(0),
currTime_(),
outputPath_()
{}
Foam::coordSetWriter::coordSetWriter(const dictionary& options)
:
coordSetWriter()
{
options.readIfPresent("verbose", verbose_);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coordSetWriter::~coordSetWriter()
{
close();
}
// * * * * * * * * * * * * * * * * * Controls * * * * * * * * * * * * * * * //
void Foam::coordSetWriter::setTime(const instant& inst)
{
currTime_ = inst;
}
void Foam::coordSetWriter::setTime(scalar timeValue)
{
currTime_ = instant(timeValue);
}
void Foam::coordSetWriter::setTime(scalar timeValue, const word& timeName)
{
currTime_.value() = timeValue;
currTime_.name() = timeName;
}
void Foam::coordSetWriter::unsetTime()
{
currTime_.value() = 0;
currTime_.name().clear();
}
void Foam::coordSetWriter::beginTime(const Time& t)
{
setTime(t.value(), t.timeName());
}
void Foam::coordSetWriter::beginTime(const instant& inst)
{
setTime(inst);
}
void Foam::coordSetWriter::endTime()
{
// Flush bufferred data
if (nDataColumns())
{
writeBuffered();
}
clearBuffers();
unsetTime();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::coordSetWriter::open(const fileName& outputPath)
{
outputPath_ = outputPath;
wroteGeom_ = false;
}
void Foam::coordSetWriter::open
(
const coordSet& coords,
const fileName& outputPath
)
{
close();
setCoordinates(coords);
open(outputPath);
}
void Foam::coordSetWriter::open
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath
)
{
close();
setTracks(tracks);
open(outputPath);
}
void Foam::coordSetWriter::close(bool force)
{
if (nDataColumns())
{
if (verbose_) Info<< "Flush buffered data:" << nl;
writeBuffered();
}
clearBuffers();
outputPath_.clear();
wroteGeom_ = false;
if (force)
{
coords_.clear();
trackTimes_.clear();
}
}
void Foam::coordSetWriter::clear()
{
close();
expire();
coords_.clear();
trackTimes_.clear();
clearBuffers(); // Reset any buffering
}
void Foam::coordSetWriter::setCoordinates(const coordSet* coords)
{
expire();
clearBuffers(); // Reset any buffering
if (coords)
{
coords_.resize(1);
coords_.set(0, coords);
}
else
{
coords_.clear();
}
trackTimes_.clear();
}
void Foam::coordSetWriter::setCoordinates(const coordSet& coords)
{
setCoordinates(&coords);
}
void Foam::coordSetWriter::setTracks(const UPtrList<coordSet>& tracks)
{
expire();
clearBuffers(); // Reset any buffering
// Shallow copy (pointers)
coords_.resize(tracks.size());
forAll(coords_, tracki)
{
coords_.set(tracki, tracks.get(tracki));
}
trackTimes_.clear();
useTracks_ = true;
}
void Foam::coordSetWriter::setTrackTimes(const UList<scalarField>& times)
{
if (times.size() == coords_.size())
{
trackTimes_ = times;
}
else
{
trackTimes_.clear();
}
}
Foam::label Foam::coordSetWriter::numPoints() const
{
label nTotal = 0;
forAll(coords_, tracki)
{
const auto* ptr = coords_.get(tracki);
if (ptr) nTotal += ptr->size();
}
return nTotal;
}
Foam::label Foam::coordSetWriter::numTracks() const
{
return coords_.size();
}
bool Foam::coordSetWriter::needsUpdate() const
{
return !upToDate_;
}
bool Foam::coordSetWriter::wroteData() const
{
return wroteGeom_;
}
bool Foam::coordSetWriter::expire()
{
const bool changed = upToDate_;
upToDate_ = false;
wroteGeom_ = false;
coords_.clear();
trackTimes_.clear();
// Field count (nFields_) is a different type of accounting
// and is unaffected by geometry changes
return changed;
}
bool Foam::coordSetWriter::hasCoords() const
{
return !coords_.empty();
}
bool Foam::coordSetWriter::empty() const
{
return coords_.empty();
}
Foam::fileName Foam::coordSetWriter::getExpectedPath
(
const word& fileExt
) const
{
fileName file;
if (!outputPath_.empty())
{
if (useTimeDir() && !timeName().empty())
{
// Splice in time-directory
file = outputPath_.path() / timeName() / outputPath_.name();
}
else
{
file = outputPath_;
}
file.ext(fileExt); // Append extension - can also be empty
}
return file;
}
Foam::fileName Foam::coordSetWriter::getFieldPrefixedPath
(
const word& fieldName,
const word& fileExt
) const
{
if (outputPath_.empty() || fieldName.empty())
{
return getExpectedPath(fileExt);
}
// Field: rootdir/<TIME>/<field>_NAME.ext
fileName file;
if (useTimeDir() && !timeName().empty())
{
// Splice in time-directory
file = outputPath_.path() / timeName();
}
else
{
file = outputPath_.path();
}
// Append <field>_NAME.EXT
file /= (fieldName + '_' + outputPath_.name());
file.ext(fileExt); // Append extension - can also be empty
return file;
}
void Foam::coordSetWriter::checkOpen() const
{
if (!is_open())
{
FatalErrorInFunction
<< type() << " : Attempted to write without a path" << nl
<< exit(FatalError);
}
}
bool Foam::coordSetWriter::merge() const
{
bool changed = false;
// Possible future requirement...
//
// if (parallel_ && Pstream::parRun() && !upToDate_)
// {
// changed = merged_.merge(coords_, mergeDim_);
// }
upToDate_ = true;
if (changed)
{
wroteGeom_ = false;
}
return changed;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<
(
Ostream& os,
const InfoProxy<coordSetWriter>& ip
)
{
const coordSetWriter& w = ip.t_;
os << "coordSetWriter:"
<< " upToDate: " << w.upToDate_
<< " nFields: " << w.nFields_
<< " time: " << w.currTime_
<< " path: " << w.outputPath_ << endl;
return os;
}
// ************************************************************************* //

View File

@ -0,0 +1,597 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::coordSetWriter
Description
Base class for writing coordSet(s) and tracks with fields.
Example:
\verbatim
coordSet coords(...);
// Construct writer of xmgr type
autoPtr<coordSetWriter> writer(coordSetWriter::New("vtk"));
writer.open(coords, path/name);
writer.write("density", rho);
writer.write("velocity", U);
\endverbatim
SourceFiles
coordSetWriterI.H
coordSetWriter.C
coordSetWriterBuffers.C
coordSetWriterNew.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriter_H
#define Foam_coordSetWriter_H
#include "coordSet.H"
#include "typeInfo.H"
#include "vector.H"
#include "tensor.H"
#include "fileName.H"
#include "wordList.H"
#include "Field.H"
#include "DynamicList.H"
#include "PtrDynList.H"
#include "UPtrList.H"
#include "instant.H"
#include "InfoProxy.H"
#include "runTimeSelectionTables.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class coordSetWriter;
class Time;
Ostream& operator<<(Ostream& os, const InfoProxy<coordSetWriter>&);
/*---------------------------------------------------------------------------*\
Class coordSetWriter Declaration
\*---------------------------------------------------------------------------*/
class coordSetWriter
{
protected:
// Protected Data
//- Reference to coordinate set(s)
UPtrList<const coordSet> coords_;
//- Track times (eg, streamlines), one per coords_ entry
List<scalarField> trackTimes_;
//- The content is up-to-date?
mutable bool upToDate_;
//- Track if geometry has been written since the last open
mutable bool wroteGeom_;
/// //- Writing in parallel (via master)
/// bool parallel_;
//- Writer with buffering output
mutable bool buffering_;
//- Prefer tracks to points during single set writing
bool useTracks_;
//- Insert additional time sub-directory in the output path
bool useTimeDir_;
//- Additional output verbosity
bool verbose_;
//- The number of fields
label nFields_;
//- The current time value/name
instant currTime_;
//- The full output directory and file (coords) name
fileName outputPath_;
// Buffering
#undef defineBufferMethod
#define defineBufferMethod(Type) \
\
/* Names of Type fields */ \
DynamicList<word> Type##Names_; \
\
/* Values of Type fields */ \
PtrDynList<Field<Type>> Type##Fields_; \
\
/* Add named Type field to buffering */ \
void appendField(const word& fieldName, const Field<Type>& vals) \
{ \
Type##Names_.append(fieldName); \
Type##Fields_.append(vals.clone()); \
}
defineBufferMethod(label);
defineBufferMethod(scalar);
defineBufferMethod(vector);
defineBufferMethod(sphericalTensor);
defineBufferMethod(symmTensor);
defineBufferMethod(tensor);
#undef defineBufferMethod
// Protected Member Functions
// Buffering
//- Write line contents (eg, buffered)
static void writeLine(Ostream&, const UList<word>&, const char* sep);
//- Write line contents (eg, buffered)
static void writeLine(Ostream&, const UList<scalar>&, const char* sep);
//- Clear out buffering
void clearBuffers();
//- The number of buffer data columns, after splitting into components
label nDataColumns() const;
//- Write buffered data
virtual bool writeBuffered();
//- Write buffered data
void writeBufferContents
(
Ostream& os,
const coordSet& coords,
const char* sep
) const;
//- Get buffered data line (components)
void getBufferLine
(
DynamicList<scalar>& buf,
const coordSet& coords,
const label pointi
) const;
// File Operations
//- Get expected (characteristic) output file name - information only
fileName getExpectedPath(const word& fileExt = word::null) const;
//- Get field-prefixed output file name.
// Eg, dir/U_name.raw
fileName getFieldPrefixedPath
(
const word& fieldName,
const word& fileExt = word::null
) const;
//- Verify that the outputPath_ has been set or FatalError
void checkOpen() const;
//- Perform any merging if not already upToDate (parallel)
//- or simply mark as being up-to-date
virtual bool merge() const;
// Helpers
//- Repackage field into a UPtrList
template<class Type>
static UPtrList<const Field<Type>>
repackageFields
(
const Field<Type>& field
);
//- Repackage multiple fields into a UPtrList
template<class Type>
static UPtrList<const Field<Type>>
repackageFields
(
const UList<Field<Type>>& fieldValues
);
//- Write coordinates and values
template<class Type>
static void writeTable
(
Ostream& os,
const coordSet& coords,
const UList<Type>& values,
const char* sep
);
// Normal write templates
//- Dummy templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName, //!< Name of field
const Field<Type>& values //!< Local field values to write
)
{
/// if (!wroteGeom_)
/// {
/// return this->write();
/// }
return fileName::null;
}
//- Dummy templated write operation. Multiple tracks
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
)
{
return fileName::null;
}
//- No copy construct
coordSetWriter(const coordSetWriter&) = delete;
//- No copy assignment
void operator=(const coordSetWriter&) = delete;
public:
//- Runtime type information
TypeName("coordSetWriter");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
coordSetWriter,
word,
(),
()
);
declareRunTimeSelectionTable
(
autoPtr,
coordSetWriter,
wordDict,
(
const dictionary& writeOptions
),
(writeOptions)
);
// Selectors
//- True if New is likely to succeed for this writeType
static bool supportedType(const word& writeType);
//- Return a reference to the selected writer
static autoPtr<coordSetWriter> New(const word& writeFormat);
//- Return a reference to the selected writer
// Select with extra write option
static autoPtr<coordSetWriter> New
(
const word& writeFormat,
const dictionary& writeOptions
);
// Constructors
//- Default construct
coordSetWriter();
//- Default construct with specified options
explicit coordSetWriter(const dictionary& options);
//- Destructor. Calls close()
virtual ~coordSetWriter();
// Member Functions
// Helpers
//- Name suffix based on fieldName (underscore separator)
static word suffix
(
const word& fldName,
const word& fileExt = word::null
);
//- Name suffix based on fieldNames (underscore separator)
static word suffix
(
const wordList& fieldNames,
const word& fileExt = word::null
);
// Capability
//- True if the format uses internal buffering (eg, column output)
virtual bool buffering() const;
//- Turn internal buffering on/off (only if supported by the writer)
virtual bool buffering(const bool on);
//- The writer is enabled. If the writer is not enabled, it may be
//- possible for the caller to skip various preparatory operations.
// This method is primarily useful for the null writer
virtual bool enabled() const
{
return true;
}
// Bookkeeping
//- Does the writer need an update (eg, lagging behind other changes)
virtual bool needsUpdate() const;
//- Geometry or fields written since the last open?
virtual bool wroteData() const;
//- Mark that content changed and the writer will need an update,
//- and set nFields = 0.
// May also free up unneeded data.
// Return false if it was previously already expired.
virtual bool expire();
//- Close any open output, remove coordSet associations and
//- expire the writer.
virtual void clear();
// Content Association
//- Set coordinates, can also be nullptr
virtual void setCoordinates(const coordSet* coords);
//- Set coordinates
virtual void setCoordinates(const coordSet& coords);
//- Set track coordinates
virtual void setTracks(const UPtrList<coordSet>& tracks);
//- Set track times
virtual void setTrackTimes(const UList<scalarField>& times);
// Queries, Access
//- The number of associated points (local processor)
label numPoints() const;
//- The number of coordinate tracks
label numTracks() const;
//- Writer is associated with content
bool hasCoords() const;
//- Writer is not associated with content
bool empty() const;
//- Test if outputPath has been set
inline bool is_open() const noexcept;
//- The number of expected output fields.
// Currently only used by the legacy VTK format.
inline label nFields() const noexcept;
//- Set the number of expected output fields
// Currently only used by the legacy VTK format.
// \return old value
inline label nFields(const label n) noexcept;
//- Prefer tracks to points during single set writing
inline bool useTracks() const noexcept;
//- Enable/disable tracks preference
// \return old value
inline bool useTracks(const bool on) noexcept;
//- Should a time directory be spliced into the output path?
inline bool useTimeDir() const noexcept;
//- Enable/disable use of spliced output path
// \return old value
inline bool useTimeDir(const bool on) noexcept;
//- Get output verbosity
inline bool verbose() const noexcept;
//- Enable/disable verbose output
// \return old value
inline bool verbose(bool on) noexcept;
// Time
//- True if there is a known time
inline bool hasTime() const;
//- The current time value/name
inline const word& timeName() const;
//- The current time value/name
inline scalar timeValue() const;
//- Set the current time
void setTime(const instant& inst);
//- Set current time from timeValue, auto generating the name
void setTime(scalar timeValue);
//- Set current time from timeValue and timeName
void setTime(scalar timeValue, const word& timeName);
//- Clear the current time
void unsetTime();
//- Begin a time-step
virtual void beginTime(const Time& t);
//- Begin a time-step
virtual void beginTime(const instant& inst);
//- End a time-step
virtual void endTime();
// Output
//- Expected (characteristic) output file name - information only.
//- Return empty when is_open() is false.
virtual fileName path() const = 0;
//- Write separate geometry to file.
/// TBD: virtual fileName write() = 0;
//- Open for output on specified path, using existing content
virtual void open(const fileName& outputPath);
//- Open from components
virtual void open
(
const coordSet& coords,
const fileName& outputPath
);
//- Open from components
virtual void open
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath
);
//- Finish output, performing any necessary cleanup
// Optional force disassociation with any coordSet(s)
virtual void close(bool force = false);
// Other
//- Return info proxy.
virtual InfoProxy<coordSetWriter> info() const
{
return *this;
}
//- Output info proxy
friend Ostream& operator<<
(
Ostream& os,
const InfoProxy<coordSetWriter>& ip
);
// Write methods
#undef declareCoordSetWriterWriteMethod
#define declareCoordSetWriterWriteMethod(Type) \
\
/*! \brief Write field of Type (point data) */ \
virtual fileName write \
( \
const word& fieldName, /*!< Name of field */ \
const Field<Type>& field /*!< Field values */ \
) = 0; \
\
/*! \brief Write track fields of Type (point data) */ \
virtual fileName write \
( \
const word& fieldName, /*!< Name of field */ \
const List<Field<Type>>& fieldValues /*!< Per-track values */ \
) = 0;
declareCoordSetWriterWriteMethod(label);
declareCoordSetWriterWriteMethod(scalar);
declareCoordSetWriterWriteMethod(vector);
declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
#undef declareCoordSetWriterWriteMethod
#define declareCoordSetWriterWriteMethod(Type) \
\
/*! \brief Write field of Type (point data) */ \
virtual fileName write \
( \
const word& fieldName, /*!< Name of field */ \
const Field<Type>& values /*!< Field values */ \
); /* override */ \
\
/*! \brief Write track fields of Type (point data) */ \
virtual fileName write \
( \
const word& fieldName, /*!< Name of field */ \
const List<Field<Type>>& fieldValues /*!< Per-track values */ \
); /* override */
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "coordSetWriterI.H"
#ifdef NoRepository
#include "coordSetWriterTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,197 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "coordSetWriter.H"
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::coordSetWriter::writeLine
(
Ostream& os,
const UList<word>& values,
const char* sep
)
{
if (!values.empty())
{
forAll(values, coli)
{
if (coli && sep) os << sep;
os << values[coli];
}
os << nl;
}
}
void Foam::coordSetWriter::writeLine
(
Ostream& os,
const UList<scalar>& values,
const char* sep
)
{
if (!values.empty())
{
forAll(values, coli)
{
if (coli && sep) os << sep;
os << values[coli];
}
os << nl;
}
}
void Foam::coordSetWriter::clearBuffers()
{
#undef doLocalCode
#define doLocalCode(Type) \
{ \
Type##Names_.clear(); \
Type##Fields_.clear(); \
}
doLocalCode(label);
doLocalCode(scalar);
doLocalCode(vector);
doLocalCode(sphericalTensor);
doLocalCode(symmTensor);
doLocalCode(tensor);
#undef doLocalCode
}
Foam::label Foam::coordSetWriter::nDataColumns() const
{
label ncol = 0;
#undef doLocalCode
#define doLocalCode(Type) \
ncol += (Type##Fields_.size() * pTraits<Type>::nComponents);
doLocalCode(label);
doLocalCode(scalar);
doLocalCode(vector);
doLocalCode(sphericalTensor);
doLocalCode(symmTensor);
doLocalCode(tensor);
#undef doLocalCode
return ncol;
}
void Foam::coordSetWriter::getBufferLine
(
DynamicList<scalar>& buf,
const coordSet& coords,
const label pointi
) const
{
buf.clear();
if (coords.hasVectorAxis())
{
const vector& p = coords.vectorCoord(pointi);
buf.append(p.x());
buf.append(p.y());
buf.append(p.z());
}
else
{
buf.append(coords.scalarCoord(pointi));
}
do
{
#undef doLocalCode
#define doLocalCode(Type) \
\
for (const auto& fld : Type##Fields_) \
{ \
const auto& val = fld[pointi]; \
for (direction d=0; d < pTraits<Type>::nComponents; ++d) \
{ \
buf.append(component(val, d)); \
} \
}
doLocalCode(label);
doLocalCode(scalar);
doLocalCode(vector);
doLocalCode(sphericalTensor);
doLocalCode(symmTensor);
doLocalCode(tensor);
#undef doLocalCode
}
while (false);
}
bool Foam::coordSetWriter::writeBuffered()
{
return false;
}
void Foam::coordSetWriter::writeBufferContents
(
Ostream& os,
const coordSet& coords,
const char* sep
) const
{
const label npts = coords.size();
const label ncomp = nDataColumns();
DynamicList<scalar> compCols(3 + ncomp);
for (label pointi = 0; pointi < npts; ++pointi)
{
getBufferLine(compCols, coords, pointi);
writeLine(os, compCols, sep);
}
}
// * * * * * * * * * * * * * * * * * Controls * * * * * * * * * * * * * * * //
bool Foam::coordSetWriter::buffering() const
{
return buffering_;
}
// disabled
bool Foam::coordSetWriter::buffering(const bool)
{
return buffering_;
}
// ************************************************************************* //

View File

@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool Foam::coordSetWriter::is_open() const noexcept
{
return !outputPath_.empty();
}
inline Foam::label Foam::coordSetWriter::nFields() const noexcept
{
return nFields_;
}
inline Foam::label Foam::coordSetWriter::nFields(const label n) noexcept
{
label old(nFields_);
nFields_ = n;
return old;
}
inline bool Foam::coordSetWriter::useTracks() const noexcept
{
return useTracks_;
}
inline bool Foam::coordSetWriter::useTracks(const bool on) noexcept
{
bool old(useTracks_);
useTracks_ = on;
return old;
}
inline bool Foam::coordSetWriter::useTimeDir() const noexcept
{
return useTimeDir_;
}
inline bool Foam::coordSetWriter::useTimeDir(const bool on) noexcept
{
bool old(useTimeDir_);
useTimeDir_ = on;
return old;
}
inline bool Foam::coordSetWriter::verbose() const noexcept
{
return verbose_;
}
inline bool Foam::coordSetWriter::verbose(bool on) noexcept
{
bool old(verbose_);
verbose_ = on;
return old;
}
inline bool Foam::coordSetWriter::hasTime() const
{
return currTime_.name().size();
}
inline const Foam::word& Foam::coordSetWriter::timeName() const
{
return currTime_.name();
}
inline Foam::scalar Foam::coordSetWriter::timeValue() const
{
return currTime_.name().empty() ? 0 : currTime_.value();
}
// ************************************************************************* //

View File

@ -0,0 +1,81 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
InClass
Foam::coordSetWriterMethods
Description
Convenience macros for instantiating coordSetWriter methods.
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriterMethods_H
#define Foam_coordSetWriterMethods_H
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Instantiate templated method for standard types
#define defineCoordSetWriterWriteField(ThisClass, ValueType) \
\
Foam::fileName ThisClass::write \
( \
const word& fieldName, \
const Field<ValueType>& values \
) \
{ \
return writeTemplate(fieldName, values); \
} \
\
Foam::fileName ThisClass::write \
( \
const word& fieldName, \
const List<Field<ValueType>>& fieldValues \
) \
{ \
return writeTemplate(fieldName, fieldValues); \
}
#define defineCoordSetWriterWriteFields(ThisClass) \
defineCoordSetWriterWriteField(ThisClass, label); \
defineCoordSetWriterWriteField(ThisClass, scalar); \
defineCoordSetWriterWriteField(ThisClass, vector); \
defineCoordSetWriterWriteField(ThisClass, sphericalTensor); \
defineCoordSetWriterWriteField(ThisClass, symmTensor); \
defineCoordSetWriterWriteField(ThisClass, tensor)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,98 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "coordSet.H"
#include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
bool Foam::coordSetWriter::supportedType(const word& writeType)
{
return
(
wordConstructorTablePtr_->found(writeType)
|| wordDictConstructorTablePtr_->found(writeType)
);
}
Foam::autoPtr<Foam::coordSetWriter> Foam::coordSetWriter::New
(
const word& writeType
)
{
auto* ctorPtr = wordConstructorTable(writeType);
if (!ctorPtr)
{
FatalErrorInLookup
(
"setWriter",
writeType,
*wordConstructorTablePtr_
) << exit(FatalError);
}
return autoPtr<coordSetWriter>(ctorPtr());
}
Foam::autoPtr<Foam::coordSetWriter> Foam::coordSetWriter::New
(
const word& writeType,
const dictionary& writeOpts
)
{
// Constructors with dictionary options
{
auto* ctorPtr = wordDictConstructorTable(writeType);
if (ctorPtr)
{
return autoPtr<coordSetWriter>(ctorPtr(writeOpts));
}
}
// Constructors without dictionary options
auto* ctorPtr = wordConstructorTable(writeType);
if (!ctorPtr)
{
FatalErrorInLookup
(
"setWriter",
writeType,
*wordConstructorTablePtr_
) << exit(FatalError);
}
return autoPtr<coordSetWriter>(ctorPtr());
}
// ************************************************************************* //

View File

@ -5,8 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation Copyright (C) 2022 OpenCFD Ltd.
Copyright (C) 2019 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,49 +25,63 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "regionSizeDistribution.H" // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
#include "regionSplit.H"
#include "volFields.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> template<class Type>
Foam::Map<Type> Foam::functionObjects::regionSizeDistribution::regionSum Foam::UPtrList<const Foam::Field<Type>>
( Foam::coordSetWriter::repackageFields(const Field<Type>& field)
const regionSplit& regions,
const Field<Type>& fld
) const
{ {
// Per region the sum of fld UPtrList<const Field<Type>> fieldPtrs(1);
Map<Type> regionToSum(regions.nRegions()/Pstream::nProcs()); fieldPtrs.set(0, &field);
forAll(fld, celli) return fieldPtrs;
{
const label regioni = regions[celli];
regionToSum(regioni, Type(Zero)) += fld[celli];
}
Pstream::mapCombineGather(regionToSum, plusEqOp<Type>());
Pstream::mapCombineScatter(regionToSum);
return regionToSum;
} }
template<class Type> template<class Type>
Foam::List<Type> Foam::functionObjects::regionSizeDistribution::extractData Foam::UPtrList<const Foam::Field<Type>>
( Foam::coordSetWriter::repackageFields(const UList<Field<Type>>& fieldValues)
const labelUList& keys,
const Map<Type>& regionData
) const
{ {
List<Type> sortedData(keys.size()); UPtrList<const Field<Type>> fieldPtrs(fieldValues.size());
forAll(fieldValues, i)
forAll(keys, i)
{ {
sortedData[i] = regionData[keys[i]]; fieldPtrs.set(i, &(fieldValues[i]));
}
return fieldPtrs;
}
template<class Type>
void Foam::coordSetWriter::writeTable
(
Ostream& os,
const coordSet& coords,
const UList<Type>& values,
const char* sep
)
{
forAll(coords, pointi)
{
// Output coordinate (point or scalar) with separator
if (coords.hasVectorAxis())
{
const vector& p = coords.vectorCoord(pointi);
os << p.x() << sep << p.y() << sep << p.z();
}
else
{
os << coords.scalarCoord(pointi);
}
// Output component values with separator
const auto& val = values[pointi];
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
os << sep << component(val, d);
}
os << nl;
} }
return sortedData;
} }

View File

@ -1,280 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "writer.H"
#include "coordSet.H"
#include "OFstream.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
template<class Type>
Foam::autoPtr<Foam::writer<Type>> Foam::writer<Type>::New
(
const word& writeType
)
{
auto* ctorPtr = wordConstructorTable(writeType);
if (!ctorPtr)
{
FatalErrorInLookup
(
"writer",
writeType,
*wordConstructorTablePtr_
) << exit(FatalError);
}
return autoPtr<writer<Type>>(ctorPtr());
}
template<class Type>
Foam::autoPtr<Foam::writer<Type>> Foam::writer<Type>::New
(
const word& writeType,
const dictionary& formatOptions
)
{
auto* ctorPtr = dictConstructorTable(writeType);
if (!ctorPtr)
{
FatalErrorInLookup
(
"writer",
writeType,
*dictConstructorTablePtr_
) << exit(FatalError);
}
return autoPtr<writer<Type>>(ctorPtr(formatOptions));
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::writer<Type>::getBaseName
(
const coordSet& points,
const wordList& valueSets
) const
{
fileName fName(points.name());
forAll(valueSets, i)
{
fName += '_' + valueSets[i];
}
return fName;
}
template<class Type>
void Foam::writer<Type>::writeCoord
(
const coordSet& points,
const label pointi,
Ostream& os
) const
{
if (points.hasVectorAxis())
{
write(points.vectorCoord(pointi), os);
}
else
{
write(points.scalarCoord(pointi), os);
}
}
template<class Type>
void Foam::writer<Type>::writeTable
(
const coordSet& points,
const List<Type>& values,
Ostream& os
) const
{
forAll(points, pointi)
{
writeCoord(points, pointi, os);
writeSeparator(os);
write(values[pointi], os);
os << nl;
}
}
template<class Type>
void Foam::writer<Type>::writeTable
(
const coordSet& points,
const List<const List<Type>*>& valuesPtrList,
Ostream& os
) const
{
forAll(points, pointi)
{
writeCoord(points, pointi, os);
forAll(valuesPtrList, i)
{
writeSeparator(os);
const List<Type>& values = *valuesPtrList[i];
write(values[pointi], os);
}
os << nl;
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type>
Foam::writer<Type>::writer()
{}
template<class Type>
Foam::writer<Type>::writer(const dictionary& dict)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
void Foam::writer<Type>::write
(
const coordSet& points,
const wordList& valueSetNames,
const List<Field<Type>>& valueSets,
Ostream& os
) const
{
List<const Field<Type>*> valueSetPtrs(valueSets.size());
forAll(valueSetPtrs, i)
{
valueSetPtrs[i] = &valueSets[i];
}
write(points, valueSetNames, valueSetPtrs, os);
}
template<class Type>
Foam::Ostream& Foam::writer<Type>::write
(
const scalar value,
Ostream& os
) const
{
return os << value;
}
template<class Type>
template<class VSType>
Foam::Ostream& Foam::writer<Type>::writeVS
(
const VSType& value,
Ostream& os
) const
{
for (direction d=0; d<VSType::nComponents; d++)
{
if (d > 0)
{
writeSeparator(os);
}
os << value.component(d);
}
return os;
}
template<class Type>
void Foam::writer<Type>::writeSeparator
(
Ostream& os
) const
{
os << token::SPACE << token::TAB;
}
template<class Type>
Foam::Ostream& Foam::writer<Type>::write
(
const vector& value,
Ostream& os
) const
{
return writeVS(value, os);
}
template<class Type>
Foam::Ostream& Foam::writer<Type>::write
(
const sphericalTensor& value,
Ostream& os
) const
{
return writeVS(value, os);
}
template<class Type>
Foam::Ostream& Foam::writer<Type>::write
(
const symmTensor& value,
Ostream& os
) const
{
return writeVS(value, os);
}
template<class Type>
Foam::Ostream& Foam::writer<Type>::write
(
const tensor& value,
Ostream& os
) const
{
return writeVS(value, os);
}
// ************************************************************************* //

View File

@ -1,244 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::writer
Description
Base class for graphics format writing. Entry points are
- write(..). \n
Write to an Ostream a table of points with corresponding values.
- write(scalar/vector/sphericalTensor/symmTensor/tensor). \n
Write single scalar/vector/sphericalTensor/symmTensor/tensor.
Default is to write space separated components.
Example:
\verbatim
// Construct writer of xmgr type
autoPtr<writer<scalar>> scalarFormatter(writer<scalar>::New("xmgr"));
// Output list of points and corresponding values
scalarFormatter().write
(
coordSet(...)
"U.component(0)", // name of values
vals // values
);
\endverbatim
SourceFiles
writer.C
\*---------------------------------------------------------------------------*/
#ifndef writer_H
#define writer_H
#include "fileName.H"
#include "wordList.H"
#include "vector.H"
#include "tensor.H"
#include "typeInfo.H"
#include "runTimeSelectionTables.H"
#include "autoPtr.H"
#include "Field.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class coordSet;
/*---------------------------------------------------------------------------*\
Class writer Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class writer
{
protected:
//- Generates filename from coordSet and sampled fields
fileName getBaseName(const coordSet&, const wordList&) const;
void writeCoord(const coordSet&, const label sampleI, Ostream&) const;
//- Writes single-column ascii write. Column 1 is coordSet coordinate,
// columns 2 is the value. Uses write() function
// to write coordinate in correct format.
void writeTable(const coordSet&, const List<Type>&, Ostream&) const;
//- Writes multi-column ascii write. Column 1 is coordSet coordinate,
// columns 2..n are the values. Uses write() function
// to write coordinate in correct format.
void writeTable
(
const coordSet&,
const List<const List<Type>*>&,
Ostream& os
) const;
//- Writes a separator. Used by write functions.
virtual void writeSeparator(Ostream& os) const;
public:
//- Runtime type information
TypeName("writer");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
writer,
word,
(),
()
);
declareRunTimeSelectionTable
(
autoPtr,
writer,
dict,
(
const dictionary& formatOptions
),
(formatOptions)
);
// Selectors
//- Return a reference to the selected writer
static autoPtr<writer> New(const word& writeFormat);
//- Return a reference to the selected writer
static autoPtr<writer> New
(
const word& writeFormat,
const dictionary& formatOptions
);
// Constructors
//- Default construct
writer();
//- Construct with dictionary
explicit writer(const dictionary& dict);
//- Destructor
virtual ~writer() = default;
// Member Functions
//- Generate file name with correct extension
virtual fileName getFileName
(
const coordSet&,
const wordList&
) const = 0;
//- General entry point for writing.
// The data is organized in a set of point with one or more values
// per point
virtual void write
(
const coordSet&,
const wordList&,
const List<const Field<Type>*>&,
Ostream&
) const = 0;
//- General entry point for writing.
// The data is organized in a set of point with one or more values
// per point
virtual void write
(
const coordSet&,
const wordList&,
const List<Field<Type>>&,
Ostream&
) const;
//- General entry point for writing of multiple coordSets.
// Each coordSet (track) has same data variables.
// The data is per variable, per track, per point of track.
// If writeTracks adds connecting lines (wherever applicable)
virtual void write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const = 0;
//- Write scalar as ascii
virtual Ostream& write(const scalar, Ostream&) const;
template<class VSType>
Ostream& writeVS(const VSType&, Ostream&) const;
//- Write vector. Tab separated ascii
virtual Ostream& write(const vector&, Ostream&) const;
//- Write sphericalTensor. Tab separated ascii
virtual Ostream& write(const sphericalTensor&, Ostream&) const;
//- Write symmTensor. Tab separated ascii
virtual Ostream& write(const symmTensor&, Ostream&) const;
//- Write tensor. Tab separated ascii
virtual Ostream& write(const tensor&, Ostream&) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "writer.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,53 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "writers.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
#define defineSetWriterType(dataType) \
defineNamedTemplateTypeNameAndDebug(writer<dataType >, 0); \
defineTemplatedRunTimeSelectionTable(writer, word, dataType); \
defineTemplatedRunTimeSelectionTable(writer, dict, dataType);
defineSetWriterType(scalar);
defineSetWriterType(vector);
defineSetWriterType(sphericalTensor);
defineSetWriterType(symmTensor);
defineSetWriterType(tensor);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -1,85 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
InClass
Foam::writer
SourceFiles
writers.C
\*---------------------------------------------------------------------------*/
#ifndef writers_H
#define writers_H
#include "writer.H"
#include "fieldTypes.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Only used internally
#define makeTypeSetWritersTypeName(typeWriter, dataType) \
\
defineNamedTemplateTypeNameAndDebug(typeWriter<dataType>, 0)
// Sometimes used externally
#define makeSetWritersTypeName(typeWriter) \
\
makeTypeSetWritersTypeName(typeWriter, scalar); \
makeTypeSetWritersTypeName(typeWriter, vector); \
makeTypeSetWritersTypeName(typeWriter, sphericalTensor); \
makeTypeSetWritersTypeName(typeWriter, symmTensor); \
makeTypeSetWritersTypeName(typeWriter, tensor)
// Define type info for single dataType template instantiation (eg, vector)
#define makeSetWriterType(typeWriter, dataType) \
\
defineNamedTemplateTypeNameAndDebug(typeWriter<dataType>, 0); \
addTemplatedToRunTimeSelectionTable \
( \
writer, typeWriter, dataType, word \
); \
addTemplatedToRunTimeSelectionTable \
( \
writer, typeWriter, dataType, dict \
);
// Define type info for scalar, vector etc. instantiations
#define makeSetWriters(typeWriter) \
\
makeSetWriterType(typeWriter, scalar); \
makeSetWriterType(typeWriter, vector); \
makeSetWriterType(typeWriter, sphericalTensor); \
makeSetWriterType(typeWriter, symmTensor); \
makeSetWriterType(typeWriter, tensor)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -5,8 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2022 OpenCFD Ltd.
Copyright (C) 2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,183 +25,242 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "csvSetWriter.H" #include "csvCoordSetWriter.H"
#include "coordSet.H" #include "coordSet.H"
#include "fileName.H" #include "fileName.H"
#include "OFstream.H" #include "OFstream.H"
#include "OSspecific.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
defineTypeName(csvWriter);
addToRunTimeSelectionTable(coordSetWriter, csvWriter, word);
addToRunTimeSelectionTable(coordSetWriter, csvWriter, wordDict);
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Implementation
#include "csvCoordSetWriterImpl.C"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type> Foam::coordSetWriters::csvWriter::csvWriter()
Foam::csvSetWriter<Type>::csvSetWriter()
: :
writer<Type>() coordSetWriter(),
{} streamOpt_(),
precision_(IOstream::defaultPrecision())
{
buffering_ = true;
}
template<class Type> Foam::coordSetWriters::csvWriter::csvWriter(const dictionary& options)
Foam::csvSetWriter<Type>::csvSetWriter(const dictionary& dict)
: :
writer<Type>(dict) coordSetWriter(options),
{} streamOpt_
(
IOstream::ASCII,
IOstream::compressionEnum("compression", options)
),
precision_
(
options.getOrDefault("precision", IOstream::defaultPrecision())
)
{
buffering_ = options.getOrDefault("buffer", true);
}
Foam::coordSetWriters::csvWriter::csvWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options
)
:
csvWriter(options)
{
open(coords, outputPath);
}
Foam::coordSetWriters::csvWriter::csvWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options
)
:
csvWriter(options)
{
open(tracks, outputPath);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coordSetWriters::csvWriter::~csvWriter()
{
close();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> bool Foam::coordSetWriters::csvWriter::buffering(const bool on)
Foam::fileName Foam::csvSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
{ {
return this->getBaseName(points, valueSetNames) + ".csv"; const bool old(buffering_);
buffering_ = on;
return old;
} }
template<class Type> Foam::fileName Foam::coordSetWriters::csvWriter::path() const
void Foam::csvSetWriter<Type>::write
(
const coordSet& points,
const wordList& valueSetNames,
const List<const Field<Type>*>& valueSets,
Ostream& os
) const
{ {
writeHeader(points,valueSetNames,os); // Assume !useTracks_, otherwise too fragile
// Collect sets into columns // 1) rootdir/<TIME>/setName.csv
List<const List<Type>*> columns(valueSets.size()); // 2) rootdir/setName.csv
forAll(valueSets, i) return getExpectedPath("csv");
{
columns[i] = valueSets[i];
}
this->writeTable(points, columns, os);
} }
template<class Type> bool Foam::coordSetWriters::csvWriter::writeBuffered()
void Foam::csvSetWriter<Type>::write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
{ {
writeHeader(tracks[0],valueSetNames,os); if (coords_.empty())
if (valueSets.size() != valueSetNames.size())
{ {
FatalErrorInFunction clearBuffers();
<< "Number of variables:" << valueSetNames.size() << endl return false;
<< "Number of valueSets:" << valueSets.size()
<< exit(FatalError);
} }
const auto& coords = coords_[0];
List<const List<Type>*> columns(valueSets.size());
forAll(tracks, trackI) DynamicList<word> headCols(3 + nDataColumns());
do
{ {
// Collect sets into columns if (coords.hasVectorAxis())
forAll(valueSets, i)
{ {
columns[i] = &valueSets[i][trackI]; // x, y, z
} headCols.append("x");
headCols.append("y");
this->writeTable(tracks[trackI], columns, os); headCols.append("z");
os << nl << nl;
}
}
template<class Type>
void Foam::csvSetWriter<Type>::writeSeparator(Ostream& os) const
{
os << token::COMMA;
}
namespace Foam
{
// otherwise compiler complains about specialization
template<>
void csvSetWriter<scalar>::writeHeader
(
const coordSet& points,
const wordList& valueSetNames,
Ostream& os
) const
{
writeCoordHeader(points, os);
forAll(valueSetNames, i)
{
if (i)
{
writeSeparator(os);
}
os << valueSetNames[i];
}
os << nl;
}
}
template<class Type>
void Foam::csvSetWriter<Type>::writeHeader
(
const coordSet& points,
const wordList& valueSetNames,
Ostream& os
) const
{
writeCoordHeader(points, os);
forAll(valueSetNames, i)
{
for (label j=0; j<Type::nComponents; j++)
{
if (i || j)
{
writeSeparator(os);
}
os << valueSetNames[i] << "_" << j;
}
}
os << nl;
}
template<class Type>
void Foam::csvSetWriter<Type>::writeCoordHeader
(
const coordSet& points,
Ostream& os
) const
{
const word axisName(points.axis());
if (points.hasVectorAxis())
{
for (auto iter = axisName.cbegin(); iter != axisName.cend(); ++iter)
{
os << *iter;
writeSeparator(os);
}
} }
else else
{ {
os << axisName; headCols.append(coords.axis());
writeSeparator(os);
} }
// label, scalar
headCols.append(labelNames_);
headCols.append(scalarNames_);
// vector space
#undef doLocalCode
#define doLocalCode(Type) \
\
for (const word& fldName : Type##Names_) \
{ \
for (direction d=0; d < pTraits<Type>::nComponents; ++d) \
{ \
headCols.append(fldName + '_' + Foam::name(d)); \
} \
} }
doLocalCode(vector);
doLocalCode(sphericalTensor);
doLocalCode(symmTensor);
doLocalCode(tensor);
#undef doLocalCode
}
while (false);
// Field:
// 1) rootdir/<TIME>/setName.csv
// 2) rootdir/setName.csv
fileName outputFile = path();
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
OFstream os(outputFile, streamOpt_);
os.precision(precision_);
writeLine(os, headCols, ",");
writeBufferContents(os, coords, ",");
clearBuffers();
return true;
}
// * * * * * * * * * * * * * * * Implementation * * * * * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::coordSetWriters::csvWriter::writeTemplate
(
const word& fieldName,
const Field<Type>& values
)
{
checkOpen();
if (coords_.empty())
{
return fileName::null;
}
if (useTracks_ || !buffering_)
{
UPtrList<const Field<Type>> fieldPtrs(repackageFields(values));
return writeTemplate(fieldName, fieldPtrs);
}
// Buffering version
appendField(fieldName, values);
return path();
}
template<class Type>
Foam::fileName Foam::coordSetWriters::csvWriter::writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
)
{
checkOpen();
if (coords_.empty())
{
return fileName::null;
}
useTracks_ = true; // Extra safety
UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
return writeTemplate(fieldName, fieldPtrs);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Field writing methods
defineCoordSetWriterWriteFields(Foam::coordSetWriters::csvWriter);
// ************************************************************************* // // ************************************************************************* //

View File

@ -0,0 +1,179 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::coordSetWriters::csvWriter
Description
Write coordSet(s) in csv format
The formatOptions for csv:
\table
Property | Description | Required | Default
buffer | Use buffered output | no | true
compression | Use file compression | no | false
precision | Write precision in ascii | no | same as IOstream
\endtable
When called with a single coordSet, will buffer the output of
all fields and output together in the order of label/scalar/vector/...
each of which is sorted alphabetically according to the field name.
When called as a track writer (eg, with multiple coordSets),
will emit one file per field.
SourceFiles
csvCoorSetWriter.C
csvCoorSetWriterImpl.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_csvWriter_H
#define Foam_coordSetWriters_csvWriter_H
#include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
/*---------------------------------------------------------------------------*\
Class csvWriter Declaration
\*---------------------------------------------------------------------------*/
class csvWriter
:
public coordSetWriter
{
// Private Data
//- Output stream option
IOstreamOption streamOpt_;
//- ASCII write precision
unsigned precision_;
// Private Member Functions
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName, //!< Name of field
const Field<Type>& vals //!< Local field values to write
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
);
protected:
// Protected Member Functions
//- Write buffered data
virtual bool writeBuffered();
public:
//- Runtime type information (no debug)
TypeNameNoDebug("csv");
// Constructors
//- Default construct
csvWriter();
//- Default construct with specified options
explicit csvWriter(const dictionary& options);
//- Construct from components
csvWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Construct from components
csvWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Destructor. Calls close()
virtual ~csvWriter();
// Member Functions
//- Enable/disable internal buffering
virtual bool buffering(const bool on); // override
//- Characteristic output file name - information only
// \warning incorrect for unbuffered or track output!
virtual fileName path() const; // override
declareCoordSetWriterWriteMethod(label);
declareCoordSetWriterWriteMethod(scalar);
declareCoordSetWriterWriteMethod(vector);
declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace coordSetWriters
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,144 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "IOmanip.H"
#include "OFstream.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Output coordinate header
static void writeCoordHeader
(
Ostream& os,
const coordSet& coords,
const label count /* (future?) */
)
{
if (coords.hasVectorAxis())
{
os << "x,y,z";
}
else
{
// axis name
// const word axisName(coords.axis());
os << word(coords.axis());
}
}
// Write field name, use named components for VectorSpace
template<class Type>
static inline void writeHeader(Ostream& os, const word& fieldName)
{
/// os << ' '; // Extra space
const auto nCmpts(pTraits<Type>::nComponents);
if (pTraits<Type>::rank || nCmpts > 1)
{
for (direction d = 0; d < nCmpts; ++d)
{
os << ',' << fieldName
<< '_' << pTraits<Type>::componentNames[d];
}
}
else
{
os << ',' << fieldName;
}
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::coordSetWriters::csvWriter::writeTemplate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
)
{
if (coords_.size() != fieldPtrs.size())
{
FatalErrorInFunction
<< "Attempted to write field: " << fieldName
<< " (" << fieldPtrs.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError);
}
label nPoints = 0;
for (const auto& pts : coords_)
{
nPoints += pts.size();
}
// Field: rootdir/<TIME>/<field>_setName.csv
fileName outputFile = getFieldPrefixedPath(fieldName, "csv");
if (verbose_)
{
Info<< "Writing field " << fieldName;
Info<< " to " << outputFile << endl;
}
// Master only
{
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
OFstream os(outputFile, streamOpt_);
os.precision(precision_);
// Header
{
writeCoordHeader(os, coords_[0], nPoints);
writeHeader<Type>(os, fieldName);
os << nl;
}
forAll(coords_, tracki)
{
writeTable(os, coords_[tracki], fieldPtrs[tracki], ",");
}
}
wroteGeom_ = true;
return outputFile;
}
// ************************************************************************* //

View File

@ -1,131 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::csvSetWriter
Description
Write set in csv format
SourceFiles
csvCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_csvWriter_H
#define Foam_coordSetWriters_csvWriter_H
#include "writer.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class csvSetWriter Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class csvSetWriter
:
public writer<Type>
{
// Private Member Functions
void writeCoordHeader(const coordSet&, Ostream&) const;
void writeHeader(const coordSet&, const wordList&, Ostream&) const;
protected:
virtual void writeSeparator(Ostream&) const;
public:
//- Runtime type information
TypeName("csv");
// Constructors
//- Default construct
csvSetWriter();
//- Construct with dictionary
explicit csvSetWriter(const dictionary& dict);
//- Destructor
virtual ~csvSetWriter() = default;
// Member Functions
virtual fileName getFileName
(
const coordSet&,
const wordList&
) const;
virtual void write
(
const coordSet&,
const wordList&,
const List<const Field<Type>*>&,
Ostream&
) const;
virtual void write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "csvCoordSetWriter.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,39 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "csvSetWriter.H"
#include "writers.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makeSetWriters(csvSetWriter);
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd. Copyright (C) 2021-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,277 +26,321 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "ensightSetWriter.H" #include "ensightCoordSetWriter.H"
#include "coordSet.H" #include "coordSet.H"
#include "IOmanip.H" #include "IOmanip.H"
#include "ensightCase.H" #include "ensightCase.H"
#include "ensightGeoFile.H" #include "ensightGeoFile.H"
#include "ensightOutput.H"
#include "ensightPTraits.H" #include "ensightPTraits.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
defineTypeName(ensightWriter);
addToRunTimeSelectionTable(coordSetWriter, ensightWriter, word);
addToRunTimeSelectionTable(coordSetWriter, ensightWriter, wordDict);
}
}
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
template<class Type>
static void writeTrackField
(
ensightFile& os,
const UPtrList<const Field<Type>>& fieldPtrs
)
{
// Write field (serial only)
os.writeKeyword(ensightPTraits<Type>::typeName);
forAll(fieldPtrs, tracki)
{
// Write as point data
os.beginPart(tracki); // Part index (0-based)
ensightOutput::Detail::writeFieldComponents
(
os,
ensightFile::coordinates,
fieldPtrs[tracki],
false /* serial only! */
);
}
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::coordSetWriters::ensightWriter::writeGeometry
(
ensightGeoFile& os,
elemOutputType elemOutput
) const
{
// Writing tracks as x/y/z coordinates, optionally with points
// or points/lines as elements.
//
// The requirements are so basic that they do not warrant an
// ensightPart treatment at all.
forAll(coords_, tracki)
{
const auto& coords = coords_[tracki];
const label nPoints = coords.size();
word partName("track" + Foam::name(tracki));
if (coords_.size() == 1 && elemOutputType::WRITE_LINES != elemOutput)
{
partName = "sampled";
}
ensightOutput::Detail::writeCoordinates
(
os,
tracki, // Part index (0-based)
partName,
nPoints,
static_cast<const pointField&>(coords),
false /* serial only! */
);
if (elemOutputType::WRITE_POINTS == elemOutput)
{
if (nPoints)
{
os.writeKeyword("point");
os.write(nPoints);
os.newline();
for (label pointi = 0; pointi < nPoints; ++pointi)
{
os.write(pointi+1); // From 0-based to 1-based index
os.newline();
}
}
}
if (elemOutputType::WRITE_LINES == elemOutput)
{
const label nLines = (nPoints-1);
if (nPoints == 1)
{
os.writeKeyword("point");
os.write(nPoints);
os.newline();
for (label pointi = 0; pointi < nPoints; ++pointi)
{
os.write(pointi+1); // From 0-based to 1-based index
os.newline();
}
}
else if (nLines > 0)
{
os.writeKeyword("bar2");
os.write(nLines);
os.newline();
for (label pointi = 0; pointi < nLines; ++pointi)
{
os.write(pointi+1); // From 0-based to 1-based index
os.write(pointi+2);
os.newline();
}
}
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type> Foam::coordSetWriters::ensightWriter::ensightWriter()
Foam::ensightSetWriter<Type>::ensightSetWriter()
: :
writer<Type>() coordSetWriter(),
writeFormat_(IOstream::ASCII),
collateTimes_(true),
caching_("fieldsDict") // Historic name
{} {}
template<class Type> Foam::coordSetWriters::ensightWriter::ensightWriter(const dictionary& options)
Foam::ensightSetWriter<Type>::ensightSetWriter(const dictionary& dict)
: :
writer<Type>(dict) coordSetWriter(options),
writeFormat_
(
IOstreamOption::formatEnum("format", options, IOstream::ASCII)
),
collateTimes_(options.getOrDefault("collateTimes", true)),
caching_("fieldsDict") // Historic name
{} {}
Foam::coordSetWriters::ensightWriter::ensightWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options
)
:
ensightWriter(options)
{
open(coords, outputPath);
}
Foam::coordSetWriters::ensightWriter::ensightWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options
)
:
ensightWriter(options)
{
open(tracks, outputPath);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coordSetWriters::ensightWriter::~ensightWriter()
{
close();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> Foam::fileName Foam::coordSetWriters::ensightWriter::path() const
Foam::fileName Foam::ensightSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
{ {
return // Assume collateTimes == true, otherwise too fragile
this->getBaseName(points, valueSetNames)
//+ '_' // Collated
//+ ensightPTraits<Type>::typeName // ========
+ ".case"; // CaseFile: rootdir/NAME/NAME.case
// Geometry: rootdir/NAME/data/<index>/geometry
// Field: rootdir/NAME/data/<index>/field
if (!outputPath_.empty())
{
return outputPath_ / (ensight::FileName(outputPath_.name()) + ".case");
} }
return fileName();
}
void Foam::coordSetWriters::ensightWriter::close(const bool force)
{
caching_.clear();
coordSetWriter::close(force);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Field writing implementations
#include "ensightCoordSetWriterCollated.C"
#include "ensightCoordSetWriterUncollated.C"
template<class Type> template<class Type>
void Foam::ensightSetWriter<Type>::write Foam::fileName Foam::coordSetWriters::ensightWriter::writeTemplate
( (
const coordSet& points, const word& fieldName,
const wordList& valueSetNames, const Field<Type>& values
const List<const Field<Type>*>& valueSets, )
Ostream& os
) const
{ {
const fileName base(os.name().lessExt()); checkOpen();
const fileName meshFile(base + ".mesh"); if (coords_.empty())
// Write .case file
os << "FORMAT" << nl
<< "type: ensight gold" << nl
<< nl
<< "GEOMETRY" << nl
<< "model: 1 " << meshFile.name().c_str() << nl
<< nl
<< "VARIABLE"
<< nl;
for (const word& valueName : valueSetNames)
{ {
fileName dataFile(base + ".***." + valueName); return fileName::null;
os.setf(ios_base::left);
os << ensightPTraits<Type>::typeName
<< " per node: 1 "
<< setw(15) << valueName
<< " " << dataFile.name().c_str()
<< nl;
} }
os << nl if (coords_.size() != 1)
<< "TIME" << nl
<< "time set: 1" << nl
<< "number of steps: 1" << nl
<< "filename start number: 0" << nl
<< "filename increment: 1" << nl
<< "time values:" << nl
<< "0.00000e+00" << nl;
// Write .mesh file
{ {
string desc("Written by OpenFOAM"); FatalErrorInFunction
OFstream os(meshFile); << "Attempted to write field: " << fieldName
os.setf(ios_base::scientific, ios_base::floatfield); << " (" << 1 << " entries) for "
os.precision(5); << coords_.size() << " sets" << nl
<< exit(FatalError);
os << "Ensight Geometry File" << nl
<< desc.c_str() << nl
<< "node id assign" << nl
<< "element id assign" << nl
<< "part" << nl
<< setw(10) << 1 << nl
<< "internalMesh" << nl
<< "coordinates" << nl
<< setw(10) << points.size() << nl;
for (direction cmpt = 0; cmpt < vector::nComponents; ++cmpt)
{
for (const point& p : points)
{
const float comp = narrowFloat(p[cmpt]);
os << setw(12) << comp << nl;
}
}
os << "point" << nl
<< setw(10) << points.size() << nl;
forAll(points, pointi)
{
os << setw(10) << pointi+1 << nl;
}
} }
// Write data files UPtrList<const Field<Type>> fieldPtrs(repackageFields(values));
forAll(valueSetNames, seti)
elemOutputType elemOutput =
(
useTracks_
? elemOutputType::WRITE_LINES
: elemOutputType::NO_ELEMENTS
);
if (collateTimes_)
{ {
const word& valueName = valueSetNames[seti]; return writeCollated(fieldName, fieldPtrs, elemOutput);
const Field<Type>& fld = *(valueSets[seti]);
fileName dataFile(base + ".000." + valueName);
OFstream os(dataFile);
os.setf(ios_base::scientific, ios_base::floatfield);
os.precision(5);
os << ensightPTraits<Type>::typeName << nl
<< "part" << nl
<< setw(10) << 1 << nl
<< "coordinates" << nl;
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
const direction cmpt = ensightPTraits<Type>::componentOrder[d];
for (const Type& val : fld)
{
const float comp = narrowFloat(component(val, cmpt));
os << setw(12) << comp << nl;
}
} }
else
{
return writeUncollated(fieldName, fieldPtrs, elemOutput);
} }
} }
template<class Type> template<class Type>
void Foam::ensightSetWriter<Type>::write Foam::fileName Foam::coordSetWriters::ensightWriter::writeTemplate
( (
const bool writeTracks, const word& fieldName,
const List<scalarField>& times, const List<Field<Type>>& fieldValues
const PtrList<coordSet>& tracks, )
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
{ {
const fileName base(os.name().lessExt()); checkOpen();
const fileName meshFile(base + ".mesh"); if (coords_.empty())
// Write .case file
os << "FORMAT" << nl
<< "type: ensight gold" << nl
<< nl
<< "GEOMETRY" << nl
<< "model: 1 " << meshFile.name().c_str() << nl
<< nl
<< "VARIABLE"
<< nl;
for (const word& valueName : valueSetNames)
{ {
fileName dataFile(base + ".***." + valueName); return fileName::null;
os.setf(ios_base::left);
os << ensightPTraits<Type>::typeName
<< " per node: 1 "
<< setw(15) << valueName
<< " " << dataFile.name().c_str()
<< nl;
} }
os << nl if (coords_.size() != fieldValues.size())
<< "TIME" << nl
<< "time set: 1" << nl
<< "number of steps: 1" << nl
<< "filename start number: 0" << nl
<< "filename increment: 1" << nl
<< "time values:" << nl
<< "0.00000e+00" << nl;
// Write .mesh file
{ {
string desc("Written by OpenFOAM"); FatalErrorInFunction
OFstream os(meshFile); << "Attempted to write field: " << fieldName
os.setf(ios_base::scientific, ios_base::floatfield); << " (" << fieldValues.size() << " entries) for "
os.precision(5); << coords_.size() << " sets" << nl
os << "Ensight Geometry File" << nl << exit(FatalError);
<< desc.c_str() << nl
<< "node id assign" << nl
<< "element id assign" << nl;
forAll(tracks, tracki)
{
const coordSet& points = tracks[tracki];
os << "part" << nl
<< setw(10) << tracki+1 << nl
<< "internalMesh" << nl
<< "coordinates" << nl
<< setw(10) << points.size() << nl;
for (direction cmpt = 0; cmpt < vector::nComponents; ++cmpt)
{
for (const point& p : points)
{
const float comp = narrowFloat(p[cmpt]);
os << setw(12) << comp << nl;
}
} }
if (writeTracks) UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
if (collateTimes_)
{ {
os << "bar2" << nl return writeCollated
<< setw(10) << points.size()-1 << nl; (
for (label i = 0; i < points.size()-1; i++) fieldName,
fieldPtrs,
elemOutputType::WRITE_LINES
);
}
else
{ {
os << setw(10) << i+1 return writeUncollated
<< setw(10) << i+2 (
<< nl; fieldName,
} fieldPtrs,
} elemOutputType::WRITE_LINES
);
} }
} }
// Write data files // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
forAll(valueSetNames, seti)
{
const word& valueName = valueSetNames[seti];
const List<Field<Type>>& fieldVals = valueSets[seti];
fileName dataFile(base + ".000." + valueName); // Field writing methods
OFstream os(dataFile); defineCoordSetWriterWriteFields(Foam::coordSetWriters::ensightWriter);
os.setf(ios_base::scientific, ios_base::floatfield);
os.precision(5);
{
os << ensightPTraits<Type>::typeName << nl;
forAll(fieldVals, tracki)
{
const Field<Type>& fld = fieldVals[tracki];
os << "part" << nl
<< setw(10) << tracki+1 << nl
<< "coordinates" << nl;
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
const direction cmpt =
ensightPTraits<Type>::componentOrder[d];
for (const Type& val : fld)
{
const float comp = narrowFloat(component(val, cmpt));
os << setw(12) << comp << nl;
}
}
}
}
}
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -0,0 +1,220 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::coordSetWriters::ensightCoordSetWriter
Description
A coordSetWriter for Ensight format.
\verbatim
formatOptions
{
ensight
{
format ascii;
collateTimes true;
}
}
\endverbatim
Format options:
\table
Property | Description | Required | Default
format | ascii/binary | no | ascii
collateTimes | use common geometry for times | no | true
\endtable
SourceFiles
ensightCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_ensightWriter_H
#define Foam_coordSetWriters_ensightWriter_H
#include "coordSetWriter.H"
#include "ensightWriterCaching.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class ensightGeoFile;
namespace coordSetWriters
{
/*---------------------------------------------------------------------------*\
Class ensightWriter Declaration
\*---------------------------------------------------------------------------*/
class ensightWriter
:
public coordSetWriter
{
// Data Types
//- Types of element output
enum elemOutputType
{
NO_ELEMENTS = 0,
WRITE_POINTS = 1,
WRITE_LINES = 2
};
// Private Data
//- Output format option (default: IOstream::ASCII)
IOstreamOption::streamFormat writeFormat_;
//- Collate times (default: true)
bool collateTimes_;
//- Cached information for times, geometry, fields (collated)
ensightOutput::writerCaching caching_;
// Private Member Functions
//- Write geometry
void writeGeometry
(
ensightGeoFile& os,
elemOutputType elemOutput
) const;
//- Write geometry
fileName writeCollated(const bool writeTracks);
//- Write geometry
fileName writeUncollated(const bool writeTracks);
//- Templated write operation - one file per timestep
template<class Type>
fileName writeCollated
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs,
elemOutputType elemOutput
);
//- Templated write operation - all time steps in single file
template<class Type>
fileName writeUncollated
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs,
elemOutputType elemOutput
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const Field<Type>& values
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
);
public:
//- Runtime type information (no debug)
TypeNameNoDebug("ensight");
// Constructors
//- Default construct
ensightWriter();
//- Default construct with specified options
explicit ensightWriter(const dictionary& options);
//- Construct from components
ensightWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Construct from components
ensightWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Destructor. Calls close()
virtual ~ensightWriter();
// Member Functions
//- Finish output, clears output times.
// Later reuse will rebuild times from fieldsDict file cache.
virtual void close(bool force = false); // override
// Write
//- Expected (characteristic) output file name - information only
// \warning incorrect for uncollated output!
virtual fileName path() const; // override
declareCoordSetWriterWriteMethod(label);
declareCoordSetWriterWriteMethod(scalar);
declareCoordSetWriterWriteMethod(vector);
declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace coordSetWriters
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,280 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated
(
const bool writeTracks
)
{
// Collated?
// ========
// CaseFile: rootdir/NAME/NAME.case
// Geometry: rootdir/NAME/NAME.mesh
wroteGeom_ = true;
return fileName::null;
}
template<class Type>
Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs,
elemOutputType elemOutput
)
{
// Geometry changed since last output? Capture now
const bool geomChanged = (!upToDate_);
checkOpen();
const ensight::FileName baseName(outputPath_.name());
const ensight::VarName varName(fieldName);
// Collated
// ========
// CaseFile: rootdir/NAME/NAME.case
// Geometry: rootdir/NAME/data/<index>/geometry
// Field: rootdir/NAME/data/<index>/field
// Use geometry name as sub-directory for results. Eg,
// - NAME1/NAME1.case
// - NAME1/data/00000000/geometry
// - NAME1/data/00000000/VAR1
// - NAME1/data/00000000/VAR2
// Names "data" and "geometry" as per ensightCase:
const char* fmt = "%08d";
const char* mask = "data/********/";
// Ignore the useTimeDir setting - manage ourselves
const fileName baseDir = outputPath_;
const word timeDir = timeName();
const scalar timeValue = currTime_.value();
const fileName outputFile = baseDir / baseName + ".case";
if (verbose_)
{
Info<< "Writing case file to " << outputFile << endl;
}
// Update geometry
merge();
{
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
const bool stateChanged =
caching_.update
(
baseDir,
timeValue,
geomChanged,
fieldName,
ensightPTraits<Type>::typeName,
varName
);
// The most current time and geometry indices
const label timeIndex = caching_.latestTimeIndex();
const label geomIndex = caching_.latestGeomIndex();
// This will be used for the name of a static geometry,
// or just the masking part for moving geometries.
const fileName geometryName
(
"data"/word::printf(fmt, geomIndex)/ensightCase::geometryName
);
// Do case file
if (stateChanged)
{
OFstream osCase(outputFile, IOstream::ASCII);
// Format options
osCase.setf(ios_base::left);
osCase.setf(ios_base::scientific, ios_base::floatfield);
osCase.precision(5);
if (verbose_)
{
Info<< "Writing case file to " << osCase.name() << endl;
}
// The geometry can be any of the following:
// 0: constant/static
// 1: moving, with the same frequency as the data
// 2: moving, with different frequency as the data
const label tsGeom = caching_.geometryTimeset();
osCase
<< "FORMAT" << nl
<< "type: ensight gold" << nl
<< nl
<< "GEOMETRY" << nl;
if (tsGeom)
{
// moving
osCase
<< "model: " << tsGeom << " " // time-set (1|2)
<< mask << geometryName.name() << nl;
}
else
{
// steady
osCase
<< "model: "
<< geometryName.c_str() << nl;
}
osCase
<< nl
<< "VARIABLE" << nl;
for (const entry& dEntry : caching_.fieldsDict())
{
const dictionary& subDict = dEntry.dict();
const word varType(subDict.get<word>("type"));
const word varName
(
subDict.getOrDefault<word>
(
"name",
dEntry.keyword() // fieldName as fallback
)
);
osCase
<< varType
<<
(
true // this->isPointData()
? " per node: 1 " // time-set 1
: " per element: 1 " // time-set 1
)
<< setw(15) << varName << ' '
<< mask << varName << nl;
}
osCase
<< nl
<< "TIME" << nl;
ensightCase::printTimeset(osCase, 1, caching_.times());
if (tsGeom == 2)
{
ensightCase::printTimeset
(
osCase,
tsGeom,
caching_.times(),
caching_.geometries()
);
}
osCase << "# end" << nl;
}
// Location for data (and possibly the geometry as well)
fileName dataDir = baseDir/"data"/word::printf(fmt, timeIndex);
// As per mkdir -p "data/00000000"
mkDir(dataDir);
const fileName geomFile(baseDir/geometryName);
if (!exists(geomFile))
{
if (verbose_)
{
Info<< "Writing geometry to " << geomFile.name() << endl;
}
// Two-argument form for path-name to avoid validating base-dir
ensightGeoFile osGeom
(
geomFile.path(),
geomFile.name(),
writeFormat_
);
writeGeometry(osGeom, elemOutput);
}
// Write field
ensightFile osField
(
dataDir,
varName,
writeFormat_
);
if (verbose_)
{
Info<< "Writing field file to " << osField.name() << endl;
}
// Write field (serial only)
writeTrackField<Type>(osField, fieldPtrs);
// Timestamp in the directory for future reference
{
OFstream timeStamp(dataDir/"time");
timeStamp
<< "# timestep time" << nl
<< dataDir.name() << ' ' << timeValue << nl;
}
}
wroteGeom_ = true;
return outputFile;
}
// ************************************************************************* //

View File

@ -0,0 +1,158 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::fileName Foam::coordSetWriters::ensightWriter::writeUncollated
(
const bool writeTracks
)
{
return fileName::null;
}
template<class Type>
Foam::fileName Foam::coordSetWriters::ensightWriter::writeUncollated
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs,
elemOutputType elemOutput
)
{
checkOpen();
const ensight::FileName baseName(outputPath_.name());
const ensight::VarName varName(fieldName);
// Uncollated
// ==========
// CaseFile: rootdir/time/<field>/NAME.case
// Geometry: rootdir/time/<field>/NAME.<index>.mesh
// Field: rootdir/time/<field>/NAME.<index>.<field>
// Variable name as sub-directory for results. Eg,
// - VAR1/NAME1.case
// - VAR1/NAME1.00000000.mesh
// - VAR1/NAME1.00000001.VAR1
// and
// - VAR2/NAME1.case
// - VAR2/NAME1.00000000.mesh
// - VAR2/NAME1.00000001.VAR2
fileName outputDir;
if (useTimeDir() && !timeName().empty())
{
// Splice in time-directory
outputDir = outputPath_.path() / timeName();
}
else
{
outputDir = outputPath_.path();
}
const fileName baseDir = outputDir / varName;
const word timeDir = timeName();
const scalar timeValue = currTime_.value();
const fileName outputFile = baseDir / baseName + ".case";
if (verbose_)
{
Info<< "Writing case file to " << outputFile << endl;
}
merge();
{
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
OFstream osCase(outputFile, IOstream::ASCII);
// Format options
osCase.setf(ios_base::left);
osCase.setf(ios_base::scientific, ios_base::floatfield);
osCase.precision(5);
// Two-argument form for path-name to avoid validating base-dir
ensightGeoFile osGeom
(
baseDir,
baseName + ".00000000.mesh",
writeFormat_
);
ensightFile osField
(
baseDir,
baseName + ".00000000." + varName,
writeFormat_
);
osCase
<< "FORMAT" << nl
<< "type: ensight gold" << nl
<< nl
<< "GEOMETRY" << nl
<< "model: 1 " << osGeom.name().name() << nl
<< nl
<< "VARIABLE" << nl
<< ensightPTraits<Type>::typeName
<<
(
true // this->isPointData()
? " per node: 1 " // time-set 1
: " per element: 1 " // time-set 1
)
<< setw(15) << varName << ' '
<< baseName.c_str() << ".********." << varName << nl;
osCase
<< nl
<< "TIME" << nl;
ensightCase::printTimeset(osCase, 1, timeValue);
osCase << "# end" << nl;
writeGeometry(osGeom, elemOutput);
// Write field (serial only)
writeTrackField<Type>(osField, fieldPtrs);
}
wroteGeom_ = true;
return outputFile;
}
// ************************************************************************* //

View File

@ -1,118 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::ensightSetWriter
Description
SourceFiles
ensightCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_ensightWriter_H
#define Foam_coordSetWriters_ensightWriter_H
#include "writer.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class ensightSetWriter Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class ensightSetWriter
:
public writer<Type>
{
public:
//- Runtime type information
TypeName("ensight");
// Constructors
//- Default construct
ensightSetWriter();
//- Construct with dictionary
explicit ensightSetWriter(const dictionary& dict);
//- Destructor
virtual ~ensightSetWriter() = default;
// Member Functions
virtual fileName getFileName
(
const coordSet&,
const wordList&
) const;
virtual void write
(
const coordSet&,
const wordList&,
const List<const Field<Type>*>&,
Ostream&
) const;
virtual void write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ensightCoordSetWriter.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,39 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "ensightSetWriter.H"
#include "writers.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makeSetWriters(ensightSetWriter);
}
// ************************************************************************* //

View File

@ -25,19 +25,30 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "gltfSetWriter.H" #include "gltfCoordSetWriter.H"
#include "coordSet.H" #include "coordSet.H"
#include "fileName.H" #include "fileName.H"
#include "OFstream.H" #include "OFstream.H"
#include "floatVector.H" #include "OSspecific.H"
#include "foamGltfScene.H" #include "foamGltfScene.H"
#include "foamGltfSceneWriter.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
template<class Type> namespace Foam
const Foam::Enum<typename Foam::gltfSetWriter<Type>::fieldOption> {
Foam::gltfSetWriter<Type>::fieldOptionNames_ namespace coordSetWriters
{
defineTypeName(gltfWriter);
addToRunTimeSelectionTable(coordSetWriter, gltfWriter, word);
addToRunTimeSelectionTable(coordSetWriter, gltfWriter, wordDict);
}
}
const Foam::Enum<Foam::coordSetWriters::gltfWriter::fieldOption>
Foam::coordSetWriters::gltfWriter::fieldOptionNames_
({ ({
// No naming for NONE // No naming for NONE
{ fieldOption::UNIFORM, "uniform" }, { fieldOption::UNIFORM, "uniform" },
@ -45,10 +56,90 @@ Foam::gltfSetWriter<Type>::fieldOptionNames_
}); });
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
template<class Type> template<class Type>
Foam::word Foam::gltfSetWriter<Type>::getColourMap static tmp<vectorField> getBoundedColours
(
const colourTable& colours,
const Field<Type>& field,
const scalar boundMin,
const scalar boundMax
)
{
const label boundDelta = (boundMax - boundMin + ROOTVSMALL);
auto tresult = tmp<vectorField>::New(field.size());
auto& result = tresult.ref();
forAll(field, i)
{
const Type& val = field[i];
const scalar f =
(
pTraits<Type>::nComponents == 1
? scalar(component(val, 0))
: scalar(mag(val))
);
// 0-1 clipped by value()
result[i] = colours.value((f - boundMin)/boundDelta);
}
return tresult;
}
template<class Type>
static vector getAnimationColour
(
const dictionary& dict,
const colourTable& colours,
const Field<Type>& field
)
{
scalar refValue(0);
scalarMinMax valLimits;
if (pTraits<Type>::nComponents == 1)
{
MinMax<Type> scanned(minMax(field));
refValue = scalar(component(field[0], 0));
valLimits.min() = scalar(component(scanned.min(), 0));
valLimits.max() = scalar(component(scanned.max(), 0));
}
else
{
// Use mag() for multiple components
refValue = mag(field[0]);
valLimits = minMaxMag(field);
}
dict.readIfPresent("min", valLimits.min());
dict.readIfPresent("max", valLimits.max());
const scalar fraction =
(
(refValue - valLimits.min())
/ (valLimits.max() - valLimits.min() + ROOTVSMALL)
);
// 0-1 clipped by value()
return colours.value(fraction);
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::word Foam::coordSetWriters::gltfWriter::getColourMap
( (
const dictionary& dict const dictionary& dict
) const ) const
@ -60,8 +151,7 @@ Foam::word Foam::gltfSetWriter<Type>::getColourMap
} }
template<class Type> const Foam::colourTable& Foam::coordSetWriters::gltfWriter::getColourTable
const Foam::colourTable& Foam::gltfSetWriter<Type>::getColourTable
( (
const dictionary& dict const dictionary& dict
) const ) const
@ -70,8 +160,7 @@ const Foam::colourTable& Foam::gltfSetWriter<Type>::getColourTable
} }
template<class Type> Foam::scalarMinMax Foam::coordSetWriters::gltfWriter::getFieldLimits
Foam::scalarMinMax Foam::gltfSetWriter<Type>::getFieldLimits
( (
const word& fieldName const word& fieldName
) const ) const
@ -87,8 +176,8 @@ Foam::scalarMinMax Foam::gltfSetWriter<Type>::getFieldLimits
} }
template<class Type> Foam::tmp<Foam::scalarField>
Foam::tmp<Foam::scalarField> Foam::gltfSetWriter<Type>::getAlphaField Foam::coordSetWriters::gltfWriter::getAlphaField
( (
const dictionary& dict const dictionary& dict
) const ) const
@ -141,27 +230,10 @@ Foam::tmp<Foam::scalarField> Foam::gltfSetWriter<Type>::getAlphaField
} }
template<class Type> void Foam::coordSetWriters::gltfWriter::setupAnimationColour()
Foam::vector Foam::gltfSetWriter<Type>::getTrackAnimationColour
(
const colourTable& colours,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
const label tracki
) const
{ {
if (!colour_)
{
FatalErrorInFunction
<< "Attempting to get colour when colour option is off"
<< abort(FatalError);
}
const dictionary& dict = animationDict_; const dictionary& dict = animationDict_;
// Fallback value
vector colourValue(Zero);
const entry* eptr = dict.findEntry("colour", keyType::LITERAL); const entry* eptr = dict.findEntry("colour", keyType::LITERAL);
if (!eptr || !eptr->isStream()) if (!eptr || !eptr->isStream())
@ -175,8 +247,11 @@ Foam::vector Foam::gltfSetWriter<Type>::getTrackAnimationColour
// Value specified // Value specified
ITstream& is = eptr->stream(); ITstream& is = eptr->stream();
is >> colourValue; is >> animateColourValue_;
dict.checkITstream(is, "colour"); dict.checkITstream(is, "colour");
// Has uniform value
animateColourOption_ = fieldOption::UNIFORM;
} }
else else
{ {
@ -188,85 +263,59 @@ Foam::vector Foam::gltfSetWriter<Type>::getTrackAnimationColour
{ {
case fieldOption::NONE: case fieldOption::NONE:
{ {
FatalErrorInFunction
<< "Cannot select 'none' for colour entry!" << nl
<< "... possible programming error"
<< exit(FatalError);
break; break;
} }
case fieldOption::UNIFORM: case fieldOption::UNIFORM:
{ {
dict.readEntry("colourValue", colourValue); dict.readEntry("colourValue", animateColourValue_);
// Has uniform value
animateColourOption_ = fieldOption::UNIFORM;
break; break;
} }
case fieldOption::FIELD: case fieldOption::FIELD:
{ {
const word fieldName = dict.get<word>("colourField"); // Needs named field...
const label fieldi = valueSetNames.find(fieldName); animateColourName_ = dict.get<word>("colourField");
if (fieldi == -1) animateColourOption_ = fieldOption::FIELD;
{ break;
FatalErrorInFunction
<< "Unable to find field " << fieldName
<< ". Valid field names are:" << valueSetNames
<< exit(FatalError);
}
const Field<Type>& colourFld = valueSets[fieldi][tracki];
scalar refValue(0);
scalarMinMax valLimits;
if (pTraits<Type>::nComponents == 1)
{
MinMax<Type> scanned(minMax(colourFld));
refValue = scalar(component(colourFld[0], 0));
valLimits.min() = scalar(component(scanned.min(), 0));
valLimits.max() = scalar(component(scanned.max(), 0));
}
else
{
// Use mag() for multiple components
refValue = mag(colourFld[0]);
valLimits = minMaxMag(colourFld);
}
dict.readIfPresent("min", valLimits.min());
dict.readIfPresent("max", valLimits.max());
const scalar fraction =
(
(refValue - valLimits.min())
/ (valLimits.max() - valLimits.min() + ROOTVSMALL)
);
return colours.value(fraction); // 0-1 clipped by value()
} }
} }
} }
return colourValue;
} }
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type> Foam::coordSetWriters::gltfWriter::gltfWriter()
Foam::gltfSetWriter<Type>::gltfSetWriter()
: :
writer<Type>(), coordSetWriter(),
writer_(nullptr),
animate_(false), animate_(false),
colour_(false), colour_(false),
animateColourOption_(fieldOption::NONE),
animateColourName_(),
animateColourValue_(Zero),
fieldInfoDict_(), fieldInfoDict_(),
animationDict_() animationDict_()
{} {}
template<class Type> Foam::coordSetWriters::gltfWriter::gltfWriter(const dictionary& options)
Foam::gltfSetWriter<Type>::gltfSetWriter(const dictionary& dict)
: :
writer<Type>(dict), coordSetWriter(options),
animate_(dict.getOrDefault("animate", false)), writer_(nullptr),
colour_(dict.getOrDefault("colour", false)), animate_(options.getOrDefault("animate", false)),
fieldInfoDict_(dict.subOrEmptyDict("fieldInfo")), colour_(options.getOrDefault("colour", false)),
animationDict_(dict.subOrEmptyDict("animationInfo")) animateColourOption_(fieldOption::NONE),
animateColourName_(),
animateColourValue_(Zero),
fieldInfoDict_(options.subOrEmptyDict("fieldInfo")),
animationDict_(options.subOrEmptyDict("animationInfo"))
{ {
// fieldInfo // fieldInfo
// { // {
@ -281,50 +330,139 @@ Foam::gltfSetWriter<Type>::gltfSetWriter(const dictionary& dict)
} }
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // Foam::coordSetWriters::gltfWriter::gltfWriter
template<class Type>
Foam::fileName Foam::gltfSetWriter<Type>::getFileName
( (
const coordSet& points, const coordSet& coords,
const wordList& valueSetNames const fileName& outputPath,
) const const dictionary& options
)
:
gltfWriter(options)
{ {
return this->getBaseName(points, valueSetNames) + ".gltf"; open(coords, outputPath);
} }
template<class Type> Foam::coordSetWriters::gltfWriter::gltfWriter
void Foam::gltfSetWriter<Type>::write
( (
const coordSet& points, const UPtrList<coordSet>& tracks,
const wordList& valueSetNames, const fileName& outputPath,
const List<const Field<Type>*>& valueSets, const dictionary& options
Ostream& os )
) const :
gltfWriter(options)
{ {
if (valueSets.size() != valueSetNames.size()) open(tracks, outputPath);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coordSetWriters::gltfWriter::~gltfWriter()
{
close();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::fileName Foam::coordSetWriters::gltfWriter::path() const
{
// 1) rootdir/<TIME>/setName.gltf
// 2) rootdir/setName.gltf
return getExpectedPath("gltf");
}
void Foam::coordSetWriters::gltfWriter::close(bool force)
{
writer_.reset(nullptr);
coordSetWriter::close(force);
}
void Foam::coordSetWriters::gltfWriter::beginTime(const Time& t)
{
writer_.reset(nullptr);
coordSetWriter::beginTime(t);
}
void Foam::coordSetWriters::gltfWriter::beginTime(const instant& inst)
{
writer_.reset(nullptr);
coordSetWriter::beginTime(inst);
}
void Foam::coordSetWriters::gltfWriter::endTime()
{
writer_.reset(nullptr);
coordSetWriter::endTime();
}
// * * * * * * * * * * * * * * * Implementation * * * * * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::coordSetWriters::gltfWriter::writeTemplate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
)
{
if (coords_.size() != fieldPtrs.size())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Number of variables:" << valueSetNames.size() << endl << "Attempted to write field: " << fieldName
<< "Number of valueSets:" << valueSets.size() << " (" << fieldPtrs.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError); << exit(FatalError);
} }
glTF::scene scene; const auto& tracks = coords_;
const label meshi = scene.addMesh(points, "points");
forAll(valueSetNames, i) // const auto& times = trackTimes_;
if (!writer_)
{ {
scene.addFieldToMesh(*valueSets[i], valueSetNames[i], meshi); // Field:
// 1) rootdir/<TIME>/setName.gltf
// 2) rootdir/setName.gltf
fileName outputFile = path();
writer_.reset(new glTF::sceneWriter(outputFile));
auto& scene = writer_->getScene();
meshes_.resize(tracks.size());
forAll(tracks, tracki)
{
word meshName("track:" + Foam::name(tracki));
if (tracks.size() == 1)
{
meshName = "points";
} }
meshes_[tracki] = scene.addMesh(tracks[tracki], meshName);
}
}
auto& scene = writer_->getScene();
forAll(tracks, tracki)
{
const label meshi = meshes_[tracki];
const auto& field = fieldPtrs[tracki];
scene.addFieldToMesh(field, fieldName, meshi);
if (colour_) if (colour_)
{ {
forAll(valueSets, fieldi)
{
const auto& field = *valueSets[fieldi];
const word& fieldName = valueSetNames[fieldi];
const dictionary dict = fieldInfoDict_.subOrEmptyDict(fieldName); const dictionary dict = fieldInfoDict_.subOrEmptyDict(fieldName);
const auto& colours = getColourTable(dict); const auto& colours = getColourTable(dict);
@ -333,11 +471,7 @@ void Foam::gltfSetWriter<Type>::write
const scalarMinMax valLimits = getFieldLimits(fieldName); const scalarMinMax valLimits = getFieldLimits(fieldName);
// Generated field colours
vectorField fieldColour(field.size());
scalarMinMax fldLimits; scalarMinMax fldLimits;
if (pTraits<Type>::nComponents == 1) if (pTraits<Type>::nComponents == 1)
{ {
MinMax<Type> scanned(minMax(field)); MinMax<Type> scanned(minMax(field));
@ -351,25 +485,18 @@ void Foam::gltfSetWriter<Type>::write
fldLimits = minMaxMag(field); fldLimits = minMaxMag(field);
} }
const scalar minf = max(fldLimits.min(), valLimits.min()); // Generated field colours
const scalar maxf = min(fldLimits.max(), valLimits.max()); vectorField fieldColour
const scalar deltaf = (maxf - minf + SMALL);
forAll(field, i)
{
const Type& val = field[i];
const scalar f =
( (
pTraits<Type>::nComponents == 1 getBoundedColours
? scalar(component(val, 0)) (
: scalar(mag(val)) colours,
field,
max(fldLimits.min(), valLimits.min()), // boundMin
min(fldLimits.max(), valLimits.max()) // boundMax
)
); );
// 0-1 clipped by value()
fieldColour[i] = colours.value((f - minf)/deltaf);
}
scene.addColourToMesh scene.addColourToMesh
( (
fieldColour, fieldColour,
@ -380,162 +507,43 @@ void Foam::gltfSetWriter<Type>::write
} }
} }
scene.write(os); return writer_().path();
} }
template<class Type> template<class Type>
void Foam::gltfSetWriter<Type>::write Foam::fileName Foam::coordSetWriters::gltfWriter::writeTemplate_animate
( (
const bool writeTracks, const word& fieldName,
const List<scalarField>& times, const UPtrList<const Field<Type>>& fieldPtrs
const PtrList<coordSet>& tracks, )
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
{ {
if (valueSets.size() != valueSetNames.size()) if (coords_.size() != fieldPtrs.size())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Number of variables:" << valueSetNames.size() << endl << "Attempted to write field: " << fieldName
<< "Number of valueSets:" << valueSets.size() << " (" << fieldPtrs.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError); << exit(FatalError);
} }
if (animate_) const auto& tracks = this->coords_;
const auto& times = this->trackTimes_;
if (!writer_)
{ {
writeAnimateTracks // Field:
( // 1) rootdir/<TIME>/setName.gltf
writeTracks, // 2) rootdir/setName.gltf
times,
tracks,
valueSetNames,
valueSets,
os
);
}
else
{
writeStaticTracks
(
writeTracks,
times,
tracks,
valueSetNames,
valueSets,
os
);
}
}
fileName outputFile = path();
template<class Type> writer_.reset(new glTF::sceneWriter(outputFile));
void Foam::gltfSetWriter<Type>::writeStaticTracks
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
{
glTF::scene scene;
forAll(tracks, tracki)
{
const vectorField& track = tracks[tracki];
const label meshi = scene.addMesh(track, "track:" + Foam::name(tracki));
forAll(valueSetNames, fieldi)
{
const word& fieldName = valueSetNames[fieldi];
const auto& field = valueSets[fieldi][tracki];
scene.addFieldToMesh(field, fieldName, meshi);
}
if (colour_) auto& scene = writer_->getScene();
{
forAll(valueSets, fieldi)
{
const auto& field = valueSets[fieldi][tracki];
const word& fieldName = valueSetNames[fieldi];
const dictionary dict = meshes_.resize(tracks.size());
fieldInfoDict_.subOrEmptyDict(fieldName);
const auto& colours = getColourTable(dict);
const auto talpha = getAlphaField(dict);
const scalarField& alpha = talpha();
const scalarMinMax valLimits = getFieldLimits(fieldName);
// Generated field colours
vectorField fieldColour(field.size());
scalarMinMax fldLimits;
if (pTraits<Type>::nComponents == 1)
{
MinMax<Type> scanned(minMax(field));
fldLimits.min() = scalar(component(scanned.min(), 0));
fldLimits.max() = scalar(component(scanned.max(), 0));
}
else
{
// Use mag() for multiple components
fldLimits = minMaxMag(field);
}
const scalar minf = max(fldLimits.min(), valLimits.min());
const scalar maxf = min(fldLimits.max(), valLimits.max());
const scalar deltaf = (maxf - minf + SMALL);
forAll(field, i)
{
const Type& val = field[i];
const scalar f =
(
pTraits<Type>::nComponents == 1
? scalar(component(val, 0))
: scalar(mag(val))
);
// 0-1 clipped by value()
fieldColour[i] = colours.value((f - minf)/deltaf);
}
scene.addColourToMesh
(
fieldColour,
"Colour:" + fieldName,
meshi,
alpha
);
}
}
}
scene.write(os);
}
template<class Type>
void Foam::gltfSetWriter<Type>::writeAnimateTracks
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
{
const auto& colours = getColourTable(animationDict_);
glTF::scene scene;
const label animationi = scene.createAnimation("animation"); const label animationi = scene.createAnimation("animation");
forAll(tracks, tracki) forAll(tracks, tracki)
@ -544,23 +552,20 @@ void Foam::gltfSetWriter<Type>::writeAnimateTracks
if (track.empty()) if (track.empty())
{ {
meshes_[tracki] = -1;
continue; continue;
} }
// Seed starting positions and field values // Seed starting position
const label meshi =
meshes_[tracki] =
scene.addMesh scene.addMesh
( (
vectorField(1, track[0]), vectorField(1, track[0]),
"track:" + Foam::name(tracki) "track:" + Foam::name(tracki)
); );
forAll(valueSetNames, fieldi) const label meshi = meshes_[tracki];
{
const Field<Type>& field = valueSets[fieldi][tracki];
const word& fieldName = valueSetNames[fieldi];
scene.addFieldToMesh(Field<Type>(1, field[0]), fieldName, meshi);
}
// Time frames // Time frames
const label timeId = const label timeId =
@ -568,38 +573,194 @@ void Foam::gltfSetWriter<Type>::writeAnimateTracks
// Translations // Translations
const vectorField translation(track - track[0]); const vectorField translation(track - track[0]);
const label translationId = scene.addField(translation, "translation"); const label translationId =
scene.addField(translation, "translation");
scene.addToAnimation(animationi, timeId, translationId, meshi); scene.addToAnimation(animationi, timeId, translationId, meshi);
}
}
auto& scene = writer_->getScene();
// Seed starting field values
forAll(tracks, tracki)
{
const auto& track = tracks[tracki];
const label meshi = meshes_[tracki];
const Field<Type>& field = fieldPtrs[tracki];
if (track.empty() || meshi < 0)
{
continue;
}
// Seed starting field values
scene.addFieldToMesh(Field<Type>(1, field[0]), fieldName, meshi);
}
// Note: colours cannot be animated... setting a fixed value.
// However, we need to wait until the field is actually seen
// Note: colours cannot be animated... setting a fixed value
if (colour_) if (colour_)
{ {
const vector colour = if (animateColourOption_ == fieldOption::NONE)
getTrackAnimationColour {
( // First time - scan for information
colours, setupAnimationColour();
valueSetNames, }
valueSets,
tracki switch (animateColourOption_)
); {
case fieldOption::NONE:
{
// Should not occur
break;
}
case fieldOption::UNIFORM:
{
// Colour value is known
vectorField fieldColour(1, animateColourValue_);
scalarField alphaChannel(1, 1.0);
const auto talpha = getAlphaField(animationDict_); const auto talpha = getAlphaField(animationDict_);
const scalarField& alpha = talpha(); if (talpha && talpha().size())
{
alphaChannel[0] = talpha()[0];
}
forAll(tracks, tracki)
{
const auto& track = tracks[tracki];
const label meshi = meshes_[tracki];
if (track.empty() || meshi < 0)
{
continue;
}
scene.addColourToMesh scene.addColourToMesh
( (
vectorField(1, colour), fieldColour,
"Colour:fixed", // ... or "Colour:constant" "Colour:fixed", // ... or "Colour:constant"
meshi, meshi,
scalarField(1, alpha[0]) alphaChannel
); );
} }
// Mark as done
animateColourName_.clear();
animateColourOption_ = fieldOption::FIELD;
break;
}
case fieldOption::FIELD:
{
if
(
!animateColourName_.empty()
&& animateColourName_ == fieldName
)
{
// This is the desired colour field. Process now
const auto& colours = getColourTable(animationDict_);
vectorField fieldColour(1, Zero);
scalarField alphaChannel(1, 1.0);
const auto talpha = getAlphaField(animationDict_);
if (talpha && talpha().size())
{
alphaChannel[0] = talpha()[0];
}
forAll(tracks, tracki)
{
const auto& track = tracks[tracki];
const label meshi = meshes_[tracki];
const Field<Type>& field = fieldPtrs[tracki];
if (track.empty() || meshi < 0)
{
continue;
}
fieldColour[0] =
getAnimationColour(animationDict_, colours, field);
scene.addColourToMesh
(
fieldColour,
"Colour:fixed", // ... or "Colour:constant"
meshi,
alphaChannel
);
}
// Mark colouring as done. Avoid retriggering
animateColourName_.clear();
animateColourOption_ = fieldOption::FIELD;
}
break;
}
}
} }
scene.write(os); return writer_().path();
} }
template<class Type>
Foam::fileName Foam::coordSetWriters::gltfWriter::writeTemplate
(
const word& fieldName,
const Field<Type>& values
)
{
checkOpen();
if (coords_.empty())
{
return fileName::null;
}
UPtrList<const Field<Type>> fieldPtrs(repackageFields(values));
return writeTemplate(fieldName, fieldPtrs);
}
template<class Type>
Foam::fileName Foam::coordSetWriters::gltfWriter::writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
)
{
checkOpen();
if (coords_.empty())
{
return fileName::null;
}
UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
if (animate_ && trackTimes_.size() >= coords_.size())
{
return writeTemplate_animate(fieldName, fieldPtrs);
}
return writeTemplate(fieldName, fieldPtrs);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Field writing methods
defineCoordSetWriterWriteFields(Foam::coordSetWriters::gltfWriter);
// ************************************************************************* // // ************************************************************************* //

View File

@ -24,10 +24,11 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class Class
Foam::gltfSetWriter Foam::coordSetWriters::gltfWriter
Description Description
Writes point data in glTF v2 format A coordSet(s) writer in glTF v2 format, which is particularly
useful for writing track data.
Two files are generated: Two files are generated:
- filename.bin : a binary file containing all scene entities - filename.bin : a binary file containing all scene entities
@ -121,23 +122,25 @@ SourceFiles
#ifndef Foam_coordSetWriters_gltfWriter_H #ifndef Foam_coordSetWriters_gltfWriter_H
#define Foam_coordSetWriters_gltfWriter_H #define Foam_coordSetWriters_gltfWriter_H
#include "writer.H" #include "coordSetWriter.H"
#include "colourTable.H" #include "colourTable.H"
#include "foamGltfFwd.H"
#include "MinMax.H" #include "MinMax.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam namespace Foam
{ {
namespace coordSetWriters
{
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class gltfSetWriter Declaration Class gltfWriter Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
template<class Type> class gltfWriter
class gltfSetWriter
: :
public writer<Type> public coordSetWriter
{ {
public: public:
@ -160,18 +163,33 @@ private:
// Private Data // Private Data
//- Backend output
autoPtr<glTF::sceneWriter> writer_;
//- Flag to animate - for particle tracks only //- Flag to animate - for particle tracks only
bool animate_; bool animate_;
//- Flag to add field colours //- Flag to add field colours
bool colour_; bool colour_;
//- Animation colour option
fieldOption animateColourOption_;
//- Animation colour field name
word animateColourName_;
//- Animation colour value
vector animateColourValue_;
//- Local field information //- Local field information
const dictionary fieldInfoDict_; const dictionary fieldInfoDict_;
//- Animation information //- Animation information
const dictionary animationDict_; const dictionary animationDict_;
//- The mesh indices in glTF scene
labelList meshes_;
// Private Member Functions // Private Member Functions
@ -184,103 +202,117 @@ private:
//- Return the named min/max field limits (from sub-dictionary) //- Return the named min/max field limits (from sub-dictionary)
scalarMinMax getFieldLimits(const word& fieldName) const; scalarMinMax getFieldLimits(const word& fieldName) const;
//- Setup animation colour or field to search for
void setupAnimationColour();
//- Return the alpha field for mesh values //- Return the alpha field for mesh values
tmp<scalarField> getAlphaField(const dictionary& dict) const; tmp<scalarField> getAlphaField(const dictionary& dict) const;
//- Return the animation colour when animating tracks
vector getTrackAnimationColour //- Templated write operation (static tracks)
template<class Type>
fileName writeTemplate
( (
const colourTable& colours, const word& fieldName,
const wordList& valueSetNames, const UPtrList<const Field<Type>>& fieldPtrs
const List<List<Field<Type>>>& valueSets, );
const label tracki
) const; //- Write animated tracks
template<class Type>
fileName writeTemplate_animate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName, //!< Name of field
const Field<Type>& vals //!< Local field values to write
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
);
public: public:
//- Runtime type information //- Runtime type information (no debug)
TypeName("gltf"); TypeNameNoDebug("gltf");
// Constructors // Constructors
//- Default construct //- Default construct
gltfSetWriter(); gltfWriter();
//- Construct from dictionary //- Default construct with specified options
explicit gltfSetWriter(const dictionary& dict); explicit gltfWriter(const dictionary& options);
//- Construct from components
gltfWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Construct from components
gltfWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Destructor //- Destructor. Calls close()
virtual ~gltfSetWriter() = default; virtual ~gltfWriter();
// Member Functions // Member Functions
//- Return the file name //- Expected (characteristic) output file name - information only
virtual fileName getFileName virtual fileName path() const; // override
(
const coordSet&,
const wordList&
) const;
//- Write //- Close and reset, clears backend.
virtual void write virtual void close(bool force = false); // override
(
const coordSet&,
const wordList&,
const List<const Field<Type>*>&,
Ostream&
) const;
//- Write tracks (main entry point) //- Begin time step. Clears existing backend.
virtual void write virtual void beginTime(const Time& t); // override
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>&,
const wordList& valueSetNames,
const List<List<Field<Type>>>&,
Ostream&
) const;
//- Write animated tracks //- Begin time step. Clears existing backend.
virtual void writeAnimateTracks virtual void beginTime(const instant& inst); // override
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const;
//- Write static tracks //- End time step. Clears existing backend.
virtual void writeStaticTracks virtual void endTime(); // override
(
const bool writeTracks,
const List<scalarField>& times, // Write
const PtrList<coordSet>& tracks,
const wordList& valueSetNames, declareCoordSetWriterWriteMethod(label);
const List<List<Field<Type>>>& valueSets, declareCoordSetWriterWriteMethod(scalar);
Ostream& declareCoordSetWriterWriteMethod(vector);
) const; declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
}; };
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace coordSetWriters
} // End namespace Foam } // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "gltfCoordSetWriter.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif #endif
// ************************************************************************* // // ************************************************************************* //

View File

@ -1,39 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "gltfSetWriter.H"
#include "writers.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makeSetWriters(gltfSetWriter);
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2021 OpenCFD Ltd. Copyright (C) 2017-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,135 +26,239 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "gnuplotSetWriter.H" #include "gnuplotCoordSetWriter.H"
#include "coordSet.H" #include "coordSet.H"
#include "fileName.H" #include "fileName.H"
#include "OFstream.H" #include "OFstream.H"
#include "OSspecific.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
defineTypeName(gnuplotWriter);
addToRunTimeSelectionTable(coordSetWriter, gnuplotWriter, word);
addToRunTimeSelectionTable(coordSetWriter, gnuplotWriter, wordDict);
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Implementation
#include "gnuplotCoordSetWriterImpl.C"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type> Foam::coordSetWriters::gnuplotWriter::gnuplotWriter()
Foam::gnuplotSetWriter<Type>::gnuplotSetWriter()
: :
writer<Type>() coordSetWriter(),
{} streamOpt_(),
precision_(IOstream::defaultPrecision())
{
buffering_ = true;
}
template<class Type> Foam::coordSetWriters::gnuplotWriter::gnuplotWriter(const dictionary& options)
Foam::gnuplotSetWriter<Type>::gnuplotSetWriter(const dictionary& dict)
: :
writer<Type>(dict) coordSetWriter(options),
{} streamOpt_
(
IOstream::ASCII,
IOstream::compressionEnum("compression", options)
),
precision_
(
options.getOrDefault("precision", IOstream::defaultPrecision())
)
{
buffering_ = options.getOrDefault("buffer", true);
}
Foam::coordSetWriters::gnuplotWriter::gnuplotWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options
)
:
gnuplotWriter(options)
{
open(coords, outputPath);
}
Foam::coordSetWriters::gnuplotWriter::gnuplotWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options
)
:
gnuplotWriter(options)
{
open(tracks, outputPath);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coordSetWriters::gnuplotWriter::~gnuplotWriter()
{
close();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> bool Foam::coordSetWriters::gnuplotWriter::buffering(const bool on)
Foam::fileName Foam::gnuplotSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
{ {
return this->getBaseName(points, valueSetNames) + ".gplt"; const bool old(buffering_);
buffering_ = on;
return old;
}
Foam::fileName Foam::coordSetWriters::gnuplotWriter::path() const
{
// 1) rootdir/<TIME>/setName.{gplt}
// 2) rootdir/setName.{gplt}
return getExpectedPath("gplt");
}
bool Foam::coordSetWriters::gnuplotWriter::writeBuffered()
{
if (coords_.empty())
{
clearBuffers();
return false;
}
// Field:
// 1) rootdir/<TIME>/setName.gplt
// 2) rootdir/setName.gplt
fileName outputFile = path();
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
OFstream os(outputFile, streamOpt_);
os.precision(precision_);
os << "set term pngcairo" << nl
<< "set output \"" << outputFile.nameLessExt() << ".png\"" << nl;
label nplots = 0;
do
{
#undef doLocalCode
#define doLocalCode(Type) \
for (const word& fldName : Type##Names_) \
{ \
os << (nplots++ ? ", \\" : "plot \\") << nl; \
os << " '-' title \"" << fldName << "\" with lines"; \
}
doLocalCode(label);
doLocalCode(scalar);
doLocalCode(vector);
doLocalCode(sphericalTensor);
doLocalCode(symmTensor);
doLocalCode(tensor);
#undef doLocalCode
}
while (false);
os << nl << nl;
if (nplots)
{
#undef doLocalCode
#define doLocalCode(Type) \
for (const Field<Type>& fld : Type##Fields_) \
{ \
writeTable(os, coords_[0], fld, " \t"); \
os << "end_data" << nl << nl; \
}
doLocalCode(label);
doLocalCode(scalar);
doLocalCode(vector);
doLocalCode(sphericalTensor);
doLocalCode(symmTensor);
doLocalCode(tensor);
#undef doLocalCode
}
os << "# end plot" << nl;
clearBuffers();
return true;
} }
template<class Type> template<class Type>
void Foam::gnuplotSetWriter<Type>::write Foam::fileName Foam::coordSetWriters::gnuplotWriter::writeTemplate
( (
const coordSet& points, const word& fieldName,
const wordList& valueSetNames, const Field<Type>& values
const List<const Field<Type>*>& valueSets, )
Ostream& os
) const
{ {
os << "set term postscript color" << nl checkOpen();
<< "set output \"" << points.name() << ".ps\"" << nl; if (coords_.empty())
// Set secondary Y axis if using two columns. Falls back to same
// values if both on same scale. However, ignore if more columns.
if (valueSetNames.size() == 2)
{ {
os << "set ylabel \"" << valueSetNames[0] << "\"" << nl return fileName::null;
<< "set y2label \"" << valueSetNames[1] << "\"" << nl
<< "set ytics nomirror" << nl << "set y2tics" << nl;
} }
os << "plot"; if (useTracks_ || !buffering_)
forAll(valueSets, i)
{ {
if (i) UPtrList<const Field<Type>> fieldPtrs(repackageFields(values));
{ return writeTemplate(fieldName, fieldPtrs);
os << ',';
} }
os << " \"-\" title \"" << valueSetNames[i] << "\" with lines";
if (valueSetNames.size() == 2) // Buffering version
{ appendField(fieldName, values);
os << " axes x1y" << (i+1) ;
}
}
os << nl;
forAll(valueSets, i) return path();
{
this->writeTable(points, *valueSets[i], os);
os << "e" << nl;
}
} }
template<class Type> template<class Type>
void Foam::gnuplotSetWriter<Type>::write Foam::fileName Foam::coordSetWriters::gnuplotWriter::writeTemplate
( (
const bool writeTracks, const word& fieldName,
const List<scalarField>& times, const List<Field<Type>>& fieldValues
const PtrList<coordSet>& tracks, )
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
{ {
if (valueSets.size() != valueSetNames.size()) checkOpen();
if (coords_.empty())
{ {
FatalErrorInFunction return fileName::null;
<< "Number of variables:" << valueSetNames.size() << endl
<< "Number of valueSets:" << valueSets.size()
<< exit(FatalError);
}
if (tracks.size() > 0)
{
os << "set term postscript color" << nl
<< "set output \"" << tracks[0].name() << ".ps\"" << nl;
forAll(tracks, trackI)
{
os << "plot";
forAll(valueSets, i)
{
if (i != 0)
{
os << ',';
} }
os << " \"-\" title \"" << valueSetNames[i] << "\" with lines"; UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
return writeTemplate(fieldName, fieldPtrs);
} }
os << nl;
forAll(valueSets, i)
{ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
this->writeTable(tracks[trackI], valueSets[i][trackI], os);
os << "e" << nl; // Field writing methods
} defineCoordSetWriterWriteFields(Foam::coordSetWriters::gnuplotWriter);
}
}
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -0,0 +1,179 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::coordSetWriters::gnuplotWriter
Description
A coordSet(s) writer in gnuplot format.
The formatOptions for gnuplot:
\table
Property | Description | Required | Default
buffer | Use buffered output | no | true
compression | Use file compression | no | false
precision | Write precision in ascii | no | same as IOstream
\endtable
When called with a single coordSet, will buffer the output of
all fields and output together in the order of label/scalar/vector/...
each of which is sorted alphabetically according to the field name.
When called as a track writer (eg, with multiple coordSets),
will emit one file per field.
SourceFiles
gnuplotCoordSetWriter.C
gnuplotCoordSetWriterImpl.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_gnuplotWriter_H
#define Foam_coordSetWriters_gnuplotWriter_H
#include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
/*---------------------------------------------------------------------------*\
Class gnuplotWriter Declaration
\*---------------------------------------------------------------------------*/
class gnuplotWriter
:
public coordSetWriter
{
// Private Data
//- Output stream option
IOstreamOption streamOpt_;
//- ASCII write precision
unsigned precision_;
// Private Member Functions
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName, //!< Name of field
const Field<Type>& vals //!< Local field values to write
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
);
protected:
// Protected Member Functions
//- Write buffered data
virtual bool writeBuffered();
public:
//- Runtime type information (no debug)
TypeNameNoDebug("gnuplot");
// Constructors
//- Default construct
gnuplotWriter();
//- Default construct with specified options
explicit gnuplotWriter(const dictionary& options);
//- Construct from components
gnuplotWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Construct from components
gnuplotWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Destructor. Calls close()
virtual ~gnuplotWriter();
// Member Functions
//- Enable/disable internal buffering
virtual bool buffering(const bool on); // override
//- Characteristic output file name - information only
virtual fileName path() const; // override
declareCoordSetWriterWriteMethod(label);
declareCoordSetWriterWriteMethod(scalar);
declareCoordSetWriterWriteMethod(vector);
declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // Endnamespace coordSetWriters
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "IOmanip.H"
#include "OFstream.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::coordSetWriters::gnuplotWriter::writeTemplate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
)
{
if (coords_.size() != fieldPtrs.size())
{
FatalErrorInFunction
<< "Attempted to write field: " << fieldName
<< " (" << fieldPtrs.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError);
}
///const label nPoints = numPoints();
// Field: rootdir/<TIME>/<field>_setName.gplt
fileName outputFile = getFieldPrefixedPath(fieldName, "gplt");
if (verbose_)
{
Info<< "Writing field " << fieldName;
Info<< " to " << outputFile << endl;
}
// Master only
{
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
OFstream os(outputFile, streamOpt_);
os.precision(precision_);
os << "set term pngcairo" << nl
<< "set output \"" << outputFile.nameLessExt() << ".png\"" << nl;
// Header
{
os << "plot \\" << nl;
os << " '-' title \"" << fieldName << "\" with lines";
os << nl << nl;
}
forAll(coords_, tracki)
{
writeTable(os, coords_[tracki], fieldPtrs[tracki], " \t");
}
os << "end_data" << nl << nl;
os << "# end plot" << nl;
}
wroteGeom_ = true;
return outputFile;
}
// ************************************************************************* //

View File

@ -1,117 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::gnuplotSetWriter
Description
SourceFiles
gnuplotCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_gnuplotWriter_H
#define Foam_coordSetWriters_gnuplotWriter_H
#include "writer.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class gnuplotSetWriter Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class gnuplotSetWriter
:
public writer<Type>
{
public:
//- Runtime type information
TypeName("gnuplot");
// Constructors
//- Default construct
gnuplotSetWriter();
//- Construct with dictionary
explicit gnuplotSetWriter(const dictionary& dict);
//- Destructor
virtual ~gnuplotSetWriter() = default;
// Member Functions
virtual fileName getFileName
(
const coordSet&,
const wordList&
) const;
virtual void write
(
const coordSet&,
const wordList&,
const List<const Field<Type>*>&,
Ostream&
) const;
virtual void write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "gnuplotCoordSetWriter.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,39 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "gnuplotSetWriter.H"
#include "writers.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makeSetWriters(gnuplotSetWriter);
}
// ************************************************************************* //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2018-2021 OpenCFD Ltd. Copyright (C) 2018-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -25,175 +25,198 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "nastranSetWriter.H" #include "nastranCoordSetWriter.H"
#include "coordSet.H" #include "coordSet.H"
#include "IOmanip.H" #include "IOmanip.H"
#include "OFstream.H"
#include "OSspecific.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
defineTypeName(nastranWriter);
addToRunTimeSelectionTable(coordSetWriter, nastranWriter, word);
addToRunTimeSelectionTable(coordSetWriter, nastranWriter, wordDict);
}
}
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
template<class Type>
static inline void putValue(Ostream& os, const Type& value, const int width)
{
if (width) os << setw(width);
os << value;
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::Ostream& Foam::coordSetWriters::nastranWriter::writeKeyword
(
Ostream& os,
const word& keyword
) const
{
return fileFormats::NASCore::writeKeyword(os, keyword, writeFormat_);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type> Foam::coordSetWriters::nastranWriter::nastranWriter()
Foam::nastranSetWriter<Type>::nastranSetWriter()
: :
writer<Type>() coordSetWriter(),
{} writeFormat_(fieldFormat::FREE),
separator_()
{
if (writeFormat_ == fieldFormat::FREE)
{
separator_ = ",";
}
}
template<class Type> Foam::coordSetWriters::nastranWriter::nastranWriter(const dictionary& options)
Foam::nastranSetWriter<Type>::nastranSetWriter(const dictionary& dict)
: :
writer<Type>(dict) coordSetWriter(options),
{} writeFormat_
(
fileFormats::NASCore::fieldFormatNames.getOrDefault
(
"format",
options,
fieldFormat::FREE
)
),
separator_()
{
if (writeFormat_ == fieldFormat::FREE)
{
separator_ = ",";
}
}
Foam::coordSetWriters::nastranWriter::nastranWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options
)
:
nastranWriter(options)
{
open(coords, outputPath);
}
Foam::coordSetWriters::nastranWriter::nastranWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options
)
:
nastranWriter(options)
{
open(tracks, outputPath);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coordSetWriters::nastranWriter::~nastranWriter()
{
close();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> Foam::fileName Foam::coordSetWriters::nastranWriter::path() const
Foam::fileName Foam::nastranSetWriter<Type>::getFileName {
// 1) rootdir/<TIME>/setName.{nas}
// 2) rootdir/setName.{nas}
return getExpectedPath("nas");
}
void Foam::coordSetWriters::nastranWriter::writeGeometry
( (
const coordSet& points, Ostream& os,
const wordList& valueSetNames label nTracks
) const ) const
{ {
return this->getBaseName(points, valueSetNames) + ".nas"; if (coords_.empty())
}
template<class Type>
void Foam::nastranSetWriter<Type>::write
(
const coordSet& points,
const wordList& valueSetNames,
const List<const Field<Type>*>& valueSets,
Ostream& os
) const
{
os << "TITLE=OpenFOAM "
<< this->getBaseName(points, valueSetNames).c_str()
<< nl
<< "$" << nl
<< "BEGIN BULK" << nl;
forAll(points, pointi)
{
fileFormats::NASCore::writeCoord
(
os, points[pointi], pointi, fieldFormat::FREE
);
}
if (false)
{
// Single track with multiple segments
const label nEdges = points.size()-1;
for (label edgei = 0; edgei < nEdges; ++edgei)
{
fileFormats::NASCore::writeKeyword
(
os,
"PLOTEL",
fieldFormat::FREE
);
// fieldFormat::SHORT
//os.setf(std::ios_base::right);
//os << setw(8) << edgei+1
// << setw(8) << edgei+1
// << setw(8) << edgei+2
// << nl;
//os.unsetf(std::ios_base::right);
// fieldFormat::FREE
os << ',' << edgei+1
<< ',' << edgei+1
<< ',' << edgei+2
<< nl;
}
}
os << "ENDDATA" << nl;
}
template<class Type>
void Foam::nastranSetWriter<Type>::write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
{
if (valueSets.size() != valueSetNames.size())
{
FatalErrorInFunction
<< "Number of variables:" << valueSetNames.size() << endl
<< "Number of valueSets:" << valueSets.size()
<< exit(FatalError);
}
if (tracks.empty())
{ {
return; return;
} }
os << "TITLE=OpenFOAM " // Field width (SHORT, LONG formats)
<< this->getBaseName(tracks[0], valueSetNames).c_str() const int width =
<< nl (
<< "$" << nl writeFormat_ == fieldFormat::SHORT ? 8
<< "BEGIN BULK" << nl; : writeFormat_ == fieldFormat::LONG ? 16
: 0
);
// label nTracks = tracks.size(); // Separator char (FREE format)
// label nPoints = 0; const char sep = (writeFormat_ == fieldFormat::FREE ? ',' : '\0');
// forAll(tracks, i)
// { // Write points
// nPoints += tracks[i].size(); os << '$' << nl
// } << "$ Points" << nl
<< '$' << nl;
label globalPointi = 0; label globalPointi = 0;
for (const coordSet& points : tracks) for (const coordSet& coords : coords_)
{ {
for (const point& p : points) for (const point& p : coords)
{ {
fileFormats::NASCore::writeCoord fileFormats::NASCore::writeCoord
( (
os, p, globalPointi, fieldFormat::FREE os, p, globalPointi, writeFormat_
); );
++globalPointi; ++globalPointi;
} }
} }
if (writeTracks) if (nTracks)
{ {
// Write ids of track points to file // Write ids of track points to file
globalPointi = 0;
label globalEdgei = 0; label globalEdgei = 0;
label globalPointi = 0;
for (const coordSet& points : tracks) for (label tracki = 0; tracki < nTracks; ++tracki)
{ {
const label nEdges = points.size()-1; const label nEdges = (coords_[tracki].size() - 1);
for (label edgei = 0; edgei < nEdges; ++edgei) for (label edgei = 0; edgei < nEdges; ++edgei)
{ {
fileFormats::NASCore::writeKeyword writeKeyword(os, "PLOTEL");
( if (sep) os << sep;
os,
"PLOTEL",
fieldFormat::FREE
);
// fieldFormat::SHORT putValue(os, globalEdgei+1, width); // Edge id
//os.setf(std::ios_base::right); if (sep) os << sep;
//os << setw(8) << globalEdgei+1
// << setw(8) << globalPointi+1
// << setw(8) << globalPointi+2
// << nl;
//os.unsetf(std::ios_base::right);
// fieldFormat::FREE putValue(os, globalPointi+1, width);
os << ',' << globalEdgei+1 if (sep) os << sep;
<< ',' << globalPointi+1
<< ',' << globalPointi+2 putValue(os, globalPointi+2, width);
<< nl; os << nl;
++globalEdgei; ++globalEdgei;
++globalPointi; ++globalPointi;
@ -201,8 +224,100 @@ void Foam::nastranSetWriter<Type>::write
} }
} }
os << "ENDDATA" << nl; wroteGeom_ = true;
} }
template<class Type>
Foam::fileName Foam::coordSetWriters::nastranWriter::writeTemplate
(
const word& fieldName,
const Field<Type>& values
)
{
checkOpen();
if (coords_.empty())
{
return fileName::null;
}
fileName outputFile = path();
if (!wroteGeom_)
{
if (verbose_)
{
Info<< "Writing nastran geometry to " << outputFile << endl;
}
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
OFstream os(outputFile);
fileFormats::NASCore::setPrecision(os, writeFormat_);
os << "TITLE=OpenFOAM " << outputFile.nameLessExt()
<< " geometry" << nl
<< "BEGIN BULK" << nl;
writeGeometry(os, (useTracks_ ? coords_.size() : 0));
os << "ENDDATA" << nl;
}
return outputFile;
}
template<class Type>
Foam::fileName Foam::coordSetWriters::nastranWriter::writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
)
{
checkOpen();
if (coords_.empty())
{
return fileName::null;
}
fileName outputFile = path();
if (!wroteGeom_)
{
if (verbose_)
{
Info<< "Writing nastran geometry to " << outputFile << endl;
}
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
OFstream os(outputFile);
fileFormats::NASCore::setPrecision(os, writeFormat_);
os << "TITLE=OpenFOAM " << outputFile.nameLessExt()
<< " geometry" << nl
<< "BEGIN BULK" << nl;
writeGeometry(os, coords_.size());
os << "ENDDATA" << nl;
}
return outputFile;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Field writing methods
defineCoordSetWriterWriteFields(Foam::coordSetWriters::nastranWriter);
// ************************************************************************* // // ************************************************************************* //

View File

@ -0,0 +1,178 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::coordSetWriters::nastranWriter
Description
Write coordSet(s) as Nastran plot lines. Does not do field data.
The formatOptions for nastran:
\table
Property | Description | Required | Default
format | short / long / free | no | free
\endtable
\section Output file locations
The \c rootdir normally corresponds to something like
\c postProcessing/\<name\>
\subsection Geometry
\verbatim
rootdir
`-- <time>
|-- setName0.{nas}
`-- setName1.{nas}
\endverbatim
SourceFiles
nastranCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_nastranWriter_H
#define Foam_coordSetWriters_nastranWriter_H
#include "coordSetWriter.H"
#include "NASCore.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
/*---------------------------------------------------------------------------*\
Class nastranWriter Declaration
\*---------------------------------------------------------------------------*/
class nastranWriter
:
public coordSetWriter
{
public:
//- File field formats
using fieldFormat = Foam::fileFormats::NASCore::fieldFormat;
//- Output load format
using loadFormat = Foam::fileFormats::NASCore::loadFormat;
private:
//- Field format (width and separator)
fieldFormat writeFormat_;
//- Separator used for free format
word separator_;
// Private Member Functions
//- Write the formatted keyword to the output stream
Ostream& writeKeyword(Ostream& os, const word& keyword) const;
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName, //!< Name of field
const Field<Type>& values //!< Local field values to write
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
);
//- Write geometry to file.
void writeGeometry(Ostream& os, label nTracks) const;
public:
//- Runtime type information (no debug)
TypeNameNoDebug("nastran");
// Constructors
//- Default construct
nastranWriter();
//- Default construct with specified options
explicit nastranWriter(const dictionary& options);
//- Construct from components
nastranWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Construct from components
nastranWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Destructor. Calls close()
virtual ~nastranWriter();
// Member Functions
//- Characteristic output file name - information only
virtual fileName path() const; // override
declareCoordSetWriterWriteMethod(label);
declareCoordSetWriterWriteMethod(scalar);
declareCoordSetWriterWriteMethod(vector);
declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace coordSetWriters
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,134 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::nastranSetWriter
Description
Line format in Nastran (currently hardcoded to 'free' format)
Does not do field data.
SourceFiles
nastranCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_nastranWriter_H
#define Foam_coordSetWriters_nastranWriter_H
#include "writer.H"
#include "NASCore.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class nastranSetWriter Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class nastranSetWriter
:
public writer<Type>
{
// Private Member Functions
//- Write the formatted keyword to the output stream
Ostream& writeKeyword
(
Ostream& os,
const word& keyword
) const;
public:
//- File field formats
using fieldFormat = Foam::fileFormats::NASCore::fieldFormat;
//- Runtime type information
TypeName("nastran");
// Constructors
//- Default construct
nastranSetWriter();
//- Construct with dictionary
explicit nastranSetWriter(const dictionary& dict);
//- Destructor
virtual ~nastranSetWriter() = default;
// Member Functions
virtual fileName getFileName
(
const coordSet&,
const wordList&
) const;
virtual void write
(
const coordSet&,
const wordList&,
const List<const Field<Type>*>&,
Ostream&
) const;
virtual void write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "nastranCoordSetWriter.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,39 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "nastranSetWriter.H"
#include "writers.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makeSetWriters(nastranSetWriter);
}
// ************************************************************************* //

View File

@ -0,0 +1,157 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "nullCoordSetWriter.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
defineTypeName(nullWriter);
addToRunTimeSelectionTable(coordSetWriter, nullWriter, word);
addToRunTimeSelectionTable(coordSetWriter, nullWriter, wordDict);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::coordSetWriters::nullWriter::nullWriter()
:
coordSetWriter()
{}
Foam::coordSetWriters::nullWriter::nullWriter(const dictionary& options)
:
nullWriter()
{}
Foam::coordSetWriters::nullWriter::nullWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options
)
:
nullWriter()
{}
Foam::coordSetWriters::nullWriter::nullWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options
)
:
nullWriter()
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coordSetWriters::nullWriter::~nullWriter()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::coordSetWriters::nullWriter::enabled() const
{
return false;
}
bool Foam::coordSetWriters::nullWriter::buffering() const
{
return false;
}
bool Foam::coordSetWriters::nullWriter::needsUpdate() const
{
return false;
}
bool Foam::coordSetWriters::nullWriter::wroteData() const
{
return true;
}
void Foam::coordSetWriters::nullWriter::setCoordinates
(
const coordSet* coords
)
{}
void Foam::coordSetWriters::nullWriter::setCoordinates
(
const coordSet& coords
)
{}
void Foam::coordSetWriters::nullWriter::setTracks
(
const UPtrList<coordSet>& tracks
)
{}
Foam::fileName Foam::coordSetWriters::nullWriter::path() const
{
return fileName();
}
void Foam::coordSetWriters::nullWriter::open(const fileName& outputPath)
{}
// Foam::fileName Foam::coordSetWriters::nullWriter::write()
// {
// wroteGeom_ = true;
// return fileName::null;
// }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Field writing methods
defineCoordSetWriterWriteFields(Foam::coordSetWriters::nullWriter);
// ************************************************************************* //

View File

@ -0,0 +1,177 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::coordSetWriters::nullWriter
Description
A coordSet(s) writer with suppressed output.
SourceFiles
nullCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_nullWriter_H
#define Foam_coordSetWriters_nullWriter_H
#include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
/*---------------------------------------------------------------------------*\
Class nullWriter Declaration
\*---------------------------------------------------------------------------*/
class nullWriter
:
public coordSetWriter
{
// Private Member Functions
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName, //!< Name of field
const Field<Type>& values //!< Local field values to write
)
{
return fileName();
}
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
)
{
return fileName();
}
public:
//- Runtime type information (no debug)
TypeNameNoDebug("none");
// Constructors
//- Default construct
nullWriter();
//- Construct with some output options
explicit nullWriter(const dictionary& options);
//- Construct from components
nullWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Construct from components
nullWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Destructor
virtual ~nullWriter();
// Member Functions
// Capability
//- False: The null writer is never enabled, which lets the caller
//- skip various (possibly expensive) preparatory operations.
virtual bool enabled() const;
//- False: no internal buffering possible
virtual bool buffering() const; // override
//- False: never needs an update.
virtual bool needsUpdate() const;
//- True: like a /dev/null device.
virtual bool wroteData() const;
// Content Association
//- Set coordinates (no-op).
virtual void setCoordinates(const coordSet*); // override
//- Set coordinates (no-op).
virtual void setCoordinates(const coordSet&); // override
//- Set tracks (no-op).
virtual void setTracks(const UPtrList<coordSet>&); // override
// Output
//- Characteristic output file name - information only.
//- Always an empty fileName
virtual fileName path() const; // override
//- Open for output on specified path, using existing content (no-op)
virtual void open(const fileName& outputPath); // override
// Member Functions
declareCoordSetWriterWriteMethod(label);
declareCoordSetWriterWriteMethod(scalar);
declareCoordSetWriterWriteMethod(vector);
declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace coordSetWriters
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd. Copyright (C) 2021-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,94 +26,199 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "rawSetWriter.H" #include "rawCoordSetWriter.H"
#include "coordSet.H" #include "coordSet.H"
#include "fileName.H" #include "fileName.H"
#include "OFstream.H" #include "OFstream.H"
#include "OSspecific.H"
#include "stringOps.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
defineTypeName(rawWriter);
addToRunTimeSelectionTable(coordSetWriter, rawWriter, word);
addToRunTimeSelectionTable(coordSetWriter, rawWriter, wordDict);
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Implementation
#include "rawCoordSetWriterImpl.C"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type> Foam::coordSetWriters::rawWriter::rawWriter()
Foam::rawSetWriter<Type>::rawSetWriter()
: :
writer<Type>() coordSetWriter(),
{} streamOpt_(),
precision_(IOstream::defaultPrecision())
{
buffering_ = true;
}
template<class Type> Foam::coordSetWriters::rawWriter::rawWriter(const dictionary& options)
Foam::rawSetWriter<Type>::rawSetWriter(const dictionary& dict)
: :
writer<Type>(dict) coordSetWriter(options),
{} streamOpt_
(
IOstream::ASCII,
IOstream::compressionEnum("compression", options)
),
precision_
(
options.getOrDefault("precision", IOstream::defaultPrecision())
)
{
buffering_ = options.getOrDefault("buffer", true);
}
Foam::coordSetWriters::rawWriter::rawWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options
)
:
rawWriter(options)
{
open(coords, outputPath);
}
Foam::coordSetWriters::rawWriter::rawWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options
)
:
rawWriter(options)
{
open(tracks, outputPath);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coordSetWriters::rawWriter::~rawWriter()
{
close();
}
// * * * * * * * * * * * * * * * * * Controls * * * * * * * * * * * * * * * //
bool Foam::coordSetWriters::rawWriter::buffering(const bool on)
{
const bool old(buffering_);
buffering_ = on;
return old;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> Foam::fileName Foam::coordSetWriters::rawWriter::path() const
Foam::fileName Foam::rawSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
{ {
return this->getBaseName(points, valueSetNames) + ".xy"; // Assume !useTracks_, otherwise too fragile
// 1) rootdir/<TIME>/setName.raw
// 2) rootdir/setName.raw
return getExpectedPath("xy"); // Traditionally 'xy', not 'raw'
}
bool Foam::coordSetWriters::rawWriter::writeBuffered()
{
if (coords_.empty())
{
clearBuffers();
return false;
}
const auto& coords = coords_[0];
// Field:
// 1) rootdir/<TIME>/setName.raw
// 2) rootdir/setName.raw
fileName outputFile = path();
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
OFstream os(outputFile, streamOpt_);
os.precision(precision_);
writeBufferContents(os, coords, " \t");
clearBuffers();
return true;
} }
template<class Type> template<class Type>
void Foam::rawSetWriter<Type>::write Foam::fileName Foam::coordSetWriters::rawWriter::writeTemplate
( (
const coordSet& points, const word& fieldName,
const wordList& valueSetNames, const Field<Type>& values
const List<const Field<Type>*>& valueSets, )
Ostream& os
) const
{ {
// Collect sets into columns checkOpen();
List<const List<Type>*> columns(valueSets.size()); if (coords_.empty())
forAll(valueSets, i)
{ {
columns[i] = valueSets[i]; return fileName::null;
} }
this->writeTable(points, columns, os); if (useTracks_ || !buffering_)
{
UPtrList<const Field<Type>> fieldPtrs(repackageFields(values));
return writeTemplate(fieldName, fieldPtrs);
}
// Buffering version
appendField(fieldName, values);
return path();
} }
template<class Type> template<class Type>
void Foam::rawSetWriter<Type>::write Foam::fileName Foam::coordSetWriters::rawWriter::writeTemplate
( (
const bool writeTracks, const word& fieldName,
const List<scalarField>& times, const List<Field<Type>>& fieldValues
const PtrList<coordSet>& tracks, )
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
{ {
if (valueSets.size() != valueSetNames.size()) checkOpen();
if (coords_.empty())
{ {
FatalErrorInFunction return fileName::null;
<< "Number of variables:" << valueSetNames.size() << endl }
<< "Number of valueSets:" << valueSets.size() useTracks_ = true; // Extra safety
<< exit(FatalError);
UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
return writeTemplate(fieldName, fieldPtrs);
} }
List<const List<Type>*> columns(valueSets.size());
forAll(tracks, trackI) // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
{
// Collect sets into columns
forAll(valueSets, i)
{
columns[i] = &valueSets[i][trackI];
}
this->writeTable(tracks[trackI], columns, os); // Field writing methods
os << nl << nl; defineCoordSetWriterWriteFields(Foam::coordSetWriters::rawWriter);
}
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -0,0 +1,178 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::coordSetWriters::rawWriter
Description
A coordSet(s) in raw format.
The formatOptions for raw:
\table
Property | Description | Required | Default
buffer | Use buffered output | no | true
compression | Use file compression | no | false
precision | Write precision in ascii | no | same as IOstream
\endtable
When called with a single coordSet, will buffer the output of
all fields and output together in the order of label/scalar/vector/...
each of which is sorted alphabetically according to the field name.
When called as a track writer (eg, with multiple coordSets),
will emit one file per field.
SourceFiles
rawCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_rawWriter_H
#define Foam_coordSetWriters_rawWriter_H
#include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
/*---------------------------------------------------------------------------*\
Class rawWriter Declaration
\*---------------------------------------------------------------------------*/
class rawWriter
:
public coordSetWriter
{
// Private Data
//- Output stream option
IOstreamOption streamOpt_;
//- ASCII write precision
unsigned precision_;
// Private Member Functions
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName, //!< Name of field
const Field<Type>& vals //!< Local field values to write
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName, //!< Name of field
const List<Field<Type>>& fieldValues
);
protected:
// Protected Member Functions
//- Write buffered data
virtual bool writeBuffered();
public:
//- Runtime type information (no debug)
TypeNameNoDebug("raw");
// Constructors
//- Default construct
rawWriter();
//- Default construct with specified options
explicit rawWriter(const dictionary& options);
//- Construct from components
rawWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Construct from components
rawWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Destructor. Calls close()
virtual ~rawWriter();
// Member Functions
//- Enable/disable internal buffering
virtual bool buffering(const bool on); // override
//- Characteristic output file name - information only
// \warning incorrect for unbuffered or track output!
virtual fileName path() const; // override
declareCoordSetWriterWriteMethod(label);
declareCoordSetWriterWriteMethod(scalar);
declareCoordSetWriterWriteMethod(vector);
declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace coordSetWriters
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,149 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "IOmanip.H"
#include "OFstream.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Output coordinate header
static void writeCoordHeader
(
Ostream& os,
const coordSet& coords,
const label count
)
{
if (coords.hasVectorAxis())
{
os << "POINT_DATA" << ' ' << count << nl;
os << "# x y z";
}
else
{
word axisName(coords.axis());
word dataName(stringOps::upper(axisName) + "_DATA");
os << dataName << ' ' << count << nl;
os << "# " << axisName;
}
}
// Write field name, use named components for VectorSpace
template<class Type>
static inline void writeHeader(Ostream& os, const word& fieldName)
{
os << ' '; // Extra space
const auto nCmpts(pTraits<Type>::nComponents);
if (pTraits<Type>::rank || nCmpts > 1)
{
for (direction d = 0; d < nCmpts; ++d)
{
os << ' ' << fieldName
<< '_' << pTraits<Type>::componentNames[d];
}
}
else
{
os << ' ' << fieldName;
}
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::coordSetWriters::rawWriter::writeTemplate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
)
{
if (coords_.size() != fieldPtrs.size())
{
FatalErrorInFunction
<< "Attempted to write field: " << fieldName
<< " (" << fieldPtrs.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError);
}
label nPoints = 0;
for (const auto& pts : coords_)
{
nPoints += pts.size();
}
// Field: rootdir/<TIME>/<field>_setName.raw
fileName outputFile = getFieldPrefixedPath(fieldName, "raw");
if (verbose_)
{
Info<< "Writing field " << fieldName;
Info<< " to " << outputFile << endl;
}
// Master only
{
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
OFstream os(outputFile, streamOpt_);
os.precision(precision_);
// Header
{
os << "# " << fieldName << " ";
writeCoordHeader(os, coords_[0], nPoints);
writeHeader<Type>(os, fieldName);
os << nl;
}
forAll(coords_, tracki)
{
writeTable(os, coords_[tracki], fieldPtrs[tracki], " ");
}
}
wroteGeom_ = true;
return outputFile;
}
// ************************************************************************* //

View File

@ -1,117 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::rawSetWriter
Description
SourceFiles
rawCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_rawWriter_H
#define Foam_coordSetWriters_rawWriter_H
#include "writer.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class rawSetWriter Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class rawSetWriter
:
public writer<Type>
{
public:
//- Runtime type information
TypeName("raw");
// Constructors
//- Default construct
rawSetWriter();
//- Construct with dictionary
explicit rawSetWriter(const dictionary& dict);
//- Destructor
virtual ~rawSetWriter() = default;
// Member Functions
virtual fileName getFileName
(
const coordSet&,
const wordList&
) const;
virtual void write
(
const coordSet&,
const wordList&,
const List<const Field<Type>*>&,
Ostream&
) const;
virtual void write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "rawCoordSetWriter.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,39 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "rawSetWriter.H"
#include "writers.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makeSetWriters(rawSetWriter);
}
// ************************************************************************* //

View File

@ -5,8 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2022 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,177 +25,310 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "vtkSetWriter.H" #include "vtkCoordSetWriter.H"
#include "coordSet.H" #include "coordSet.H"
#include "fileName.H" #include "fileName.H"
#include "OFstream.H" #include "foamVtkCoordSetWriter.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
defineTypeName(vtkWriter);
addToRunTimeSelectionTable(coordSetWriter, vtkWriter, word);
addToRunTimeSelectionTable(coordSetWriter, vtkWriter, wordDict);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type> Foam::coordSetWriters::vtkWriter::vtkWriter()
Foam::vtkSetWriter<Type>::vtkSetWriter()
: :
writer<Type>() coordSetWriter(),
fmtType_(static_cast<unsigned>(vtk::formatType::INLINE_BASE64)),
precision_(IOstream::defaultPrecision()),
writer_(nullptr)
{} {}
template<class Type> Foam::coordSetWriters::vtkWriter::vtkWriter
Foam::vtkSetWriter<Type>::vtkSetWriter(const dictionary& dict) (
const vtk::outputOptions& opts
)
: :
writer<Type>(dict) coordSetWriter(),
fmtType_(static_cast<unsigned>(opts.fmt())),
precision_(opts.precision()),
writer_(nullptr)
{} {}
Foam::coordSetWriters::vtkWriter::vtkWriter(const dictionary& options)
:
coordSetWriter(options),
fmtType_(static_cast<unsigned>(vtk::formatType::INLINE_BASE64)),
precision_
(
options.getOrDefault("precision", IOstream::defaultPrecision())
),
writer_(nullptr)
{
// format: ascii | binary
// legacy: true | false
vtk::outputOptions opts(vtk::formatType::INLINE_BASE64);
opts.ascii
(
IOstream::ASCII
== IOstream::formatEnum("format", options, IOstream::BINARY)
);
opts.legacy(options.getOrDefault("legacy", false));
// Convert back to raw data type
fmtType_ = static_cast<unsigned>(opts.fmt());
}
Foam::coordSetWriters::vtkWriter::vtkWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options
)
:
vtkWriter(options)
{
open(coords, outputPath);
}
Foam::coordSetWriters::vtkWriter::vtkWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options
)
:
vtkWriter(options)
{
open(tracks, outputPath);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coordSetWriters::vtkWriter::~vtkWriter()
{
close();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> Foam::fileName Foam::coordSetWriters::vtkWriter::path() const
Foam::fileName Foam::vtkSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
{ {
return this->getBaseName(points, valueSetNames) + ".vtk"; // 1) rootdir/<TIME>/setName.{vtk|vtp}
// 2) rootdir/setName.{vtk|vtp}
// From raw unsigned value to vtk::outputOptions
vtk::outputOptions opts(static_cast<vtk::formatType>(fmtType_));
return getExpectedPath(vtk::polyWriter::ext(opts));
} }
void Foam::coordSetWriters::vtkWriter::close(bool force)
{
writer_.clear();
coordSetWriter::close(force);
}
void Foam::coordSetWriters::vtkWriter::beginTime(const Time& t)
{
writer_.clear();
coordSetWriter::beginTime(t);
}
void Foam::coordSetWriters::vtkWriter::beginTime(const instant& inst)
{
writer_.clear();
coordSetWriter::beginTime(inst);
}
void Foam::coordSetWriters::vtkWriter::endTime()
{
writer_.clear();
coordSetWriter::endTime();
}
Foam::fileName Foam::coordSetWriters::vtkWriter::write()
{
checkOpen();
if (needsUpdate())
{
writer_.clear();
}
merge();
if (coords_.empty())
{
return fileName::null;
}
// From raw unsigned values to vtk::outputOptions
vtk::outputOptions opts(static_cast<vtk::formatType>(fmtType_), precision_);
// Geometry: rootdir/<TIME>/setName.{vtk|vtp}
fileName outputFile = getExpectedPath(vtk::polyWriter::ext(opts));
if (verbose_)
{
Info<< "Writing geometry to " << outputFile << endl;
}
if (!writer_ && true) // always (non-parallel)
{
UPtrList<const pointField> points(coords_.size());
forAll(coords_, tracki)
{
points.set(tracki, coords_.get(tracki));
}
writer_.reset
(
new vtk::coordSetWriter
(
points,
opts,
outputFile,
false // serial!
)
);
if (useTracks_ || coords_.size() > 1)
{
writer_->setElementType(vtk::coordSetWriter::LINE_ELEMENTS);
}
if (this->hasTime())
{
// Time name in title
writer_->setTime(currTime_);
writer_->writeTimeValue();
}
else
{
// Set name in title
writer_->beginFile(outputPath_.nameLessExt());
}
writer_->writeGeometry();
}
wroteGeom_ = true;
return outputFile;
}
// * * * * * * * * * * * * * * * Implementation * * * * * * * * * * * * * * * //
template<class Type> template<class Type>
void Foam::vtkSetWriter<Type>::write Foam::fileName Foam::coordSetWriters::vtkWriter::writeTemplate
( (
const coordSet& points, const word& fieldName,
const wordList& valueSetNames, const UPtrList<const Field<Type>>& fieldPtrs
const List<const Field<Type>*>& valueSets, )
Ostream& os
) const
{ {
os << "# vtk DataFile Version 2.0" << nl if (coords_.size() != fieldPtrs.size())
<< points.name() << nl
<< "ASCII" << nl
<< "DATASET POLYDATA" << nl
<< "POINTS " << points.size() << " double" << nl;
for (const point& pt : points)
{
os << float(pt.x()) << ' '
<< float(pt.y()) << ' '
<< float(pt.z()) << nl;
}
os << "POINT_DATA " << points.size() << nl
<< " FIELD attributes " << valueSetNames.size() << nl;
forAll(valueSetNames, setI)
{
os << valueSetNames[setI] << ' '
<< int(pTraits<Type>::nComponents) << ' '
<< points.size() << " float" << nl;
const Field<Type>& fld = *valueSets[setI];
forAll(fld, pointi)
{
if (pointi)
{
os << ' ';
}
writer<Type>::write(fld[pointi], os);
}
os << nl;
}
}
template<class Type>
void Foam::vtkSetWriter<Type>::write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
{
if (valueSets.size() != valueSetNames.size())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Number of variables:" << valueSetNames.size() << endl << "Attempted to write field: " << fieldName
<< "Number of valueSets:" << valueSets.size() << " (" << fieldPtrs.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError); << exit(FatalError);
} }
label nTracks = tracks.size(); // Open file, writing geometry (if required)
label nPoints = 0; fileName outputFile = this->write();
forAll(tracks, i)
if (!nFields_ && writer_->legacy())
{ {
nPoints += tracks[i].size(); // Emit error message, but attempt to recover anyhow
nFields_ = 1;
FatalErrorInFunction
<< "Using VTK legacy format, but did not define nFields!"
<< nl
<< "Assuming nFields=1 (may be incorrect) and continuing..."
<< nl
<< " Field " << fieldName << " to " << outputFile << nl;
Info<< FatalError;
Info<< endl;
} }
os << "# vtk DataFile Version 2.0" << nl writer_->beginPointData(nFields_);
<< tracks[0].name() << nl
<< "ASCII" << nl
<< "DATASET POLYDATA" << nl
<< "POINTS " << nPoints << " double" << nl;
for (const coordSet& points : tracks) writer_->writePointData(fieldName, fieldPtrs);
{
for (const point& pt : points) wroteGeom_ = true;
{ return outputFile;
os << float(pt.x()) << ' '
<< float(pt.y()) << ' '
<< float(pt.z()) << nl;
}
} }
if (writeTracks)
{
os << "LINES " << nTracks << ' ' << nPoints+nTracks << nl;
// Write ids of track points to file template<class Type>
label globalPtI = 0; Foam::fileName Foam::coordSetWriters::vtkWriter::writeTemplate
forAll(tracks, trackI) (
const word& fieldName,
const Field<Type>& values
)
{ {
const coordSet& points = tracks[trackI]; checkOpen();
if (coords_.empty())
const label len = points.size();
os << len;
for (label i = 0; i < len; ++i)
{ {
os << ' ' << globalPtI; return fileName::null;
++globalPtI;
}
os << nl;
}
} }
os << "POINT_DATA " << nPoints << nl UPtrList<const Field<Type>> fieldPtrs(repackageFields(values));
<< " FIELD attributes " << valueSetNames.size() << nl; return writeTemplate(fieldName, fieldPtrs);
}
forAll(valueSetNames, setI)
{
os << valueSetNames[setI] << ' '
<< int(pTraits<Type>::nComponents) << ' '
<< nPoints << " float" << nl;
const List<Field<Type>>& fieldVals = valueSets[setI]; template<class Type>
Foam::fileName Foam::coordSetWriters::vtkWriter::writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
)
{
checkOpen();
if (coords_.empty())
{
return fileName::null;
}
useTracks_ = true; // Extra safety
for (const Field<Type>& vals : fieldVals) UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
{ return writeTemplate(fieldName, fieldPtrs);
forAll(vals, j)
{
if (j)
{
os << ' ';
}
writer<Type>::write(vals[j], os);
}
os << nl;
}
}
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Field writing methods
defineCoordSetWriterWriteFields(Foam::coordSetWriters::vtkWriter);
// ************************************************************************* // // ************************************************************************* //

View File

@ -0,0 +1,185 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::coordSetWriters::vtkWriter
Description
SourceFiles
vtkCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_vtkWriter_H
#define Foam_coordSetWriters_vtkWriter_H
#include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class OFstream;
namespace vtk
{
// Forward Declarations
class outputOptions;
class coordSetWriter;
}
namespace coordSetWriters
{
/*---------------------------------------------------------------------------*\
Class vtkCoordSetWriter Declaration
\*---------------------------------------------------------------------------*/
class vtkWriter
:
public coordSetWriter
{
// Private Data
//- The VTK output format type.
// Stored as a raw value to avoid a header dependency on fileFormats
unsigned fmtType_;
//- ASCII write precision
unsigned precision_;
//- Backend writer - master only
autoPtr<Foam::vtk::coordSetWriter> writer_;
// Private Member Functions
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName, //!< Name of field
const Field<Type>& vals //!< Local field values to write
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
);
public:
//- Runtime type information (no debug)
TypeNameNoDebug("vtk");
// Constructors
//- Default construct
vtkWriter();
//- Construct with some output options
explicit vtkWriter(const vtk::outputOptions& opts);
//- Default construct with specified options
explicit vtkWriter(const dictionary& options);
//- Construct from components
vtkWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Construct from components
vtkWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Destructor. Calls close()
virtual ~vtkWriter();
// Member Functions
//- Expected (characteristic) output file name - information only
virtual fileName path() const; // override
//- Close and reset, clears backend.
virtual void close(bool force = false); // override
//- Begin time step. Clears existing backend.
virtual void beginTime(const Time& t); // override
//- Begin time step. Clears existing backend.
virtual void beginTime(const instant& inst); // override
//- End time step. Clears existing backend.
virtual void endTime(); // override
// Write
//- Write geometry to file.
virtual fileName write(); // override
declareCoordSetWriterWriteMethod(label);
declareCoordSetWriterWriteMethod(scalar);
declareCoordSetWriterWriteMethod(vector);
declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace coordSetWriters
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,120 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::vtkSetWriter
Description
Note
The output order of symmTensor is incorrect.
SourceFiles
vtkCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_vtkWriter_H
#define Foam_coordSetWriters_vtkWriter_H
#include "writer.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class vtkSetWriter Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class vtkSetWriter
:
public writer<Type>
{
public:
//- Runtime type information
TypeName("vtk");
// Constructors
//- Default construct
vtkSetWriter();
//- Construct with dictionary
explicit vtkSetWriter(const dictionary& dict);
//- Destructor
virtual ~vtkSetWriter() = default;
// Member Functions
virtual fileName getFileName
(
const coordSet&,
const wordList&
) const;
virtual void write
(
const coordSet&,
const wordList&,
const List<const Field<Type>*>&,
Ostream&
) const;
virtual void write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "vtkCoordSetWriter.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,39 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "vtkSetWriter.H"
#include "writers.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makeSetWriters(vtkSetWriter);
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd. Copyright (C) 2021-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,110 +26,244 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "xmgraceSetWriter.H" #include "xmgraceCoordSetWriter.H"
#include "coordSet.H" #include "coordSet.H"
#include "fileName.H" #include "fileName.H"
#include "OFstream.H" #include "OFstream.H"
#include "OSspecific.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
defineTypeName(xmgraceWriter);
addToRunTimeSelectionTable(coordSetWriter, xmgraceWriter, word);
addToRunTimeSelectionTable(coordSetWriter, xmgraceWriter, wordDict);
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Implementation
#include "xmgraceCoordSetWriterImpl.C"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type> Foam::coordSetWriters::xmgraceWriter::xmgraceWriter()
Foam::xmgraceSetWriter<Type>::xmgraceSetWriter()
: :
writer<Type>() coordSetWriter(),
{} streamOpt_(),
precision_(IOstream::defaultPrecision()),
ofile_(nullptr),
nWritten_(0)
{
buffering_ = true;
}
template<class Type> Foam::coordSetWriters::xmgraceWriter::xmgraceWriter(const dictionary& options)
Foam::xmgraceSetWriter<Type>::xmgraceSetWriter(const dictionary& dict)
: :
writer<Type>(dict) coordSetWriter(options),
{} streamOpt_
(
IOstream::ASCII,
IOstream::compressionEnum("compression", options)
),
precision_
(
options.getOrDefault("precision", IOstream::defaultPrecision())
),
ofile_(nullptr),
nWritten_(0)
{
buffering_ = options.getOrDefault("buffer", true);
}
Foam::coordSetWriters::xmgraceWriter::xmgraceWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options
)
:
xmgraceWriter(options)
{
open(coords, outputPath);
}
Foam::coordSetWriters::xmgraceWriter::xmgraceWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options
)
:
xmgraceWriter(options)
{
open(tracks, outputPath);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coordSetWriters::xmgraceWriter::~xmgraceWriter()
{
close();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> bool Foam::coordSetWriters::xmgraceWriter::buffering(const bool on)
Foam::fileName Foam::xmgraceSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
{ {
return this->getBaseName(points, valueSetNames) + ".agr"; const bool old(buffering_);
buffering_ = on;
return old;
}
Foam::fileName Foam::coordSetWriters::xmgraceWriter::path() const
{
// Assume !useTracks_, otherwise too fragile
// 1) rootdir/<TIME>/setName.agr
// 2) rootdir/setName.agr
return getExpectedPath("agr");
}
void Foam::coordSetWriters::xmgraceWriter::close(bool force)
{
ofile_.reset(nullptr);
nWritten_ = 0;
coordSetWriter::close(force);
}
void Foam::coordSetWriters::xmgraceWriter::beginTime(const Time& t)
{
ofile_.reset(nullptr);
nWritten_ = 0;
coordSetWriter::beginTime(t);
}
void Foam::coordSetWriters::xmgraceWriter::beginTime(const instant& inst)
{
ofile_.reset(nullptr);
nWritten_ = 0;
coordSetWriter::beginTime(inst);
}
void Foam::coordSetWriters::xmgraceWriter::endTime()
{
ofile_.reset(nullptr);
nWritten_ = 0;
coordSetWriter::endTime();
} }
template<class Type> template<class Type>
void Foam::xmgraceSetWriter<Type>::write Foam::fileName Foam::coordSetWriters::xmgraceWriter::writeTemplate
( (
const coordSet& points, const word& fieldName,
const wordList& valueSetNames, const Field<Type>& values
const List<const Field<Type>*>& valueSets, )
Ostream& os
) const
{ {
checkOpen();
if (coords_.empty())
{
return fileName::null;
}
if (useTracks_ || !buffering_)
{
UPtrList<const Field<Type>> fieldPtrs(repackageFields(values));
return writeTemplate(fieldName, fieldPtrs);
}
// Regular version
const auto& coords = coords_[0];
if (!ofile_)
{
// Field:
// 1) rootdir/<TIME>/setName.agr
// 2) rootdir/setName.agr
const fileName outputFile = path();
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
ofile_.reset(new OFstream(outputFile, streamOpt_));
auto& os = ofile_();
os.precision(precision_);
// Preamble
os << "@g0 on" << nl os << "@g0 on" << nl
<< "@with g0" << nl << "@with g0" << nl
<< "@ title \"" << points.name() << '"' << nl << "@ title \"" << coords.name() << '"' << nl
<< "@ xaxis label " << '"' << points.axis() << '"' << nl; << "@ xaxis label \"" << coords.axis() << '"' << nl;
forAll(valueSets, i) nWritten_ = 0; // Restarted
}
auto& os = ofile_();
// Plot entry
{ {
os << "@ s" << i << " legend " << '"' os << "@ s" << nWritten_
<< valueSetNames[i] << '"' << nl << " legend \"" << fieldName << '"' << nl
<< "@target G0.S" << i << nl; << "@target G0.S" << nWritten_ << nl;
this->writeTable(points, *valueSets[i], os); writeTable(os, coords, values, " \t");
os << '&' << nl; os << '&' << nl;
os << "# end_data" << nl;
++nWritten_;
} }
return ofile_().name();
} }
template<class Type> template<class Type>
void Foam::xmgraceSetWriter<Type>::write Foam::fileName Foam::coordSetWriters::xmgraceWriter::writeTemplate
( (
const bool writeTracks, const word& fieldName,
const List<scalarField>& times, const List<Field<Type>>& fieldValues
const PtrList<coordSet>& tracks, )
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
{ {
if (valueSets.size() != valueSetNames.size()) checkOpen();
if (coords_.empty())
{ {
FatalErrorInFunction return fileName::null;
<< "Number of variables:" << valueSetNames.size() << endl
<< "Number of valueSets:" << valueSets.size()
<< exit(FatalError);
} }
if (tracks.size() > 0) useTracks_ = true; // Extra safety
{
os << "@g0 on" << nl
<< "@with g0" << nl
<< "@ title \"" << tracks[0].name() << '"' << nl
<< "@ xaxis label " << '"' << tracks[0].axis() << '"' << nl;
// Data index. UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
label sI = 0; return writeTemplate(fieldName, fieldPtrs);
}
forAll(tracks, trackI)
{
forAll(valueSets, i)
{
os << "@ s" << sI << " legend " << '"'
<< valueSetNames[i] << "_track" << i << '"' << nl
<< "@target G0.S" << sI << nl;
this->writeTable(tracks[trackI], valueSets[i][trackI], os);
os << '&' << nl;
sI++; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
}
} // Field writing methods
} defineCoordSetWriterWriteFields(Foam::coordSetWriters::xmgraceWriter);
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -0,0 +1,204 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::coordSetWriters::xmgraceWriter
Description
Write coordSet(s) in xmgrace format
The formatOptions for xmgrace:
\table
Property | Description | Required | Default
buffer | Use buffered output | no | true
compression | Use file compression | no | false
precision | Write precision in ascii | no | same as IOstream
\endtable
When called with a single coordSet, will combine all output fields
into a single file. Although it is nominally 'buffered', it actually
just keeps track of the number of fields written into the file.
When called as a track writer (eg, with multiple coordSets),
will emit one file per field.
\section Output file locations
The \c rootdir normally corresponds to something like
\c postProcessing/\<name\>
\subsection Geometry and Fields
\verbatim
rootdir
`-- timeName
`-- setName.{agr}
\endverbatim
SourceFiles
xmgraceCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_xmgraceWriter_H
#define Foam_coordSetWriters_xmgraceWriter_H
#include "coordSetWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class OFstream;
namespace coordSetWriters
{
/*---------------------------------------------------------------------------*\
Class xmgraceWriter Declaration
\*---------------------------------------------------------------------------*/
class xmgraceWriter
:
public coordSetWriter
{
// Private Data
//- Output stream option
IOstreamOption streamOpt_;
//- ASCII write precision
unsigned precision_;
//- Backend output file (when buffering)
autoPtr<Foam::OFstream> ofile_;
//- The number of fields written (when buffering)
label nWritten_;
// Private Member Functions
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName, //!< Name of field
const Field<Type>& vals //!< Local field values to write
);
//- Templated write operation
template<class Type>
fileName writeTemplate
(
const word& fieldName,
const List<Field<Type>>& fieldValues
);
public:
//- Runtime type information (no debug)
TypeNameNoDebug("xmgr");
// Constructors
//- Default construct
xmgraceWriter();
//- Default construct with specified options
explicit xmgraceWriter(const dictionary& options);
//- Construct from components
xmgraceWriter
(
const coordSet& coords,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Construct from components
xmgraceWriter
(
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options = dictionary()
);
//- Destructor. Calls close()
virtual ~xmgraceWriter();
// Member Functions
//- Enable/disable internal buffering
virtual bool buffering(const bool on); // override
//- Characteristic output file name - information only
virtual fileName path() const; // override
//- Close and reset, clears backend.
virtual void close(bool force = false); // override
//- Begin time step. Clears existing backend.
virtual void beginTime(const Time& t); // override
//- Begin time step. Clears existing backend.
virtual void beginTime(const instant& inst); // override
//- End time step. Clears existing backend.
virtual void endTime(); // override
declareCoordSetWriterWriteMethod(label);
declareCoordSetWriterWriteMethod(scalar);
declareCoordSetWriterWriteMethod(vector);
declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace coordSetWriters
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,102 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "IOmanip.H"
#include "OFstream.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::coordSetWriters::xmgraceWriter::writeTemplate
(
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
)
{
if (coords_.size() != fieldPtrs.size())
{
FatalErrorInFunction
<< "Attempted to write field: " << fieldName
<< " (" << fieldPtrs.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError);
}
// Field: rootdir/<TIME>/<field>_setName.agr
fileName outputFile = getFieldPrefixedPath(fieldName, "agr");
if (verbose_)
{
Info<< "Writing field " << fieldName;
Info<< " to " << outputFile << endl;
}
// Master only
{
if (!isDir(outputFile.path()))
{
mkDir(outputFile.path());
}
OFstream os(outputFile, streamOpt_);
os.precision(precision_);
// Preamble
{
const coordSet& coords = coords_[0];
os << "@g0 on" << nl
<< "@with g0" << nl
<< "@ title \"" << coords.name() << '"' << nl
<< "@ xaxis label \"" << coords.axis() << '"' << nl;
}
const label setNumber = 0;
// Plot entry
os << "@ s" << setNumber
<< " legend \"" << fieldName << '"' << nl
<< "@target G0.S" << setNumber << nl;
forAll(coords_, tracki)
{
writeTable(os, coords_[tracki], fieldPtrs[tracki], " \t");
}
os << '&' << nl;
os << "# end_data" << nl;
}
wroteGeom_ = true;
return outputFile;
}
// ************************************************************************* //

View File

@ -1,117 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::xmgraceSetWriter
Description
SourceFiles
xmgraceCoordSetWriter.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_coordSetWriters_xmgraceWriter_H
#define Foam_coordSetWriters_xmgraceWriter_H
#include "writer.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class xmgraceSetWriter Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class xmgraceSetWriter
:
public writer<Type>
{
public:
//- Runtime type information
TypeName("xmgr");
// Constructors
//- Default construct
xmgraceSetWriter();
//- Construct with dictionary
explicit xmgraceSetWriter(const dictionary& dict);
//- Destructor
virtual ~xmgraceSetWriter() = default;
// Member Functions
virtual fileName getFileName
(
const coordSet&,
const wordList&
) const;
virtual void write
(
const coordSet&,
const wordList&,
const List<const Field<Type>*>&,
Ostream&
) const;
virtual void write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "xmgraceCoordSetWriter.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,39 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "xmgraceSetWriter.H"
#include "writers.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makeSetWriters(xmgraceSetWriter);
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd. Copyright (C) 2015-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -32,7 +32,7 @@ License
#include "Time.H" #include "Time.H"
#include "DynamicField.H" #include "DynamicField.H"
#include "PatchTools.H" #include "PatchTools.H"
#include "writer.H" #include "coordSetWriter.H"
#include "triSurfaceMesh.H" #include "triSurfaceMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -611,7 +611,7 @@ bool Foam::searchableSurfaces::checkSizes
bool Foam::searchableSurfaces::checkIntersection bool Foam::searchableSurfaces::checkIntersection
( (
const scalar tolerance, const scalar tolerance,
const autoPtr<writer<scalar>>& setWriter, autoPtr<coordSetWriter>& setWriter,
const bool report const bool report
) const ) const
{ {
@ -669,7 +669,7 @@ bool Foam::searchableSurfaces::checkIntersection
label nHits = 0; label nHits = 0;
DynamicField<point> intersections(edges0.size()/100); DynamicField<point> intersections(edges0.size()/100);
DynamicField<scalar> intersectionEdge(intersections.capacity()); DynamicField<label> intersectionEdge(intersections.capacity());
forAll(hits, edgeI) forAll(hits, edgeI)
{ {
@ -680,7 +680,7 @@ bool Foam::searchableSurfaces::checkIntersection
) )
{ {
intersections.append(hits[edgeI].hitPoint()); intersections.append(hits[edgeI].hitPoint());
intersectionEdge.append(1.0*edgeI); intersectionEdge.append(edgeI);
nHits++; nHits++;
} }
} }
@ -698,7 +698,7 @@ bool Foam::searchableSurfaces::checkIntersection
<< " locations." << " locations."
<< endl; << endl;
if (setWriter) if (setWriter && setWriter->enabled())
{ {
scalarField dist(mag(intersections)); scalarField dist(mag(intersections));
coordSet track coordSet track
@ -708,31 +708,27 @@ bool Foam::searchableSurfaces::checkIntersection
std::move(intersections), std::move(intersections),
std::move(dist) std::move(dist)
); );
wordList valueSetNames(1, "edgeIndex");
List<const scalarField*> valueSets
(
1,
&intersectionEdge
);
fileName fName
( auto& writer = *setWriter;
setWriter().getFileName(track, valueSetNames) writer.nFields(1);
);
Info<< " Writing intersection locations to " writer.open
<< fName << endl;
OFstream os
(
s0.searchableSurface::time().path()
/fName
);
setWriter().write
( (
track, track,
valueSetNames, (
valueSets, s0.searchableSurface::time().path()
os / (track.name() + "_edgeIndex")
)
); );
fileName fName =
writer.write("edgeIndex", intersectionEdge);
writer.close(true);
Info<< " Wrote intersection locations to "
<< fName << endl;
} }
} }
@ -841,7 +837,7 @@ Foam::label Foam::searchableSurfaces::checkGeometry
( (
const scalar maxRatio, const scalar maxRatio,
const scalar tol, const scalar tol,
const autoPtr<writer<scalar>>& setWriter, autoPtr<coordSetWriter>& setWriter,
const scalar minQuality, const scalar minQuality,
const bool report const bool report
) const ) const

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -68,7 +69,7 @@ namespace Foam
{ {
// Forward Declarations // Forward Declarations
template<class T> class writer; class coordSetWriter;
class triSurface; class triSurface;
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
@ -254,7 +255,7 @@ public:
bool checkIntersection bool checkIntersection
( (
const scalar tol, const scalar tol,
const autoPtr<writer<scalar>>&, autoPtr<coordSetWriter>& setWriter,
const bool report const bool report
) const; ) const;
@ -273,7 +274,7 @@ public:
( (
const scalar maxRatio, const scalar maxRatio,
const scalar tolerance, const scalar tolerance,
const autoPtr<writer<scalar>>& setWriter, autoPtr<coordSetWriter>& setWriter,
const scalar minQuality, const scalar minQuality,
const bool report const bool report
) const; ) const;

View File

@ -13,7 +13,6 @@ sampledSet/patchSeed/patchSeedSet.C
sampledSet/patchEdge/patchEdgeSet.C sampledSet/patchEdge/patchEdgeSet.C
sampledSet/sampledSet/sampledSet.C sampledSet/sampledSet/sampledSet.C
sampledSet/sampledSets/sampledSets.C sampledSet/sampledSets/sampledSets.C
sampledSet/sampledSets/sampledSetsGrouping.C
sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.C sampledSet/triSurfaceMeshPointSet/triSurfaceMeshPointSet.C
sampledSet/uniform/uniformSet.C sampledSet/uniform/uniformSet.C
sampledSet/array/arraySet.C sampledSet/array/arraySet.C

View File

@ -57,11 +57,11 @@ void Foam::midPointAndFaceSet::genSamples()
while (size() > 0) while (size() > 0)
{ {
// Add first face // Add first face
mpfSamplePoints[mpfSamplei] = operator[](samplei); mpfSamplePoints[mpfSamplei] = points()[samplei];
mpfSampleCells[mpfSamplei] = cells_[samplei]; mpfSampleCells[mpfSamplei] = cells_[samplei];
mpfSampleFaces[mpfSamplei] = faces_[samplei]; mpfSampleFaces[mpfSamplei] = faces_[samplei];
mpfSampleSegments[mpfSamplei] = segments_[samplei]; mpfSampleSegments[mpfSamplei] = segments_[samplei];
mpfSampleCurveDist[mpfSamplei] = curveDist_[samplei]; mpfSampleCurveDist[mpfSamplei] = distance_[samplei];
++mpfSamplei; ++mpfSamplei;
while while
@ -70,7 +70,7 @@ void Foam::midPointAndFaceSet::genSamples()
&& (segments_[samplei] == segments_[samplei+1]) && (segments_[samplei] == segments_[samplei+1])
) )
{ {
point midPoint(0.5*(operator[](samplei) + operator[](samplei+1))); point midPoint(0.5*(points()[samplei] + points()[samplei+1]));
label cellm = pointInCell(midPoint, samplei); label cellm = pointInCell(midPoint, samplei);
if (cellm != -1) if (cellm != -1)

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2018-2021 OpenCFD Ltd. Copyright (C) 2018-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -30,7 +30,6 @@ License
#include "polyMesh.H" #include "polyMesh.H"
#include "primitiveMesh.H" #include "primitiveMesh.H"
#include "meshSearch.H" #include "meshSearch.H"
#include "writer.H"
#include "particle.H" #include "particle.H"
#include "globalIndex.H" #include "globalIndex.H"
@ -52,16 +51,16 @@ void Foam::sampledSet::checkDimensions() const
(cells_.size() != size()) (cells_.size() != size())
|| (faces_.size() != size()) || (faces_.size() != size())
|| (segments_.size() != size()) || (segments_.size() != size())
|| (curveDist_.size() != size()) || (distance_.size() != size())
) )
{ {
FatalErrorInFunction FatalErrorInFunction
<< "sizes not equal : " << "Sizes not equal : "
<< " points:" << size() << " points:" << size()
<< " cells:" << cells_.size() << " cells:" << cells_.size()
<< " faces:" << faces_.size() << " faces:" << faces_.size()
<< " segments:" << segments_.size() << " segments:" << segments_.size()
<< " curveDist:" << curveDist_.size() << " distance:" << distance_.size()
<< abort(FatalError); << abort(FatalError);
} }
} }
@ -75,14 +74,12 @@ Foam::label Foam::sampledSet::getBoundaryCell(const label facei) const
Foam::label Foam::sampledSet::getNeighbourCell(const label facei) const Foam::label Foam::sampledSet::getNeighbourCell(const label facei) const
{ {
if (facei >= mesh().nInternalFaces()) if (facei < mesh().nInternalFaces())
{
return mesh().faceOwner()[facei];
}
else
{ {
return mesh().faceNeighbour()[facei]; return mesh().faceNeighbour()[facei];
} }
return mesh().faceOwner()[facei];
} }
@ -384,11 +381,11 @@ void Foam::sampledSet::setSamples
const labelList& samplingCells, const labelList& samplingCells,
const labelList& samplingFaces, const labelList& samplingFaces,
const labelList& samplingSegments, const labelList& samplingSegments,
const scalarList& samplingCurveDist const scalarList& samplingDistance
) )
{ {
setPoints(samplingPts); setPoints(samplingPts);
curveDist_ = samplingCurveDist; setDistance(samplingDistance, false); // check=false
segments_ = samplingSegments; segments_ = samplingSegments;
cells_ = samplingCells; cells_ = samplingCells;
@ -404,11 +401,11 @@ void Foam::sampledSet::setSamples
labelList&& samplingCells, labelList&& samplingCells,
labelList&& samplingFaces, labelList&& samplingFaces,
labelList&& samplingSegments, labelList&& samplingSegments,
scalarList&& samplingCurveDist scalarList&& samplingDistance
) )
{ {
setPoints(std::move(samplingPts)); setPoints(std::move(samplingPts));
curveDist_ = std::move(samplingCurveDist); setDistance(std::move(samplingDistance), false); // check=false
segments_ = std::move(samplingSegments); segments_ = std::move(samplingSegments);
cells_ = std::move(samplingCells); cells_ = std::move(samplingCells);
@ -418,48 +415,6 @@ void Foam::sampledSet::setSamples
} }
Foam::autoPtr<Foam::coordSet> Foam::sampledSet::gather
(
labelList& indexSet,
labelList& allSegments
) const
{
// Combine sampleSet from processors. Sort by curveDist. Return
// ordering in indexSet.
// Note: only master results are valid
List<point> allPts;
globalIndex::gatherOp(*this, allPts);
globalIndex::gatherOp(segments(), allSegments);
scalarList allCurveDist;
globalIndex::gatherOp(curveDist(), allCurveDist);
if (Pstream::master() && allCurveDist.empty())
{
WarningInFunction
<< "Sample set " << name()
<< " has zero points." << endl;
}
// Sort curveDist and use to fill masterSamplePts
Foam::sortedOrder(allCurveDist, indexSet); // uses stable sort
scalarList sortedDist(allCurveDist, indexSet); // with indices for mapping
allSegments = UIndirectList<label>(allSegments, indexSet)();
return autoPtr<coordSet>::New
(
name(),
axis(),
List<point>(UIndirectList<point>(allPts, indexSet)),
sortedDist
);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::sampledSet::sampledSet Foam::sampledSet::sampledSet
@ -513,6 +468,25 @@ Foam::sampledSet::sampledSet
{} {}
// Foam::autoPtr<Foam::coordSet> Foam::sampledSet::gather
// (
// labelList& sortOrder,
// labelList& allSegments
// ) const
// {
// autoPtr<coordSet> result(coordSet::gatherSort(sortOrder));
//
// // Optional
// if (notNull(allSegments))
// {
// globalIndex::gatherOp(segments(), allSegments);
// allSegments = UIndirectList<label>(allSegments, sortOrder)();
// }
//
// return result;
// }
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::autoPtr<Foam::sampledSet> Foam::sampledSet::New Foam::autoPtr<Foam::sampledSet> Foam::sampledSet::New

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2018 OpenCFD Ltd. Copyright (C) 2017-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -50,20 +50,20 @@ SourceFiles
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef sampledSet_H #ifndef Foam_sampledSet_H
#define sampledSet_H #define Foam_sampledSet_H
#include "coordSet.H" #include "coordSet.H"
#include "autoPtr.H"
#include "typeInfo.H" #include "typeInfo.H"
#include "runTimeSelectionTables.H" #include "runTimeSelectionTables.H"
#include "autoPtr.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam namespace Foam
{ {
// Forward declarations // Forward Declarations
class polyMesh; class polyMesh;
class meshSearch; class meshSearch;
@ -75,7 +75,7 @@ class sampledSet
: :
public coordSet public coordSet
{ {
// Private data // Private Data
//- Reference to mesh //- Reference to mesh
const polyMesh& mesh_; const polyMesh& mesh_;
@ -86,6 +86,8 @@ class sampledSet
protected: protected:
// Protected Data
//- Segment numbers //- Segment numbers
labelList segments_; labelList segments_;
@ -154,7 +156,7 @@ protected:
const labelList& samplingCells, const labelList& samplingCells,
const labelList& samplingFaces, const labelList& samplingFaces,
const labelList& samplingSegments, const labelList& samplingSegments,
const scalarList& samplingCurveDist const scalarList& samplingDistance
); );
//- Set sample data. Move list contents. //- Set sample data. Move list contents.
@ -164,7 +166,7 @@ protected:
labelList&& samplingCells, labelList&& samplingCells,
labelList&& samplingFaces, labelList&& samplingFaces,
labelList&& samplingSegments, labelList&& samplingSegments,
scalarList&& samplingCurveDist scalarList&& samplingDistance
); );
public: public:
@ -194,22 +196,58 @@ public:
// PtrLists of sampledSet // PtrLists of sampledSet
class iNew class iNew
{ {
//- Reference to the volume mesh
const polyMesh& mesh_; const polyMesh& mesh_;
const meshSearch& searchEngine_; const meshSearch& search_;
public: public:
iNew(const polyMesh& mesh, const meshSearch& searchEngine) iNew(const polyMesh& mesh, const meshSearch& searchEngine)
: :
mesh_(mesh), mesh_(mesh),
searchEngine_(searchEngine) search_(searchEngine)
{} {}
autoPtr<sampledSet> operator()(Istream& is) const autoPtr<sampledSet> operator()(Istream& is) const
{ {
word name(is); word name(is);
dictionary dict(is); dictionary dict(is);
return sampledSet::New(name, mesh_, searchEngine_, dict); return sampledSet::New(name, mesh_, search_, dict);
}
};
//- PtrList read-construction helper that captures dictionaries used
//- during creation.
class iNewCapture
{
//- Reference to the volume mesh
const polyMesh& mesh_;
const meshSearch& search_;
//- Captured (recorded) dictionaries
DynamicList<dictionary>& capture_;
public:
iNewCapture
(
const polyMesh& mesh,
const meshSearch& searchEngine,
DynamicList<dictionary>& capture
)
:
mesh_(mesh),
search_(searchEngine),
capture_(capture)
{}
autoPtr<sampledSet> operator()(Istream& is) const
{
word name(is);
capture_.append(dictionary(is));
return sampledSet::New(name, mesh_, search_, capture_.last());
} }
}; };
@ -269,27 +307,27 @@ public:
// Member Functions // Member Functions
const polyMesh& mesh() const const polyMesh& mesh() const noexcept
{ {
return mesh_; return mesh_;
} }
const meshSearch& searchEngine() const const meshSearch& searchEngine() const noexcept
{ {
return searchEngine_; return searchEngine_;
} }
const labelList& segments() const const labelList& segments() const noexcept
{ {
return segments_; return segments_;
} }
const labelList& cells() const const labelList& cells() const noexcept
{ {
return cells_; return cells_;
} }
const labelList& faces() const const labelList& faces() const noexcept
{ {
return faces_; return faces_;
} }
@ -297,13 +335,16 @@ public:
//- Output for debugging //- Output for debugging
Ostream& write(Ostream&) const; Ostream& write(Ostream&) const;
//- Helper: gather onto master and sort.
// \return (on master) gathered set and overall sort order // Other
autoPtr<coordSet> gather
( /// //- Gather and sort.
labelList& indexSet, /// \return (on master) gathered set and overall sort order
labelList& allSegments /// autoPtr<coordSet> gather
) const; /// (
/// labelList& sortOrder,
/// labelList& allSegments
/// ) const;
}; };

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd. Copyright (C) 2015-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -29,9 +29,12 @@ License
#include "sampledSets.H" #include "sampledSets.H"
#include "dictionary.H" #include "dictionary.H"
#include "Time.H" #include "Time.H"
#include "globalIndex.H"
#include "volFields.H" #include "volFields.H"
#include "volPointInterpolation.H"
#include "mapPolyMesh.H" #include "mapPolyMesh.H"
#include "IOobjectList.H"
#include "UIndirectList.H"
#include "ListOps.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -48,36 +51,287 @@ namespace Foam
); );
} }
bool Foam::sampledSets::verbose_ = false; #include "sampledSetsImpl.C"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::sampledSets::combineSampledSets Foam::autoPtr<Foam::coordSetWriter> Foam::sampledSets::newWriter
( (
PtrList<coordSet>& masterSampledSets, word writeType,
labelListList& indexSets const dictionary& formatOptions,
const dictionary& setDict
) )
{ {
// Combine sampleSets from processors. Sort by curveDist. Return // Per-set adjustment
// ordering in indexSets. setDict.readIfPresent<word>("setFormat", writeType);
// Note: only master results are valid
masterSampledSets_.clear(); dictionary options = formatOptions.subOrEmptyDict(writeType);
masterSampledSets_.setSize(size());
indexSets_.setSize(size());
const PtrList<sampledSet>& sampledSets = *this; options.merge
forAll(sampledSets, setI)
{
labelList segments;
masterSampledSets.set
( (
setI, setDict.subOrEmptyDict("formatOptions").subOrEmptyDict(writeType)
sampledSets[setI].gather(indexSets[setI], segments)
); );
return coordSetWriter::New(writeType, options);
} }
void Foam::sampledSets::gatherAllSets()
{
// Any writer references will become invalid
for (auto& writer : writers_)
{
writer.expire();
}
const PtrList<sampledSet>& localSets = *this;
gatheredSets_.clear();
gatheredSets_.resize(localSets.size());
gatheredSorting_.resize_nocopy(localSets.size());
globalIndices_.resize_nocopy(localSets.size());
forAll(localSets, seti)
{
const coordSet& coords = localSets[seti];
globalIndices_[seti].reset(coords.size(), globalIndex::gatherOnly{});
gatheredSets_.set(seti, coords.gatherSort(gatheredSorting_[seti]));
}
}
Foam::IOobjectList Foam::sampledSets::preCheckFields()
{
wordList allFields; // Just needed for warnings
HashTable<wordHashSet> selected;
IOobjectList objects(0);
if (loadFromFiles_)
{
// Check files for a particular time
objects = IOobjectList(mesh_, mesh_.time().timeName());
allFields = objects.names();
selected = objects.classes(fieldSelection_);
}
else
{
// Check currently available fields
allFields = mesh_.names();
selected = mesh_.classes(fieldSelection_);
}
// Probably not needed...
// if (Pstream::parRun())
// {
// Pstream::mapCombineGather(selected, HashSetOps::plusEqOp<word>());
// Pstream::mapCombineScatter(selected);
// }
DynamicList<label> missed(fieldSelection_.size());
// Detect missing fields
forAll(fieldSelection_, i)
{
if
(
fieldSelection_[i].isLiteral()
&& !ListOps::found(allFields, fieldSelection_[i])
)
{
missed.append(i);
}
}
if (missed.size())
{
WarningInFunction
<< nl
<< "Cannot find "
<< (loadFromFiles_ ? "field file" : "registered field")
<< " matching "
<< UIndirectList<wordRe>(fieldSelection_, missed) << endl;
}
// The selected field names, ordered by (scalar, vector, ...)
// with internal sorting
selectedFieldNames_.clear();
do
{
#undef doLocalCode
#define doLocalCode(InputType) \
{ \
const auto iter = selected.find(InputType::typeName); \
if (iter.found()) \
{ \
selectedFieldNames_.append(iter.val().sortedToc()); \
} \
}
doLocalCode(volScalarField);
doLocalCode(volVectorField);
doLocalCode(volSphericalTensorField);
doLocalCode(volSymmTensorField);
doLocalCode(volTensorField);
#undef doLocalCode
}
while (false);
// Now propagate field counts (per surface)
// - can update writer even when not writing without problem
const label nFields = selectedFieldNames_.size();
forAll(writers_, seti)
{
coordSetWriter& writer = writers_[seti];
writer.nFields(nFields);
}
return objects;
}
void Foam::sampledSets::initDict(const dictionary& dict, const bool initial)
{
PtrList<sampledSet>::clear();
if (initial)
{
writers_.clear();
}
const entry* eptr = dict.findEntry("sets");
if (eptr && eptr->isDict())
{
PtrList<sampledSet> sampSets(eptr->dict().size());
if (initial)
{
writers_.resize(sampSets.size());
}
label seti = 0;
for (const entry& dEntry : eptr->dict())
{
if (!dEntry.isDict())
{
continue;
}
const dictionary& subDict = dEntry.dict();
autoPtr<sampledSet> sampSet =
sampledSet::New
(
dEntry.keyword(),
mesh_,
searchEngine_,
subDict
);
// if (!sampSet || !sampSet->enabled())
// {
// continue;
// }
// Define the set
sampSets.set(seti, sampSet);
// Define writer, but do not attached
if (initial)
{
writers_.set
(
seti,
newWriter(writeFormat_, writeFormatOptions_, subDict)
);
// Use outputDir/TIME/set-name
writers_[seti].useTimeDir(true);
writers_[seti].verbose(verbose_);
}
++seti;
}
sampSets.resize(seti);
if (initial)
{
writers_.resize(seti);
}
static_cast<PtrList<sampledSet>&>(*this).transfer(sampSets);
}
else if (eptr)
{
// This is slightly trickier.
// We want access to the individual dictionaries used for construction
DynamicList<dictionary> capture;
PtrList<sampledSet> input
(
eptr->stream(),
sampledSet::iNewCapture(mesh_, searchEngine_, capture)
);
PtrList<sampledSet> sampSets(input.size());
if (initial)
{
writers_.resize(sampSets.size());
}
label seti = 0;
forAll(input, inputi)
{
const dictionary& subDict = capture[inputi];
autoPtr<sampledSet> sampSet = input.release(inputi);
// if (!sampSet || !sampSet->enabled())
// {
// continue;
// }
// Define the set
sampSets.set(seti, sampSet);
// Define writer, but do not attached
if (initial)
{
writers_.set
(
seti,
newWriter(writeFormat_, writeFormatOptions_, subDict)
);
// Use outputDir/TIME/set-name
writers_[seti].useTimeDir(true);
writers_[seti].verbose(verbose_);
}
++seti;
}
sampSets.resize(seti);
if (initial)
{
writers_.resize(seti);
}
static_cast<PtrList<sampledSet>&>(*this).transfer(sampSets);
}
gatherAllSets();
needsCorrect_ = false;
} }
@ -90,21 +344,27 @@ Foam::sampledSets::sampledSets
const dictionary& dict const dictionary& dict
) )
: :
functionObjects::regionFunctionObject(name, runTime, dict), functionObjects::fvMeshFunctionObject(name, runTime, dict),
PtrList<sampledSet>(), PtrList<sampledSet>(),
mesh_(refCast<const fvMesh>(obr_)), dict_(dict),
loadFromFiles_(false), loadFromFiles_(false),
outputPath_(fileName::null), verbose_(false),
searchEngine_(mesh_), onExecute_(false),
interpolationScheme_(word::null), needsCorrect_(false),
writeFormat_(word::null), outputPath_
writeFormatOptions_(dict.subOrEmptyDict("formatOptions"))
{
outputPath_ =
( (
mesh_.time().globalPath()/functionObject::outputPrefix/name time_.globalPath()/functionObject::outputPrefix/name
); ),
searchEngine_(mesh_),
samplePointScheme_(),
writeFormat_(),
writeFormatOptions_(dict.subOrEmptyDict("formatOptions")),
writers_(),
selectedFieldNames_(),
gatheredSets_(),
gatheredSorting_(),
globalIndices_()
{
if (mesh_.name() != polyMesh::defaultRegion) if (mesh_.name() != polyMesh::defaultRegion)
{ {
outputPath_ /= mesh_.name(); outputPath_ /= mesh_.name();
@ -124,26 +384,31 @@ Foam::sampledSets::sampledSets
const bool loadFromFiles const bool loadFromFiles
) )
: :
functionObjects::regionFunctionObject(name, obr, dict), functionObjects::fvMeshFunctionObject(name, obr, dict),
PtrList<sampledSet>(), PtrList<sampledSet>(),
mesh_(refCast<const fvMesh>(obr)), dict_(dict),
loadFromFiles_(loadFromFiles), loadFromFiles_(loadFromFiles),
outputPath_(fileName::null), verbose_(false),
searchEngine_(mesh_), onExecute_(false),
interpolationScheme_(word::null), needsCorrect_(false),
writeFormat_(word::null), outputPath_
writeFormatOptions_(dict.subOrEmptyDict("formatOptions"))
{
outputPath_ =
( (
mesh_.time().globalPath()/functionObject::outputPrefix/name time_.globalPath()/functionObject::outputPrefix/name
); ),
searchEngine_(mesh_),
samplePointScheme_(),
writeFormat_(),
writeFormatOptions_(dict.subOrEmptyDict("formatOptions")),
writers_(),
selectedFieldNames_(),
gatheredSets_(),
gatheredSorting_(),
globalIndices_()
{
if (mesh_.name() != polyMesh::defaultRegion) if (mesh_.name() != polyMesh::defaultRegion)
{ {
outputPath_ /= mesh_.name(); outputPath_ /= mesh_.name();
} }
outputPath_.clean(); // Remove unneeded ".." outputPath_.clean(); // Remove unneeded ".."
read(dict); read(dict);
@ -152,7 +417,7 @@ Foam::sampledSets::sampledSets
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::sampledSets::verbose(const bool on) bool Foam::sampledSets::verbose(const bool on) noexcept
{ {
bool old(verbose_); bool old(verbose_);
verbose_ = on; verbose_ = on;
@ -160,122 +425,205 @@ bool Foam::sampledSets::verbose(const bool on)
} }
bool Foam::sampledSets::read(const dictionary& dict)
{
if (&dict_ != &dict)
{
// Update local copy of dictionary
dict_ = dict;
}
fvMeshFunctionObject::read(dict);
PtrList<sampledSet>::clear();
writers_.clear();
fieldSelection_.clear();
selectedFieldNames_.clear();
gatheredSets_.clear();
gatheredSorting_.clear();
globalIndices_.clear();
verbose_ = dict.getOrDefault("verbose", false);
onExecute_ = dict.getOrDefault("sampleOnExecute", false);
samplePointScheme_ =
dict.getOrDefault<word>("interpolationScheme", "cellPoint");
const entry* eptr = dict.findEntry("sets");
if (eptr)
{
dict.readEntry("setFormat", writeFormat_);
}
// const dictionary formatOptions(dict.subOrEmptyDict("formatOptions"));
// Writer type and format options
// const word writerType =
// (eptr ? dict.get<word>("setFormat") : word::null);
// writerType_ = (eptr ? dict.get<word>("setFormat") : word::null);
initDict(dict, true);
// Have some sets, so sort out which fields are needed and report
if (this->size())
{
dict_.readEntry("fields", fieldSelection_);
fieldSelection_.uniq();
// Report
forAll(*this, seti)
{
const sampledSet& s = (*this)[seti];
if (!seti)
{
Info<< "Sampled set:" << nl;
}
Info<< " " << s.name() << " -> " << writers_[seti].type()
<< nl;
}
Info<< endl;
}
if (debug && Pstream::master())
{
Pout<< "sample fields:" << flatOutput(fieldSelection_) << nl
<< "sample sets:" << nl << '(' << nl;
for
(
const sampledSet& s
: static_cast<const PtrList<sampledSet>&>(*this)
)
{
Pout<< " " << s << endl;
}
Pout<< ')' << endl;
}
// FUTURE:
// Ensure all sets and merge information are expired
// expire(true);
return true;
}
bool Foam::sampledSets::performAction(unsigned request)
{
if (empty())
{
// Nothing to do
return true;
}
else if (needsCorrect_)
{
searchEngine_.correct();
initDict(dict_, false);
}
// FUTURE:
// Update sets and store
// ...
// Determine availability of fields.
// Count number of fields (only seems to be needed for VTK legacy)
IOobjectList objects = preCheckFields();
const label nFields = selectedFieldNames_.size();
if (!nFields)
{
// Nothing to do
return true;
}
// Update writers
forAll(*this, seti)
{
const coordSet& s = gatheredSets_[seti];
if (request & ACTION_WRITE)
{
coordSetWriter& writer = writers_[seti];
if (writer.needsUpdate())
{
writer.setCoordinates(s);
}
if (writer.buffering())
{
writer.open
(
outputPath_
/ word(s.name() + coordSetWriter::suffix(selectedFieldNames_))
);
}
else
{
writer.open(outputPath_/s.name());
}
writer.beginTime(mesh_.time());
}
}
// Sample fields
performAction<VolumeField<scalar>>(objects, request);
performAction<VolumeField<vector>>(objects, request);
performAction<VolumeField<sphericalTensor>>(objects, request);
performAction<VolumeField<symmTensor>>(objects, request);
performAction<VolumeField<tensor>>(objects, request);
// Finish this time step
forAll(writers_, seti)
{
// Write geometry if no fields were written so that we still
// can have something to look at
if (request & ACTION_WRITE)
{
/// if (!writers_[seti].wroteData())
/// {
/// writers_[seti].write();
/// }
writers_[seti].endTime();
}
}
return true;
}
bool Foam::sampledSets::execute() bool Foam::sampledSets::execute()
{ {
if (onExecute_)
{
return performAction(ACTION_ALL & ~ACTION_WRITE);
}
return true; return true;
} }
bool Foam::sampledSets::write() bool Foam::sampledSets::write()
{ {
if (size()) return performAction(ACTION_ALL);
{
const label nFields = classifyFields();
if (Pstream::master())
{
if (debug)
{
Pout<< "timeName = " << mesh_.time().timeName() << nl
<< "scalarFields " << scalarFields_ << nl
<< "vectorFields " << vectorFields_ << nl
<< "sphTensorFields " << sphericalTensorFields_ << nl
<< "symTensorFields " << symmTensorFields_ <<nl
<< "tensorFields " << tensorFields_ <<nl;
}
if (nFields)
{
if (debug)
{
Pout<< "Creating directory "
<< outputPath_/mesh_.time().timeName()
<< nl << endl;
}
mkDir(outputPath_/mesh_.time().timeName());
}
else
{
Info<< "No fields to sample" << endl;
}
}
if (nFields)
{
sampleAndWrite(scalarFields_);
sampleAndWrite(vectorFields_);
sampleAndWrite(sphericalTensorFields_);
sampleAndWrite(symmTensorFields_);
sampleAndWrite(tensorFields_);
}
}
return true;
}
bool Foam::sampledSets::read(const dictionary& dict)
{
dict_ = dict;
if (dict_.found("sets"))
{
dict_.readEntry("fields", fieldSelection_);
clearFieldGroups();
dict.readEntry("interpolationScheme", interpolationScheme_);
dict.readEntry("setFormat", writeFormat_);
PtrList<sampledSet> newList
(
dict_.lookup("sets"),
sampledSet::iNew(mesh_, searchEngine_)
);
transfer(newList);
combineSampledSets(masterSampledSets_, indexSets_);
if (this->size())
{
Info<< "Reading set description:" << nl;
forAll(*this, setI)
{
Info<< " " << operator[](setI).name() << nl;
}
Info<< endl;
}
}
if (Pstream::master() && debug)
{
Pout<< "sample fields:" << fieldSelection_ << nl
<< "sample sets:" << nl << "(" << nl;
forAll(*this, setI)
{
Pout<< " " << operator[](setI) << endl;
}
Pout<< ")" << endl;
}
return true;
} }
void Foam::sampledSets::correct() void Foam::sampledSets::correct()
{ {
if (dict_.found("sets")) needsCorrect_ = true;
{
searchEngine_.correct();
PtrList<sampledSet> newList
(
dict_.lookup("sets"),
sampledSet::iNew(mesh_, searchEngine_)
);
transfer(newList);
combineSampledSets(masterSampledSets_, indexSets_);
}
} }

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2015-2018 OpenCFD Ltd. Copyright (C) 2015-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -29,24 +29,86 @@ Class
Description Description
Set of sets to sample. Set of sets to sample.
Call sampledSets.write() to sample and write files.
The write() method is used to sample and write files.
Example of function object specification:
\verbatim
surfaces
{
type sets;
libs (sampling);
// Write at same frequency as fields
writeControl writeTime;
writeInterval 1;
// Fields to be sampled
fields (p U);
// Scheme to obtain values
interpolationScheme cellPoint;
// Output format
surfaceFormat vtk;
formatOptions
{
vtk
{
precision 10;
}
}
sets
{
Uref
{
type cloud;
axis xyz;
points ((-0.0508 0.0508 0.01));
}
}
}
\endverbatim
Entries:
\table
Property | Description | Required | Default
type | Type-name: sets | yes |
sets | Dictionary or list of sample sets | expected |
fields | word/regex list of fields to sample | yes |
interpolationScheme | scheme to obtain values | no | cellPoint
setFormat | output format | yes |
sampleOnExecute | Sample (store) on execution as well | no | false
formatOptions | dictionary of format options | no |
\endtable
Additional per-set entries:
\table
Property | Description | Required | Default
store | Store surface/fields on registry | no |
setFormat | output format | no |
formatOptions | dictionary of format options | no |
\endtable
SourceFiles SourceFiles
sampledSets.C sampledSets.C
sampledSetsImpl.C
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef sampledSets_H #ifndef Foam_sampledSets_H
#define sampledSets_H #define Foam_sampledSets_H
#include "regionFunctionObject.H" #include "fvMeshFunctionObject.H"
#include "sampledSet.H" #include "sampledSet.H"
#include "volFieldsFwd.H"
#include "meshSearch.H" #include "meshSearch.H"
#include "interpolation.H"
#include "coordSet.H" #include "coordSet.H"
#include "writer.H" #include "coordSetWriter.H"
#include "wordRes.H" #include "volFieldsFwd.H"
#include "IOobjectList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -55,9 +117,8 @@ namespace Foam
// Forward Declarations // Forward Declarations
class Time; class Time;
class objectRegistry;
class dictionary; class dictionary;
class fvMesh; class globalIndex;
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class sampledSets Declaration Class sampledSets Declaration
@ -65,97 +126,37 @@ class fvMesh;
class sampledSets class sampledSets
: :
public functionObjects::regionFunctionObject, public functionObjects::fvMeshFunctionObject,
public PtrList<sampledSet> public PtrList<sampledSet>
{ {
// Private Classes
//- Class used for grouping field types
template<class Type>
class fieldGroup
:
public DynamicList<word>
{
public:
//- The set formatter
autoPtr<writer<Type>> formatter;
//- Construct null
fieldGroup() = default;
//- Reset format and field list
void clear()
{
DynamicList<word>::clear();
formatter.clear();
}
void setFormatter(const word& writeFormat, const dictionary& dict)
{
formatter = writer<Type>::New(writeFormat, dict);
}
};
//- Class used for sampling volFields
template<class Type>
class volFieldSampler
:
public List<Field<Type>>
{
//- Name of this collection of values
const word name_;
public:
//- Construct interpolating field to the sampleSets
volFieldSampler
(
const word& interpolationScheme,
const GeometricField<Type, fvPatchField, volMesh>& field,
const PtrList<sampledSet>&
);
//- Construct mapping field to the sampleSets
volFieldSampler
(
const GeometricField<Type, fvPatchField, volMesh>& field,
const PtrList<sampledSet>&
);
//- Construct from components
volFieldSampler
(
const List<Field<Type>>& values,
const word& name
);
//- Return the field name
const word& name() const
{
return name_;
}
};
// Static Data Members // Static Data Members
//- Output verbosity //- Local control for sampling actions
static bool verbose_; enum sampleActionType : unsigned
{
ACTION_NONE = 0,
ACTION_WRITE = 0x1,
ACTION_STORE = 0x2,
ACTION_ALL = 0xF
};
// Private Data // Private Data
//- Const reference to fvMesh
const fvMesh& mesh_;
//- Keep the dictionary to recreate sets for moving mesh cases //- Keep the dictionary to recreate sets for moving mesh cases
dictionary dict_; dictionary dict_;
//- Load fields from files (not from objectRegistry) //- Load fields from files (not from objectRegistry)
bool loadFromFiles_; bool loadFromFiles_;
//- Output verbosity
bool verbose_;
//- Perform sample/store actions on execute as well
bool onExecute_;
//- Correct meshSearch and update sets
bool needsCorrect_;
//- Output path //- Output path
fileName outputPath_; fileName outputPath_;
@ -168,8 +169,8 @@ class sampledSets
//- Names of fields to sample //- Names of fields to sample
wordRes fieldSelection_; wordRes fieldSelection_;
//- Interpolation scheme to use //- Interpolation/sample scheme to obtain values at the points
word interpolationScheme_; word samplePointScheme_;
//- Output format to use //- Output format to use
word writeFormat_; word writeFormat_;
@ -178,61 +179,76 @@ class sampledSets
dictionary writeFormatOptions_; dictionary writeFormatOptions_;
// Categorized scalar/vector/tensor fields // Output control
fieldGroup<scalar> scalarFields_; //- The coordSet writers (one per sampled set)
fieldGroup<vector> vectorFields_; PtrList<coordSetWriter> writers_;
fieldGroup<sphericalTensor> sphericalTensorFields_;
fieldGroup<symmTensor> symmTensorFields_; //- Current list of field names selected for sampling
fieldGroup<tensor> tensorFields_; DynamicList<word> selectedFieldNames_;
// Merging structures // Merging
PtrList<coordSet> masterSampledSets_; //- Gathered coordSet. (Content only meaningful on master)
labelListList indexSets_; PtrList<coordSet> gatheredSets_;
//- Indexed sort order for gathered coordSet.
// (Content only meaningful on master)
List<labelList> gatheredSorting_;
//- The globalIndex for gathering. (Content only meaningful on master)
List<globalIndex> globalIndices_;
// Private Member Functions // Private Member Functions
//- Clear old field groups //- A new coordSet writer, with per-set formatOptions
void clearFieldGroups(); static autoPtr<coordSetWriter> newWriter
//- Classify field types, returns the number of fields
label classifyFields();
//- Combine points from all processors. Sort by curveDist and produce
//- index list. Valid result only on master processor.
void combineSampledSets
( (
PtrList<coordSet>& masterSampledSets, word writeType,
labelListList& indexSets const dictionary& formatOptions,
const dictionary& surfDict
); );
//- Combine values from all processors. //- Perform sampling action with store/write
// Valid result only on master processor. bool performAction(unsigned request);
template<class T>
void combineSampledValues
(
const PtrList<volFieldSampler<T>>& sampledFields,
const labelListList& indexSets,
PtrList<volFieldSampler<T>>& masterFields
);
//- Write set on master, return fileName //- Count selected/sampled fields
// Returns empty IOobjectList if loadFromFiles_ is not active
//
// Adjusts selectedFieldNames_
IOobjectList preCheckFields();
//- Setup the sets (optional writers)
void initDict(const dictionary& dict, const bool initial);
//- Combine points from all processors.
//- Sort by curve distance and produce index list.
//- Valid result only on master processor.
void gatherAllSets();
//- Write sampled fieldName on coordSet and on outputDir path
template<class Type> template<class Type>
fileName writeSampleFile void writeCoordSet
( (
const coordSet& masterSampleSet, coordSetWriter& writer,
const PtrList<volFieldSampler<Type>>& masterFields, const Field<Type>& values,
const label setI, const word& fieldName
const fileName& timeDir,
const writer<Type>& formatter
); );
template<class Type> //- Get from registry or load from disk
void sampleAndWrite(fieldGroup<Type>& fields); template<class GeoField>
tmp<GeoField> getOrLoadField(const word& fieldName) const;
//- Sample and store/write a specific volume field
template<class Type>
void performAction(const VolumeField<Type>& field, unsigned request);
//- Sample and write all applicable sampled fields
// Only uses IOobjectList when loadFromFiles_ is active
template<class GeoField>
void performAction(const IOobjectList& objects, unsigned request);
//- No copy construct //- No copy construct
sampledSets(const sampledSets&) = delete; sampledSets(const sampledSets&) = delete;
@ -253,7 +269,7 @@ public:
sampledSets sampledSets
( (
const word& name, const word& name,
const Time& time, const Time& runTime,
const dictionary& dict const dictionary& dict
); );
@ -262,8 +278,8 @@ public:
sampledSets sampledSets
( (
const word& name, const word& name,
const objectRegistry&, const objectRegistry& obr,
const dictionary&, const dictionary& dict,
const bool loadFromFiles = false const bool loadFromFiles = false
); );
@ -276,7 +292,7 @@ public:
//- Enable/disable verbose output //- Enable/disable verbose output
// \return old value // \return old value
bool verbose(const bool on); bool verbose(const bool on) noexcept;
//- Read the sampledSets //- Read the sampledSets
virtual bool read(const dictionary&); virtual bool read(const dictionary&);
@ -307,12 +323,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "sampledSetsTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif #endif
// ************************************************************************* // // ************************************************************************* //

View File

@ -1,129 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sampledSets.H"
#include "volFields.H"
#include "IOobjectList.H"
#include "UIndirectList.H"
#include "ListOps.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::sampledSets::clearFieldGroups()
{
scalarFields_.clear();
vectorFields_.clear();
sphericalTensorFields_.clear();
symmTensorFields_.clear();
tensorFields_.clear();
}
Foam::label Foam::sampledSets::classifyFields()
{
label nFields = 0;
clearFieldGroups();
wordList allFields; // Just needed for warnings
HashTable<wordHashSet> available;
if (loadFromFiles_)
{
// Check files for a particular time
IOobjectList objects(mesh_, mesh_.time().timeName());
allFields = objects.names();
available = objects.classes(fieldSelection_);
}
else
{
// Check currently available fields
allFields = mesh_.names();
available = mesh_.classes(fieldSelection_);
}
DynamicList<label> missed(fieldSelection_.size());
// Detect missing fields
forAll(fieldSelection_, i)
{
if (!ListOps::found(allFields, fieldSelection_[i]))
{
missed.append(i);
}
}
if (missed.size())
{
WarningInFunction
<< nl
<< "Cannot find "
<< (loadFromFiles_ ? "field file" : "registered field")
<< " matching "
<< UIndirectList<wordRe>(fieldSelection_, missed) << endl;
}
forAllConstIters(available, iter)
{
const word& fieldType = iter.key();
const wordList fieldNames = iter.val().sortedToc();
const label count = fieldNames.size(); // pre-filtered, so non-empty
if (fieldType == volScalarField::typeName)
{
scalarFields_.append(fieldNames);
nFields += count;
}
else if (fieldType == volVectorField::typeName)
{
vectorFields_.append(fieldNames);
nFields += count;
}
else if (fieldType == volSphericalTensorField::typeName)
{
sphericalTensorFields_.append(fieldNames);
nFields += count;
}
else if (fieldType == volSymmTensorField::typeName)
{
symmTensorFields_.append(fieldNames);
nFields += count;
}
else if (fieldType == volTensorField::typeName)
{
tensorFields_.append(fieldNames);
nFields += count;
}
}
return nFields;
}
// ************************************************************************* //

View File

@ -0,0 +1,241 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sampledSets.H"
#include "globalIndex.H"
#include "interpolation.H"
#include "volFields.H"
#include "volPointInterpolation.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class GeoField>
Foam::tmp<GeoField>
Foam::sampledSets::getOrLoadField(const word& fieldName) const
{
tmp<GeoField> tfield;
if (loadFromFiles_)
{
tfield.reset
(
new GeoField
(
IOobject
(
fieldName,
mesh_.time().timeName(),
mesh_,
IOobject::MUST_READ,
IOobject::NO_WRITE,
false
),
mesh_
)
);
}
else
{
// Slightly paranoid here
tfield.cref(mesh_.cfindObject<GeoField>(fieldName));
}
return tfield;
}
template<class Type>
void Foam::sampledSets::writeCoordSet
(
coordSetWriter& writer,
const Field<Type>& values,
const word& fieldName
)
{
fileName outputName;
if (Pstream::master())
{
outputName = writer.write(fieldName, values);
}
Pstream::scatter(outputName);
if (outputName.size())
{
// Case-local file name with "<case>" to make relocatable
dictionary propsDict;
propsDict.add
(
"file",
time_.relativePath(outputName, true)
);
setProperty(fieldName, propsDict);
}
}
template<class Type>
void Foam::sampledSets::performAction
(
const VolumeField<Type>& fld,
unsigned request
)
{
const word& fieldName = fld.name();
// The interpolator for this field
autoPtr<interpolation<Type>> interpPtr;
if (!samplePointScheme_.empty() && samplePointScheme_ != "cell")
{
interpPtr.reset(interpolation<Type>::New(samplePointScheme_, fld));
}
forAll(*this, seti)
{
const sampledSet& s = (*this)[seti];
const globalIndex& globIdx = globalIndices_[seti];
const labelList& globOrder = gatheredSorting_[seti];
const word& setName = s.name();
Field<Type> values(s.size());
if (interpPtr)
{
forAll(s, samplei)
{
const point& p = s[samplei];
const label celli = s.cells()[samplei];
const label facei = s.faces()[samplei];
if (celli == -1 && facei == -1)
{
// Special condition for illegal sampling points
values[samplei] = pTraits<Type>::max;
}
else
{
values[samplei] = interpPtr().interpolate(p, celli, facei);
}
}
}
else
{
forAll(s, samplei)
{
const label celli = s.cells()[samplei];
if (celli == -1)
{
values[samplei] = pTraits<Type>::max;
}
else
{
values[samplei] = fld[celli];
}
}
}
// Collect data from all processors
globIdx.gatherInplace(values);
// Some values only available on master
Type avgValue, minValue, maxValue;
label sizeValue;
if (Pstream::master())
{
avgValue = average(values);
minValue = min(values);
maxValue = max(values);
sizeValue = values.size();
// Use sorted order
values = UIndirectList<Type>(values, globOrder)();
}
Pstream::scatter(avgValue);
Pstream::scatter(minValue);
Pstream::scatter(maxValue);
Pstream::scatter(sizeValue);
// Store results: min/max/average/size with the name of the set
// for scoping.
// Eg, average(lines,T) ...
const word resultArg('(' + setName + ',' + fieldName + ')');
this->setResult("average" + resultArg, avgValue);
this->setResult("min" + resultArg, minValue);
this->setResult("max" + resultArg, maxValue);
this->setResult("size" + resultArg, sizeValue);
if (verbose_)
{
Info<< name() << ' ' << setName << " : " << fieldName << nl
<< " avg: " << avgValue << nl
<< " min: " << minValue << nl
<< " max: " << maxValue << nl << nl;
}
if (request & ACTION_WRITE)
{
writeCoordSet<Type>(writers_[seti], values, fieldName);
}
}
}
template<class GeoField>
void Foam::sampledSets::performAction
(
const IOobjectList& objects,
unsigned request
)
{
wordList fieldNames;
if (loadFromFiles_)
{
fieldNames = objects.sortedNames<GeoField>(fieldSelection_);
}
else
{
fieldNames = mesh_.thisDb().sortedNames<GeoField>(fieldSelection_);
}
for (const word& fieldName : fieldNames)
{
tmp<GeoField> tfield = getOrLoadField<GeoField>(fieldName);
if (tfield)
{
performAction<typename GeoField::value_type>(tfield(), request);
}
}
}
// ************************************************************************* //

View File

@ -1,376 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sampledSets.H"
#include "volFields.H"
#include "globalIndex.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type>
Foam::sampledSets::volFieldSampler<Type>::volFieldSampler
(
const word& interpolationScheme,
const GeometricField<Type, fvPatchField, volMesh>& field,
const PtrList<sampledSet>& samplers
)
:
List<Field<Type>>(samplers.size()),
name_(field.name())
{
autoPtr<interpolation<Type>> interpolator
(
interpolation<Type>::New(interpolationScheme, field)
);
forAll(samplers, setI)
{
Field<Type>& values = this->operator[](setI);
const sampledSet& samples = samplers[setI];
values.setSize(samples.size());
forAll(samples, sampleI)
{
const point& samplePt = samples[sampleI];
label celli = samples.cells()[sampleI];
label facei = samples.faces()[sampleI];
if (celli == -1 && facei == -1)
{
// Special condition for illegal sampling points
values[sampleI] = pTraits<Type>::max;
}
else
{
values[sampleI] = interpolator().interpolate
(
samplePt,
celli,
facei
);
}
}
}
}
template<class Type>
Foam::sampledSets::volFieldSampler<Type>::volFieldSampler
(
const GeometricField<Type, fvPatchField, volMesh>& field,
const PtrList<sampledSet>& samplers
)
:
List<Field<Type>>(samplers.size()),
name_(field.name())
{
forAll(samplers, setI)
{
Field<Type>& values = this->operator[](setI);
const sampledSet& samples = samplers[setI];
values.setSize(samples.size());
forAll(samples, sampleI)
{
label celli = samples.cells()[sampleI];
if (celli ==-1)
{
values[sampleI] = pTraits<Type>::max;
}
else
{
values[sampleI] = field[celli];
}
}
}
}
template<class Type>
Foam::sampledSets::volFieldSampler<Type>::volFieldSampler
(
const List<Field<Type>>& values,
const word& name
)
:
List<Field<Type>>(values),
name_(name)
{}
template<class Type>
Foam::fileName Foam::sampledSets::writeSampleFile
(
const coordSet& masterSampleSet,
const PtrList<volFieldSampler<Type>>& masterFields,
const label setI,
const fileName& timeDir,
const writer<Type>& formatter
)
{
wordList valueSetNames(masterFields.size());
List<const Field<Type>*> valueSets(masterFields.size());
forAll(masterFields, fieldi)
{
const word& fieldName = masterFields[fieldi].name();
valueSetNames[fieldi] = fieldName;
// Values only available on master
Type averageValue, minValue, maxValue;
label sizeValue;
if (Pstream::master())
{
valueSets[fieldi] = &masterFields[fieldi][setI];
averageValue = average(*valueSets[fieldi]);
minValue = min(*valueSets[fieldi]);
maxValue = max(*valueSets[fieldi]);
sizeValue = valueSets[fieldi]->size();
}
Pstream::scatter(averageValue);
Pstream::scatter(minValue);
Pstream::scatter(maxValue);
Pstream::scatter(sizeValue);
// Set results
setResult("average(" + fieldName + ")", averageValue);
setResult("min(" + fieldName + ")", minValue);
setResult("max(" + fieldName + ")", maxValue);
setResult("size(" + fieldName + ")", sizeValue);
}
fileName fName;
if (Pstream::master())
{
fName = timeDir/formatter.getFileName(masterSampleSet, valueSetNames);
OFstream ofs(fName);
if (ofs.opened())
{
formatter.write
(
masterSampleSet,
valueSetNames,
valueSets,
ofs
);
}
else
{
WarningInFunction
<< "File " << ofs.name() << " could not be opened. "
<< "No data will be written" << endl;
}
}
Pstream::scatter(fName);
return fName;
}
template<class T>
void Foam::sampledSets::combineSampledValues
(
const PtrList<volFieldSampler<T>>& sampledFields,
const labelListList& indexSets,
PtrList<volFieldSampler<T>>& masterFields
)
{
forAll(sampledFields, fieldi)
{
List<Field<T>> masterValues(indexSets.size());
forAll(indexSets, setI)
{
// Collect data from all processors
Field<T> allData;
globalIndex::gatherOp(sampledFields[fieldi][setI], allData);
if (Pstream::master())
{
masterValues[setI] = UIndirectList<T>
(
allData,
indexSets[setI]
)();
}
}
masterFields.set
(
fieldi,
new volFieldSampler<T>
(
masterValues,
sampledFields[fieldi].name()
)
);
}
}
template<class Type>
void Foam::sampledSets::sampleAndWrite(fieldGroup<Type>& fields)
{
if (fields.size())
{
const bool interpolate = interpolationScheme_ != "cell";
// Create or use existing writer
if (!fields.formatter)
{
fields.setFormatter(writeFormat_, writeFormatOptions_);
}
// Storage for interpolated values
PtrList<volFieldSampler<Type>> sampledFields(fields.size());
forAll(fields, fieldi)
{
if (Pstream::master() && verbose_)
{
Pout<< "sampledSets::sampleAndWrite: "
<< fields[fieldi] << endl;
}
if (loadFromFiles_)
{
GeometricField<Type, fvPatchField, volMesh> vf
(
IOobject
(
fields[fieldi],
mesh_.time().timeName(),
mesh_,
IOobject::MUST_READ,
IOobject::NO_WRITE,
false
),
mesh_
);
if (interpolate)
{
sampledFields.set
(
fieldi,
new volFieldSampler<Type>
(
interpolationScheme_,
vf,
*this
)
);
}
else
{
sampledFields.set
(
fieldi,
new volFieldSampler<Type>(vf, *this)
);
}
}
else
{
if (interpolate)
{
sampledFields.set
(
fieldi,
new volFieldSampler<Type>
(
interpolationScheme_,
mesh_.lookupObject
<GeometricField<Type, fvPatchField, volMesh>>
(fields[fieldi]),
*this
)
);
}
else
{
sampledFields.set
(
fieldi,
new volFieldSampler<Type>
(
mesh_.lookupObject
<GeometricField<Type, fvPatchField, volMesh>>
(fields[fieldi]),
*this
)
);
}
}
}
// Combine sampled fields from processors.
// Note: only master results are valid
PtrList<volFieldSampler<Type>> masterFields(sampledFields.size());
combineSampledValues(sampledFields, indexSets_, masterFields);
forAll(masterSampledSets_, setI)
{
fileName sampleFile = writeSampleFile
(
masterSampledSets_[setI],
masterFields,
setI,
outputPath_/mesh_.time().timeName(),
fields.formatter()
);
if (sampleFile.size())
{
// Case-local file name with "<case>" to make relocatable
forAll(masterFields, fieldi)
{
dictionary propsDict;
propsDict.add
(
"file",
time_.relativePath(sampleFile, true)
);
const word& fieldName = masterFields[fieldi].name();
setProperty(fieldName, propsDict);
}
}
}
}
}
// ************************************************************************* //

View File

@ -940,7 +940,7 @@ void Foam::shortestPathSet::genSamples
// Get the target point // Get the target point
const label outsideCelli = mesh.findCell(outsidePoint); const label outsideCelli = mesh.findCell(outsidePoint);
// Maintain overall track length. Used to make curveDist continuous. // Maintain overall track length. Used to make curve distance continuous.
scalar trackLength = 0; scalar trackLength = 0;
List<topoDistanceData<label>> allFaceInfo(mesh.nFaces()); List<topoDistanceData<label>> allFaceInfo(mesh.nFaces());