36 template<
class CloudType>
49 Info<<
"Creating output file" <<
endl;
52 if (Pstream::master())
55 mkDir(this->outputTimeDir());
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>
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 faceTris_.setSize(polygons.size());
134 area_.setSize(polygons.size());
140 area_[faceI] =
f.mag(points_);
143 f.triangles(points_, tris);
144 faceTris_[faceI].transfer(tris);
146 faces_[faceI].transfer(
f);
148 pointOffset += polyPoints.size();
153 template<
class CloudType>
156 mode_ = mtConcentricCircle;
160 radius_ = this->coeffDict().lookup(
"radius");
168 refDir = this->coeffDict().lookup(
"refDir");
169 refDir -= normal_[0]*(normal_[0] & refDir);
170 refDir /=
mag(refDir);
177 vector tangent = vector::zero;
178 scalar magTangent = 0.0;
181 while (magTangent < SMALL)
185 tangent = v - (v & normal_[0])*normal_[0];
186 magTangent =
mag(tangent);
189 refDir = tangent/magTangent;
193 scalar dThetaSector = 360.0/scalar(nS);
194 label intervalPerSector =
max(1, ceil(dThetaSector/dTheta));
195 dTheta = dThetaSector/scalar(intervalPerSector);
197 label nPointPerSector = intervalPerSector + 1;
199 label nPointPerRadius = nS*(nPointPerSector - 1);
200 label nPoint = radius_.size()*nPointPerRadius;
201 label nFace = radius_.size()*nS;
206 points_.setSize(nPoint);
207 faces_.setSize(nFace);
208 area_.setSize(nFace);
210 coordSys_ =
cylindricalCS(
"coordSys", origin, normal_[0], refDir,
false);
219 label pointOffset = radI*nPointPerRadius + 1;
221 for (
label i = 0; i < nPointPerRadius; i++)
223 label pI = i + pointOffset;
225 points_[pI] = coordSys_.globalPosition(pCyl);
235 for (
label secI = 0; secI < nS; secI++)
242 for (
label ptI = 0; ptI < nPointPerSector; ptI++)
244 label i = ptI + secI*(nPointPerSector - 1);
245 label id = ptIDs.fcIndex(i - 1) + 1;
249 label faceI = secI + radI*nS;
251 faces_[faceI] =
face(facePts);
252 area_[faceI] = faces_[faceI].mag(points_);
257 for (
label secI = 0; secI < nS; secI++)
261 label offset = (radI - 1)*nPointPerRadius + 1;
263 for (
label ptI = 0; ptI < nPointPerSector; ptI++)
265 label i = ptI + secI*(nPointPerSector - 1);
266 label id = offset + ptIDs.fcIndex(i - 1);
269 for (
label ptI = nPointPerSector-1; ptI >= 0; ptI--)
271 label i = ptI + secI*(nPointPerSector - 1);
272 label id = offset + nPointPerRadius + ptIDs.fcIndex(i - 1);
276 label faceI = secI + radI*nS;
278 faces_[faceI] =
face(facePts);
279 area_[faceI] = faces_[faceI].mag(points_);
286 template<
class CloudType>
293 label dummyNearType = -1;
294 label dummyNearLabel = -1;
298 const label facePoint0 = faces_[faceI][0];
300 const point& pf = points_[facePoint0];
302 const scalar d1 = normal_[faceI] & (p1 - pf);
303 const scalar d2 = normal_[faceI] & (p2 - pf);
312 const point pIntersect = p1 + (d1/(d1 - d2))*(p2 - p1);
319 const face& tri = tris[triI];
327 if (t.
classify(pIntersect, dummyNearType, dummyNearLabel))
329 hitFaceIDs_.append(faceI);
336 template<
class CloudType>
345 const scalar d1 = normal_[0] & (p1 - coordSys_.origin());
346 const scalar d2 = normal_[0] & (p2 - coordSys_.origin());
355 const point pCyl = coordSys_.localPosition(p1 + (d1/(d1 - d2))*(p2 - p1));
359 if (r < radius_.last())
362 while (r > radius_[radI])
383 hitFaceIDs_.append(secI);
388 template<
class CloudType>
393 scalar timeNew = time.
value();
394 scalar timeElapsed = timeNew - timeOld_;
396 totalTime_ += timeElapsed;
398 const scalar
alpha = (totalTime_ - timeElapsed)/totalTime_;
399 const scalar
beta = timeElapsed/totalTime_;
403 massFlowRate_[faceI] =
404 alpha*massFlowRate_[faceI] +
beta*mass_[faceI]/timeElapsed;
405 massTotal_[faceI] += mass_[faceI];
408 const label procI = Pstream::myProcNo();
413 this->getModelProperty(
"massTotal", faceMassTotal);
416 this->getModelProperty(
"massFlowRate", faceMassFlowRate);
419 scalar sumTotalMass = 0.0;
420 scalar sumAverageMFR = 0.0;
424 allProcMass[procI] = massTotal_[faceI];
425 Pstream::gatherList(allProcMass);
426 faceMassTotal[faceI] +=
sum(allProcMass);
428 scalarList allProcMassFlowRate(Pstream::nProcs());
429 allProcMassFlowRate[procI] = massFlowRate_[faceI];
430 Pstream::gatherList(allProcMassFlowRate);
431 faceMassFlowRate[faceI] +=
sum(allProcMassFlowRate);
433 sumTotalMass += faceMassTotal[faceI];
434 sumAverageMFR += faceMassFlowRate[faceI];
436 if (outputFilePtr_.valid())
441 <<
tab << faceMassTotal[faceI]
442 <<
tab << faceMassFlowRate[faceI]
447 Info<<
" sum(total mass) = " << sumTotalMass <<
nl
448 <<
" sum(average mass flow rate) = " << sumAverageMFR <<
nl
452 if (surfaceFormat_ !=
"none")
454 if (Pstream::master())
461 this->coeffDict().subOrEmptyDict(
"formatOptions").
462 subOrEmptyDict(surfaceFormat_)
468 this->outputTimeDir(),
479 this->outputTimeDir(),
494 this->setModelProperty(
"massTotal", dummy);
495 this->setModelProperty(
"massFlowRate", dummy);
502 this->setModelProperty(
"massTotal", faceMassTotal);
503 this->setModelProperty(
"massFlowRate", faceMassFlowRate);
509 massTotal_[faceI] = 0.0;
510 massFlowRate_[faceI] = 0.0;
517 template<
class CloudType>
522 const word& modelName
527 parcelType_(this->coeffDict().lookupOrDefault(
"parcelType", -1)),
528 removeCollected_(this->coeffDict().
lookup(
"removeCollected")),
536 negateParcelsOppositeNormal_
540 surfaceFormat_(this->coeffDict().
lookup(
"surfaceFormat")),
541 resetOnWrite_(this->coeffDict().
lookup(
"resetOnWrite")),
546 log_(this->coeffDict().
lookup(
"log")),
551 normal_ /=
mag(normal_);
554 if (
mode ==
"polygon")
558 initPolygons(polygons);
563 else if (
mode ==
"polygonWithNormal")
567 this->coeffDict().
lookup(
"polygons")
571 normal_.setSize(polygonAndNormal.
size());
575 polygons[polyI] = polygonAndNormal[polyI].first();
576 normal_[polyI] = polygonAndNormal[polyI].second();
577 normal_[polyI] /=
mag(normal_[polyI]) + ROOTVSMALL;
580 initPolygons(polygons);
582 else if (
mode ==
"concentricCircle")
587 initConcentricCircles();
592 <<
"Unknown mode " <<
mode <<
". Available options are "
593 <<
"polygon, polygonWithNormal and concentricCircle"
597 mass_.setSize(faces_.size(), 0.0);
598 massTotal_.setSize(faces_.size(), 0.0);
599 massFlowRate_.setSize(faces_.size(), 0.0);
601 makeLogFile(faces_, points_, area_);
605 template<
class CloudType>
638 template<
class CloudType>
645 template<
class CloudType>
651 const point& position0,
655 if ((parcelType_ != -1) && (parcelType_ !=
p.typeId()))
661 const point position1 = position0 + 1.0001*(
p.position() - position0);
669 collectParcelPolygon(position0, position1);
672 case mtConcentricCircle:
674 collectParcelConcentricCircles(position0, position1);
685 label faceI = hitFaceIDs_[i];
686 scalar m =
p.nParticle()*
p.mass();
688 if (negateParcelsOppositeNormal_)
691 Uhat /=
mag(Uhat) + ROOTVSMALL;
692 if ((Uhat & normal_[faceI]) < 0)
703 mass_[faceI + 1] += m;
704 mass_[faceI + 2] += m;
705 mass_[faceI + 3] += m;
708 if (removeCollected_)
710 keepParticle =
false;