41 namespace functionObjects
67 else if (
dict.readIfPresent(
"CofR", origin))
78 coordSysPtr_.reset(
new coordSystem::cartesian(origin, e3, e1));
92 auto* forcePtr = mesh_.getObjectPtr<
volVectorField>(scopedName(
"force"));
111 mesh_.objectRegistry::store(forcePtr);
120 auto* momentPtr = mesh_.getObjectPtr<
volVectorField>(scopedName(
"moment"));
128 scopedName(
"moment"),
139 mesh_.objectRegistry::store(momentPtr);
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 : patchSet_)
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")
319 mesh_.time().timeName(),
327 return (lookupObject<volScalarField>(rhoName_));
334 if (rhoName_ ==
"rhoInf")
338 mesh_.boundary()[patchi].size(),
343 const auto&
rho = lookupObject<volScalarField>(rhoName_);
344 return rho.boundaryField()[patchi];
355 if (rhoName_ !=
"rhoInf")
358 <<
"Dynamic pressure is expected but kinematic is provided." 374 constexpr
bool updateAccessTime =
false;
376 sumPatchForcesP_ +=
sum(fP);
377 sumPatchForcesV_ +=
sum(fV);
378 force().boundaryFieldRef(updateAccessTime)[patchi] += fP + fV;
383 sumPatchMomentsP_ +=
sum(mP);
384 sumPatchMomentsV_ +=
sum(mV);
385 moment().boundaryFieldRef(updateAccessTime)[patchi] += mP + mV;
396 auto& force = this->force();
397 auto& moment = this->moment();
401 const label celli =
cellIDs[i];
403 sumInternalForces_ +=
f[i];
404 force[celli] +=
f[i];
407 sumInternalMoments_ += m;
415 if (!forceFilePtr_.valid())
417 forceFilePtr_ = newFileAtStartTime(
"force");
418 writeIntegratedDataFileHeader(
"Force", forceFilePtr_());
421 if (!momentFilePtr_.valid())
423 momentFilePtr_ = newFileAtStartTime(
"moment");
424 writeIntegratedDataFileHeader(
"Moment", momentFilePtr_());
435 const auto& coordSys = coordSysPtr_();
436 const auto vecDesc = [](
const word& root)->
string 438 return root +
"_x " + root +
"_y " + root +
"_z";
441 writeHeaderValue(
os,
"CofR", coordSys.origin());
443 writeCommented(
os,
"Time");
444 writeTabbed(
os, vecDesc(
"total"));
445 writeTabbed(
os, vecDesc(
"pressure"));
446 writeTabbed(
os, vecDesc(
"viscous"));
450 writeTabbed(
os, vecDesc(
"porous"));
459 const auto& coordSys = coordSysPtr_();
461 writeIntegratedDataFile
463 coordSys.localVector(sumPatchForcesP_),
464 coordSys.localVector(sumPatchForcesV_),
465 coordSys.localVector(sumInternalForces_),
469 writeIntegratedDataFile
471 coordSys.localVector(sumPatchMomentsP_),
472 coordSys.localVector(sumPatchMomentsV_),
473 coordSys.localVector(sumInternalMoments_),
487 writeCurrentTime(
os);
489 writeValue(
os, pres + vis +
internal);
490 writeValue(
os, pres);
495 writeValue(
os,
internal);
504 const string& descriptor,
515 Log <<
" Sum of " << descriptor.c_str() <<
nl 516 <<
" Total : " << (pres + vis +
internal) <<
nl 517 <<
" Pressure : " << pres <<
nl 518 <<
" Viscous : " << vis <<
nl;
522 Log <<
" Porous : " <<
internal <<
nl;
538 writeFile(mesh_,
name),
539 sumPatchForcesP_(
Zero),
540 sumPatchForcesV_(
Zero),
541 sumPatchMomentsP_(
Zero),
542 sumPatchMomentsV_(
Zero),
543 sumInternalForces_(
Zero),
544 sumInternalMoments_(
Zero),
547 coordSysPtr_(nullptr),
555 directForceDensity_(false),
577 fvMeshFunctionObject(
name, obr,
dict),
578 writeFile(mesh_,
name),
579 sumPatchForcesP_(
Zero),
580 sumPatchForcesV_(
Zero),
581 sumPatchMomentsP_(
Zero),
582 sumPatchMomentsV_(
Zero),
583 sumInternalForces_(
Zero),
584 sumInternalMoments_(
Zero),
587 coordSysPtr_(nullptr),
595 directForceDensity_(false),
623 mesh_.boundaryMesh().patchSet
625 dict.get<wordRes>(
"patches")
628 dict.readIfPresent(
"directForceDensity", directForceDensity_);
629 if (directForceDensity_)
632 if (
dict.readIfPresent<word>(
"fD", fDName_))
640 if (
dict.readIfPresent<word>(
"p", pName_))
644 if (
dict.readIfPresent<word>(
"U", UName_))
648 if (
dict.readIfPresent<word>(
"rho", rhoName_))
650 Info<<
" rho: " << rhoName_ <<
endl;
654 if (rhoName_ ==
"rhoInf")
657 Info<<
" Freestream density (rhoInf) set to " << rhoRef_ <<
endl;
661 if (
dict.readIfPresent<scalar>(
"pRef", pRef_))
663 Info<<
" Reference pressure (pRef) set to " << pRef_ <<
endl;
667 dict.readIfPresent(
"porosity", porosity_);
670 Info<<
" Including porosity effects" <<
endl;
674 Info<<
" Not including porosity effects" <<
endl;
677 writeFields_ =
dict.getOrDefault(
"writeFields",
false);
680 Info<<
" Fields will be written" <<
endl;
694 const point& origin = coordSysPtr_->origin();
696 if (directForceDensity_)
698 const auto& fD = lookupObject<volVectorField>(fDName_);
699 const auto& fDb = fD.boundaryField();
701 const auto& Sfb = mesh_.Sf().boundaryField();
702 const auto& magSfb = mesh_.magSf().boundaryField();
703 const auto&
Cb = mesh_.C().boundaryField();
705 for (
const label patchi : patchSet_)
712 Sfb[patchi]/magSfb[patchi]
714 Sfb[patchi] & fDb[patchi]
719 const vectorField fV(magSfb[patchi]*fDb[patchi] - fP);
721 addToPatchFields(patchi, Md, fP, fV);
726 const auto&
p = lookupObject<volScalarField>(pName_);
727 const auto& pb =
p.boundaryField();
729 const auto& Sfb = mesh_.Sf().boundaryField();
730 const auto&
Cb = mesh_.C().boundaryField();
732 const auto&
U = lookupObject<volVectorField>(UName_);
735 const auto& gradUb = gradU.boundaryField();
738 const scalar rhoRef =
rho(
p);
739 const scalar pRef = pRef_/rhoRef;
741 for (
const label patchi : patchSet_)
745 const vectorField fP(rhoRef*Sfb[patchi]*(pb[patchi] - pRef));
749 Sfb[patchi] & devRhoReff(gradUb[patchi], patchi)
752 addToPatchFields(patchi, Md, fP, fV);
758 const auto&
U = lookupObject<volVectorField>(UName_);
762 const auto models = obr_.lookupClass<porosityModel>();
767 <<
"Porosity effects requested, " 768 <<
"but no porosity models found in the database" 775 auto& pm =
const_cast<porosityModel&
>(*iter());
779 const labelList& cellZoneIDs = pm.cellZoneIDs();
781 for (
const label zonei : cellZoneIDs)
783 const cellZone& cZone = mesh_.cellZones()[zonei];
789 addToInternalField(cZone, Md, fP);
794 reduce(sumPatchForcesP_, sumOp<vector>());
795 reduce(sumPatchForcesV_, sumOp<vector>());
805 return sumPatchForcesP_ + sumPatchForcesV_ + sumInternalForces_;
811 return sumPatchMomentsP_ + sumPatchMomentsV_ + sumInternalMoments_;
821 const auto& coordSys = coordSysPtr_();
823 const auto localFp(coordSys.localVector(sumPatchForcesP_));
824 const auto localFv(coordSys.localVector(sumPatchForcesV_));
825 const auto localFi(coordSys.localVector(sumInternalForces_));
827 logIntegratedData(
"forces", localFp, localFv, localFi);
829 const auto localMp(coordSys.localVector(sumPatchMomentsP_));
830 const auto localMv(coordSys.localVector(sumPatchMomentsV_));
831 const auto localMi(coordSys.localVector(sumInternalMoments_));
833 logIntegratedData(
"moments", localMp, localMv, localMi);
835 setResult(
"pressureForce", localFp);
836 setResult(
"viscousForce", localFv);
837 setResult(
"internalForce", localFi);
838 setResult(
"pressureMoment", localMp);
839 setResult(
"viscousMoment", localMv);
840 setResult(
"internalMoment", localMi);
850 Log <<
" writing force and moment files." <<
endl;
852 createIntegratedDataFiles();
853 writeIntegratedDataFiles();
858 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)
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, using an OSstream.
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)...
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 INVALID.
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.
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...
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
static const GeometricField< symmTensor, fvPatchField, volMesh > & null()
Return a null geometric field.
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.
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
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.
void readFields(const typename GeoFieldType::Mesh &mesh, const IOobjectList &objects, const wordHashSet &selectedFields, LIFOStack< regIOobject *> &storedObjects)
Read the selected GeometricFields of the templated type.
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)
virtual bool write()
Write to data files/fields and to streams.
forAllConstIters(mixture.phases(), phase)
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)