Loading...
Searching...
No Matches
ThermalPhaseChangePhaseSystem.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) 2015-2019 OpenFOAM Foundation
9 Copyright (C) 2020 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
32#include "fvmSup.H"
33
34// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
35
36template<class BasePhaseSystem>
39(
40 const phasePairKey& key
41) const
42{
43 if (!iDmdt_.found(key))
44 {
45 return phaseSystem::dmdt(key);
46 }
47
48 const scalar dmdtSign(Pair<word>::compare(iDmdt_.find(key).key(), key));
50 return dmdtSign**iDmdt_[key];
51}
52
53
54template<class BasePhaseSystem>
57(
58 const phasePairKey& key
59) const
60{
61 if (!wDmdt_.found(key))
62 {
63 return phaseSystem::dmdt(key);
64 }
65
66 const scalar dmdtSign(Pair<word>::compare(wDmdt_.find(key).key(), key));
67
68 return dmdtSign**wDmdt_[key];
69}
70
71
72// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
73
74template<class BasePhaseSystem>
77(
78 const fvMesh& mesh
79)
80:
81 BasePhaseSystem(mesh),
82 volatile_(this->template getOrDefault<word>("volatile", "none")),
83 saturationModel_
84 (
85 saturationModel::New(this->subDict("saturationModel"), mesh)
86 ),
87 phaseChange_(this->lookup("phaseChange"))
88{
89
91 (
93 this->phasePairs_,
94 phasePairIter
95 )
96 {
97 const phasePair& pair(phasePairIter());
98
99 if (pair.ordered())
100 {
101 continue;
102 }
103
104 // Initially assume no mass transfer
105 iDmdt_.set
106 (
107 pair,
109 (
111 (
112 IOobject::groupName("iDmdt", pair.name()),
113 this->mesh().time().timeName(),
114 this->mesh(),
117 ),
118 this->mesh(),
120 )
121 );
122
123 // Initially assume no mass transfer
124 wDmdt_.set
125 (
126 pair,
128 (
130 (
131 IOobject::groupName("wDmdt", pair.name()),
132 this->mesh().time().timeName(),
133 this->mesh(),
136 ),
137 this->mesh(),
139 )
140 );
141
142 // Initially assume no mass transfer
144 (
145 pair,
147 (
149 (
150 IOobject::groupName("wMDotL", pair.name()),
151 this->mesh().time().timeName(),
152 this->mesh(),
155 ),
156 this->mesh(),
158 )
159 );
161}
162
163
164// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
165
166template<class BasePhaseSystem>
170
171
172// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
173
174template<class BasePhaseSystem>
178 return saturationModel_();
179}
180
181
182template<class BasePhaseSystem>
185(
186 const phasePairKey& key
187) const
189 return BasePhaseSystem::dmdt(key) + this->iDmdt(key) + this->wDmdt(key);
190}
191
192
193template<class BasePhaseSystem>
196{
197 PtrList<volScalarField> dmdts(BasePhaseSystem::dmdts());
198
199 forAllConstIter(iDmdtTable, iDmdt_, iDmdtIter)
200 {
201 const phasePair& pair = this->phasePairs_[iDmdtIter.key()];
202 const volScalarField& iDmdt = *iDmdtIter();
203
204 this->addField(pair.phase1(), "dmdt", iDmdt, dmdts);
205 this->addField(pair.phase2(), "dmdt", - iDmdt, dmdts);
206 }
207
208 forAllConstIter(wDmdtTable, wDmdt_, wDmdtIter)
209 {
210 const phasePair& pair = this->phasePairs_[wDmdtIter.key()];
211 const volScalarField& wDmdt = *wDmdtIter();
212
213 this->addField(pair.phase1(), "dmdt", wDmdt, dmdts);
214 this->addField(pair.phase2(), "dmdt", - wDmdt, dmdts);
215 }
217 return dmdts;
218}
219
220
221template<class BasePhaseSystem>
224{
226 BasePhaseSystem::heatTransfer();
227
228 phaseSystem::heatTransferTable& eqns = eqnsPtr();
229
230 // Add boundary term
232 (
234 this->phasePairs_,
235 phasePairIter
236 )
237 {
238 if (this->wMDotL_.found(phasePairIter.key()))
239 {
240 const phasePair& pair(phasePairIter());
241
242 if (pair.ordered())
243 {
244 continue;
245 }
246
247 const phaseModel& phase1 = pair.phase1();
248 const phaseModel& phase2 = pair.phase2();
249
250 *eqns[phase1.name()] += negPart(*this->wMDotL_[pair]);
251 *eqns[phase2.name()] -= posPart(*this->wMDotL_[pair]);
252
253 if
254 (
255 phase1.thermo().he().member() == "e"
256 || phase2.thermo().he().member() == "e"
257 )
258 {
259 const volScalarField dmdt
260 (
261 this->iDmdt(pair) + this->wDmdt(pair)
262 );
263
264 if (phase1.thermo().he().member() == "e")
265 {
266 *eqns[phase1.name()] +=
267 phase1.thermo().p()*dmdt/phase1.thermo().rho();
268 }
269
270 if (phase2.thermo().he().member() == "e")
271 {
272 *eqns[phase2.name()] -=
273 phase2.thermo().p()*dmdt/phase2.thermo().rho();
274 }
275 }
276 }
277 }
279 return eqnsPtr;
280}
281
282
283template<class BasePhaseSystem>
286{
288 BasePhaseSystem::massTransfer();
289
290 phaseSystem::massTransferTable& eqns = eqnsPtr();
291
293 (
295 this->phasePairs_,
296 phasePairIter
297 )
298 {
299 const phasePair& pair(phasePairIter());
300
301 if (pair.ordered())
302 {
303 continue;
304 }
305
306 const phaseModel& phase = pair.phase1();
307 const phaseModel& otherPhase = pair.phase2();
308
309 const PtrList<volScalarField>& Yi = phase.Y();
310
311 forAll(Yi, i)
312 {
313 if (Yi[i].member() != volatile_)
314 {
315 continue;
316 }
317
318 const word name
319 (
320 IOobject::groupName(volatile_, phase.name())
321 );
322
323 const word otherName
324 (
325 IOobject::groupName(volatile_, otherPhase.name())
326 );
327
328 // Note that the phase YiEqn does not contain a continuity error
329 // term, so these additions represent the entire mass transfer
330
331 const volScalarField dmdt(this->iDmdt(pair) + this->wDmdt(pair));
332
333 *eqns[name] += dmdt;
334 *eqns[otherName] -= dmdt;
335 }
336 }
338 return eqnsPtr;
339}
340
341
342template<class BasePhaseSystem>
343void
345{
347 alphatPhaseChangeWallFunction;
348
350 (
351 typename BasePhaseSystem::heatTransferModelTable,
352 this->heatTransferModels_,
353 heatTransferModelIter
354 )
355 {
356 const phasePair& pair
357 (
358 this->phasePairs_[heatTransferModelIter.key()]
359 );
360
361 const phaseModel& phase1 = pair.phase1();
362 const phaseModel& phase2 = pair.phase2();
363
364 const volScalarField& T1(phase1.thermo().T());
365 const volScalarField& T2(phase2.thermo().T());
366
367 const volScalarField& he1(phase1.thermo().he());
368 const volScalarField& he2(phase2.thermo().he());
369
370 const volScalarField& p(phase1.thermo().p());
371
372 volScalarField& iDmdt(*this->iDmdt_[pair]);
373 volScalarField& Tf(*this->Tf_[pair]);
374
375 const volScalarField Tsat(saturationModel_->Tsat(phase1.thermo().p()));
376
378 (
379 he1.member() == "e"
380 ? phase1.thermo().he(p, Tsat) + p/phase1.rho()
381 : phase1.thermo().he(p, Tsat)
382 );
384 (
385 he2.member() == "e"
386 ? phase2.thermo().he(p, Tsat) + p/phase2.rho()
387 : phase2.thermo().he(p, Tsat)
388 );
389
391 (
392 he1.member() == "e"
393 ? he1 + p/phase1.rho()
395 );
396
398 (
399 he2.member() == "e"
400 ? he2 + p/phase2.rho()
402 );
403
405 (
406 (neg0(iDmdt)*hf2 + pos(iDmdt)*h2)
407 - (pos0(iDmdt)*hf1 + neg(iDmdt)*h1)
408 );
409
410 volScalarField iDmdtNew(iDmdt);
411
412 if (phaseChange_)
413 {
414 volScalarField H1(heatTransferModelIter().first()->K(0));
415 volScalarField H2(heatTransferModelIter().second()->K(0));
416
417 iDmdtNew = (H1*(Tsat - T1) + H2*(Tsat - T2))/L;
418 }
419 else
420 {
421 iDmdtNew == Zero;
422 }
423
424 volScalarField H1(heatTransferModelIter().first()->K());
425 volScalarField H2(heatTransferModelIter().second()->K());
426
427 // Limit the H[12] to avoid /0
428 H1.clamp_min(SMALL);
429 H2.clamp_min(SMALL);
430
431 Tf = (H1*T1 + H2*T2 + iDmdtNew*L)/(H1 + H2);
432
433 {
434 auto limits = gMinMax(Tf.primitiveField());
435 auto avg = gAverage(Tf.primitiveField());
436
437 Info<< "Tf." << pair.name()
438 << ": min = " << limits.min()
439 << ", mean = " << avg
440 << ", max = " << limits.max()
441 << endl;
442 }
443
444 scalar iDmdtRelax(this->mesh().fieldRelaxationFactor("iDmdt"));
445 iDmdt = (1 - iDmdtRelax)*iDmdt + iDmdtRelax*iDmdtNew;
446
447 if (phaseChange_)
448 {
449 auto limits = gMinMax(iDmdt.primitiveField());
450 auto avg = gAverage(iDmdt.primitiveField());
451
452 Info<< "iDmdt." << pair.name()
453 << ": min = " << limits.min()
454 << ", mean = " << avg
455 << ", max = " << limits.max()
456 << ", integral = " << fvc::domainIntegrate(iDmdt).value()
457 << endl;
458 }
459
460 volScalarField& wDmdt(*this->wDmdt_[pair]);
461 volScalarField& wMDotL(*this->wMDotL_[pair]);
462 wDmdt *= 0.0;
463 wMDotL *= 0.0;
464
465 bool wallBoilingActive = false;
466
467 forAllConstIter(phasePair, pair, iter)
468 {
469 const phaseModel& phase = iter();
470 const phaseModel& otherPhase = iter.otherPhase();
471
472 if
473 (
474 phase.mesh().foundObject<volScalarField>
475 (
476 "alphat." + phase.name()
477 )
478 )
479 {
480 const volScalarField& alphat =
481 phase.mesh().lookupObject<volScalarField>
482 (
483 "alphat." + phase.name()
484 );
485
486 const fvPatchList& patches = this->mesh().boundary();
487 forAll(patches, patchi)
488 {
489 const fvPatch& currPatch = patches[patchi];
490
491 if
492 (
494 (
495 alphat.boundaryField()[patchi]
496 )
497 )
498 {
499 const alphatPhaseChangeWallFunction& PCpatch =
501 (
502 alphat.boundaryField()[patchi]
503 );
504
505 phasePairKey key(phase.name(), otherPhase.name());
506
507 if (PCpatch.activePhasePair(key))
508 {
509 wallBoilingActive = true;
510
511 const scalarField& patchDmdt =
512 PCpatch.dmdt(key);
513 const scalarField& patchMDotL =
514 PCpatch.mDotL(key);
515
516 const scalar sign
517 (
518 Pair<word>::compare(pair, key)
519 );
520
521 forAll(patchDmdt, facei)
522 {
523 const label faceCelli =
524 currPatch.faceCells()[facei];
525 wDmdt[faceCelli] -= sign*patchDmdt[facei];
526 wMDotL[faceCelli] -= sign*patchMDotL[facei];
527 }
528 }
529 }
530 }
531 }
532 }
533
534 if (wallBoilingActive)
535 {
536 auto limits = gMinMax(wDmdt.primitiveField());
537 auto avg = gAverage(wDmdt.primitiveField());
538
539 Info<< "wDmdt." << pair.name()
540 << ": min = " << limits.min()
541 << ", mean = " << avg
542 << ", max = " << limits.max()
543 << ", integral = " << fvc::domainIntegrate(wDmdt).value()
545 }
546 }
547}
548
549
550template<class BasePhaseSystem>
552{
553 if (BasePhaseSystem::read())
554 {
555 bool readOK = true;
556
557 // Models ...
558
559 return readOK;
560 }
561 else
562 {
563 return false;
564 }
565}
566
567
568// ************************************************************************* //
CGAL::Exact_predicates_exact_constructions_kernel K
phaseModel & phase1
phaseModel & phase2
const Mesh & mesh() const noexcept
Return const reference to mesh.
void clamp_min(const Type &lower)
Impose lower (floor) clamp on the field values (in-place).
const Internal::FieldType & primitiveField() const noexcept
Return a const-reference to the internal field values.
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
bool set(const Key &key, T *ptr)
Assign a new entry, overwrites existing.
@ READ_IF_PRESENT
Reading is optional [identical to LAZY_READ].
@ AUTO_WRITE
Automatically write from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
static word member(const word &name)
Return member (name without the extension).
Definition IOobject.C:313
static word groupName(StringType base, const word &group)
Create dot-delimited name.group string.
static int compare(const Pair< T > &a, const Pair< T > &b)
Compare Pairs.
Definition PairI.H:24
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition PtrList.H:67
virtual tmp< volScalarField > dmdt(const phasePairKey &key) const
Return the mass transfer rate for a pair.
virtual autoPtr< phaseSystem::heatTransferTable > heatTransfer() const
Return the heat transfer matrices.
autoPtr< saturationModel > saturationModel_
The saturation model used to evaluate Tsat = Tf.
virtual void correctInterfaceThermo()
Correct the interface thermodynamics.
tmp< volScalarField > wDmdt(const phasePairKey &key) const
Return the boundary mass transfer rate for a pair.
HashPtrTable< volScalarField, phasePairKey, phasePairKey::hash > iDmdtTable
wMDotLTable wMDotL_
Boundary thermal energy transfer rate.
virtual autoPtr< phaseSystem::massTransferTable > massTransfer() const
Return the mass transfer matrices.
iDmdtTable iDmdt_
Interfacial Mass transfer rate.
ThermalPhaseChangePhaseSystem(const fvMesh &)
Construct from fvMesh.
tmp< volScalarField > iDmdt(const phasePairKey &key) const
Return the interfacial mass transfer rate for a pair.
virtual PtrList< volScalarField > dmdts() const
Return the mass transfer rates for each phase.
wDmdtTable wDmdt_
Boundary Mass transfer rate.
HashPtrTable< volScalarField, phasePairKey, phasePairKey::hash > wDmdtTable
virtual bool read()
Read base phaseProperties dictionary.
const saturationModel & saturation() const
Return the saturationModel.
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
Abstract base-class for all alphatWallFunctions supporting phase-change.
Mesh data needed to do the Finite Volume discretisation.
Definition fvMesh.H:85
const fvBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition fvMesh.H:395
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition fvPatch.H:71
virtual const labelUList & faceCells() const
Return faceCells.
Definition fvPatch.C:107
Single incompressible phase derived from the phase-fraction. Used as part of the multiPhaseMixture fo...
Definition phaseModel.H:56
const phaseModel & otherPhase() const
Return the other phase in this two-phase system.
Definition phaseModel.C:211
const word & name() const
Definition phaseModel.H:166
An ordered or unorder pair of phase names. Typically specified as follows.
bool ordered() const noexcept
Return the ordered flag.
Description for mass transfer between a pair of phases. The direction of the mass transfer is from th...
Definition phasePair.H:52
virtual word name() const
Pair name.
Definition phasePair.C:62
const multiphaseInter::phaseModel & phase1() const
Definition phasePairI.H:23
const multiphaseInter::phaseModel & phase2() const
Definition phasePairI.H:29
virtual tmp< volScalarField > dmdt(const phasePairKey &key) const
Return the mass transfer rate for a pair.
HashPtrTable< fvScalarMatrix > massTransferTable
Definition phaseSystem.H:81
HashTable< autoPtr< phasePair >, phasePairKey, phasePairKey::hash > phasePairTable
Definition phaseSystem.H:89
HashPtrTable< fvScalarMatrix > heatTransferTable
Definition phaseSystem.H:79
Single incompressible phase derived from the phase-fraction. Used as part of the multiPhaseMixture fo...
Definition phase.H:53
const word & name() const
Definition phase.H:114
Lookup type of boundary radiation properties.
Definition lookup.H:60
A class for managing temporary objects.
Definition tmp.H:75
A class for handling words, derived from Foam::string.
Definition word.H:66
volScalarField & p
auto limits
Definition setRDeltaT.H:186
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
Volume integrate volField creating a volField.
Calculate the finiteVolume matrix for implicit and explicit sources.
auto & name
dimensioned< Type > domainIntegrate(const GeometricField< Type, fvPatchField, volMesh > &vf)
Type gAverage(const FieldField< Field, Type > &f, const label comm)
The global arithmetic average of a FieldField.
dimensionedScalar pos(const dimensionedScalar &ds)
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh > > &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
PtrList< fvPatch > fvPatchList
Store lists of fvPatch as a PtrList.
Definition fvPatch.H:64
dimensionedScalar pos0(const dimensionedScalar &ds)
dimensionedScalar sign(const dimensionedScalar &ds)
const dimensionSet dimEnergy
const dimensionSet dimTime(0, 0, 1, 0, 0, 0, 0)
GeometricField< scalar, fvPatchField, volMesh > volScalarField
messageStream Info
Information stream (stdout output on master, null elsewhere).
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensionedScalar negPart(const dimensionedScalar &ds)
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
dimensionedScalar neg(const dimensionedScalar &ds)
MinMax< Type > gMinMax(const FieldField< Field, Type > &f)
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
dimensionedScalar neg0(const dimensionedScalar &ds)
const dimensionSet dimVolume(pow3(dimLength))
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
const dimensionSet dimDensity
dimensionedScalar posPart(const dimensionedScalar &ds)
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object.
Definition stdFoam.H:356
volScalarField & he2
Definition EEqns.H:3
const vector L(dict.get< vector >("L"))