propellerInfo.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2021-2022 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
28#include "propellerInfo.H"
29#include "cylindricalCS.H"
30#include "fvMesh.H"
31#include "IOMRFZoneList.H"
33#include "interpolation.H"
34#include "Function1.H"
35#include "surfaceWriter.H"
36#include "treeDataCell.H"
38
39// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40
41namespace Foam
42{
43namespace functionObjects
44{
47}
48}
49
52({
53 { rotationMode::SPECIFIED, "specified" },
54 { rotationMode::MRF, "MRF" },
55});
56
57
58// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
59
61(
62 const dictionary& dict
63)
64{
65 vector origin(Zero);
66 vector axis(Zero);
67
68 switch (rotationMode_)
69 {
71 {
72 origin = dict.get<vector>("origin");
73 axis = dict.get<vector>("axis");
74 axis.normalise();
75
76 n_ = dict.get<scalar>("n");
77 break;
78 }
80 {
81 MRFName_ = dict.get<word>("MRF");
82 const auto* MRFZones =
83 mesh_.cfindObject<IOMRFZoneList>("MRFProperties");
84
85 if (!MRFZones)
86 {
88 << "Unable to find MRFProperties in the database. "
89 << "Is this an MRF case?"
91 }
92 const auto& mrf = MRFZones->MRFZoneList::getFromName(MRFName_);
93 vector offset = dict.getOrDefault("originOffset", vector::zero);
94 origin = offset + mrf.origin();
95 axis = mrf.axis();
96
97 // Convert rad/s to revolutions per second
98 n_ = (mrf.Omega() & axis)/constant::mathematical::twoPi;
99 break;
100 }
101 default:
102 {
104 << "Unhandled enumeration " << rotationModeNames_[rotationMode_]
105 << abort(FatalError);
106 }
107 }
108
109 vector alphaAxis;
110 if (!dict.readIfPresent("alphaAxis", alphaAxis))
111 {
112 // Value has not been set - find vector orthogonal to axis
113
114 vector cand(Zero);
115 scalar minDot = GREAT;
116 for (direction d = 0; d < 3; ++d)
117 {
118 vector test(Zero);
119 test[d] = 1;
120 scalar dotp = mag(test & axis);
121 if (dotp < minDot)
122 {
123 minDot = dotp;
124 cand = test;
125 }
126 }
127
128 alphaAxis = axis ^ cand;
129 }
130
131 alphaAxis.normalise();
132
133 coordSysPtr_.reset(new coordSystem::cylindrical(origin, axis, alphaAxis));
134}
135
136
138{
139 switch (rotationMode_)
140 {
141 case rotationMode::SPECIFIED:
142 {
143 // Set on dictionary re-read
144 break;
145 }
146 case rotationMode::MRF:
147 {
148 const auto* MRFZones =
149 mesh_.cfindObject<IOMRFZoneList>("MRFProperties");
150
151 if (!MRFZones)
152 {
154 << "Unable to find MRFProperties in the database. "
155 << "Is this an MRF case?"
156 << exit(FatalError);
157 }
158
159 const auto& mrf = MRFZones->MRFZoneList::getFromName(MRFName_);
160
161 // Convert rad/s to revolutions per second
162 n_ = (mrf.Omega() & mrf.axis())/constant::mathematical::twoPi;
163 break;
164 }
165 default:
166 {
168 << "Unhandled enumeration " << rotationModeNames_[rotationMode_]
169 << abort(FatalError);
170 }
171 }
172}
173
174
176{
177 if (!writeToFile())
178 {
179 return;
180 }
181
182 if (writePropellerPerformance_ && !propellerPerformanceFilePtr_)
183 {
184 propellerPerformanceFilePtr_ = createFile("propellerPerformance");
185 auto& os = propellerPerformanceFilePtr_();
186
187 writeHeader(os, "Propeller performance");
188 writeHeaderValue(os, "CofR", coordSysPtr_->origin());
189 writeHeaderValue(os, "Radius", radius_);
190 writeHeaderValue(os, "Axis", coordSysPtr_->e3());
191
192 writeHeader(os, "");
193
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");
201 os << nl;
202 }
203
204 if (writeWakeFields_)
205 {
206 if (!wakeFilePtr_) wakeFilePtr_ = createFile("wake");
207 if (!axialWakeFilePtr_) axialWakeFilePtr_ = createFile("axialWake");
208 }
209}
210
211
213{
214 const auto* UPtr = mesh_.cfindObject<volVectorField>(UName_);
215
216 if (!UPtr)
217 {
219 << "Unable to find velocity field " << UName_
220 << " . Available vector fields are: "
221 << mesh_.names<volVectorField>()
222 << exit(FatalError);
223 }
224
225 return *UPtr;
226}
227
228
230(
231 const coordinateSystem& coordSys,
232 const scalar r1,
233 const scalar r2,
234 const scalar nTheta,
235 const label nRadius,
236 faceList& faces,
238) const
239{
240 label nPoint = nRadius*nTheta;
241 if (r1 < SMALL)
242 {
243 nPoint += 1; // 1 for origin
244 }
245 else
246 {
247 nPoint += nTheta;
248 }
249 const label nFace = nRadius*nTheta;
250
251 points.setSize(nPoint);
252 faces.setSize(nFace);
253
254 const point& origin = coordSys.origin();
255 const scalar zCoord = 0;
256 label pointi = 0;
257 for (int radiusi = 0; radiusi <= nRadius; ++radiusi)
258 {
259 if (r1 < SMALL && radiusi == 0)
260 {
261 points[pointi++] = origin;
262 }
263 else
264 {
265 const scalar r = r1 + radiusi*(r2 - r1)/nRadius;
266
267 for (label i = 0; i < nTheta; ++i)
268 {
269 point p
270 (
271 r,
272 (i/scalar(nTheta))*constant::mathematical::twoPi,
273 zCoord
274 );
275
276 points[pointi++] = coordSys.globalPosition(p);
277 }
278 }
279 }
280
281
282 const List<label> ptIDs(identity(nTheta));
283
284 // Faces
285 label facei = 0;
286 label pointOffset0 = 0;
287 label radiusOffset = 0;
288 DynamicList<label> facePts(4);
289 for (int radiusi = 0; radiusi < nRadius; ++radiusi)
290 {
291 if (r1 < SMALL && radiusi == 0)
292 {
293 radiusOffset = 1;
294 pointOffset0 = 1;
295
296 // Adding faces as a fan about the origin
297 for (label thetai = 1; thetai <= nTheta; ++thetai)
298 {
299 facePts.clear();
300
301 // Append triangle about origin
302 facePts.append(0);
303 facePts.append(thetai);
304 facePts.append(1 + ptIDs.fcIndex(thetai - 1));
305
306 faces[facei++] = face(facePts);
307 }
308 }
309 else
310 {
311 for (label thetai = 0; thetai < nTheta; ++thetai)
312 {
313 facePts.clear();
314
315 label offset = pointOffset0 + (radiusi-radiusOffset)*nTheta;
316
317 // Inner
318 facePts.append(offset + ptIDs.fcIndex(thetai - 1));
319 facePts.append(offset + ptIDs.fcIndex(thetai));
320
321 // Outer
322 facePts.append(offset + nTheta + ptIDs.fcIndex(thetai));
323 facePts.append(offset + nTheta + ptIDs.fcIndex(thetai - 1));
324
325 faces[facei++] = face(facePts);
326 }
327 }
328 }
329}
330
331
333(
334 const dictionary& dict
335)
336{
337 const dictionary& sampleDiskDict(dict.subDict("sampleDisk"));
338
339 const scalar r1 = sampleDiskDict.getScalar("r1");
340 const scalar r2 = sampleDiskDict.getScalar("r2");
341
342 nTheta_ = sampleDiskDict.getLabel("nTheta");
343 nRadial_ = sampleDiskDict.getLabel("nRadial");
344
345 setSampleDiskGeometry
346 (
347 coordSysPtr_(),
348 r1,
349 r2,
350 nTheta_,
351 nRadial_,
352 faces_,
353 points_
354 );
355
356 // Surface writer
357 word surfWriterType;
358 if (sampleDiskDict.readIfPresent("surfaceWriter", surfWriterType))
359 {
360 const auto writeOptions = sampleDiskDict.subOrEmptyDict("writeOptions");
361
362 surfaceWriterPtr_ = surfaceWriter::New
363 (
364 surfWriterType,
365 writeOptions.subOrEmptyDict(surfWriterType)
366 );
367
368 // Use outputDir/TIME/surface-name
369 surfaceWriterPtr_->useTimeDir(true);
370 }
371
372 errorOnPointNotFound_ =
373 sampleDiskDict.getOrDefault("errorOnPointNotFound", false);
374
375 updateSampleDiskCells();
376}
377
378
380{
381 if (!writeWakeFields_)
382 {
383 return;
384 }
385
386 treeBoundBox bb(points_);
387 bb.inflate(0.05);
388 DynamicList<label> treeCellIDs(10*points_.size());
389
390 const auto& meshCells = mesh_.cells();
391 const auto& meshFaces = mesh_.faces();
392 const auto& meshPoints = mesh_.points();
393
394 forAll(meshCells, celli)
395 {
396 bool found = false;
397
398 for (const label facei : meshCells[celli])
399 {
400 for (const label fpi : meshFaces[facei])
401 {
402 if (bb.contains(meshPoints[fpi]))
403 {
404 found = true;
405 break;
406 }
407 }
408
409 if (found)
410 {
411 treeCellIDs.append(celli);
412 break;
413 }
414 }
415 }
416
418 (
419 treeDataCell(true, mesh_, std::move(treeCellIDs), polyMesh::CELL_TETS),
420 bb,
421 10,
422 100,
423 10
424 );
425
426 cellIds_.setSize(points_.size(), -1);
427 pointMask_.setSize(points_.size(), false);
428
429 // Kick the tet base points calculation to avoid parallel comms later
430 (void)mesh_.tetBasePtIs();
431
432 const auto& cellLabels = tree.shapes().cellLabels();
433
434 forAll(points_, pointi)
435 {
436 const vector& pos = points_[pointi];
437
438// label meshCelli = mesh_.findCell(pos);
439 label treeCelli = tree.findInside(pos);
440
441 label proci = treeCelli >= 0 ? Pstream::myProcNo() : -1;
442
443 reduce(proci, maxOp<label>());
444
445 pointMask_[pointi] = treeCelli != -1;
446
447 if (proci >= 0)
448 {
449 cellIds_[pointi] =
450 proci == Pstream::myProcNo()
451 ? cellLabels[treeCelli]
452 : -1;
453 }
454 else
455 {
456 if (errorOnPointNotFound_)
457 {
459 << "Position " << pos << " not found in mesh"
460 << abort(FatalError);
461 }
462 else
463 {
465 << "Position " << pos << " not found in mesh"
466 << endl;
467 }
468 }
469 }
470
472}
473
474
476(
477 const scalarField& field
478) const
479{
480 if (field.size() != points_.size())
481 {
483 << "Inconsistent field sizes: input:" << field.size()
484 << " points:" << points_.size()
485 << abort(FatalError);
486 }
487
488 scalar sumArea = 0;
489 scalar sumFieldArea = 0;
490 forAll(faces_, facei)
491 {
492 const face& f = faces_[facei];
493
494 bool valid = true;
495 scalar faceValue = 0;
496 for (const label pti : f)
497 {
498 // Exclude contributions where sample cell for point was not found
499 if (!pointMask_[pti])
500 {
501 valid = false;
502 break;
503 }
504 faceValue += field[pti];
505 }
506
507 if (valid)
508 {
509 scalar area = f.mag(points_);
510 sumArea += area;
511 sumFieldArea += faceValue/f.size()*area;
512 }
513 }
514
515 return sumFieldArea/(sumArea + ROOTVSMALL);
516}
517
518
520(
521 const vectorField& U,
522 const vectorField& Ur,
523 const scalar URef
524)
525{
526 // Write surface
527 if (!surfaceWriterPtr_)
528 {
529 return;
530 }
531
532
533 // Time-aware, with time spliced into the output path
534 surfaceWriterPtr_->isPointData(true);
535 surfaceWriterPtr_->beginTime(time_);
536 surfaceWriterPtr_->open
537 (
538 points_,
539 faces_,
540 (baseFileDir() / name() / "surfaces" / "disk"),
541 false // serial - already merged
542 );
543 surfaceWriterPtr_->nFields(4); // Legacy VTK
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();
550}
551
552
554{
555 if (!writePropellerPerformance_)
556 {
557 return;
558 }
559
560 // Update n_
561 setRotationalSpeed();
562
563 const vector sumForce = forceEff();
564 const vector sumMoment = momentEff();
565
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;
571 const scalar kq =
572 -sign(n_)*(sumMoment & coordSysPtr_->e3())/(denom*diameter);
573 const scalar etaO = kt*j/(kq*constant::mathematical::twoPi + ROOTVSMALL);
574
575 if (writeToFile())
576 {
577 auto& os = propellerPerformanceFilePtr_();
578
579 writeCurrentTime(os);
580 os << tab << n_
581 << tab << URef
582 << tab << j
583 << tab << kt
584 << tab << 10*kq
585 << tab << etaO
586 << nl;
587
588 os.flush();
589 }
590
591 Log << type() << " " << name() << " output:" << nl
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
598 << nl;
599
600
601 // Write state/results information
602 setResult("n", n_);
603 setResult("URef", URef);
604 setResult("Kt", kt);
605 setResult("Kq", kq);
606 setResult("J", j);
607 setResult("etaO", etaO);
608}
609
610
612(
613 const vectorField& U,
614 const scalar URef
615)
616{
617 if (!Pstream::master()) return;
618
619 // Velocity
620 auto& os = wakeFilePtr_();
621
622 const pointField propPoints(coordSysPtr_->localPosition(points_));
623 const label offset =
624 mag(propPoints[1][0] - propPoints[0][0]) < SMALL ? 0 : 1;
625 const scalar rMax = propPoints.last()[0];
626
627 const scalar UzMean = meanSampleDiskField(U.component(2));
628
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);
633 writeHeader(os, "");
634 writeCommented(os, "r/R");
635 writeTabbed(os, "alpha");
636 writeTabbed(os, "(x y z)");
637 writeTabbed(os, "(Ur Utheta Uz)");
638 os << nl;
639
640 for (label thetai = 0; thetai < nTheta_; ++thetai)
641 {
642 const scalar deg = 360*thetai/scalar(nTheta_);
643
644 for (label radiusi = 0; radiusi <= nRadial_; ++radiusi)
645 {
646 label pointi = radiusi*nTheta_ + thetai + offset;
647
648 if (radiusi == 0 && offset == 1)
649 {
650 // Only a single point at the centre - repeat for all thetai
651 pointi = 0;
652 }
653
654 if (pointMask_[pointi])
655 {
656 const scalar rR = propPoints[radiusi*nTheta_][0]/rMax;
657
658 os << rR << tab << deg << tab
659 << points_[pointi] << tab << U[pointi] << nl;
660 }
661 }
662 }
663
664 writeBreak(os);
665
666 os << endl;
667}
668
669
671(
672 const vectorField& U,
673 const scalar URef
674)
675{
676 if (!Pstream::master()) return;
677
678 // Alternative common format - axial wake component
679 auto& os = axialWakeFilePtr_();
680
681 const pointField propPoints(coordSysPtr_->localPosition(points_));
682 const label offset =
683 mag(propPoints[1][0] - propPoints[0][0]) < SMALL ? 0 : 1;
684 const scalar rMax = propPoints.last()[0];
685
686 writeHeaderValue(os, "Time", time_.timeOutputValue());
687
688 os << "# angle";
689 for (label radiusi = 0; radiusi <= nRadial_; ++radiusi)
690 {
691 label pointi = radiusi*nTheta_;
692 scalar r = propPoints[pointi][0];
693 os << tab << "r/R=" << r/rMax;
694 }
695 os << nl;
696
697 for (label thetai = 0; thetai < nTheta_; ++thetai)
698 {
699 os << 360*thetai/scalar(nTheta_);
700
701 for (label radiusi = 0; radiusi <= nRadial_; ++radiusi)
702 {
703 label pointi = radiusi*nTheta_ + thetai + offset;
704
705 if (radiusi == 0 && offset == 1)
706 {
707 // Only a single point at the centre - repeat for all thetai
708 pointi = 0;
709 }
710
711 if (pointMask_[pointi])
712 {
713 os << tab << 1 - U[pointi][2]/URef;
714 }
715 else
716 {
717 os << tab << "undefined";
718 }
719 }
720
721 os << nl;
722 }
723
724 writeBreak(os);
725
726 os << endl;
727}
728
729
731{
732 if (!writeWakeFields_)
733 {
734 return;
735 }
736
737 // Normalised velocity
738 const vectorField UDisk(interpolate(U(), vector::uniform(nanValue_))());
739 const vectorField UrDisk(coordSysPtr_->localVector(UDisk));
740
741 // Surface field data
742 writeSampleDiskSurface(UDisk, UrDisk, URef);
743
744 // Write wake text files
745 writeWake(UrDisk, URef);
746 writeAxialWake(UrDisk, URef);
747}
748
749
750template<class Type>
752(
754 const Type& defaultValue
755) const
756{
757 auto tfield = tmp<Field<Type>>::New(points_.size(), defaultValue);
758 auto& field = tfield.ref();
759
760 autoPtr<interpolation<Type>> interpolator
761 (
762 interpolation<Type>::New(interpolationScheme_, psi)
763 );
764
765 forAll(points_, pointi)
766 {
767 const label celli = cellIds_[pointi];
768
769 if (cellIds_[pointi] != -1)
770 {
771 const point& position = points_[pointi];
772 field[pointi] = interpolator().interpolate(position, celli);
773 }
774 }
775
777
778 return tfield;
779}
780
781
782// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
783
785(
786 const word& name,
787 const Time& runTime,
788 const dictionary& dict,
789 bool readFields
790)
791:
792 forces(name, runTime, dict, false),
793 radius_(0),
794 URefPtr_(nullptr),
795 rotationMode_(rotationMode::SPECIFIED),
796 MRFName_(),
797 n_(0),
798 writePropellerPerformance_(true),
799 propellerPerformanceFilePtr_(nullptr),
800 writeWakeFields_(true),
801 surfaceWriterPtr_(nullptr),
802 nTheta_(0),
803 nRadial_(0),
804 points_(),
805 errorOnPointNotFound_(false),
806 faces_(),
807 cellIds_(),
808 pointMask_(),
809 interpolationScheme_("cell"),
810 wakeFilePtr_(nullptr),
811 axialWakeFilePtr_(nullptr),
812 nanValue_(pTraits<scalar>::min)
813{
814 if (readFields)
815 {
816 read(dict);
817 Log << endl;
818 }
819}
820
821
823(
824 const word& name,
825 const objectRegistry& obr,
826 const dictionary& dict,
827 bool readFields
828)
829:
830 propellerInfo(name, obr.time(), dict, false)
831{}
832
833
834// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
835
837{
838 if (forces::read(dict))
839 {
840 radius_ = dict.getScalar("radius");
841 URefPtr_.reset(Function1<scalar>::New("URef", dict, &mesh_));
842 rotationMode_ = rotationModeNames_.get("rotationMode", dict);
843
844 // Must be set before setting the surface
845 setCoordinateSystem(dict);
846
847 writePropellerPerformance_ =
848 dict.get<bool>("writePropellerPerformance");
849
850 writeWakeFields_ = dict.get<bool>("writeWakeFields");
851 if (writeWakeFields_)
852 {
853 setSampleDiskSurface(dict);
854
855 dict.readIfPresent("interpolationScheme", interpolationScheme_);
856
857 dict.readIfPresent("nanValue", nanValue_);
858 }
859
860 return true;
861 }
862
863 return false;
864}
865
866
868{
869 calcForcesMoments();
870
871 createFiles();
872
873 if (writeWakeFields_)
874 {
875 // Only setting mean axial velocity result during execute
876 // - wake fields are 'heavy' and controlled separately using the
877 // writeControl
878 const vectorField
879 UDisk
880 (
881 coordSysPtr_->localVector
882 (
884 (
885 U(),
886 vector::uniform(nanValue_)
887 )()
888 )
889 );
890 const scalar UzMean = meanSampleDiskField(UDisk.component(2));
891
892 setResult("UzMean", UzMean);
893 }
894
895 writePropellerPerformance();
896
897 return true;
898}
899
900
902{
903 const scalar URef = URefPtr_->value(time_.timeOutputValue());
904 writeWakeFields(URef);
905
906 return true;
907}
908
909
911{
912 updateSampleDiskCells();
913}
914
915
917{
918 updateSampleDiskCells();
919}
920
921
922// ************************************************************************* //
#define Log
Definition: PDRblock.C:35
bool found
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.
Definition: DynamicList.H:72
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:391
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: Enum.H:61
tmp< Field< cmptType > > component(const direction) const
Return a component field of the field.
Definition: Field.C:545
Top level data entry class for use in dictionaries. Provides a mechanism to specify a variable as a c...
Definition: Function1.H:96
List of MRF zones with IO functionality. MRF zones are specified by a list of dictionary entries,...
Definition: IOMRFZoneList.H:75
void setSize(const label n)
Alias for resize()
Definition: List.H:218
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.
Definition: Time.H:80
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
T & last()
Return the last element of the list.
Definition: UListI.H:216
label fcIndex(const label i) const noexcept
Definition: UListI.H:60
Vector< Cmpt > & normalise(const scalar tol=ROOTVSMALL)
Inplace normalise the vector by its magnitude.
Definition: VectorI.H:123
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
void inflate(const scalar s)
Inflate box by factor*mag(span) in all dimensions.
Definition: boundBox.C:175
A cylindrical coordinate system (r-theta-z). The coordinate system angle theta is always in radians.
Definition: cylindricalCS.H:74
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,...
Definition: dictionary.H:126
dictionary subOrEmptyDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX, const bool mandatory=false) const
Definition: dictionary.C:540
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)
Definition: dictionary.H:1546
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)
Definition: dictionary.H:1547
Particle-size distribution model wherein random samples are drawn from the doubly-truncated uniform p...
Definition: uniform.H:164
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
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...
Definition: abort.H:128
Computes forces and moments over a given list of patches by integrating pressure and viscous forces a...
Definition: forces.H:325
autoPtr< coordinateSystem > coordSysPtr_
Coordinate system used when evaluating forces and moments.
Definition: forces.H:363
const fvMesh & mesh_
Reference to the fvMesh.
Computes the magnitude of an input field.
Definition: mag.H:153
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.
Definition: propellerInfo.C:61
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...
Definition: readFields.H:158
Non-pointer based hierarchical recursive searching.
Definition: indexedOctree.H:74
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.
Definition: interpolation.H:60
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:162
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.
Definition: pTraits.H:59
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
int myProcNo() const noexcept
Return processor number.
bool interpolate() const noexcept
Same as isPointData()
splitCell * master() const
Definition: splitCell.H:113
A class for managing temporary objects.
Definition: tmp.H:65
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:89
bool contains(const vector &dir, const point &) const
Contains point (inside or on edge) and moving in direction.
Definition: treeBoundBox.C:320
Encapsulation of data needed to search in/for cells. Used to find the cell containing a point (e....
Definition: treeDataCell.H:57
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
U
Definition: pEqn.H:72
volScalarField & p
const volScalarField & psi
rDeltaTY field()
dynamicFvMesh & mesh
engineTime & runTime
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
const pointField & points
#define DebugInfo
Report an information message using Foam::Info.
constexpr scalar twoPi(2 *M_PI)
Namespace for OpenFOAM.
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)
Definition: labelList.C:38
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.
Definition: MSwindows.C:598
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
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.
Definition: hashSets.C:33
dimensionedScalar pow4(const dimensionedScalar &ds)
uint8_t direction
Definition: direction.H:56
IOerror FatalIOError
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
bool interpolate(const vector &p1, const vector &p2, const vector &o, vector &n, scalar l)
Definition: curveTools.C:75
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh > > &tdf1, const word &name, const dimensionSet &dimensions)
Global function forwards to reuseTmpDimensionedField::New.
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
constexpr char tab
The tab '\t' character(0x09)
Definition: Ostream.H:52
labelList f(nPoints)
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
A non-counting (dummy) refCount.
Definition: refCount.H:59