37 template<
class CloudType>
41 const Field<point>& points,
42 const Field<scalar>& area
50 Info<<
"Creating output file" <<
endl;
53 if (Pstream::master())
56 mkDir(this->writeTimeDir());
61 new OFstream(this->writeTimeDir()/(
type() +
".dat"))
65 <<
"# Source : " <<
type() <<
nl 66 <<
"# Bins : " << faces.size() <<
nl 67 <<
"# Total area : " <<
sum(area) <<
nl;
70 <<
"# Geometry :" << nl
73 <<
tab <<
"(Centre_x Centre_y Centre_z)" 82 <<
tab << faces[i].centre(points)
89 <<
"# Output format:" <<
nl;
94 word binId =
"bin_" + id;
100 <<
tab <<
"mass[" <<
id <<
"]" 101 <<
tab <<
"massFlowRate[" <<
id <<
"]" 109 template<
class CloudType>
112 const List<Field<point>>& polygons
120 label np = polygons[polyI].size();
124 <<
"polygons must consist of at least 3 points" 131 label pointOffset = 0;
132 points_.setSize(nPoints);
133 faces_.setSize(polygons.size());
134 area_.setSize(polygons.size());
137 const Field<point>& polyPoints = polygons[facei];
138 face
f(
identity(polyPoints.size()) + pointOffset);
139 UIndirectList<point>(points_,
f) = polyPoints;
140 area_[facei] = f.mag(points_);
141 faces_[facei].transfer(f);
143 pointOffset += polyPoints.size();
148 template<
class CloudType>
151 mode_ = mtConcentricCircle;
155 this->coeffDict().lookup(
"radius") >> radius_;
156 nSector_ = this->coeffDict().template lookup<label>(
"nSector");
163 refDir = this->coeffDict().lookup(
"refDir");
164 refDir -= normal_[0]*(normal_[0] & refDir);
165 refDir /=
mag(refDir);
175 scalar dThetaSector = 360.0/scalar(nS);
176 label intervalPerSector =
max(1, ceil(dThetaSector/dTheta));
177 dTheta = dThetaSector/scalar(intervalPerSector);
179 label nPointPerSector = intervalPerSector + 1;
181 label nPointPerRadius = nS*(nPointPerSector - 1);
182 label nPoint = radius_.size()*nPointPerRadius;
183 label nFace = radius_.size()*nS;
188 points_.setSize(nPoint);
189 faces_.setSize(nFace);
190 area_.setSize(nFace);
192 coordSys_ = coordinateSystems::cylindrical
201 List<label> ptIDs(
identity(nPointPerRadius));
208 label pointOffset = radI*nPointPerRadius + 1;
210 for (
label i = 0; i < nPointPerRadius; i++)
212 label pI = i + pointOffset;
214 points_[pI] = coordSys_.globalPosition(pCyl);
219 DynamicList<label> facePts(2*nPointPerSector);
224 for (
label secI = 0; secI < nS; secI++)
231 for (
label ptI = 0; ptI < nPointPerSector; ptI++)
233 label i = ptI + secI*(nPointPerSector - 1);
234 label id = ptIDs.fcIndex(i - 1) + 1;
238 label facei = secI + radI*nS;
240 faces_[facei] = face(facePts);
241 area_[facei] = faces_[facei].mag(points_);
246 for (
label secI = 0; secI < nS; secI++)
250 label offset = (radI - 1)*nPointPerRadius + 1;
252 for (
label ptI = 0; ptI < nPointPerSector; ptI++)
254 label i = ptI + secI*(nPointPerSector - 1);
255 label id = offset + ptIDs.fcIndex(i - 1);
258 for (
label ptI = nPointPerSector-1; ptI >= 0; ptI--)
260 label i = ptI + secI*(nPointPerSector - 1);
261 label id = offset + nPointPerRadius + ptIDs.fcIndex(i - 1);
265 label facei = secI + radI*nS;
267 faces_[facei] = face(facePts);
268 area_[facei] = faces_[facei].mag(points_);
275 template<
class CloudType>
284 const label facePoint0 = faces_[facei][0];
286 const point& pf = points_[facePoint0];
288 const scalar d1 = normal_[facei] & (p1 - pf);
289 const scalar d2 = normal_[facei] & (p2 - pf);
298 const point pIntersect = p1 + (d1/(d1 - d2))*(p2 - p1);
306 const face& f = faces_[facei];
307 const vector a = f.area(points_);
309 for (
label i = 0; i < f.size(); ++ i)
311 const label j = f.fcIndex(i);
312 const triPointRef t(pIntersect, points_[f[i]], points_[f[j]]);
313 if ((a & t.area()) < 0)
323 hitFaceIDs_.append(facei);
329 template<
class CloudType>
338 const scalar d1 = normal_[0] & (p1 - coordSys_.origin());
339 const scalar d2 = normal_[0] & (p2 - coordSys_.origin());
348 const point pCyl = coordSys_.localPosition(p1 + (d1/(d1 - d2))*(p2 - p1));
352 if (r < radius_.last())
355 while (r > radius_[radI])
379 hitFaceIDs_.append(secI);
386 template<
class CloudType>
391 scalar timeNew = time.
value();
392 scalar timeElapsed = timeNew - timeOld_;
394 totalTime_ += timeElapsed;
396 const scalar
alpha = (totalTime_ - timeElapsed)/totalTime_;
397 const scalar beta = timeElapsed/totalTime_;
401 massFlowRate_[facei] =
402 alpha*massFlowRate_[facei] + beta*mass_[facei]/timeElapsed;
403 massTotal_[facei] += mass_[facei];
406 const label proci = Pstream::myProcNo();
411 this->getModelProperty(
"massTotal", faceMassTotal);
414 this->getModelProperty(
"massFlowRate", faceMassFlowRate);
417 scalar sumTotalMass = 0.0;
418 scalar sumAverageMFR = 0.0;
422 allProcMass[proci] = massTotal_[facei];
423 Pstream::gatherList(allProcMass);
424 faceMassTotal[facei] +=
sum(allProcMass);
426 scalarList allProcMassFlowRate(Pstream::nProcs());
427 allProcMassFlowRate[proci] = massFlowRate_[facei];
428 Pstream::gatherList(allProcMassFlowRate);
429 faceMassFlowRate[facei] +=
sum(allProcMassFlowRate);
431 sumTotalMass += faceMassTotal[facei];
432 sumAverageMFR += faceMassFlowRate[facei];
434 if (outputFilePtr_.valid())
439 <<
tab << faceMassTotal[facei]
440 <<
tab << faceMassFlowRate[facei]
445 Info<<
" sum(total mass) = " << sumTotalMass << nl
446 <<
" sum(average mass flow rate) = " << sumAverageMFR << nl
450 if (surfaceFormat_ !=
"none")
452 if (Pstream::master())
461 this->writeTimeDir(),
472 this->writeTimeDir(),
487 this->setModelProperty(
"massTotal", dummy);
488 this->setModelProperty(
"massFlowRate", dummy);
495 this->setModelProperty(
"massTotal", faceMassTotal);
496 this->setModelProperty(
"massFlowRate", faceMassFlowRate);
502 massTotal_[facei] = 0.0;
503 massFlowRate_[facei] = 0.0;
510 template<
class CloudType>
515 const word& modelName
520 parcelType_(this->coeffDict().lookupOrDefault(
"parcelType", -1)),
521 removeCollected_(this->coeffDict().
lookup(
"removeCollected")),
528 negateParcelsOppositeNormal_
532 surfaceFormat_(this->coeffDict().
lookup(
"surfaceFormat")),
533 resetOnWrite_(this->coeffDict().
lookup(
"resetOnWrite")),
538 log_(this->coeffDict().
lookup(
"log")),
540 timeOld_(owner.mesh().time().value()),
543 normal_ /=
mag(normal_);
546 if (mode ==
"polygon")
550 initPolygons(polygons);
555 else if (mode ==
"polygonWithNormal")
559 this->coeffDict().
lookup(
"polygons")
567 polygons[polyI] = polygonAndNormal[polyI].
first();
568 normal_[polyI] = polygonAndNormal[polyI].second();
569 normal_[polyI] /=
mag(normal_[polyI]) + rootVSmall;
572 initPolygons(polygons);
574 else if (mode ==
"concentricCircle")
579 initConcentricCircles();
584 <<
"Unknown mode " << mode <<
". Available options are " 585 <<
"polygon, polygonWithNormal and concentricCircle" 589 mass_.setSize(faces_.size(), 0.0);
590 massTotal_.setSize(faces_.size(), 0.0);
591 massFlowRate_.setSize(faces_.size(), 0.0);
593 makeLogFile(faces_, points_, area_);
597 template<
class CloudType>
605 parcelType_(pc.parcelType_),
606 removeCollected_(pc.removeCollected_),
609 nSector_(pc.nSector_),
611 coordSys_(pc.coordSys_),
613 negateParcelsOppositeNormal_(pc.negateParcelsOppositeNormal_),
614 surfaceFormat_(pc.surfaceFormat_),
615 resetOnWrite_(pc.resetOnWrite_),
616 totalTime_(pc.totalTime_),
618 massTotal_(pc.massTotal_),
619 massFlowRate_(pc.massFlowRate_),
629 template<
class CloudType>
636 template<
class CloudType>
641 const point& position0,
645 if ((parcelType_ != -1) && (parcelType_ != p.typeId()))
656 collectParcelPolygon(position0, p.position());
659 case mtConcentricCircle:
661 collectParcelConcentricCircles(position0, p.position());
670 label facei = hitFaceIDs_[i];
671 scalar m = p.nParticle()*p.mass();
673 if (negateParcelsOppositeNormal_)
681 Unormal = Uhat & normal_[facei];
684 case mtConcentricCircle:
686 Unormal = Uhat & normal_[0];
693 Uhat /=
mag(Uhat) + rootVSmall;
706 mass_[facei + 1] += m;
707 mass_[facei + 2] += m;
708 mass_[facei + 3] += m;
711 if (removeCollected_)
713 keepParticle =
false;
dimensionedScalar sign(const dimensionedScalar &ds)
#define forAll(list, i)
Loop across all elements in list.
mode_t mode(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file mode.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
errorManipArg< error, int > exit(error &err, const int errNo=1)
A list of keyword definitions, which are a keyword followed by any number of values (e...
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
ParticleCollector(const dictionary &dict, CloudType &owner, const word &modelName)
Construct from dictionary.
Unit conversion functions.
void size(const label)
Override size to be inconsistent with allocated storage.
volScalarField alpha(IOobject("alpha", runTime.timeName(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE), lambda *max(Ua &U, zeroSensitivity))
Ostream & endl(Ostream &os)
Add newline and flush stream.
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
volVectorField vectorField(fieldObject, mesh)
static word timeName(const scalar, const int precision=precision_)
Return time name of given scalar time.
Vector< scalar > vector
A scalar version of the templated Vector.
void write()
Write post-processing info.
const Time & time() const
Return the top-level database.
T & first()
Return the first element of the list.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
scalar degToRad(const scalar deg)
Conversion from degrees to radians.
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
stressControl lookup("compactNormalStress") >> compactNormalStress
Form normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
static const Identity< scalar > I
autoPtr< BasicCompressibleMomentumTransportModel > New(const volScalarField &rho, const volVectorField &U, const surfaceScalarField &phi, const typename BasicCompressibleMomentumTransportModel::transportModel &transport)
A class for handling words, derived from string.
const Type & value() const
Return const reference to value.
virtual void postMove(parcelType &p, const scalar dt, const point &position0, bool &keepParticle)
Post-move hook.
const scalar twoPi(2 *pi)
IOstream::streamFormat writeFormat() const
Default write format.
virtual ~ParticleCollector()
Destructor.
bool mkDir(const fileName &, mode_t=0777)
Make a directory and return an error if it could not be created.
word name(const complex &)
Return a string representation of a complex.
Vector< Cmpt > perpendicular(const Vector< Cmpt > &v)
void setSize(const label)
Reset size of List.
vector point
Point is a vector.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Function object to collect the parcel mass- and mass flow rate over a set of polygons. The polygons can either be specified by sets of user- supplied points, or in a concentric circles arrangement. If a parcel is 'collected', it can be flagged to be removed from the domain using the removeCollected entry.
Mesh data needed to do the Finite Volume discretisation.
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
triangle< point, const point & > triPointRef
dimensioned< scalar > mag(const dimensioned< Type > &)
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.
Templated base class for dsmc cloud.
Templated cloud function object base class.