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

View File

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

View File

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

View File

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

View File

@ -74,7 +74,7 @@ Usage
#include "Time.H"
#include "fvMesh.H"
#include "globalMeshData.H"
#include "vtkSetWriter.H"
#include "vtkCoordSetWriter.H"
#include "vtkSurfaceWriter.H"
#include "IOdictionary.H"
#include "regionProperties.H"
@ -262,11 +262,11 @@ int main(int argc, char *argv[])
autoPtr<surfaceWriter> surfWriter;
autoPtr<writer<scalar>> setWriter;
autoPtr<coordSetWriter> setWriter;
if (writeSets)
{
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 "cellSet.H"
#include "Time.H"
#include "writer.H"
#include "coordSetWriter.H"
#include "surfaceWriter.H"
#include "syncTools.H"
#include "globalIndex.H"
@ -417,7 +417,7 @@ void Foam::mergeAndWrite
void Foam::mergeAndWrite
(
const writer<scalar>& writer,
coordSetWriter& writer,
const pointSet& set
)
{
@ -441,39 +441,26 @@ void Foam::mergeAndWrite
}
// Write with scalar pointID
// Write with pointID
if (Pstream::master())
{
scalarField scalarPointIDs(mergedIDs.size());
forAll(mergedIDs, i)
{
scalarPointIDs[i] = 1.0*mergedIDs[i];
}
coordSet coords(set.name(), "distance", mergedPts, mag(mergedPts));
coordSet points(set.name(), "distance", mergedPts, mag(mergedPts));
// Output. E.g. pointSet p0 -> postProcessing/<time>/p0.vtk
List<const scalarField*> flds(1, &scalarPointIDs);
wordList fldNames(1, "pointID");
// Output e.g. pointSet p0 to
// postProcessing/<time>/p0.vtk
fileName outputDir
fileName outputPath
(
set.time().globalPath()
/ functionObject::outputPrefix
/ mesh.pointsInstance()
// set.name()
/ set.name()
);
outputDir.clean(); // Remove unneeded ".."
mkDir(outputDir);
outputPath.clean(); // Remove unneeded ".."
fileName outputFile(outputDir/writer.getFileName(points, wordList()));
//fileName outputFile(outputDir/set.name());
OFstream os(outputFile);
writer.write(points, fldNames, flds, os);
writer.open(coords, outputPath);
writer.nFields(1);
writer.write("pointID", mergedIDs);
writer.close(true);
}
}

View File

@ -10,7 +10,7 @@ namespace Foam
class cellSet;
class fileName;
class polyMesh;
template<class T> class writer;
class coordSetWriter;
class surfaceWriter;
void printMeshStats(const polyMesh& mesh, const bool allTopology);
@ -36,7 +36,7 @@ namespace Foam
//- Write vtk representation of (assembled) pointSet to 'set' file in
// 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 "emptyPolyPatch.H"
#include "processorPolyPatch.H"
#include "vtkSetWriter.H"
#include "vtkCoordSetWriter.H"
#include "vtkSurfaceWriter.H"
#include "checkTools.H"
#include "treeBoundBox.H"
@ -117,7 +117,7 @@ Foam::label Foam::checkTopology
const bool allTopology,
const bool allGeometry,
autoPtr<surfaceWriter>& surfWriter,
const autoPtr<writer<scalar>>& setWriter
autoPtr<coordSetWriter>& setWriter
)
{
label noFailedChecks = 0;
@ -203,7 +203,7 @@ Foam::label Foam::checkTopology
<< " illegal cells to set " << cells.name() << endl;
cells.instance() = mesh.pointsInstance();
cells.write();
if (surfWriter)
if (surfWriter && surfWriter->enabled())
{
mergeAndWrite(*surfWriter, cells);
}
@ -227,7 +227,7 @@ Foam::label Foam::checkTopology
<< " unused points to set " << points.name() << endl;
points.instance() = mesh.pointsInstance();
points.write();
if (setWriter)
if (setWriter && setWriter->enabled())
{
mergeAndWrite(*setWriter, points);
}
@ -249,7 +249,7 @@ Foam::label Foam::checkTopology
<< " unordered faces to set " << faces.name() << endl;
faces.instance() = mesh.pointsInstance();
faces.write();
if (surfWriter)
if (surfWriter && surfWriter->enabled())
{
mergeAndWrite(*surfWriter, faces);
}
@ -269,7 +269,7 @@ Foam::label Foam::checkTopology
<< faces.name() << endl;
faces.instance() = mesh.pointsInstance();
faces.write();
if (surfWriter)
if (surfWriter && surfWriter->enabled())
{
mergeAndWrite(*surfWriter, faces);
}
@ -290,11 +290,10 @@ Foam::label Foam::checkTopology
<< endl;
cells.instance() = mesh.pointsInstance();
cells.write();
if (surfWriter)
if (surfWriter && surfWriter->enabled())
{
mergeAndWrite(*surfWriter, cells);
}
}
}
@ -314,7 +313,7 @@ Foam::label Foam::checkTopology
<< faces.name() << endl;
faces.instance() = mesh.pointsInstance();
faces.write();
if (surfWriter)
if (surfWriter && surfWriter->enabled())
{
mergeAndWrite(*surfWriter, faces);
}
@ -369,7 +368,7 @@ Foam::label Foam::checkTopology
<< endl;
oneCells.instance() = mesh.pointsInstance();
oneCells.write();
if (surfWriter)
if (surfWriter && surfWriter->enabled())
{
mergeAndWrite(*surfWriter, oneCells);
}
@ -385,7 +384,7 @@ Foam::label Foam::checkTopology
<< endl;
twoCells.instance() = mesh.pointsInstance();
twoCells.write();
if (surfWriter)
if (surfWriter && surfWriter->enabled())
{
mergeAndWrite(*surfWriter, twoCells);
}
@ -530,7 +529,7 @@ Foam::label Foam::checkTopology
<< " points that are in multiple regions to set "
<< points.name() << endl;
points.write();
if (setWriter)
if (setWriter && setWriter->enabled())
{
mergeAndWrite(*setWriter, points);
}
@ -641,7 +640,7 @@ Foam::label Foam::checkTopology
<< " conflicting points to set " << points.name() << endl;
points.instance() = mesh.pointsInstance();
points.write();
if (setWriter)
if (setWriter && setWriter->enabled())
{
mergeAndWrite(*setWriter, points);
}

View File

@ -6,7 +6,7 @@ namespace Foam
// Forward Declarations
class polyMesh;
class pointSet;
template<class T> class writer;
class coordSetWriter;
class surfaceWriter;
template<class PatchType>
@ -24,6 +24,6 @@ namespace Foam
const bool allTopology,
const bool allGeometry,
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"));
// 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"));

View File

@ -42,199 +42,34 @@ Description
#include "fvMesh.H"
#include "Time.H"
#include "timeSelector.H"
#include "OFstream.H"
#include "coordSetWriter.H"
#include "passiveParticleCloud.H"
#include "writer.H"
#include "ListOps.H"
#include "particleTracksSampler.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;
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>
void writeTrackFields
(
List<List<DynamicList<Type>>>& fieldValues,
const wordList& fieldNames,
const PtrList<coordSet>& tracks,
const List<scalarField>& times,
const List<vectorField>& dirs,
const word& setFormat,
const dictionary& formatOptions,
const word& cloudName
coordSetWriter& writer,
HashTable<List<DynamicList<Type>>>& fieldTable
)
{
if (fieldValues.empty())
for (const word& fieldName : fieldTable.sortedToc())
{
return;
}
// Steal and reshape from List<DynamicList> to List<Field>
auto& input = fieldTable[fieldName];
auto writerPtr = writer<Type>::New(setFormat, formatOptions);
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)
List<Field<Type>> fields(input.size());
forAll(input, tracki)
{
fields[fieldi][tracki].transfer(fieldValues[fieldi][tracki]);
fields[tracki].transfer(input[tracki]);
}
writer.write(fieldName, fields);
}
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"
);
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",
"name",
@ -285,137 +128,147 @@ int main(int argc, char *argv[])
#include "createControls.H"
args.readListIfPresent<wordRe>("fields", acceptFields);
args.readIfPresent("format", setFormat);
args.readIfPresent("stride", sampleFrequency);
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");
mkDir(vtkPath);
particleTracksSampler trackSampler;
Info<< "Scanning times to determine track data for cloud " << cloudName
<< nl << endl;
labelList maxIds(Pstream::nProcs(), -1);
forAll(timeDirs, timei)
{
runTime.setTime(timeDirs[timei], timei);
Info<< "Time = " << runTime.timeName() << endl;
Info<< " Reading particle positions" << endl;
passiveParticleCloud myCloud(mesh, cloudName);
Info<< " Read " << returnReduce(myCloud.size(), sumOp<label>())
<< " particles" << endl;
for (const passiveParticle& p : myCloud)
labelList maxIds(Pstream::nProcs(), -1);
forAll(timeDirs, timei)
{
const label origId = p.origId();
const label origProc = p.origProc();
runTime.setTime(timeDirs[timei], timei);
Info<< "Time = " << runTime.timeName() << endl;
// Handle case where we are processing particle data generated in
// parallel using more cores than when running this application.
if (origProc >= maxIds.size())
passiveParticleCloud myCloud(mesh, cloudName);
Info<< " Read " << returnReduce(myCloud.size(), sumOp<label>())
<< " particles" << endl;
for (const passiveParticle& p : myCloud)
{
maxIds.setSize(origProc+1, -1);
}
const label origId = p.origId();
const label origProc = p.origProc();
maxIds[origProc] = max(maxIds[origProc], origId);
// Handle case where processing particle data generated in
// parallel using more cores than for this application.
if (origProc >= maxIds.size())
{
maxIds.resize(origProc+1, -1);
}
maxIds[origProc] = max(maxIds[origProc], origId);
}
}
const label maxNProcs = returnReduce(maxIds.size(), maxOp<label>());
maxIds.resize(maxNProcs, -1);
Pstream::listCombineGather(maxIds, maxEqOp<label>());
Pstream::listCombineScatter(maxIds);
// From ids to count
const labelList numIds = maxIds + 1;
// Set parcel addressing
trackSampler.reset(numIds);
Info<< nl
<< "Detected particles originating from "
<< maxNProcs << " processors." << nl
<< "Particle statistics:" << endl;
if (Pstream::master())
{
const globalIndex& parcelAddr = trackSampler.parcelAddr();
for (const label proci : parcelAddr.allProcs())
{
Info<< " Found " << parcelAddr.localSize(proci)
<< " particles originating"
<< " from processor " << proci << nl;
}
}
}
label maxNProcs = returnReduce(maxIds.size(), maxOp<label>());
Info<< "Detected particles originating from " << maxNProcs
<< " processors." << nl << endl;
maxIds.setSize(maxNProcs, -1);
Pstream::listCombineGather(maxIds, maxEqOp<label>());
Pstream::listCombineScatter(maxIds);
labelList numIds = maxIds + 1;
Info<< nl << "Particle statistics:" << endl;
forAll(maxIds, proci)
{
Info<< " Found " << numIds[proci] << " particles originating"
<< " from processor " << proci << endl;
}
Info<< nl << endl;
// 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];
}
label nParticle = startIds.last() + numIds[startIds.size()-1];
trackSampler.setSampleRate(sampleFrequency, maxPositions, maxTracks);
// Number of tracks to generate
const label nTracks =
maxTracks > 0
? min(nParticle/sampleFrequency, maxTracks)
: nParticle/sampleFrequency;
const label nTracks = trackSampler.nTracks();
// Storage for all particle tracks
List<DynamicList<vector>> allTracks(nTracks);
List<DynamicList<point>> allTrackPos(nTracks);
List<DynamicList<scalar>> allTrackTimes(nTracks);
// Lists of field, tracki, trackValues
//List<List<DynamicList<label>>> labelFields;
List<List<DynamicList<scalar>>> scalarFields;
List<List<DynamicList<vector>>> vectorFields;
List<List<DynamicList<sphericalTensor>>> sphTensorFields;
List<List<DynamicList<symmTensor>>> symTensorFields;
List<List<DynamicList<tensor>>> tensorFields;
//List<word> labelFieldNames;
List<word> scalarFieldNames;
List<word> vectorFieldNames;
List<word> sphTensorFieldNames;
List<word> symTensorFieldNames;
List<word> tensorFieldNames;
// Track field values by name/type
HashTable<List<DynamicList<label>>> labelFields; // <- mostly unused
HashTable<List<DynamicList<scalar>>> scalarFields;
HashTable<List<DynamicList<vector>>> vectorFields;
HashTable<List<DynamicList<sphericalTensor>>> sphericalTensorFields;
HashTable<List<DynamicList<symmTensor>>> symmTensorFields;
HashTable<List<DynamicList<tensor>>> tensorFields;
Info<< "\nGenerating " << nTracks << " particle tracks for cloud "
<< cloudName << nl << endl;
Info<< nl
<< "Generating " << nTracks
<< " particle tracks for cloud " << cloudName << nl << endl;
forAll(timeDirs, 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.
Info<< " Reading particle positions" << endl;
passiveParticleCloud myCloud(mesh, cloudName);
pointField localPositions(myCloud.size(), Zero);
scalarField localTimes(myCloud.size(), Zero);
pointField localPositions(myCloud.size());
scalarField localTimes(myCloud.size(), runTime.value());
List<labelField> allOrigIds(Pstream::nProcs());
List<labelField> allOrigProcs(Pstream::nProcs());
// Collect the track data on all processors that have positions
allOrigIds[Pstream::myProcNo()].setSize(myCloud.size(), Zero);
allOrigProcs[Pstream::myProcNo()].setSize(myCloud.size(), Zero);
label i = 0;
for (const passiveParticle& p : myCloud)
// Gather track data from all processors that have positions
trackSampler.resetCloud(myCloud.size());
{
allOrigIds[Pstream::myProcNo()][i] = p.origId();
allOrigProcs[Pstream::myProcNo()][i] = p.origProc();
localPositions[i] = p.position();
localTimes[i] = runTime.value();
++i;
labelField& origIds = trackSampler.origParcelIds_;
labelField& origProcs = trackSampler.origProcIds_;
label np = 0;
for (const passiveParticle& p : myCloud)
{
origIds[np] = p.origId();
origProcs[np] = p.origProc();
localPositions[np] = p.position();
++np;
}
trackSampler.gatherInplace(origIds);
trackSampler.gatherInplace(origProcs);
}
// Collect the track data on the master processor
Pstream::gatherList(allOrigIds);
Pstream::gatherList(allOrigProcs);
// Read cloud fields (from disk) into object registry
objectRegistry obr
(
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
// (not registered as IOFields)
// Note: createTrack is a local #define to reduce arg count...
createTrack(localPositions, allTracks);
createTrack(localTimes, allTrackTimes);
trackSampler.createTrackField(localPositions, allTrackPos);
trackSampler.createTrackField(localTimes, allTrackTimes);
// Create the track fields
// Note: setFields is a local #define to reduce arg count...
//setFields(labelFields, labelFieldNames);
setFields(scalarFields, scalarFieldNames);
setFields(vectorFields, vectorFieldNames);
setFields(sphTensorFields, sphTensorFieldNames);
setFields(symTensorFields, symTensorFieldNames);
setFields(tensorFields, tensorFieldNames);
///trackSampler.setTrackFields(obr, labelFields);
trackSampler.setTrackFields(obr, scalarFields);
trackSampler.setTrackFields(obr, vectorFields);
trackSampler.setTrackFields(obr, sphericalTensorFields);
trackSampler.setTrackFields(obr, symmTensorFields);
trackSampler.setTrackFields(obr, tensorFields);
}
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())
{
PtrList<coordSet> tracks(allTracks.size());
List<scalarField> times(tracks.size());
PtrList<coordSet> tracks(allTrackPos.size());
List<scalarField> times(allTrackPos.size());
forAll(tracks, tracki)
{
tracks.set
(
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]);
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];
forAll(UTracks, tracki)
{
const auto& U = UTracks[tracki];
dirs[tracki] = U/(mag(U) + ROOTVSMALL);
}
}
auto& writer = *writerPtr;
// Write track fields
// Note: writeFields is a local #define to reduce arg count...
//writeFields(allLabelFields, labelFieldNames, tracks);
writeFields(scalarFields, scalarFieldNames, tracks, times, dirs);
writeFields(vectorFields, vectorFieldNames, tracks, times, dirs);
writeFields(sphTensorFields, sphTensorFieldNames, tracks, times, dirs);
writeFields(symTensorFields, symTensorFieldNames, tracks, times, dirs);
writeFields(tensorFields, tensorFieldNames, tracks, times, dirs);
const fileName outputPath
(
functionObject::outputPrefix/cloud::prefix/cloudName
/ "particleTracks" / "tracks"
);
Info<< " "
<< 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;

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"));
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
(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -441,7 +441,7 @@ void Foam::meshRefinement::nearestFace
(
const labelUList& startFaces,
const bitSet& isBlockedFace,
autoPtr<mapDistribute>& mapPtr,
labelList& faceToStart,
const label nIter
@ -2808,23 +2808,19 @@ Foam::fileName Foam::meshRefinement::writeLeakPath
const polyMesh& mesh,
const pointField& locationsInMesh,
const pointField& locationsOutsideMesh,
const writer<scalar>& leakPathFormatter,
const boolList& blockedFace
const boolList& blockedFace,
coordSetWriter& writer
)
{
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
fileName outputDir;
if (Pstream::master())
{
outputDir =
mesh.time().globalPath()
/ functionObject::outputPrefix
/ mesh.pointsInstance();
outputDir.clean();
mkDir(outputDir);
}
fileName outputDir
(
mesh.time().globalPath()
/ functionObject::outputPrefix
/ mesh.pointsInstance()
);
outputDir.clean(); // Remove unneeded ".."
// Write the leak path
@ -2877,7 +2873,7 @@ Foam::fileName Foam::meshRefinement::writeLeakPath
label& n = nElemsPerSegment[segmenti];
points[n] = leakPath[elemi];
dist[n] = leakPath.curveDist()[elemi];
dist[n] = leakPath.distance()[elemi];
n++;
}
}
@ -2887,13 +2883,11 @@ Foam::fileName Foam::meshRefinement::writeLeakPath
{
// Collect data from all processors
List<pointList> gatheredPts(Pstream::nProcs());
gatheredPts[Pstream::myProcNo()] =
std::move(segmentPoints[segmenti]);
gatheredPts[Pstream::myProcNo()] = std::move(segmentPoints[segmenti]);
Pstream::gatherList(gatheredPts);
List<scalarList> gatheredDist(Pstream::nProcs());
gatheredDist[Pstream::myProcNo()] =
std::move(segmentDist[segmenti]);
gatheredDist[Pstream::myProcNo()] = std::move(segmentDist[segmenti]);
Pstream::gatherList(gatheredDist);
// 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));
allLeakPaths.set
@ -2932,42 +2926,28 @@ Foam::fileName Foam::meshRefinement::writeLeakPath
fileName fName;
if (Pstream::master())
{
List<List<scalarField>> allLeakData(1);
List<scalarField>& varData = allLeakData[0];
varData.setSize(allLeakPaths.size());
List<scalarField> allLeakData(allLeakPaths.size());
forAll(allLeakPaths, segmenti)
{
varData[segmenti] = allLeakPaths[segmenti].curveDist();
allLeakData[segmenti] = allLeakPaths[segmenti].distance();
}
const wordList valueSetNames(1, "leakPath");
writer.nFields(1);
fName =
outputDir
/leakPathFormatter.getFileName
(
allLeakPaths[0],
valueSetNames
);
writer.open
(
allLeakPaths,
(outputDir / allLeakPaths[0].name())
);
// 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,
valueSetNames,
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;
}
@ -2982,11 +2962,12 @@ Foam::label Foam::meshRefinement::findRegions
const vector& perturbVec,
const pointField& locationsInMesh,
const pointField& locationsOutsideMesh,
const bool exitIfLeakPath,
const refPtr<writer<scalar>>& leakPathFormatter,
const label nRegions,
labelList& cellRegion,
const boolList& blockedFace
const boolList& blockedFace,
// Leak-path
const bool exitIfLeakPath,
const refPtr<coordSetWriter>& leakPathFormatter
)
{
bitSet insideCell(mesh.nCells());
@ -3022,7 +3003,10 @@ Foam::label Foam::meshRefinement::findRegions
// mesh do not conflict with those inside
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
(
mesh,
@ -3031,46 +3015,39 @@ Foam::label Foam::meshRefinement::findRegions
locationsOutsideMesh[i]
);
if (regioni != -1)
if (regioni == -1 && (indexi = insideRegions.find(regioni)) != -1)
{
// Do a quick check for locationsOutsideMesh overlapping with
// inside ones.
label index = insideRegions.find(regioni);
if (index != -1)
if (leakPathFormatter)
{
if (leakPathFormatter.valid())
{
const fileName fName
const fileName fName
(
writeLeakPath
(
writeLeakPath
(
mesh,
locationsInMesh,
locationsOutsideMesh,
leakPathFormatter,
blockedFace
)
);
Info<< "Dumped leak path to " << fName << endl;
}
mesh,
locationsInMesh,
locationsOutsideMesh,
blockedFace,
leakPathFormatter.constCast()
)
);
Info<< "Dumped leak path to " << fName << endl;
}
if (exitIfLeakPath)
{
FatalErrorInFunction
<< "Location in mesh " << locationsInMesh[index]
<< " is inside same mesh region " << regioni
<< " as one of the locations outside mesh "
<< locationsOutsideMesh
<< exit(FatalError);
}
else
{
WarningInFunction
<< "Location in mesh " << locationsInMesh[index]
<< " is inside same mesh region " << regioni
<< " as one of the locations outside mesh "
<< locationsOutsideMesh << endl;
}
auto& err =
(
exitIfLeakPath
? FatalErrorInFunction
: WarningInFunction
);
err << "Location in mesh " << locationsInMesh[indexi]
<< " is inside same mesh region " << regioni
<< " as one of the locations outside mesh "
<< locationsOutsideMesh << endl;
if (exitIfLeakPath)
{
FatalError << exit(FatalError);
}
}
}
@ -3103,7 +3080,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMeshRegions
const pointField& locationsInMesh,
const pointField& locationsOutsideMesh,
const bool exitIfLeakPath,
const refPtr<writer<scalar>>& leakPathFormatter
const refPtr<coordSetWriter>& leakPathFormatter
)
{
// Force calculation of face decomposition (used in findCell)
@ -3120,14 +3097,15 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMeshRegions
label nRemove = findRegions
(
mesh_,
mergeDistance_ * vector::one, // perturbVec
vector::uniform(mergeDistance_), // perturbVec
locationsInMesh,
locationsOutsideMesh,
exitIfLeakPath,
leakPathFormatter,
cellRegion.nRegions(),
cellRegion,
blockedFace
blockedFace,
// Leak-path
exitIfLeakPath,
leakPathFormatter
);
// Subset

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2018 OpenCFD Ltd.
Copyright (C) 2017-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,6 +27,7 @@ License
\*---------------------------------------------------------------------------*/
#include "coordSet.H"
#include "globalIndex.H"
// * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * * //
@ -36,11 +37,13 @@ const Foam::Enum
>
Foam::coordSet::coordFormatNames
({
{ coordFormat::XYZ, "xyz" },
{ coordFormat::X, "x" },
{ coordFormat::Y, "y" },
{ coordFormat::Z, "z" },
{ coordFormat::RADIUS, "radius" },
{ coordFormat::DISTANCE, "distance" },
{ coordFormat::XYZ, "xyz" },
/// { coordFormat::DEFAULT, "default" },
});
@ -48,12 +51,12 @@ Foam::coordSet::coordFormatNames
void Foam::coordSet::checkDimensions() const
{
if (size() != curveDist_.size())
if (points().size() != distance().size())
{
FatalErrorInFunction
<< "Size of points and curve distance must be the same" << nl
<< " points size : " << size()
<< " curve size : " << curveDist_.size()
<< "Size not equal :" << nl
<< " points:" << points().size()
<< " distance:" << distance().size()
<< abort(FatalError);
}
}
@ -61,6 +64,15 @@ void Foam::coordSet::checkDimensions() const
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Foam::coordSet::coordSet()
// :
// pointField(),
// name_(),
// distance_(),
// axis_(coordFormat::DEFAULT)
// {}
Foam::coordSet::coordSet
(
const word& name,
@ -69,8 +81,8 @@ Foam::coordSet::coordSet
:
pointField(),
name_(name),
axis_(axisType),
curveDist_()
distance_(),
axis_(axisType)
{}
@ -80,10 +92,7 @@ Foam::coordSet::coordSet
const word& axis
)
:
pointField(),
name_(name),
axis_(coordFormatNames[axis]),
curveDist_()
coordSet(name, coordFormatNames.get(axis))
{}
@ -92,13 +101,13 @@ Foam::coordSet::coordSet
const word& name,
const word& axis,
const List<point>& points,
const scalarList& curveDist
const scalarList& dist
)
:
pointField(points),
name_(name),
axis_(coordFormatNames[axis]),
curveDist_(curveDist)
distance_(dist),
axis_(coordFormatNames[axis])
{
checkDimensions();
}
@ -109,13 +118,13 @@ Foam::coordSet::coordSet
const word& name,
const word& axis,
List<point>&& points,
scalarList&& curveDist
scalarList&& dist
)
:
pointField(std::move(points)),
name_(name),
axis_(coordFormatNames[axis]),
curveDist_(std::move(curveDist))
distance_(std::move(dist)),
axis_(coordFormatNames.get(axis))
{
checkDimensions();
}
@ -123,7 +132,7 @@ Foam::coordSet::coordSet
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::coordSet::hasVectorAxis() const
bool Foam::coordSet::hasVectorAxis() const noexcept
{
return axis_ == coordFormat::XYZ;
}
@ -131,72 +140,105 @@ bool Foam::coordSet::hasVectorAxis() const
Foam::scalar Foam::coordSet::scalarCoord(const label index) const
{
const point& p = operator[](index);
switch (axis_)
{
case coordFormat::X:
{
return p.x();
return points()[index].x();
}
case coordFormat::Y:
{
return p.y();
return points()[index].y();
}
case coordFormat::Z:
{
return p.z();
return points()[index].z();
}
case coordFormat::RADIUS:
{
return mag(points()[index]);
}
case coordFormat::DISTANCE:
{
// Note: If this has been constructed from the 'name' and 'axis'
// constructor the curveDist list will not have been set
// Note: the distance will unset it constructed from
// 'name' and 'axis' only
if (curveDist_.empty())
if (distance().empty())
{
FatalErrorInFunction
<< "Axis type '" << coordFormatNames[axis_]
<< "' requested but curve distance has not been set"
<< abort(FatalError);
}
return curveDist_[index];
return distance()[index];
}
default:
{
FatalErrorInFunction
<< "Illegal axis specification '" << coordFormatNames[axis_]
<< "' for sampling line " << name_
<< "' for sampling " << name_
<< 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 p;
return points()[index];
}
Foam::Ostream& Foam::coordSet::write(Ostream& os) const
{
os << "name:" << name_ << " axis:" << coordFormatNames[axis_]
os << "name:" << name_ << " axis:" << coordFormatNames[axis_] << nl
<< nl
<< nl << "\t(coord)"
<< endl;
<< "\t(coord)" << nl;
for (const point& pt : *this)
for (const point& p : *this)
{
os << '\t' << pt << endl;
os << '\t' << p << nl;
}
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 |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
Copyright (C) 2017-2018 OpenCFD Ltd.
Copyright (C) 2017-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -35,11 +35,11 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef coordSet_H
#define coordSet_H
#ifndef Foam_coordSet_H
#define Foam_coordSet_H
#include "pointField.H"
#include "word.H"
#include "scalarList.H"
#include "Enum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -57,49 +57,55 @@ class coordSet
{
public:
// Public data types
// Public Data Types
//- Enumeration defining the output format for coordinates
enum class coordFormat
{
XYZ,
X,
Y,
Z,
DISTANCE
X, //!< Use 'x' component of points for (scalar) axis
Y, //!< Use 'y' component of points for (scalar) axis
Z, //!< Use 'z' component of points for (scalar) axis
RADIUS, //!< Use mag of points for (scalar) axis
DISTANCE, //!< Use additional distance field for (scalar) axis
XYZ, //!< Use x,y,z point values
/// DEFAULT
};
//- String representation of coordFormat enum
static const Enum<coordFormat> coordFormatNames;
private:
//- Check for consistent dimensions of points and curve distance
void checkDimensions() const;
protected:
// Protected Data
//- Name
const word name_;
word name_;
//- Axis write type
const coordFormat axis_;
//- Cumulative distance for "distance" write specifier.
scalarList distance_;
//- Cumulative distance "distance" write specifier.
scalarList curveDist_;
//- Axis type
coordFormat axis_;
// Protected Member Functions
//- Check for consistent dimensions of points and curve distance
void checkDimensions() const;
public:
// Constructors
//- Construct from components
// Note: curveDist will be empty
/// //- Default construct
/// coordSet();
//- Default construct with name and axis type
coordSet(const word& name, const coordFormat axisType);
//- Construct from components
// Note: curveDist will be empty
//- Default construct with name and axis type
coordSet(const word& name, const word& axis);
//- Copy construct from components
@ -108,7 +114,7 @@ public:
const word& name,
const word& axis,
const List<point>& points,
const scalarList& curveDist
const scalarList& dist
);
//- Move construct from components
@ -117,66 +123,116 @@ public:
const word& name,
const word& axis,
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_;
}
word axis() const
//- The sort axis name
const word& axis() const
{
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)
{
static_cast<pointField&>(*this) = newPoints;
}
//- Set the points
//- Move assign new points
void setPoints(List<point>&& newPoints)
{
static_cast<pointField&>(*this) = std::move(newPoints);
}
//- Return the cumulative distance
const scalarList& curveDist() const
//- Copy assign the cumulative distance
void setDistance(const scalarList& dist, const bool check=true)
{
return curveDist_;
distance_ = dist;
if (check) checkDimensions();
}
//- Set the cumulative distance
void setCurveDist(const scalarList& curveDist)
//- Move assign the cumulative distance
void setDistance(scalarList&& dist, const bool check=true)
{
curveDist_ = curveDist;
checkDimensions();
distance_ = std::move(dist);
if (check) checkDimensions();
}
//- Set the cumulative distance
void setCurveDist(scalarList&& curveDist)
{
curveDist_ = std::move(curveDist);
checkDimensions();
}
//- Is axis specification a vector
bool hasVectorAxis() const;
// Output-related
//- True if axis specification is a vector
bool hasVectorAxis() const noexcept;
//- 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;
//- Get point according to axis="xyz" specification
vector vectorCoord(const label index) const;
const vector& vectorCoord(const label index) const;
//- Write to stream
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
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,49 +25,63 @@ License
\*---------------------------------------------------------------------------*/
#include "regionSizeDistribution.H"
#include "regionSplit.H"
#include "volFields.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class Type>
Foam::Map<Type> Foam::functionObjects::regionSizeDistribution::regionSum
(
const regionSplit& regions,
const Field<Type>& fld
) const
Foam::UPtrList<const Foam::Field<Type>>
Foam::coordSetWriter::repackageFields(const Field<Type>& field)
{
// Per region the sum of fld
Map<Type> regionToSum(regions.nRegions()/Pstream::nProcs());
UPtrList<const Field<Type>> fieldPtrs(1);
fieldPtrs.set(0, &field);
forAll(fld, celli)
{
const label regioni = regions[celli];
regionToSum(regioni, Type(Zero)) += fld[celli];
}
Pstream::mapCombineGather(regionToSum, plusEqOp<Type>());
Pstream::mapCombineScatter(regionToSum);
return regionToSum;
return fieldPtrs;
}
template<class Type>
Foam::List<Type> Foam::functionObjects::regionSizeDistribution::extractData
(
const labelUList& keys,
const Map<Type>& regionData
) const
Foam::UPtrList<const Foam::Field<Type>>
Foam::coordSetWriter::repackageFields(const UList<Field<Type>>& fieldValues)
{
List<Type> sortedData(keys.size());
forAll(keys, i)
UPtrList<const Field<Type>> fieldPtrs(fieldValues.size());
forAll(fieldValues, 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
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,183 +25,242 @@ License
\*---------------------------------------------------------------------------*/
#include "csvSetWriter.H"
#include "csvCoordSetWriter.H"
#include "coordSet.H"
#include "fileName.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 * * * * * * * * * * * * * * //
template<class Type>
Foam::csvSetWriter<Type>::csvSetWriter()
Foam::coordSetWriters::csvWriter::csvWriter()
:
writer<Type>()
{}
coordSetWriter(),
streamOpt_(),
precision_(IOstream::defaultPrecision())
{
buffering_ = true;
}
template<class Type>
Foam::csvSetWriter<Type>::csvSetWriter(const dictionary& dict)
Foam::coordSetWriters::csvWriter::csvWriter(const dictionary& options)
:
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 * * * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::csvSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
bool Foam::coordSetWriters::csvWriter::buffering(const bool on)
{
return this->getBaseName(points, valueSetNames) + ".csv";
const bool old(buffering_);
buffering_ = on;
return old;
}
template<class Type>
void Foam::csvSetWriter<Type>::write
(
const coordSet& points,
const wordList& valueSetNames,
const List<const Field<Type>*>& valueSets,
Ostream& os
) const
Foam::fileName Foam::coordSetWriters::csvWriter::path() const
{
writeHeader(points,valueSetNames,os);
// Assume !useTracks_, otherwise too fragile
// Collect sets into columns
List<const List<Type>*> columns(valueSets.size());
// 1) rootdir/<TIME>/setName.csv
// 2) rootdir/setName.csv
forAll(valueSets, i)
{
columns[i] = valueSets[i];
}
this->writeTable(points, columns, os);
return getExpectedPath("csv");
}
template<class Type>
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
bool Foam::coordSetWriters::csvWriter::writeBuffered()
{
writeHeader(tracks[0],valueSetNames,os);
if (valueSets.size() != valueSetNames.size())
if (coords_.empty())
{
FatalErrorInFunction
<< "Number of variables:" << valueSetNames.size() << endl
<< "Number of valueSets:" << valueSets.size()
<< exit(FatalError);
clearBuffers();
return false;
}
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
forAll(valueSets, i)
if (coords.hasVectorAxis())
{
columns[i] = &valueSets[i][trackI];
// x, y, z
headCols.append("x");
headCols.append("y");
headCols.append("z");
}
else
{
headCols.append(coords.axis());
}
this->writeTable(tracks[trackI], columns, os);
os << nl << nl;
}
}
// label, scalar
headCols.append(labelNames_);
headCols.append(scalarNames_);
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);
// 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)); \
} \
}
os << valueSetNames[i];
}
os << nl;
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>
void Foam::csvSetWriter<Type>::writeHeader
Foam::fileName Foam::coordSetWriters::csvWriter::writeTemplate
(
const coordSet& points,
const wordList& valueSetNames,
Ostream& os
) const
const word& fieldName,
const List<Field<Type>>& fieldValues
)
{
writeCoordHeader(points, os);
forAll(valueSetNames, i)
checkOpen();
if (coords_.empty())
{
for (label j=0; j<Type::nComponents; j++)
{
if (i || j)
{
writeSeparator(os);
}
os << valueSetNames[i] << "_" << j;
}
return fileName::null;
}
useTracks_ = true; // Extra safety
os << nl;
UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
return writeTemplate(fieldName, fieldPtrs);
}
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
{
os << axisName;
writeSeparator(os);
}
}
// 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 |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,277 +26,321 @@ License
\*---------------------------------------------------------------------------*/
#include "ensightSetWriter.H"
#include "ensightCoordSetWriter.H"
#include "coordSet.H"
#include "IOmanip.H"
#include "ensightCase.H"
#include "ensightGeoFile.H"
#include "ensightOutput.H"
#include "ensightPTraits.H"
#include "coordSetWriterMethods.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 * * * * * * * * * * * * * * //
template<class Type>
Foam::ensightSetWriter<Type>::ensightSetWriter()
Foam::coordSetWriters::ensightWriter::ensightWriter()
:
writer<Type>()
coordSetWriter(),
writeFormat_(IOstream::ASCII),
collateTimes_(true),
caching_("fieldsDict") // Historic name
{}
template<class Type>
Foam::ensightSetWriter<Type>::ensightSetWriter(const dictionary& dict)
Foam::coordSetWriters::ensightWriter::ensightWriter(const dictionary& options)
:
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 * * * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::ensightSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
Foam::fileName Foam::coordSetWriters::ensightWriter::path() const
{
return
this->getBaseName(points, valueSetNames)
//+ '_'
//+ ensightPTraits<Type>::typeName
+ ".case";
// Assume collateTimes == true, otherwise too fragile
// Collated
// ========
// 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();
}
template<class Type>
void Foam::ensightSetWriter<Type>::write
(
const coordSet& points,
const wordList& valueSetNames,
const List<const Field<Type>*>& valueSets,
Ostream& os
) const
void Foam::coordSetWriters::ensightWriter::close(const bool force)
{
const fileName base(os.name().lessExt());
const fileName meshFile(base + ".mesh");
caching_.clear();
coordSetWriter::close(force);
}
// 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)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Field writing implementations
#include "ensightCoordSetWriterCollated.C"
#include "ensightCoordSetWriterUncollated.C"
template<class Type>
Foam::fileName Foam::coordSetWriters::ensightWriter::writeTemplate
(
const word& fieldName,
const Field<Type>& values
)
{
checkOpen();
if (coords_.empty())
{
fileName dataFile(base + ".***." + valueName);
os.setf(ios_base::left);
os << ensightPTraits<Type>::typeName
<< " per node: 1 "
<< setw(15) << valueName
<< " " << dataFile.name().c_str()
<< nl;
return fileName::null;
}
os << nl
<< "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
if (coords_.size() != 1)
{
string desc("Written by OpenFOAM");
OFstream os(meshFile);
os.setf(ios_base::scientific, ios_base::floatfield);
os.precision(5);
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;
}
FatalErrorInFunction
<< "Attempted to write field: " << fieldName
<< " (" << 1 << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError);
}
// Write data files
forAll(valueSetNames, seti)
UPtrList<const Field<Type>> fieldPtrs(repackageFields(values));
elemOutputType elemOutput =
(
useTracks_
? elemOutputType::WRITE_LINES
: elemOutputType::NO_ELEMENTS
);
if (collateTimes_)
{
const word& valueName = valueSetNames[seti];
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;
}
}
return writeCollated(fieldName, fieldPtrs, elemOutput);
}
else
{
return writeUncollated(fieldName, fieldPtrs, elemOutput);
}
}
template<class Type>
void Foam::ensightSetWriter<Type>::write
Foam::fileName Foam::coordSetWriters::ensightWriter::writeTemplate
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
const word& fieldName,
const List<Field<Type>>& fieldValues
)
{
const fileName base(os.name().lessExt());
const fileName meshFile(base + ".mesh");
// 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)
checkOpen();
if (coords_.empty())
{
fileName dataFile(base + ".***." + valueName);
os.setf(ios_base::left);
os << ensightPTraits<Type>::typeName
<< " per node: 1 "
<< setw(15) << valueName
<< " " << dataFile.name().c_str()
<< nl;
return fileName::null;
}
os << nl
<< "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
if (coords_.size() != fieldValues.size())
{
string desc("Written by OpenFOAM");
OFstream os(meshFile);
os.setf(ios_base::scientific, ios_base::floatfield);
os.precision(5);
os << "Ensight Geometry File" << nl
<< 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)
{
os << "bar2" << nl
<< setw(10) << points.size()-1 << nl;
for (label i = 0; i < points.size()-1; i++)
{
os << setw(10) << i+1
<< setw(10) << i+2
<< nl;
}
}
}
FatalErrorInFunction
<< "Attempted to write field: " << fieldName
<< " (" << fieldValues.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError);
}
UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
// Write data files
forAll(valueSetNames, seti)
if (collateTimes_)
{
const word& valueName = valueSetNames[seti];
const List<Field<Type>>& fieldVals = 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;
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;
}
}
}
}
return writeCollated
(
fieldName,
fieldPtrs,
elemOutputType::WRITE_LINES
);
}
else
{
return writeUncollated
(
fieldName,
fieldPtrs,
elemOutputType::WRITE_LINES
);
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Field writing methods
defineCoordSetWriterWriteFields(Foam::coordSetWriters::ensightWriter);
// ************************************************************************* //

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 "fileName.H"
#include "OFstream.H"
#include "floatVector.H"
#include "OSspecific.H"
#include "foamGltfScene.H"
#include "foamGltfSceneWriter.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
template<class Type>
const Foam::Enum<typename Foam::gltfSetWriter<Type>::fieldOption>
Foam::gltfSetWriter<Type>::fieldOptionNames_
namespace Foam
{
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
{ fieldOption::UNIFORM, "uniform" },
@ -45,10 +56,90 @@ Foam::gltfSetWriter<Type>::fieldOptionNames_
});
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
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
@ -60,8 +151,7 @@ Foam::word Foam::gltfSetWriter<Type>::getColourMap
}
template<class Type>
const Foam::colourTable& Foam::gltfSetWriter<Type>::getColourTable
const Foam::colourTable& Foam::coordSetWriters::gltfWriter::getColourTable
(
const dictionary& dict
) const
@ -70,8 +160,7 @@ const Foam::colourTable& Foam::gltfSetWriter<Type>::getColourTable
}
template<class Type>
Foam::scalarMinMax Foam::gltfSetWriter<Type>::getFieldLimits
Foam::scalarMinMax Foam::coordSetWriters::gltfWriter::getFieldLimits
(
const word& fieldName
) const
@ -87,8 +176,8 @@ Foam::scalarMinMax Foam::gltfSetWriter<Type>::getFieldLimits
}
template<class Type>
Foam::tmp<Foam::scalarField> Foam::gltfSetWriter<Type>::getAlphaField
Foam::tmp<Foam::scalarField>
Foam::coordSetWriters::gltfWriter::getAlphaField
(
const dictionary& dict
) const
@ -141,27 +230,10 @@ Foam::tmp<Foam::scalarField> Foam::gltfSetWriter<Type>::getAlphaField
}
template<class Type>
Foam::vector Foam::gltfSetWriter<Type>::getTrackAnimationColour
(
const colourTable& colours,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
const label tracki
) const
void Foam::coordSetWriters::gltfWriter::setupAnimationColour()
{
if (!colour_)
{
FatalErrorInFunction
<< "Attempting to get colour when colour option is off"
<< abort(FatalError);
}
const dictionary& dict = animationDict_;
// Fallback value
vector colourValue(Zero);
const entry* eptr = dict.findEntry("colour", keyType::LITERAL);
if (!eptr || !eptr->isStream())
@ -175,8 +247,11 @@ Foam::vector Foam::gltfSetWriter<Type>::getTrackAnimationColour
// Value specified
ITstream& is = eptr->stream();
is >> colourValue;
is >> animateColourValue_;
dict.checkITstream(is, "colour");
// Has uniform value
animateColourOption_ = fieldOption::UNIFORM;
}
else
{
@ -188,85 +263,59 @@ Foam::vector Foam::gltfSetWriter<Type>::getTrackAnimationColour
{
case fieldOption::NONE:
{
FatalErrorInFunction
<< "Cannot select 'none' for colour entry!" << nl
<< "... possible programming error"
<< exit(FatalError);
break;
}
case fieldOption::UNIFORM:
{
dict.readEntry("colourValue", colourValue);
dict.readEntry("colourValue", animateColourValue_);
// Has uniform value
animateColourOption_ = fieldOption::UNIFORM;
break;
}
case fieldOption::FIELD:
{
const word fieldName = dict.get<word>("colourField");
const label fieldi = valueSetNames.find(fieldName);
if (fieldi == -1)
{
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()
// Needs named field...
animateColourName_ = dict.get<word>("colourField");
animateColourOption_ = fieldOption::FIELD;
break;
}
}
}
return colourValue;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type>
Foam::gltfSetWriter<Type>::gltfSetWriter()
Foam::coordSetWriters::gltfWriter::gltfWriter()
:
writer<Type>(),
coordSetWriter(),
writer_(nullptr),
animate_(false),
colour_(false),
animateColourOption_(fieldOption::NONE),
animateColourName_(),
animateColourValue_(Zero),
fieldInfoDict_(),
animationDict_()
{}
template<class Type>
Foam::gltfSetWriter<Type>::gltfSetWriter(const dictionary& dict)
Foam::coordSetWriters::gltfWriter::gltfWriter(const dictionary& options)
:
writer<Type>(dict),
animate_(dict.getOrDefault("animate", false)),
colour_(dict.getOrDefault("colour", false)),
fieldInfoDict_(dict.subOrEmptyDict("fieldInfo")),
animationDict_(dict.subOrEmptyDict("animationInfo"))
coordSetWriter(options),
writer_(nullptr),
animate_(options.getOrDefault("animate", false)),
colour_(options.getOrDefault("colour", false)),
animateColourOption_(fieldOption::NONE),
animateColourName_(),
animateColourValue_(Zero),
fieldInfoDict_(options.subOrEmptyDict("fieldInfo")),
animationDict_(options.subOrEmptyDict("animationInfo"))
{
// fieldInfo
// {
@ -281,50 +330,139 @@ Foam::gltfSetWriter<Type>::gltfSetWriter(const dictionary& dict)
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::gltfSetWriter<Type>::getFileName
Foam::coordSetWriters::gltfWriter::gltfWriter
(
const coordSet& points,
const wordList& valueSetNames
) const
const coordSet& coords,
const fileName& outputPath,
const dictionary& options
)
:
gltfWriter(options)
{
return this->getBaseName(points, valueSetNames) + ".gltf";
open(coords, outputPath);
}
template<class Type>
void Foam::gltfSetWriter<Type>::write
Foam::coordSetWriters::gltfWriter::gltfWriter
(
const coordSet& points,
const wordList& valueSetNames,
const List<const Field<Type>*>& valueSets,
Ostream& os
) const
const UPtrList<coordSet>& tracks,
const fileName& outputPath,
const dictionary& options
)
:
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
<< "Number of variables:" << valueSetNames.size() << endl
<< "Number of valueSets:" << valueSets.size()
<< "Attempted to write field: " << fieldName
<< " (" << fieldPtrs.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError);
}
glTF::scene scene;
const label meshi = scene.addMesh(points, "points");
forAll(valueSetNames, i)
const auto& tracks = coords_;
// 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);
}
}
if (colour_)
{
forAll(valueSets, fieldi)
{
const auto& field = *valueSets[fieldi];
const word& fieldName = valueSetNames[fieldi];
auto& scene = writer_->getScene();
forAll(tracks, tracki)
{
const label meshi = meshes_[tracki];
const auto& field = fieldPtrs[tracki];
scene.addFieldToMesh(field, fieldName, meshi);
if (colour_)
{
const dictionary dict = fieldInfoDict_.subOrEmptyDict(fieldName);
const auto& colours = getColourTable(dict);
@ -333,11 +471,7 @@ void Foam::gltfSetWriter<Type>::write
const scalarMinMax valLimits = getFieldLimits(fieldName);
// Generated field colours
vectorField fieldColour(field.size());
scalarMinMax fldLimits;
if (pTraits<Type>::nComponents == 1)
{
MinMax<Type> scanned(minMax(field));
@ -351,24 +485,17 @@ void Foam::gltfSetWriter<Type>::write
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 =
// Generated field colours
vectorField fieldColour
(
getBoundedColours
(
pTraits<Type>::nComponents == 1
? scalar(component(val, 0))
: scalar(mag(val))
);
// 0-1 clipped by value()
fieldColour[i] = colours.value((f - minf)/deltaf);
}
colours,
field,
max(fldLimits.min(), valLimits.min()), // boundMin
min(fldLimits.max(), valLimits.max()) // boundMax
)
);
scene.addColourToMesh
(
@ -380,226 +507,260 @@ void Foam::gltfSetWriter<Type>::write
}
}
scene.write(os);
return writer_().path();
}
template<class Type>
void Foam::gltfSetWriter<Type>::write
Foam::fileName Foam::coordSetWriters::gltfWriter::writeTemplate_animate
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
)
{
if (valueSets.size() != valueSetNames.size())
if (coords_.size() != fieldPtrs.size())
{
FatalErrorInFunction
<< "Number of variables:" << valueSetNames.size() << endl
<< "Number of valueSets:" << valueSets.size()
<< "Attempted to write field: " << fieldName
<< " (" << fieldPtrs.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError);
}
if (animate_)
{
writeAnimateTracks
(
writeTracks,
times,
tracks,
valueSetNames,
valueSets,
os
);
}
else
{
writeStaticTracks
(
writeTracks,
times,
tracks,
valueSetNames,
valueSets,
os
);
}
}
const auto& tracks = this->coords_;
const auto& times = this->trackTimes_;
template<class Type>
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)
if (!writer_)
{
const vectorField& track = tracks[tracki];
const label meshi = scene.addMesh(track, "track:" + Foam::name(tracki));
forAll(valueSetNames, fieldi)
// 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());
const label animationi = scene.createAnimation("animation");
forAll(tracks, tracki)
{
const word& fieldName = valueSetNames[fieldi];
const auto& field = valueSets[fieldi][tracki];
scene.addFieldToMesh(field, fieldName, meshi);
}
const auto& track = tracks[tracki];
if (colour_)
{
forAll(valueSets, fieldi)
if (track.empty())
{
const auto& field = valueSets[fieldi][tracki];
const word& fieldName = valueSetNames[fieldi];
const dictionary dict =
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
);
meshes_[tracki] = -1;
continue;
}
// Seed starting position
meshes_[tracki] =
scene.addMesh
(
vectorField(1, track[0]),
"track:" + Foam::name(tracki)
);
const label meshi = meshes_[tracki];
// Time frames
const label timeId =
scene.addField(times[tracki], "time:" + Foam::name(tracki));
// Translations
const vectorField translation(track - track[0]);
const label translationId =
scene.addField(translation, "translation");
scene.addToAnimation(animationi, timeId, translationId, meshi);
}
}
scene.write(os);
}
auto& scene = writer_->getScene();
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");
// 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())
if (track.empty() || meshi < 0)
{
continue;
}
// Seed starting positions and field values
const label meshi =
scene.addMesh
(
vectorField(1, track[0]),
"track:" + Foam::name(tracki)
);
// Seed starting field values
scene.addFieldToMesh(Field<Type>(1, field[0]), fieldName, meshi);
}
forAll(valueSetNames, fieldi)
// Note: colours cannot be animated... setting a fixed value.
// However, we need to wait until the field is actually seen
if (colour_)
{
if (animateColourOption_ == fieldOption::NONE)
{
const Field<Type>& field = valueSets[fieldi][tracki];
const word& fieldName = valueSetNames[fieldi];
scene.addFieldToMesh(Field<Type>(1, field[0]), fieldName, meshi);
// First time - scan for information
setupAnimationColour();
}
// Time frames
const label timeId =
scene.addField(times[tracki], "time:" + Foam::name(tracki));
// Translations
const vectorField translation(track - track[0]);
const label translationId = scene.addField(translation, "translation");
scene.addToAnimation(animationi, timeId, translationId, meshi);
// Note: colours cannot be animated... setting a fixed value
if (colour_)
switch (animateColourOption_)
{
const vector colour =
getTrackAnimationColour
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_);
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
(
fieldColour,
"Colour:fixed", // ... or "Colour:constant"
meshi,
alphaChannel
);
}
// Mark as done
animateColourName_.clear();
animateColourOption_ = fieldOption::FIELD;
break;
}
case fieldOption::FIELD:
{
if
(
colours,
valueSetNames,
valueSets,
tracki
);
!animateColourName_.empty()
&& animateColourName_ == fieldName
)
{
// This is the desired colour field. Process now
const auto talpha = getAlphaField(animationDict_);
const auto& colours = getColourTable(animationDict_);
const scalarField& alpha = talpha();
vectorField fieldColour(1, Zero);
scalarField alphaChannel(1, 1.0);
scene.addColourToMesh
(
vectorField(1, colour),
"Colour:fixed", // ... or "Colour:constant"
meshi,
scalarField(1, alpha[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/>.
Class
Foam::gltfSetWriter
Foam::coordSetWriters::gltfWriter
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:
- filename.bin : a binary file containing all scene entities
@ -121,23 +122,25 @@ SourceFiles
#ifndef Foam_coordSetWriters_gltfWriter_H
#define Foam_coordSetWriters_gltfWriter_H
#include "writer.H"
#include "coordSetWriter.H"
#include "colourTable.H"
#include "foamGltfFwd.H"
#include "MinMax.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
/*---------------------------------------------------------------------------*\
Class gltfSetWriter Declaration
Class gltfWriter Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class gltfSetWriter
class gltfWriter
:
public writer<Type>
public coordSetWriter
{
public:
@ -160,18 +163,33 @@ private:
// Private Data
//- Backend output
autoPtr<glTF::sceneWriter> writer_;
//- Flag to animate - for particle tracks only
bool animate_;
//- Flag to add field colours
bool colour_;
//- Animation colour option
fieldOption animateColourOption_;
//- Animation colour field name
word animateColourName_;
//- Animation colour value
vector animateColourValue_;
//- Local field information
const dictionary fieldInfoDict_;
//- Animation information
const dictionary animationDict_;
//- The mesh indices in glTF scene
labelList meshes_;
// Private Member Functions
@ -184,103 +202,117 @@ private:
//- Return the named min/max field limits (from sub-dictionary)
scalarMinMax getFieldLimits(const word& fieldName) const;
//- Setup animation colour or field to search for
void setupAnimationColour();
//- Return the alpha field for mesh values
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 wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
const label tracki
) const;
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
);
//- 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:
//- Runtime type information
TypeName("gltf");
//- Runtime type information (no debug)
TypeNameNoDebug("gltf");
// Constructors
//- Default construct
gltfSetWriter();
gltfWriter();
//- Construct from dictionary
explicit gltfSetWriter(const dictionary& dict);
//- Default construct with specified options
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
virtual ~gltfSetWriter() = default;
//- Destructor. Calls close()
virtual ~gltfWriter();
// Member Functions
//- Return the file name
virtual fileName getFileName
(
const coordSet&,
const wordList&
) const;
//- Expected (characteristic) output file name - information only
virtual fileName path() const; // override
//- Write
virtual void write
(
const coordSet&,
const wordList&,
const List<const Field<Type>*>&,
Ostream&
) const;
//- Close and reset, clears backend.
virtual void close(bool force = false); // override
//- Write tracks (main entry point)
virtual void write
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>&,
const wordList& valueSetNames,
const List<List<Field<Type>>>&,
Ostream&
) const;
//- Begin time step. Clears existing backend.
virtual void beginTime(const Time& t); // override
//- Write animated tracks
virtual void writeAnimateTracks
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const;
//- Begin time step. Clears existing backend.
virtual void beginTime(const instant& inst); // override
//- Write static tracks
virtual void writeStaticTracks
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream&
) const;
//- End time step. Clears existing backend.
virtual void endTime(); // override
// Write
declareCoordSetWriterWriteMethod(label);
declareCoordSetWriterWriteMethod(scalar);
declareCoordSetWriterWriteMethod(vector);
declareCoordSetWriterWriteMethod(sphericalTensor);
declareCoordSetWriterWriteMethod(symmTensor);
declareCoordSetWriterWriteMethod(tensor);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace coordSetWriters
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "gltfCoordSetWriter.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) 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 |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2021 OpenCFD Ltd.
Copyright (C) 2017-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,135 +26,239 @@ License
\*---------------------------------------------------------------------------*/
#include "gnuplotSetWriter.H"
#include "gnuplotCoordSetWriter.H"
#include "coordSet.H"
#include "fileName.H"
#include "OFstream.H"
#include "OSspecific.H"
#include "coordSetWriterMethods.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 * * * * * * * * * * * * * * //
template<class Type>
Foam::gnuplotSetWriter<Type>::gnuplotSetWriter()
Foam::coordSetWriters::gnuplotWriter::gnuplotWriter()
:
writer<Type>()
{}
coordSetWriter(),
streamOpt_(),
precision_(IOstream::defaultPrecision())
{
buffering_ = true;
}
template<class Type>
Foam::gnuplotSetWriter<Type>::gnuplotSetWriter(const dictionary& dict)
Foam::coordSetWriters::gnuplotWriter::gnuplotWriter(const dictionary& options)
:
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 * * * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::gnuplotSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
bool Foam::coordSetWriters::gnuplotWriter::buffering(const bool on)
{
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>
void Foam::gnuplotSetWriter<Type>::write
Foam::fileName Foam::coordSetWriters::gnuplotWriter::writeTemplate
(
const coordSet& points,
const wordList& valueSetNames,
const List<const Field<Type>*>& valueSets,
Ostream& os
) const
const word& fieldName,
const Field<Type>& values
)
{
os << "set term postscript color" << nl
<< "set output \"" << points.name() << ".ps\"" << nl;
// 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)
checkOpen();
if (coords_.empty())
{
os << "set ylabel \"" << valueSetNames[0] << "\"" << nl
<< "set y2label \"" << valueSetNames[1] << "\"" << nl
<< "set ytics nomirror" << nl << "set y2tics" << nl;
return fileName::null;
}
os << "plot";
forAll(valueSets, i)
if (useTracks_ || !buffering_)
{
if (i)
{
os << ',';
}
os << " \"-\" title \"" << valueSetNames[i] << "\" with lines";
if (valueSetNames.size() == 2)
{
os << " axes x1y" << (i+1) ;
}
UPtrList<const Field<Type>> fieldPtrs(repackageFields(values));
return writeTemplate(fieldName, fieldPtrs);
}
os << nl;
forAll(valueSets, i)
{
this->writeTable(points, *valueSets[i], os);
os << "e" << nl;
}
// Buffering version
appendField(fieldName, values);
return path();
}
template<class Type>
void Foam::gnuplotSetWriter<Type>::write
Foam::fileName Foam::coordSetWriters::gnuplotWriter::writeTemplate
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
const word& fieldName,
const List<Field<Type>>& fieldValues
)
{
if (valueSets.size() != valueSetNames.size())
checkOpen();
if (coords_.empty())
{
FatalErrorInFunction
<< "Number of variables:" << valueSetNames.size() << endl
<< "Number of valueSets:" << valueSets.size()
<< exit(FatalError);
return fileName::null;
}
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";
}
os << nl;
forAll(valueSets, i)
{
this->writeTable(tracks[trackI], valueSets[i][trackI], os);
os << "e" << nl;
}
}
}
UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
return writeTemplate(fieldName, fieldPtrs);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// 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
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2021 OpenCFD Ltd.
Copyright (C) 2018-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -25,175 +25,198 @@ License
\*---------------------------------------------------------------------------*/
#include "nastranSetWriter.H"
#include "nastranCoordSetWriter.H"
#include "coordSet.H"
#include "IOmanip.H"
#include "OFstream.H"
#include "OSspecific.H"
#include "coordSetWriterMethods.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 * * * * * * * * * * * * * * //
template<class Type>
Foam::nastranSetWriter<Type>::nastranSetWriter()
Foam::coordSetWriters::nastranWriter::nastranWriter()
:
writer<Type>()
{}
coordSetWriter(),
writeFormat_(fieldFormat::FREE),
separator_()
{
if (writeFormat_ == fieldFormat::FREE)
{
separator_ = ",";
}
}
template<class Type>
Foam::nastranSetWriter<Type>::nastranSetWriter(const dictionary& dict)
Foam::coordSetWriters::nastranWriter::nastranWriter(const dictionary& options)
:
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 * * * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::nastranSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
Foam::fileName Foam::coordSetWriters::nastranWriter::path() const
{
return this->getBaseName(points, valueSetNames) + ".nas";
// 1) rootdir/<TIME>/setName.{nas}
// 2) rootdir/setName.{nas}
return getExpectedPath("nas");
}
template<class Type>
void Foam::nastranSetWriter<Type>::write
void Foam::coordSetWriters::nastranWriter::writeGeometry
(
const coordSet& points,
const wordList& valueSetNames,
const List<const Field<Type>*>& valueSets,
Ostream& os
Ostream& os,
label nTracks
) 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())
if (coords_.empty())
{
return;
}
os << "TITLE=OpenFOAM "
<< this->getBaseName(tracks[0], valueSetNames).c_str()
<< nl
<< "$" << nl
<< "BEGIN BULK" << nl;
// Field width (SHORT, LONG formats)
const int width =
(
writeFormat_ == fieldFormat::SHORT ? 8
: writeFormat_ == fieldFormat::LONG ? 16
: 0
);
// label nTracks = tracks.size();
// label nPoints = 0;
// forAll(tracks, i)
// {
// nPoints += tracks[i].size();
// }
// Separator char (FREE format)
const char sep = (writeFormat_ == fieldFormat::FREE ? ',' : '\0');
// Write points
os << '$' << nl
<< "$ Points" << nl
<< '$' << nl;
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
(
os, p, globalPointi, fieldFormat::FREE
os, p, globalPointi, writeFormat_
);
++globalPointi;
}
}
if (writeTracks)
if (nTracks)
{
// Write ids of track points to file
globalPointi = 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)
{
fileFormats::NASCore::writeKeyword
(
os,
"PLOTEL",
fieldFormat::FREE
);
writeKeyword(os, "PLOTEL");
if (sep) os << sep;
// fieldFormat::SHORT
//os.setf(std::ios_base::right);
//os << setw(8) << globalEdgei+1
// << setw(8) << globalPointi+1
// << setw(8) << globalPointi+2
// << nl;
//os.unsetf(std::ios_base::right);
putValue(os, globalEdgei+1, width); // Edge id
if (sep) os << sep;
// fieldFormat::FREE
os << ',' << globalEdgei+1
<< ',' << globalPointi+1
<< ',' << globalPointi+2
<< nl;
putValue(os, globalPointi+1, width);
if (sep) os << sep;
putValue(os, globalPointi+2, width);
os << nl;
++globalEdgei;
++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 |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,94 +26,199 @@ License
\*---------------------------------------------------------------------------*/
#include "rawSetWriter.H"
#include "rawCoordSetWriter.H"
#include "coordSet.H"
#include "fileName.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 * * * * * * * * * * * * * * //
template<class Type>
Foam::rawSetWriter<Type>::rawSetWriter()
Foam::coordSetWriters::rawWriter::rawWriter()
:
writer<Type>()
{}
coordSetWriter(),
streamOpt_(),
precision_(IOstream::defaultPrecision())
{
buffering_ = true;
}
template<class Type>
Foam::rawSetWriter<Type>::rawSetWriter(const dictionary& dict)
Foam::coordSetWriters::rawWriter::rawWriter(const dictionary& options)
:
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 * * * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::rawSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
Foam::fileName Foam::coordSetWriters::rawWriter::path() 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>
void Foam::rawSetWriter<Type>::write
Foam::fileName Foam::coordSetWriters::rawWriter::writeTemplate
(
const coordSet& points,
const wordList& valueSetNames,
const List<const Field<Type>*>& valueSets,
Ostream& os
) const
const word& fieldName,
const Field<Type>& values
)
{
// Collect sets into columns
List<const List<Type>*> columns(valueSets.size());
forAll(valueSets, i)
checkOpen();
if (coords_.empty())
{
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>
void Foam::rawSetWriter<Type>::write
Foam::fileName Foam::coordSetWriters::rawWriter::writeTemplate
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
const word& fieldName,
const List<Field<Type>>& fieldValues
)
{
if (valueSets.size() != valueSetNames.size())
checkOpen();
if (coords_.empty())
{
FatalErrorInFunction
<< "Number of variables:" << valueSetNames.size() << endl
<< "Number of valueSets:" << valueSets.size()
<< exit(FatalError);
return fileName::null;
}
useTracks_ = true; // Extra safety
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);
os << nl << nl;
}
UPtrList<const Field<Type>> fieldPtrs(repackageFields(fieldValues));
return writeTemplate(fieldName, fieldPtrs);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Field writing methods
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
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2021 OpenCFD Ltd.
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,177 +25,310 @@ License
\*---------------------------------------------------------------------------*/
#include "vtkSetWriter.H"
#include "vtkCoordSetWriter.H"
#include "coordSet.H"
#include "fileName.H"
#include "OFstream.H"
#include "foamVtkCoordSetWriter.H"
#include "coordSetWriterMethods.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace coordSetWriters
{
defineTypeName(vtkWriter);
addToRunTimeSelectionTable(coordSetWriter, vtkWriter, word);
addToRunTimeSelectionTable(coordSetWriter, vtkWriter, wordDict);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type>
Foam::vtkSetWriter<Type>::vtkSetWriter()
Foam::coordSetWriters::vtkWriter::vtkWriter()
:
writer<Type>()
coordSetWriter(),
fmtType_(static_cast<unsigned>(vtk::formatType::INLINE_BASE64)),
precision_(IOstream::defaultPrecision()),
writer_(nullptr)
{}
template<class Type>
Foam::vtkSetWriter<Type>::vtkSetWriter(const dictionary& dict)
Foam::coordSetWriters::vtkWriter::vtkWriter
(
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 * * * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::vtkSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
Foam::fileName Foam::coordSetWriters::vtkWriter::path() 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));
}
template<class Type>
void Foam::vtkSetWriter<Type>::write
(
const coordSet& points,
const wordList& valueSetNames,
const List<const Field<Type>*>& valueSets,
Ostream& os
) const
void Foam::coordSetWriters::vtkWriter::close(bool force)
{
os << "# vtk DataFile Version 2.0" << nl
<< points.name() << nl
<< "ASCII" << nl
<< "DATASET POLYDATA" << nl
<< "POINTS " << points.size() << " double" << nl;
writer_.clear();
coordSetWriter::close(force);
}
for (const point& pt : points)
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())
{
os << float(pt.x()) << ' '
<< float(pt.y()) << ' '
<< float(pt.z()) << nl;
writer_.clear();
}
merge();
if (coords_.empty())
{
return fileName::null;
}
os << "POINT_DATA " << points.size() << nl
<< " FIELD attributes " << valueSetNames.size() << nl;
// From raw unsigned values to vtk::outputOptions
vtk::outputOptions opts(static_cast<vtk::formatType>(fmtType_), precision_);
forAll(valueSetNames, setI)
// Geometry: rootdir/<TIME>/setName.{vtk|vtp}
fileName outputFile = getExpectedPath(vtk::polyWriter::ext(opts));
if (verbose_)
{
os << valueSetNames[setI] << ' '
<< int(pTraits<Type>::nComponents) << ' '
<< points.size() << " float" << nl;
Info<< "Writing geometry to " << outputFile << endl;
}
const Field<Type>& fld = *valueSets[setI];
forAll(fld, pointi)
if (!writer_ && true) // always (non-parallel)
{
UPtrList<const pointField> points(coords_.size());
forAll(coords_, tracki)
{
if (pointi)
{
os << ' ';
}
writer<Type>::write(fld[pointi], os);
points.set(tracki, coords_.get(tracki));
}
os << nl;
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>
void Foam::vtkSetWriter<Type>::write
Foam::fileName Foam::coordSetWriters::vtkWriter::writeTemplate
(
const bool writeTracks,
const List<scalarField>& times,
const PtrList<coordSet>& tracks,
const wordList& valueSetNames,
const List<List<Field<Type>>>& valueSets,
Ostream& os
) const
const word& fieldName,
const UPtrList<const Field<Type>>& fieldPtrs
)
{
if (valueSets.size() != valueSetNames.size())
if (coords_.size() != fieldPtrs.size())
{
FatalErrorInFunction
<< "Number of variables:" << valueSetNames.size() << endl
<< "Number of valueSets:" << valueSets.size()
<< "Attempted to write field: " << fieldName
<< " (" << fieldPtrs.size() << " entries) for "
<< coords_.size() << " sets" << nl
<< exit(FatalError);
}
label nTracks = tracks.size();
label nPoints = 0;
forAll(tracks, i)
// Open file, writing geometry (if required)
fileName outputFile = this->write();
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
<< tracks[0].name() << nl
<< "ASCII" << nl
<< "DATASET POLYDATA" << nl
<< "POINTS " << nPoints << " double" << nl;
writer_->beginPointData(nFields_);
for (const coordSet& points : tracks)
{
for (const point& pt : points)
{
os << float(pt.x()) << ' '
<< float(pt.y()) << ' '
<< float(pt.z()) << nl;
}
}
writer_->writePointData(fieldName, fieldPtrs);
if (writeTracks)
{
os << "LINES " << nTracks << ' ' << nPoints+nTracks << nl;
// Write ids of track points to file
label globalPtI = 0;
forAll(tracks, trackI)
{
const coordSet& points = tracks[trackI];
const label len = points.size();
os << len;
for (label i = 0; i < len; ++i)
{
os << ' ' << globalPtI;
++globalPtI;
}
os << nl;
}
}
os << "POINT_DATA " << nPoints << nl
<< " FIELD attributes " << valueSetNames.size() << nl;
forAll(valueSetNames, setI)
{
os << valueSetNames[setI] << ' '
<< int(pTraits<Type>::nComponents) << ' '
<< nPoints << " float" << nl;
const List<Field<Type>>& fieldVals = valueSets[setI];
for (const Field<Type>& vals : fieldVals)
{
forAll(vals, j)
{
if (j)
{
os << ' ';
}
writer<Type>::write(vals[j], os);
}
os << nl;
}
}
wroteGeom_ = true;
return outputFile;
}
template<class Type>
Foam::fileName Foam::coordSetWriters::vtkWriter::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::vtkWriter::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::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 |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,110 +26,244 @@ License
\*---------------------------------------------------------------------------*/
#include "xmgraceSetWriter.H"
#include "xmgraceCoordSetWriter.H"
#include "coordSet.H"
#include "fileName.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 * * * * * * * * * * * * * * //
template<class Type>
Foam::xmgraceSetWriter<Type>::xmgraceSetWriter()
Foam::coordSetWriters::xmgraceWriter::xmgraceWriter()
:
writer<Type>()
{}
coordSetWriter(),
streamOpt_(),
precision_(IOstream::defaultPrecision()),
ofile_(nullptr),
nWritten_(0)
{
buffering_ = true;
}
template<class Type>
Foam::xmgraceSetWriter<Type>::xmgraceSetWriter(const dictionary& dict)
Foam::coordSetWriters::xmgraceWriter::xmgraceWriter(const dictionary& options)
:
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 * * * * * * * * * * * * * //
template<class Type>
Foam::fileName Foam::xmgraceSetWriter<Type>::getFileName
(
const coordSet& points,
const wordList& valueSetNames
) const
bool Foam::coordSetWriters::xmgraceWriter::buffering(const bool on)
{
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>
void Foam::xmgraceSetWriter<Type>::write
Foam::fileName Foam::coordSetWriters::xmgraceWriter::writeTemplate
(
const coordSet& points,
const wordList& valueSetNames,
const List<const Field<Type>*>& valueSets,
Ostream& os
) const
const word& fieldName,
const Field<Type>& values
)
{
os << "@g0 on" << nl
<< "@with g0" << nl
<< "@ title \"" << points.name() << '"' << nl
<< "@ xaxis label " << '"' << points.axis() << '"' << nl;
forAll(valueSets, i)
checkOpen();
if (coords_.empty())
{
os << "@ s" << i << " legend " << '"'
<< valueSetNames[i] << '"' << nl
<< "@target G0.S" << i << nl;
this->writeTable(points, *valueSets[i], os);
os << '&' << nl;
return fileName::null;
}
}
template<class Type>
void Foam::xmgraceSetWriter<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())
if (useTracks_ || !buffering_)
{
FatalErrorInFunction
<< "Number of variables:" << valueSetNames.size() << endl
<< "Number of valueSets:" << valueSets.size()
<< exit(FatalError);
UPtrList<const Field<Type>> fieldPtrs(repackageFields(values));
return writeTemplate(fieldName, fieldPtrs);
}
if (tracks.size() > 0)
// 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
<< "@with g0" << nl
<< "@ title \"" << tracks[0].name() << '"' << nl
<< "@ xaxis label " << '"' << tracks[0].axis() << '"' << nl;
<< "@ title \"" << coords.name() << '"' << nl
<< "@ xaxis label \"" << coords.axis() << '"' << nl;
// Data index.
label sI = 0;
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++;
}
}
nWritten_ = 0; // Restarted
}
auto& os = ofile_();
// Plot entry
{
os << "@ s" << nWritten_
<< " legend \"" << fieldName << '"' << nl
<< "@target G0.S" << nWritten_ << nl;
writeTable(os, coords, values, " \t");
os << '&' << nl;
os << "# end_data" << nl;
++nWritten_;
}
return ofile_().name();
}
template<class Type>
Foam::fileName Foam::coordSetWriters::xmgraceWriter::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::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 |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd.
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -32,7 +32,7 @@ License
#include "Time.H"
#include "DynamicField.H"
#include "PatchTools.H"
#include "writer.H"
#include "coordSetWriter.H"
#include "triSurfaceMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -611,7 +611,7 @@ bool Foam::searchableSurfaces::checkSizes
bool Foam::searchableSurfaces::checkIntersection
(
const scalar tolerance,
const autoPtr<writer<scalar>>& setWriter,
autoPtr<coordSetWriter>& setWriter,
const bool report
) const
{
@ -669,7 +669,7 @@ bool Foam::searchableSurfaces::checkIntersection
label nHits = 0;
DynamicField<point> intersections(edges0.size()/100);
DynamicField<scalar> intersectionEdge(intersections.capacity());
DynamicField<label> intersectionEdge(intersections.capacity());
forAll(hits, edgeI)
{
@ -680,7 +680,7 @@ bool Foam::searchableSurfaces::checkIntersection
)
{
intersections.append(hits[edgeI].hitPoint());
intersectionEdge.append(1.0*edgeI);
intersectionEdge.append(edgeI);
nHits++;
}
}
@ -698,7 +698,7 @@ bool Foam::searchableSurfaces::checkIntersection
<< " locations."
<< endl;
if (setWriter)
if (setWriter && setWriter->enabled())
{
scalarField dist(mag(intersections));
coordSet track
@ -708,31 +708,27 @@ bool Foam::searchableSurfaces::checkIntersection
std::move(intersections),
std::move(dist)
);
wordList valueSetNames(1, "edgeIndex");
List<const scalarField*> valueSets
(
1,
&intersectionEdge
);
fileName fName
(
setWriter().getFileName(track, valueSetNames)
);
Info<< " Writing intersection locations to "
<< fName << endl;
OFstream os
(
s0.searchableSurface::time().path()
/fName
);
setWriter().write
auto& writer = *setWriter;
writer.nFields(1);
writer.open
(
track,
valueSetNames,
valueSets,
os
(
s0.searchableSurface::time().path()
/ (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 tol,
const autoPtr<writer<scalar>>& setWriter,
autoPtr<coordSetWriter>& setWriter,
const scalar minQuality,
const bool report
) const

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2018-2021 OpenCFD Ltd.
Copyright (C) 2018-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -30,7 +30,6 @@ License
#include "polyMesh.H"
#include "primitiveMesh.H"
#include "meshSearch.H"
#include "writer.H"
#include "particle.H"
#include "globalIndex.H"
@ -52,16 +51,16 @@ void Foam::sampledSet::checkDimensions() const
(cells_.size() != size())
|| (faces_.size() != size())
|| (segments_.size() != size())
|| (curveDist_.size() != size())
|| (distance_.size() != size())
)
{
FatalErrorInFunction
<< "sizes not equal : "
<< "Sizes not equal : "
<< " points:" << size()
<< " cells:" << cells_.size()
<< " faces:" << faces_.size()
<< " segments:" << segments_.size()
<< " curveDist:" << curveDist_.size()
<< " distance:" << distance_.size()
<< abort(FatalError);
}
}
@ -75,14 +74,12 @@ Foam::label Foam::sampledSet::getBoundaryCell(const label facei) const
Foam::label Foam::sampledSet::getNeighbourCell(const label facei) const
{
if (facei >= mesh().nInternalFaces())
{
return mesh().faceOwner()[facei];
}
else
if (facei < mesh().nInternalFaces())
{
return mesh().faceNeighbour()[facei];
}
return mesh().faceOwner()[facei];
}
@ -384,11 +381,11 @@ void Foam::sampledSet::setSamples
const labelList& samplingCells,
const labelList& samplingFaces,
const labelList& samplingSegments,
const scalarList& samplingCurveDist
const scalarList& samplingDistance
)
{
setPoints(samplingPts);
curveDist_ = samplingCurveDist;
setDistance(samplingDistance, false); // check=false
segments_ = samplingSegments;
cells_ = samplingCells;
@ -404,11 +401,11 @@ void Foam::sampledSet::setSamples
labelList&& samplingCells,
labelList&& samplingFaces,
labelList&& samplingSegments,
scalarList&& samplingCurveDist
scalarList&& samplingDistance
)
{
setPoints(std::move(samplingPts));
curveDist_ = std::move(samplingCurveDist);
setDistance(std::move(samplingDistance), false); // check=false
segments_ = std::move(samplingSegments);
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 * * * * * * * * * * * * * * //
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 * * * * * * * * * * * * * //
Foam::autoPtr<Foam::sampledSet> Foam::sampledSet::New

View File

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

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd.
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -29,9 +29,12 @@ License
#include "sampledSets.H"
#include "dictionary.H"
#include "Time.H"
#include "globalIndex.H"
#include "volFields.H"
#include "volPointInterpolation.H"
#include "mapPolyMesh.H"
#include "IOobjectList.H"
#include "UIndirectList.H"
#include "ListOps.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -48,36 +51,287 @@ namespace Foam
);
}
bool Foam::sampledSets::verbose_ = false;
#include "sampledSetsImpl.C"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::sampledSets::combineSampledSets
Foam::autoPtr<Foam::coordSetWriter> Foam::sampledSets::newWriter
(
PtrList<coordSet>& masterSampledSets,
labelListList& indexSets
word writeType,
const dictionary& formatOptions,
const dictionary& setDict
)
{
// Combine sampleSets from processors. Sort by curveDist. Return
// ordering in indexSets.
// Note: only master results are valid
// Per-set adjustment
setDict.readIfPresent<word>("setFormat", writeType);
masterSampledSets_.clear();
masterSampledSets_.setSize(size());
indexSets_.setSize(size());
dictionary options = formatOptions.subOrEmptyDict(writeType);
const PtrList<sampledSet>& sampledSets = *this;
options.merge
(
setDict.subOrEmptyDict("formatOptions").subOrEmptyDict(writeType)
);
forAll(sampledSets, setI)
return coordSetWriter::New(writeType, options);
}
void Foam::sampledSets::gatherAllSets()
{
// Any writer references will become invalid
for (auto& writer : writers_)
{
labelList segments;
masterSampledSets.set
(
setI,
sampledSets[setI].gather(indexSets[setI], segments)
);
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
)
:
functionObjects::regionFunctionObject(name, runTime, dict),
functionObjects::fvMeshFunctionObject(name, runTime, dict),
PtrList<sampledSet>(),
mesh_(refCast<const fvMesh>(obr_)),
dict_(dict),
loadFromFiles_(false),
outputPath_(fileName::null),
searchEngine_(mesh_),
interpolationScheme_(word::null),
writeFormat_(word::null),
writeFormatOptions_(dict.subOrEmptyDict("formatOptions"))
{
outputPath_ =
verbose_(false),
onExecute_(false),
needsCorrect_(false),
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)
{
outputPath_ /= mesh_.name();
@ -124,26 +384,31 @@ Foam::sampledSets::sampledSets
const bool loadFromFiles
)
:
functionObjects::regionFunctionObject(name, obr, dict),
functionObjects::fvMeshFunctionObject(name, obr, dict),
PtrList<sampledSet>(),
mesh_(refCast<const fvMesh>(obr)),
dict_(dict),
loadFromFiles_(loadFromFiles),
outputPath_(fileName::null),
searchEngine_(mesh_),
interpolationScheme_(word::null),
writeFormat_(word::null),
writeFormatOptions_(dict.subOrEmptyDict("formatOptions"))
{
outputPath_ =
verbose_(false),
onExecute_(false),
needsCorrect_(false),
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)
{
outputPath_ /= mesh_.name();
}
outputPath_.clean(); // Remove unneeded ".."
read(dict);
@ -152,7 +417,7 @@ Foam::sampledSets::sampledSets
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::sampledSets::verbose(const bool on)
bool Foam::sampledSets::verbose(const bool on) noexcept
{
bool old(verbose_);
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()
{
if (onExecute_)
{
return performAction(ACTION_ALL & ~ACTION_WRITE);
}
return true;
}
bool Foam::sampledSets::write()
{
if (size())
{
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;
return performAction(ACTION_ALL);
}
void Foam::sampledSets::correct()
{
if (dict_.found("sets"))
{
searchEngine_.correct();
PtrList<sampledSet> newList
(
dict_.lookup("sets"),
sampledSet::iNew(mesh_, searchEngine_)
);
transfer(newList);
combineSampledSets(masterSampledSets_, indexSets_);
}
needsCorrect_ = true;
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2018 OpenCFD Ltd.
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -29,24 +29,86 @@ Class
Description
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
sampledSets.C
sampledSetsImpl.C
\*---------------------------------------------------------------------------*/
#ifndef sampledSets_H
#define sampledSets_H
#ifndef Foam_sampledSets_H
#define Foam_sampledSets_H
#include "regionFunctionObject.H"
#include "fvMeshFunctionObject.H"
#include "sampledSet.H"
#include "volFieldsFwd.H"
#include "meshSearch.H"
#include "interpolation.H"
#include "coordSet.H"
#include "writer.H"
#include "wordRes.H"
#include "coordSetWriter.H"
#include "volFieldsFwd.H"
#include "IOobjectList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -55,9 +117,8 @@ namespace Foam
// Forward Declarations
class Time;
class objectRegistry;
class dictionary;
class fvMesh;
class globalIndex;
/*---------------------------------------------------------------------------*\
Class sampledSets Declaration
@ -65,97 +126,37 @@ class fvMesh;
class sampledSets
:
public functionObjects::regionFunctionObject,
public functionObjects::fvMeshFunctionObject,
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
//- Output verbosity
static bool verbose_;
//- Local control for sampling actions
enum sampleActionType : unsigned
{
ACTION_NONE = 0,
ACTION_WRITE = 0x1,
ACTION_STORE = 0x2,
ACTION_ALL = 0xF
};
// Private Data
//- Const reference to fvMesh
const fvMesh& mesh_;
//- Keep the dictionary to recreate sets for moving mesh cases
dictionary dict_;
//- Load fields from files (not from objectRegistry)
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
fileName outputPath_;
@ -168,8 +169,8 @@ class sampledSets
//- Names of fields to sample
wordRes fieldSelection_;
//- Interpolation scheme to use
word interpolationScheme_;
//- Interpolation/sample scheme to obtain values at the points
word samplePointScheme_;
//- Output format to use
word writeFormat_;
@ -178,61 +179,76 @@ class sampledSets
dictionary writeFormatOptions_;
// Categorized scalar/vector/tensor fields
// Output control
fieldGroup<scalar> scalarFields_;
fieldGroup<vector> vectorFields_;
fieldGroup<sphericalTensor> sphericalTensorFields_;
fieldGroup<symmTensor> symmTensorFields_;
fieldGroup<tensor> tensorFields_;
//- The coordSet writers (one per sampled set)
PtrList<coordSetWriter> writers_;
//- Current list of field names selected for sampling
DynamicList<word> selectedFieldNames_;
// Merging structures
// Merging
PtrList<coordSet> masterSampledSets_;
labelListList indexSets_;
//- Gathered coordSet. (Content only meaningful on master)
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
//- Clear old field groups
void clearFieldGroups();
//- 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
//- A new coordSet writer, with per-set formatOptions
static autoPtr<coordSetWriter> newWriter
(
PtrList<coordSet>& masterSampledSets,
labelListList& indexSets
word writeType,
const dictionary& formatOptions,
const dictionary& surfDict
);
//- Combine values from all processors.
// Valid result only on master processor.
template<class T>
void combineSampledValues
(
const PtrList<volFieldSampler<T>>& sampledFields,
const labelListList& indexSets,
PtrList<volFieldSampler<T>>& masterFields
);
//- Perform sampling action with store/write
bool performAction(unsigned request);
//- 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>
fileName writeSampleFile
void writeCoordSet
(
const coordSet& masterSampleSet,
const PtrList<volFieldSampler<Type>>& masterFields,
const label setI,
const fileName& timeDir,
const writer<Type>& formatter
coordSetWriter& writer,
const Field<Type>& values,
const word& fieldName
);
template<class Type>
void sampleAndWrite(fieldGroup<Type>& fields);
//- Get from registry or load from disk
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
sampledSets(const sampledSets&) = delete;
@ -253,7 +269,7 @@ public:
sampledSets
(
const word& name,
const Time& time,
const Time& runTime,
const dictionary& dict
);
@ -262,8 +278,8 @@ public:
sampledSets
(
const word& name,
const objectRegistry&,
const dictionary&,
const objectRegistry& obr,
const dictionary& dict,
const bool loadFromFiles = false
);
@ -276,7 +292,7 @@ public:
//- Enable/disable verbose output
// \return old value
bool verbose(const bool on);
bool verbose(const bool on) noexcept;
//- Read the sampledSets
virtual bool read(const dictionary&);
@ -307,12 +323,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "sampledSetsTemplates.C"
#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
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;
List<topoDistanceData<label>> allFaceInfo(mesh.nFaces());