effectivenessHeatExchangerSource.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) 2013-2015 OpenFOAM Foundation
9 Copyright (C) 2016-2022 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
30#include "fvMesh.H"
31#include "fvMatrix.H"
33#include "basicThermo.H"
34#include "coupledPolyPatch.H"
35#include "surfaceInterpolate.H"
36
37// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38
39namespace Foam
40{
41namespace fv
42{
45 (
46 option,
49 );
50}
51}
52
53
54// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55
56void Foam::fv::effectivenessHeatExchangerSource::initialise()
57{
58 const label zoneID = mesh_.faceZones().findZoneID(faceZoneName_);
59
60 if (zoneID < 0)
61 {
63 << type() << " " << this->name() << ": "
64 << " Unknown face zone name: " << faceZoneName_
65 << ". Valid face zones are: " << mesh_.faceZones().names()
66 << exit(FatalError);
67 }
68
69 const faceZone& fZone = mesh_.faceZones()[zoneID];
70
71 faceId_.setSize(fZone.size());
72 facePatchId_.setSize(fZone.size());
73 faceSign_.setSize(fZone.size());
74
75 label count = 0;
76 forAll(fZone, i)
77 {
78 const label facei = fZone[i];
79 label faceId = -1;
80 label facePatchId = -1;
81 if (mesh_.isInternalFace(facei))
82 {
83 faceId = facei;
84 facePatchId = -1;
85 }
86 else
87 {
88 facePatchId = mesh_.boundaryMesh().whichPatch(facei);
89 const polyPatch& pp = mesh_.boundaryMesh()[facePatchId];
90 const auto* cpp = isA<coupledPolyPatch>(pp);
91
92 if (cpp)
93 {
94 faceId = (cpp->owner() ? pp.whichFace(facei) : -1);
95 }
96 else if (!isA<emptyPolyPatch>(pp))
97 {
98 faceId = pp.whichFace(facei);
99 }
100 else
101 {
102 faceId = -1;
103 facePatchId = -1;
104 }
105 }
106
107 if (faceId >= 0)
108 {
109 if (fZone.flipMap()[i])
110 {
111 faceSign_[count] = -1;
112 }
113 else
114 {
115 faceSign_[count] = 1;
116 }
117 faceId_[count] = faceId;
118 facePatchId_[count] = facePatchId;
119 count++;
120 }
121 }
122 faceId_.setSize(count);
123 facePatchId_.setSize(count);
124 faceSign_.setSize(count);
125}
126
127
128void Foam::fv::effectivenessHeatExchangerSource::writeFileHeader(Ostream& os)
129{
130 writeFile::writeHeader(os, "Effectiveness heat exchanger source");
131 writeFile::writeCommented(os, "Time");
132 writeFile::writeTabbed(os, "Net mass flux [kg/s]");
133 writeFile::writeTabbed(os, "Total heat exchange [W]");
134 writeFile::writeTabbed(os, "Secondary inlet T [K]");
135 writeFile::writeTabbed(os, "Tref [K]");
136 writeFile::writeTabbed(os, "Effectiveness");
137
138 if (secondaryCpPtr_)
139 {
140 writeFile::writeTabbed(os, "Secondary outlet T [K]");
141 }
142
143 os << endl;
144}
145
146
147// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
148
150(
151 const word& name,
152 const word& modelType,
153 const dictionary& dict,
154 const fvMesh& mesh
155)
156:
157 fv::cellSetOption(name, modelType, dict, mesh),
158 writeFile(mesh, name, modelType, coeffs_),
159 userPrimaryInletT_(false),
160 targetQdotActive_(false),
161 secondaryCpPtr_
162 (
163 Function1<scalar>::NewIfPresent
164 (
165 "secondaryCp",
166 coeffs_,
167 word::null,
168 &mesh
169 )
170 ),
171 eTable_(),
172 targetQdotCalcInterval_(5),
173 secondaryMassFlowRate_(0),
174 secondaryInletT_(0),
175 primaryInletT_(0),
176 targetQdot_(0),
177 targetQdotRelax_(0.5),
178 UName_("U"),
179 TName_("T"),
180 phiName_("phi"),
181 faceZoneName_("unknown-faceZone"),
182 faceId_(),
183 facePatchId_(),
184 faceSign_()
185{
186 read(dict);
187
188 // Set the field name to that of the energy
189 // field from which the temperature is obtained
190
192
193 fieldNames_.resize(1, thermo.he().name());
194
196
197 eTable_.reset(new interpolation2DTable<scalar>(coeffs_));
198
199 initialise();
200
201 writeFileHeader(file());
202}
203
204
205// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
206
208(
209 const volScalarField& rho,
210 fvMatrix<scalar>& eqn,
211 const label
212)
213{
214 const auto& thermo = mesh_.lookupObject<basicThermo>(basicThermo::dictName);
215 const auto& phi = mesh_.lookupObject<surfaceScalarField>(phiName_);
216 const auto& T = mesh_.lookupObject<volScalarField>(TName_);
217
220
221 scalar sumPhi = 0;
222 scalar sumMagPhi = 0;
223 scalar CpfMean = 0;
224 scalar primaryInletTfMean = 0;
225 forAll(faceId_, i)
226 {
227 const label facei = faceId_[i];
228 if (facePatchId_[i] != -1)
229 {
230 const label patchi = facePatchId_[i];
231 const scalar phii = phi.boundaryField()[patchi][facei]*faceSign_[i];
232 const scalar magPhii = mag(phii);
233
234 sumPhi += phii;
235 sumMagPhi += magPhii;
236
237 const scalar Cpfi = Cpf.boundaryField()[patchi][facei];
238 const scalar Tfi = Tf.boundaryField()[patchi][facei];
239
240 CpfMean += Cpfi*magPhii;
241 primaryInletTfMean += Tfi*magPhii;
242 }
243 else
244 {
245 const scalar phii = phi[facei]*faceSign_[i];
246 const scalar magPhii = mag(phii);
247
248 sumPhi += phii;
249 sumMagPhi += magPhii;
250
251 CpfMean += Cpf[facei]*magPhii;
252 primaryInletTfMean += Tf[facei]*magPhii;
253 }
254 }
255 reduce(CpfMean, sumOp<scalar>());
256 reduce(sumPhi, sumOp<scalar>());
257 reduce(sumMagPhi, sumOp<scalar>());
258 CpfMean /= sumMagPhi + ROOTVSMALL;
259
260 scalar primaryInletT = primaryInletT_;
261 if (!userPrimaryInletT_)
262 {
263 reduce(primaryInletTfMean, sumOp<scalar>());
264 primaryInletT = primaryInletTfMean/(sumMagPhi + ROOTVSMALL);
265 }
266
267 const scalar effectiveness = eTable_()(mag(sumPhi), secondaryMassFlowRate_);
268
269 const scalar alpha = effectiveness*CpfMean*mag(sumPhi);
270
271 const scalar Qt = alpha*(secondaryInletT_ - primaryInletT);
272
273 if
274 (
275 targetQdotActive_
276 && (mesh_.time().timeIndex() % targetQdotCalcInterval_ == 0)
277 )
278 {
279 const scalar dT = (targetQdot_ - Qt)/(alpha + ROOTVSMALL);
280 secondaryInletT_ += targetQdotRelax_*dT;
281 }
282
283 const scalarField TCells(T, cells_);
284 scalar Tref = 0;
285 scalarField deltaTCells(cells_.size(), Zero);
286 if (Qt > 0)
287 {
288 Tref = gMax(TCells);
289 forAll(deltaTCells, i)
290 {
291 deltaTCells[i] = max(Tref - TCells[i], scalar(0));
292 }
293 }
294 else
295 {
296 Tref = gMin(TCells);
297 forAll(deltaTCells, i)
298 {
299 deltaTCells[i] = max(TCells[i] - Tref, scalar(0));
300 }
301 }
302
303
304 const auto& U = mesh_.lookupObject<volVectorField>(UName_);
305 const scalarField& V = mesh_.V();
306 scalar sumWeight = 0;
307 forAll(cells_, i)
308 {
309 const label celli = cells_[i];
310 sumWeight += V[celli]*mag(U[celli])*deltaTCells[i];
311 }
312 reduce(sumWeight, sumOp<scalar>());
313
314 if (this->V() > VSMALL && mag(Qt) > VSMALL)
315 {
316 scalarField& heSource = eqn.source();
317
318 forAll(cells_, i)
319 {
320 const label celli = cells_[i];
321 heSource[celli] -=
322 Qt*V[celli]*mag(U[celli])*deltaTCells[i]
323 /(sumWeight + ROOTVSMALL);
324 }
325 }
326
327 Log << nl
328 << type() << ": " << name() << nl << incrIndent
329 << indent << "Net mass flux [kg/s] : " << sumPhi << nl
330 << indent << "Total heat exchange [W] : " << Qt << nl
331 << indent << "Secondary inlet T [K] : " << secondaryInletT_ << nl
332 << indent << "Tref [K] : " << Tref << nl
333 << indent << "Effectiveness : " << effectiveness
334 << decrIndent;
335
336 if (Pstream::master())
337 {
338 Ostream& os = file();
339 writeCurrentTime(os);
340
341 os << tab << sumPhi
342 << tab << Qt
343 << tab << secondaryInletT_
344 << tab << Tref
345 << tab << effectiveness;
346
347 if (secondaryCpPtr_)
348 {
349 // Secondary Cp as a function of the starting secondary temperature
350 const scalar secondaryCp = secondaryCpPtr_->value(secondaryInletT_);
351 const scalar secondaryOutletT =
352 Qt/(secondaryMassFlowRate_*secondaryCp) + secondaryInletT_;
353
354 Log << nl << incrIndent << indent
355 << "Secondary outlet T [K] : " << secondaryOutletT
356 << decrIndent;
357
358 os << tab << secondaryOutletT;
359 }
360 os << endl;
361 }
362
363 Info<< nl << endl;
364}
365
366
368{
369 if (!(fv::cellSetOption::read(dict) && writeFile::read(dict)))
370 {
371 return false;
372 }
373
374 coeffs_.readEntry("secondaryMassFlowRate", secondaryMassFlowRate_);
375 coeffs_.readEntry("secondaryInletT", secondaryInletT_);
376
377 if (coeffs_.readIfPresent("primaryInletT", primaryInletT_))
378 {
379 userPrimaryInletT_ = true;
380 Info<< type() << " " << this->name() << ": " << indent << nl
381 << "employing user-specified primary flow inlet temperature: "
382 << primaryInletT_ << endl;
383 }
384 else
385 {
386 Info<< type() << " " << this->name() << ": " << indent << nl
387 << "employing flux-weighted primary flow inlet temperature"
388 << endl;
389 }
390
391 if (coeffs_.readIfPresent("targetQdot", targetQdot_))
392 {
393 targetQdotActive_ = true;
394 Info<< indent << "employing target heat rejection of "
395 << targetQdot_ << nl;
396
397 coeffs_.readIfPresent
398 (
399 "targetQdotCalcInterval",
400 targetQdotCalcInterval_
401 );
402
403 Info<< indent << "updating secondary inlet temperature every "
404 << targetQdotCalcInterval_ << " iterations" << nl;
405
406 coeffs_.readIfPresent("targetQdotRelax", targetQdotRelax_);
407
408 Info<< indent << "temperature relaxation: "
409 << targetQdotRelax_ << endl;
410 }
411
412 UName_ = coeffs_.getOrDefault<word>("U", "U");
413 TName_ = coeffs_.getOrDefault<word>("T", "T");
414 phiName_ = coeffs_.getOrDefault<word>("phi", "phi");
415 coeffs_.readEntry("faceZone", faceZoneName_);
416
417 return true;
418}
419
420
421// ************************************************************************* //
#define Log
Definition: PDRblock.C:35
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
surfaceScalarField & phi
Top level data entry class for use in dictionaries. Provides a mechanism to specify a variable as a c...
Definition: Function1.H:96
const Boundary & boundaryField() const
Return const-reference to the boundary field.
void setSize(const label n)
Alias for resize()
Definition: List.H:218
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
virtual bool read()
Re-read model coefficients if they have changed.
label findZoneID(const word &zoneName) const
Find zone index by name, return -1 if not found.
Definition: ZoneMesh.C:525
wordList names() const
A list of the zone names.
Definition: ZoneMesh.C:304
Abstract base-class for fluid and solid thermodynamic properties.
Definition: basicThermo.H:66
static const word dictName
Definition: basicThermo.H:256
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
virtual OFstream & file()
Return access to the file (if only 1)
Definition: writeFile.C:233
A special matrix type and solver, designed for finite volume solutions of scalar equations....
Definition: fvMatrix.H:121
Field< Type > & source() noexcept
Definition: fvMatrix.H:458
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:91
Intermediate abstract class for handling cell-set options for the derived fvOptions.
Heat exchanger source model for compressible flows, where the heat exchanger is modelled as an energy...
virtual bool read(const dictionary &dict)
Read dictionary.
virtual void addSup(fvMatrix< scalar > &eqn, const label fieldi)
Add explicit/implicit contribution to momentum equation.
Base abstract class for handling finite volume options (i.e. fvOption).
Definition: fvOption.H:127
const word & name() const noexcept
Return const access to the source name.
Definition: fvOptionI.H:31
const fvMesh & mesh_
Reference to the mesh database.
Definition: fvOption.H:139
wordList fieldNames_
Field names to apply source to - populated by derived models.
Definition: fvOption.H:148
dictionary coeffs_
Dictionary containing source coefficients.
Definition: fvOption.H:145
void resetApplied()
Resize/reset applied flag list for all fieldNames_ entries.
Definition: fvOption.C:48
2D table interpolation. The data must be in ascending order in both dimensions x and y.
const Type & lookupObject(const word &name, const bool recursive=false) const
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:498
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
splitCell * master() const
Definition: splitCell.H:113
Basic thermodynamics type based on the use of fitting functions for cp, h, s obtained from the templa...
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
U
Definition: pEqn.H:72
const volScalarField & T
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
const labelIOList & zoneID
label faceId(-1)
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:78
static tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > interpolate(const GeometricField< Type, fvPatchField, volMesh > &tvf, const surfaceScalarField &faceFlux, Istream &schemeData)
Interpolate field onto faces using scheme given by Istream.
Namespace for OpenFOAM.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
messageStream Info
Information stream (stdout output on master, null elsewhere)
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:598
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:349
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:342
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
error FatalError
Type gMin(const FieldField< Field, Type > &f)
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:356
Type gMax(const FieldField< Field, Type > &f)
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
constexpr char tab
The tab '\t' character(0x09)
Definition: Ostream.H:52
labelList fv(nPoints)
volScalarField & alpha
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333