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 : 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")
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;
417 forceFilePtr_ = newFileAtStartTime(
"force");
418 writeIntegratedDataFileHeader(
"Force", forceFilePtr_());
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),
554 directForceDensity_(false),
576 fvMeshFunctionObject(
name, obr,
dict),
577 writeFile(mesh_,
name),
578 sumPatchForcesP_(
Zero),
579 sumPatchForcesV_(
Zero),
580 sumPatchMomentsP_(
Zero),
581 sumPatchMomentsV_(
Zero),
582 sumInternalForces_(
Zero),
583 sumInternalMoments_(
Zero),
586 coordSysPtr_(nullptr),
593 directForceDensity_(false),
623 patchIDs_ =
pbm.patchSet(
dict.get<wordRes>(
"patches")).sortedToc();
625 dict.readIfPresent(
"directForceDensity", directForceDensity_);
626 if (directForceDensity_)
629 if (
dict.readIfPresent<word>(
"fD", fDName_))
637 if (
dict.readIfPresent<word>(
"p", pName_))
641 if (
dict.readIfPresent<word>(
"U", UName_))
645 if (
dict.readIfPresent<word>(
"rho", rhoName_))
647 Info<<
" rho: " << rhoName_ <<
endl;
651 if (rhoName_ ==
"rhoInf")
654 Info<<
" Freestream density (rhoInf) set to " << rhoRef_ <<
endl;
658 if (
dict.readIfPresent<scalar>(
"pRef", pRef_))
660 Info<<
" Reference pressure (pRef) set to " << pRef_ <<
endl;
664 dict.readIfPresent(
"porosity", porosity_);
667 Info<<
" Including porosity effects" <<
endl;
671 Info<<
" Not including porosity effects" <<
endl;
674 writeFields_ =
dict.getOrDefault(
"writeFields",
false);
677 Info<<
" Fields will be written" <<
endl;
691 const point& origin = coordSysPtr_->origin();
693 if (directForceDensity_)
695 const auto& fD = lookupObject<volVectorField>(fDName_);
696 const auto& fDb = fD.boundaryField();
698 const auto& Sfb = mesh_.Sf().boundaryField();
699 const auto& magSfb = mesh_.magSf().boundaryField();
700 const auto&
Cb = mesh_.C().boundaryField();
702 for (
const label patchi : patchIDs_)
709 Sfb[patchi]/magSfb[patchi]
711 Sfb[patchi] & fDb[patchi]
716 const vectorField fV(magSfb[patchi]*fDb[patchi] - fP);
718 addToPatchFields(patchi, Md, fP, fV);
723 const auto&
p = lookupObject<volScalarField>(pName_);
724 const auto& pb =
p.boundaryField();
726 const auto& Sfb = mesh_.Sf().boundaryField();
727 const auto&
Cb = mesh_.C().boundaryField();
729 const auto&
U = lookupObject<volVectorField>(UName_);
732 const auto& gradUb = gradU.boundaryField();
735 const scalar rhoRef =
rho(
p);
736 const scalar pRef = pRef_/rhoRef;
738 for (
const label patchi : patchIDs_)
742 const vectorField fP(rhoRef*Sfb[patchi]*(pb[patchi] - pRef));
746 Sfb[patchi] & devRhoReff(gradUb[patchi], patchi)
749 addToPatchFields(patchi, Md, fP, fV);
755 const auto&
U = lookupObject<volVectorField>(UName_);
759 const UPtrList<const porosityModel> models
761 obr_.csorted<porosityModel>()
767 <<
"Porosity effects requested, " 768 <<
"but no porosity models found in the database" 772 for (
const porosityModel& mdl : models)
775 auto& pm =
const_cast<porosityModel&
>(mdl);
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)
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, 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 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.
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...
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.
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.
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)