ENH: direct ensight output of float/double

- since ensight format is always float and also always written
  component-wise, perform the double -> float narrowing when
  extracting the components.  This reduces the amount of data
  transferred between processors.

ENH: avoid vtk/ensight parallel communication of empty messages

- since ensight writes by element type (eg, tet, hex, polyhedral) the
  individual written field sections will tend to be relatively sparse.
  Skip zero-size messages, which should help reduce some of the
  synchronization bottlenecks.

ENH: use 'data chunking' when writing ensight files in parallel

- since ensight fields are written on a per-element basis, the
  corresponding segment can become rather sparsely distributed. With
  'data chunking', we attempt to get as many send/recv messages in
  before flushing the buffer for writing. This should make the
  sequential send/recv less affected by the IO time.

ENH: allow use of an external buffer when writing ensight components

STYLE: remove last vestiges of autoPtr<ensightFile> for output routines
This commit is contained in:
Mark Olesen
2022-11-11 15:59:06 +01:00
parent 5338e56c73
commit 0fabbcb404
33 changed files with 1698 additions and 517 deletions

View File

@ -0,0 +1,3 @@
foamToEnsight-check.C
EXE = $(FOAM_USER_APPBIN)/foamToEnsight-check

View File

@ -0,0 +1,16 @@
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/finiteArea/lnInclude \
-I$(LIB_SRC)/fileFormats/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/conversion/lnInclude \
-I$(LIB_SRC)/lagrangian/intermediate/lnInclude
EXE_LIBS = \
-lfiniteVolume \
-lfiniteArea \
-lfileFormats \
-lmeshTools \
-lconversion \
-llagrangianIntermediate \
-lgenericPatchFields

View File

@ -0,0 +1,357 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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/>.
Application
foamToEnsight-check
Description
Check data sizes for conversion to ensight format.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "timeSelector.H"
#include "IOobjectList.H"
#include "IOmanip.H"
#include "OFstream.H"
#include "Pstream.H"
#include "HashOps.H"
#include "regionProperties.H"
#include "fvc.H"
#include "faMesh.H"
#include "fvMesh.H"
// file-format/conversion
#include "ensightFaMesh.H"
#include "ensightMesh.H"
using namespace Foam;
void printStats(const FixedList<label, 3>& stats, const char *what = "")
{
Info<< what << "max-comm: "<< stats[0] << nl
<< what << "max-size: "<< stats[1] << nl
<< what << "off-proc: "<< stats[2] << nl;
}
template<class EnsightPartType>
FixedList<label, 3> printPartInfo
(
const EnsightPartType& part,
int verbose = 0
)
{
Info<< "part: " << part.name().c_str() << nl
<< " size: "
<< (Pstream::parRun() ? part.total() : part.size())
<< " (";
FixedList<label, 3> stats(Zero);
label& maxComm = stats[0];
label& maxSize = stats[1];
label& totNonLocalSize = stats[2];
for (int typei=0; typei < EnsightPartType::nTypes; ++typei)
{
const auto etype = typename EnsightPartType::elemType(typei);
if (typei) Info<< ' ';
Info<< EnsightPartType::elemNames[etype] << ": "
<< (Pstream::parRun() ? part.total(etype) : part.size(etype));
label elemCount = part.size(etype);
label commCount = (Pstream::master() ? label(0) : elemCount);
label nonLocalCount = commCount;
if (Pstream::parRun())
{
reduce(elemCount, maxOp<label>());
reduce(commCount, maxOp<label>());
reduce(nonLocalCount, sumOp<label>());
}
maxComm = max(maxComm, commCount);
maxSize = max(maxSize, elemCount);
totNonLocalSize = max(totNonLocalSize, nonLocalCount);
}
Info<< ")" << endl;
if (verbose && Pstream::parRun() && part.total())
{
for (int typei=0; typei < EnsightPartType::nTypes; ++typei)
{
const auto etype = typename EnsightPartType::elemType(typei);
label elemCount = part.size(etype);
label totCount = part.total(etype);
Info<< " "
<< EnsightPartType::elemNames[etype] << ": "
<< totCount;
if (totCount)
{
labelList sizes(UPstream::listGatherValues(elemCount));
Info<< " ";
sizes.writeList(Info);
}
Info<< endl;
}
}
printStats(stats, " ");
return stats;
}
void printInfo(const ensightMesh& mesh, int verbose = 0)
{
FixedList<label, 3> cellStats(Zero);
FixedList<label, 3> faceStats(Zero);
for (const auto& iter : mesh.cellZoneParts().sorted())
{
FixedList<label, 3> stats = printPartInfo(iter.val(), verbose);
for (label i=0; i < 3; ++i)
{
cellStats[i] = max(cellStats[i], stats[i]);
}
}
for (const auto& iter : mesh.faceZoneParts().sorted())
{
FixedList<label, 3> stats = printPartInfo(iter.val(), verbose);
for (label i=0; i < 3; ++i)
{
faceStats[i] = max(faceStats[i], stats[i]);
}
}
for (const auto& iter : mesh.boundaryParts().sorted())
{
FixedList<label, 3> stats = printPartInfo(iter.val(), verbose);
for (label i=0; i < 3; ++i)
{
faceStats[i] = max(faceStats[i], stats[i]);
}
}
Info<< nl
<< "===============" << nl;
printStats(cellStats, "cell ");
Info<< nl;
printStats(faceStats, "face ");
Info<< "===============" << endl;
}
void printInfo(const ensightFaMesh& mesh, int verbose = 0)
{
printPartInfo(mesh.areaPart());
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
argList::addNote
(
"Check data sizes for conversion of OpenFOAM to Ensight format"
);
// timeSelector::addOptions();
// Less frequently used - reduce some clutter
argList::setAdvanced("decomposeParDict");
argList::addVerboseOption("Additional verbosity");
#include "addAllRegionOptions.H"
argList::addBoolOption
(
"no-boundary", // noPatches
"Suppress writing any patches"
);
argList::addBoolOption
(
"no-internal",
"Suppress writing the internal mesh"
);
argList::addBoolOption
(
"no-cellZones",
"Suppress writing any cellZones"
);
argList::addBoolOption
(
"no-finite-area",
"Suppress output of finite-area mesh/fields",
true // mark as an advanced option
);
#include "setRootCase.H"
// ------------------------------------------------------------------------
// Configuration
const int optVerbose = args.verbose();
const bool doBoundary = !args.found("no-boundary");
const bool doInternal = !args.found("no-internal");
const bool doCellZones = !args.found("no-cellZones");
const bool doFiniteArea = !args.found("no-finite-area");
ensightMesh::options writeOpts;
writeOpts.useBoundaryMesh(doBoundary);
writeOpts.useInternalMesh(doInternal);
writeOpts.useCellZones(doCellZones);
// ------------------------------------------------------------------------
#include "createTime.H"
instantList timeDirs = timeSelector::select0(runTime, args);
// Handle -allRegions, -regions, -region
#include "getAllRegionOptions.H"
// ------------------------------------------------------------------------
#include "createNamedMeshes.H"
// ------------------------------------------------------------------------
/// #include "createMeshAccounting.H"
PtrList<ensightMesh> ensightMeshes(regionNames.size());
PtrList<faMesh> meshesFa(regionNames.size());
PtrList<ensightFaMesh> ensightMeshesFa(regionNames.size());
forAll(regionNames, regioni)
{
const fvMesh& mesh = meshes[regioni];
ensightMeshes.set
(
regioni,
new ensightMesh(mesh, writeOpts)
);
ensightMeshes[regioni].verbose(optVerbose);
if (doFiniteArea)
{
autoPtr<faMesh> faMeshPtr(faMesh::TryNew(mesh));
if (faMeshPtr)
{
meshesFa.set(regioni, std::move(faMeshPtr));
ensightMeshesFa.set
(
regioni,
new ensightFaMesh(meshesFa[regioni])
);
ensightMeshesFa[regioni].verbose(optVerbose);
}
}
}
// ------------------------------------------------------------------------
if (Pstream::master())
{
Info<< "Checking " << timeDirs.size() << " time steps" << nl;
}
forAll(timeDirs, timei)
{
runTime.setTime(timeDirs[timei], timei);
forAll(regionNames, regioni)
{
const word& regionName = regionNames[regioni];
// const word& regionDir = polyMesh::regionName(regionName);
auto& mesh = meshes[regioni];
polyMesh::readUpdateState meshState = mesh.readUpdate();
const bool moving = (meshState != polyMesh::UNCHANGED);
auto& ensMesh = ensightMeshes[regioni];
// Finite-area (can be missing)
auto* ensFaMeshPtr = ensightMeshesFa.get(regioni);
if (moving)
{
ensMesh.expire();
ensMesh.correct();
if (ensFaMeshPtr)
{
ensFaMeshPtr->expire();
ensFaMeshPtr->correct();
}
}
if (moving || timei == 0) // report
{
if (regionNames.size() > 1)
{
Info<< "region=" << regionName << nl;
}
printInfo(ensMesh, optVerbose);
if (ensFaMeshPtr)
{
printInfo(*ensFaMeshPtr, optVerbose);
}
}
}
}
Info<< "\nEnd"<< nl << endl;
return 0;
}
// ************************************************************************* //

View File

@ -45,10 +45,10 @@ if (doLagrangian)
ensightOutput::writeCloudPositions ensightOutput::writeCloudPositions
( (
os.ref(),
mesh, mesh,
cloudName, cloudName,
cloudExists, cloudExists
os
); );
Info<< " positions"; Info<< " positions";
@ -86,26 +86,34 @@ if (doLagrangian)
} }
bool wrote = false; bool wrote = false;
if (fieldType == scalarIOField::typeName) do
{ {
autoPtr<ensightFile> os = #undef ensight_WRITE_CLOUD_FIELD
ensCase.newCloudData<scalar>(cloudName, fieldName); #define ensight_WRITE_CLOUD_FIELD(PrimitiveType) \
\
if (fieldType == IOField<PrimitiveType>::typeName) \
{ \
autoPtr<ensightFile> os = \
ensCase.newCloudData<PrimitiveType> \
( \
cloudName, \
fieldName \
); \
\
wrote = ensightOutput::readWriteCloudField<PrimitiveType> \
( \
os.ref(), \
fieldObject, \
fieldExists \
); \
break; \
}
wrote = ensightOutput::writeCloudField<scalar> ensight_WRITE_CLOUD_FIELD(scalar);
( ensight_WRITE_CLOUD_FIELD(vector);
fieldObject, fieldExists, os
);
}
else if (fieldType == vectorIOField::typeName)
{
autoPtr<ensightFile> os =
ensCase.newCloudData<vector>(cloudName, fieldName);
wrote = ensightOutput::writeCloudField<vector> #undef ensight_WRITE_CLOUD_FIELD
( } while (false);
fieldObject, fieldExists, os
);
}
if (wrote) if (wrote)
{ {

View File

@ -1,7 +1,7 @@
/*--------------------------------*- C++ -*----------------------------------*\ /*--------------------------------*- C++ -*----------------------------------*\
| ========= | | | ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2206 | | \\ / O peration | Version: v2212 |
| \\ / A nd | Website: www.openfoam.com | | \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | | | \\/ M anipulation | |
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -118,7 +118,14 @@ OptimisationSwitches
// Default: 1e9 // Default: 1e9
maxMasterFileBufferSize 1e9; maxMasterFileBufferSize 1e9;
commsType nonBlocking; //scheduled; //blocking; // Upper limit when bundling off-processor field transfers (ensight).
// for component-wise transfer (uses float: 4 bytes)
// Eg, 5M for 50 ranks of 100k cells
ensight.maxChunk 5000000;
// Default communication type (nonBlocking | scheduled | blocking);
commsType nonBlocking;
floatTransfer 0; floatTransfer 0;
nProcsSimpleSum 0; nProcsSimpleSum 0;
@ -136,6 +143,7 @@ OptimisationSwitches
// global reduction, even if multi-pass is not needed) // global reduction, even if multi-pass is not needed)
maxCommsSize 0; maxCommsSize 0;
// Trap floating point exception. // Trap floating point exception.
// Can override with FOAM_SIGFPE env variable (true|false) // Can override with FOAM_SIGFPE env variable (true|false)
trapFpe 1; trapFpe 1;
@ -539,6 +547,7 @@ DebugSwitches
empty 0; empty 0;
engineMesh 0; engineMesh 0;
enrichedPatch 0; enrichedPatch 0;
ensight 0;
epsilonWallFunction 0; epsilonWallFunction 0;
errorDrivenRefinement 0; errorDrivenRefinement 0;
evaporationModel 0; evaporationModel 0;

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd. Copyright (C) 2021-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -31,8 +31,8 @@ Description
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef ensightOutputAreaField_H #ifndef Foam_ensightOutput_areaField_H
#define ensightOutputAreaField_H #define Foam_ensightOutput_areaField_H
#include "ensightOutput.H" #include "ensightOutput.H"
#include "ensightFaces.H" #include "ensightFaces.H"
@ -57,12 +57,39 @@ namespace ensightOutput
template<class Type> template<class Type>
bool writeAreaField bool writeAreaField
( (
//! Component scratch buffer
ensightOutput::floatBufferType& scratch,
//! Output file (must be valid on master)
ensightFile& os, ensightFile& os,
//! The field content to be written
const GeometricField<Type, faPatchField, areaMesh>& fld, const GeometricField<Type, faPatchField, areaMesh>& fld,
//! The addressing into the field
const ensightFaMesh& ensMesh const ensightFaMesh& ensMesh
); );
//- Write finite-area field component-wise
template<class Type>
bool writeAreaField
(
//! Output file (must be valid on master)
ensightFile& os,
//! The field content to be written
const GeometricField<Type, faPatchField, areaMesh>& fld,
//! The addressing into the field
const ensightFaMesh& ensMesh
)
{
ensightOutput::floatBufferType scratch;
return ensightOutput::writeAreaField(scratch, os, fld, ensMesh);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace ensightOutput } // End namespace ensightOutput

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd. Copyright (C) 2021-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -34,6 +34,7 @@ License
template<class Type> template<class Type>
bool Foam::ensightOutput::writeAreaField bool Foam::ensightOutput::writeAreaField
( (
ensightOutput::floatBufferType& scratch,
ensightFile& os, ensightFile& os,
const GeometricField<Type, faPatchField, areaMesh>& fld, const GeometricField<Type, faPatchField, areaMesh>& fld,
const ensightFaMesh& ensMesh const ensightFaMesh& ensMesh
@ -45,6 +46,7 @@ bool Foam::ensightOutput::writeAreaField
{ {
ensightOutput::Detail::writeFaceLocalField ensightOutput::Detail::writeFaceLocalField
( (
scratch,
os, os,
fld, fld,
ensMesh.areaPart(), ensMesh.areaPart(),

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -31,8 +31,8 @@ Description
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef ensightOutputVolField_H #ifndef Foam_ensightOutput_volField_H
#define ensightOutputVolField_H #define Foam_ensightOutput_volField_H
#include "ensightOutput.H" #include "ensightOutput.H"
#include "ensightFaces.H" #include "ensightFaces.H"
@ -58,30 +58,115 @@ namespace ensightOutput
template<class Type> template<class Type>
bool writeVolField bool writeVolField
( (
//! Component scratch buffer
ensightOutput::floatBufferType& scratch,
//! Output file (must be valid on master)
ensightFile& os, ensightFile& os,
//! The field content to be written
const GeometricField<Type, fvPatchField, volMesh>& vf, const GeometricField<Type, fvPatchField, volMesh>& vf,
//! The addressing (element-wise) into the field
const ensightMesh& ensMesh const ensightMesh& ensMesh
); );
//- Write volume field component-wise
template<class Type>
bool writeVolField
(
//! Output file (must be valid on master)
ensightFile& os,
//! The field content to be written
const GeometricField<Type, fvPatchField, volMesh>& vf,
//! The addressing (element-wise) into the field
const ensightMesh& ensMesh
)
{
ensightOutput::floatBufferType scratch;
return ensightOutput::writeVolField<Type>(scratch, os, vf, ensMesh);
}
//- Write volume field component-wise, optionally forcing interpolation //- Write volume field component-wise, optionally forcing interpolation
template<class Type> template<class Type>
bool writeVolField bool writeVolField
( (
//! Component scratch buffer
ensightOutput::floatBufferType& scratch,
//! Output file (must be valid on master)
ensightFile& os, ensightFile& os,
//! The field content to be written
const GeometricField<Type, fvPatchField, volMesh>& vf, const GeometricField<Type, fvPatchField, volMesh>& vf,
//! The addressing (element-wise) into the field
const ensightMesh& ensMesh, const ensightMesh& ensMesh,
//! Interpolate values to points
const bool nodeValues const bool nodeValues
); );
//- Write volume field component-wise, optionally forcing interpolation
template<class Type>
bool writeVolField
(
//! Output file (must be valid on master)
ensightFile& os,
//! The field content to be written
const GeometricField<Type, fvPatchField, volMesh>& vf,
//! The addressing (element-wise) into the field
const ensightMesh& ensMesh,
//! Interpolate values to points
const bool nodeValues
)
{
ensightOutput::floatBufferType scratch;
return ensightOutput::writeVolField<Type>
(
scratch, os, vf, ensMesh, nodeValues
);
}
//- Write point field component-wise
template<class Type>
bool writePointField
(
//! Component scratch buffer
ensightOutput::floatBufferType& scratch,
//! Output file (must be valid on master)
ensightFile& os,
//! The field content to be written
const GeometricField<Type, pointPatchField, pointMesh>& pf,
//! The addressing (element-wise) into the field
const ensightMesh& ensMesh
);
//- Write point field component-wise //- Write point field component-wise
template<class Type> template<class Type>
bool writePointField bool writePointField
( (
//! Output file (must be valid on master)
ensightFile& os, ensightFile& os,
//! The field content to be written
const GeometricField<Type, pointPatchField, pointMesh>& pf, const GeometricField<Type, pointPatchField, pointMesh>& pf,
//! The addressing (element-wise) into the field
const ensightMesh& ensMesh const ensightMesh& ensMesh
); )
{
ensightOutput::floatBufferType scratch;
return ensightOutput::writePointField<Type>(scratch, os, pf, ensMesh);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2021 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -40,6 +40,7 @@ License
template<class Type> template<class Type>
bool Foam::ensightOutput::writeVolField bool Foam::ensightOutput::writeVolField
( (
ensightOutput::floatBufferType& scratch,
ensightFile& os, ensightFile& os,
const GeometricField<Type, fvPatchField, volMesh>& vf, const GeometricField<Type, fvPatchField, volMesh>& vf,
const ensightMesh& ensMesh const ensightMesh& ensMesh
@ -54,13 +55,12 @@ bool Foam::ensightOutput::writeVolField
const Map<ensightFaces>& faceZoneParts = ensMesh.faceZoneParts(); const Map<ensightFaces>& faceZoneParts = ensMesh.faceZoneParts();
const Map<ensightFaces>& boundaryParts = ensMesh.boundaryParts(); const Map<ensightFaces>& boundaryParts = ensMesh.boundaryParts();
// Write internalMesh and cellZones - sorted by index // Write internalMesh and cellZones - sorted by index
for (const label zoneId : cellZoneParts.sortedToc()) for (const label zoneId : cellZoneParts.sortedToc())
{ {
const ensightCells& part = cellZoneParts[zoneId]; const ensightCells& part = cellZoneParts[zoneId];
ensightOutput::writeField(os, vf, part, parallel); ensightOutput::writeField(scratch, os, vf, part, parallel);
} }
@ -88,6 +88,7 @@ bool Foam::ensightOutput::writeVolField
ensightOutput::writeField ensightOutput::writeField
( (
scratch,
os, os,
vf.boundaryField()[patchId], vf.boundaryField()[patchId],
localPart, localPart,
@ -170,7 +171,7 @@ bool Foam::ensightOutput::writeVolField
// - boundary faces use the corresponding patch value // - boundary faces use the corresponding patch value
// Local copy of the field // Local copy of the field
values.resize(part.size()); values.resize_nocopy(part.size());
values = Zero; values = Zero;
auto valIter = values.begin(); auto valIter = values.begin();
@ -189,7 +190,10 @@ bool Foam::ensightOutput::writeVolField
// The field is already in the proper element order // The field is already in the proper element order
// - just need its corresponding sub-fields // - just need its corresponding sub-fields
ensightOutput::Detail::writeFaceSubField(os, values, part, parallel); ensightOutput::Detail::writeFaceSubField
(
scratch, os, values, part, parallel
);
} }
return true; return true;
@ -199,6 +203,7 @@ bool Foam::ensightOutput::writeVolField
template<class Type> template<class Type>
bool Foam::ensightOutput::writePointField bool Foam::ensightOutput::writePointField
( (
ensightOutput::floatBufferType& scratch,
ensightFile& os, ensightFile& os,
const GeometricField<Type, pointPatchField, pointMesh>& pf, const GeometricField<Type, pointPatchField, pointMesh>& pf,
const ensightMesh& ensMesh const ensightMesh& ensMesh
@ -219,16 +224,28 @@ bool Foam::ensightOutput::writePointField
{ {
const ensightCells& part = cellZoneParts[zoneId]; const ensightCells& part = cellZoneParts[zoneId];
labelList uniquePointLabels;
part.uniqueMeshPoints(mesh, uniquePointLabels, parallel);
if (Pstream::master()) if (Pstream::master())
{ {
os.beginPart(part.index()); os.beginPart(part.index());
} }
labelList uniquePointLabels; // Skip if empty
part.uniqueMeshPoints(mesh, uniquePointLabels, parallel); if
(
parallel
? returnReduceAnd(uniquePointLabels.empty())
: uniquePointLabels.empty()
)
{
continue;
}
ensightOutput::Detail::writeFieldComponents ensightOutput::Detail::writeFieldComponents
( (
scratch,
os, os,
ensightFile::coordinates, ensightFile::coordinates,
UIndirectList<Type>(pf.internalField(), uniquePointLabels), UIndirectList<Type>(pf.internalField(), uniquePointLabels),
@ -244,13 +261,24 @@ bool Foam::ensightOutput::writePointField
{ {
const ensightFaces& part = boundaryParts[patchId]; const ensightFaces& part = boundaryParts[patchId];
labelList uniquePointLabels;
part.uniqueMeshPoints(mesh, uniquePointLabels, parallel);
if (Pstream::master()) if (Pstream::master())
{ {
os.beginPart(part.index()); os.beginPart(part.index());
} }
labelList uniquePointLabels; // Skip if empty
part.uniqueMeshPoints(mesh, uniquePointLabels, parallel); if
(
parallel
? returnReduceAnd(uniquePointLabels.empty())
: uniquePointLabels.empty()
)
{
continue;
}
const auto& bfld = pf.boundaryField()[patchId]; const auto& bfld = pf.boundaryField()[patchId];
@ -272,6 +300,7 @@ bool Foam::ensightOutput::writePointField
ensightOutput::Detail::writeFieldComponents ensightOutput::Detail::writeFieldComponents
( (
scratch,
os, os,
ensightFile::coordinates, ensightFile::coordinates,
UIndirectList<Type>(*vpp, uniquePointLabels), UIndirectList<Type>(*vpp, uniquePointLabels),
@ -282,6 +311,7 @@ bool Foam::ensightOutput::writePointField
{ {
ensightOutput::Detail::writeFieldComponents ensightOutput::Detail::writeFieldComponents
( (
scratch,
os, os,
ensightFile::coordinates, ensightFile::coordinates,
UIndirectList<Type>(pf.internalField(), uniquePointLabels), UIndirectList<Type>(pf.internalField(), uniquePointLabels),
@ -297,26 +327,36 @@ bool Foam::ensightOutput::writePointField
{ {
const ensightFaces& part = faceZoneParts[zoneId]; const ensightFaces& part = faceZoneParts[zoneId];
labelList uniquePointLabels;
part.uniqueMeshPoints(mesh, uniquePointLabels, parallel);
if (Pstream::master()) if (Pstream::master())
{ {
os.beginPart(part.index()); os.beginPart(part.index());
} }
// Skip if empty
if
(
parallel
? returnReduceAnd(uniquePointLabels.empty())
: uniquePointLabels.empty()
)
{
continue;
}
// CAVEAT - does not properly handle valuePointPatchField, // CAVEAT - does not properly handle valuePointPatchField,
// uses internalField only // uses internalField only
{ ensightOutput::Detail::writeFieldComponents
labelList uniquePointLabels; (
part.uniqueMeshPoints(mesh, uniquePointLabels, parallel); scratch,
os,
ensightOutput::Detail::writeFieldComponents ensightFile::coordinates,
( UIndirectList<Type>(pf.internalField(), uniquePointLabels),
os, parallel
ensightFile::coordinates, );
UIndirectList<Type>(pf.internalField(), uniquePointLabels),
parallel
);
}
} }
return true; return true;
@ -328,6 +368,7 @@ bool Foam::ensightOutput::writePointField
template<class Type> template<class Type>
bool Foam::ensightOutput::writeVolField bool Foam::ensightOutput::writeVolField
( (
ensightOutput::floatBufferType& scratch,
ensightFile& os, ensightFile& os,
const GeometricField<Type, fvPatchField, volMesh>& vf, const GeometricField<Type, fvPatchField, volMesh>& vf,
const ensightMesh& ensMesh, const ensightMesh& ensMesh,
@ -343,10 +384,10 @@ bool Foam::ensightOutput::writeVolField
pfld.ref().checkOut(); pfld.ref().checkOut();
pfld.ref().rename(vf.name()); pfld.ref().rename(vf.name());
return ensightOutput::writePointField<Type>(os, pfld, ensMesh); return ensightOutput::writePointField<Type>(scratch, os, pfld, ensMesh);
} }
return ensightOutput::writeVolField<Type>(os, vf, ensMesh); return ensightOutput::writeVolField<Type>(scratch, os, vf, ensMesh);
} }

View File

@ -43,9 +43,23 @@ const char* const Foam::ensightFile::coordinates = "coordinates";
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
bool Foam::ensightFile::hasUndef(const UList<scalar>& field) bool Foam::ensightFile::hasUndef(const UList<float>& field)
{ {
for (const scalar& val : field) for (const float val : field)
{
if (std::isnan(val))
{
return true;
}
}
return true;
}
bool Foam::ensightFile::hasUndef(const UList<double>& field)
{
for (const double val : field)
{ {
if (std::isnan(val)) if (std::isnan(val))
{ {
@ -354,15 +368,32 @@ void Foam::ensightFile::writeList(const UList<label>& field)
{ {
for (const label val : field) for (const label val : field)
{ {
write(scalar(val)); write(float(val));
newline(); newline();
} }
} }
void Foam::ensightFile::writeList(const UList<scalar>& field) void Foam::ensightFile::writeList(const UList<float>& field)
{ {
for (const scalar val : field) for (const float val : field)
{
if (std::isnan(val))
{
writeUndef();
}
else
{
write(val);
}
newline();
}
}
void Foam::ensightFile::writeList(const UList<double>& field)
{
for (const double val : field)
{ {
if (std::isnan(val)) if (std::isnan(val))
{ {

View File

@ -228,26 +228,42 @@ public:
// Adds newline after each value (ascii stream) // Adds newline after each value (ascii stream)
void writeList(const UList<label>& field); void writeList(const UList<label>& field);
//- Write a list of floating-point as "%12.5e" or as binary //- Write a list of floats as "%12.5e" or as binary.
//- (double is narrowed to float).
// Adds newline after each value (ascii stream) // Adds newline after each value (ascii stream)
void writeList(const UList<scalar>& field); void writeList(const UList<float>& field);
//- Write an indirect list of scalars as "%12.5e" or as binary //- Write a list of double as "%12.5e" or as binary.
//- (double is narrowed to float)
// Adds newline after each value (ascii stream)
void writeList(const UList<double>& field);
//- Write an indirect list of float as "%12.5e" or as binary
// Adds newline after each value (ascii stream)
template<class Addr>
void writeList(const IndirectListBase<float, Addr>& field);
//- Write an indirect list of double as "%12.5e" or as binary.
//- (double is narrowed to float) //- (double is narrowed to float)
// Adds newline after each value (ascii stream) // Adds newline after each value (ascii stream)
template<class Addr> template<class Addr>
void writeList(const IndirectListBase<scalar, Addr>& field); void writeList(const IndirectListBase<double, Addr>& field);
// Other Methods // Other Methods
//- Check for any NaN in the field //- Check for any NaN in the field
static bool hasUndef(const UList<scalar>& field); static bool hasUndef(const UList<float>& field);
//- Check for any NaN in the field
static bool hasUndef(const UList<double>& field);
//- Check for any NaN in the field //- Check for any NaN in the field
template<class Addr> template<class Addr>
static bool hasUndef(const IndirectListBase<scalar, Addr>& field); static bool hasUndef(const IndirectListBase<float, Addr>& field);
//- Check for any NaN in the field
template<class Addr>
static bool hasUndef(const IndirectListBase<double, Addr>& field);
}; };

View File

@ -28,9 +28,24 @@ License
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
template<class Addr> template<class Addr>
bool Foam::ensightFile::hasUndef(const IndirectListBase<scalar, Addr>& field) bool Foam::ensightFile::hasUndef(const IndirectListBase<float, Addr>& field)
{ {
for (const scalar val : field) for (const float val : field)
{
if (std::isnan(val))
{
return true;
}
}
return true;
}
template<class Addr>
bool Foam::ensightFile::hasUndef(const IndirectListBase<double, Addr>& field)
{
for (const double val : field)
{ {
if (std::isnan(val)) if (std::isnan(val))
{ {
@ -56,9 +71,27 @@ void Foam::ensightFile::writeLabels(const IndirectListBase<label, Addr>& list)
template<class Addr> template<class Addr>
void Foam::ensightFile::writeList(const IndirectListBase<scalar, Addr>& field) void Foam::ensightFile::writeList(const IndirectListBase<float, Addr>& field)
{ {
for (const scalar val : field) for (const float val : field)
{
if (std::isnan(val))
{
writeUndef();
}
else
{
write(val);
}
newline();
}
}
template<class Addr>
void Foam::ensightFile::writeList(const IndirectListBase<double, Addr>& field)
{
for (const double val : field)
{ {
if (std::isnan(val)) if (std::isnan(val))
{ {

View File

@ -32,6 +32,23 @@ License
#include "polyMesh.H" #include "polyMesh.H"
#include "ListOps.H" #include "ListOps.H"
#include "manifoldCellsMeshObject.H" #include "manifoldCellsMeshObject.H"
#include "debug.H"
#include "defineDebugSwitch.H"
#include "registerSwitch.H"
// * * * * * * * * * * * * * * * * Globals * * * * * * * * * * * * * * * * * //
defineDebugSwitchWithName(Foam::ensightOutput, "ensight", 0);
registerDebugSwitchWithName(Foam::ensightOutput, ensightOutput, "ensight");
int Foam::ensightOutput::maxChunk_
(
Foam::debug::optimisationSwitch("ensight.maxChunk", 0)
);
registerOptSwitch("ensight.maxChunk", int, Foam::ensightOutput::maxChunk_);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -38,6 +38,7 @@ SourceFiles
#ifndef Foam_ensightOutput_H #ifndef Foam_ensightOutput_H
#define Foam_ensightOutput_H #define Foam_ensightOutput_H
#include "ensightOutputFwd.H"
#include "ensightFile.H" #include "ensightFile.H"
#include "ensightGeoFile.H" #include "ensightGeoFile.H"
#include "ensightCells.H" #include "ensightCells.H"
@ -186,7 +187,8 @@ void writeFaceConnectivity
const ensightFaces::elemType etype, const ensightFaces::elemType etype,
const label nTotal, const label nTotal,
const UIndirectList<face>& faces, const UIndirectList<face>& faces,
bool parallel //!< Collective write? //! Prefer collective write?
bool parallel
); );
@ -197,7 +199,8 @@ void writeFaceConnectivity
const ensightFaces::elemType etype, const ensightFaces::elemType etype,
const label nTotal, const label nTotal,
const faceUList& faces, const faceUList& faces,
bool parallel //!< Collective write? //! Prefer collective write?
bool parallel
); );
@ -207,7 +210,8 @@ void writeFaceConnectivity
ensightGeoFile& os, ensightGeoFile& os,
const ensightFaces& part, const ensightFaces& part,
const faceUList& faces, const faceUList& faces,
bool parallel //!< Collective write? //! Prefer collective write?
bool parallel
); );
@ -219,7 +223,8 @@ void writeFaceConnectivityPresorted
ensightGeoFile& os, ensightGeoFile& os,
const ensightFaces& part, const ensightFaces& part,
const faceUList& faces, const faceUList& faces,
bool parallel //!< Collective write? //! Prefer collective write?
bool parallel
); );
@ -232,10 +237,20 @@ void writeFaceConnectivityPresorted
template<class Type> template<class Type>
bool writeField bool writeField
( (
//! Component scratch buffer
ensightOutput::floatBufferType& scratch,
//! Output file (must be valid on master)
ensightFile& os, ensightFile& os,
//! The field content to be written
const Field<Type>& fld, const Field<Type>& fld,
//! The addressing (element-wise) into the field
const ensightCells& part, const ensightCells& part,
bool parallel //!< Collective write?
//! Prefer collective write?
bool parallel
); );
//- Write a field of faces values as an indirect list, //- Write a field of faces values as an indirect list,
@ -243,13 +258,69 @@ bool writeField
template<class Type> template<class Type>
bool writeField bool writeField
( (
//! Component scratch buffer
ensightOutput::floatBufferType& scratch,
//! Output file (must be valid on master)
ensightFile& os, ensightFile& os,
//! The field content to be written
const Field<Type>& fld, const Field<Type>& fld,
//! The addressing (element-wise) into the field
const ensightFaces& part, const ensightFaces& part,
bool parallel //!< Collective write?
//! Prefer collective write?
bool parallel
); );
//- Write a field of cell values as an indirect list,
//- using the cell ids from ensightCells
template<class Type>
bool writeField
(
//! Output file (must be valid on master)
ensightFile& os,
//! The field content to be written
const Field<Type>& fld,
//! The addressing (element-wise) into the field
const ensightCells& part,
//! Prefer collective write?
bool parallel
)
{
ensightOutput::floatBufferType scratch;
return ensightOutput::writeField(scratch, os, fld, part, parallel);
}
//- Write a field of faces values as an indirect list,
//- using the face ids from ensightFaces
template<class Type>
bool writeField
(
//! Output file (must be valid on master)
ensightFile& os,
//! The field content to be written
const Field<Type>& fld,
//! The addressing (element-wise) into the field
const ensightFaces& part,
//! Prefer collective write?
bool parallel
)
{
ensightOutput::floatBufferType scratch;
return ensightOutput::writeField(scratch, os, fld, part, parallel);
}
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Namespace ensightOutput::Detail Namespace ensightOutput::Detail
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -302,48 +373,109 @@ void writeLabelListList
); );
//- Copy specified field component into a scalar buffer //- Copy specified field component into a scalar buffer.
//- works for various lists types. Must be adequately sized before calling //- Works for various lists types. Must be adequately sized before calling
template<template<typename> class FieldContainer, class Type> template<template<typename> class FieldContainer, class Type>
void copyComponent void copyComponent
( (
List<scalar>& cmptBuffer, //! Input field data
const FieldContainer<Type>& input, const FieldContainer<Type>& input,
const direction cmpt
//! Component to be extracted
const direction cmpt,
//! [out] Component scratch buffer
UList<float>& cmptBuffer
); );
//- Write field content (component-wise) //- Write coordinates (component-wise) for the given part.
template<template<typename> class FieldContainer, class Type> //
void writeFieldContent // Has internal check for (nPoints != 0)
(
ensightFile& os,
const FieldContainer<Type>& fld,
bool parallel //!< Collective write?
);
//- Write coordinates (component-wise) for the given part
template<template<typename> class FieldContainer> template<template<typename> class FieldContainer>
bool writeCoordinates bool writeCoordinates
( (
//! Output file (must be valid on master)
ensightGeoFile& os, ensightGeoFile& os,
//! The ensight part id
const label partId, const label partId,
//! The ensight part description
const word& partName, const word& partName,
//! The total number of points
const label nPoints, const label nPoints,
//! The point field to be written
const FieldContainer<Foam::point>& fld, const FieldContainer<Foam::point>& fld,
bool parallel //!< Collective write?
//! Prefer collective write?
bool parallel
); );
//- Write field content (component-wise) for the given ensight element type //- Write field content (component-wise) for the given ensight element type.
template<template<typename> class FieldContainer, class Type> template<template<typename> class FieldContainer, class Type>
bool writeFieldComponents void writeFieldComponents
( (
//! Component scratch buffer
ensightOutput::floatBufferType& scratch,
//! Output file (must be valid on master)
ensightFile& os, ensightFile& os,
//! The ensight element type (ignored if nullptr)
const char* key, const char* key,
//! The field content to be written for this element type
const FieldContainer<Type>& fld, const FieldContainer<Type>& fld,
bool parallel //!< Collective write?
//! Prefer collective write?
bool parallel
);
//- Write field content (component-wise) for the given ensight element type.
template<template<typename> class FieldContainer, class Type>
void writeFieldComponents
(
//! Output file (must be valid on master)
ensightFile& os,
//! The ensight element type (can be nullptr)
const char* key,
//! The field content to be written for this element type
const FieldContainer<Type>& fld,
//!< Prefer collective write?
bool parallel
)
{
ensightOutput::floatBufferType scratch;
Detail::writeFieldComponents(scratch, os, key, fld, parallel);
}
//- Write a sub-field of faces values as an indirect list,
//- using the sub-list sizing information from ensightFaces
template<class Type>
bool writeFaceSubField
(
//! Component scratch buffer
ensightOutput::floatBufferType& scratch,
//! Output file (must be valid on master)
ensightFile& os,
//! The field content to be written
const Field<Type>& fld,
//! The addressing (element-wise) into the field
const ensightFaces& part,
//! Prefer collective write?
bool parallel
); );
@ -352,11 +484,22 @@ bool writeFieldComponents
template<class Type> template<class Type>
bool writeFaceSubField bool writeFaceSubField
( (
//! Output file (must be valid on master)
ensightFile& os, ensightFile& os,
//! The field content to be written
const Field<Type>& fld, const Field<Type>& fld,
//! The addressing (element-wise) into the field
const ensightFaces& part, const ensightFaces& part,
bool parallel //!< Collective write?
); //! Prefer collective write?
bool parallel
)
{
ensightOutput::floatBufferType scratch;
return Detail::writeFaceSubField(scratch, os, fld, part, parallel);
}
//- Write a field of faces values as an indirect list, //- Write a field of faces values as an indirect list,
@ -364,12 +507,44 @@ bool writeFaceSubField
template<class Type> template<class Type>
bool writeFaceLocalField bool writeFaceLocalField
( (
//! Component scratch buffer
ensightOutput::floatBufferType& scratch,
//! Output file (must be valid on master)
ensightFile& os, ensightFile& os,
//! The field content to be written
const Field<Type>& fld, const Field<Type>& fld,
//! The addressing (element-wise) into the field
const ensightFaces& part, const ensightFaces& part,
bool parallel //!< Collective write?
//! Prefer collective write?
bool parallel
); );
//- Write a field of faces values as an indirect list,
//- using the face order from ensightFaces
template<class Type>
bool writeFaceLocalField
(
//! Output file (must be valid on master)
ensightFile& os,
//! The field content to be written
const Field<Type>& fld,
//! The addressing (element-wise) into the field
const ensightFaces& part,
//! Prefer collective write?
bool parallel
)
{
ensightOutput::floatBufferType scratch;
return Detail::writeFaceLocalField(scratch, os, fld, part, parallel);
}
} // End namespace Detail } // End namespace Detail

View File

@ -0,0 +1,78 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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/>.
Namespace
Foam::ensightOutput
Description
A collection of functions for writing ensight file content.
\*---------------------------------------------------------------------------*/
#ifndef Foam_ensightOutputFwd_H
#define Foam_ensightOutputFwd_H
#include "DynamicList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class ensightFile;
class ensightGeoFile;
/*---------------------------------------------------------------------------*\
Namespace ensightOutput
\*---------------------------------------------------------------------------*/
namespace ensightOutput
{
//- The list type used for component-wise buffering.
// Always has value_type = \c float (what ensight uses internally)
typedef DynamicList<float> floatBufferType;
//- Static debugging option
extern int debug;
//- Upper limit on number of items for bundled off-processor field transfers.
//- The component-wise transfer uses float (4 bytes).
// Eg, 5M for 50 ranks of 100k cells each
extern int maxChunk_;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace ensightOutput
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -55,9 +55,9 @@ void Foam::ensightOutput::Detail::writeLabelListList
template<template<typename> class FieldContainer, class Type> template<template<typename> class FieldContainer, class Type>
void Foam::ensightOutput::Detail::copyComponent void Foam::ensightOutput::Detail::copyComponent
( (
List<scalar>& cmptBuffer,
const FieldContainer<Type>& input, const FieldContainer<Type>& input,
const direction cmpt const direction cmpt,
UList<float>& cmptBuffer
) )
{ {
if (cmptBuffer.size() < input.size()) if (cmptBuffer.size() < input.size())
@ -70,78 +70,178 @@ void Foam::ensightOutput::Detail::copyComponent
auto iter = cmptBuffer.begin(); auto iter = cmptBuffer.begin();
for (const Type& val : input) if (std::is_same<float, typename pTraits<Type>::cmptType>::value)
{ {
*iter = component(val, cmpt); // Direct copy
++iter; for (const Type& val : input)
{
*iter = component(val, cmpt);
++iter;
}
}
else
{
// Copy with narrowing
for (const Type& val : input)
{
*iter = narrowFloat(component(val, cmpt));
++iter;
}
} }
} }
template<template<typename> class FieldContainer, class Type> template<template<typename> class FieldContainer, class Type>
void Foam::ensightOutput::Detail::writeFieldContent void Foam::ensightOutput::Detail::writeFieldComponents
( (
ensightOutput::floatBufferType& scratch,
ensightFile& os, ensightFile& os,
const char* key,
const FieldContainer<Type>& fld, const FieldContainer<Type>& fld,
bool parallel bool parallel
) )
{ {
// already checked prior to calling, but extra safety
parallel = parallel && Pstream::parRun(); parallel = parallel && Pstream::parRun();
const label localSize = fld.size();
// Gather sizes (offsets irrelevant) // Gather sizes (offsets irrelevant)
const globalIndex procAddr const globalIndex procAddr
( (
parallel parallel
? globalIndex(globalIndex::gatherOnly{}, fld.size()) ? globalIndex(globalIndex::gatherOnly{}, localSize)
: globalIndex(globalIndex::gatherNone{}, fld.size()) : globalIndex(globalIndex::gatherNone{}, localSize)
); );
if (Pstream::master() && key)
{
os.writeKeyword(key);
}
if (Pstream::master()) if (Pstream::master())
{ {
DynamicList<scalar> cmptBuffer(procAddr.maxSize()); // Buffer size needed for an individual rank
const label minSize(max(localSize, procAddr.maxSize()));
// Buffer size needed for all nonLocal ranks
const label nonLocalSize(procAddr.totalSize() - localSize);
// Maximum off-processor transfer size
const label maxTransfer =
(
(ensightOutput::maxChunk_ > 0)
? min(static_cast<label>(ensightOutput::maxChunk_), nonLocalSize)
: static_cast<label>(0)
);
// Allocate at least enough to process a single rank, but potentially
// receive multiple ranks at a time before writing
scratch.resize_nocopy(max(minSize, maxTransfer));
if (Pstream::master() && debug > 1)
{
Info<< "ensight";
if (key)
{
Info<< " (" << key << ')';
}
Info<< " total-size:" << procAddr.totalSize()
<< " buf-size:" << scratch.size() << "/" << scratch.capacity()
<< " any-proc:" << minSize
<< " off-proc:" << nonLocalSize << endl;
Info<< "proc-sends: (";
label nPending = localSize;
Info<< (localSize ? '0' : '_');
// Receive others, writing as needed
for (const label proci : procAddr.subProcs())
{
const label procSize = procAddr.localSize(proci);
if (procSize)
{
if (nPending + procSize > scratch.size())
{
// Flush buffer
nPending = 0;
Info<< ") (";
}
else
{
Info<< ' ';
}
Info<< proci;
nPending += procSize;
}
}
Info<< ')' << endl;
}
for (direction d=0; d < pTraits<Type>::nComponents; ++d) for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{ {
const direction cmpt = ensightPTraits<Type>::componentOrder[d]; const direction cmpt = ensightPTraits<Type>::componentOrder[d];
// Write master data // Master
cmptBuffer.resize_nocopy(procAddr.localSize(0)); copyComponent(fld, cmpt, scratch);
copyComponent(cmptBuffer, fld, cmpt); label nPending = localSize;
os.writeList(cmptBuffer);
// Receive and write // Receive others, writing as needed
for (const label proci : procAddr.subProcs()) for (const label proci : procAddr.subProcs())
{ {
cmptBuffer.resize_nocopy(procAddr.localSize(proci)); const label procSize = procAddr.localSize(proci);
UIPstream::read
( if (procSize)
UPstream::commsTypes::scheduled, {
proci, if (nPending + procSize > scratch.size())
cmptBuffer.data_bytes(), {
cmptBuffer.size_bytes() // Flush buffer
); os.writeList(SubList<float>(scratch, nPending));
os.writeList(cmptBuffer); nPending = 0;
}
SubList<float> slot(scratch, procSize, nPending);
nPending += procSize;
UIPstream::read
(
UPstream::commsTypes::scheduled,
proci,
slot.data_bytes(),
slot.size_bytes()
);
}
}
if (nPending)
{
// Flush buffer
os.writeList(SubList<float>(scratch, nPending));
} }
} }
} }
else if (parallel) else if (parallel && localSize)
{ {
// Send scratch.resize_nocopy(localSize);
List<scalar> cmptBuffer(fld.size());
for (direction d=0; d < pTraits<Type>::nComponents; ++d) for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{ {
const direction cmpt = ensightPTraits<Type>::componentOrder[d]; const direction cmpt = ensightPTraits<Type>::componentOrder[d];
copyComponent(cmptBuffer, fld, cmpt); copyComponent(fld, cmpt, scratch);
UOPstream::write UOPstream::write
( (
UPstream::commsTypes::scheduled, UPstream::commsTypes::scheduled,
UPstream::masterNo(), UPstream::masterNo(),
cmptBuffer.cdata_bytes(), scratch.cdata_bytes(),
cmptBuffer.size_bytes() scratch.size_bytes()
); );
} }
} }
@ -159,45 +259,31 @@ bool Foam::ensightOutput::Detail::writeCoordinates
bool parallel bool parallel
) )
{ {
parallel = parallel && Pstream::parRun();
if (Pstream::master()) if (Pstream::master())
{ {
os.beginPart(partId, partName); os.beginPart(partId, partName);
os.beginCoordinates(nPoints); os.beginCoordinates(nPoints);
} }
ensightOutput::Detail::writeFieldContent(os, fld, parallel); bool ok = (Pstream::master() && (nPoints > 0));
if (parallel)
return true;
}
template<template<typename> class FieldContainer, class Type>
bool Foam::ensightOutput::Detail::writeFieldComponents
(
ensightFile& os,
const char* key,
const FieldContainer<Type>& fld,
bool parallel
)
{
parallel = parallel && Pstream::parRun();
// Preliminary checks
{ {
// No field Pstream::broadcast(ok);
if (parallel ? returnReduceAnd(fld.empty()) : fld.empty()) return false;
} }
if (ok)
if (Pstream::master())
{ {
os.writeKeyword(key); ensightOutput::floatBufferType scratch;
ensightOutput::Detail::writeFieldComponents
(
scratch,
os,
nullptr, // (no element type)
fld,
parallel
);
} }
ensightOutput::Detail::writeFieldContent(os, fld, parallel);
return true; return true;
} }
@ -205,6 +291,7 @@ bool Foam::ensightOutput::Detail::writeFieldComponents
template<class Type> template<class Type>
bool Foam::ensightOutput::Detail::writeFaceSubField bool Foam::ensightOutput::Detail::writeFaceSubField
( (
ensightOutput::floatBufferType& scratch,
ensightFile& os, ensightFile& os,
const Field<Type>& fld, const Field<Type>& fld,
const ensightFaces& part, const ensightFaces& part,
@ -213,13 +300,17 @@ bool Foam::ensightOutput::Detail::writeFaceSubField
{ {
parallel = parallel && Pstream::parRun(); parallel = parallel && Pstream::parRun();
// Preliminary checks: total() contains pre-reduced information // Need geometry and field. part.total() is already reduced
{ const bool good =
// No geometry (
if (parallel ? !part.total() : !part.size()) return false; parallel
? (part.total() && returnReduceOr(fld.size()))
: (part.size() && fld.size())
);
// No field if (!good)
if (parallel ? returnReduceAnd(fld.empty()) : fld.empty()) return false; {
return false;
} }
@ -232,13 +323,18 @@ bool Foam::ensightOutput::Detail::writeFaceSubField
{ {
const auto etype = ensightFaces::elemType(typei); const auto etype = ensightFaces::elemType(typei);
ensightOutput::Detail::writeFieldComponents // Write elements of this type
( if (parallel ? part.total(etype) : part.size(etype))
os, {
ensightFaces::key(etype), ensightOutput::Detail::writeFieldComponents
SubField<Type>(fld, part.range(etype)), (
parallel scratch,
); os,
ensightFaces::key(etype),
SubField<Type>(fld, part.range(etype)),
parallel
);
}
} }
return true; return true;
@ -248,6 +344,7 @@ bool Foam::ensightOutput::Detail::writeFaceSubField
template<class Type> template<class Type>
bool Foam::ensightOutput::Detail::writeFaceLocalField bool Foam::ensightOutput::Detail::writeFaceLocalField
( (
ensightOutput::floatBufferType& scratch,
ensightFile& os, ensightFile& os,
const Field<Type>& fld, const Field<Type>& fld,
const ensightFaces& part, const ensightFaces& part,
@ -256,15 +353,20 @@ bool Foam::ensightOutput::Detail::writeFaceLocalField
{ {
parallel = parallel && Pstream::parRun(); parallel = parallel && Pstream::parRun();
// Preliminary checks: total() contains pre-reduced information // Need geometry and field. part.total() is already reduced
{ const bool good =
// No geometry (
if (parallel ? !part.total() : !part.size()) return false; parallel
? (part.total() && returnReduceOr(fld.size()))
: (part.size() && fld.size())
);
// No field if (!good)
if (parallel ? returnReduceAnd(fld.empty()) : fld.empty()) return false; {
return false;
} }
bool validAddressing = (part.size() == part.faceOrder().size()); bool validAddressing = (part.size() == part.faceOrder().size());
if (parallel) if (parallel)
@ -289,13 +391,18 @@ bool Foam::ensightOutput::Detail::writeFaceLocalField
{ {
const auto etype = ensightFaces::elemType(typei); const auto etype = ensightFaces::elemType(typei);
ensightOutput::Detail::writeFieldComponents // Write elements of this type
( if (parallel ? part.total(etype) : part.size(etype))
os, {
ensightFaces::key(etype), ensightOutput::Detail::writeFieldComponents
UIndirectList<Type>(fld, part.faceOrder(etype)), (
parallel scratch,
); os,
ensightFaces::key(etype),
UIndirectList<Type>(fld, part.faceOrder(etype)),
parallel
);
}
} }
return true; return true;
@ -307,6 +414,7 @@ bool Foam::ensightOutput::Detail::writeFaceLocalField
template<class Type> template<class Type>
bool Foam::ensightOutput::writeField bool Foam::ensightOutput::writeField
( (
ensightOutput::floatBufferType& scratch,
ensightFile& os, ensightFile& os,
const Field<Type>& fld, const Field<Type>& fld,
const ensightCells& part, const ensightCells& part,
@ -315,13 +423,17 @@ bool Foam::ensightOutput::writeField
{ {
parallel = parallel && Pstream::parRun(); parallel = parallel && Pstream::parRun();
// Preliminary checks: total() contains pre-reduced information // Need geometry and field. part.total() is already reduced
{ const bool good =
// No geometry (
if (parallel ? !part.total() : !part.size()) return false; parallel
? (part.total() && returnReduceOr(fld.size()))
: (part.size() && fld.size())
);
// No field if (!good)
if (parallel ? returnReduceAnd(fld.empty()) : fld.empty()) return false; {
return false;
} }
@ -334,13 +446,18 @@ bool Foam::ensightOutput::writeField
{ {
const auto etype = ensightCells::elemType(typei); const auto etype = ensightCells::elemType(typei);
ensightOutput::Detail::writeFieldComponents // Write elements of this type
( if (parallel ? part.total(etype) : part.size(etype))
os, {
ensightCells::key(etype), ensightOutput::Detail::writeFieldComponents
UIndirectList<Type>(fld, part.cellIds(etype)), (
parallel scratch,
); os,
ensightCells::key(etype),
UIndirectList<Type>(fld, part.cellIds(etype)),
parallel
);
}
} }
return true; return true;
@ -350,6 +467,7 @@ bool Foam::ensightOutput::writeField
template<class Type> template<class Type>
bool Foam::ensightOutput::writeField bool Foam::ensightOutput::writeField
( (
ensightOutput::floatBufferType& scratch,
ensightFile& os, ensightFile& os,
const Field<Type>& fld, const Field<Type>& fld,
const ensightFaces& part, const ensightFaces& part,
@ -358,13 +476,17 @@ bool Foam::ensightOutput::writeField
{ {
parallel = parallel && Pstream::parRun(); parallel = parallel && Pstream::parRun();
// Preliminary checks: total() contains pre-reduced information // Need geometry and field. part.total() is already reduced
{ const bool good =
// No geometry (
if (parallel ? !part.total() : !part.size()) return false; parallel
? (part.total() && returnReduceOr(fld.size()))
: (part.size() && fld.size())
);
// No field if (!good)
if (parallel ? returnReduceAnd(fld.empty()) : fld.empty()) return false; {
return false;
} }
@ -377,13 +499,18 @@ bool Foam::ensightOutput::writeField
{ {
const auto etype = ensightFaces::elemType(typei); const auto etype = ensightFaces::elemType(typei);
ensightOutput::Detail::writeFieldComponents // Write elements of this type
( if (parallel ? part.total(etype) : part.size(etype))
os, {
ensightFaces::key(etype), ensightOutput::Detail::writeFieldComponents
UIndirectList<Type>(fld, part.faceIds(etype)), (
parallel scratch,
); os,
ensightFaces::key(etype),
UIndirectList<Type>(fld, part.faceIds(etype)),
parallel
);
}
} }
return true; return true;

View File

@ -99,7 +99,7 @@ Foam::FixedList<Foam::label, 5> Foam::ensightCells::sizes() const
{ {
FixedList<label, 5> count; FixedList<label, 5> count;
forAll(count, typei) for (int typei = 0; typei < nTypes; ++typei)
{ {
count[typei] = size(elemType(typei)); count[typei] = size(elemType(typei));
} }
@ -108,14 +108,14 @@ Foam::FixedList<Foam::label, 5> Foam::ensightCells::sizes() const
} }
Foam::label Foam::ensightCells::total() const Foam::label Foam::ensightCells::totalSize() const noexcept
{ {
label nTotal = 0; label count = 0;
forAll(sizes_, typei) for (label n : sizes_)
{ {
nTotal += sizes_[typei]; count += n;
} }
return nTotal; return count;
} }
@ -137,11 +137,10 @@ void Foam::ensightCells::clearOut()
void Foam::ensightCells::reduce() void Foam::ensightCells::reduce()
{ {
forAll(sizes_, typei) for (int typei = 0; typei < nTypes; ++typei)
{ {
sizes_[typei] = size(elemType(typei)); sizes_[typei] = size(elemType(typei));
} }
// Can reduce FixedList with sumOp<label> in a single operation
Foam::reduce(sizes_, sumOp<label>()); Foam::reduce(sizes_, sumOp<label>());
} }

View File

@ -82,7 +82,7 @@ public:
// Static Functions // Static Functions
//- The ensight element name for the specified 'Cell' type //- The ensight element name for the specified 'Cell' type
inline static const char* key(const elemType etype); inline static const char* key(const elemType etype) noexcept;
private: private:
@ -183,7 +183,10 @@ public:
//- The global size of all element types. //- The global size of all element types.
// This value is only meaningful after a reduce operation. // This value is only meaningful after a reduce operation.
label total() const; label totalSize() const noexcept;
//- Same as totalSize()
label total() const noexcept { return totalSize(); }
//- The global size of the specified element type. //- The global size of the specified element type.
// This value is only meaningful after a reduce operation. // This value is only meaningful after a reduce operation.

View File

@ -46,7 +46,7 @@ inline bool Foam::ensightCells::manifold() const noexcept
} }
inline const char* Foam::ensightCells::key(const elemType etype) inline const char* Foam::ensightCells::key(const elemType etype) noexcept
{ {
return elemNames[etype]; return elemNames[etype];
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2021 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -124,7 +124,7 @@ Foam::FixedList<Foam::label, 3> Foam::ensightFaces::sizes() const
{ {
FixedList<label, 3> count; FixedList<label, 3> count;
forAll(count, typei) for (int typei = 0; typei < nTypes; ++typei)
{ {
count[typei] = size(elemType(typei)); count[typei] = size(elemType(typei));
} }
@ -133,14 +133,14 @@ Foam::FixedList<Foam::label, 3> Foam::ensightFaces::sizes() const
} }
Foam::label Foam::ensightFaces::total() const Foam::label Foam::ensightFaces::totalSize() const noexcept
{ {
label nTotal = 0; label count = 0;
forAll(sizes_, typei) for (label n : sizes_)
{ {
nTotal += sizes_[typei]; count += n;
} }
return nTotal; return count;
} }
@ -163,11 +163,10 @@ void Foam::ensightFaces::clearOut()
void Foam::ensightFaces::reduce() void Foam::ensightFaces::reduce()
{ {
forAll(sizes_, typei) for (int typei = 0; typei < nTypes; ++typei)
{ {
sizes_[typei] = size(elemType(typei)); sizes_[typei] = size(elemType(typei));
} }
// Can reduce FixedList with sumOp<label> in a single operation
Foam::reduce(sizes_, sumOp<label>()); Foam::reduce(sizes_, sumOp<label>());
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2021 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -97,7 +97,7 @@ public:
// Static Functions // Static Functions
//- The ensight element name for the specified 'Face' type //- The ensight element name for the specified 'Face' type
static inline const char* key(const elemType etype); static inline const char* key(const elemType etype) noexcept;
private: private:
@ -162,7 +162,10 @@ public:
//- The global size of all element types. //- The global size of all element types.
// This value is only meaningful after a reduce operation. // This value is only meaningful after a reduce operation.
label total() const; label totalSize() const noexcept;
//- Same as totalSize
label total() const noexcept { return totalSize(); }
//- The global size of the specified element type. //- The global size of the specified element type.
// This value is only meaningful after a reduce operation. // This value is only meaningful after a reduce operation.

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2021 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -46,7 +46,7 @@ Foam::ensightFaces::add(const elemType etype, label id, bool flip)
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline const char* Foam::ensightFaces::key(const elemType etype) inline const char* Foam::ensightFaces::key(const elemType etype) noexcept
{ {
return elemNames[etype]; return elemNames[etype];
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2013-2015 OpenFOAM Foundation Copyright (C) 2013-2015 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd. Copyright (C) 2019-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -41,11 +41,20 @@ Foam::ensightPTraits<Foam::label>::componentOrder[] = {0};
template<> template<>
const char* const const char* const
Foam::ensightPTraits<Foam::scalar>::typeName = "scalar"; Foam::ensightPTraits<float>::typeName = "scalar";
template<> template<>
const Foam::direction const Foam::direction
Foam::ensightPTraits<Foam::scalar>::componentOrder[] = {0}; Foam::ensightPTraits<float>::componentOrder[] = {0};
template<>
const char* const
Foam::ensightPTraits<double>::typeName = "scalar";
template<>
const Foam::direction
Foam::ensightPTraits<double>::componentOrder[] = {0};
template<> template<>

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2013-2015 OpenFOAM Foundation Copyright (C) 2013-2015 OpenFOAM Foundation
Copyright (C) 2019-2021 OpenCFD Ltd. Copyright (C) 2019-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -47,7 +47,7 @@ namespace Foam
{ {
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class ensightPTraits Declaration Class ensightPTraits Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
template<class Type> template<class Type>
@ -69,8 +69,11 @@ struct ensightPTraits
template<> const char* const ensightPTraits<label>::typeName; template<> const char* const ensightPTraits<label>::typeName;
template<> const direction ensightPTraits<label>::componentOrder[]; template<> const direction ensightPTraits<label>::componentOrder[];
template<> const char* const ensightPTraits<scalar>::typeName; template<> const char* const ensightPTraits<float>::typeName;
template<> const direction ensightPTraits<scalar>::componentOrder[]; template<> const direction ensightPTraits<float>::componentOrder[];
template<> const char* const ensightPTraits<double>::typeName;
template<> const direction ensightPTraits<double>::componentOrder[];
template<> const char* const ensightPTraits<vector>::typeName; template<> const char* const ensightPTraits<vector>::typeName;
template<> const direction ensightPTraits<vector>::componentOrder[]; template<> const direction ensightPTraits<vector>::componentOrder[];

View File

@ -130,7 +130,7 @@ void Foam::vtk::writeListParallel
) )
{ {
// Gather sizes (offsets irrelevant) // Gather sizes (offsets irrelevant)
const globalIndex procAddr(values.size(), globalIndex::gatherOnly{}); const globalIndex procAddr(globalIndex::gatherOnly{}, values.size());
if (Pstream::master()) if (Pstream::master())
{ {
@ -146,33 +146,40 @@ void Foam::vtk::writeListParallel
for (const label proci : procAddr.subProcs()) for (const label proci : procAddr.subProcs())
{ {
recvData.resize_nocopy(procAddr.localSize(proci)); const label procSize = procAddr.localSize(proci);
UIPstream::read
(
UPstream::commsTypes::scheduled,
proci,
recvData.data_bytes(),
recvData.size_bytes()
);
// With value offset if (procSize)
const label offsetId = procOffset.localStart(proci);
for (const label val : recvData)
{ {
vtk::write(fmt, val + offsetId); recvData.resize_nocopy(procSize);
UIPstream::read
(
UPstream::commsTypes::scheduled,
proci,
recvData.data_bytes(),
recvData.size_bytes()
);
// With value offset
const label offsetId = procOffset.localStart(proci);
for (const label val : recvData)
{
vtk::write(fmt, val + offsetId);
}
} }
} }
} }
else else
{ {
// Send if (values.size())
UOPstream::write {
( UOPstream::write
UPstream::commsTypes::scheduled, (
UPstream::masterNo(), UPstream::commsTypes::scheduled,
values.cdata_bytes(), UPstream::masterNo(),
values.size_bytes() values.cdata_bytes(),
); values.size_bytes()
);
}
} }
} }

View File

@ -171,7 +171,7 @@ void Foam::vtk::writeListParallel
// Gather sizes (offsets irrelevant) // Gather sizes (offsets irrelevant)
const globalIndex procAddr(values.size(), globalIndex::gatherOnly{}); const globalIndex procAddr(globalIndex::gatherOnly{}, values.size());
if (Pstream::master()) if (Pstream::master())
@ -184,27 +184,34 @@ void Foam::vtk::writeListParallel
for (const label proci : procAddr.subProcs()) for (const label proci : procAddr.subProcs())
{ {
recvData.resize_nocopy(procAddr.localSize(proci)); const label procSize = procAddr.localSize(proci);
UIPstream::read
( if (procSize)
UPstream::commsTypes::scheduled, {
proci, recvData.resize_nocopy(procSize);
recvData.data_bytes(), UIPstream::read
recvData.size_bytes() (
); UPstream::commsTypes::scheduled,
vtk::writeList(fmt, recvData); proci,
recvData.data_bytes(),
recvData.size_bytes()
);
vtk::writeList(fmt, recvData);
}
} }
} }
else else
{ {
// Send if (values.size())
UOPstream::write {
( UOPstream::write
UPstream::commsTypes::scheduled, (
UPstream::masterNo(), UPstream::commsTypes::scheduled,
values.cdata_bytes(), UPstream::masterNo(),
values.size_bytes() values.cdata_bytes(),
); values.size_bytes()
);
}
} }
} }
@ -233,7 +240,7 @@ void Foam::vtk::writeListParallel
} }
// Gather sizes (offsets irrelevant) // Gather sizes (offsets irrelevant)
const globalIndex procAddr(sendData.size(), globalIndex::gatherOnly{}); const globalIndex procAddr(globalIndex::gatherOnly{}, sendData.size());
if (Pstream::master()) if (Pstream::master())
@ -246,26 +253,34 @@ void Foam::vtk::writeListParallel
for (const label proci : procAddr.subProcs()) for (const label proci : procAddr.subProcs())
{ {
recvData.resize_nocopy(procAddr.localSize(proci)); const label procSize = procAddr.localSize(proci);
UIPstream::read
( if (procSize)
UPstream::commsTypes::scheduled, {
proci, recvData.resize_nocopy(procSize);
recvData.data_bytes(), UIPstream::read
recvData.size_bytes() (
); UPstream::commsTypes::scheduled,
vtk::writeList(fmt, recvData); proci,
recvData.data_bytes(),
recvData.size_bytes()
);
vtk::writeList(fmt, recvData);
}
} }
} }
else else
{ {
UOPstream::write if (sendData.size())
( {
UPstream::commsTypes::scheduled, UOPstream::write
UPstream::masterNo(), (
sendData.cdata_bytes(), UPstream::commsTypes::scheduled,
sendData.size_bytes() UPstream::masterNo(),
); sendData.cdata_bytes(),
sendData.size_bytes()
);
}
} }
} }
@ -294,7 +309,7 @@ void Foam::vtk::writeListParallel
} }
// Gather sizes (offsets irrelevant) // Gather sizes (offsets irrelevant)
const globalIndex procAddr(sendData.size(), globalIndex::gatherOnly{}); const globalIndex procAddr(globalIndex::gatherOnly{}, sendData.size());
if (Pstream::master()) if (Pstream::master())
@ -307,26 +322,35 @@ void Foam::vtk::writeListParallel
for (const label proci : procAddr.subProcs()) for (const label proci : procAddr.subProcs())
{ {
recvData.resize_nocopy(procAddr.localSize(proci)); const label procSize = procAddr.localSize(proci);
UIPstream::read
( if (procSize)
UPstream::commsTypes::scheduled, {
proci, recvData.resize_nocopy(procSize);
recvData.data_bytes(),
recvData.size_bytes() UIPstream::read
); (
vtk::writeList(fmt, recvData); UPstream::commsTypes::scheduled,
proci,
recvData.data_bytes(),
recvData.size_bytes()
);
vtk::writeList(fmt, recvData);
}
} }
} }
else else
{ {
UOPstream::write if (sendData.size())
( {
UPstream::commsTypes::scheduled, UOPstream::write
UPstream::masterNo(), (
sendData.cdata_bytes(), UPstream::commsTypes::scheduled,
sendData.size_bytes() UPstream::masterNo(),
); sendData.cdata_bytes(),
sendData.size_bytes()
);
}
} }
} }
@ -349,8 +373,8 @@ void Foam::vtk::writeListsParallel
// Gather sizes (offsets irrelevant) // Gather sizes (offsets irrelevant)
const globalIndex procAddr1(values1.size(), globalIndex::gatherOnly{}); const globalIndex procAddr1(globalIndex::gatherOnly{}, values1.size());
const globalIndex procAddr2(values2.size(), globalIndex::gatherOnly{}); const globalIndex procAddr2(globalIndex::gatherOnly{}, values2.size());
if (Pstream::master()) if (Pstream::master())
@ -368,45 +392,61 @@ void Foam::vtk::writeListsParallel
for (const label proci : procAddr1.subProcs()) for (const label proci : procAddr1.subProcs())
{ {
// values1 // values1
recvData.resize_nocopy(procAddr1.localSize(proci)); label procSize = procAddr1.localSize(proci);
UIPstream::read
( if (procSize)
UPstream::commsTypes::scheduled, {
proci, recvData.resize_nocopy(procSize);
recvData.data_bytes(), UIPstream::read
recvData.size_bytes() (
); UPstream::commsTypes::scheduled,
vtk::writeList(fmt, recvData); proci,
recvData.data_bytes(),
recvData.size_bytes()
);
vtk::writeList(fmt, recvData);
}
// values2 // values2
recvData.resize_nocopy(procAddr2.localSize(proci)); procSize = procAddr2.localSize(proci);
UIPstream::read
( if (procSize)
UPstream::commsTypes::scheduled, {
proci, recvData.resize_nocopy(procSize);
recvData.data_bytes(), UIPstream::read
recvData.size_bytes() (
); UPstream::commsTypes::scheduled,
vtk::writeList(fmt, recvData); proci,
recvData.data_bytes(),
recvData.size_bytes()
);
vtk::writeList(fmt, recvData);
}
} }
} }
else else
{ {
UOPstream::write if (values1.size())
( {
UPstream::commsTypes::scheduled, UOPstream::write
UPstream::masterNo(), (
values1.cdata_bytes(), UPstream::commsTypes::scheduled,
values1.size_bytes() UPstream::masterNo(),
); values1.cdata_bytes(),
values1.size_bytes()
);
}
UOPstream::write if (values2.size())
( {
UPstream::commsTypes::scheduled, UOPstream::write
UPstream::masterNo(), (
values2.cdata_bytes(), UPstream::commsTypes::scheduled,
values2.size_bytes() UPstream::masterNo(),
); values2.cdata_bytes(),
values2.size_bytes()
);
}
} }
} }
@ -437,8 +477,8 @@ void Foam::vtk::writeListsParallel
// Gather sizes (offsets irrelevant) // Gather sizes (offsets irrelevant)
const globalIndex procAddr1(values1.size(), globalIndex::gatherOnly{}); const globalIndex procAddr1(globalIndex::gatherOnly{}, values1.size());
const globalIndex procAddr2(sendData2.size(), globalIndex::gatherOnly{}); const globalIndex procAddr2(globalIndex::gatherOnly{}, sendData2.size());
if (Pstream::master()) if (Pstream::master())
@ -457,45 +497,61 @@ void Foam::vtk::writeListsParallel
for (const label proci : procAddr1.subProcs()) for (const label proci : procAddr1.subProcs())
{ {
// values1 // values1
recvData.resize_nocopy(procAddr1.localSize(proci)); label procSize = procAddr1.localSize(proci);
UIPstream::read
( if (procSize)
UPstream::commsTypes::scheduled, {
proci, recvData.resize_nocopy(procSize);
recvData.data_bytes(), UIPstream::read
recvData.size_bytes() (
); UPstream::commsTypes::scheduled,
vtk::writeList(fmt, recvData); proci,
recvData.data_bytes(),
recvData.size_bytes()
);
vtk::writeList(fmt, recvData);
}
// values2 // values2
recvData.resize_nocopy(procAddr2.localSize(proci)); procSize = procAddr2.localSize(proci);
UIPstream::read
( if (procSize)
UPstream::commsTypes::scheduled, {
proci, recvData.resize_nocopy(procSize);
recvData.data_bytes(), UIPstream::read
recvData.size_bytes() (
); UPstream::commsTypes::scheduled,
vtk::writeList(fmt, recvData); proci,
recvData.data_bytes(),
recvData.size_bytes()
);
vtk::writeList(fmt, recvData);
}
} }
} }
else else
{ {
UOPstream::write if (values1.size())
( {
UPstream::commsTypes::scheduled, UOPstream::write
UPstream::masterNo(), (
values1.cdata_bytes(), UPstream::commsTypes::scheduled,
values1.size_bytes() UPstream::masterNo(),
); values1.cdata_bytes(),
values1.size_bytes()
);
}
UOPstream::write if (sendData2.size())
( {
UPstream::commsTypes::scheduled, UOPstream::write
UPstream::masterNo(), (
sendData2.cdata_bytes(), UPstream::commsTypes::scheduled,
sendData2.size_bytes() UPstream::masterNo(),
); sendData2.cdata_bytes(),
sendData2.size_bytes()
);
}
} }
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,6 +26,7 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "ensightWrite.H" #include "ensightWrite.H"
#include "ensightOutput.H"
#include "Time.H" #include "Time.H"
#include "polyMesh.H" #include "polyMesh.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
@ -47,6 +48,9 @@ namespace functionObjects
} }
} }
// Implementation
#include "ensightWriteImpl.C"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::label Foam::functionObjects::ensightWrite::writeAllVolFields Foam::label Foam::functionObjects::ensightWrite::writeAllVolFields
@ -57,11 +61,26 @@ Foam::label Foam::functionObjects::ensightWrite::writeAllVolFields
{ {
label count = 0; label count = 0;
count += writeVolFields<scalar>(proxy, acceptField); ensightOutput::floatBufferType scratch;
count += writeVolFields<vector>(proxy, acceptField);
count += writeVolFields<sphericalTensor>(proxy, acceptField); {
count += writeVolFields<symmTensor>(proxy, acceptField); #undef doLocalCode
count += writeVolFields<tensor>(proxy, acceptField); #define doLocalCode(PrimitiveType) \
count += writeVolFieldsImpl<PrimitiveType> \
( \
scratch, \
proxy, \
acceptField \
);
doLocalCode(scalar);
doLocalCode(vector);
doLocalCode(sphericalTensor);
doLocalCode(symmTensor);
doLocalCode(tensor);
#undef doLocalCode
}
return count; return count;
} }
@ -215,6 +234,8 @@ bool Foam::functionObjects::ensightWrite::write()
ensMesh_().write(os); ensMesh_().write(os);
} }
// TBD: handle allow/deny filters
wordHashSet acceptField(mesh_.names<void>(selectFields_)); wordHashSet acceptField(mesh_.names<void>(selectFields_));
// Prune restart fields // Prune restart fields

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -127,16 +127,18 @@ See also
SourceFiles SourceFiles
ensightWrite.C ensightWrite.C
ensightWriteTemplates.C ensightWriteImpl.C
ensightWriteUpdate.C
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef functionObjects_ensightWrite_H #ifndef Foam_functionObjects_ensightWrite_H
#define functionObjects_ensightWrite_H #define Foam_functionObjects_ensightWrite_H
#include "fvMeshFunctionObject.H" #include "fvMeshFunctionObject.H"
#include "ensightCase.H" #include "ensightCase.H"
#include "ensightMesh.H" #include "ensightMesh.H"
#include "ensightOutputFwd.H"
#include "interpolation.H" #include "interpolation.H"
#include "volFields.H" #include "volFields.H"
@ -223,6 +225,15 @@ class ensightWrite
// Write // Write
//- Write selected volume fields.
template<class Type>
label writeVolFieldsImpl
(
ensightOutput::floatBufferType& scratch,
const fvMeshSubset& proxy,
const wordHashSet& acceptField
);
//- Write all volume fields //- Write all volume fields
label writeAllVolFields label writeAllVolFields
( (
@ -230,15 +241,6 @@ class ensightWrite
const wordHashSet& acceptField const wordHashSet& acceptField
); );
//- Write selected volume fields.
template<class Type>
label writeVolFields
(
const fvMeshSubset& proxy,
const wordHashSet& acceptField
);
//- No copy construct //- No copy construct
ensightWrite(const ensightWrite&) = delete; ensightWrite(const ensightWrite&) = delete;
@ -296,12 +298,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ensightWriteTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif #endif
// ************************************************************************* // // ************************************************************************* //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -30,8 +30,9 @@ License
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type> template<class Type>
Foam::label Foam::functionObjects::ensightWrite::writeVolFields Foam::label Foam::functionObjects::ensightWrite::writeVolFieldsImpl
( (
ensightOutput::floatBufferType& scratch,
const fvMeshSubset& proxy, const fvMeshSubset& proxy,
const wordHashSet& acceptField const wordHashSet& acceptField
) )
@ -58,6 +59,7 @@ Foam::label Foam::functionObjects::ensightWrite::writeVolFields
ensightOutput::writeVolField<Type> ensightOutput::writeVolField<Type>
( (
scratch,
os.ref(), os.ref(),
field, field,
ensMesh(), ensMesh(),

View File

@ -35,40 +35,41 @@ License
namespace Foam namespace Foam
{ {
//- Binary output
static inline void writeMeasured_binary //- Binary output
( static inline void writeMeasured_binary
ensightFile& os, (
const UList<point>& points ensightFile& os,
) const UList<floatVector>& points
)
{
for (const floatVector& p : points)
{ {
for (const point& p : points) os.write(p.x());
{ os.write(p.y());
os.write(p.x()); os.write(p.z());
os.write(p.y()); }
os.write(p.z()); }
}
//- ASCII output. Id + position together
static inline label writeMeasured_ascii
(
ensightFile& os,
label pointId,
const UList<floatVector>& points
)
{
for (const floatVector& p : points)
{
os.write(++pointId, 8); // 1-index and an unusual width
os.write(p.x());
os.write(p.y());
os.write(p.z());
os.newline();
} }
//- ASCII output. Id + position together return pointId;
static inline label writeMeasured_ascii }
(
ensightFile& os,
label pointId,
const UList<point>& points
)
{
for (const point& p : points)
{
os.write(++pointId, 8); // 1-index and an unusual width
os.write(p.x());
os.write(p.y());
os.write(p.z());
os.newline();
}
return pointId;
}
} // End namespace Foam } // End namespace Foam
@ -77,10 +78,10 @@ namespace Foam
bool Foam::ensightOutput::writeCloudPositions bool Foam::ensightOutput::writeCloudPositions
( (
ensightFile& os,
const fvMesh& mesh, const fvMesh& mesh,
const word& cloudName, const word& cloudName,
bool exists, bool exists
autoPtr<ensightFile>& output
) )
{ {
label nLocalParcels(0); label nLocalParcels(0);
@ -97,7 +98,6 @@ bool Foam::ensightOutput::writeCloudPositions
if (Pstream::master()) if (Pstream::master())
{ {
ensightFile& os = output();
os.beginParticleCoordinates(nTotParcels); os.beginParticleCoordinates(nTotParcels);
} }
@ -111,10 +111,12 @@ bool Foam::ensightOutput::writeCloudPositions
const globalIndex procAddr(nLocalParcels, globalIndex::gatherOnly{}); const globalIndex procAddr(nLocalParcels, globalIndex::gatherOnly{});
DynamicList<point> positions; DynamicList<floatVector> positions;
positions.reserve(Pstream::master() ? procAddr.maxSize() : nLocalParcels); positions.reserve(Pstream::master() ? procAddr.maxSize() : nLocalParcels);
// Extract positions // Extract positions from parcel.
// Store as floatVector, since that is what Ensight will write anyhow
if (parcelsPtr) if (parcelsPtr)
{ {
const auto& parcels = *parcelsPtr; const auto& parcels = *parcelsPtr;
@ -123,10 +125,26 @@ bool Foam::ensightOutput::writeCloudPositions
auto outIter = positions.begin(); auto outIter = positions.begin();
for (const passiveParticle& p : parcels) if (std::is_same<float, vector::cmptType>::value)
{ {
*outIter = p.position(); for (const passiveParticle& p : parcels)
++outIter; {
*outIter = p.position();
++outIter;
}
}
else
{
for (const passiveParticle& p : parcels)
{
vector pos(p.position());
(*outIter).x() = narrowFloat(pos.x());
(*outIter).y() = narrowFloat(pos.y());
(*outIter).z() = narrowFloat(pos.z());
++outIter;
}
} }
parcelsPtr.reset(nullptr); parcelsPtr.reset(nullptr);
@ -134,7 +152,6 @@ bool Foam::ensightOutput::writeCloudPositions
if (Pstream::master()) if (Pstream::master())
{ {
ensightFile& os = output();
const bool isBinaryOutput = (os.format() == IOstreamOption::BINARY); const bool isBinaryOutput = (os.format() == IOstreamOption::BINARY);
label parcelId = 0; label parcelId = 0;
@ -164,35 +181,42 @@ bool Foam::ensightOutput::writeCloudPositions
// Receive and write // Receive and write
for (const label proci : procAddr.subProcs()) for (const label proci : procAddr.subProcs())
{ {
positions.resize_nocopy(procAddr.localSize(proci)); const label procSize = procAddr.localSize(proci);
UIPstream::read
(
UPstream::commsTypes::scheduled,
proci,
positions.data_bytes(),
positions.size_bytes()
);
if (isBinaryOutput) if (procSize)
{ {
writeMeasured_binary(os, positions); positions.resize_nocopy(procSize);
} UIPstream::read
else (
{ UPstream::commsTypes::scheduled,
parcelId = writeMeasured_ascii(os, parcelId, positions); proci,
positions.data_bytes(),
positions.size_bytes()
);
if (isBinaryOutput)
{
writeMeasured_binary(os, positions);
}
else
{
parcelId = writeMeasured_ascii(os, parcelId, positions);
}
} }
} }
} }
else else
{ {
// Send if (positions.size())
UOPstream::write {
( UOPstream::write
UPstream::commsTypes::scheduled, (
UPstream::masterNo(), UPstream::commsTypes::scheduled,
positions.cdata_bytes(), UPstream::masterNo(),
positions.size_bytes() positions.cdata_bytes(),
); positions.size_bytes()
);
}
} }
return true; return true;

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2021 OpenCFD Ltd. Copyright (C) 2016-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -35,11 +35,10 @@ SourceFiles
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef ensightOutputCloud_H #ifndef Foam_ensightOutputCloud_H
#define ensightOutputCloud_H #define Foam_ensightOutputCloud_H
#include "ensightFile.H" #include "ensightFile.H"
#include "autoPtr.H"
#include "IOField.H" #include "IOField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -59,10 +58,17 @@ namespace ensightOutput
//- Write cloud positions //- Write cloud positions
bool writeCloudPositions bool writeCloudPositions
( (
//! Output file (must be valid on master)
ensightFile& os,
//! The associated volume mesh
const fvMesh& mesh, const fvMesh& mesh,
//! The name of the cloud
const word& cloudName, const word& cloudName,
bool exists,
autoPtr<ensightFile>& output //! The processor-local existence
bool exists
); );
@ -70,19 +76,27 @@ bool writeCloudPositions
template<class Type> template<class Type>
bool writeCloudField bool writeCloudField
( (
const IOField<Type>& field, //! Output file (must be valid on master)
ensightFile& os ensightFile& os,
//! The cloud field
const IOField<Type>& field
); );
//- Read cloud field from IOobject (if exists == true) and write, //- Read cloud field from IOobject (if exists == true) and write,
//- always returning true. //- always returning true.
template<class Type> template<class Type>
bool writeCloudField bool readWriteCloudField
( (
const IOobject& io, //! Output file (must be valid on master)
bool exists, ensightFile& os,
autoPtr<ensightFile>& output
//! The field object name/location for reading
const IOobject& fieldObject,
//! Exists anywhere? May still be missing on a local processor
bool existsAny
); );
@ -98,9 +112,13 @@ namespace Detail
template<class Type> template<class Type>
label writeCloudFieldContent label writeCloudFieldContent
( (
//! Output file (must be valid on master)
ensightFile& os, ensightFile& os,
const UList<Type>& fld, const UList<Type>& fld,
label count = 0 //!< The current output count
//! The current output count
label count = 0
); );

View File

@ -69,8 +69,8 @@ Foam::label Foam::ensightOutput::Detail::writeCloudFieldContent
template<class Type> template<class Type>
bool Foam::ensightOutput::writeCloudField bool Foam::ensightOutput::writeCloudField
( (
const IOField<Type>& field, ensightFile& os,
ensightFile& os const IOField<Type>& field
) )
{ {
if (returnReduceAnd(field.empty())) if (returnReduceAnd(field.empty()))
@ -79,7 +79,7 @@ bool Foam::ensightOutput::writeCloudField
} }
// Gather sizes (offsets irrelevant) // Gather sizes (offsets irrelevant)
const globalIndex procAddr(field.size(), globalIndex::gatherOnly{}); const globalIndex procAddr(globalIndex::gatherOnly{}, field.size());
if (Pstream::master()) if (Pstream::master())
{ {
@ -99,21 +99,27 @@ bool Foam::ensightOutput::writeCloudField
for (const label proci : procAddr.subProcs()) for (const label proci : procAddr.subProcs())
{ {
recvData.resize_nocopy(procAddr.localSize(proci)); const label procSize = procAddr.localSize(proci);
UIPstream::read
(
UPstream::commsTypes::scheduled,
proci,
recvData.data_bytes(),
recvData.size_bytes()
);
count = ensightOutput::Detail::writeCloudFieldContent if (procSize)
( {
os, recvData.resize_nocopy(procSize);
recvData,
count UIPstream::read
); (
UPstream::commsTypes::scheduled,
proci,
recvData.data_bytes(),
recvData.size_bytes()
);
count = ensightOutput::Detail::writeCloudFieldContent
(
os,
recvData,
count
);
}
} }
// Add final newline if required // Add final newline if required
@ -124,14 +130,16 @@ bool Foam::ensightOutput::writeCloudField
} }
else else
{ {
// Send if (field.size())
UOPstream::write {
( UOPstream::write
UPstream::commsTypes::scheduled, (
UPstream::masterNo(), UPstream::commsTypes::scheduled,
field.cdata_bytes(), UPstream::masterNo(),
field.size_bytes() field.cdata_bytes(),
); field.size_bytes()
);
}
} }
return true; return true;
@ -139,25 +147,25 @@ bool Foam::ensightOutput::writeCloudField
template<class Type> template<class Type>
bool Foam::ensightOutput::writeCloudField bool Foam::ensightOutput::readWriteCloudField
( (
const IOobject& io, ensightFile& os,
const bool exists, const IOobject& fieldObject,
autoPtr<ensightFile>& output const bool existsAny
) )
{ {
if (exists) if (existsAny)
{ {
// When exists == true, it exists globally, // When exists == true, it exists somewhere globally,
// but can still be missing on the local processor. // but can still be missing on the local processor.
// Handle this by READ_IF_PRESENT instead. // Handle this by READ_IF_PRESENT instead.
IOobject fieldObj(io); IOobject io(fieldObject);
fieldObj.readOpt(IOobject::READ_IF_PRESENT); io.readOpt(IOobject::READ_IF_PRESENT);
IOField<Type> field(fieldObj); IOField<Type> field(io);
writeCloudField(field, output.ref()); writeCloudField(os, field);
} }
return true; return true;

View File

@ -67,14 +67,22 @@ static void writeTrackField
forAll(fieldPtrs, tracki) forAll(fieldPtrs, tracki)
{ {
// Write as point data const Field<Type>& fld = fieldPtrs[tracki];
os.beginPart(tracki); // Part index (0-based) os.beginPart(tracki); // Part index (0-based)
// Skip if empty. This check is probably redundant
if (fld.empty())
{
continue;
}
// Write as coordinates data
ensightOutput::Detail::writeFieldComponents ensightOutput::Detail::writeFieldComponents
( (
os, os,
ensightFile::coordinates, ensightFile::coordinates,
fieldPtrs[tracki], fld,
false /* serial only! */ false /* serial only! */
); );
} }