Merge branch 'feature-forces-forcecoeffs' into 'develop'

ENH: binField: new function object for data binning

See merge request Development/openfoam!433
This commit is contained in:
Andrew Heather
2022-06-09 09:33:21 +00:00
26 changed files with 3507 additions and 1308 deletions

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2012-2016 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd.
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -237,6 +237,14 @@ public:
const string& property,
const Type& value
) const;
//- Write a given value to stream with the space delimiter
template<class Type>
void writeValue
(
Ostream& os,
const Type& val
) const;
};

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2013-2016 OpenFOAM Foundation
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -41,4 +42,18 @@ void Foam::functionObjects::writeFile::writeHeaderValue
}
template<class Type>
void Foam::functionObjects::writeFile::writeValue
(
Ostream& os,
const Type& val
) const
{
for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; ++cmpt)
{
os << ' ' << component(val, cmpt);
}
}
// ************************************************************************* //

View File

@ -1,5 +1,11 @@
AMIWeights/AMIWeights.C
binField/binField.C
binField/binModels/binModel/binModel.C
binField/binModels/binModel/binModelNew.C
binField/binModels/uniformBin/uniformBin.C
binField/binModels/singleDirectionUniformBin/singleDirectionUniformBin.C
columnAverage/columnAverage.C
continuityError/continuityError.C

View File

@ -0,0 +1,128 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "binField.H"
#include "binModel.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
defineTypeNameAndDebug(binField, 0);
addToRunTimeSelectionTable(functionObject, binField, dictionary);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::binField::binField
(
const word& name,
const Time& runTime,
const dictionary& dict,
bool readFields
)
:
fvMeshFunctionObject(name, runTime, dict),
binModelPtr_(nullptr)
{
if (readFields)
{
read(dict);
}
}
Foam::functionObjects::binField::binField
(
const word& name,
const objectRegistry& obr,
const dictionary& dict,
bool readFields
)
:
fvMeshFunctionObject(name, obr, dict),
binModelPtr_(nullptr)
{
if (readFields)
{
read(dict);
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionObjects::binField::read(const dictionary& dict)
{
if (!fvMeshFunctionObject::read(dict))
{
return false;
}
Info<< type() << " " << name() << ":" << endl;
binModelPtr_.reset(binModel::New(dict, mesh_, name()));
return true;
}
bool Foam::functionObjects::binField::execute()
{
Log << type() << " " << name() << ":" << nl
<< " Calculating bins" << nl << endl;
binModelPtr_->apply();
return true;
}
bool Foam::functionObjects::binField::write()
{
return true;
}
void Foam::functionObjects::binField::updateMesh(const mapPolyMesh& mpm)
{
binModelPtr_->updateMesh(mpm);
}
void Foam::functionObjects::binField::movePoints(const polyMesh& mesh)
{
binModelPtr_->movePoints(mesh);
}
// ************************************************************************* //

View File

@ -0,0 +1,221 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::functionObjects::binField
Group
grpFieldFunctionObjects
Description
Calculates binned data, where specified patches are divided into
segments according to various input bin characteristics, so that
spatially-localised information can be output for each segment.
Operands:
\table
Operand | Type | Location
input | vol\<Type\>Field(s) <!--
--> | \<time\>/\<inpField\>s
output file | dat <!--
--> | postProcessing/\<FO\>/\<time\>/\<file\>
output field | - | -
\endtable
where \c \<Type\>=Scalar/Vector/SphericalTensor/SymmTensor/Tensor.
Usage
Minimal example by using \c system/controlDict.functions:
\verbatim
binField1
{
// Mandatory entries
type binField;
libs (fieldFunctionObjects);
binModel <word>;
fields (<wordHashSet>);
patches (<wordRes>);
binData
{
// Entries of the chosen binModel
}
// Optional entries
cellZones (<wordRes>);
decomposePatchValues <bool>;
// Conditional optional entries
// Option-1, i.e. general coordinate system specification
coordinateSystem
{
type cartesian;
origin (0 0 0);
rotation
{
type axes;
e3 (0 0 1);
e1 (1 0 0); // (e1, e2) or (e2, e3) or (e3, e1)
}
}
// Option-2, i.e. the centre of rotation
// by inherently using e3=(0 0 1) and e1=(1 0 0)
CofR (0 0 0);
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: binField | word | yes | -
libs | Library name: fieldFunctionObjects | word | yes | -
binModel | Name of the bin model | word | yes | -
fields | Names of operand fields | wordHasSet | yes | -
patches | Names of operand patches | wordRes | yes | -
binData | Entries of the chosen bin model | dict | yes | -
decomposePatchValues | Flag to output normal and tangential <!--
--> components | bool | no | false
cellZones | Names of operand cell zones | wordRes | no | -
coordinateSystem | Coordinate system specifier | dict | cndtnl | -
CofR | Centre of rotation | vector | cndtnl | -
\endtable
Options for the \c binModel entry:
\verbatim
singleDirectionUniformBin | Segments in a single direction
uniformBin | Segments in multiple directions
\endverbatim
The inherited entries are elaborated in:
- \link fvMeshFunctionObject.H \endlink
- \link writeFile.H \endlink
- \link coordinateSystem.H \endlink
SourceFiles
binField.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_functionObjects_binField_H
#define Foam_functionObjects_binField_H
#include "fvMeshFunctionObject.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class binModel;
namespace functionObjects
{
/*---------------------------------------------------------------------------*\
Class binField Declaration
\*---------------------------------------------------------------------------*/
class binField
:
public fvMeshFunctionObject
{
protected:
// Protected Data
//- Runtime-selectable bin model
autoPtr<binModel> binModelPtr_;
public:
//- Runtime type information
TypeName("binField");
// Constructors
//- Construct from Time and dictionary
binField
(
const word& name,
const Time& runTime,
const dictionary& dict,
const bool readFields = true
);
//- Construct from objectRegistry and dictionary
binField
(
const word& name,
const objectRegistry& obr,
const dictionary& dict,
const bool readFields = true
);
//- No copy construct
binField(const binField&) = delete;
//- No copy assignment
void operator=(const binField&) = delete;
//- Destructor
virtual ~binField() = default;
// Member Functions
//- Read the dictionary
virtual bool read(const dictionary& dict);
//- Execute the function object
virtual bool execute();
//- Write to data files/fields and to streams
virtual bool write();
//- Update for changes of mesh
virtual void updateMesh(const mapPolyMesh& mpm);
//- Update for changes of mesh
virtual void movePoints(const polyMesh& mesh);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionObjects
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,205 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "binModel.H"
#include "fvMesh.H"
#include "cartesianCS.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(binModel, 0);
defineRunTimeSelectionTable(binModel, dictionary);
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<>
bool Foam::binModel::decomposePatchValues
(
List<List<vector>>& data,
const label bini,
const vector& v,
const vector& n
) const
{
if (!decomposePatchValues_)
{
return false;
}
#ifdef FULLDEBUG
if (data.size() != 3)
{
FatalErrorInFunction
<< "Inconsistent data list size - expect size 3"
<< abort(FatalError);
}
#endif
data[1][bini] += n*(v & n);
data[2][bini] += v - n*(v & n);
return true;
}
void Foam::binModel::setCoordinateSystem
(
const dictionary& dict,
const word& e3Name,
const word& e1Name
)
{
coordSysPtr_.clear();
if (dict.found(coordinateSystem::typeName_()))
{
coordSysPtr_ =
coordinateSystem::New
(
mesh_,
dict,
coordinateSystem::typeName_()
);
Info<< "Setting co-ordinate system:" << nl
<< " - type : " << coordSysPtr_->name() << nl
<< " - origin : " << coordSysPtr_->origin() << nl
<< " - e3 : " << coordSysPtr_->e3() << nl
<< " - e1 : " << coordSysPtr_->e1() << endl;
}
else if (dict.found("CofR"))
{
const vector origin(dict.get<point>("CofR"));
const vector e3
(
e3Name == word::null
? vector(0, 0, 1)
: dict.get<vector>(e3Name)
);
const vector e1
(
e1Name == word::null
? vector(1, 0, 0)
: dict.get<vector>(e1Name)
);
coordSysPtr_.reset(new coordSystem::cartesian(origin, e3, e1));
}
else
{
coordSysPtr_.reset(new coordSystem::cartesian(dict));
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::binModel::binModel
(
const dictionary& dict,
const fvMesh& mesh,
const word& outputPrefix
)
:
writeFile(mesh, outputPrefix),
mesh_(mesh),
decomposePatchValues_(false),
cumulative_(false),
coordSysPtr_(),
nBin_(1),
patchSet_(),
fieldNames_(),
cellZoneIDs_(),
filePtrs_()
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
bool Foam::binModel::read(const dictionary& dict)
{
patchSet_ = mesh_.boundaryMesh().patchSet(dict.get<wordRes>("patches"));
fieldNames_ = dict.get<wordHashSet>("fields").sortedToc();
if (dict.found("cellZones"))
{
DynamicList<label> zoneIDs;
DynamicList<wordRe> czUnmatched;
for (const auto& cz : dict.get<wordRes>("cellZones"))
{
const labelList czi(mesh_.cellZones().indices(cz));
if (czi.empty())
{
czUnmatched.append(cz);
}
else
{
zoneIDs.append(czi);
}
}
if (czUnmatched.size())
{
WarningInFunction
<< "Unable to find zone(s): " << czUnmatched << nl
<< "Valid cellZones are : " << mesh_.cellZones().sortedNames()
<< endl;
}
cellZoneIDs_.transfer(zoneIDs);
}
decomposePatchValues_ = dict.get<bool>("decomposePatchValues");
filePtrs_.setSize(fieldNames_.size());
forAll(filePtrs_, i)
{
filePtrs_.set(i, createFile(fieldNames_[i] + "Bin"));
}
setCoordinateSystem(dict);
return true;
}
void Foam::binModel::updateMesh(const mapPolyMesh& mpm)
{}
void Foam::binModel::movePoints(const polyMesh& mesh)
{}
// ************************************************************************* //

View File

@ -0,0 +1,243 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::binModel
Description
Base class for bin models to handle general bin characteristics.
SourceFiles
binModel.C
binModelNew.C
binModelTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_binModel_H
#define Foam_binModel_H
#include "dictionary.H"
#include "HashSet.H"
#include "volFields.H"
#include "runTimeSelectionTables.H"
#include "OFstream.H"
#include "coordinateSystem.H"
#include "writeFile.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class fvMesh;
/*---------------------------------------------------------------------------*\
Class binModel Declaration
\*---------------------------------------------------------------------------*/
class binModel
:
public functionObjects::writeFile
{
protected:
// Protected Data
//- Reference to the mesh
const fvMesh& mesh_;
//- Decompose patch values into normal and tangential components
bool decomposePatchValues_;
//- Flag to accumulate bin data with
//- increasing distance in binning direction
bool cumulative_;
//- Local coordinate system of bins
autoPtr<coordinateSystem> coordSysPtr_;
//- Total number of bins
label nBin_;
//- Indices of operand patches
labelHashSet patchSet_;
//- Names of operand fields
wordList fieldNames_;
//- Indices of operand cell zones
labelList cellZoneIDs_;
//- List of file pointers; 1 file per field
PtrList<OFstream> filePtrs_;
// Protected Member Functions
//- Set the co-ordinate system from dictionary and axes names
void setCoordinateSystem
(
const dictionary& dict,
const word& e3Name = word::null,
const word& e1Name = word::null
);
//- Helper function to decompose patch values
//- into normal and tangential components
template<class Type>
bool decomposePatchValues
(
List<List<Type>>& data,
const label bini,
const Type& v,
const vector& n
) const;
//- Helper function to construct a string description for a given type
template<class Type>
string writeComponents(const word& stem) const;
//- Write binned data to stream
template<class Type>
void writeBinnedData
(
List<List<Type>>& data,
Ostream& os
) const;
public:
//- Runtime type information
TypeName("binModel");
// Declare runtime constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
binModel,
dictionary,
(
const dictionary& dict,
const fvMesh& mesh,
const word& outputPrefix
),
(dict, mesh, outputPrefix)
);
// Selectors
//- Return a reference to the selected bin model
static autoPtr<binModel> New
(
const dictionary& dict,
const fvMesh& mesh,
const word& outputPrefix
);
// Constructors
//- Construct from components
binModel
(
const dictionary& dict,
const fvMesh& mesh,
const word& outputPrefix
);
//- No copy construct
binModel(const binModel&) = delete;
//- No copy assignment
void operator=(const binModel&) = delete;
//- Destructor
virtual ~binModel() = default;
// Member Functions
//- Read the dictionary
virtual bool read(const dictionary& dict);
// Access
//- Return the total number of bins
label nBin() const noexcept
{
return nBin_;
};
// Evaluation
//- Initialise bin properties
virtual void initialise() = 0;
//- Apply bins
virtual void apply() = 0;
//- Update for changes of mesh
virtual void updateMesh(const mapPolyMesh& mpm);
//- Update for changes of mesh
virtual void movePoints(const polyMesh& mesh);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<>
bool binModel::decomposePatchValues
(
List<List<vector>>& data,
const label bini,
const vector& v,
const vector& n
) const;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "binModelTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "binModel.H"
#include "fvMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::binModel> Foam::binModel::New
(
const dictionary& dict,
const fvMesh& mesh,
const word& outputPrefix
)
{
word modelType(dict.get<word>("binModel"));
auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
if (!cstrIter.found())
{
FatalIOErrorInLookup
(
dict,
"binModel",
modelType,
*dictionaryConstructorTablePtr_
) << exit(FatalIOError);
}
return autoPtr<binModel>(cstrIter()(dict, mesh, outputPrefix));
}
// ************************************************************************* //

View File

@ -0,0 +1,102 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class Type>
bool Foam::binModel::decomposePatchValues
(
List<List<Type>>& data,
const label bini,
const Type& v,
const vector& n
) const
{
return decomposePatchValues_;
}
template<class Type>
Foam::string Foam::binModel::writeComponents(const word& stem) const
{
if (pTraits<Type>::nComponents == 1)
{
return stem;
}
string result = "";
for (label cmpt = 0; cmpt < pTraits<Type>::nComponents; ++cmpt)
{
if (cmpt) result += " ";
result += stem + "_" + word(pTraits<Type>::componentNames[cmpt]);
}
return result;
};
template<class Type>
void Foam::binModel::writeBinnedData
(
List<List<Type>>& data,
Ostream& os
) const
{
if (cumulative_)
{
for (auto& datai : data)
{
for (label bini = 1; bini < nBin_; ++bini)
{
datai[bini] += datai[bini-1];
}
}
}
writeCurrentTime(os);
for (label bini = 0; bini < nBin_; ++bini)
{
Type total = Zero;
for (label i = 0; i < data.size(); ++i)
{
total += data[i][bini];
}
writeValue(os, total);
for (label i = 0; i < data.size(); ++i)
{
writeValue(os, data[i][bini]);
}
}
os << endl;
}
// ************************************************************************* //

View File

@ -0,0 +1,186 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "singleDirectionUniformBin.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace binModels
{
defineTypeNameAndDebug(singleDirectionUniformBin, 0);
addToRunTimeSelectionTable(binModel, singleDirectionUniformBin, dictionary);
}
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::binModels::singleDirectionUniformBin::initialise()
{
const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
// Determine extents of patches in a given direction
scalar geomMin = GREAT;
scalar geomMax = -GREAT;
for (const label patchi : patchSet_)
{
const polyPatch& pp = pbm[patchi];
const scalarField d(pp.faceCentres() & binDir_);
geomMin = min(min(d), geomMin);
geomMax = max(max(d), geomMax);
}
for (const label zonei : cellZoneIDs_)
{
const cellZone& cZone = mesh_.cellZones()[zonei];
const vectorField cz(mesh_.C(), cZone);
const scalarField d(cz & binDir_);
geomMin = min(min(d), geomMin);
geomMax = max(max(d), geomMax);
}
reduce(geomMin, minOp<scalar>());
reduce(geomMax, maxOp<scalar>());
// Slightly boost max so that region of interest is fully within bounds
geomMax = 1.0001*(geomMax - geomMin) + geomMin;
// Use geometry limits if not specified by the user
if (binMin_ == GREAT) binMin_ = geomMin;
if (binMax_ == GREAT) binMax_ = geomMax;
binDx_ = (binMax_ - binMin_)/scalar(nBin_);
if (binDx_ <= 0)
{
FatalErrorInFunction
<< "Max bound must be greater than min bound" << nl
<< " d = " << binDx_ << nl
<< " min = " << binMin_ << nl
<< " max = " << binMax_ << nl
<< exit(FatalError);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::binModels::singleDirectionUniformBin::singleDirectionUniformBin
(
const dictionary& dict,
const fvMesh& mesh,
const word& outputPrefix
)
:
binModel(dict, mesh, outputPrefix),
binDx_(0),
binMin_(GREAT),
binMax_(GREAT),
binDir_(Zero)
{
read(dict);
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
bool Foam::binModels::singleDirectionUniformBin::read(const dictionary& dict)
{
if (!binModel::read(dict))
{
return false;
}
Info<< " Activating a set of single-direction bins" << endl;
const dictionary& binDict = dict.subDict("binData");
nBin_ = binDict.getCheck<label>("nBin", labelMinMax::ge(1));
Info<< " Employing " << nBin_ << " bins" << endl;
if (binDict.readIfPresent("min", binMin_))
{
Info<< " - min : " << binMin_ << endl;
}
if (binDict.readIfPresent("max", binMax_))
{
Info<< " - max : " << binMax_ << endl;
}
cumulative_ = binDict.getOrDefault<bool>("cumulative", false);
Info<< " - cumulative : " << cumulative_ << endl;
Info<< " - decomposePatchValues : " << decomposePatchValues_ << endl;
binDir_ = binDict.get<vector>("direction");
binDir_.normalise();
if (mag(binDir_) == 0)
{
FatalIOErrorInFunction(dict)
<< "Input direction should not be zero valued" << nl
<< " direction = " << binDir_ << nl
<< exit(FatalIOError);
}
Info<< " - direction : " << binDir_ << nl << endl;
initialise();
return true;
}
void Foam::binModels::singleDirectionUniformBin::apply()
{
forAll(fieldNames_, i)
{
const bool ok =
processField<scalar>(i)
|| processField<vector>(i)
|| processField<sphericalTensor>(i)
|| processField<symmTensor>(i)
|| processField<tensor>(i);
if (!ok)
{
WarningInFunction
<< "Unable to find field " << fieldNames_[i]
<< ". Avaliable objects are "
<< mesh_.objectRegistry::sortedToc()
<< endl;
}
}
writtenHeader_ = true;
}
// ************************************************************************* //

View File

@ -0,0 +1,186 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::binModels::singleDirectionUniformBin
Description
Calculates binned data in a specified direction.
For example, a 10cm-long patch extending only in the x-direction
can be binned into 5 bins in the same direction, so that
local information can be output for each 2cm-long segment.
Usage
Minimal example by using \c system/controlDict.functions:
\verbatim
binField1
{
// Other binField entries
...
// Mandatory entries
binModel singleDirectionUniformBin;
binData
{
// Mandatory entries
nBin <label>;
direction <vector>;
// Optional entries
cumulative <bool>;
min <scalar>;
max <scalar>;
}
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
binModel | Type name: singleDirectionUniformBin | word | yes | -
binData | Entries of the chosen bin model | dict | yes | -
nBin | Number of bins in binning direction | label | yes | -
direction | Binning direction | vector | yes | -
cumulative | Flag to bin data accumulated with increasing distance <!--
--> in binning direction | bool | no | false
min | Min-bound in the binning direction with respect to <!--
--> the global coordinate system's origin | scalar | no | GREAT
max | Max-bound in the binning direction with respect to <!--
--> the global coordinate system's origin | scalar | no | GREAT
\endtable
SourceFiles
singleDirectionUniformBin.C
singleDirectionUniformBinTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_binModels_singleDirectionUniformBin_H
#define Foam_binModels_singleDirectionUniformBin_H
#include "binModel.H"
#include "writeFile.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace binModels
{
/*---------------------------------------------------------------------------*\
Class singleDirectionUniformBin Declaration
\*---------------------------------------------------------------------------*/
class singleDirectionUniformBin
:
public binModel
{
protected:
// Protected Data
//- Distance between bin divisions
scalar binDx_;
//- Minimum bin bound
scalar binMin_;
//- Maximum bin bound
scalar binMax_;
//- Binning direction
vector binDir_;
// Protected Member Functions
//- Write header for a binned-data file
template<class Type>
void writeFileHeader(OFstream& os) const;
//- Initialise bin properties
virtual void initialise();
//- Apply the binning to field fieldi
template<class Type>
bool processField(const label fieldi);
public:
//- Runtime type information
TypeName("singleDirectionUniformBin");
// Constructors
//- Construct from components
singleDirectionUniformBin
(
const dictionary& dict,
const fvMesh& mesh,
const word& outputPrefix
);
//- No copy construct
singleDirectionUniformBin(const singleDirectionUniformBin&) = delete;
//- No copy assignment
void operator=(const singleDirectionUniformBin&) = delete;
//- Destructor
virtual ~singleDirectionUniformBin() = default;
// Member Functions
//- Read the dictionary
virtual bool read(const dictionary& dict);
//- Apply bins
virtual void apply();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace binModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "singleDirectionUniformBinTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,195 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
template<class Type>
void Foam::binModels::singleDirectionUniformBin::writeFileHeader
(
OFstream& os
) const
{
writeHeaderValue(os, "bins", nBin_);
writeHeaderValue(os, "start", binMin_);
writeHeaderValue(os, "end", binMax_);
writeHeaderValue(os, "delta", binDx_);
writeHeaderValue(os, "direction", binDir_);
// Compute and print bin end points in the binning direction
vectorField binPoints(nBin_);
writeCommented(os, "x co-ords :");
forAll(binPoints, pointi)
{
binPoints[pointi] = (binMin_ + (pointi + 1)*binDx_)*binDir_;
os << tab << binPoints[pointi].x();
}
os << nl;
writeCommented(os, "y co-ords :");
forAll(binPoints, pointi)
{
os << tab << binPoints[pointi].y();
}
os << nl;
writeCommented(os, "z co-ords :");
forAll(binPoints, pointi)
{
os << tab << binPoints[pointi].z();
}
os << nl;
writeHeader(os, "");
writeCommented(os, "Time");
for (label i = 0; i < nBin_; ++i)
{
const word ibin("_" + Foam::name(i));
writeTabbed(os, writeComponents<Type>("total" + ibin));
writeTabbed(os, writeComponents<Type>("internal" + ibin));
if (decomposePatchValues_)
{
writeTabbed(os, writeComponents<Type>("normal" + ibin));
writeTabbed(os, writeComponents<Type>("tangenial" + ibin));
}
else
{
writeTabbed(os, writeComponents<Type>("patch" + ibin));
}
}
os << endl;
}
template<class Type>
bool Foam::binModels::singleDirectionUniformBin::processField
(
const label fieldi
)
{
const word& fieldName = fieldNames_[fieldi];
typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
const VolFieldType* fieldPtr = mesh_.findObject<VolFieldType>(fieldName);
if (!fieldPtr)
{
return false;
}
if (Pstream::master() && !writtenHeader_)
{
writeFileHeader<Type>(filePtrs_[fieldi]);
}
const VolFieldType& fld = *fieldPtr;
// Total number of fields
//
// 0: internal
// 1: patch total
//
// OR
//
// 0: internal
// 1: patch normal
// 2: patch tangential
label nField = 2;
if (decomposePatchValues_)
{
nField += 1;
}
List<List<Type>> data(nField);
for (auto& binList : data)
{
binList.setSize(nBin_, Zero);
}
for (const label zonei : cellZoneIDs_)
{
const cellZone& cZone = mesh_.cellZones()[zonei];
for (const label celli : cZone)
{
const scalar dd = mesh_.C()[celli] & binDir_;
if (dd < binMin_ || dd > binMax_)
{
continue;
}
// Find the bin division corresponding to the cell
const label bini =
min(max(floor((dd - binMin_)/binDx_), 0), nBin_ - 1);
data[0][bini] += fld[celli];
}
}
forAllIters(patchSet_, iter)
{
const label patchi = iter();
const polyPatch& pp = mesh_.boundaryMesh()[patchi];
const vectorField np(mesh_.boundary()[patchi].nf());
const scalarField dd(pp.faceCentres() & binDir_);
forAll(dd, facei)
{
// Avoid faces outside of the bin
if (dd[facei] < binMin_ || dd[facei] > binMax_)
{
continue;
}
// Find the bin division corresponding to the face
const label bini =
min(max(floor((dd[facei] - binMin_)/binDx_), 0), nBin_ - 1);
const Type& v = fld.boundaryField()[patchi][facei];
if (!decomposePatchValues(data, bini, v, np[facei]))
{
data[1][bini] += v;
}
}
}
if (Pstream::master())
{
writeBinnedData(data, filePtrs_[fieldi]);
}
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,315 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "uniformBin.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace binModels
{
defineTypeNameAndDebug(uniformBin, 0);
addToRunTimeSelectionTable(binModel, uniformBin, dictionary);
}
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::binModels::uniformBin::initialise()
{
const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
// Determine extents of patches in a given coordinate system
vector geomMin(GREAT, GREAT, GREAT);
vector geomMax(-GREAT, -GREAT, -GREAT);
for (const label patchi : patchSet_)
{
const polyPatch& pp = pbm[patchi];
const vectorField ppcs(coordSysPtr_->localPosition(pp.faceCentres()));
for (direction i = 0; i < vector::nComponents; ++i)
{
geomMin[i] = min(min(ppcs.component(i)), geomMin[i]);
geomMax[i] = max(max(ppcs.component(i)), geomMax[i]);
}
}
for (const label zonei : cellZoneIDs_)
{
const cellZone& cZone = mesh_.cellZones()[zonei];
const vectorField d
(
coordSysPtr_->localPosition(vectorField(mesh_.C(), cZone))
);
for (direction i = 0; i < vector::nComponents; ++i)
{
geomMin[i] = min(min(d.component(i)), geomMin[i]);
geomMax[i] = max(max(d.component(i)), geomMax[i]);
}
}
reduce(geomMin, minOp<vector>());
reduce(geomMax, maxOp<vector>());
for (direction i = 0; i < vector::nComponents; ++i)
{
// Slightly boost max so that region of interest is fully within bounds
geomMax[i] = 1.0001*(geomMax[i] - geomMin[i]) + geomMin[i];
// Use geometry limits if not specified by the user
if (binMinMax_[i][0] == GREAT) binMinMax_[i][0] = geomMin[i];
if (binMinMax_[i][1] == GREAT) binMinMax_[i][1] = geomMax[i];
if (binMinMax_[i][0] > binMinMax_[i][1])
{
FatalErrorInFunction
<< "Max bounds must be greater than min bounds" << nl
<< " direction = " << i << nl
<< " min = " << binMinMax_[i][0] << nl
<< " max = " << binMinMax_[i][1] << nl
<< exit(FatalError);
}
//- Compute bin widths in binning directions
binW_[i] = (binMinMax_[i][1] - binMinMax_[i][0])/scalar(nBins_[i]);
if (binW_[i] <= 0)
{
FatalErrorInFunction
<< "Bin widths must be greater than zero" << nl
<< " direction = " << i << nl
<< " min bound = " << binMinMax_[i][0] << nl
<< " max bound = " << binMinMax_[i][1] << nl
<< " bin width = " << binW_[i]
<< exit(FatalError);
}
}
setBinsAddressing();
}
Foam::labelList Foam::binModels::uniformBin::binAddr(const vectorField& d) const
{
labelList binIndices(d.size(), -1);
forAll(d, i)
{
// Avoid elements outside of the bin
bool faceInside = true;
for (direction j = 0; j < vector::nComponents; ++j)
{
if (d[i][j] < binMinMax_[j][0] || d[i][j] > binMinMax_[j][1])
{
faceInside = false;
break;
}
}
if (faceInside)
{
// Find the bin division corresponding to the element
Vector<label> n(Zero);
for (direction j = 0; j < vector::nComponents; ++j)
{
n[j] = floor((d[i][j] - binMinMax_[j][0])/binW_[j]);
n[j] = min(max(n[j], 0), nBins_[j] - 1);
}
// Order: (e1, e2, e3), the first varies the fastest
binIndices[i] = n[0] + nBins_[0]*n[1] + nBins_[0]*nBins_[1]*n[2];
}
else
{
binIndices[i] = -1;
}
}
return binIndices;
}
void Foam::binModels::uniformBin::setBinsAddressing()
{
faceToBin_.setSize(mesh_.nBoundaryFaces());
faceToBin_ = -1;
forAllIters(patchSet_, iter)
{
const polyPatch& pp = mesh_.boundaryMesh()[iter()];
const label i0 = pp.start() - mesh_.nInternalFaces();
SubList<label>(faceToBin_, pp.size(), i0) =
binAddr(coordSysPtr_->localPosition(pp.faceCentres()));
}
cellToBin_.setSize(mesh_.nCells());
cellToBin_ = -1;
for (const label zonei : cellZoneIDs_)
{
const cellZone& cZone = mesh_.cellZones()[zonei];
labelList bins
(
binAddr(coordSysPtr_->localPosition(vectorField(mesh_.C(), cZone)))
);
forAll(cZone, i)
{
const label celli = cZone[i];
cellToBin_[celli] = bins[i];
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::binModels::uniformBin::uniformBin
(
const dictionary& dict,
const fvMesh& mesh,
const word& outputPrefix
)
:
binModel(dict, mesh, outputPrefix),
nBins_(Zero),
binW_(Zero),
binMinMax_
(
vector2D(GREAT, GREAT),
vector2D(GREAT, GREAT),
vector2D(GREAT, GREAT)
)
{
read(dict);
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
bool Foam::binModels::uniformBin::read(const dictionary& dict)
{
if (!binModel::read(dict))
{
return false;
}
Info<< " Activating a set of uniform bins" << endl;
const dictionary& binDict = dict.subDict("binData");
nBins_ = binDict.get<Vector<label>>("nBin");
for (const label n : nBins_)
{
nBin_ *= n;
}
if (nBin_ <= 0)
{
FatalIOErrorInFunction(binDict)
<< "Number of bins must be greater than zero" << nl
<< " e1 bins = " << nBins_[0] << nl
<< " e2 bins = " << nBins_[1] << nl
<< " e3 bins = " << nBins_[2]
<< exit(FatalIOError);
}
Info<< " - Employing:" << nl
<< " " << nBins_[0] << " e1 bins," << nl
<< " " << nBins_[1] << " e2 bins," << nl
<< " " << nBins_[2] << " e3 bins"
<< endl;
cumulative_ = binDict.getOrDefault<bool>("cumulative", false);
Info<< " - cumulative : " << cumulative_ << endl;
Info<< " - decomposePatchValues : " << decomposePatchValues_ << endl;
if (binDict.found("minMax"))
{
const dictionary& minMaxDict = binDict.subDict("minMax");
for (direction i = 0; i < vector::nComponents; ++i)
{
const word ei("e" + Foam::name(i));
if (minMaxDict.readIfPresent(ei, binMinMax_[i]))
{
Info<< " - " << ei << " min : "
<< binMinMax_[i][0] << nl
<< " - " << ei << " max : "
<< binMinMax_[i][1] << endl;
}
}
}
Info<< endl;
initialise();
return true;
}
void Foam::binModels::uniformBin::apply()
{
forAll(fieldNames_, i)
{
const bool ok =
processField<scalar>(i)
|| processField<vector>(i)
|| processField<sphericalTensor>(i)
|| processField<symmTensor>(i)
|| processField<tensor>(i);
if (!ok)
{
WarningInFunction
<< "Unable to find field " << fieldNames_[i]
<< endl;
}
}
writtenHeader_ = true;
}
void Foam::binModels::uniformBin::updateMesh(const mapPolyMesh& mpm)
{}
void Foam::binModels::uniformBin::movePoints(const polyMesh& mesh)
{
setBinsAddressing();
}
// ************************************************************************* //

View File

@ -0,0 +1,222 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::binModels::uniformBin
Description
Calculates binned data in multiple segments according to
a specified Cartesian or cylindrical coordinate system.
Usage
Minimal example by using \c system/controlDict.functions:
\verbatim
binField1
{
// Other binField entries
...
// Mandatory entries
binModel uniformBin;
binData
{
// Mandatory entries
nBin <Vector<label>>;
// Optional entries
cumulative <bool>;
minMax
{
e1 (<scalar> <scalar>); // (min max);
e2 (<scalar> <scalar>);
e3 (<scalar> <scalar>);
}
}
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
binModel | Type name: uniformBin | word | yes | -
binData | Entries of the chosen bin model | dict | yes | -
nBin | Numbers of bins in specified directions | Vector\<label\> <!--
--> | yes | -
cumulative | Flag to bin data accumulated with increasing distance <!--
--> in binning direction | bool | no | false
minMax | Min-max bounds in binning directions with respect to <!--
--> the coordinateSystem's origin | dict | no | -
\endtable
Note
- The order of bin numbering is (e1, e2, e3), where the first
varies the fastest. For example, for a cylindrical bin with
\f$ nBin = (radial, azimuth, height) = (2, 4, 2) \f$, the bin indices
may look like as follows - note the counterclockwise increments:
\verbatim
|-------------------|
| 12 | | 14 |
| 11 | 13 |
| 9 | 15 |
| 10 | | 16 |
|-------------------|
/ / / /
/ / / /
|-------------------|
| 4 | | 6 |
| 3 | 5 |
| 1 | 7 |
| 2 | | 8 |
|-------------------|
\endverbatim
SourceFiles
uniformBin.C
uniformBinTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_binModels_uniformBin_H
#define Foam_binModels_uniformBin_H
#include "binModel.H"
#include "writeFile.H"
#include "coordinateSystem.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace binModels
{
/*---------------------------------------------------------------------------*\
Class uniformBin Declaration
\*---------------------------------------------------------------------------*/
class uniformBin
:
public binModel
{
protected:
// Protected Data
//- Numbers of bins in binning directions
Vector<label> nBins_;
//- Equidistant bin widths in binning directions
vector binW_;
//- Min-max bounds of bins in binning directions
Vector<vector2D> binMinMax_;
//- Face index to bin index addressing
labelList faceToBin_;
//- Cell index to bin index addressing
labelList cellToBin_;
// Protected Member Functions
//- Write header for an binned-data file
template<class Type>
void writeFileHeader(OFstream& os) const;
//- Initialise bin properties
virtual void initialise();
//- Return list of bin indices corresponding to positions given by d
virtual labelList binAddr(const vectorField& d) const;
//- Set/cache the bin addressing
virtual void setBinsAddressing();
//- Apply the binning to field fieldi
template<class Type>
bool processField(const label fieldi);
public:
//- Runtime type information
TypeName("uniformBin");
// Constructors
//- Construct from components
uniformBin
(
const dictionary& dict,
const fvMesh& mesh,
const word& outputPrefix
);
//- No copy construct
uniformBin(const uniformBin&) = delete;
//- No copy assignment
void operator=(const uniformBin&) = delete;
//- Destructor
virtual ~uniformBin() = default;
// Member Functions
//- Read the dictionary
virtual bool read(const dictionary& dict);
//- Apply bins
virtual void apply();
//- Update for changes of mesh
virtual void updateMesh(const mapPolyMesh& mpm);
//- Update for changes of mesh
virtual void movePoints(const polyMesh& mesh);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "uniformBinTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace binModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,178 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class Type>
void Foam::binModels::uniformBin::writeFileHeader
(
OFstream& os
) const
{
writeHeader(os, "bins");
const tensor& R = coordSysPtr_->R();
for (direction i = 0; i < vector::nComponents; ++i)
{
writeHeaderValue(os, "e" + Foam::name(i) + " bins", nBins_[i]);
writeHeaderValue(os, " start", binMinMax_[i][0]);
writeHeaderValue(os, " end", binMinMax_[i][1]);
writeHeaderValue(os, " delta", binW_[i]);
writeHeaderValue(os, " direction", R.col(i));
}
writeCommented(os, "bin end co-ordinates:");
os << nl;
// Compute and print bin end points in binning directions
for (direction i = 0; i < vector::nComponents; ++i)
{
scalar binEnd = binMinMax_[i][0];
writeCommented(os, "e"+Foam::name(i)+" co-ords :");
for (label j = 0; j < nBins_[i]; ++j)
{
binEnd += binW_[i];
os << tab << binEnd;
}
os << nl;
}
writeHeader(os, "");
writeCommented(os, "Time");
for (label i = 0; i < nBin_; ++i)
{
const word ibin(Foam::name(i) + ':');
writeTabbed(os, writeComponents<Type>("total" + ibin));
writeTabbed(os, writeComponents<Type>("internal" + ibin));
if (decomposePatchValues_)
{
writeTabbed(os, writeComponents<Type>("normal" + ibin));
writeTabbed(os, writeComponents<Type>("tangential" + ibin));
}
else
{
writeTabbed(os, writeComponents<Type>("patch" + ibin));
}
}
os << endl;
}
template<class Type>
bool Foam::binModels::uniformBin::processField(const label fieldi)
{
const word& fieldName = fieldNames_[fieldi];
typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
const VolFieldType* fieldPtr = mesh_.findObject<VolFieldType>(fieldName);
if (!fieldPtr)
{
return false;
}
if (Pstream::master() && !writtenHeader_)
{
writeFileHeader<Type>(filePtrs_[fieldi]);
}
const VolFieldType& fld = *fieldPtr;
// Total number of fields
//
// 0: internal
// 1: patch total
//
// OR
//
// 0: internal
// 1: patch normal
// 2: patch tangential
label nField = 2;
if (decomposePatchValues_)
{
nField += 1;
}
List<List<Type>> data(nField);
for (auto& binList : data)
{
binList.setSize(nBin_, Zero);
}
for (const label zonei : cellZoneIDs_)
{
const cellZone& cZone = mesh_.cellZones()[zonei];
for (const label celli : cZone)
{
const label bini = cellToBin_[celli];
if (bini != -1)
{
data[0][bini] += fld[celli];
}
}
}
forAllIters(patchSet_, iter)
{
const label patchi = iter();
const polyPatch& pp = mesh_.boundaryMesh()[patchi];
const vectorField np(mesh_.boundary()[patchi].nf());
forAll(pp, facei)
{
const label localFacei =
pp.start() - mesh_.nInternalFaces() + facei;
const label bini = faceToBin_[localFacei];
if (bini != -1)
{
const Type& v = fld.boundaryField()[patchi][facei];
if (!decomposePatchValues(data, bini, v, np[facei]))
{
data[1][bini] += v;
}
}
}
}
if (Pstream::master())
{
writeBinnedData(data, filePtrs_[fieldi]);
}
return true;
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd.
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -50,47 +50,121 @@ namespace functionObjects
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::functionObjects::forceCoeffs::createFiles()
void Foam::functionObjects::forceCoeffs::initialise()
{
// Note: Only possible to create bin files after bins have been initialised
if (initialised_)
{
return;
}
if (writeToFile() && !coeffFilePtr_)
initialised_ = true;
}
void Foam::functionObjects::forceCoeffs::reset()
{
Cf_.reset();
Cm_.reset();
forceCoeff_ == dimensionedVector(dimless, Zero);
momentCoeff_ == dimensionedVector(dimless, Zero);
}
Foam::HashTable<Foam::functionObjects::forceCoeffs::coeffDesc>
Foam::functionObjects::forceCoeffs::selectCoeffs() const
{
HashTable<coeffDesc> coeffs(16);
coeffs.insert("Cd", coeffDesc("Drag force", "Cd", 0, 0));
coeffs.insert("Cs", coeffDesc("Side force", "Cs", 1, 2));
coeffs.insert("Cl", coeffDesc("Lift force", "Cl", 2, 1));
// Add front/rear options
const auto frontRearCoeffs(coeffs);
forAllConstIters(frontRearCoeffs, iter)
{
const auto& fr = iter.val();
coeffs.insert(fr.frontName(), fr.front());
coeffs.insert(fr.rearName(), fr.rear());
}
// Add moments
coeffs.insert("CmRoll", coeffDesc("Roll moment", "CmRoll", 0, -1));
coeffs.insert("CmPitch", coeffDesc("Pitch moment", "CmPitch", 1, -1));
coeffs.insert("CmYaw", coeffDesc("Yaw moment", "CmYaw", 2, -1));
return coeffs;
}
void Foam::functionObjects::forceCoeffs::calcForceCoeffs()
{
// Calculate scaling factors
const scalar pDyn = 0.5*rhoRef_*sqr(magUInf_);
const dimensionedScalar forceScaling
(
dimless/dimForce,
scalar(1)/(Aref_*pDyn + SMALL)
);
const auto& coordSys = coordSysPtr_();
// Calculate force coefficients
forceCoeff_ = forceScaling*force_;
Cf_.reset
(
forceScaling.value()*coordSys.localVector(sumPatchForcesV_),
forceScaling.value()*coordSys.localVector(sumPatchForcesP_),
forceScaling.value()*coordSys.localVector(sumInternalForces_)
);
}
void Foam::functionObjects::forceCoeffs::calcMomentCoeffs()
{
// Calculate scaling factors
const scalar pDyn = 0.5*rhoRef_*sqr(magUInf_);
const dimensionedScalar momentScaling
(
dimless/(dimForce*dimLength),
scalar(1)/(Aref_*pDyn*lRef_ + SMALL)
);
const auto& coordSys = coordSysPtr_();
// Calculate moment coefficients
momentCoeff_ = momentScaling*moment_;
Cm_.reset
(
momentScaling.value()*coordSys.localVector(sumPatchMomentsP_),
momentScaling.value()*coordSys.localVector(sumPatchMomentsV_),
momentScaling.value()*coordSys.localVector(sumInternalMoments_)
);
}
void Foam::functionObjects::forceCoeffs::createIntegratedDataFile()
{
if (!coeffFilePtr_.valid())
{
coeffFilePtr_ = createFile("coefficient");
writeIntegratedHeader("Coefficients", coeffFilePtr_());
if (nBin_ > 1)
{
CdBinFilePtr_ = createFile("CdBin");
writeBinHeader("Drag coefficient bins", CdBinFilePtr_());
CsBinFilePtr_ = createFile("CsBin");
writeBinHeader("Side coefficient bins", CsBinFilePtr_());
ClBinFilePtr_ = createFile("ClBin");
writeBinHeader("Lift coefficient bins", ClBinFilePtr_());
CmRollBinFilePtr_ = createFile("CmRollBin");
writeBinHeader("Roll moment coefficient bins", CmRollBinFilePtr_());
CmPitchBinFilePtr_ = createFile("CmPitchBin");
writeBinHeader("Moment coefficient bins", CmPitchBinFilePtr_());
CmYawBinFilePtr_ = createFile("CmYawBin");
writeBinHeader("Yaw moment coefficient bins", CmYawBinFilePtr_());
}
writeIntegratedDataFileHeader("Coefficients", coeffFilePtr_());
}
}
void Foam::functionObjects::forceCoeffs::writeIntegratedHeader
void Foam::functionObjects::forceCoeffs::writeIntegratedDataFileHeader
(
const word& header,
Ostream& os
OFstream& os
) const
{
const auto& coordSys = coordSysPtr_();
writeHeader(os, "Force coefficients");
writeHeader(os, "Force and moment coefficients");
writeHeaderValue(os, "dragDir", coordSys.e1());
writeHeaderValue(os, "sideDir", coordSys.e2());
writeHeaderValue(os, "liftDir", coordSys.e3());
@ -103,128 +177,38 @@ void Foam::functionObjects::forceCoeffs::writeIntegratedHeader
writeHeaderValue(os, "CofR", coordSys.origin());
writeHeader(os, "");
writeCommented(os, "Time");
writeTabbed(os, "Cd");
writeTabbed(os, "Cs");
writeTabbed(os, "Cl");
writeTabbed(os, "CmRoll");
writeTabbed(os, "CmPitch");
writeTabbed(os, "CmYaw");
writeTabbed(os, "Cd(f)");
writeTabbed(os, "Cd(r)");
writeTabbed(os, "Cs(f)");
writeTabbed(os, "Cs(r)");
writeTabbed(os, "Cl(f)");
writeTabbed(os, "Cl(r)");
os << endl;
}
void Foam::functionObjects::forceCoeffs::writeBinHeader
(
const word& header,
Ostream& os
) const
for (const auto& iter : coeffs_.sorted())
{
writeHeader(os, header);
writeHeaderValue(os, "bins", nBin_);
writeHeaderValue(os, "start", binMin_);
writeHeaderValue(os, "delta", binDx_);
writeHeaderValue(os, "direction", binDir_);
const auto& coeff = iter.val();
vectorField binPoints(nBin_);
writeCommented(os, "x co-ords :");
forAll(binPoints, pointi)
{
binPoints[pointi] = (binMin_ + (pointi + 1)*binDx_)*binDir_;
os << tab << binPoints[pointi].x();
}
os << nl;
if (!coeff.active_) continue;
writeCommented(os, "y co-ords :");
forAll(binPoints, pointi)
{
os << tab << binPoints[pointi].y();
}
os << nl;
writeCommented(os, "z co-ords :");
forAll(binPoints, pointi)
{
os << tab << binPoints[pointi].z();
}
os << nl;
writeHeader(os, "");
writeCommented(os, "Time");
for (label j = 0; j < nBin_; ++j)
{
const word jn(Foam::name(j) + ':');
writeTabbed(os, jn + "total");
writeTabbed(os, jn + "pressure");
writeTabbed(os, jn + "viscous");
if (porosity_)
{
writeTabbed(os, jn + "porous");
}
writeTabbed(os, coeff.name_);
}
os << endl;
}
void Foam::functionObjects::forceCoeffs::writeIntegratedData
(
const word& title,
const List<Field<scalar>>& coeff
) const
void Foam::functionObjects::forceCoeffs::writeIntegratedDataFile()
{
if (!log)
{
return;
}
OFstream& os = coeffFilePtr_();
const scalar pressure = sum(coeff[0]);
const scalar viscous = sum(coeff[1]);
const scalar porous = sum(coeff[2]);
const scalar total = pressure + viscous + porous;
Info<< " " << title << " : " << total << token::TAB
<< '('
<< "pressure: " << pressure << token::TAB
<< "viscous: " << viscous;
if (porosity_)
{
Info<< token::TAB << "porous: " << porous;
}
Info<< ')' << endl;
}
void Foam::functionObjects::forceCoeffs::writeBinData
(
const List<Field<scalar>> coeffs,
Ostream& os
) const
{
writeCurrentTime(os);
for (label bini = 0; bini < nBin_; ++bini)
for (const auto& iter : coeffs_.sorted())
{
scalar total = coeffs[0][bini] + coeffs[1][bini] + coeffs[2][bini];
const auto& coeff = iter.val();
os << tab << total << tab << coeffs[0][bini] << tab << coeffs[1][bini];
if (!coeff.active_) continue;
if (porosity_)
{
os << tab << coeffs[2][bini];
}
const vector coeffValue = coeff.value(Cf_, Cm_);
os << tab << (coeffValue.x() + coeffValue.y() + coeffValue.z());
}
os << endl;
coeffFilePtr_() << endl;
}
@ -239,16 +223,39 @@ Foam::functionObjects::forceCoeffs::forceCoeffs
)
:
forces(name, runTime, dict, false),
Cf_(),
Cm_(),
forceCoeff_
(
IOobject
(
"forceCoeff", // scopedName() is not available at ctor level
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedVector(dimless, Zero)
),
momentCoeff_
(
IOobject
(
"momentCoeff",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedVector(dimless, Zero)
),
coeffFilePtr_(),
magUInf_(Zero),
lRef_(Zero),
Aref_(Zero),
coeffFilePtr_(),
CdBinFilePtr_(),
CsBinFilePtr_(),
ClBinFilePtr_(),
CmRollBinFilePtr_(),
CmPitchBinFilePtr_(),
CmYawBinFilePtr_()
initialised_(false)
{
if (readFields)
{
@ -263,230 +270,139 @@ Foam::functionObjects::forceCoeffs::forceCoeffs
bool Foam::functionObjects::forceCoeffs::read(const dictionary& dict)
{
forces::read(dict);
if (!forces::read(dict))
{
return false;
}
// Free stream velocity magnitude
initialised_ = false;
// Reference scales
dict.readEntry("magUInf", magUInf_);
dict.readEntry("lRef", lRef_);
dict.readEntry("Aref", Aref_);
// If case is compressible we must read rhoInf (store in rhoRef_) to
// calculate the reference dynamic pressure
// Note: for incompressible, rhoRef_ is already initialised
// If case is compressible we must read rhoInf
// (stored in rhoRef_) to calculate the reference dynamic pressure
// Note: for incompressible, rhoRef_ is already initialised to 1
if (rhoName_ != "rhoInf")
{
dict.readEntry("rhoInf", rhoRef_);
}
// Reference length and area scales
dict.readEntry("lRef", lRef_);
dict.readEntry("Aref", Aref_);
Info<< " magUInf: " << magUInf_ << nl
<< " lRef : " << lRef_ << nl
<< " Aref : " << Aref_ << nl
<< " rhoInf : " << rhoRef_ << endl;
if (writeFields_)
if (min(magUInf_, rhoRef_) < SMALL || min(lRef_, Aref_) < SMALL)
{
volVectorField* forceCoeffPtr
(
new volVectorField
(
IOobject
(
scopedName("forceCoeff"),
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedVector(dimless, Zero)
)
);
FatalIOErrorInFunction(dict)
<< "Non-zero values are required for reference scales"
<< exit(FatalIOError);
mesh_.objectRegistry::store(forceCoeffPtr);
volVectorField* momentCoeffPtr
(
new volVectorField
(
IOobject
(
scopedName("momentCoeff"),
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedVector(dimless, Zero)
)
);
mesh_.objectRegistry::store(momentCoeffPtr);
return false;
}
if (!dict.found("coefficients"))
{
Info<< " Selecting all coefficients" << nl;
coeffs_ = selectCoeffs();
for (auto& iter : coeffs_.sorted())
{
auto& coeff = iter.val();
coeff.active_ = true;
Info<< " - " << coeff << nl;
}
}
else
{
const wordHashSet coeffs(dict.get<wordHashSet>("coefficients"));
coeffs_ = selectCoeffs();
Info<< " Selecting coefficients:" << nl;
for (const word& key : coeffs)
{
auto coeffIter = coeffs_.find(key);
if (!coeffIter.good())
{
FatalIOErrorInFunction(dict)
<< "Unknown coefficient type " << key
<< " . Valid entries are : " << coeffs_.sortedToc()
<< exit(FatalIOError);
}
auto& coeff = coeffIter.val();
coeff.active_ = true;
Info<< " - " << coeff << nl;
}
}
forceCoeff_.rename(scopedName("forceCoeff"));
momentCoeff_.rename(scopedName("momentCoeff"));
Info<< endl;
return true;
}
bool Foam::functionObjects::forceCoeffs::execute()
{
forces::calcForcesMoment();
forces::calcForcesMoments();
createFiles();
initialise();
// Storage for pressure, viscous and porous contributions to coeffs
List<Field<scalar>> dragCoeffs(3);
List<Field<scalar>> sideCoeffs(3);
List<Field<scalar>> liftCoeffs(3);
List<Field<scalar>> rollMomentCoeffs(3);
List<Field<scalar>> pitchMomentCoeffs(3);
List<Field<scalar>> yawMomentCoeffs(3);
reset();
forAll(liftCoeffs, i)
Log << type() << " " << name() << " write:" << nl
<< " " << "Coefficient"
<< tab << "Total"
<< tab << "Pressure"
<< tab << "Viscous"
<< tab << "Internal"
<< nl;
calcForceCoeffs();
calcMomentCoeffs();
auto logValues = [](const word& name, const vector& coeff, Ostream& os)
{
dragCoeffs[i].setSize(nBin_);
sideCoeffs[i].setSize(nBin_);
liftCoeffs[i].setSize(nBin_);
rollMomentCoeffs[i].setSize(nBin_);
pitchMomentCoeffs[i].setSize(nBin_);
yawMomentCoeffs[i].setSize(nBin_);
os << " " << name << ":"
<< tab << coeff.x() + coeff.y() + coeff.z()
<< tab << coeff.x()
<< tab << coeff.y()
<< tab << coeff.z()
<< nl;
};
// Always setting all results
for (const auto& iter : coeffs_.sorted())
{
const word& coeffName = iter.key();
const auto& coeff = iter.val();
// Vectors for x:pressure, y:viscous, z:internal
const vector coeffValue = coeff.value(Cf_, Cm_);
if (log && coeff.active_)
{
logValues(coeffName, coeffValue, Info);
}
// Calculate coefficients
scalar CdTot = 0;
scalar CsTot = 0;
scalar ClTot = 0;
scalar CmRollTot = 0;
scalar CmPitchTot = 0;
scalar CmYawTot = 0;
const scalar pDyn = 0.5*rhoRef_*sqr(magUInf_);
// Avoid divide by zero in 2D cases
const scalar momentScaling = 1.0/(Aref_*pDyn*lRef_ + SMALL);
const scalar forceScaling = 1.0/(Aref_*pDyn + SMALL);
const auto& coordSys = coordSysPtr_();
forAll(liftCoeffs, i)
{
const Field<vector> localForce(coordSys.localVector(force_[i]));
const Field<vector> localMoment(coordSys.localVector(moment_[i]));
dragCoeffs[i] = forceScaling*(localForce.component(0));
sideCoeffs[i] = forceScaling*(localForce.component(1));
liftCoeffs[i] = forceScaling*(localForce.component(2));
rollMomentCoeffs[i] = momentScaling*(localMoment.component(0));
pitchMomentCoeffs[i] = momentScaling*(localMoment.component(1));
yawMomentCoeffs[i] = momentScaling*(localMoment.component(2));
CdTot += sum(dragCoeffs[i]);
CsTot += sum(sideCoeffs[i]);
ClTot += sum(liftCoeffs[i]);
CmRollTot += sum(rollMomentCoeffs[i]);
CmPitchTot += sum(pitchMomentCoeffs[i]);
CmYawTot += sum(yawMomentCoeffs[i]);
setResult(coeffName, coeffValue.x() + coeffValue.y() + coeffValue.z());
setResult(coeffName & "pressure", coeffValue.x());
setResult(coeffName & "viscous", coeffValue.y());
setResult(coeffName & "internal", coeffValue.z());
}
// Single contributions to the front and rear
const scalar CdfTot = 0.5*CdTot + CmRollTot;
const scalar CdrTot = 0.5*CdTot - CmRollTot;
const scalar CsfTot = 0.5*CsTot + CmYawTot;
const scalar CsrTot = 0.5*CsTot - CmYawTot;
const scalar ClfTot = 0.5*ClTot + CmPitchTot;
const scalar ClrTot = 0.5*ClTot - CmPitchTot;
Log << type() << " " << name() << " execute:" << nl
<< " Coefficients" << nl;
writeIntegratedData("Cd", dragCoeffs);
writeIntegratedData("Cs", sideCoeffs);
writeIntegratedData("Cl", liftCoeffs);
writeIntegratedData("CmRoll", rollMomentCoeffs);
writeIntegratedData("CmPitch", pitchMomentCoeffs);
writeIntegratedData("CmYaw", yawMomentCoeffs);
Log << " Cd(f) : " << CdfTot << nl
<< " Cd(r) : " << CdrTot << nl;
Log << " Cs(f) : " << CsfTot << nl
<< " Cs(r) : " << CsrTot << nl;
Log << " Cl(f) : " << ClfTot << nl
<< " Cl(r) : " << ClrTot << nl;
if (writeToFile())
{
writeCurrentTime(coeffFilePtr_());
coeffFilePtr_()
<< tab << CdTot << tab << CsTot << tab << ClTot
<< tab << CmRollTot << tab << CmPitchTot << tab << CmYawTot
<< tab << CdfTot << tab << CdrTot
<< tab << CsfTot << tab << CsrTot
<< tab << ClfTot << tab << ClrTot << endl;
if (nBin_ > 1)
{
if (binCumulative_)
{
forAll(liftCoeffs, i)
{
for (label bini = 1; bini < nBin_; ++bini)
{
dragCoeffs[i][bini] += dragCoeffs[i][bini-1];
sideCoeffs[i][bini] += sideCoeffs[i][bini-1];
liftCoeffs[i][bini] += liftCoeffs[i][bini-1];
rollMomentCoeffs[i][bini] +=
rollMomentCoeffs[i][bini-1];
pitchMomentCoeffs[i][bini] +=
pitchMomentCoeffs[i][bini-1];
yawMomentCoeffs[i][bini] += yawMomentCoeffs[i][bini-1];
}
}
}
writeBinData(dragCoeffs, CdBinFilePtr_());
writeBinData(sideCoeffs, CsBinFilePtr_());
writeBinData(liftCoeffs, ClBinFilePtr_());
writeBinData(rollMomentCoeffs, CmRollBinFilePtr_());
writeBinData(pitchMomentCoeffs, CmPitchBinFilePtr_());
writeBinData(yawMomentCoeffs, CmYawBinFilePtr_());
}
}
// Write state/results information
{
setResult("Cd", CdTot);
setResult("Cs", CsTot);
setResult("Cl", ClTot);
setResult("CmRoll", CmRollTot);
setResult("CmPitch", CmPitchTot);
setResult("CmYaw", CmYawTot);
setResult("Cd(f)", CdfTot);
setResult("Cd(r)", CdrTot);
setResult("Cs(f)", CsfTot);
setResult("Cs(r)", CsrTot);
setResult("Cl(f)", ClfTot);
setResult("Cl(r)", ClrTot);
}
if (writeFields_)
{
const volVectorField& force =
lookupObject<volVectorField>(scopedName("force"));
const volVectorField& moment =
lookupObject<volVectorField>(scopedName("moment"));
volVectorField& forceCoeff =
lookupObjectRef<volVectorField>(scopedName("forceCoeff"));
volVectorField& momentCoeff =
lookupObjectRef<volVectorField>(scopedName("momentCoeff"));
dimensionedScalar f0("f0", dimForce, Aref_*pDyn);
dimensionedScalar m0("m0", dimForce*dimLength, Aref_*lRef_*pDyn);
forceCoeff == force/f0;
momentCoeff == moment/m0;
}
Log << endl;
return true;
}
@ -494,18 +410,23 @@ bool Foam::functionObjects::forceCoeffs::execute()
bool Foam::functionObjects::forceCoeffs::write()
{
if (writeToFile())
{
Log << " writing force and moment coefficient files." << endl;
createIntegratedDataFile();
writeIntegratedDataFile();
}
if (writeFields_)
{
const volVectorField& forceCoeff =
lookupObject<volVectorField>(scopedName("forceCoeff"));
const volVectorField& momentCoeff =
lookupObject<volVectorField>(scopedName("momentCoeff"));
forceCoeff.write();
momentCoeff.write();
forceCoeff_.write();
momentCoeff_.write();
}
Log << endl;
return true;
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019-2020 OpenCFD Ltd.
Copyright (C) 2019-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -31,117 +31,185 @@ Group
grpForcesFunctionObjects
Description
Extends the \c forces functionObject by providing coefficients for:
- drag, side and lift forces (Cd, Cs, and Cl)
- roll, pitch and yaw moments (CmRoll, CmPitch, and CmYaw)
- front and rear axle force contributions (C(f) and C(r)) wherein
Computes force and moment coefficients over a given
list of patches, and optionally over given porous zones.
The following coefficients can be selected and output:
\verbatim
Cd(f/r) = 0.5*Cd \pm CmRoll
Cs(f/r) = 0.5*Cs \pm CmYaw
Cl(f/r) = 0.5*Cl \pm CmPitch
Cd | Drag coefficient
Cs | Side-force coefficient
Cl | Lift coefficient
CmRoll | Roll-moment coefficient
CmPitch | Pitch-moment coefficient
CmYaw | Yaw-moment coefficient
\endverbatim
The data can optionally be output into bins, defined in a given direction.
The force coefficients can also be optionally output
in terms of their front and rear axle constituents:
\verbatim
Cd{f,r} = 0.5*Cd {+,-} CmRoll
Cs{f,r} = 0.5*Cs {+,-} CmYaw
Cl{f,r} = 0.5*Cl {+,-} CmPitch
\endverbatim
where \c f and \c r represent front and rear axles, respectively.
The binned data provides the total and consitituent components per bin:
- total coefficient
- pressure coefficient contribution
- viscous coefficient contribution
- porous coefficient contribution
Force and moment coefficients are output
in their total and constituent components:
- total force and moment coefficients
- pressure contributions
- viscous contributions
- porous resistance contributions (optional)
Data is written into multiple files in the
postProcessing/\<functionObjectName\> directory:
- coefficient.dat : integrated coefficients over all geometries
- CdBin.dat : drag coefficient bins
- CsBin.dat : side coefficient bins
- ClBin.dat : lift coefficient bins
- CmRollBin.dat : roll moment coefficient bins
- CmPitchBin.dat : pitch moment coefficient bins
- CmYawBin.dat : yaw moment coefficient bins
Force and moment coefficients can be computed and output in:
- the global Cartesian coordinate system (default)
- a user-defined Cartesian coordinate system
Operands:
\table
Operand | Type | Location
input | - | -
output file | dat | postProcessing/\<FO\>/\<time\>/\<file\>s
output field | volVectorField | \<time\>/\<outField\>s
\endtable
where \c \<file\>s:
\verbatim
coefficient.dat | Integrated coefficients over all patches
\endverbatim
where \c \<outField\>s:
\verbatim
<namePrefix>:forceCoeff | Force coefficient field
<namePrefix>:momentCoeff | Moment coefficient field
\endverbatim
Usage
Example of function object specification:
Minimal example by using \c system/controlDict.functions:
\verbatim
forceCoeffs1
{
// Mandatory entries
type forceCoeffs;
libs (forces);
...
log yes;
writeFields yes;
patches (walls);
patches (<wordRes>); // (wall1 "(wall2|wall3)");
magUInf <scalar>;
lRef <scalar>;
Aref <scalar>;
// input keywords for directions of force/moment coefficients
// refer below for options, and relations
// Optional entries
coefficients (<wordHashSet>);
directForceDensity <bool>;
porosity <bool>;
writeFields <bool>;
useNamePrefix <bool>;
magUInf 100;
lRef 3.5;
Aref 2.2;
porosity no;
// Conditional mandatory entries
binData
{
nBin 20;
direction (1 0 0);
cumulative yes;
}
}
\endverbatim
// Cartesian coordinate system specification when evaluating
// force and moment coefficients, either of the below
Where the entries comprise:
\table
Property | Description | Required | Default
type | Type name: forceCoeffs | yes |
log | Write force data to standard output | no | no
writeFields | Write force,moment coefficient fields | no | no
patches | Patches included in the forces calculation | yes |
magUInf | Free stream velocity magnitude | yes |
rhoInf | Free stream density | for compressible cases |
lRef | Reference length scale for moment calculations | yes |
Aref | Reference area | yes |
porosity | Include porosity contributions | no | false
\endtable
Bin data is optional, but if the dictionary is present, the entries must
be defined according to following:
\table
nBin | Number of data bins | yes |
direction | Direction along which bins are defined | yes |
cumulative | Bin data accumulated with incresing distance | yes |
\endtable
Input of force/moment coefficient directions:
- require an origin, and two orthogonal directions; the remaining orthogonal
direction is determined accordingly.
- can be added by the three options below.
\verbatim
// Option-1, i.e. the centre of rotation
// by inherently using e3=(0 0 1) and e1=(1 0 0)
CofR (0 0 0); // Centre of rotation
dragDir (1 0 0);
liftDir (0 0 1);
\endverbatim
\verbatim
// Option-2, i.e. local coordinate system specification
origin (0 0 0);
e1 (1 0 0);
e3 (0 0 1); // combinations: (e1, e2) or (e2, e3) or (e3, e1)
\endverbatim
e3 (0 0 1); // (e1, e2) or (e2, e3) or (e3, e1)
\verbatim
// Option-3, i.e. general coordinate system specification
coordinateSystem
{
type cartesian;
origin (0 0 0);
rotation
{
type axes;
e1 (1 0 0);
e3 (0 0 1); // combinations: (e1, e2) or (e2, e3) or (e3, e1)
e3 (0 0 1);
e1 (1 0 0); // (e1, e2) or (e2, e3) or (e3, e1)
}
}
// Conditional optional entries
// if directForceDensity == true
fD <word>;
// if directForceDensity == false
p <word>;
U <word>;
rho <word>;
rhoInf <scalar>; // redundant for incompressible-flow cases
pRef <scalar>;
// Inherited entries
...
}
\endverbatim
The default direction relations are shown below:
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: forceCoeffs | word | yes | -
libs | Library name: forces | word | yes | -
patches | Names of operand patches | wordRes | yes | -
coefficients | Names of operand coefficients | wordHashSet | no | -
magUInf | Reference velocity magnitude | scalar | yes | -
lRef | Reference length scale for moment calculations <!--
--> | scalar | yes | -
Aref | Reference area | scalar | yes | -
directForceDensity | Flag to directly supply force density <!--
--> | bool | no | false
porosity | Flag to include porosity contributions | bool | no | false
writeFields | Flag to write force and moment fields | bool | no | false
useNamePrefix | Flag to include prefix for field names | bool | no | false
CofR | Centre of rotation | vector | cndtnl | -
origin | Origin of coordinate system | vector | cndtnl | -
e3 | e3 coordinate axis | vector | cndtnl | -
e1 | e1 coordinate axis | vector | cndtnl | -
coordinateSystem | Coordinate system specifier | dictionary | cndtnl | -
fD | Name of force density field | word | cndtnl-no | fD
p | Name of pressure field | word | cndtnl-no | p
U | Name of velocity field | word | cndtnl-no | U
rho | Name of density field | word | cndtnl-no | rho
rhoInf | Value of reference density | scalar | cndtnl-yes | -
pRef | Value of reference pressure | scalar | cndtnl-no | 0
\endtable
Options for the \c coefficients entry:
\verbatim
Cd | Drag coefficient
Cs | Side-force coefficient
Cl | Lift coefficient
CmRoll | Roll-moment coefficient
CmPitch | Pitch-moment coefficient
CmYaw | Yaw-moment coefficient
Cdf | Front-axle drag coefficient
Csf | Front-axle side-force coefficient
Clf | Front-axle lift coefficient
Cdr | Rear-axle drag coefficient
Csr | Rear-axle side-force coefficient
Clr | Rear-axle lift coefficient
\endverbatim
The inherited entries are elaborated in:
- \link functionObject.H \endlink
- \link writeFile.H \endlink
- \link coordinateSystem.H \endlink
- \link forces.H \endlink
Note
- \c rhoInf is always redundant for incompressible computations.
That is, \c rhoInf is always equal to 1 in incompressible
computations no matter which input value is assigned to \c rhoInf.
The value of \c rhoInf is only used for compressible computations.
- \c writeControl and \c writeInterval entries of function
object do control when to output force and moment files and fields.
- Input for force/moment coefficient directions
require an origin and two orthogonal directions where
the remaining orthogonal direction is automatically computed.
- The default direction relations are shown below:
\table
Property | Description | Alias | Direction
@ -153,20 +221,17 @@ Usage
yawAxis | Yaw axis | e3 | (0 0 1)
\endtable
See also
Foam::functionObject
Foam::functionObjects::timeControl
Foam::functionObjects::forces
SourceFiles
forceCoeffs.C
\*---------------------------------------------------------------------------*/
#ifndef functionObjects_forceCoeffs_H
#define functionObjects_forceCoeffs_H
#ifndef Foam_functionObjects_forceCoeffs_H
#define Foam_functionObjects_forceCoeffs_H
#include "forces.H"
#include "HashSet.H"
#include "Enum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -183,78 +248,261 @@ class forceCoeffs
:
public forces
{
// Private data
public:
// Free-stream conditions
// Container for force and moment components
class forceComponents
{
// Private Data
//- Free-stream velocity magnitude
scalar magUInf_;
//- Pressure force/moment component
vector pressure_;
//- Viscous force/moment component
vector viscous_;
//- Internal force/moment component
vector internal_;
public:
// Constructors
//- Default construct
forceComponents()
:
pressure_(Zero),
viscous_(Zero),
internal_(Zero)
{}
// Member Functions
//- Return the sum of the components
const vector total() const noexcept
{
return pressure_ + viscous_ + internal_;
}
//- Reset the components to zero
void reset() noexcept
{
pressure_ = Zero;
viscous_ = Zero;
internal_ = Zero;
}
//- Reset the components to given values
void reset
(
const vector& pressure,
const vector& viscous,
const vector& internal
) noexcept
{
pressure_ = pressure;
viscous_ = viscous;
internal_ = internal;
}
// Member Operators
//- Return components in a given direction
vector operator[](const label cmpt) const
{
return vector(pressure_[cmpt], viscous_[cmpt], internal_[cmpt]);
}
};
// Coefficients description
struct coeffDesc
{
enum splitType
{
stFront,
stRear,
stNone
};
string desc_;
word name_;
label c0_;
label c1_;
bool active_;
splitType splitType_;
// Constructors
//- Construct from components
coeffDesc
(
const string& description,
const word& name,
const label c0,
const label c1 = -1
)
:
desc_(description),
name_(name),
c0_(c0),
c1_(c1),
active_(false),
splitType_(stNone)
{}
//- Return name with front-name appendix
const word frontName() const noexcept
{
return name_ + "(f)";
}
//- Return name with rear-name appendix
const word rearName() const noexcept
{
return name_ + "(r)";
}
//- Return force/moment components based on the specified split type
vector value(const forceComponents& f, const forceComponents& m) const
{
if (c1_ == -1)
{
return m[c0_];
}
else
{
switch (splitType_)
{
case stFront:
{
return 0.5*f[c0_] + m[c1_];
}
case stRear:
{
return 0.5*f[c0_] - m[c1_];
}
case stNone:
{
return f[c0_];
}
}
}
FatalErrorInFunction
<< "Cannot determine value"
<< abort(FatalError);
return vector::zero;
}
//- Return front-axle coefficient description
coeffDesc front() const
{
coeffDesc coeff(*this);
coeff.name_ = coeff.frontName();
coeff.desc_ = coeff.desc_ + " front";
coeff.splitType_ = stFront;
return coeff;
}
//- Return rear-axle coefficient description
coeffDesc rear() const
{
coeffDesc coeff(*this);
coeff.name_ = coeff.rearName();
coeff.desc_ = coeff.desc_ + " rear";
coeff.splitType_ = stRear;
return coeff;
}
};
private:
// Private Data
//- Force components
forceComponents Cf_;
//- Moment components
forceComponents Cm_;
//- Force coefficient field
volVectorField forceCoeff_;
//- Moment coefficient field
volVectorField momentCoeff_;
//- Operand force and moment coefficients
HashTable<coeffDesc> coeffs_;
// File streams
//- File stream for integrated operand coefficients
autoPtr<OFstream> coeffFilePtr_;
// Reference scales
//- Reference length [m]
//- Reference velocity magnitude [m/s]
scalar magUInf_;
//- Reference length scale [m]
scalar lRef_;
//- Reference area [m^2]
scalar Aref_;
// File streams
//- Integrated coefficients
autoPtr<OFstream> coeffFilePtr_;
//- Drag coefficient
autoPtr<OFstream> CdBinFilePtr_;
//- Side coefficient
autoPtr<OFstream> CsBinFilePtr_;
//- Lift coefficient
autoPtr<OFstream> ClBinFilePtr_;
//- Roll moment coefficient
autoPtr<OFstream> CmRollBinFilePtr_;
//- Pitch moment coefficient
autoPtr<OFstream> CmPitchBinFilePtr_;
//- Yaw moment coefficient
autoPtr<OFstream> CmYawBinFilePtr_;
// Private Member Functions
//- No copy construct
forceCoeffs(const forceCoeffs&) = delete;
//- No copy assignment
void operator=(const forceCoeffs&) = delete;
//- Flag of initialisation (internal)
bool initialised_;
protected:
// Protected Member Functions
//- Create the output files
void createFiles();
//- Initialise containers and fields
void initialise();
//- Write header for integrated data
void writeIntegratedHeader(const word& header, Ostream& os) const;
//- Reset containers and fields
void reset();
//- Write header for binned data
void writeBinHeader(const word& header, Ostream& os) const;
//- Write integrated data
void writeIntegratedData
// Evaluation
//- Return the operand coefficients
HashTable<coeffDesc> selectCoeffs() const;
//- Calculate force coefficients
void calcForceCoeffs();
//- Calculate moment coefficients
void calcMomentCoeffs();
//- Return integrated {total, pressure, viscous, porous} components
List<scalar> integrateData(const List<Field<scalar>>& coeff) const;
// I-O
//- Create the integrated-coefficient file
void createIntegratedDataFile();
//- Write header to the integrated-coefficient file
void writeIntegratedDataFileHeader
(
const word& title,
const List<Field<scalar>>& coeff
const word& header,
OFstream& os
) const;
//- Write binned data
void writeBinData(const List<Field<scalar>> coeffs, Ostream& os) const;
//- Write integrated coefficients to the integrated-coefficient file
void writeIntegratedDataFile();
public:
@ -270,10 +518,16 @@ public:
(
const word& name,
const Time& runTime,
const dictionary&,
const dictionary& dict,
const bool readFields = true
);
//- No copy construct
forceCoeffs(const forceCoeffs&) = delete;
//- No copy assignment
void operator=(const forceCoeffs&) = delete;
//- Destructor
virtual ~forceCoeffs() = default;
@ -281,19 +535,27 @@ public:
// Member Functions
//- Read the forces data
virtual bool read(const dictionary&);
//- Read the dictionary
virtual bool read(const dictionary& dict);
//- Execute
//- Execute the function object
virtual bool execute();
//- Write the forces
//- Write to data files/fields and to streams
virtual bool write();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Ostream& operator<<(Ostream& os, const forceCoeffs::coeffDesc& coeff)
{
os << coeff.desc_.c_str() << ": " << coeff.name_;
return os;
}
} // End namespace functionObjects
} // End namespace Foam

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd.
Copyright (C) 2015-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -31,127 +31,155 @@ Group
grpForcesFunctionObjects
Description
Calculates the forces and moments by integrating the pressure and
skin-friction forces over a given list of patches, and the resistance
from porous zones.
Computes forces and moments over a given list of patches by integrating
pressure and viscous forces and moments, and optionally resistance forces
and moments from porous zones.
Forces and moments are calculated in a global Cartesian coordinate system
by default, or using a user-defined system. Contributions can be 'binned'
according to a user-defined number of uniform-width collection zones (bins)
that span the input geometries, oriented by a user-defined direction vector.
Forces and moments are output in their total and constituent components:
- total forces and moments
- pressure contributions
- viscous contributions
- porous resistance contributions (optional)
Results are written to multiple files as a function of time in the
postProcessing/\<functionObjectName\> directory:
- force.dat : forces
- moment.dat : moments
- forceBin.dat : force bins
- momentBin.dat : moment bins
Forces and moments can be computed and output in:
- the global Cartesian coordinate system (default)
- a user-defined Cartesian coordinate system
Operands:
\table
Operand | Type | Location
input | - | -
output file | dat | postProcessing/\<FO\>/\<time\>/\<file\>s
output field | volVectorField | \<time\>/\<outField\>s
\endtable
where \c \<file\>s:
\verbatim
force.dat | Forces
moment.dat | Moments
\endverbatim
where \c \<outField\>s:
\verbatim
<namePrefix>:force | Force field
<namePrefix>:moment | Moment field
\endverbatim
Usage
Example of function object specification:
Minimal example by using \c system/controlDict.functions:
\verbatim
forces1
<namePrefix>
{
// Mandatory entries
type forces;
libs (forces);
...
log yes;
writeFields yes;
patches (walls);
patches (<wordRes>);
binData
{
nBin 20;
direction (1 0 0);
cumulative yes;
}
}
\endverbatim
// Optional entries
directForceDensity <bool>;
porosity <bool>;
writeFields <bool>;
useNamePrefix <bool>;
Where the entries comprise:
\table
Property | Description | Required | Default value
type | Type name: forces | yes |
log | Write force data to standard output | no | no
writeFields | Write the force and moment fields | no | no
patches | Patches included in the forces calculation | yes |
p | Pressure field name | no | p
U | Velocity field name | no | U
rho | Density field name (see below) | no | rho
CofR | Centre of rotation (see below) | no |
porosity | flag to include porosity contributions | no | no
directForceDensity | Force density supplied directly (see below)|no|no
fD | Name of force density field (see below) | no | fD
\endtable
// Conditional mandatory entries
Bin data is optional, but if the dictionary is present, the entries must
be defined according o
\table
nBin | number of data bins | yes |
direction | direction along which bins are defined | yes |
cumulative | bin data accumulated with incresing distance | yes |
\endtable
// if directForceDensity == true
fD <word>;
Note
- For incompressible cases, set \c rho to \c rhoInf. You will then be
required to provide a \c rhoInf value corresponding to the free-stream
constant density.
- If the force density is supplied directly, set the \c directForceDensity
flag to 'yes', and supply the force density field using the \c
fDName entry
- The centre of rotation (CofR) for moment calculations can either be
specified by an \c CofR entry, or be taken from origin of the local
coordinate system. For example,
\verbatim
CofR (0 0 0);
\endverbatim
or
\verbatim
// Cartesian coordinate system specification when
// evaluating forces and moments, either of the below
// Option-1, i.e. the centre of rotation
// by inherently using e3=(0 0 1) and e1=(1 0 0)
CofR (0 0 0); // Centre of rotation
// Option-2, i.e. local coordinate system specification
origin (0 0 0);
e1 (0 1 0);
e3 (0 0 1);
\endverbatim
or
\verbatim
e1 (1 0 0);
e3 (0 0 1); // (e1, e2) or (e2, e3) or (e3, e1)
// Option-3, i.e. general coordinate system specification
coordinateSystem
{
type cartesian;
origin (0 0 0);
rotation
{
type axes;
e3 (0 0 1);
e1 (1 0 0);
e1 (1 0 0); // (e1, e2) or (e2, e3) or (e3, e1)
}
}
// Conditional optional entries
// if directForceDensity == false
p <word>;
U <word>;
rho <word>;
rhoInf <scalar>; // enabled if rho=rhoInf
pRef <scalar>;
// Inherited entries
...
}
\endverbatim
See also
Foam::functionObject
Foam::functionObjects::fvMeshFunctionObject
Foam::functionObjects::writeFile
Foam::functionObjects::timeControl
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: forces | word | yes | -
libs | Library name: forces | word | yes | -
patches | Names of operand patches | wordRes | yes | -
directForceDensity | Flag to directly supply force density <!--
--> | bool | no | false
porosity | Flag to include porosity contributions | bool | no | false
writeFields | Flag to write force and moment fields | bool | no | false
useNamePrefix | Flag to include prefix for field names | bool | no | false
CofR | Centre of rotation | vector | cndtnl | -
origin | Origin of coordinate system | vector | cndtnl | -
e3 | e3 coordinate axis | vector | cndtnl | -
e1 | e1 coordinate axis | vector | cndtnl | -
coordinateSystem | Coordinate system specifier | dictionary | cndtnl | -
fD | Name of force density field | word | cndtnl | -
p | Name of pressure field | word | cndtnl | p
U | Name of velocity field | word | cndtnl | U
rho | Name of density field | word | cndtnl | rho
rhoInf | Value of reference density | scalar | cndtnl | -
pRef | Value of reference pressure | scalar | cndtnl | 0
\endtable
The inherited entries are elaborated in:
- \link functionObject.H \endlink
- \link writeFile.H \endlink
- \link coordinateSystem.H \endlink
Note
- For incompressible cases, set \c rho to \c rhoInf.
You will then be required to provide a \c rhoInf
value corresponding to the constant freestream density.
- \c writeControl and \c writeInterval entries of function
object do control when to output force and moment files and fields.
SourceFiles
forces.C
\*---------------------------------------------------------------------------*/
#ifndef functionObjects_forces_H
#define functionObjects_forces_H
#ifndef Foam_functionObjects_forces_H
#define Foam_functionObjects_forces_H
#include "fvMeshFunctionObject.H"
#include "writeFile.H"
#include "coordinateSystem.H"
#include "volFieldsFwd.H"
#include "HashSet.H"
#include "Tuple2.H"
#include "OFstream.H"
#include "Switch.H"
#include "volFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
@ -164,107 +192,87 @@ class forces
public fvMeshFunctionObject,
public writeFile
{
protected:
// Protected data
// Protected Data
//- Pressure, viscous and porous force per bin
List<Field<vector>> force_;
// Fields
//- Forces
volVectorField force_;
//- Moments
volVectorField moment_;
//- Sum of patch pressure forces
vector sumPatchForcesP_;
//- Sum of patch viscous forces
vector sumPatchForcesV_;
//- Sum of patch pressure moments
vector sumPatchMomentsP_;
//- Sum of patch viscous moments
vector sumPatchMomentsV_;
//- Sum of internal forces
vector sumInternalForces_;
//- Sum of internal moments
vector sumInternalMoments_;
//- Pressure, viscous and porous moment per bin
List<Field<vector>> moment_;
// File streams
//- Forces
//- File stream for forces
autoPtr<OFstream> forceFilePtr_;
//- Moments
//- File stream for moments
autoPtr<OFstream> momentFilePtr_;
//- Force bins
autoPtr<OFstream> forceBinFilePtr_;
//- Moment bins
autoPtr<OFstream> momentBinFilePtr_;
// Read from dictionary
//- Patches to integrate forces over
//- Coordinate system used when evaluating forces and moments
autoPtr<coordinateSystem> coordSysPtr_;
//- Names of operand patches
labelHashSet patchSet_;
//- Name of pressure field
word pName_;
//- Name of velocity field
word UName_;
//- Name of density field (optional)
word rhoName_;
//- Is the force density being supplied directly?
Switch directForceDensity_;
//- The name of the force density (fD) field
word fDName_;
//- Reference density needed for incompressible calculations
scalar rhoRef_;
//- Reference pressure
scalar pRef_;
//- Coordinate system used when evaluating forces/moments
autoPtr<coordinateSystem> coordSysPtr_;
//- Name of pressure field
word pName_;
//- Name of velocity field
word UName_;
//- Name of density field
word rhoName_;
//- Name of force density field
word fDName_;
//- Flag to directly supply force density
bool directForceDensity_;
//- Flag to include porosity effects
bool porosity_;
// Bin information
//- Number of bins
label nBin_;
//- Direction used to determine bin orientation
vector binDir_;
//- Distance between bin divisions
scalar binDx_;
//- Minimum bin bounds
scalar binMin_;
//- Maximum bin bounds
scalar binMax_;
//- Bin positions along binDir
List<point> binPoints_;
//- Should bin data be cumulative?
bool binCumulative_;
//- Write fields flag
//- Flag to write force and moment fields
bool writeFields_;
//- Initialised flag
//- Flag of initialisation (internal)
bool initialised_;
// Protected Member Functions
//- Create the output files
void createFiles();
//- Write header for integrated data
void writeIntegratedHeader(const word& header, Ostream& os) const;
//- Write header for binned data
void writeBinHeader(const word& header, Ostream& os) const;
//- Set the co-ordinate system from dictionary and axes names
void setCoordinateSystem
(
@ -273,87 +281,80 @@ protected:
const word& e1Name = word::null
);
//- Initialise the fields
//- Initialise containers and fields
void initialise();
//- Initialise the collection bins
void initialiseBins();
//- Reset containers and fields
void reset();
//- Reset the fields prior to accumulation of force/moments
void resetFields();
//- Return the effective viscous stress (laminar + turbulent).
// Evaluation
//- Return the effective stress (viscous + turbulent)
tmp<volSymmTensorField> devRhoReff() const;
//- Dynamic viscosity field
//- Return dynamic viscosity field
tmp<volScalarField> mu() const;
//- Return rho if specified otherwise rhoRef
tmp<volScalarField> rho() const;
//- Return rhoRef if the pressure field is dynamic, i.e. p/rho
// otherwise return 1
//- Return rhoRef if the pressure field is
//- dynamic (i.e. p/rho), otherwise return 1
scalar rho(const volScalarField& p) const;
//- Accumulate bin data
void applyBins
(
const vectorField& Md,
const vectorField& fN,
const vectorField& fT,
const vectorField& fP,
const vectorField& d
);
//- Add patch contributions to force and moment fields
void addToFields
void addToPatchFields
(
const label patchi,
const vectorField& Md,
const vectorField& fN,
const vectorField& fT,
const vectorField& fP
const vectorField& fP,
const vectorField& fV
);
//- Add cell contributions to force and moment fields
void addToFields
//- Add cell contributions to force and
//- moment fields, and include porosity effects
void addToInternalField
(
const labelList& cellIDs,
const vectorField& Md,
const vectorField& fN,
const vectorField& fT,
const vectorField& fP
const vectorField& f
);
//- Helper function to write integrated forces and moments
void writeIntegratedForceMoment
// I-O
//- Create the integrated-data files
void createIntegratedDataFiles();
//- Write header for an integrated-data file
void writeIntegratedDataFileHeader
(
const word& header,
OFstream& os
) const;
//- Write integrated data to files
void writeIntegratedDataFiles();
//- Write integrated data to a file
void writeIntegratedDataFile
(
const vector& pres,
const vector& vis,
const vector& internal,
OFstream& os
) const;
//- Write integrated data to stream
void logIntegratedData
(
const string& descriptor,
const vectorField& fm0,
const vectorField& fm1,
const vectorField& fm2,
autoPtr<OFstream>& osPtr
const vector& pres,
const vector& vis,
const vector& internal
) const;
//- Write force data
void writeForces();
//- Helper function to write binned forces and moments
void writeBinnedForceMoment
(
const List<Field<vector>>& fm,
autoPtr<OFstream>& osPtr
) const;
//- Write binned data
void writeBins();
//- No copy construct
forces(const forces&) = delete;
//- No copy assignment
void operator=(const forces&) = delete;
public:
@ -381,6 +382,12 @@ public:
const bool readFields = true
);
//- No copy construct
forces(const forces&) = delete;
//- No copy assignment
void operator=(const forces&) = delete;
//- Destructor
virtual ~forces() = default;
@ -388,11 +395,11 @@ public:
// Member Functions
//- Read the forces data
virtual bool read(const dictionary&);
//- Read the dictionary
virtual bool read(const dictionary& dict);
//- Calculate the forces and moments
virtual void calcForcesMoment();
//- Calculate forces and moments
virtual void calcForcesMoments();
//- Return the total force
virtual vector forceEff() const;
@ -400,10 +407,10 @@ public:
//- Return the total moment
virtual vector momentEff() const;
//- Execute, currently does nothing
//- Execute the function object
virtual bool execute();
//- Write the forces
//- Write to data files/fields and to streams
virtual bool write();
};

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
Copyright (C) 2021-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -560,8 +560,8 @@ void Foam::functionObjects::propellerInfo::writePropellerPerformance()
// Update n_
setRotationalSpeed();
const vector sumForce(sum(force_[0]) + sum(force_[1]) + sum(force_[2]));
const vector sumMoment(sum(moment_[0]) + sum(moment_[1]) + sum(moment_[2]));
const vector sumForce = forceEff();
const vector sumMoment = momentEff();
const scalar diameter = 2*radius_;
const scalar URef = URefPtr_->value(time_.timeOutputValue());
@ -866,7 +866,7 @@ bool Foam::functionObjects::propellerInfo::read(const dictionary& dict)
bool Foam::functionObjects::propellerInfo::execute()
{
calcForcesMoment();
calcForcesMoments();
createFiles();

View File

@ -304,7 +304,7 @@ void Foam::rigidBodyMeshMotion::solve()
forcesDict.add("CofR", vector::zero);
functionObjects::forces f("forces", db(), forcesDict);
f.calcForcesMoment();
f.calcForcesMoments();
fx[bodyID] = ramp*spatialVector(f.momentEff(), f.forceEff());
}

View File

@ -228,7 +228,7 @@ void Foam::rigidBodyMeshMotionSolver::solve()
forcesDict.add("CofR", vector::zero);
functionObjects::forces f("forces", db(), forcesDict);
f.calcForcesMoment();
f.calcForcesMoments();
fx[bodyID] = spatialVector(f.momentEff(), f.forceEff());
}

View File

@ -221,7 +221,7 @@ void sixDoFRigidBodyDisplacementPointPatchVectorField::updateCoeffs()
functionObjects::forces f("forces", db(), forcesDict);
f.calcForcesMoment();
f.calcForcesMoments();
// Get the forces on the patch faces at the current positions

View File

@ -247,7 +247,7 @@ void Foam::sixDoFRigidBodyMotionSolver::solve()
functionObjects::forces f("forces", db(), forcesDict);
f.calcForcesMoment();
f.calcForcesMoments();
motion_.update
(

View File

@ -27,15 +27,28 @@ forceCoeffs1
magUInf 20;
lRef 1.42; // Wheelbase length
Aref 0.75; // Estimated
}
/*
binField1
{
type binField;
libs (fieldFunctionObjects);
binModel singleDirectionUniformBin;
fields (forceCoeff);
patches (motorBikeGroup);
decomposePatchValues true;
CofR ${..forceCoeffs1.CofR};
binData
{
nBin 20; // output data into 20 bins
direction (1 0 0); // bin direction
cumulative yes;
}
*/
writeControl timeStep;
}
*/
// ************************************************************************* //

View File

@ -27,6 +27,19 @@ forceCoeffs1
lRef 4; // Wheelbase length
Aref 1; // Estimated
porosity on;
}
binField1
{
type binField;
libs (fieldFunctionObjects);
binModel singleDirectionUniformBin;
fields (forceCoeff);
patches (body);
decomposePatchValues yes;
CofR ${..forceCoeffs1.CofR};
cellZones (porousZone);
binData
{
@ -34,6 +47,7 @@ forceCoeffs1
direction (1 0 0); // bin direction
cumulative yes;
}
writeControl writeTime;
}