43 namespace functionObjects
53 { rotationMode::SPECIFIED,
"specified" },
76 n_ =
dict.get<scalar>(
"n");
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();
110 if (!
dict.readIfPresent(
"alphaAxis", alphaAxis))
115 scalar minDot = GREAT;
120 scalar dotp =
mag(test & axis);
128 alphaAxis = axis ^ cand;
139 switch (rotationMode_)
141 case rotationMode::SPECIFIED:
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)
282 const List<label> ptIDs(
identity(nTheta));
286 label pointOffset0 = 0;
287 label radiusOffset = 0;
288 DynamicList<label> facePts(4);
289 for (
int radiusi = 0; radiusi < nRadius; ++radiusi)
291 if (r1 < SMALL && radiusi == 0)
297 for (label thetai = 1; thetai <= nTheta; ++thetai)
303 facePts.append(thetai);
304 facePts.append(1 + ptIDs.fcIndex(thetai - 1));
306 faces[facei++] = face(facePts);
311 for (label thetai = 0; thetai < nTheta; ++thetai)
315 label offset = pointOffset0 + (radiusi-radiusOffset)*nTheta;
318 facePts.append(offset + ptIDs.fcIndex(thetai - 1));
319 facePts.append(offset + ptIDs.fcIndex(thetai));
322 facePts.append(offset + nTheta + ptIDs.fcIndex(thetai));
323 facePts.append(offset + nTheta + ptIDs.fcIndex(thetai - 1));
325 faces[facei++] = face(facePts);
334 const dictionary&
dict
337 const dictionary& sampleDiskDict(
dict.subDict(
"sampleDisk"));
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])
402 if (bb.contains(meshPoints[fpi]))
411 treeCellIDs.append(celli);
417 indexedOctree<treeDataCell> tree
426 cellIds_.setSize(points_.size(), -1);
427 pointMask_.setSize(points_.size(),
false);
430 (void)mesh_.tetBasePtIs();
432 const auto& cellLabels = tree.shapes().cellLabels();
439 label treeCelli = tree.findInside(
pos);
443 reduce(proci, maxOp<label>());
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"
481 if (
field.size() != points_.size())
484 <<
"Inconsistent field sizes: input:" <<
field.size()
485 <<
" points:" << points_.size()
490 scalar sumFieldArea = 0;
493 const face&
f = faces_[facei];
496 scalar faceValue = 0;
497 for (
const label pti :
f)
500 if (!pointMask_[pti])
505 faceValue +=
field[pti];
510 scalar
area =
f.mag(points_);
512 sumFieldArea += faceValue/
f.size()*
area;
516 return sumFieldArea/(sumArea + ROOTVSMALL);
528 if (!surfaceWriterPtr_)
535 surfaceWriterPtr_->isPointData(
true);
536 surfaceWriterPtr_->beginTime(time_);
537 surfaceWriterPtr_->open
541 (baseFileDir() /
name() /
"surfaces" /
"disk"),
544 surfaceWriterPtr_->nFields(4);
545 surfaceWriterPtr_->write(
"U",
U);
546 surfaceWriterPtr_->write(
"Ur", Ur);
547 surfaceWriterPtr_->write(
"UNorm",
U/URef);
548 surfaceWriterPtr_->write(
"UrNorm", Ur/URef);
549 surfaceWriterPtr_->endTime();
550 surfaceWriterPtr_->clear();
556 if (!writePropellerPerformance_)
562 setRotationalSpeed();
564 const vector sumForce(
sum(force_[0]) +
sum(force_[1]) +
sum(force_[2]));
565 const vector sumMoment(
sum(moment_[0]) +
sum(moment_[1]) +
sum(moment_[2]));
567 const scalar diameter = 2*radius_;
568 const scalar URef = URefPtr_->value(time_.timeOutputValue());
569 const scalar j = -URef/
mag(n_ + ROOTVSMALL)/diameter;
570 const scalar denom = rhoRef_*
sqr(n_)*
pow4(diameter);
571 const scalar kt = (sumForce & coordSysPtr_->e3())/denom;
573 -
sign(n_)*(sumMoment & coordSysPtr_->e3())/(denom*diameter);
578 auto&
os = propellerPerformanceFilePtr_();
580 writeCurrentTime(
os);
593 <<
" Revolutions per second, n : " << n_ <<
nl
594 <<
" Reference velocity, URef : " << URef <<
nl
595 <<
" Advance coefficient, J : " << j <<
nl
596 <<
" Thrust coefficient, Kt : " << kt <<
nl
597 <<
" Torque coefficient, 10*Kq : " << 10*kq <<
nl
598 <<
" Efficiency, etaO : " << etaO <<
nl
604 setResult(
"URef", URef);
608 setResult(
"etaO", etaO);
621 auto&
os = wakeFilePtr_();
623 const pointField propPoints(coordSysPtr_->localPosition(points_));
625 mag(propPoints[1][0] - propPoints[0][0]) < SMALL ? 0 : 1;
626 const scalar rMax = propPoints.last()[0];
628 const scalar UzMean = meanSampleDiskField(
U.component(2));
630 writeHeaderValue(
os,
"Time", time_.timeOutputValue());
631 writeHeaderValue(
os,
"Reference velocity", URef);
632 writeHeaderValue(
os,
"Direction", coordSysPtr_->e3());
633 writeHeaderValue(
os,
"Wake", 1 - UzMean/URef);
635 writeCommented(
os,
"r/R");
636 writeTabbed(
os,
"alpha");
637 writeTabbed(
os,
"(x y z)");
638 writeTabbed(
os,
"(Ur Utheta Uz)");
641 for (label thetai = 0; thetai < nTheta_; ++thetai)
643 const scalar deg = 360*thetai/scalar(nTheta_);
645 for (label radiusi = 0; radiusi <= nRadial_; ++radiusi)
647 label pointi = radiusi*nTheta_ + thetai + offset;
649 if (radiusi == 0 && offset == 1)
655 if (pointMask_[pointi])
657 const scalar rR = propPoints[radiusi*nTheta_][0]/rMax;
660 << points_[pointi] <<
tab <<
U[pointi] <<
nl;
680 auto&
os = axialWakeFilePtr_();
682 const pointField propPoints(coordSysPtr_->localPosition(points_));
684 mag(propPoints[1][0] - propPoints[0][0]) < SMALL ? 0 : 1;
685 const scalar rMax = propPoints.last()[0];
687 writeHeaderValue(
os,
"Time", time_.timeOutputValue());
690 for (label radiusi = 0; radiusi <= nRadial_; ++radiusi)
692 label pointi = radiusi*nTheta_;
693 scalar r = propPoints[pointi][0];
694 os <<
tab <<
"r/R=" << r/rMax;
698 for (label thetai = 0; thetai < nTheta_; ++thetai)
700 os << 360*thetai/scalar(nTheta_);
702 for (label radiusi = 0; radiusi <= nRadial_; ++radiusi)
704 label pointi = radiusi*nTheta_ + thetai + offset;
706 if (radiusi == 0 && offset == 1)
712 if (pointMask_[pointi])
714 os <<
tab << 1 -
U[pointi][2]/URef;
718 os <<
tab <<
"undefined";
733 if (!writeWakeFields_)
740 const vectorField UrDisk(coordSysPtr_->localVector(UDisk));
743 writeSampleDiskSurface(UDisk, UrDisk, URef);
746 writeWake(UrDisk, URef);
747 writeAxialWake(UrDisk, URef);
755 const Type& defaultValue
759 auto&
field = tfield.ref();
768 const label celli = cellIds_[pointi];
770 if (cellIds_[pointi] != -1)
772 const point& position = points_[pointi];
773 field[pointi] = interpolator().interpolate(position, celli);
797 rotationMode_(rotationMode::SPECIFIED),
800 writePropellerPerformance_(true),
801 propellerPerformanceFilePtr_(nullptr),
802 writeWakeFields_(true),
803 surfaceWriterPtr_(nullptr),
807 errorOnPointNotFound_(false),
811 interpolationScheme_(
"cell"),
812 wakeFilePtr_(nullptr),
813 axialWakeFilePtr_(nullptr),
842 radius_ =
dict.getScalar(
"radius");
844 rotationMode_ = rotationModeNames_.get(
"rotationMode",
dict);
847 setCoordinateSystem(
dict);
849 writePropellerPerformance_ =
850 dict.get<
bool>(
"writePropellerPerformance");
852 writeWakeFields_ =
dict.get<
bool>(
"writeWakeFields");
853 if (writeWakeFields_)
855 setSampleDiskSurface(
dict);
857 dict.readIfPresent(
"interpolationScheme", interpolationScheme_);
859 dict.readIfPresent(
"nanValue", nanValue_);
875 if (writeWakeFields_)
883 coordSysPtr_->localVector
892 const scalar UzMean = meanSampleDiskField(UDisk.
component(2));
894 setResult(
"UzMean", UzMean);
897 writePropellerPerformance();
905 const scalar URef = URefPtr_->value(time_.timeOutputValue());
906 writeWakeFields(URef);
914 updateSampleDiskCells();
920 updateSampleDiskCells();