41 namespace functionObjects
67 else if (
dict.readIfPresent(
"CofR", origin))
78 coordSysPtr_.reset(
new coordSystem::cartesian(origin, e3, e1));
92 auto* ptr = mesh_.getObjectPtr<
volVectorField>(scopedName(
"force"));
120 auto* ptr = mesh_.getObjectPtr<
volVectorField>(scopedName(
"moment"));
128 scopedName(
"moment"),
153 if (directForceDensity_)
155 if (!foundObject<volVectorField>(fDName_))
158 <<
"Could not find " << fDName_ <<
" in database" 166 !foundObject<volVectorField>(UName_)
167 || !foundObject<volScalarField>(pName_)
171 <<
"Could not find U: " << UName_
172 <<
" or p:" << pName_ <<
" in database" 176 if (rhoName_ !=
"rhoInf" && !foundObject<volScalarField>(rhoName_))
179 <<
"Could not find rho:" << rhoName_ <<
" in database" 190 sumPatchForcesP_ =
Zero;
191 sumPatchForcesV_ =
Zero;
192 sumPatchMomentsP_ =
Zero;
193 sumPatchMomentsV_ =
Zero;
195 sumInternalForces_ =
Zero;
196 sumInternalMoments_ =
Zero;
198 auto& force = this->force();
199 auto& moment = this->moment();
208 constexpr
bool updateAccessTime =
false;
209 for (
const label patchi : patchIDs_)
211 force.boundaryFieldRef(updateAccessTime)[patchi] =
Zero;
212 moment.boundaryFieldRef(updateAccessTime)[patchi] =
Zero;
228 if (foundObject<icoTurbModel>(icoTurbModel::propertiesName))
231 lookupObject<icoTurbModel>(icoTurbModel::propertiesName);
235 else if (foundObject<cmpTurbModel>(cmpTurbModel::propertiesName))
238 lookupObject<cmpTurbModel>(cmpTurbModel::propertiesName);
248 else if (foundObject<transportModel>(
"transportProperties"))
250 const auto& laminarT =
251 lookupObject<transportModel>(
"transportProperties");
255 else if (foundObject<dictionary>(
"transportProperties"))
258 lookupObject<dictionary>(
"transportProperties");
267 <<
"No valid model for viscous stress calculation" 283 else if (foundObject<transportModel>(
"transportProperties"))
285 const auto& laminarT =
286 lookupObject<transportModel>(
"transportProperties");
288 return rho()*laminarT.nu();
290 else if (foundObject<dictionary>(
"transportProperties"))
293 lookupObject<dictionary>(
"transportProperties");
302 <<
"No valid model for dynamic viscosity calculation" 312 if (rhoName_ ==
"rhoInf")
323 return (lookupObject<volScalarField>(rhoName_));
330 if (rhoName_ ==
"rhoInf")
334 mesh_.boundary()[patchi].size(),
339 const auto&
rho = lookupObject<volScalarField>(rhoName_);
340 return rho.boundaryField()[patchi];
351 if (rhoName_ !=
"rhoInf")
354 <<
"Dynamic pressure is expected but kinematic is provided." 370 constexpr
bool updateAccessTime =
false;
372 sumPatchForcesP_ +=
sum(fP);
373 sumPatchForcesV_ +=
sum(fV);
374 force().boundaryFieldRef(updateAccessTime)[patchi] += fP + fV;
379 sumPatchMomentsP_ +=
sum(mP);
380 sumPatchMomentsV_ +=
sum(mV);
381 moment().boundaryFieldRef(updateAccessTime)[patchi] += mP + mV;
392 auto& force = this->force();
393 auto& moment = this->moment();
397 const label celli =
cellIDs[i];
399 sumInternalForces_ +=
f[i];
400 force[celli] +=
f[i];
403 sumInternalMoments_ += m;
413 forceFilePtr_ = newFileAtStartTime(
"force");
414 writeIntegratedDataFileHeader(
"Force", forceFilePtr_());
419 momentFilePtr_ = newFileAtStartTime(
"moment");
420 writeIntegratedDataFileHeader(
"Moment", momentFilePtr_());
431 const auto& coordSys = coordSysPtr_();
432 const auto vecDesc = [](
const word& root)->
string 434 return root +
"_x " + root +
"_y " + root +
"_z";
437 writeHeaderValue(
os,
"CofR", coordSys.origin());
439 writeCommented(
os,
"Time");
440 writeTabbed(
os, vecDesc(
"total"));
441 writeTabbed(
os, vecDesc(
"pressure"));
442 writeTabbed(
os, vecDesc(
"viscous"));
446 writeTabbed(
os, vecDesc(
"porous"));
455 const auto& coordSys = coordSysPtr_();
457 writeIntegratedDataFile
459 coordSys.localVector(sumPatchForcesP_),
460 coordSys.localVector(sumPatchForcesV_),
461 coordSys.localVector(sumInternalForces_),
465 writeIntegratedDataFile
467 coordSys.localVector(sumPatchMomentsP_),
468 coordSys.localVector(sumPatchMomentsV_),
469 coordSys.localVector(sumInternalMoments_),
483 writeCurrentTime(
os);
485 writeValue(
os, pres + vis +
internal);
486 writeValue(
os, pres);
491 writeValue(
os,
internal);
500 const string& descriptor,
511 Log <<
" Sum of " << descriptor.c_str() <<
nl 512 <<
" Total : " << (pres + vis +
internal) <<
nl 513 <<
" Pressure : " << pres <<
nl 514 <<
" Viscous : " << vis <<
nl;
518 Log <<
" Porous : " <<
internal <<
nl;
534 writeFile(mesh_,
name),
535 sumPatchForcesP_(
Zero),
536 sumPatchForcesV_(
Zero),
537 sumPatchMomentsP_(
Zero),
538 sumPatchMomentsV_(
Zero),
539 sumInternalForces_(
Zero),
540 sumInternalMoments_(
Zero),
543 coordSysPtr_(nullptr),
550 directForceDensity_(false),
572 fvMeshFunctionObject(
name, obr,
dict),
573 writeFile(mesh_,
name),
574 sumPatchForcesP_(
Zero),
575 sumPatchForcesV_(
Zero),
576 sumPatchMomentsP_(
Zero),
577 sumPatchMomentsV_(
Zero),
578 sumInternalForces_(
Zero),
579 sumInternalMoments_(
Zero),
582 coordSysPtr_(nullptr),
589 directForceDensity_(false),
619 patchIDs_ =
pbm.patchSet(
dict.get<wordRes>(
"patches")).sortedToc();
621 dict.readIfPresent(
"directForceDensity", directForceDensity_);
622 if (directForceDensity_)
625 if (
dict.readIfPresent<word>(
"fD", fDName_))
633 if (
dict.readIfPresent<word>(
"p", pName_))
637 if (
dict.readIfPresent<word>(
"U", UName_))
641 if (
dict.readIfPresent<word>(
"rho", rhoName_))
643 Info<<
" rho: " << rhoName_ <<
endl;
647 if (rhoName_ ==
"rhoInf")
650 Info<<
" Freestream density (rhoInf) set to " << rhoRef_ <<
endl;
654 if (
dict.readIfPresent<scalar>(
"pRef", pRef_))
656 Info<<
" Reference pressure (pRef) set to " << pRef_ <<
endl;
660 dict.readIfPresent(
"porosity", porosity_);
663 Info<<
" Including porosity effects" <<
endl;
667 Info<<
" Not including porosity effects" <<
endl;
670 writeFields_ =
dict.getOrDefault(
"writeFields",
false);
673 Info<<
" Fields will be written" <<
endl;
687 const point& origin = coordSysPtr_->origin();
689 if (directForceDensity_)
691 const auto& fD = lookupObject<volVectorField>(fDName_);
692 const auto& fDb = fD.boundaryField();
694 const auto& Sfb = mesh_.Sf().boundaryField();
695 const auto& magSfb = mesh_.magSf().boundaryField();
696 const auto&
Cb = mesh_.C().boundaryField();
698 for (
const label patchi : patchIDs_)
705 Sfb[patchi]/magSfb[patchi]
707 Sfb[patchi] & fDb[patchi]
712 const vectorField fV(magSfb[patchi]*fDb[patchi] - fP);
714 addToPatchFields(patchi, Md, fP, fV);
719 const auto&
p = lookupObject<volScalarField>(pName_);
720 const auto& pb =
p.boundaryField();
722 const auto& Sfb = mesh_.Sf().boundaryField();
723 const auto&
Cb = mesh_.C().boundaryField();
725 const auto&
U = lookupObject<volVectorField>(UName_);
728 const auto& gradUb = gradU.boundaryField();
731 const scalar rhoRef =
rho(
p);
732 const scalar pRef = pRef_/rhoRef;
734 for (
const label patchi : patchIDs_)
738 const vectorField fP(rhoRef*Sfb[patchi]*(pb[patchi] - pRef));
742 Sfb[patchi] & devRhoReff(gradUb[patchi], patchi)
745 addToPatchFields(patchi, Md, fP, fV);
751 const auto&
U = lookupObject<volVectorField>(UName_);
755 const UPtrList<const porosityModel> models
757 obr_.csorted<porosityModel>()
763 <<
"Porosity effects requested, " 764 <<
"but no porosity models found in the database" 768 for (
const porosityModel& mdl : models)
771 auto& pm =
const_cast<porosityModel&
>(mdl);
775 const labelList& cellZoneIDs = pm.cellZoneIDs();
777 for (
const label zonei : cellZoneIDs)
779 const cellZone& cZone = mesh_.cellZones()[zonei];
785 addToInternalField(cZone, Md, fP);
790 reduce(sumPatchForcesP_, sumOp<vector>());
791 reduce(sumPatchForcesV_, sumOp<vector>());
801 return sumPatchForcesP_ + sumPatchForcesV_ + sumInternalForces_;
807 return sumPatchMomentsP_ + sumPatchMomentsV_ + sumInternalMoments_;
817 const auto& coordSys = coordSysPtr_();
819 const auto localFp(coordSys.localVector(sumPatchForcesP_));
820 const auto localFv(coordSys.localVector(sumPatchForcesV_));
821 const auto localFi(coordSys.localVector(sumInternalForces_));
823 logIntegratedData(
"forces", localFp, localFv, localFi);
825 const auto localMp(coordSys.localVector(sumPatchMomentsP_));
826 const auto localMv(coordSys.localVector(sumPatchMomentsV_));
827 const auto localMi(coordSys.localVector(sumInternalMoments_));
829 logIntegratedData(
"moments", localMp, localMv, localMi);
831 setResult(
"pressureForce", localFp);
832 setResult(
"viscousForce", localFv);
833 setResult(
"internalForce", localFi);
834 setResult(
"pressureMoment", localMp);
835 setResult(
"viscousMoment", localMv);
836 setResult(
"internalMoment", localMi);
846 Log <<
" writing force and moment files." <<
endl;
848 createIntegratedDataFiles();
849 writeIntegratedDataFiles();
854 Log <<
" writing force and moment fields." <<
endl;
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
virtual vector momentEff() const
Return the total moment.
word dictName() const
The local dictionary name (final part of scoped name)
const polyBoundaryMesh & pbm
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
defineTypeNameAndDebug(ObukhovLength, 0)
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1)
static bool initialised_(false)
static void writeHeader(Ostream &os, const word &fieldName)
dimensionedScalar log(const dimensionedScalar &ds)
errorManipArg< error, int > exit(error &err, const int errNo=1)
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
GeometricField< tensor, fvPatchField, volMesh > volTensorField
Output to file stream as an OSstream, normally using std::ofstream for the actual output...
constexpr char nl
The newline '\n' character (0x0a)
const dimensionSet dimViscosity
compressible::turbulenceModel & turb
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
ThermalDiffusivity< CompressibleTurbulenceModel< fluidThermo > > turbulenceModel
Ostream & endl(Ostream &os)
Add newline and flush stream.
volVectorField & force()
Return access to the force field.
An indexed form of CGAL::Triangulation_cell_base_3<K> used to keep track of the Delaunay cells (tets)...
bool store()
Register object with its registry and transfer ownership to the registry.
virtual vector forceEff() const
Return the total force.
IncompressibleTurbulenceModel< transportModel > turbulenceModel
Ignore writing from objectRegistry::writeObject()
GeometricField< vector, fvPatchField, volMesh > volVectorField
void addToPatchFields(const label patchi, const vectorField &Md, const vectorField &fP, const vectorField &fV)
Add patch contributions to force and moment fields.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
virtual bool read(const dictionary &dict)
Read the dictionary.
void writeIntegratedDataFiles()
Write integrated data to files.
Macros for easy insertion into run-time selection tables.
tmp< symmTensorField > devRhoReff(const tensorField &gradUp, const label patchi) const
Return the effective stress (viscous + turbulent) for patch.
void writeIntegratedDataFile(const vector &pres, const vector &vis, const vector &internal, OFstream &os) const
Write integrated data to a file.
#define forAll(list, i)
Loop across all elements in list.
A Cartesian coordinate system.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
psiReactionThermo & thermo
virtual bool execute()
Execute the function object.
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
virtual void calcForcesMoments()
Calculate forces and moments.
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
void readFields(const typename GeoFieldType::Mesh &mesh, const IOobjectList &objects, const NameMatchPredicate &selectedFields, DynamicList< regIOobject *> &storedObjects)
Read the selected GeometricFields of the templated type and store on the objectRegistry.
Calculate the gradient of the given field.
A class for handling words, derived from Foam::string.
tmp< volScalarField > mu() const
Return dynamic viscosity field.
static MinMax< scalar > ge(const scalar &minVal)
A semi-infinite range from minVal to the type max.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
static const GeometricField< symmTensor, fvPatchField, volMesh > & null() noexcept
Return a null GeometricField (reference to a nullObject).
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
IOdictionary transportProperties(IOobject("transportProperties", runTime.constant(), mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
void addToInternalField(const labelList &cellIDs, const vectorField &Md, const vectorField &f)
Add cell contributions to force and moment fields, and include porosity effects.
tmp< volScalarField > rho() const
Return rho if specified otherwise rhoRef.
const dimensionSet dimPressure
void createIntegratedDataFiles()
Create the integrated-data files.
volVectorField & moment()
Return access to the moment field.
Basic thermodynamics type based on the use of fitting functions for cp, h, s obtained from the templa...
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
static tmp< GeometricField< scalar, fvPatchField, volMesh > > New(const word &name, IOobjectOption::registerOption regOpt, const Mesh &mesh, const dimensionSet &dims, const word &patchFieldType=fvPatchField< scalar >::calculatedType())
Return tmp field (NO_READ, NO_WRITE) from name, mesh, dimensions and patch type. [Takes current timeN...
const dimensionSet dimForce
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
void reset()
Reset containers and fields.
void initialise()
Initialise containers and fields.
OBJstream os(runTime.globalPath()/outputName)
addToRunTimeSelectionTable(functionObject, ObukhovLength, dictionary)
virtual bool read(const dictionary &dict)
Read.
void setCoordinateSystem(const dictionary &dict, const word &e3Name=word::null, const word &e1Name=word::null)
Set the co-ordinate system from dictionary and axes names.
const dimensionSet dimDensity
const dimensionedScalar mu
Atomic mass unit.
Field< tensor > tensorField
Specialisation of Field<T> for tensor.
autoPtr< coordinateSystem > coordSysPtr_
Coordinate system used when evaluating forces and moments.
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
forces(const word &name, const Time &runTime, const dictionary &dict, const bool readFields=true)
Construct from Time and dictionary.
const objectRegistry & obr_
Reference to the region objectRegistry.
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual bool read(const dictionary &dict)
Read optional controls.
Field< vector > vectorField
Specialisation of Field<T> for vector.
List< label > labelList
A List of labels.
A class for managing temporary objects.
void writeIntegratedDataFileHeader(const word &header, OFstream &os) const
Write header for an integrated-data file.
Registry of regIOobjects.
Defines the attributes of an object for which implicit objectRegistry management is supported...
void logIntegratedData(const string &descriptor, const vector &pres, const vector &vis, const vector &internal) const
Write integrated data to stream.
Request registration (bool: true)
Do not request registration (bool: false)
void reduce(T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) using linear/tree communication schedule.
virtual bool write()
Write to data files/fields and to streams.
SymmTensor< Cmpt > devTwoSymm(const SymmTensor< Cmpt > &st)
Return the deviatoric part of twice the symmetric part of a SymmTensor.
static constexpr const zero Zero
Global zero (0)