Commit d13c6849 authored by mark's avatar mark

ENH: improved handling of mesh/topology changes on output

parent 0856fed3
......@@ -8,6 +8,7 @@ adiosCoreWriteField.C
adiosReader.C
adiosReaderCloudInfo.C
adiosReaderField.C
adiosReaderVarInfo.C
lagrangian/ParcelEncoding.C
......
......@@ -59,7 +59,7 @@ const Foam::word
Foam::adiosCore::dataDirectory("adiosData");
const Foam::word
Foam::adiosCore::fileExt("bp");
Foam::adiosCore::fileExt("ofbp");
const Foam::string
Foam::adiosCore::foamAttribute = "/openfoam";
......
......@@ -207,6 +207,14 @@ public:
return regionPath(regionName) / "cloud" / cloudName;
}
//- Buffer for reading/writing (streamed) content to/from ADIOS files.
// Also used when reading/writing dissimilar content.
inline static DynamicCharList& transferBuffer()
{
return transfer_;
}
};
......
......@@ -71,6 +71,8 @@ Foam::adiosCoreWrite::adiosCoreWrite
comm_(MPI_COMM_NULL),
vars_()
{
Info<< "adiosWrite (" << Pstream::nProcs() << " procs)" << endl;
MPI_Comm_dup(MPI_COMM_WORLD, &comm_);
// Initialize ADIOS
......
......@@ -31,34 +31,38 @@ License
void Foam::adiosCoreWrite::definePatchAttributes(const polyMesh& mesh)
{
const polyPatchList& patches = mesh.boundaryMesh();
stringList pNames(patches.size());
stringList pTypes(patches.size());
label nPatches = 0;
forAll(patches, patchI)
if (Pstream::master())
{
const polyPatch& p = patches[patchI];
// Only count 'real' (non-processor patches)
if (isA<processorPolyPatch>(p))
// Attributes are global - only passed via the master
const polyPatchList& patches = mesh.boundaryMesh();
stringList pNames(patches.size());
stringList pTypes(patches.size());
label nPatches = 0;
forAll(patches, patchI)
{
break;
}
const polyPatch& p = patches[patchI];
// Only count 'real' (non-processor patches)
if (isA<processorPolyPatch>(p))
{
break;
}
pNames[patchI] = p.name();
pTypes[patchI] = p.type();
pNames[patchI] = p.name();
pTypes[patchI] = p.type();
++nPatches;
}
++nPatches;
}
pNames.setSize(nPatches);
pTypes.setSize(nPatches);
pNames.setSize(nPatches);
pTypes.setSize(nPatches);
const fileName varPath = adiosCore::regionPath(mesh.name());
const fileName varPath = adiosCore::regionPath(mesh.name());
defineIntAttribute("nPatches", varPath, nPatches);
defineListAttribute("patch-names", varPath, pNames);
defineListAttribute("patch-types", varPath, pTypes);
defineIntAttribute("nPatches", varPath, nPatches);
defineListAttribute("patch-names", varPath, pNames);
defineListAttribute("patch-types", varPath, pTypes);
}
}
......@@ -120,14 +124,14 @@ void Foam::adiosCoreWrite::writeMeshFaces(const polyMesh& mesh)
// this is not particularly elegant, but should be stable
List<label> start(nFaces+1);
// // use transfer_ to avoid reallocations
// Use transfer buffer to avoid reallocations
// UList<label> start
// (
// reinterpret_cast<label*>(transfer_.data()),
// transfer_.capacity() / sizeof(label)
// reinterpret_cast<label*>(transferBuffer().data()),
// transferBuffer().capacity() / sizeof(label)
// );
// use transfer_ to avoid reallocations
// Use transfer buffer to avoid reallocations
// Pout<< "indices " << start.size() << endl;
// calculate start as per CompactIOList.C:
......@@ -153,11 +157,11 @@ void Foam::adiosCoreWrite::writeMeshFaces(const polyMesh& mesh)
// this is not particularly elegant, but should be stable
List<label> elems(start[start.size()-1]);
// use transfer_ to avoid reallocations
// Use transfer buffer to avoid reallocations
// UList<label> elems
// (
// reinterpret_cast<label*>(transfer_.data()),
// transfer_.capacity() / sizeof(label)
// reinterpret_cast<label*>(transferBuffer().data()),
// transferBuffer().capacity() / sizeof(label)
// );
// Pout<< "size: " << elems.size() << endl;
......
......@@ -74,24 +74,20 @@ int64_t Foam::adiosCoreWrite::writeStreamVariable
const Type& obj
)
{
if (varName.name() == "boundary")
{
Info<< "have: " << varName << " => " << obj << endl;
}
OutputCounter counter(adiosCore::strFormat);
counter << obj;
int64_t varid = defineStreamVariable(varName, counter.size());
// Use transfer_ to avoid too many reallocations - needs some rework?
transfer_.reserve(adios_expected_var_size(varid));
// Use transfer buffer to avoid too many reallocations
// - Needs some rework to cleanup or for byte-alignment?
transferBuffer().reserve(adios_expected_var_size(varid));
OutputBufStreamer os(transfer_, adiosCore::strFormat);
OutputBufStreamer os(transferBuffer(), adiosCore::strFormat);
os << obj;
// Do the actual write (as stream)
writeVariable(varName, transfer_);
writeVariable(varName, transferBuffer());
return varid;
}
......@@ -126,7 +122,6 @@ int64_t Foam::adiosCoreWrite::writeGeometricField
// "internalField" as primitive field
const int64_t varid = writeField(varName, field.internalField());
// Independent of storage, provide a quick lookup of field patch types
if (Pstream::master())
{
......@@ -154,10 +149,16 @@ int64_t Foam::adiosCoreWrite::writeGeometricField
}
// "boundaryField" as byte stream, but need adapter for dictionary format
BoundaryWriter<Type, PatchField, GeoMesh> adapter(bfield);
writeStreamVariable(varName/"boundaryField", adapter);
// Also write the corresponding "_0" field if it exists
if (field.nOldTimes() > 1)
{
writeGeometricField(field.oldTime());
}
return varid;
}
......
......@@ -233,15 +233,19 @@ Foam::adiosReader::getFieldInfo(const word& regName) const
HashTable<fieldInfo> table;
bool hasAux = false;
forAllConstIter(VarContainer, variables, iter)
{
const fileName& varName = iter.key();
const VarInfo& varInfo = iter();
if (varName.count('/') == 2 && varName.path() == startsWith)
if
(
varName.count('/') == 2 && varName.path() == startsWith
// Ignore "_0" fields, they are addressed separately
&& varName(varName.size()-2, 2) != "_0"
)
{
// matches regName/field/xxx
// matches regName/field/xxx, but not regName/field/xxx_0
table.insert
(
......@@ -254,46 +258,6 @@ Foam::adiosReader::getFieldInfo(const word& regName) const
)
);
}
if (varName.count('/') == 3)
{
hasAux = true;
}
}
// This could be somewhat more efficient, but then it would be less general
if (hasAux)
{
forAllConstIter(VarContainer, variables, iter)
{
const fileName& varName = iter.key();
const VarInfo& varInfo = iter();
if (varName.count('/') == 3)
{
const word& parent = varName.path().name();
if (table.found(parent))
{
// matches regName/field/xxx/yyy
table[parent].aux().insert
(
varName.name(),
fieldInfo
(
varName,
varInfo.sizeOf(),
word::null // only parent has this information
)
);
}
else
{
// WARNING?
}
}
}
}
// Info<<"Table ";
......@@ -900,4 +864,13 @@ bool Foam::adiosReader::getVariable
}
size_t Foam::adiosReader::getBuffered
(
const string& name
) const
{
return getBuffered(name, adiosCore::transferBuffer());
}
// ************************************************************************* //
......@@ -34,15 +34,18 @@ SourceFiles
#ifndef adiosReader_H
#define adiosReader_H
#include "adiosCore.H"
#include "adiosTime.H"
#include "fileName.H"
#include "fvMesh.H"
#include "IBufStream.H"
#include "DynamicCharList.H"
#include "regIOobject.H"
#include "HashTable.H"
#include "Ostream.H"
#include "adios.h"
#include "adios_read.h"
#include "adiosTime.H"
#include "ParcelEncoding.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -94,6 +97,15 @@ private:
void select(ADIOS_SELECTION *sel);
template<class Type, class SourceType>
label copyList
(
UList<Type>& dst,
const fileName& varName
) const;
//- Disallow default bitwise copy construct
adiosReader(const adiosReader&) = delete;
......@@ -241,11 +253,53 @@ public:
bool getVariable(const string& varName, void* data) const;
//- Retrieve the variable into our buffer area
//- Retrieve variable into buffer, using the common adiosCore buffer.
// On success the buffer is resized according to the data.
// On failure the buffer is resized to zero.
size_t getBuffered(const string& varName) const;
//- Retrieve variable into buffer.
// On success the buffer is resized according to the data.
// On failure the buffer is resized to zero.
template<class T>
size_t getBuffered(const string& varName, DynamicList<T>& buffer) const;
size_t getBuffered
(
const string& varName,
DynamicList<T>& buffer
) const;
// Functions for reading (fields, clouds)
//- Read data for a given volume field type.
// Return the number of elements read.
label readFieldObject
(
regIOobject& obj,
const fieldInfo& src
) const;
//- Read GeometricField.
// Read internalField directly, boundaryField as a byte-stream
// Return the number of elements read.
template<class Type, template<class> class PatchField, class GeoMesh>
label readGeometricField
(
GeometricField<Type, PatchField, GeoMesh>& field,
const fileName& varName
) const;
//- Read a dimensioned field (eg, internalField) directly.
// Return the number of elements read.
template<class Type, class GeoMesh>
label readField
(
DimensionedField<Type, GeoMesh>& field,
const fileName& varName
) const;
};
......@@ -319,9 +373,6 @@ class adiosReader::fieldInfo
word className_;
size_t nBytes_;
//- Can also contain auxiliary field information (eg, field/U/boundaryField)
HashTable<fieldInfo> aux_;
public:
......@@ -341,8 +392,7 @@ public:
:
fileName(varName),
className_(className),
nBytes_(nbytes),
aux_()
nBytes_(nbytes)
{}
......@@ -380,19 +430,6 @@ public:
}
inline HashTable<fieldInfo>& aux()
{
return aux_;
}
inline const HashTable<fieldInfo>& aux() const
{
return aux_;
}
//- Output some information
Ostream& info(Ostream& os) const
{
......@@ -405,11 +442,6 @@ public:
}
os.writeEntry("sizeof", nBytes_);
forAllConstIter(HashTable<fieldInfo>, aux_, iter)
{
iter().info(os);
}
os.endBlock();
return os;
......
......@@ -2,8 +2,8 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright(C) 2015 Norbert Podhorszki
\\/ M anipulation | Copyright(C) 2016 OpenCFD Ltd.
\\ / A nd | Copyright(C) 2016 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -23,7 +23,6 @@ License
\*---------------------------------------------------------------------------*/
#include "adiosWrite.H"
#include "adiosReader.H"
#include "emptyFvPatchField.H"
......@@ -34,12 +33,11 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::adiosWrite::readFieldObject
Foam::label Foam::adiosReader::readFieldObject
(
regIOobject& obj,
const adiosReader& reader,
const adiosReader::fieldInfo& src
)
const fieldInfo& src
) const
{
const word& fieldType = obj.type();
const word& srcType = src.type();
......@@ -61,7 +59,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<pointScalarField&>(obj),
reader, src
src
);
}
else if (fieldType == pointVectorField::typeName)
......@@ -69,7 +67,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<pointVectorField&>(obj),
reader, src
src
);
}
else if (fieldType == pointSphericalTensorField::typeName)
......@@ -77,7 +75,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<pointSphericalTensorField&>(obj),
reader, src
src
);
}
else if (fieldType == pointSymmTensorField::typeName)
......@@ -85,7 +83,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<pointSymmTensorField&>(obj),
reader, src
src
);
}
else if (fieldType == pointTensorField::typeName)
......@@ -93,7 +91,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<pointTensorField&>(obj),
reader, src
src
);
}
......@@ -103,7 +101,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<surfaceScalarField&>(obj),
reader, src
src
);
}
else if (fieldType == surfaceVectorField::typeName)
......@@ -111,7 +109,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<surfaceVectorField&>(obj),
reader, src
src
);
}
else if (fieldType == surfaceSphericalTensorField::typeName)
......@@ -119,7 +117,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<surfaceSphericalTensorField&>(obj),
reader, src
src
);
}
else if (fieldType == surfaceSymmTensorField::typeName)
......@@ -127,7 +125,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<surfaceSymmTensorField&>(obj),
reader, src
src
);
}
else if (fieldType == surfaceTensorField::typeName)
......@@ -135,7 +133,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<surfaceTensorField&>(obj),
reader, src
src
);
}
......@@ -145,7 +143,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<volScalarField&>(obj),
reader, src
src
);
}
else if (fieldType == volVectorField::typeName)
......@@ -153,7 +151,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<volVectorField&>(obj),
reader, src
src
);
}
else if (fieldType == volSphericalTensorField::typeName)
......@@ -161,7 +159,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<volSphericalTensorField&>(obj),
reader, src
src
);
}
else if (fieldType == volSymmTensorField::typeName)
......@@ -169,7 +167,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<volSymmTensorField&>(obj),
reader, src
src
);
}
else if (fieldType == volTensorField::typeName)
......@@ -177,10 +175,9 @@ Foam::label Foam::adiosWrite::readFieldObject
return readGeometricField
(
static_cast<volTensorField&>(obj),
reader, src
src
);
}
// TODO: internal volume fields
// Internal volume fields
else if (fieldType == volScalarField::Internal::typeName)
......@@ -188,7 +185,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readField
(
static_cast<volScalarField::Internal&>(obj),
reader, src
src
);
}
else if (fieldType == volVectorField::Internal::typeName)
......@@ -196,7 +193,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readField
(
static_cast<volVectorField::Internal&>(obj),
reader, src
src
);
}
else if (fieldType == volSphericalTensorField::Internal::typeName)
......@@ -204,7 +201,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readField
(
static_cast<volSphericalTensorField::Internal&>(obj),
reader, src
src
);
}
else if (fieldType == volSymmTensorField::Internal::typeName)
......@@ -212,7 +209,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readField
(
static_cast<volSymmTensorField::Internal&>(obj),
reader, src
src
);
}
else if (fieldType == volTensorField::Internal::typeName)
......@@ -220,7 +217,7 @@ Foam::label Foam::adiosWrite::readFieldObject
return readField
(
static_cast<volTensorField::Internal&>(obj),
reader, src
src
);
}
......
......@@ -23,6 +23,7 @@ License
\*---------------------------------------------------------------------------*/
#include "adiosCore.H"
#include "adiosReader.H"
#include "error.H"
#include "CStringList.H"
......@@ -31,49 +32,56 @@ License
#include "adios_read.h"
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * * //
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class T>
size_t Foam::adiosReader::getBuffered
template<class Type, class SourceType>
Foam::label Foam::adiosReader::copyList
(
const string& name,
DynamicList<T>& buffer
UList<Type>& dst,
const fileName& varName
) const
{
size_t nbytes = 0;
DynamicCharList& buffer = adiosCore::transferBuffer();
label sizeRead = -1;
if (hasVariable(name))
if (hasVariable(varName))
{
const VarInfo& vinfo = variables[name];
nbytes = vinfo.sizeOf();
size_t nread = getBuffered(varName, buffer);
sizeRead = (nread / sizeof(SourceType) / pTraits<Type>::nComponents);
const size_t sizeT = sizeof(T);
const size_t target = (nbytes / sizeT) + (nbytes % sizeT);
// TODO? check sizes
buffer.reserve(nbytes / sizeT + nbytes % sizeT);
UList<SourceType> src
(
reinterpret_cast<SourceType*>(buffer.data()),
sizeRead
);
if (getVariable(name, buffer.data()))
// Component-wise copy
label srcindex = 0;
forAll(dst, i)
{
buffer.setSize(target);
}
else
{
buffer.setSize(0);
nbytes = 0;
for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; ++cmpt)
{
setComponent(dst[i], cmpt) = src[srcindex++];
}
}
}
if (!nbytes)
// Fatal
if (sizeRead < 0)
{
FatalErrorInFunction
<< "missing adios variable: " << name
<< "missing adios variable: " << varName << endl
<< exit(FatalIOError);
}
return nbytes;
return sizeRead;
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * * //
template<class StringType>
bool Foam::adiosReader::readStringListAttributeIfPresent
(
......@@ -133,4 +141,179 @@ bool Foam::adiosReader::readStringListAttributeIfPresent
}
template<class bufferT>
size_t Foam::adiosReader::getBuffered
(
const string& name,
DynamicList<bufferT>& buffer
) const
{
size_t nbytes = 0;
if (hasVariable(name))
{
const VarInfo& vinfo = variables[name];
nbytes = vinfo.sizeOf();
const size_t sizeT = sizeof(bufferT);
const size_t target = (nbytes / sizeT) + (nbytes % sizeT);
buffer.reserve(nbytes / sizeT + nbytes % sizeT);
if (getVariable(name, buffer.data()))
{
buffer.setSize(target);
}
else
{
buffer.setSize(0);
nbytes = 0;
}
}
if