36 template<
class CloudType>
40 const Field<point>&
points,
41 const Field<scalar>& area
49 Info<<
"Creating output file" <<
endl;
52 if (Pstream::master())
55 mkDir(this->writeTimeDir());
60 new OFstream(this->writeTimeDir()/(
type() +
".dat"))
64 <<
"# Source : " <<
type() <<
nl
65 <<
"# Bins : " << faces.size() <<
nl
66 <<
"# Total area : " <<
sum(area) <<
nl;
69 <<
"# Geometry :" <<
nl
72 <<
tab <<
"(Centre_x Centre_y Centre_z)"
88 <<
"# Output format:" <<
nl;
93 word binId =
"bin_" + id;
99 <<
tab <<
"mass[" <<
id <<
"]"
100 <<
tab <<
"massFlowRate[" <<
id <<
"]"
108 template<
class CloudType>
111 const List<Field<point>>& polygons
119 label np = polygons[polyI].size();
123 <<
"polygons must consist of at least 3 points"
130 label pointOffset = 0;
132 faces_.setSize(polygons.size());
133 area_.setSize(polygons.size());
136 const Field<point>& polyPoints = polygons[facei];
138 UIndirectList<point>(points_,
f) = polyPoints;
139 area_[facei] =
f.mag(points_);
140 faces_[facei].transfer(
f);
142 pointOffset += polyPoints.size();
147 template<
class CloudType>
150 mode_ = mtConcentricCircle;
152 vector origin(this->coeffDict().lookup(
"origin"));
154 this->coeffDict().lookup(
"radius") >> radius_;
155 nSector_ = this->coeffDict().template lookup<label>(
"nSector");
162 refDir = this->coeffDict().lookup(
"refDir");
163 refDir -= normal_[0]*(normal_[0] & refDir);
164 refDir /=
mag(refDir);
174 scalar dThetaSector =
degToRad(360.0)/scalar(nS);
175 label intervalPerSector =
max(1, ceil(dThetaSector/dTheta));
176 dTheta = dThetaSector/scalar(intervalPerSector);
178 label nPointPerSector = intervalPerSector + 1;
180 label nPointPerRadius = nS*(nPointPerSector - 1);
181 label nPoint = radius_.size()*nPointPerRadius;
182 label nFace = radius_.size()*nS;
187 points_.setSize(nPoint);
188 faces_.setSize(nFace);
189 area_.setSize(nFace);
192 coordinateSystems::cylindrical(
"coordSys", origin, normal_[0], refDir);
201 label pointOffset = radI*nPointPerRadius + 1;
203 for (
label i = 0; i < nPointPerRadius; i++)
205 label pI = i + pointOffset;
206 point pCyl(radius_[radI], i*dTheta, 0.0);
207 points_[pI] = coordSys_.globalPosition(pCyl);
212 DynamicList<label> facePts(2*nPointPerSector);
217 for (
label secI = 0; secI < nS; secI++)
224 for (
label ptI = 0; ptI < nPointPerSector; ptI++)
226 label i = ptI + secI*(nPointPerSector - 1);
227 label id = ptIDs.fcIndex(i - 1) + 1;
231 label facei = secI + radI*nS;
233 faces_[facei] =
face(facePts);
234 area_[facei] = faces_[facei].mag(points_);
239 for (
label secI = 0; secI < nS; secI++)
245 for (
label ptI = 0; ptI < nPointPerSector; ptI++)
247 label i = ptI + secI*(nPointPerSector - 1);
251 for (
label ptI = nPointPerSector-1; ptI >= 0; ptI--)
253 label i = ptI + secI*(nPointPerSector - 1);
254 label id =
offset + nPointPerRadius + ptIDs.fcIndex(i - 1);
258 label facei = secI + radI*nS;
260 faces_[facei] =
face(facePts);
261 area_[facei] = faces_[facei].mag(points_);
268 template<
class CloudType>
277 const label facePoint0 = faces_[facei][0];
279 const point& pf = points_[facePoint0];
281 const scalar d1 = normal_[facei] & (p1 - pf);
282 const scalar d2 = normal_[facei] & (p2 - pf);
291 const point pIntersect = p1 + (d1/(d1 - d2))*(p2 - p1);
299 const face&
f = faces_[facei];
300 const vector a =
f.area(points_);
302 for (
label i = 0; i <
f.size(); ++ i)
304 const label j =
f.fcIndex(i);
305 const triPointRef t(pIntersect, points_[
f[i]], points_[
f[j]]);
306 if ((a & t.area()) < 0)
316 hitFaceIndices_.append(facei);
322 template<
class CloudType>
331 const scalar d1 = normal_[0] & (p1 - coordSys_.origin());
332 const scalar d2 = normal_[0] & (p2 - coordSys_.origin());
341 const point pCyl = coordSys_.localPosition(p1 + (d1/(d1 - d2))*(p2 - p1));
345 if (r < radius_.last())
348 while (r > radius_[radI])
372 hitFaceIndices_.append(secI);
379 template<
class CloudType>
384 scalar timeNew = time.
value();
385 scalar timeElapsed = timeNew - timeOld_;
387 totalTime_ += timeElapsed;
389 const scalar
alpha = (totalTime_ - timeElapsed)/totalTime_;
390 const scalar beta = timeElapsed/totalTime_;
394 massFlowRate_[facei] =
395 alpha*massFlowRate_[facei] + beta*mass_[facei]/timeElapsed;
396 massTotal_[facei] += mass_[facei];
399 const label proci = Pstream::myProcNo();
404 this->getModelProperty(
"massTotal", faceMassTotal);
407 this->getModelProperty(
"massFlowRate", faceMassFlowRate);
410 scalar sumTotalMass = 0.0;
411 scalar sumAverageMFR = 0.0;
415 allProcMass[proci] = massTotal_[facei];
416 Pstream::gatherList(allProcMass);
417 faceMassTotal[facei] +=
sum(allProcMass);
419 scalarList allProcMassFlowRate(Pstream::nProcs());
420 allProcMassFlowRate[proci] = massFlowRate_[facei];
421 Pstream::gatherList(allProcMassFlowRate);
422 faceMassFlowRate[facei] +=
sum(allProcMassFlowRate);
424 sumTotalMass += faceMassTotal[facei];
425 sumAverageMFR += faceMassFlowRate[facei];
427 if (outputFilePtr_.valid())
432 <<
tab << faceMassTotal[facei]
433 <<
tab << faceMassFlowRate[facei]
438 Info<<
" sum(total mass) = " << sumTotalMass <<
nl
439 <<
" sum(average mass flow rate) = " << sumAverageMFR <<
nl
443 if (surfaceFormat_ !=
"none")
445 if (Pstream::master())
454 this->writeTimeDir(),
471 this->setModelProperty(
"massTotal", dummy);
472 this->setModelProperty(
"massFlowRate", dummy);
479 this->setModelProperty(
"massTotal", faceMassTotal);
480 this->setModelProperty(
"massFlowRate", faceMassFlowRate);
486 massTotal_[facei] = 0.0;
487 massFlowRate_[facei] = 0.0;
494 template<
class CloudType>
504 parcelType_(this->coeffDict().lookupOrDefault(
"parcelType", -1)),
505 removeCollected_(this->coeffDict().lookup(
"removeCollected")),
512 negateParcelsOppositeNormal_
514 readBool(this->coeffDict().lookup(
"negateParcelsOppositeNormal"))
516 surfaceFormat_(this->coeffDict().lookup(
"surfaceFormat")),
517 resetOnWrite_(this->coeffDict().lookup(
"resetOnWrite")),
522 log_(this->coeffDict().lookup(
"log")),
524 timeOld_(owner.
mesh().time().value()),
527 normal_ /=
mag(normal_);
530 if (
mode ==
"polygon")
534 initPolygons(polygons);
539 else if (
mode ==
"polygonWithNormal")
551 polygons[polyI] = polygonAndNormal[polyI].
first();
552 normal_[polyI] = polygonAndNormal[polyI].second();
553 normal_[polyI] /=
mag(normal_[polyI]) + rootVSmall;
556 initPolygons(polygons);
558 else if (
mode ==
"concentricCircle")
563 initConcentricCircles();
568 <<
"Unknown mode " << mode <<
". Available options are "
569 <<
"polygon, polygonWithNormal and concentricCircle"
577 makeLogFile(faces_, points_, area_);
581 template<
class CloudType>
589 parcelType_(pc.parcelType_),
590 removeCollected_(pc.removeCollected_),
593 nSector_(pc.nSector_),
595 coordSys_(pc.coordSys_),
597 negateParcelsOppositeNormal_(pc.negateParcelsOppositeNormal_),
598 surfaceFormat_(pc.surfaceFormat_),
599 resetOnWrite_(pc.resetOnWrite_),
600 totalTime_(pc.totalTime_),
602 massTotal_(pc.massTotal_),
603 massFlowRate_(pc.massFlowRate_),
613 template<
class CloudType>
620 template<
class CloudType>
625 const point& position0,
629 if ((parcelType_ != -1) && (parcelType_ !=
p.typeId()))
634 hitFaceIndices_.clear();
643 p.position(this->owner().mesh())
647 case mtConcentricCircle:
649 collectParcelConcentricCircles
652 p.position(this->owner().mesh())
660 forAll(hitFaceIndices_, i)
662 label facei = hitFaceIndices_[i];
663 scalar m =
p.nParticle()*
p.mass();
665 if (negateParcelsOppositeNormal_)
673 Unormal = Uhat & normal_[facei];
676 case mtConcentricCircle:
678 Unormal = Uhat & normal_[0];
685 Uhat /=
mag(Uhat) + rootVSmall;
698 mass_[facei + 1] += m;
699 mass_[facei + 2] += m;
700 mass_[facei + 3] += m;
703 if (removeCollected_)
705 keepParticle =
false;
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
#define forAll(list, i)
Loop across all elements in list.
Templated cloud function object base class.
Templated base class for dsmc cloud.
void size(const label)
Override size to be inconsistent with allocated storage.
void setSize(const label)
Reset size of List.
Function object to collect the parcel mass- and mass flow rate over a set of polygons....
virtual void postMove(parcelType &p, const scalar dt, const point &position0, bool &keepParticle)
Post-move hook.
virtual ~ParticleCollector()
Destructor.
ParticleCollector(const dictionary &dict, CloudType &owner, const word &modelName)
Construct from dictionary.
void write()
Write post-processing info.
Templated 3D SphericalTensor derived from VectorSpace adding construction from 1 component,...
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
T & first()
Return the first element of the list.
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
A coordinate rotation specified using global axis.
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
const Type & value() const
Return const reference to value.
const word & name() const
Return const reference to name.
Mesh data needed to do the Finite Volume discretisation.
const Time & time() const
Return the top-level database.
const polyMesh & mesh() const
Return reference to polyMesh.
const dictionary & coeffDict() const
Return const access to the coefficients dictionary.
A class for handling words, derived from string.
A class representing the concept of 0 used to avoid unnecessary manipulations for objects that are kn...
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
volScalarField alpha(IOobject("alpha", runTime.name(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE), lambda *max(Ua &U, zeroSensitivity))
autoPtr< CompressibleMomentumTransportModel > New(const volScalarField &rho, const volVectorField &U, const surfaceScalarField &phi, const viscosity &viscosity)
const scalar twoPi(2 *pi)
errorManipArg< error, int > exit(error &err, const int errNo=1)
mode_t mode(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file mode.
scalar degToRad(const scalar deg)
Convert degrees to radians.
dimensionedScalar sign(const dimensionedScalar &ds)
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Ostream & endl(Ostream &os)
Add newline and flush stream.
static const Identity< scalar > I
vector point
Point is a vector.
void mag(LagrangianPatchField< scalar > &f, const LagrangianPatchField< Type > &f1)
Vector< scalar > vector
A scalar version of the templated Vector.
dimensionSet normalised(const dimensionSet &)
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
Field< vector > vectorField
Specialisation of Field<T> for vector.
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
triangle< point, const point & > triPointRef
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
dimensionSet perpendicular(const dimensionSet &)
void offset(label &lst, const label o)
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.