FacePostProcessing.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) 2011-2017 OpenFOAM Foundation
9 Copyright (C) 2016-2021 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "FacePostProcessing.H"
30#include "Pstream.H"
31#include "ListListOps.H"
32#include "globalIndex.H"
33#include "surfaceWriter.H"
34
35// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
36
37template<class CloudType>
39(
40 const word& zoneName,
41 const label zoneI,
42 const label nFaces,
43 const scalar totArea
44)
45{
46 // Create the output file if not already created
47 if (log_)
48 {
49 if (debug)
50 {
51 Info<< "Creating output file." << endl;
52 }
53
54 if (Pstream::master())
55 {
56 // Create directory if does not exist
57 mkDir(this->writeTimeDir());
58
59 // Open new file at start up
60 outputFilePtr_.set
61 (
62 zoneI,
63 new OFstream
64 (
65 this->writeTimeDir()/(type() + '_' + zoneName + ".dat")
66 )
67 );
68
69 outputFilePtr_[zoneI]
70 << "# Source : " << type() << nl
71 << "# Face zone : " << zoneName << nl
72 << "# Faces : " << nFaces << nl
73 << "# Area : " << totArea << nl
74 << "# Time" << tab << "mass" << tab << "massFlowRate" << endl;
75 }
76 }
77}
78
79
80// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
81
82template<class CloudType>
84{
85 const fvMesh& mesh = this->owner().mesh();
86 const Time& time = mesh.time();
87 const faceZoneMesh& fzm = mesh.faceZones();
88 scalar timeNew = time.value();
89 scalar timeElapsed = timeNew - timeOld_;
90
91 totalTime_ += timeElapsed;
92
93 const scalar alpha = (totalTime_ - timeElapsed)/totalTime_;
94 const scalar beta = timeElapsed/totalTime_;
95
96 forAll(faceZoneIDs_, zoneI)
97 {
98 massFlowRate_[zoneI] =
99 alpha*massFlowRate_[zoneI] + beta*mass_[zoneI]/timeElapsed;
100 massTotal_[zoneI] += mass_[zoneI];
101 }
102
103 const label proci = Pstream::myProcNo();
104
105 Info<< type() << " output:" << nl;
106
107 List<scalarField> zoneMassTotal(mass_.size());
108 List<scalarField> zoneMassFlowRate(massFlowRate_.size());
109 forAll(faceZoneIDs_, zoneI)
110 {
111 const word& zoneName = fzm[faceZoneIDs_[zoneI]].name();
112
113 scalarListList allProcMass(Pstream::nProcs());
114 allProcMass[proci] = massTotal_[zoneI];
115 Pstream::gatherList(allProcMass);
116 zoneMassTotal[zoneI] =
117 ListListOps::combine<scalarList>
118 (
119 allProcMass, accessOp<scalarList>()
120 );
121 const scalar sumMassTotal = sum(zoneMassTotal[zoneI]);
122
123 scalarListList allProcMassFlowRate(Pstream::nProcs());
124 allProcMassFlowRate[proci] = massFlowRate_[zoneI];
125 Pstream::gatherList(allProcMassFlowRate);
126 zoneMassFlowRate[zoneI] =
127 ListListOps::combine<scalarList>
128 (
129 allProcMassFlowRate, accessOp<scalarList>()
130 );
131 const scalar sumMassFlowRate = sum(zoneMassFlowRate[zoneI]);
132
133 Info<< " " << zoneName
134 << ": total mass = " << sumMassTotal
135 << "; average mass flow rate = " << sumMassFlowRate
136 << nl;
137
138 if (outputFilePtr_.set(zoneI))
139 {
140 OFstream& os = outputFilePtr_[zoneI];
141 os << time.timeName() << token::TAB << sumMassTotal << token::TAB
142 << sumMassFlowRate<< endl;
143 }
144 }
145
146 Info<< endl;
147
148
149 if (surfaceFormat_ != "none")
150 {
151 forAll(faceZoneIDs_, zoneI)
152 {
153 const faceZone& fZone = fzm[faceZoneIDs_[zoneI]];
154
155 labelList pointToGlobal;
156 labelList uniqueMeshPointLabels;
157 autoPtr<globalIndex> globalPointsPtr =
158 mesh.globalData().mergePoints
159 (
160 fZone().meshPoints(),
161 fZone().meshPointMap(),
162 pointToGlobal,
163 uniqueMeshPointLabels
164 );
165
166 pointField uniquePoints(mesh.points(), uniqueMeshPointLabels);
167 List<pointField> allProcPoints(Pstream::nProcs());
168 allProcPoints[proci] = uniquePoints;
169 Pstream::gatherList(allProcPoints);
170
171 faceList faces(fZone().localFaces());
172 forAll(faces, i)
173 {
174 inplaceRenumber(pointToGlobal, faces[i]);
175 }
176 List<faceList> allProcFaces(Pstream::nProcs());
177 allProcFaces[proci] = faces;
178 Pstream::gatherList(allProcFaces);
179
180 if (Pstream::master())
181 {
182 pointField allPoints
183 (
184 ListListOps::combine<pointField>
185 (
186 allProcPoints, accessOp<pointField>()
187 )
188 );
189
190 faceList allFaces
191 (
192 ListListOps::combine<faceList>
193 (
194 allProcFaces, accessOp<faceList>()
195 )
196 );
197
198 auto writer = surfaceWriter::New
199 (
200 surfaceFormat_,
201 this->coeffDict().subOrEmptyDict("formatOptions")
202 .subOrEmptyDict(surfaceFormat_)
203 );
204
205 if (debug)
206 {
207 writer->verbose(true);
208 }
209
210 writer->open
211 (
212 allPoints,
213 allFaces,
214 (this->writeTimeDir() / fZone.name()),
215 false // serial - already merged
216 );
217
218 writer->nFields(2); // Legacy VTK
219 writer->write("massTotal", zoneMassTotal[zoneI]);
220 writer->write("massFlowRate", zoneMassFlowRate[zoneI]);
221 }
222 }
223 }
224
225
226 if (resetOnWrite_)
227 {
228 forAll(faceZoneIDs_, zoneI)
229 {
230 massFlowRate_[zoneI] = 0.0;
231 }
232 timeOld_ = timeNew;
233 totalTime_ = 0.0;
234 }
235
236 forAll(mass_, zoneI)
237 {
238 mass_[zoneI] = 0.0;
239 }
240
241 // writeProperties();
242}
243
244
245// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
246
247template<class CloudType>
249(
250 const dictionary& dict,
251 CloudType& owner,
252 const word& modelName
253)
254:
255 CloudFunctionObject<CloudType>(dict, owner, modelName, typeName),
256 faceZoneIDs_(),
257 surfaceFormat_(this->coeffDict().lookup("surfaceFormat")),
258 resetOnWrite_(this->coeffDict().getBool("resetOnWrite")),
259 log_(this->coeffDict().getBool("log")),
260 totalTime_(0.0),
261 mass_(),
262 massTotal_(),
263 massFlowRate_(),
264 outputFilePtr_(),
265 timeOld_(owner.mesh().time().value())
266{
267 wordList faceZoneNames(this->coeffDict().lookup("faceZones"));
268 mass_.setSize(faceZoneNames.size());
269 massTotal_.setSize(faceZoneNames.size());
270 massFlowRate_.setSize(faceZoneNames.size());
271
272 outputFilePtr_.setSize(faceZoneNames.size());
273
275 const faceZoneMesh& fzm = owner.mesh().faceZones();
276 const surfaceScalarField& magSf = owner.mesh().magSf();
277 const polyBoundaryMesh& pbm = owner.mesh().boundaryMesh();
278 forAll(faceZoneNames, i)
279 {
280 const word& zoneName = faceZoneNames[i];
281 label zoneI = fzm.findZoneID(zoneName);
282 if (zoneI != -1)
283 {
284 zoneIDs.append(zoneI);
285 const faceZone& fz = fzm[zoneI];
286 mass_[i].setSize(fz.size(), 0.0);
287 massTotal_[i].setSize(fz.size(), 0.0);
288 massFlowRate_[i].setSize(fz.size(), 0.0);
289
290 label nFaces = returnReduce(fz.size(), sumOp<label>());
291 Info<< " " << zoneName << " faces: " << nFaces << nl;
292
293 scalar totArea = 0.0;
294 forAll(fz, j)
295 {
296 label facei = fz[j];
297 if (facei < owner.mesh().nInternalFaces())
298 {
299 totArea += magSf[fz[j]];
300 }
301 else
302 {
303 label bFacei = facei - owner.mesh().nInternalFaces();
304 label patchi = pbm.patchID()[bFacei];
305 const polyPatch& pp = pbm[patchi];
306
307 if
308 (
309 !magSf.boundaryField()[patchi].coupled()
310 || refCast<const coupledPolyPatch>(pp).owner()
311 )
312 {
313 label localFacei = pp.whichFace(facei);
314 totArea += magSf.boundaryField()[patchi][localFacei];
315 }
316 }
317 }
318 totArea = returnReduce(totArea, sumOp<scalar>());
319
320 makeLogFile(zoneName, i, nFaces, totArea);
321 }
322 }
323
324 faceZoneIDs_.transfer(zoneIDs);
325
326 // readProperties(); AND initialise mass... fields
327}
328
329
330template<class CloudType>
332(
334)
335:
337 faceZoneIDs_(pff.faceZoneIDs_),
338 surfaceFormat_(pff.surfaceFormat_),
339 resetOnWrite_(pff.resetOnWrite_),
340 log_(pff.log_),
341 totalTime_(pff.totalTime_),
342 mass_(pff.mass_),
343 massTotal_(pff.massTotal_),
344 massFlowRate_(pff.massFlowRate_),
345 outputFilePtr_(),
346 timeOld_(0.0)
347{}
348
349
350// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
351
352template<class CloudType>
354{
355 if
356 (
357 this->owner().solution().output()
358 || this->owner().solution().transient()
359 )
360 {
361 const faceZoneMesh& fzm = this->owner().mesh().faceZones();
362
363 forAll(faceZoneIDs_, i)
364 {
365 const faceZone& fz = fzm[faceZoneIDs_[i]];
366
367 label faceId = -1;
368 forAll(fz, j)
369 {
370 if (fz[j] == p.face())
371 {
372 faceId = j;
373 break;
374 }
375 }
376
377 if (faceId != -1)
378 {
379 mass_[i][faceId] += p.mass()*p.nParticle();
380 }
381 }
382 }
383}
384
385
386// ************************************************************************* //
vtk::internalMeshWriter writer(topoMesh, topoCells, vtk::formatType::INLINE_ASCII, runTime.path()/"blockTopology")
Templated cloud function object base class.
const CloudType & owner() const
Return const access to the owner cloud.
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:75
const fvMesh & mesh() const
Return reference to the mesh.
Definition: DSMCCloudI.H:44
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
Records particle face quantities on used-specified face zone.
void write()
Write post-processing info.
virtual void postFace(const parcelType &p, bool &keepParticle)
Post-face hook.
const Boundary & boundaryField() const
Return const-reference to the boundary field.
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:65
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
void transfer(List< T > &list)
Definition: List.C:447
void setSize(const label n)
Alias for resize()
Definition: List.H:218
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
Output to file stream, using an OSstream.
Definition: OFstream.H:57
The TAB Method for Numerical Calculation of Spray Droplet Breakup.
Definition: TAB.H:69
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:80
static word timeName(const scalar t, const int precision=precision_)
Definition: Time.C:780
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
label findZoneID(const word &zoneName) const
Find zone index by name, return -1 if not found.
Definition: ZoneMesh.C:525
const MeshType & mesh() const noexcept
Return the mesh reference.
Definition: ZoneMesh.H:142
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
const Type & value() const
Return const reference to value.
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:67
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:91
const surfaceScalarField & magSf() const
Return cell face area magnitudes.
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
const labelList & patchID() const
Per boundary face label the patch index.
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:498
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:75
label whichFace(const label l) const
Return label of face in patch from global face label.
Definition: polyPatch.H:451
label nInternalFaces() const noexcept
Number of internal faces.
Lookup type of boundary radiation properties.
Definition: lookup.H:66
Selector class for relaxation factors, solver type and solution.
Definition: solution.H:66
const dictionary & coeffDict() const
Return const access to the coefficients dictionary.
Definition: subModelBase.C:131
A class for handling words, derived from Foam::string.
Definition: word.H:68
const word & name() const noexcept
The zone name.
volScalarField & p
dynamicFvMesh & mesh
OBJstream os(runTime.globalPath()/outputName)
const labelList nFaces(UPstream::listGatherValues< label >(aMesh.nFaces()))
const labelIOList & zoneIDs
Definition: correctPhi.H:59
label faceId(-1)
type
Types of root.
Definition: Roots.H:55
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
static Ostream & output(Ostream &os, const IntRange< T > &range)
Definition: IntRanges.C:66
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
constexpr char tab
The tab '\t' character(0x09)
Definition: Ostream.H:52
volScalarField & alpha
dictionary dict
dimensionedScalar beta("beta", dimless/dimTemperature, laminarTransport)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
mkDir(pdfPath)