ENH: improvements to the parallelization of ensightCloud output

- communication mode is now selectable (default is blocking)

- eliminate serial-only version as being redundant
This commit is contained in:
Mark Olesen 2018-10-10 10:32:14 +02:00
parent e4fac35d60
commit 4f2ec88d24
13 changed files with 291 additions and 545 deletions

View File

@ -1,4 +1,3 @@
ensightOutputCloud.C
foamToEnsight.C
EXE = $(FOAM_APPBIN)/foamToEnsight

View File

@ -4,10 +4,10 @@ EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/conversion/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/lagrangian/basic/lnInclude
-I$(LIB_SRC)/lagrangian/intermediate/lnInclude
EXE_LIBS = \
-ldynamicMesh \
-lgenericPatchFields \
-llagrangian \
-llagrangianIntermediate \
-lconversion

View File

@ -1,161 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "ensightOutputCloud.H"
#include "fvMesh.H"
#include "passiveParticle.H"
#include "Cloud.H"
#include "pointList.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
void Foam::ensightCloud::writePositions
(
const fvMesh& mesh,
const word& cloudName,
const bool exists,
autoPtr<ensightFile>& output
)
{
// Total number of parcels on all processes
label nTotParcels = 0;
autoPtr<Cloud<passiveParticle>> cloudPtr;
if (exists)
{
cloudPtr.reset(new Cloud<passiveParticle>(mesh, cloudName, false));
nTotParcels = cloudPtr().size();
}
reduce(nTotParcels, sumOp<label>());
if (Pstream::master())
{
ensightFile& os = output();
os.beginParticleCoordinates(nTotParcels);
if (!nTotParcels)
{
return; // DONE
}
if (os.format() == IOstream::BINARY)
{
// binary write is Ensight6 - first ids, then positions
// 1-index
for (label parcelId = 0; parcelId < nTotParcels; ++parcelId)
{
os.write(parcelId+1);
}
// Master
forAllConstIter(Cloud<passiveParticle>, cloudPtr(), elmnt)
{
const point p(elmnt().position());
os.write(p.x());
os.write(p.y());
os.write(p.z());
}
// Slaves
for (int slave=1; slave<Pstream::nProcs(); ++slave)
{
IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
pointList points(fromSlave);
forAll(points, pti)
{
const point& p = points[pti];
os.write(p.x());
os.write(p.y());
os.write(p.z());
}
}
}
else
{
// ASCII id + position together
label parcelId = 0;
forAllConstIter(Cloud<passiveParticle>, cloudPtr(), elmnt)
{
const point p(elmnt().position());
os.write(++parcelId, 8); // unusual width
os.write(p.x());
os.write(p.y());
os.write(p.z());
os.newline();
}
// Slaves
for (int slave=1; slave<Pstream::nProcs(); ++slave)
{
IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
pointList points(fromSlave);
forAll(points, pti)
{
const point& p = points[pti];
os.write(++parcelId, 8); // unusual width
os.write(p.x());
os.write(p.y());
os.write(p.z());
os.newline();
}
}
}
}
else if (nTotParcels)
{
// SLAVE, and data exist
pointList points(cloudPtr().size());
label pti = 0;
forAllConstIter(Cloud<passiveParticle>, cloudPtr(), elmnt)
{
const point p(elmnt().position());
points[pti++] = p;
}
{
OPstream toMaster
(
Pstream::commsTypes::scheduled,
Pstream::masterNo()
);
toMaster
<< points;
}
}
}
// ************************************************************************* //

View File

@ -1,4 +1,3 @@
ensightOutputSerialCloud.C
foamToEnsightParts.C
EXE = $(FOAM_APPBIN)/foamToEnsightParts

View File

@ -3,11 +3,11 @@ EXE_INC = \
-I$(LIB_SRC)/fileFormats/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/conversion/lnInclude \
-I$(LIB_SRC)/lagrangian/basic/lnInclude
-I$(LIB_SRC)/lagrangian/intermediate/lnInclude
EXE_LIBS = \
-lfiniteVolume \
-llagrangian \
-llagrangianIntermediate \
-lmeshTools \
-lconversion \
-lgenericPatchFields

View File

@ -1,95 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "ensightOutputSerialCloud.H"
#include "ensightPTraits.H"
#include "passiveParticle.H"
#include "IOField.H"
#include "volFields.H"
#include "surfaceFields.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
void Foam::ensightSerialCloud::writePositions
(
const polyMesh& mesh,
const word& cloudName,
autoPtr<ensightFile> output
)
{
label nTotParcels = 0;
autoPtr<Cloud<passiveParticle>> cloudPtr;
cloudPtr.reset(new Cloud<passiveParticle>(mesh, cloudName, false));
nTotParcels = cloudPtr().size();
Cloud<passiveParticle> parcels(mesh, cloudName, false);
if (Pstream::master())
{
ensightFile& os = output();
os.beginParticleCoordinates(nTotParcels);
// binary write is Ensight6 - first ids, then positions
if (os.format() == IOstream::BINARY)
{
// 1-index
for (label parcelId = 0; parcelId < nTotParcels; ++parcelId)
{
os.write(parcelId+1);
}
forAllConstIter(Cloud<passiveParticle>, cloudPtr(), elmnt)
{
const vector p(elmnt().position());
os.write(p.x());
os.write(p.y());
os.write(p.z());
}
}
else
{
// ASCII id + position together
label parcelId = 0;
forAllConstIter(Cloud<passiveParticle>, cloudPtr(), elmnt)
{
const vector p(elmnt().position());
os.write(++parcelId, 8); // unusual width
os.write(p.x());
os.write(p.y());
os.write(p.z());
os.newline();
}
}
}
}
// ************************************************************************* //

View File

@ -1,89 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 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/>.
Description
Miscellaneous collection of functions and template related to Ensight data
SourceFiles
ensightOutputFunctions.C
\*---------------------------------------------------------------------------*/
#ifndef ensightOutputSerialCloud_H
#define ensightOutputSerialCloud_H
#include "ensightFile.H"
#include "Cloud.H"
#include "polyMesh.H"
#include "IOobject.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace ensightSerialCloud
{
//- Write cloud positions
void writePositions
(
const polyMesh& mesh,
const word& cloudName,
autoPtr<ensightFile> output
);
//- Write cloud field
template<class Type>
bool writeCloudField
(
const IOField<Type>& field,
ensightFile& os
);
//- Write cloud field
template<class Type>
bool writeCloudField
(
const IOobject& fieldObject,
autoPtr<ensightFile> output
);
} // End namespace ensightSerialCloud
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "ensightOutputSerialCloudTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,90 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "ensightOutputSerialCloud.H"
#include "ensightSerialOutput.H"
#include "ensightPTraits.H"
#include "passiveParticle.H"
#include "IOField.H"
#include "volFields.H"
#include "surfaceFields.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
template<class Type>
bool Foam::ensightSerialCloud::writeCloudField
(
const IOField<Type>& field,
ensightFile& os
)
{
// 6 values per line
label count = 0;
forAll(field, i)
{
Type val = field[i];
if (mag(val) < 1e-90)
{
val = Zero;
}
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
label cmpt = ensightPTraits<Type>::componentOrder[d];
os.write(component(val, cmpt));
if (++count % 6 == 0)
{
os.newline();
}
}
}
// add final newline if required
if (count % 6)
{
os.newline();
}
return true;
}
template<class Type>
bool Foam::ensightSerialCloud::writeCloudField
(
const IOobject& fieldObject,
autoPtr<ensightFile> output
)
{
IOField<Type> field(fieldObject);
return writeCloudField(field, output.ref());
}
// ************************************************************************* //

View File

@ -79,9 +79,7 @@ Note
#include "ensightGeoFile.H"
#include "ensightParts.H"
#include "ensightSerialOutput.H"
// local files
#include "ensightOutputSerialCloud.H"
#include "ensightOutputCloud.H"
#include "memInfo.H"
@ -398,13 +396,19 @@ int main(int argc, char *argv[])
Info<< "Write " << cloudName << " (" << flush;
ensightSerialCloud::writePositions
(
mesh,
cloudName,
ensCase.newCloud(cloudName)
);
Info<< " positions";
{
auto os = ensCase.newCloud(cloudName);
ensightCloud::writePositions
(
mesh,
cloudName,
cloudExists,
os
);
Info<< " positions";
}
forAllConstIters(theseCloudFields, fieldIter)
@ -425,26 +429,38 @@ int main(int argc, char *argv[])
bool wrote = false;
if (fieldType == scalarIOField::typeName)
{
wrote = ensightSerialCloud::writeCloudField<scalar>
auto os =
ensCase.newCloudData<scalar>(cloudName, fieldName);
wrote = ensightCloud::writeCloudField<scalar>
(
*fieldObject,
ensCase.newCloudData<scalar>(cloudName, fieldName)
true, // field exists
os
);
}
else if (fieldType == vectorIOField::typeName)
{
wrote = ensightSerialCloud::writeCloudField<vector>
auto os =
ensCase.newCloudData<vector>(cloudName, fieldName);
wrote = ensightCloud::writeCloudField<vector>
(
*fieldObject,
ensCase.newCloudData<vector>(cloudName, fieldName)
true, // field exists
os
);
}
else if (fieldType == tensorIOField::typeName)
{
wrote = ensightSerialCloud::writeCloudField<tensor>
auto os =
ensCase.newCloudData<tensor>(cloudName, fieldName);
wrote = ensightCloud::writeCloudField<tensor>
(
*fieldObject,
ensCase.newCloudData<tensor>(cloudName, fieldName)
true, // field exists
os
);
}

View File

@ -119,6 +119,7 @@ clouds/Templates/KinematicCloud/cloudSolution/cloudSolution.C
submodels/MPPIC/AveragingMethods/makeAveragingMethods.C
/* conversion methods */
conversion/ensight/ensightOutputCloud.C
conversion/vtk/foamVtkLagrangianWriter.C

View File

@ -0,0 +1,172 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016-2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "ensightOutputCloud.H"
#include "fvMesh.H"
#include "Cloud.H"
#include "passiveParticle.H"
#include "pointField.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
//- Binary output
static inline void writeMeasured
(
ensightFile& os,
const pointField& points
)
{
for (const point& p : points)
{
os.write(p.x());
os.write(p.y());
os.write(p.z());
}
}
//- ASCII output. Id + position together
static inline label writeMeasured
(
ensightFile& os,
label pointId,
const pointField& 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
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
bool Foam::ensightCloud::writePositions
(
const fvMesh& mesh,
const word& cloudName,
bool exists,
autoPtr<ensightFile>& output,
Pstream::commsTypes comm
)
{
pointField positions;
if (exists)
{
Cloud<passiveParticle> parcels(mesh, cloudName, false);
positions.resize(parcels.size());
auto outIter = positions.begin();
forAllConstIters(parcels, iter)
{
*outIter = iter().position();
++outIter;
}
}
// Total number of parcels on all processes
const label nTotParcels = returnReduce(positions.size(), sumOp<label>());
// Update the exists/not exists information (for return value)
exists = nTotParcels;
if (Pstream::master())
{
ensightFile& os = output();
os.beginParticleCoordinates(nTotParcels);
if (!exists)
{
return exists; // DONE
}
if (os.format() == IOstream::BINARY)
{
// binary write is Ensight6 - first ids, then positions
// 1-index
for (label parcelId = 1; parcelId <= nTotParcels; ++parcelId)
{
os.write(parcelId);
}
// Master
writeMeasured(os, positions);
// Slaves
for (int slave=1; slave<Pstream::nProcs(); ++slave)
{
IPstream fromSlave(comm, slave);
pointField recv(fromSlave);
writeMeasured(os, recv);
}
}
else
{
// ASCII id + position together
label parcelId = 0;
// Master
parcelId = writeMeasured(os, parcelId, positions);
// Slaves
for (int slave=1; slave<Pstream::nProcs(); ++slave)
{
IPstream fromSlave(comm, slave);
pointField recv(fromSlave);
parcelId = writeMeasured(os, parcelId, recv);
}
}
}
else if (nTotParcels)
{
// SLAVE, and data exist
OPstream toMaster(comm, Pstream::masterNo());
toMaster
<< positions;
}
return exists;
}
// ************************************************************************* //

View File

@ -2,8 +2,8 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -22,10 +22,11 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Namespace
Foam::ensightOutput
Foam::ensightCloud
Description
A collection of global functions for writing ensight file content.
A collection of global functions for writing clouds as
ensight file content.
SourceFiles
ensightOutputCloud.C
@ -37,27 +38,27 @@ SourceFiles
#define ensightOutputCloud_H
#include "ensightFile.H"
#include "ensightMesh.H"
#include "autoPtr.H"
#include "IOField.H"
#include "volFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declarations
class fvMesh;
namespace ensightCloud
{
//- Write cloud positions
void writePositions
bool writePositions
(
const fvMesh& mesh,
const word& cloudName,
const bool exists,
autoPtr<ensightFile>& output
bool exists,
autoPtr<ensightFile>& output,
Pstream::commsTypes comm = Pstream::commsTypes::blocking
);
@ -66,17 +67,20 @@ template<class Type>
bool writeCloudField
(
const IOField<Type>& field,
ensightFile& os
ensightFile& os,
Pstream::commsTypes comm = Pstream::commsTypes::blocking
);
//- Write cloud field from IOobject, always returning true.
//- Read cloud field from IOobject (if exists == true) and write,
//- always returning true.
template<class Type>
bool writeCloudField
(
IOobject& fieldObject,
const bool exists,
autoPtr<ensightFile>& output
const IOobject& io,
bool exists,
autoPtr<ensightFile>& output,
Pstream::commsTypes comm = Pstream::commsTypes::blocking
);

View File

@ -2,8 +2,8 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,42 +26,66 @@ License
#include "ensightOutputCloud.H"
#include "ensightPTraits.H"
#include "IOField.H"
#include "Time.H"
#include "globalIndex.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
template<class Type>
bool Foam::ensightCloud::writeCloudField
(
const IOField<Type>& field,
ensightFile& os
ensightFile& os,
Pstream::commsTypes comm
)
{
const bool exists = (returnReduce(field.size(), sumOp<label>()) > 0);
if (exists)
if (returnReduce(field.empty(), andOp<bool>()))
{
if (Pstream::master())
return false;
}
if (Pstream::master())
{
// 6 values per line
label count = 0;
// Master
for (Type val : field) // <-- working on a copy
{
// 6 values per line
label count = 0;
// Master
forAll(field, i)
if (mag(val) < 1e-90) // approximately root(ROOTVSMALL)
{
Type val = field[i];
val = Zero;
}
if (mag(val) < 1e-90)
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
const direction cmpt =
ensightPTraits<Type>::componentOrder[d];
os.write(component(val, cmpt));
if (++count % 6 == 0)
{
os.newline();
}
}
}
// Slaves
for (int slave=1; slave<Pstream::nProcs(); ++slave)
{
IPstream fromSlave(comm, slave);
Field<Type> recv(fromSlave);
for (Type val : field) // <-- working on a copy
{
if (mag(val) < 1e-90) // approximately root(ROOTVSMALL)
{
val = Zero;
}
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
label cmpt = ensightPTraits<Type>::componentOrder[d];
const direction cmpt =
ensightPTraits<Type>::componentOrder[d];
os.write(component(val, cmpt));
if (++count % 6 == 0)
@ -70,79 +94,45 @@ bool Foam::ensightCloud::writeCloudField
}
}
}
// Slaves
for (int slave=1; slave<Pstream::nProcs(); ++slave)
{
IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
Field<Type> slaveData(fromSlave);
forAll(slaveData, i)
{
Type val = slaveData[i];
if (mag(val) < 1e-90)
{
val = Zero;
}
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
label cmpt = ensightPTraits<Type>::componentOrder[d];
os.write(component(val, cmpt));
if (++count % 6 == 0)
{
os.newline();
}
}
}
}
// add final newline if required
if (count % 6)
{
os.newline();
}
}
else
{
OPstream toMaster
(
Pstream::commsTypes::scheduled,
Pstream::masterNo()
);
toMaster
<< field;
// Add final newline if required
if (count % 6)
{
os.newline();
}
}
else
{
OPstream toMaster(comm, Pstream::masterNo());
toMaster << field;
}
return exists;
return true;
}
template<class Type>
bool Foam::ensightCloud::writeCloudField
(
IOobject& fieldObject,
const IOobject& io,
const bool exists,
autoPtr<ensightFile>& output
autoPtr<ensightFile>& output,
Pstream::commsTypes comm
)
{
if (exists)
{
// when exists == true, it exists globally,
// When exists == true, it exists globally,
// but can still be missing on the local processor.
// Handle this by READ_IF_PRESENT instead.
const IOobject::readOption rOpt = fieldObject.readOpt();
fieldObject.readOpt() = IOobject::READ_IF_PRESENT;
IOobject fieldObj(io);
fieldObj.readOpt() = IOobject::READ_IF_PRESENT;
IOField<Type> field(fieldObject);
fieldObject.readOpt() = rOpt;
IOField<Type> field(fieldObj);
writeCloudField(field, output.ref());
writeCloudField(field, output.ref(), comm);
}
return true;