TwoResistanceHeatTransferPhaseSystem.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) 2015-2020 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 
28 #include "heatTransferModel.H"
29 #include "fvmSup.H"
30 #include "rhoReactionThermo.H"
31 
32 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
33 
34 template<class BasePhaseSystem>
36 (
37  const phaseSystem::dmdtfTable& dmdtfs,
38  phaseSystem::heatTransferTable& eqns
39 ) const
40 {
41  // In the presence of thermally-coupled mass transfer, the relation between
42  // heat transfers across the interface between phases 1 and 2 is:
43  //
44  // Q1 + Q2 = mDot*L
45  // H1*(Tf - T1) + H2*(Tf - T1) = mDot*L
46  //
47  // Where Q1 and Q2 are the net transfer into phases 1 and 2 respectively,
48  // H1 and H2 are the heat transfer coefficients on either side, Tf is the
49  // temperature at the interface, mDot is the mass transfer rate from phase
50  // 2 to phase 1, and L is the latent heat of phase 2 minus phase 1.
51  //
52  // Rearranging for Tf:
53  //
54  // Tf = (H1*T1 + H2*T2 + mDot*L)/(H1 + H2)
55  //
56  // And for Q1 and Q2:
57  //
58  // Q1 = HEff*(T2 - T1) + H1/(H1 + H2)*mDot*L
59  // Q2 = HEff*(T1 - T2) + H2/(H1 + H2)*mDot*L
60  //
61  // The HEff terms are those implemented in the heatTransfer method. The
62  // latent heat mDot*L terms are added below (as well as other standard
63  // terms representing sensible energy and kinetic energy differences).
64 
65  forAllConstIter(phaseSystem::dmdtfTable, dmdtfs, dmdtfIter)
66  {
67  const phasePairKey& key = dmdtfIter.key();
68  const phasePair& pair(this->phasePairs_[key]);
69 
70  const volScalarField dmdtf(Pair<word>::compare(pair, key)**dmdtfIter());
71  const volScalarField dmdtf21(posPart(dmdtf));
72  const volScalarField dmdtf12(negPart(dmdtf));
73 
74  const phaseModel& phase1 = pair.phase1();
75  const phaseModel& phase2 = pair.phase2();
76  const rhoThermo& thermo1 = phase1.thermo();
77  const rhoThermo& thermo2 = phase2.thermo();
78  const volScalarField& he1(thermo1.he());
79  const volScalarField& he2(thermo2.he());
80  const volScalarField K1(phase1.K());
81  const volScalarField K2(phase2.K());
82 
83  if (heatTransferModels_.found(key))
84  {
85  // Assume a thermally-coupled mass transfer process. Calculate
86  // heat transfers by evaluating properties at the interface
87  // temperature...
88 
89  // Transfer of energy from the interface into the bulk
90  const volScalarField& Tf(*Tf_[key]);
91  const volScalarField hef1(thermo1.he(thermo1.p(), Tf));
92  const volScalarField hef2(thermo2.he(thermo2.p(), Tf));
93  *eqns[phase1.name()] += dmdtf*hef1;
94  *eqns[phase2.name()] -= dmdtf*hef2;
95 
96  // Latent heat contribution
97  const volScalarField L(hef2 + thermo2.hc() - hef1 - thermo1.hc());
98  const volScalarField H1(heatTransferModels_[key].first()->K());
99  const volScalarField H2(heatTransferModels_[key].second()->K());
100  const volScalarField H1Fac(H1/(H1 + H2));
101  *eqns[phase1.name()] += H1Fac*dmdtf*L;
102  *eqns[phase2.name()] += (1 - H1Fac)*dmdtf*L;
103 
104  // Transfer of kinetic energy
105  *eqns[phase1.name()] += dmdtf21*K2 + dmdtf12*K1;
106  *eqns[phase2.name()] -= dmdtf12*K1 + dmdtf21*K2;
107  }
108  else
109  {
110  // In the absence of a heat transfer model, assume a
111  // non-thermally-coupled mass transfer process; i.e., no phase
112  // change and therefore no interface state or latent heat...
113 
114  // Transfer of energy from bulk to bulk
115  *eqns[phase1.name()] += dmdtf21*he2 + fvm::Sp(dmdtf12, he1);
116  *eqns[phase2.name()] -= dmdtf12*he1 + fvm::Sp(dmdtf21, he2);
117 
118  // Transfer of kinetic energy
119  *eqns[phase1.name()] += dmdtf21*K2 + dmdtf12*K1;
120  *eqns[phase2.name()] -= dmdtf12*K1 + dmdtf21*K2;
121  }
122  }
123 }
124 
125 
126 template<class BasePhaseSystem>
128 (
129  const phaseSystem::dmidtfTable& dmidtfs,
130  phaseSystem::heatTransferTable& eqns
131 ) const
132 {
133  // See the addDmdtHe method for a description of the latent heat terms
134 
135  forAllConstIter(phaseSystem::dmidtfTable, dmidtfs, dmidtfIter)
136  {
137  const phasePairKey& key = dmidtfIter.key();
138  const phasePair& pair(this->phasePairs_[key]);
139 
140  const phaseModel& phase1 = pair.phase1();
141  const phaseModel& phase2 = pair.phase2();
142  const rhoThermo& thermo1 = phase1.thermo();
143  const rhoThermo& thermo2 = phase2.thermo();
144  const volScalarField& he1(thermo1.he());
145  const volScalarField& he2(thermo2.he());
146  const volScalarField K1(phase1.K());
147  const volScalarField K2(phase2.K());
148 
149  if (heatTransferModels_.found(key))
150  {
151  // Assume a thermally-coupled mass transfer process. Calculate
152  // heat transfers by evaluating properties at the interface
153  // temperature...
154 
155  // Transfer coefficients
156  const volScalarField H1(heatTransferModels_[key].first()->K());
157  const volScalarField H2(heatTransferModels_[key].second()->K());
158  const volScalarField H1Fac(H1/(H1 + H2));
159 
160  // Interface properties
161  const volScalarField& Tf(*Tf_[key]);
162  const volScalarField hef1(thermo1.he(thermo1.p(), Tf));
163  const volScalarField hef2(thermo2.he(thermo2.p(), Tf));
164  const volScalarField hc1(thermo1.hc());
165  const volScalarField hc2(thermo2.hc());
166 
167  // Loop the species
169  (
170  HashPtrTable<volScalarField>,
171  *dmidtfIter(),
172  dmidtfJter
173  )
174  {
175  const word& member = dmidtfJter.key();
176 
177  const volScalarField dmidtf
178  (
179  Pair<word>::compare(pair, key)**dmidtfJter()
180  );
181  const volScalarField dmidtf21(posPart(dmidtf));
182  const volScalarField dmidtf12(negPart(dmidtf));
183 
184  // Create the interface energies for the transferring specie
185  volScalarField hefi1(hef1), hci1(hc1);
186  if (isA<rhoReactionThermo>(thermo1))
187  {
188  const basicSpecieMixture& composition1 =
189  refCast<const rhoReactionThermo>(thermo1).composition();
190  hefi1 =
191  composition1.HE
192  (
193  composition1.species()[member],
194  thermo1.p(),
195  Tf
196  );
197  hci1 =
199  (
201  composition1.Hf(composition1.species()[member])
202  );
203  }
204  volScalarField hefi2(hef2), hci2(hc2);
205  if (isA<rhoReactionThermo>(thermo2))
206  {
207  const basicSpecieMixture& composition2 =
208  refCast<const rhoReactionThermo>(thermo2).composition();
209  hefi2 =
210  composition2.HE
211  (
212  composition2.species()[member],
213  thermo2.p(),
214  Tf
215  );
216  hci2 =
218  (
220  composition2.Hf(composition2.species()[member])
221  );
222  }
223 
224  // Create the latent heat for the transferring specie
225  const volScalarField Li(hefi2 + hci2 - hefi1 - hci1);
226 
227  // Transfer of energy from the interface into the bulk
228  *eqns[phase1.name()] += dmidtf*hefi1;
229  *eqns[phase2.name()] -= dmidtf*hefi2;
230 
231  // Latent heat contribution
232  *eqns[phase1.name()] += H1Fac*dmidtf*Li;
233  *eqns[phase2.name()] += (1 - H1Fac)*dmidtf*Li;
234 
235  // Transfer of kinetic energy
236  *eqns[phase1.name()] += dmidtf21*K2 + dmidtf12*K1;
237  *eqns[phase2.name()] -= dmidtf12*K1 + dmidtf21*K2;
238  }
239  }
240  else
241  {
242  // In the absence of a heat transfer model, assume a
243  // non-thermally-coupled mass transfer process; i.e., no phase
244  // change and therefore no interface state or latent heat...
245 
246  // Loop the species
248  (
249  HashPtrTable<volScalarField>,
250  *dmidtfIter(),
251  dmidtfJter
252  )
253  {
254  const word& member = dmidtfJter.key();
255 
256  const volScalarField dmidtf
257  (
258  Pair<word>::compare(pair, key)**dmidtfJter()
259  );
260  const volScalarField dmidtf21(posPart(dmidtf));
261  const volScalarField dmidtf12(negPart(dmidtf));
262 
263  // Create the energies for the transferring specie
264  volScalarField hei1(he1);
265  if (isA<rhoReactionThermo>(thermo1))
266  {
267  const basicSpecieMixture& composition1 =
268  refCast<const rhoReactionThermo>(thermo1).composition();
269  hei1 =
270  composition1.HE
271  (
272  composition1.species()[member],
273  thermo1.p(),
274  thermo1.T()
275  );
276  }
277  volScalarField hei2(he2);
278  if (isA<rhoReactionThermo>(thermo2))
279  {
280  const basicSpecieMixture& composition2 =
281  refCast<const rhoReactionThermo>(thermo2).composition();
282  hei2 =
283  composition2.HE
284  (
285  composition2.species()[member],
286  thermo2.p(),
287  thermo2.T()
288  );
289  }
290 
291  // Transfer of energy from bulk to bulk
292  *eqns[phase1.name()] += dmidtf21*hei2 + fvm::Sp(dmidtf12, he1);
293  *eqns[phase2.name()] -= dmidtf12*hei1 + fvm::Sp(dmidtf21, he2);
294 
295  // Transfer of kinetic energy
296  *eqns[phase1.name()] += dmidtf21*K2 + dmidtf12*K1;
297  *eqns[phase2.name()] -= dmidtf12*K1 + dmidtf21*K2;
298  }
299  }
300  }
301 }
302 
303 
304 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
305 
306 template<class BasePhaseSystem>
309 (
310  const fvMesh& mesh
311 )
312 :
313  BasePhaseSystem(mesh)
314 {
315  this->generatePairsAndSubModels
316  (
317  "heatTransfer",
318  heatTransferModels_,
319  false
320  );
321 
322  // Check that models have been specified on both sides of the interfaces
324  (
325  heatTransferModelTable,
326  heatTransferModels_,
327  heatTransferModelIter
328  )
329  {
330  const phasePair& pair = this->phasePairs_[heatTransferModelIter.key()];
331 
332  if (!heatTransferModels_[pair].first().valid())
333  {
335  << "A heat transfer model for the " << pair.phase1().name()
336  << " side of the " << pair << " pair is not specified"
337  << exit(FatalError);
338  }
339  if (!heatTransferModels_[pair].second().valid())
340  {
342  << "A heat transfer model for the " << pair.phase2().name()
343  << " side of the " << pair << " pair is not specified"
344  << exit(FatalError);
345  }
346  }
347 
348  // Calculate initial Tf-s as the mean between the two phases
350  (
351  heatTransferModelTable,
352  heatTransferModels_,
353  heatTransferModelIter
354  )
355  {
356  const phasePair& pair = this->phasePairs_[heatTransferModelIter.key()];
357 
358  const volScalarField& T1(pair.phase1().thermo().T());
359  const volScalarField& T2(pair.phase2().thermo().T());
360 
361  Tf_.insert
362  (
363  pair,
364  new volScalarField
365  (
366  IOobject
367  (
368  IOobject::groupName("Tf", pair.name()),
369  this->mesh().time().timeName(),
370  this->mesh(),
373  ),
374  (T1 + T2)/2
375  )
376  );
377  }
378 }
379 
380 
381 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
382 
383 template<class BasePhaseSystem>
386 {}
387 
388 
389 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
390 
391 template<class BasePhaseSystem>
394 heatTransfer() const
395 {
396  autoPtr<phaseSystem::heatTransferTable> eqnsPtr
397  (
399  );
400 
401  phaseSystem::heatTransferTable& eqns = eqnsPtr();
402 
403  forAll(this->phaseModels_, phasei)
404  {
405  const phaseModel& phase = this->phaseModels_[phasei];
406 
407  eqns.insert
408  (
409  phase.name(),
410  new fvScalarMatrix(phase.thermo().he(), dimEnergy/dimTime)
411  );
412  }
413 
414  // In the absence of mass transfer, the relation between heat transfers
415  // across the interface between phases 1 and 2 is:
416  //
417  // Q1 + Q2 = 0
418  // H1*(Tf - T1) + H2*(Tf - T1) = 0
419  //
420  // Where Q1 and Q2 are the net transfer into phases 1 and 2 respectively,
421  // H1 and H2 are the heat transfer coefficients on either side, and Tf is
422  // the temperature at the interface.
423  //
424  // Rearranging for Tf:
425  //
426  // Tf = (H1*T1 + H2*T2)/(H1 + H2)
427  //
428  // Which gives the following for Q1 and Q2:
429  //
430  // Q1 = H1*H2/(H1 + H2)*(T2 - T1)
431  // Q2 = H1*H2/(H1 + H2)*(T1 - T2)
432  //
433  // The transfer is therefore the same as for the single-resistance system
434  // with a single effective heat transfer coefficient:
435  //
436  // HEff = H1*H2/(H1 + H2)
437  //
438  // This is implemented below
439 
441  (
442  heatTransferModelTable,
443  heatTransferModels_,
444  heatTransferModelIter
445  )
446  {
447  const phasePair& pair
448  (
449  this->phasePairs_[heatTransferModelIter.key()]
450  );
451 
452  const phaseModel& phase1 = pair.phase1();
453  const phaseModel& phase2 = pair.phase2();
454 
455  const volScalarField& he1(phase1.thermo().he());
456  const volScalarField& he2(phase2.thermo().he());
457 
458  const volScalarField Cpv1(phase1.thermo().Cpv());
459  const volScalarField Cpv2(phase2.thermo().Cpv());
460 
461  // Heat transfer between phases in the absence of mass transfer
462  const volScalarField H1(heatTransferModelIter().first()->K());
463  const volScalarField H2(heatTransferModelIter().second()->K());
464  const volScalarField HEff(H1*H2/(H1 + H2));
465  *eqns[phase1.name()] +=
466  HEff*(phase2.thermo().T() - phase1.thermo().T())
467  + H1/Cpv1*he1 - fvm::Sp(H1/Cpv1, he1);
468  *eqns[phase2.name()] +=
469  HEff*(phase1.thermo().T() - phase2.thermo().T())
470  + H2/Cpv2*he2 - fvm::Sp(H2/Cpv2, he2);
471  }
472 
473  return eqnsPtr;
474 }
475 
476 
477 template<class BasePhaseSystem>
480 {
481  BasePhaseSystem::correctEnergyTransport();
482 
484 }
485 
486 
487 template<class BasePhaseSystem>
490 {
492  (
493  heatTransferModelTable,
494  heatTransferModels_,
495  heatTransferModelIter
496  )
497  {
498  const phasePair& pair = this->phasePairs_[heatTransferModelIter.key()];
499 
500  const phaseModel& phase1 = pair.phase1();
501  const phaseModel& phase2 = pair.phase2();
502 
503  const volScalarField& T1(phase1.thermo().T());
504  const volScalarField& T2(phase2.thermo().T());
505 
506  const volScalarField H1(heatTransferModels_[pair].first()->K());
507  const volScalarField H2(heatTransferModels_[pair].second()->K());
508  const dimensionedScalar HSmall(H1.dimensions(), small);
509 
510  volScalarField& Tf = *Tf_[pair];
511 
512  Tf = (H1*T1 + H2*T2)/max(H1 + H2, HSmall);
513 
514  Info<< "Tf." << pair.name()
515  << ": min = " << min(Tf.primitiveField())
516  << ", mean = " << average(Tf.primitiveField())
517  << ", max = " << max(Tf.primitiveField())
518  << endl;
519  }
520 }
521 
522 
523 template<class BasePhaseSystem>
525 {
526  if (BasePhaseSystem::read())
527  {
528  bool readOK = true;
529 
530  // Models ...
531 
532  return readOK;
533  }
534  else
535  {
536  return false;
537  }
538 }
539 
540 
541 // ************************************************************************* //
fvMatrix< scalar > fvScalarMatrix
Definition: fvMatricesFwd.H:42
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
label phasei
Definition: pEqn.H:27
#define K1
Definition: SHA1.C:167
error FatalError
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
basicSpecieMixture & composition
#define K2
Definition: SHA1.C:168
static int compare(const Pair< word > &a, const Pair< word > &b)
Compare Pairs.
Definition: Pair.H:142
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
HashPtrTable< fvScalarMatrix > heatTransferTable
Definition: phaseSystem.H:77
void read(Istream &, label &, const dictionary &)
In-place read with dictionary lookup.
tmp< fvMatrix< Type > > Sp(const volScalarField::Internal &, const GeometricField< Type, fvPatchField, volMesh > &)
CGAL::Exact_predicates_exact_constructions_kernel K
dimensionedScalar posPart(const dimensionedScalar &ds)
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:57
virtual void correctInterfaceThermo()
Correct the interface thermodynamics.
dynamicFvMesh & mesh
mixture thermo2().correctRho(psi2 *(p_rgh - p_rgh_0))
static word groupName(Name name, const word &group)
void addDmidtHef(const phaseSystem::dmidtfTable &dmidtfs, phaseSystem::heatTransferTable &eqns) const
Add energy transfer terms which result from specie mass transfers.
virtual void correctInterfaceThermo()
Correct the interface thermodynamics.
mixture thermo1().correctRho(psi1 *(p_rgh - p_rgh_0))
dimensioned< Type > average(const DimensionedField< Type, GeoMesh > &df)
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
void addDmdtHefs(const phaseSystem::dmdtfTable &dmdtfs, phaseSystem::heatTransferTable &eqns) const
Add energy transfer terms which result from bulk mass transfers.
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
const dimensionSet dimEnergy
virtual autoPtr< phaseSystem::heatTransferTable > heatTransfer() const
Return the heat transfer matrices.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
const dimensionSet dimTime(0, 0, 1, 0, 0, 0, 0)
Definition: dimensionSets.H:51
virtual ~TwoResistanceHeatTransferPhaseSystem()
Destructor.
messageStream Info
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
const dimensionSet dimMass(1, 0, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:49
virtual void correctEnergyTransport()
Correct the energy transport e.g. alphat and Tf.
Calculate the matrix for implicit and explicit sources.
dimensionedScalar negPart(const dimensionedScalar &ds)
TwoResistanceHeatTransferPhaseSystem(const fvMesh &)
Construct from fvMesh.
zeroField Sp
Definition: alphaSuSp.H:2
virtual bool read()
Read base phaseProperties dictionary.