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 for (
const label patchi : patchIDs_)
210 force.boundaryField().constCast()[patchi] =
Zero;
211 moment.boundaryField().constCast()[patchi] =
Zero;
227 if (
const auto* turbp = cfindObject<icoModel>(icoModel::propertiesName))
229 const auto&
turb = *turbp;
234 if (
const auto* turbp = cfindObject<cmpModel>(cmpModel::propertiesName))
236 const auto&
turb = *turbp;
243 const auto&
thermo = *thermop;
248 if (
const auto* props = cfindObject<transportModel>(
"transportProperties"))
250 const auto& laminarT = *props;
255 if (
const auto* props = cfindObject<dictionary>(
"transportProperties"))
264 <<
"No valid model for viscous stress calculation" 275 const auto&
thermo = *thermop;
280 if (
const auto* props = cfindObject<transportModel>(
"transportProperties"))
282 const auto& laminarT = *props;
284 return rho()*laminarT.nu();
287 if (
const auto* props = cfindObject<dictionary>(
"transportProperties"))
296 <<
"No valid model for dynamic viscosity calculation" 305 if (rhoName_ ==
"rhoInf")
316 return lookupObject<volScalarField>(rhoName_);
323 if (rhoName_ ==
"rhoInf")
327 mesh_.boundary()[patchi].size(),
332 const auto&
rho = lookupObject<volScalarField>(rhoName_);
333 return rho.boundaryField()[patchi];
344 if (rhoName_ !=
"rhoInf")
347 <<
"Dynamic pressure is expected but kinematic is provided." 363 sumPatchForcesP_ +=
sum(fP);
364 sumPatchForcesV_ +=
sum(fV);
365 force().boundaryField().constCast()[patchi] += fP + fV;
370 sumPatchMomentsP_ +=
sum(mP);
371 sumPatchMomentsV_ +=
sum(mV);
372 moment().boundaryField().constCast()[patchi] += mP + mV;
383 auto& force = this->force();
384 auto& moment = this->moment();
388 const label celli =
cellIDs[i];
390 sumInternalForces_ +=
f[i];
391 force[celli] +=
f[i];
394 sumInternalMoments_ += m;
404 forceFilePtr_ = newFileAtStartTime(
"force");
405 writeIntegratedDataFileHeader(
"Force", forceFilePtr_());
410 momentFilePtr_ = newFileAtStartTime(
"moment");
411 writeIntegratedDataFileHeader(
"Moment", momentFilePtr_());
422 const auto& coordSys = coordSysPtr_();
423 const auto vecDesc = [](
const word& root)->
string 425 return root +
"_x " + root +
"_y " + root +
"_z";
428 writeHeaderValue(
os,
"CofR", coordSys.origin());
430 writeCommented(
os,
"Time");
431 writeTabbed(
os, vecDesc(
"total"));
432 writeTabbed(
os, vecDesc(
"pressure"));
433 writeTabbed(
os, vecDesc(
"viscous"));
437 writeTabbed(
os, vecDesc(
"porous"));
446 const auto& coordSys = coordSysPtr_();
448 writeIntegratedDataFile
450 coordSys.localVector(sumPatchForcesP_),
451 coordSys.localVector(sumPatchForcesV_),
452 coordSys.localVector(sumInternalForces_),
456 writeIntegratedDataFile
458 coordSys.localVector(sumPatchMomentsP_),
459 coordSys.localVector(sumPatchMomentsV_),
460 coordSys.localVector(sumInternalMoments_),
474 writeCurrentTime(
os);
476 writeValue(
os, pres + vis +
internal);
477 writeValue(
os, pres);
482 writeValue(
os,
internal);
491 const string& descriptor,
502 Log <<
" Sum of " << descriptor.c_str() <<
nl 503 <<
" Total : " << (pres + vis +
internal) <<
nl 504 <<
" Pressure : " << pres <<
nl 505 <<
" Viscous : " << vis <<
nl;
509 Log <<
" Porous : " <<
internal <<
nl;
525 writeFile(mesh_,
name),
526 sumPatchForcesP_(
Zero),
527 sumPatchForcesV_(
Zero),
528 sumPatchMomentsP_(
Zero),
529 sumPatchMomentsV_(
Zero),
530 sumInternalForces_(
Zero),
531 sumInternalMoments_(
Zero),
534 coordSysPtr_(nullptr),
541 directForceDensity_(false),
563 fvMeshFunctionObject(
name, obr,
dict),
564 writeFile(mesh_,
name),
565 sumPatchForcesP_(
Zero),
566 sumPatchForcesV_(
Zero),
567 sumPatchMomentsP_(
Zero),
568 sumPatchMomentsV_(
Zero),
569 sumInternalForces_(
Zero),
570 sumInternalMoments_(
Zero),
573 coordSysPtr_(nullptr),
580 directForceDensity_(false),
610 patchIDs_ =
pbm.patchSet(
dict.get<wordRes>(
"patches")).sortedToc();
612 dict.readIfPresent(
"directForceDensity", directForceDensity_);
613 if (directForceDensity_)
616 if (
dict.readIfPresent<word>(
"fD", fDName_))
624 if (
dict.readIfPresent<word>(
"p", pName_))
628 if (
dict.readIfPresent<word>(
"U", UName_))
632 if (
dict.readIfPresent<word>(
"rho", rhoName_))
634 Info<<
" rho: " << rhoName_ <<
endl;
638 if (rhoName_ ==
"rhoInf")
641 Info<<
" Freestream density (rhoInf) set to " << rhoRef_ <<
endl;
645 if (
dict.readIfPresent<scalar>(
"pRef", pRef_))
647 Info<<
" Reference pressure (pRef) set to " << pRef_ <<
endl;
651 dict.readIfPresent(
"porosity", porosity_);
654 Info<<
" Including porosity effects" <<
endl;
658 Info<<
" Not including porosity effects" <<
endl;
661 writeFields_ =
dict.getOrDefault(
"writeFields",
false);
664 Info<<
" Fields will be written" <<
endl;
678 const point& origin = coordSysPtr_->origin();
680 if (directForceDensity_)
682 const auto& fD = lookupObject<volVectorField>(fDName_);
683 const auto& fDb = fD.boundaryField();
685 const auto& Sfb = mesh_.Sf().boundaryField();
686 const auto& magSfb = mesh_.magSf().boundaryField();
687 const auto&
Cb = mesh_.C().boundaryField();
689 for (
const label patchi : patchIDs_)
696 Sfb[patchi]/magSfb[patchi]
698 Sfb[patchi] & fDb[patchi]
703 const vectorField fV(magSfb[patchi]*fDb[patchi] - fP);
705 addToPatchFields(patchi, Md, fP, fV);
710 const auto&
p = lookupObject<volScalarField>(pName_);
711 const auto& pb =
p.boundaryField();
713 const auto& Sfb = mesh_.Sf().boundaryField();
714 const auto&
Cb = mesh_.C().boundaryField();
716 const auto&
U = lookupObject<volVectorField>(UName_);
719 const auto& gradUb = gradU.boundaryField();
722 const scalar rhoRef =
rho(
p);
723 const scalar pRef = pRef_/rhoRef;
725 for (
const label patchi : patchIDs_)
729 const vectorField fP(rhoRef*Sfb[patchi]*(pb[patchi] - pRef));
733 Sfb[patchi] & devRhoReff(gradUb[patchi], patchi)
736 addToPatchFields(patchi, Md, fP, fV);
742 const auto&
U = lookupObject<volVectorField>(UName_);
746 const UPtrList<const porosityModel> models
748 obr_.csorted<porosityModel>()
754 <<
"Porosity effects requested, " 755 <<
"but no porosity models found in the database" 759 for (
const porosityModel& mdl : models)
762 auto& pm =
const_cast<porosityModel&
>(mdl);
766 const labelList& cellZoneIDs = pm.cellZoneIDs();
768 for (
const label zonei : cellZoneIDs)
770 const cellZone& cZone = mesh_.cellZones()[zonei];
776 addToInternalField(cZone, Md, fP);
781 reduce(sumPatchForcesP_, sumOp<vector>());
782 reduce(sumPatchForcesV_, sumOp<vector>());
792 return sumPatchForcesP_ + sumPatchForcesV_ + sumInternalForces_;
798 return sumPatchMomentsP_ + sumPatchMomentsV_ + sumInternalMoments_;
808 const auto& coordSys = coordSysPtr_();
810 const auto localFp(coordSys.localVector(sumPatchForcesP_));
811 const auto localFv(coordSys.localVector(sumPatchForcesV_));
812 const auto localFi(coordSys.localVector(sumInternalForces_));
814 logIntegratedData(
"forces", localFp, localFv, localFi);
816 const auto localMp(coordSys.localVector(sumPatchMomentsP_));
817 const auto localMv(coordSys.localVector(sumPatchMomentsV_));
818 const auto localMi(coordSys.localVector(sumInternalMoments_));
820 logIntegratedData(
"moments", localMp, localMv, localMi);
822 setResult(
"pressureForce", localFp);
823 setResult(
"viscousForce", localFv);
824 setResult(
"internalForce", localFi);
825 setResult(
"pressureMoment", localMp);
826 setResult(
"viscousMoment", localMv);
827 setResult(
"internalMoment", localMi);
837 Log <<
" writing force and moment files." <<
endl;
839 createIntegratedDataFiles();
840 writeIntegratedDataFiles();
845 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)
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.
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1, const label comm)
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 reduce(T &value, [[maybe_unused]] BinaryOp bop, [[maybe_unused]] const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce)
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.
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
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 registered IO, a reference to the associated polyMesh...
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)
limits reset(1/(limits.max()+VSMALL), 1/(limits.min()+VSMALL))
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)
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)