FacePostProcessing.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "FacePostProcessing.H"
27 #include "Pstream.H"
28 #include "ListListOps.H"
29 #include "surfaceWriter.H"
30 #include "globalIndex.H"
31 
32 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
33 
34 template<class CloudType>
36 (
37  const word& zoneName,
38  const label zoneI,
39  const label nFaces,
40  const scalar totArea
41 )
42 {
43  // Create the output file if not already created
44  if (log_)
45  {
46  if (debug)
47  {
48  Info<< "Creating output file." << endl;
49  }
50 
51  if (Pstream::master())
52  {
53  // Create directory if does not exist
54  mkDir(this->writeTimeDir());
55 
56  // Open new file at start up
57  outputFilePtr_.set
58  (
59  zoneI,
60  new OFstream
61  (
62  this->writeTimeDir()/(type() + '_' + zoneName + ".dat")
63  )
64  );
65 
66  outputFilePtr_[zoneI]
67  << "# Source : " << type() << nl
68  << "# Face zone : " << zoneName << nl
69  << "# Faces : " << nFaces << nl
70  << "# Area : " << totArea << nl
71  << "# Time" << tab << "mass" << tab << "massFlowRate" << endl;
72  }
73  }
74 }
75 
76 
77 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
78 
79 template<class CloudType>
81 {
82  const fvMesh& mesh = this->owner().mesh();
83  const Time& time = mesh.time();
84  const meshFaceZones& mfz = mesh.faceZones();
85  scalar timeNew = time.value();
86  scalar timeElapsed = timeNew - timeOld_;
87 
88  totalTime_ += timeElapsed;
89 
90  const scalar alpha = (totalTime_ - timeElapsed)/totalTime_;
91  const scalar beta = timeElapsed/totalTime_;
92 
93  forAll(faceZoneIDs_, zoneI)
94  {
95  massFlowRate_[zoneI] =
96  alpha*massFlowRate_[zoneI] + beta*mass_[zoneI]/timeElapsed;
97  massTotal_[zoneI] += mass_[zoneI];
98  }
99 
100  const label proci = Pstream::myProcNo();
101 
102  Info<< type() << " output:" << nl;
103 
104  List<scalarField> zoneMassTotal(mass_.size());
105  List<scalarField> zoneMassFlowRate(massFlowRate_.size());
106  forAll(faceZoneIDs_, zoneI)
107  {
108  const word& zoneName = mfz[faceZoneIDs_[zoneI]].name();
109 
110  scalarListList allProcMass(Pstream::nProcs());
111  allProcMass[proci] = massTotal_[zoneI];
112  Pstream::gatherList(allProcMass);
113  zoneMassTotal[zoneI] =
114  ListListOps::combine<scalarList>
115  (
116  allProcMass, accessOp<scalarList>()
117  );
118  const scalar sumMassTotal = sum(zoneMassTotal[zoneI]);
119 
120  scalarListList allProcMassFlowRate(Pstream::nProcs());
121  allProcMassFlowRate[proci] = massFlowRate_[zoneI];
122  Pstream::gatherList(allProcMassFlowRate);
123  zoneMassFlowRate[zoneI] =
124  ListListOps::combine<scalarList>
125  (
126  allProcMassFlowRate, accessOp<scalarList>()
127  );
128  const scalar sumMassFlowRate = sum(zoneMassFlowRate[zoneI]);
129 
130  Info<< " " << zoneName
131  << ": total mass = " << sumMassTotal
132  << "; average mass flow rate = " << sumMassFlowRate
133  << nl;
134 
135  if (outputFilePtr_.set(zoneI))
136  {
137  OFstream& os = outputFilePtr_[zoneI];
138  os << time.timeName() << token::TAB << sumMassTotal << token::TAB
139  << sumMassFlowRate<< endl;
140  }
141  }
142 
143  Info<< endl;
144 
145 
146  if (surfaceFormat_ != "none")
147  {
148  forAll(faceZoneIDs_, zoneI)
149  {
150  const faceZone& fZone = mfz[faceZoneIDs_[zoneI]];
151 
152  labelList pointToGlobal;
153  labelList uniqueMeshPointLabels;
154  autoPtr<globalIndex> globalPointsPtr =
155  mesh.globalData().mergePoints
156  (
157  fZone().meshPoints(),
158  fZone().meshPointMap(),
159  pointToGlobal,
160  uniqueMeshPointLabels
161  );
162 
163  pointField uniquePoints(mesh.points(), uniqueMeshPointLabels);
164  List<pointField> allProcPoints(Pstream::nProcs());
165  allProcPoints[proci] = uniquePoints;
166  Pstream::gatherList(allProcPoints);
167 
168  faceList faces(fZone().localFaces());
169  forAll(faces, i)
170  {
171  inplaceRenumber(pointToGlobal, faces[i]);
172  }
173  List<faceList> allProcFaces(Pstream::nProcs());
174  allProcFaces[proci] = faces;
175  Pstream::gatherList(allProcFaces);
176 
177  if (Pstream::master())
178  {
180  (
181  ListListOps::combine<pointField>
182  (
183  allProcPoints, accessOp<pointField>()
184  )
185  );
186 
187  faceList allFaces
188  (
189  ListListOps::combine<faceList>
190  (
191  allProcFaces, accessOp<faceList>()
192  )
193  );
194 
196  (
197  surfaceWriter::New(surfaceFormat_, this->coeffDict())
198  );
199 
200  writer->write
201  (
202  this->writeTimeDir(),
203  fZone.name(),
204  allPoints,
205  allFaces,
206  false,
207  "massTotal",
208  zoneMassTotal[zoneI],
209  "massFlowRate",
210  zoneMassFlowRate[zoneI]
211  );
212  }
213  }
214  }
215 
216 
217  if (resetOnWrite_)
218  {
219  forAll(faceZoneIDs_, zoneI)
220  {
221  massFlowRate_[zoneI] = 0.0;
222  }
223  timeOld_ = timeNew;
224  totalTime_ = 0.0;
225  }
226 
227  forAll(mass_, zoneI)
228  {
229  mass_[zoneI] = 0.0;
230  }
231 
232  // writeProperties();
233 }
234 
235 
236 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
237 
238 template<class CloudType>
240 (
241  const dictionary& dict,
242  CloudType& owner,
243  const word& modelName
244 )
245 :
246  CloudFunctionObject<CloudType>(dict, owner, modelName, typeName),
247  faceZoneIDs_(),
248  surfaceFormat_(this->coeffDict().lookup("surfaceFormat")),
249  resetOnWrite_(this->coeffDict().lookup("resetOnWrite")),
250  totalTime_(0.0),
251  mass_(),
252  massTotal_(),
253  massFlowRate_(),
254  log_(this->coeffDict().lookup("log")),
255  outputFilePtr_(),
256  timeOld_(owner.mesh().time().value())
257 {
258  wordList faceZoneNames(this->coeffDict().lookup("faceZones"));
259  mass_.setSize(faceZoneNames.size());
260  massTotal_.setSize(faceZoneNames.size());
261  massFlowRate_.setSize(faceZoneNames.size());
262 
263  outputFilePtr_.setSize(faceZoneNames.size());
264 
265  DynamicList<label> zoneIDs;
266  const meshFaceZones& mfz = owner.mesh().faceZones();
267  const surfaceScalarField& magSf = owner.mesh().magSf();
268  const polyBoundaryMesh& pbm = owner.mesh().boundaryMesh();
269  forAll(faceZoneNames, i)
270  {
271  const word& zoneName = faceZoneNames[i];
272  label zoneI = mfz.findZoneID(zoneName);
273  if (zoneI != -1)
274  {
275  zoneIDs.append(zoneI);
276  const faceZone& fz = mfz[zoneI];
277  mass_[i].setSize(fz.size(), 0.0);
278  massTotal_[i].setSize(fz.size(), 0.0);
279  massFlowRate_[i].setSize(fz.size(), 0.0);
280 
281  label nFaces = returnReduce(fz.size(), sumOp<label>());
282  Info<< " " << zoneName << " faces: " << nFaces << nl;
283 
284  scalar totArea = 0.0;
285  forAll(fz, j)
286  {
287  label facei = fz[j];
288  if (facei < owner.mesh().nInternalFaces())
289  {
290  totArea += magSf[fz[j]];
291  }
292  else
293  {
294  label bFacei = facei - owner.mesh().nInternalFaces();
295  label patchi = pbm.patchID()[bFacei];
296  const polyPatch& pp = pbm[patchi];
297 
298  if
299  (
300  !magSf.boundaryField()[patchi].coupled()
301  || refCast<const coupledPolyPatch>(pp).owner()
302  )
303  {
304  label localFacei = pp.whichFace(facei);
305  totArea += magSf.boundaryField()[patchi][localFacei];
306  }
307  }
308  }
309  totArea = returnReduce(totArea, sumOp<scalar>());
310 
311  makeLogFile(zoneName, i, nFaces, totArea);
312  }
313  }
314 
315  faceZoneIDs_.transfer(zoneIDs);
316 
317  // readProperties(); AND initialise mass... fields
318 }
319 
320 
321 template<class CloudType>
323 (
325 )
326 :
328  faceZoneIDs_(pff.faceZoneIDs_),
329  surfaceFormat_(pff.surfaceFormat_),
330  resetOnWrite_(pff.resetOnWrite_),
331  totalTime_(pff.totalTime_),
332  mass_(pff.mass_),
333  massTotal_(pff.massTotal_),
334  massFlowRate_(pff.massFlowRate_),
335  log_(pff.log_),
336  outputFilePtr_(),
337  timeOld_(0.0)
338 {}
339 
340 
341 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
342 
343 template<class CloudType>
345 {}
346 
347 
348 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
349 
350 template<class CloudType>
351 void Foam::FacePostProcessing<CloudType>::postFace(const parcelType& p, bool&)
352 {
353  if
354  (
355  this->owner().solution().output()
356  || this->owner().solution().transient()
357  )
358  {
359  const meshFaceZones& mfz = this->owner().mesh().faceZones();
360 
361  forAll(faceZoneIDs_, i)
362  {
363  const faceZone& fz = mfz[faceZoneIDs_[i]];
364 
365  label faceId = -1;
366  forAll(fz, j)
367  {
368  if (fz[j] == p.face())
369  {
370  faceId = j;
371  break;
372  }
373  }
374 
375  if (faceId != -1)
376  {
377  mass_[i][faceId] += p.mass()*p.nParticle();
378  }
379  }
380  }
381 }
382 
383 
384 // ************************************************************************* //
dictionary dict
label findZoneID(const word &zoneName) const
Find zone index given a name.
Definition: MeshZones.C:341
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
label faceId(-1)
const word & name() const
Return name.
Definition: IOobject.H:315
autoPtr< CompressibleMomentumTransportModel > New(const volScalarField &rho, const volVectorField &U, const surfaceScalarField &phi, const viscosity &viscosity)
void inplaceRenumber(const labelUList &oldToNew, ListType &)
Inplace renumber the values of a list.
void write()
Write post-processing info.
static const char tab
Definition: Ostream.H:259
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
const Boundary & boundaryField() const
Return const-reference to the boundary field.
Output to file stream.
Definition: OFstream.H:82
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
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.
Definition: Ostream.H:251
const labelList & patchID() const
Per boundary face label the patch index.
FacePostProcessing(const dictionary &dict, CloudType &owner, const word &modelName)
Construct from dictionary.
autoPtr< globalIndex > mergePoints(labelList &pointToGlobal, labelList &uniquePoints) const
Helper for merging (collocated!) mesh point data.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:372
virtual ~FacePostProcessing()
Destructor.
fvMesh & mesh
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1211
virtual void postFace(const parcelType &p, bool &keepParticle)
Post-face hook.
stressControl lookup("compactNormalStress") >> compactNormalStress
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
static word timeName(const scalar, const int precision=curPrecision_)
Return time name of given scalar time.
Definition: Time.C:666
A class for handling words, derived from string.
Definition: word.H:59
mkDir(pdfPath)
Records particle face quantities on used-specified face zone.
const Type & value() const
Return const reference to value.
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1435
const word & name() const
Return name.
Definition: zone.H:147
void setSize(const label)
Reset size of PtrList. If extending the PtrList, new entries are.
Definition: PtrList.C:131
Foam::polyBoundaryMesh.
static const char nl
Definition: Ostream.H:260
label patchi
const meshFaceZones & faceZones() const
Return face zones.
Definition: polyMesh.H:495
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:95
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
messageStream Info
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
Selector class for relaxation factors, solver type and solution.
Definition: solution.H:48
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:65
volScalarField & p
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:75
Templated cloud function object base class.
label whichFace(const label l) const
Return label of face in patch from global face label.
Definition: polyPatch.H:386