43namespace functionObjects
53 { rotationMode::SPECIFIED,
"specified" },
54 { rotationMode::MRF,
"MRF" },
82 const auto* MRFZones =
88 <<
"Unable to find MRFProperties in the database. "
89 <<
"Is this an MRF case?"
92 const auto& mrf = MRFZones->MRFZoneList::getFromName(
MRFName_);
94 origin = offset + mrf.origin();
115 scalar minDot = GREAT;
120 scalar dotp =
mag(test & axis);
128 alphaAxis = axis ^ cand;
139 switch (rotationMode_)
141 case rotationMode::SPECIFIED:
146 case rotationMode::MRF:
148 const auto* MRFZones =
154 <<
"Unable to find MRFProperties in the database. "
155 <<
"Is this an MRF case?"
159 const auto& mrf = MRFZones->MRFZoneList::getFromName(MRFName_);
168 <<
"Unhandled enumeration " << rotationModeNames_[rotationMode_]
182 if (writePropellerPerformance_ && !propellerPerformanceFilePtr_)
184 propellerPerformanceFilePtr_ = createFile(
"propellerPerformance");
185 auto&
os = propellerPerformanceFilePtr_();
188 writeHeaderValue(
os,
"CofR", coordSysPtr_->origin());
189 writeHeaderValue(
os,
"Radius", radius_);
190 writeHeaderValue(
os,
"Axis", coordSysPtr_->e3());
194 writeCommented(
os,
"Time");
195 writeTabbed(
os,
"n");
196 writeTabbed(
os,
"URef");
197 writeTabbed(
os,
"J");
198 writeTabbed(
os,
"KT");
199 writeTabbed(
os,
"10*KQ");
200 writeTabbed(
os,
"eta0");
204 if (writeWakeFields_)
206 if (!wakeFilePtr_) wakeFilePtr_ = createFile(
"wake");
207 if (!axialWakeFilePtr_) axialWakeFilePtr_ = createFile(
"axialWake");
219 <<
"Unable to find velocity field " << UName_
220 <<
" . Available vector fields are: "
240 label nPoint = nRadius*nTheta;
249 const label nFace = nRadius*nTheta;
255 const scalar zCoord = 0;
257 for (
int radiusi = 0; radiusi <= nRadius; ++radiusi)
259 if (r1 < SMALL && radiusi == 0)
261 points[pointi++] = origin;
265 const scalar r = r1 + radiusi*(r2 - r1)/nRadius;
267 for (label i = 0; i < nTheta; ++i)
286 label pointOffset0 = 0;
287 label radiusOffset = 0;
289 for (
int radiusi = 0; radiusi < nRadius; ++radiusi)
291 if (r1 < SMALL && radiusi == 0)
297 for (label thetai = 1; thetai <= nTheta; ++thetai)
306 faces[facei++] =
face(facePts);
311 for (label thetai = 0; thetai < nTheta; ++thetai)
315 label offset = pointOffset0 + (radiusi-radiusOffset)*nTheta;
325 faces[facei++] =
face(facePts);
339 const scalar r1 = sampleDiskDict.
getScalar(
"r1");
340 const scalar r2 = sampleDiskDict.
getScalar(
"r2");
342 nTheta_ = sampleDiskDict.
getLabel(
"nTheta");
343 nRadial_ = sampleDiskDict.
getLabel(
"nRadial");
345 setSampleDiskGeometry
358 if (sampleDiskDict.
readIfPresent(
"surfaceWriter", surfWriterType))
360 const auto writeOptions = sampleDiskDict.
subOrEmptyDict(
"writeOptions");
365 writeOptions.subOrEmptyDict(surfWriterType)
369 surfaceWriterPtr_->useTimeDir(
true);
372 errorOnPointNotFound_ =
373 sampleDiskDict.
getOrDefault(
"errorOnPointNotFound",
false);
375 updateSampleDiskCells();
381 if (!writeWakeFields_)
390 const auto& meshCells = mesh_.cells();
391 const auto& meshFaces = mesh_.faces();
392 const auto& meshPoints = mesh_.points();
398 for (
const label facei : meshCells[celli])
400 for (
const label fpi : meshFaces[facei])
411 treeCellIDs.
append(celli);
426 cellIds_.setSize(points_.size(), -1);
427 pointMask_.setSize(points_.size(),
false);
430 (void)mesh_.tetBasePtIs();
432 const auto& cellLabels = tree.
shapes().cellLabels();
445 pointMask_[pointi] = treeCelli != -1;
451 ? cellLabels[treeCelli]
456 if (errorOnPointNotFound_)
459 <<
"Position " <<
pos <<
" not found in mesh"
465 <<
"Position " <<
pos <<
" not found in mesh"
480 if (
field.size() != points_.size())
483 <<
"Inconsistent field sizes: input:" <<
field.size()
484 <<
" points:" << points_.size()
489 scalar sumFieldArea = 0;
492 const face&
f = faces_[facei];
495 scalar faceValue = 0;
496 for (
const label pti :
f)
499 if (!pointMask_[pti])
504 faceValue +=
field[pti];
509 scalar area =
f.mag(points_);
511 sumFieldArea += faceValue/
f.size()*area;
515 return sumFieldArea/(sumArea + ROOTVSMALL);
527 if (!surfaceWriterPtr_)
534 surfaceWriterPtr_->isPointData(
true);
535 surfaceWriterPtr_->beginTime(time_);
536 surfaceWriterPtr_->open
540 (baseFileDir() /
name() /
"surfaces" /
"disk"),
543 surfaceWriterPtr_->nFields(4);
544 surfaceWriterPtr_->write(
"U",
U);
545 surfaceWriterPtr_->write(
"Ur", Ur);
546 surfaceWriterPtr_->write(
"UNorm",
U/URef);
547 surfaceWriterPtr_->write(
"UrNorm", Ur/URef);
548 surfaceWriterPtr_->endTime();
549 surfaceWriterPtr_->clear();
555 if (!writePropellerPerformance_)
561 setRotationalSpeed();
563 const vector sumForce = forceEff();
564 const vector sumMoment = momentEff();
566 const scalar diameter = 2*radius_;
567 const scalar URef = URefPtr_->value(time_.timeOutputValue());
568 const scalar j = -URef/
mag(n_ + ROOTVSMALL)/diameter;
569 const scalar denom = rhoRef_*
sqr(n_)*
pow4(diameter);
570 const scalar kt = (sumForce & coordSysPtr_->e3())/denom;
572 -
sign(n_)*(sumMoment & coordSysPtr_->e3())/(denom*diameter);
577 auto&
os = propellerPerformanceFilePtr_();
579 writeCurrentTime(
os);
592 <<
" Revolutions per second, n : " << n_ <<
nl
593 <<
" Reference velocity, URef : " << URef <<
nl
594 <<
" Advance coefficient, J : " << j <<
nl
595 <<
" Thrust coefficient, Kt : " << kt <<
nl
596 <<
" Torque coefficient, 10*Kq : " << 10*kq <<
nl
597 <<
" Efficiency, etaO : " << etaO <<
nl
603 setResult(
"URef", URef);
607 setResult(
"etaO", etaO);
620 auto&
os = wakeFilePtr_();
622 const pointField propPoints(coordSysPtr_->localPosition(points_));
624 mag(propPoints[1][0] - propPoints[0][0]) < SMALL ? 0 : 1;
625 const scalar rMax = propPoints.
last()[0];
627 const scalar UzMean = meanSampleDiskField(
U.component(2));
629 writeHeaderValue(
os,
"Time", time_.timeOutputValue());
630 writeHeaderValue(
os,
"Reference velocity", URef);
631 writeHeaderValue(
os,
"Direction", coordSysPtr_->e3());
632 writeHeaderValue(
os,
"Wake", 1 - UzMean/URef);
634 writeCommented(
os,
"r/R");
635 writeTabbed(
os,
"alpha");
636 writeTabbed(
os,
"(x y z)");
637 writeTabbed(
os,
"(Ur Utheta Uz)");
640 for (label thetai = 0; thetai < nTheta_; ++thetai)
642 const scalar deg = 360*thetai/scalar(nTheta_);
644 for (label radiusi = 0; radiusi <= nRadial_; ++radiusi)
646 label pointi = radiusi*nTheta_ + thetai + offset;
648 if (radiusi == 0 && offset == 1)
654 if (pointMask_[pointi])
656 const scalar rR = propPoints[radiusi*nTheta_][0]/rMax;
659 << points_[pointi] <<
tab <<
U[pointi] <<
nl;
679 auto&
os = axialWakeFilePtr_();
681 const pointField propPoints(coordSysPtr_->localPosition(points_));
683 mag(propPoints[1][0] - propPoints[0][0]) < SMALL ? 0 : 1;
684 const scalar rMax = propPoints.
last()[0];
686 writeHeaderValue(
os,
"Time", time_.timeOutputValue());
689 for (label radiusi = 0; radiusi <= nRadial_; ++radiusi)
691 label pointi = radiusi*nTheta_;
692 scalar r = propPoints[pointi][0];
693 os <<
tab <<
"r/R=" << r/rMax;
697 for (label thetai = 0; thetai < nTheta_; ++thetai)
699 os << 360*thetai/scalar(nTheta_);
701 for (label radiusi = 0; radiusi <= nRadial_; ++radiusi)
703 label pointi = radiusi*nTheta_ + thetai + offset;
705 if (radiusi == 0 && offset == 1)
711 if (pointMask_[pointi])
713 os <<
tab << 1 -
U[pointi][2]/URef;
717 os <<
tab <<
"undefined";
732 if (!writeWakeFields_)
739 const vectorField UrDisk(coordSysPtr_->localVector(UDisk));
742 writeSampleDiskSurface(UDisk, UrDisk, URef);
745 writeWake(UrDisk, URef);
746 writeAxialWake(UrDisk, URef);
754 const Type& defaultValue
758 auto&
field = tfield.ref();
767 const label celli = cellIds_[pointi];
769 if (cellIds_[pointi] != -1)
771 const point& position = points_[pointi];
772 field[pointi] = interpolator().interpolate(position, celli);
798 writePropellerPerformance_(true),
799 propellerPerformanceFilePtr_(nullptr),
800 writeWakeFields_(true),
801 surfaceWriterPtr_(nullptr),
805 errorOnPointNotFound_(false),
809 interpolationScheme_(
"cell"),
810 wakeFilePtr_(nullptr),
811 axialWakeFilePtr_(nullptr),
840 radius_ =
dict.getScalar(
"radius");
842 rotationMode_ = rotationModeNames_.get(
"rotationMode",
dict);
845 setCoordinateSystem(
dict);
847 writePropellerPerformance_ =
848 dict.get<
bool>(
"writePropellerPerformance");
850 writeWakeFields_ =
dict.get<
bool>(
"writeWakeFields");
851 if (writeWakeFields_)
853 setSampleDiskSurface(
dict);
855 dict.readIfPresent(
"interpolationScheme", interpolationScheme_);
857 dict.readIfPresent(
"nanValue", nanValue_);
873 if (writeWakeFields_)
881 coordSysPtr_->localVector
890 const scalar UzMean = meanSampleDiskField(UDisk.
component(2));
892 setResult(
"UzMean", UzMean);
895 writePropellerPerformance();
903 const scalar URef = URefPtr_->value(time_.timeOutputValue());
904 writeWakeFields(URef);
912 updateSampleDiskCells();
918 updateSampleDiskCells();
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
void append(const T &val)
Copy append an element to the end of this list.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
tmp< Field< cmptType > > component(const direction) const
Return a component field of the field.
Top level data entry class for use in dictionaries. Provides a mechanism to specify a variable as a c...
List of MRF zones with IO functionality. MRF zones are specified by a list of dictionary entries,...
void setSize(const label n)
Alias for resize()
static void listCombineAllGather(const List< commsStruct > &comms, List< T > &values, const CombineOp &cop, const int tag, const label comm)
After completion all processors have the same data.
virtual bool read()
Re-read model coefficients if they have changed.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
T & last()
Return the last element of the list.
label fcIndex(const label i) const noexcept
Vector< Cmpt > & normalise(const scalar tol=ROOTVSMALL)
Inplace normalise the vector by its magnitude.
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
void inflate(const scalar s)
Inflate box by factor*mag(span) in all dimensions.
A cylindrical coordinate system (r-theta-z). The coordinate system angle theta is always in radians.
Base class for coordinate system specification, the default coordinate system type is cartesian .
point globalPosition(const point &local) const
From local coordinate position to global (cartesian) position.
virtual const point & origin() const
Return origin.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
dictionary subOrEmptyDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX, const bool mandatory=false) const
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
label getLabel(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Same as get< label >(const word&, keyType::option)
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
scalar getScalar(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Same as get< scalar >(const word&, keyType::option)
A face is a list of labels corresponding to mesh vertices.
Abstract base-class for Time/database function objects.
Watches for presence of the named trigger file in the case directory and signals a simulation stop (o...
Computes forces and moments over a given list of patches by integrating pressure and viscous forces a...
autoPtr< coordinateSystem > coordSysPtr_
Coordinate system used when evaluating forces and moments.
const fvMesh & mesh_
Reference to the fvMesh.
Computes the magnitude of an input field.
Calculates propeller performance and wake field properties.
word MRFName_
Name of MRF zone (if applicable)
void UpdateMesh(const mapPolyMesh &mpm)
void writeWake(const vectorField &U, const scalar URef)
Write the wake text file.
void writeWakeFields(const scalar URef)
Write the wake fields.
void createFiles()
Create output files.
rotationMode rotationMode_
Rotation mode.
void setSampleDiskSurface(const dictionary &dict)
Set the sample surface based on dictionary settings.
void writeAxialWake(const vectorField &U, const scalar URef)
Write the axial wake text file.
void writeSampleDiskSurface(const vectorField &U, const vectorField &Ur, const scalar URef)
Write the sample surface.
const volVectorField & U() const
Return the velocity field.
void writePropellerPerformance()
Write the wake fields.
void setCoordinateSystem(const dictionary &dict)
Set the coordinate system.
scalar meanSampleDiskField(const scalarField &field) const
Return the area average of a field.
void setRotationalSpeed()
Set the rotational speed.
void setSampleDiskGeometry(const coordinateSystem &coordSys, const scalar r1, const scalar r2, const scalar nTheta, const label nRadius, faceList &faces, pointField &points) const
Set the faces and points for the sample surface.
scalar n_
Propeller speed (revolutions per second)
virtual bool execute()
Execute, currently does nothing.
virtual bool write()
Write the forces.
void updateSampleDiskCells()
Set the sample cells corresponding to the sample points.
static const Enum< rotationMode > rotationModeNames_
virtual bool read(const dictionary &)
Read the forces data.
Reads fields from the time directories and adds them to the mesh database for further post-processing...
Non-pointer based hierarchical recursive searching.
label findInside(const point &) const
Find shape containing point. Only implemented for certain.
const Type & shapes() const
Reference to shape.
Abstract base class for volume field interpolation.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
void movePoints()
Update for new mesh geometry.
Registry of regIOobjects.
const Type * cfindObject(const word &name, const bool recursive=false) const
Return const pointer to the object of the given Type.
A traits class, which is primarily used for primitives.
Mesh consisting of general polyhedral cells.
int myProcNo() const noexcept
Return processor number.
bool interpolate() const noexcept
Same as isPointData()
splitCell * master() const
A class for managing temporary objects.
Standard boundBox with extra functionality for use in octree.
bool contains(const vector &dir, const point &) const
Contains point (inside or on edge) and moving in direction.
Encapsulation of data needed to search in/for cells. Used to find the cell containing a point (e....
A class for handling words, derived from Foam::string.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
const volScalarField & psi
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
OBJstream os(runTime.globalPath()/outputName)
#define DebugInfo
Report an information message using Foam::Info.
constexpr scalar twoPi(2 *M_PI)
dimensionedScalar pos(const dimensionedScalar &ds)
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
dimensionedScalar sign(const dimensionedScalar &ds)
dimensionedSymmTensor sqr(const dimensionedVector &dv)
static void writeHeader(Ostream &os, const word &fieldName)
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Ostream & endl(Ostream &os)
Add newline and flush stream.
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
dimensionedScalar pow4(const dimensionedScalar &ds)
static constexpr const zero Zero
Global zero (0)
bool interpolate(const vector &p1, const vector &p2, const vector &o, vector &n, scalar l)
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh > > &tdf1, const word &name, const dimensionSet &dimensions)
Global function forwards to reuseTmpDimensionedField::New.
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
errorManipArg< error, int > exit(error &err, const int errNo=1)
constexpr char nl
The newline '\n' character (0x0a)
constexpr char tab
The tab '\t' character(0x09)
#define forAll(list, i)
Loop across all elements in list.
A non-counting (dummy) refCount.