Newer
Older
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\/ M anipulation |
-------------------------------------------------------------------------------

Konstantinos Missios
committed
Copyright (C) 2016-2023 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 "regionSizeDistribution.H"
#include "regionSplit.H"
#include "volFields.H"
#include "fvcVolumeIntegrate.H"

Konstantinos Missios
committed
#include "mathematicalConstants.H"
#include "addToRunTimeSelectionTable.H"

Konstantinos Missios
committed
using namespace Foam::constant;
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
Henry Weller
committed
namespace functionObjects
{
defineTypeNameAndDebug(regionSizeDistribution, 0);
addToRunTimeSelectionTable
(
functionObject,
regionSizeDistribution,
dictionary
);
Henry Weller
committed
}
}
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
{
template<class Type>
static Map<Type> regionSum(const regionSplit& regions, const Field<Type>& fld)
{
// Per region the sum of fld
Map<Type> regionToSum(regions.nRegions()/Pstream::nProcs());
forAll(fld, celli)
{
const label regioni = regions[celli];
regionToSum(regioni, Type(Zero)) += fld[celli];
}
Pstream::mapCombineReduce(regionToSum, plusEqOp<Type>());
template<class Type>
static List<Type> extractData(const labelUList& keys, const Map<Type>& regionData)
{
List<Type> sortedData(keys.size());
forAll(keys, i)
{
sortedData[i] = regionData[keys[i]];
}
return sortedData;
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Henry Weller
committed
void Foam::functionObjects::regionSizeDistribution::writeAlphaFields
(
const regionSplit& regions,
const Map<label>& patchRegions,
const Map<scalar>& regionVolume,
const volScalarField& alpha
) const
{

Konstantinos Missios
committed
const scalar maxDropletVol = 1.0/6.0*mathematical::pi*pow3(maxDiam_);
// Split alpha field
// ~~~~~~~~~~~~~~~~~
// Split into
// - liquidCore : region connected to inlet patches
// - per region a volume : for all other regions
// - backgroundAlpha : remaining alpha
// Construct field
volScalarField liquidCore
(
IOobject
(
scopedName(alphaName_ + "_liquidCore"),
obr_.time().timeName(),
obr_,
IOobject::NO_READ
),
alpha,
fvPatchFieldBase::calculatedType()
);
volScalarField backgroundAlpha
(
IOobject
(
scopedName(alphaName_ + "_background"),
obr_.time().timeName(),
obr_,
IOobject::NO_READ
),
alpha,
fvPatchFieldBase::calculatedType()
);
// Knock out any cell not in patchRegions
forAll(liquidCore, celli)
const label regioni = regions[celli];
backgroundAlpha[celli] = 0;
}
else
{
liquidCore[celli] = 0;
const scalar regionVol = regionVolume[regioni];
if (regionVol < maxDropletVol)
{
backgroundAlpha[celli] = 0;
}
}
}
liquidCore.correctBoundaryConditions();
backgroundAlpha.correctBoundaryConditions();
if (log)
{
Info<< " Volume of liquid-core = "
<< fvc::domainIntegrate(liquidCore).value()
<< nl
<< " Volume of background = "
<< fvc::domainIntegrate(backgroundAlpha).value()
<< endl;
}
Log << " Writing liquid-core field to " << liquidCore.name() << endl;
liquidCore.write();
Log<< " Writing background field to " << backgroundAlpha.name() << endl;
backgroundAlpha.write();
}
Henry Weller
committed
Foam::Map<Foam::label>
Foam::functionObjects::regionSizeDistribution::findPatchRegions
(
const regionSplit& regions
) const
{
// Mark all regions starting at patches
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Count number of patch faces (just for initial sizing)
const labelHashSet patchIDs(mesh_.boundaryMesh().patchSet(patchNames_));
label nPatchFaces = 0;
for (const label patchi : patchIDs)
nPatchFaces += mesh_.boundaryMesh()[patchi].size();
}
Map<label> patchRegions(nPatchFaces);
for (const label patchi : patchIDs)
const polyPatch& pp = mesh_.boundaryMesh()[patchi];
// Collect all regions on the patch
const labelList& faceCells = pp.faceCells();
for (const label celli : faceCells)
{
patchRegions.insert
(
Pstream::myProcNo() // dummy value
);
}
}
// Make sure all the processors have the same set of regions
Pstream::mapCombineReduce(patchRegions, minEqOp<label>());
return patchRegions;
}
Henry Weller
committed
Foam::tmp<Foam::scalarField>
Foam::functionObjects::regionSizeDistribution::divide
(
const scalarField& num,
const scalarField& denom
)
{
auto tresult = tmp<scalarField>::New(num.size());
auto& result = tresult.ref();
forAll(denom, i)
{
if (denom[i] != 0)
{
result[i] = num[i]/denom[i];
}
else
{
}
}
return tresult;
}
Henry Weller
committed
void Foam::functionObjects::regionSizeDistribution::writeGraphs
(
const word& fieldName, // name of field
const scalarField& sortedField, // per region field data
const labelList& indices, // index of bin for each region
const scalarField& binCount, // per bin number of regions
const coordSet& coords // graph data for bins
) const
{
if (Pstream::master())
{
// Calculate per-bin average
scalarField binSum(nBins_, Zero);
forAll(sortedField, i)
{
binSum[indices[i]] += sortedField[i];
}
scalarField binAvg(divide(binSum, binCount));
// Per bin deviation
scalarField binSqrSum(nBins_, Zero);
forAll(sortedField, i)
{
binSqrSum[indices[i]] += Foam::sqr(sortedField[i]);
}
scalarField binDev
(
sqrt(divide(binSqrSum, binCount) - Foam::sqr(binAvg))
);
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
auto& writer = formatterPtr_();
word outputName;
if (writer.buffering())
{
outputName =
(
coords.name()
+ coordSetWriter::suffix
(
wordList
({
fieldName + "_sum",
fieldName + "_avg",
fieldName + "_dev"
})
)
);
}
else
{
outputName = coords.name();
}
writer.open
(
coords,
(baseTimeDir() / outputName)
);
Log << " Writing distribution of "
<< fieldName << " to " << writer.path() << endl;
writer.write(fieldName + "_sum", binSum);
writer.write(fieldName + "_avg", binAvg);
writer.write(fieldName + "_dev", binDev);
writer.close(true);
}
}
Henry Weller
committed
void Foam::functionObjects::regionSizeDistribution::writeGraphs
(
const word& fieldName, // name of field
const scalarField& cellField, // per cell field data
const regionSplit& regions, // per cell the region(=droplet)
const labelList& sortedRegions, // valid regions in sorted order
const scalarField& sortedNormalisation,
const labelList& indices, // per region index of bin
const scalarField& binCount, // per bin number of regions
const coordSet& coords // graph data for bins
) const
{
// Sum on a per-region basis. Parallel reduced.
Map<scalar> regionField(regionSum(regions, cellField));
// Extract in region order
scalarField sortedField
(
sortedNormalisation
* extractData(sortedRegions, regionField)
);
writeGraphs
(
fieldName, // name of field
sortedField, // per region field data
indices, // index of bin for each region
binCount, // per bin number of regions
coords // graph data for bins
);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Henry Weller
committed
Foam::functionObjects::regionSizeDistribution::regionSizeDistribution
(
const word& name,
const Time& runTime,
const dictionary& dict
)
:
fvMeshFunctionObject(name, runTime, dict),
writeFile(obr_, name),
alphaName_(dict.get<word>("field")),
patchNames_(dict.get<wordRes>("patches")),
isoPlanes_(dict.getOrDefault("isoPlanes", false))
{
read(dict);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionObjects::regionSizeDistribution::read(const dictionary& dict)
{
fvMeshFunctionObject::read(dict);
Andrew Heather
committed
writeFile::read(dict);
dict.readEntry("nBins", nBins_);
dict.readEntry("field", alphaName_);
dict.readEntry("threshold", threshold_);
dict.readEntry("maxDiameter", maxDiam_);
Henry Weller
committed
minDiam_ = 0.0;
dict.readIfPresent("minDiameter", minDiam_);
dict.readEntry("patches", patchNames_);
dict.readEntry("fields", fields_);
Henry Weller
committed
const word setFormat(dict.get<word>("setFormat"));
formatterPtr_ = coordSetWriter::New
(
setFormat,
dict.subOrEmptyDict("formatOptions").optionalSubDict(setFormat)
);
Henry Weller
committed
csysPtr_ = coordinateSystem::NewIfPresent(obr_, dict);
Andrew Heather
committed
Info<< "Transforming all vectorFields with coordinate system "
<< csysPtr_->name() << endl;
}
dict.readEntry("origin", origin_);
dict.readEntry("direction", direction_);
dict.readEntry("maxD", maxDiameter_);
dict.readEntry("nDownstreamBins", nDownstreamBins_);
dict.readEntry("maxDownstream", maxDownstream_);
direction_.normalise();
return true;
}
bool Foam::functionObjects::regionSizeDistribution::execute()
{
return true;
}
bool Foam::functionObjects::regionSizeDistribution::write()
{
Log << type() << " " << name() << " write:" << nl;
tmp<volScalarField> talpha;
talpha.cref(obr_.cfindObject<volScalarField>(alphaName_));
if (talpha)
Henry Weller
committed
{
Log << " Looking up field " << alphaName_ << endl;
Henry Weller
committed
}
else
{
Info<< " Reading field " << alphaName_ << endl;
Henry Weller
committed
(
new volScalarField
(
Henry Weller
committed
IOobject
(
Henry Weller
committed
alphaName_,
mesh_.time().timeName(),
mesh_,
Henry Weller
committed
IOobject::MUST_READ,
IOobject::NO_WRITE
),
mesh_
Henry Weller
committed
)
);
}
Log << " Volume of alpha = "
Henry Weller
committed
<< fvc::domainIntegrate(alpha).value()
<< endl;
const scalar meshVol = gSum(mesh_.V());

Konstantinos Missios
committed
const scalar maxDropletVol = 1.0/6.0*mathematical::pi*pow3(maxDiam_);
Henry Weller
committed
const scalar delta = (maxDiam_-minDiam_)/nBins_;
Log << " Mesh volume = " << meshVol << nl
<< " Maximum droplet diameter = " << maxDiam_ << nl
<< " Maximum droplet volume = " << maxDropletVol
<< endl;
Henry Weller
committed
// Determine blocked faces
boolList blockedFace(mesh_.nFaces(), false);
// label nBlocked = 0;
Henry Weller
committed
{
for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
{
scalar ownVal = alpha[mesh_.faceOwner()[facei]];
scalar neiVal = alpha[mesh_.faceNeighbour()[facei]];
Henry Weller
committed
if
(
(ownVal < threshold_ && neiVal > threshold_)
|| (ownVal > threshold_ && neiVal < threshold_)
)
{
blockedFace[facei] = true;
// ++nBlocked;
}
Henry Weller
committed
}
Henry Weller
committed
// Block coupled faces
forAll(alpha.boundaryField(), patchi)
{
const fvPatchScalarField& fvp = alpha.boundaryField()[patchi];
if (fvp.coupled())
{
Henry Weller
committed
tmp<scalarField> townFld(fvp.patchInternalField());
tmp<scalarField> tnbrFld(fvp.patchNeighbourField());
const auto& ownFld = townFld();
const auto& nbrFld = tnbrFld();
Henry Weller
committed
label start = fvp.patch().patch().start();
Henry Weller
committed
forAll(ownFld, i)
{
scalar ownVal = ownFld[i];
scalar neiVal = nbrFld[i];
Henry Weller
committed
if
(
(ownVal < threshold_ && neiVal > threshold_)
|| (ownVal > threshold_ && neiVal < threshold_)
)
{
Henry Weller
committed
blockedFace[start+i] = true;
// ++nBlocked;
}
}
}
}
Henry Weller
committed
}
regionSplit regions(mesh_, blockedFace);
Log << " Determined " << regions.nRegions()
Henry Weller
committed
<< " disconnected regions" << endl;
Henry Weller
committed
if (debug)
{
volScalarField region
(
IOobject
(
Henry Weller
committed
"region",
mesh_.time().timeName(),
mesh_,
Henry Weller
committed
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(dimless, Zero)
Henry Weller
committed
);
Info<< " Dumping region as volScalarField to " << region.name()
<< endl;
Henry Weller
committed
forAll(regions, celli)
{
region[celli] = regions[celli];
}
Henry Weller
committed
region.correctBoundaryConditions();
region.write();
}
Henry Weller
committed
// Determine regions connected to supplied patches
Map<label> patchRegions(findPatchRegions(regions));
Henry Weller
committed
// Sum all regions
const scalarField alphaVol(alpha.primitiveField()*mesh_.V());
Map<scalar> allRegionVolume(regionSum(regions, mesh_.V()));
Henry Weller
committed
Map<scalar> allRegionAlphaVolume(regionSum(regions, alphaVol));
Map<label> allRegionNumCells
(
regionSum
Henry Weller
committed
regions,
labelField(mesh_.nCells(), 1.0)
Henry Weller
committed
)
);
Henry Weller
committed
if (debug)
{
Info<< " " << token::TAB << "Region"
<< token::TAB << "Volume(mesh)"
<< token::TAB << "Volume(" << alpha.name() << "):"
<< token::TAB << "nCells"
Henry Weller
committed
scalar meshSumVol = 0.0;
scalar alphaSumVol = 0.0;
label nCells = 0;
auto vIter = allRegionVolume.cbegin();
auto aIter = allRegionAlphaVolume.cbegin();
auto numIter = allRegionNumCells.cbegin();
Henry Weller
committed
for
(
;
vIter.good() && aIter.good();
Henry Weller
committed
++vIter, ++aIter, ++numIter
)
{
Henry Weller
committed
Info<< " " << token::TAB << vIter.key()
<< token::TAB << vIter()
<< token::TAB << aIter()
<< token::TAB << numIter()
Henry Weller
committed
meshSumVol += vIter();
alphaSumVol += aIter();
nCells += numIter();
}
Henry Weller
committed
Info<< " " << token::TAB << "Total:"
<< token::TAB << meshSumVol
<< token::TAB << alphaSumVol
<< token::TAB << nCells
<< endl;
}
Henry Weller
committed
{
Info<< " Patch connected regions (liquid core):" << nl;
Henry Weller
committed
Info<< token::TAB << " Region"
<< token::TAB << "Volume(mesh)"
<< token::TAB << "Volume(" << alpha.name() << "):"
forAllConstIters(patchRegions, iter)
{
const label regioni = iter.key();
Info<< " " << token::TAB << regioni
<< token::TAB << allRegionAlphaVolume[regioni] << nl;
}
Henry Weller
committed
Info<< endl;
}
Henry Weller
committed
{
Info<< " Background regions:" << nl;
Henry Weller
committed
Info<< " " << token::TAB << "Region"
<< token::TAB << "Volume(mesh)"
<< token::TAB << "Volume(" << alpha.name() << "):"
<< nl;
auto vIter = allRegionVolume.cbegin();
auto aIter = allRegionAlphaVolume.cbegin();
Henry Weller
committed
for
(
;
vIter.good() && aIter.good();
Henry Weller
committed
++vIter, ++aIter
)
{
if
Henry Weller
committed
!patchRegions.found(vIter.key())
&& vIter() >= maxDropletVol
{
Henry Weller
committed
Info<< " " << token::TAB << vIter.key()
<< token::TAB << vIter()
<< token::TAB << aIter() << nl;
}
}
Henry Weller
committed
Info<< endl;
}
Henry Weller
committed
// Split alpha field
// ~~~~~~~~~~~~~~~~~
// Split into
// - liquidCore : region connected to inlet patches
// - per region a volume : for all other regions
// - backgroundAlpha : remaining alpha
writeAlphaFields(regions, patchRegions, allRegionVolume, alpha);
Henry Weller
committed
// Extract droplet-only allRegionVolume, i.e. delete liquid core
// (patchRegions) and background regions from maps.
// Note that we have to use mesh volume (allRegionVolume) and not
// allRegionAlphaVolume since background might not have alpha in it.
// Deleting regions where the volume-alpha-weighted is lower than
// threshold
forAllIters(allRegionVolume, vIter)
Henry Weller
committed
{
const label regioni = vIter.key();
Henry Weller
committed
if
(
Henry Weller
committed
|| vIter() >= maxDropletVol
|| (allRegionAlphaVolume[regioni]/vIter() < threshold_)
Henry Weller
committed
)
{
Henry Weller
committed
allRegionVolume.erase(vIter);
allRegionAlphaVolume.erase(regioni);
allRegionNumCells.erase(regioni);
}
Henry Weller
committed
}
Henry Weller
committed
if (allRegionVolume.size())
{
// Construct mids of bins for plotting
Henry Weller
committed
scalar x = 0.5*delta;
for (point& p : xBin)
{
p.x() = x;
x += delta;
}
Henry Weller
committed
}
Henry Weller
committed
const coordSet coords("diameter", "x", xBin, mag(xBin));
Henry Weller
committed
// Get in region order the alpha*volume and diameter
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Henry Weller
committed
const labelList sortedRegions = allRegionAlphaVolume.sortedToc();
Henry Weller
committed
scalarField sortedVols
(
extractData(sortedRegions, allRegionAlphaVolume)
Henry Weller
committed
);
vectorField centroids(sortedVols.size(), Zero);
// Check if downstream bins are calculated
if (isoPlanes_)
{
vectorField alphaDistance
(
(alpha.primitiveField()*mesh_.V())
*(mesh_.C().primitiveField() - origin_)()
);
Map<vector> allRegionAlphaDistance
(
regionSum
(
regions,
alphaDistance
)
);
// 2. centroid
vectorField sortedMoment
(
extractData(sortedRegions, allRegionAlphaDistance)
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
);
centroids = sortedMoment/sortedVols + origin_;
// Bin according to centroid
scalarField distToPlane((centroids - origin_) & direction_);
vectorField radialDistToOrigin
(
(centroids - origin_) - (distToPlane*direction_)
);
const scalar deltaX = maxDownstream_/nDownstreamBins_;
labelList downstreamIndices(distToPlane.size(), -1);
forAll(distToPlane, i)
{
if
(
(mag(radialDistToOrigin[i]) < maxDiameter_)
&& (distToPlane[i] < maxDownstream_)
)
{
downstreamIndices[i] = distToPlane[i]/deltaX;
}
}
scalarField binDownCount(nDownstreamBins_, Zero);
forAll(distToPlane, i)
{
if (downstreamIndices[i] != -1)
{
binDownCount[downstreamIndices[i]] += 1.0;
}
}
// Write
if (Pstream::master())
{
// Construct mids of bins for plotting
pointField xBin(nDownstreamBins_, Zero);
scalar x = 0.5*deltaX;
for (point& p : xBin)
{
p.x() = x;
x += deltaX;
}
}
const coordSet coords("distance", "x", xBin, mag(xBin));
auto& writer = formatterPtr_();
writer.nFields(1);
writer.open
(
coords,
writeFile::baseTimeDir() / (coords.name() + "_isoPlanes")
);
writer.write("isoPlanes", binDownCount);
writer.close(true);
}
// Write to log
if (log)
{
Info<< " Iso-planes Bins:" << nl
<< " " << token::TAB << "Bin"
<< token::TAB << "Min distance"
<< token::TAB << "Count:"
scalar delta = 0.0;
<< token::TAB << delta
<< token::TAB << binDownCount[bini] << nl;
delta += deltaX;
}
Info<< endl;
}
}
Henry Weller
committed
// Calculate the diameters
scalarField sortedDiameters(sortedVols.size());
forAll(sortedDiameters, i)
{
sortedDiameters[i] = Foam::cbrt
Henry Weller
committed
sortedVols[i]
*6/constant::mathematical::pi
Henry Weller
committed
}
Henry Weller
committed
// Determine the bin index for all the diameters
labelList indices(sortedDiameters.size());
forAll(sortedDiameters, i)
{
indices[i] = (sortedDiameters[i]-minDiam_)/delta;
}
Henry Weller
committed
// Calculate the counts per diameter bin
scalarField binCount(nBins_, Zero);
Henry Weller
committed
forAll(sortedDiameters, i)
{
binCount[indices[i]] += 1.0;
}
Henry Weller
committed
// Write counts
if (Pstream::master())
{
auto& writer = formatterPtr_();
writer.nFields(1);
writer.open
(
coords,
writeFile::baseTimeDir() / (coords.name() + "_count")
);
writer.write("count", binCount);
writer.close(true);
Henry Weller
committed
}
Henry Weller
committed
// Write to log
Henry Weller
committed
{
Info<< " Bins:" << nl
<< " " << token::TAB << "Bin"
Henry Weller
committed
<< token::TAB << "Min diameter"
<< token::TAB << "Count:"
Henry Weller
committed
scalar diam = 0.0;
{
Henry Weller
committed
<< token::TAB << diam
<< token::TAB << binCount[bini] << nl;
Henry Weller
committed
diam += delta;
}
Henry Weller
committed
Info<< endl;
}
Henry Weller
committed
// Write average and deviation of droplet volume.
writeGraphs
(
"volume", // name of field
sortedVols, // per region field data
indices, // per region the bin index
Henry Weller
committed
binCount, // per bin number of regions
coords // graph data for bins
);
Henry Weller
committed
{
for
(
const word& fldName
: obr_.sortedNames<volScalarField>(fields_)
)
Henry Weller
committed
{
Andrew Heather
committed
Log << " Scalar field " << fldName << endl;
tmp<Field<scalar>> tfld
(
obr_.lookupObject<volScalarField>(fldName).primitiveField()
);
const auto& fld = tfld();
Henry Weller
committed
writeGraphs
(
fldName, // name of field
alphaVol*fld, // per cell field data
Henry Weller
committed
regions, // per cell the region(=droplet)
sortedRegions, // valid regions in sorted order
1.0/sortedVols, // per region normalisation
Henry Weller
committed
indices, // index of bin for each region
binCount, // per bin number of regions
coords // graph data for bins
);
Henry Weller
committed
}
{
for
(
const word& fldName
: obr_.sortedNames<volVectorField>(fields_)
)
Henry Weller
committed
{
Log << " Vector field " << fldName << endl;
tmp<Field<vector>> tfld
(
obr_.lookupObject<volVectorField>(fldName).primitiveField()
);
Henry Weller
committed
{
Log << "Transforming vector field " << fldName
Henry Weller
committed
<< " with coordinate system "
<< csysPtr_->name()
Henry Weller
committed
<< endl;
tfld = csysPtr_->localVector(tfld());
Henry Weller
committed
}
Henry Weller
committed
// Components
for (direction cmpt = 0; cmpt < vector::nComponents; ++cmpt)
Henry Weller
committed
{
writeGraphs
(
fldName + vector::componentNames[cmpt],
alphaVol*fld.component(cmpt),// per cell field data
Henry Weller
committed
regions, // per cell the region(=droplet)
sortedRegions, // valid regions in sorted order
1.0/sortedVols, // per region normalisation
Henry Weller
committed
indices, // index of bin for each region
binCount, // per bin number of regions
coords // graph data for bins
);
}
Henry Weller
committed
// Magnitude
writeGraphs
(
fldName + "mag", // name of field
alphaVol*mag(fld), // per cell field data
regions, // per cell the region(=droplet)
sortedRegions, // valid regions in sorted order
1.0/sortedVols, // per region normalisation