twoPhaseSystem.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 | Copyright (C) 2013-2016 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 "twoPhaseSystem.H"
27 #include "dragModel.H"
28 #include "virtualMassModel.H"
29 
30 #include "MULES.H"
31 #include "subCycle.H"
32 
33 #include "fvcDdt.H"
34 #include "fvcDiv.H"
35 #include "fvcSnGrad.H"
36 #include "fvcFlux.H"
37 #include "fvcSup.H"
38 
39 #include "fvmDdt.H"
40 #include "fvmLaplacian.H"
41 #include "fvmSup.H"
42 
43 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 
45 namespace Foam
46 {
47  defineTypeNameAndDebug(twoPhaseSystem, 0);
48  defineRunTimeSelectionTable(twoPhaseSystem, dictionary);
49 }
50 
51 
52 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
53 
55 (
56  const fvMesh& mesh
57 )
58 :
59  phaseSystem(mesh),
60  phase1_(phaseModels_[0]),
61  phase2_(phaseModels_[1])
62 {
63  phase2_.volScalarField::operator=(scalar(1) - phase1_);
64 
65  volScalarField& alpha1 = phase1_;
66  mesh.setFluxRequired(alpha1.name());
67 }
68 
69 
70 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
71 
73 {}
74 
75 
76 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
77 
80 {
81  return sigma
82  (
83  phasePairKey(phase1().name(), phase2().name())
84  );
85 }
86 
87 
88 const Foam::dragModel& Foam::twoPhaseSystem::drag(const phaseModel& phase) const
89 {
90  return lookupSubModel<dragModel>(phase, otherPhase(phase));
91 }
92 
93 
96 {
97  return Kd
98  (
99  phasePairKey(phase1().name(), phase2().name())
100  );
101 }
102 
103 
106 {
107  return Kdf
108  (
109  phasePairKey(phase1().name(), phase2().name())
110  );
111 }
112 
113 
115 Foam::twoPhaseSystem::virtualMass(const phaseModel& phase) const
116 {
117  return lookupSubModel<virtualMassModel>(phase, otherPhase(phase));
118 }
119 
120 
123 {
124  return Vm
125  (
126  phasePairKey(phase1().name(), phase2().name())
127  );
128 }
129 
130 
133 {
134  return Vmf
135  (
136  phasePairKey(phase1().name(), phase2().name())
137  );
138 }
139 
140 
143 {
144  return F
145  (
146  phasePairKey(phase1().name(), phase2().name())
147  );
148 }
149 
150 
153 {
154  return Ff
155  (
156  phasePairKey(phase1().name(), phase2().name())
157  );
158 }
159 
160 
163 {
164  return D
165  (
166  phasePairKey(phase1().name(), phase2().name())
167  );
168 }
169 
170 
172 {
173  return transfersMass(phase1());
174 }
175 
176 
179 {
180  return dmdt
181  (
182  phasePairKey(phase1().name(), phase2().name())
183  );
184 }
185 
186 
188 {
189  const Time& runTime = mesh_.time();
190 
191  volScalarField& alpha1 = phase1_;
192  volScalarField& alpha2 = phase2_;
193 
194  const dictionary& alphaControls = mesh_.solverDict(alpha1.name());
195 
196  label nAlphaSubCycles(readLabel(alphaControls.lookup("nAlphaSubCycles")));
197  label nAlphaCorr(readLabel(alphaControls.lookup("nAlphaCorr")));
198 
199  bool LTS = fv::localEulerDdt::enabled(mesh_);
200 
201  word alphaScheme("div(phi," + alpha1.name() + ')');
202  word alpharScheme("div(phir," + alpha1.name() + ')');
203 
204  const surfaceScalarField& phi = this->phi();
205  const surfaceScalarField& phi1 = phase1_.phi();
206  const surfaceScalarField& phi2 = phase2_.phi();
207 
208  // Construct the dilatation rate source term
209  tmp<volScalarField::Internal> tdgdt;
210 
211  if (phase1_.divU().valid() && phase2_.divU().valid())
212  {
213  tdgdt =
214  (
215  alpha2()
216  *phase1_.divU()()()
217  - alpha1()
218  *phase2_.divU()()()
219  );
220  }
221  else if (phase1_.divU().valid())
222  {
223  tdgdt =
224  (
225  alpha2()
226  *phase1_.divU()()()
227  );
228  }
229  else if (phase2_.divU().valid())
230  {
231  tdgdt =
232  (
233  - alpha1()
234  *phase2_.divU()()()
235  );
236  }
237 
238  alpha1.correctBoundaryConditions();
239  surfaceScalarField alpha1f(fvc::interpolate(max(alpha1, scalar(0))));
240 
241  surfaceScalarField phic("phic", phi);
242  surfaceScalarField phir("phir", phi1 - phi2);
243 
244  tmp<surfaceScalarField> alphaDbyA;
245 
246  if (notNull(phase1_.DbyA()) && notNull(phase2_.DbyA()))
247  {
248  surfaceScalarField DbyA(phase1_.DbyA() + phase2_.DbyA());
249 
250  alphaDbyA =
251  fvc::interpolate(max(alpha1, scalar(0)))
252  *fvc::interpolate(max(alpha2, scalar(0)))
253  *DbyA;
254 
255  phir += DbyA*fvc::snGrad(alpha1, "bounded")*mesh_.magSf();
256  }
257 
258  for (int acorr=0; acorr<nAlphaCorr; acorr++)
259  {
261  (
262  IOobject
263  (
264  "Sp",
265  runTime.timeName(),
266  mesh_
267  ),
268  mesh_,
269  dimensionedScalar("Sp", dimless/dimTime, 0.0)
270  );
271 
273  (
274  IOobject
275  (
276  "Su",
277  runTime.timeName(),
278  mesh_
279  ),
280  // Divergence term is handled explicitly to be
281  // consistent with the explicit transport solution
282  fvc::div(phi)*min(alpha1, scalar(1))
283  );
284 
285  if (tdgdt.valid())
286  {
287  scalarField& dgdt = tdgdt.ref();
288 
289  forAll(dgdt, celli)
290  {
291  if (dgdt[celli] > 0.0)
292  {
293  Sp[celli] -= dgdt[celli]/max(1.0 - alpha1[celli], 1e-4);
294  Su[celli] += dgdt[celli]/max(1.0 - alpha1[celli], 1e-4);
295  }
296  else if (dgdt[celli] < 0.0)
297  {
298  Sp[celli] += dgdt[celli]/max(alpha1[celli], 1e-4);
299  }
300  }
301  }
302 
303  surfaceScalarField alphaPhic1
304  (
305  fvc::flux
306  (
307  phic,
308  alpha1,
309  alphaScheme
310  )
311  + fvc::flux
312  (
313  -fvc::flux(-phir, scalar(1) - alpha1, alpharScheme),
314  alpha1,
316  )
317  );
318 
319  surfaceScalarField::Boundary& alphaPhic1Bf =
320  alphaPhic1.boundaryFieldRef();
321 
322  // Ensure that the flux at inflow BCs is preserved
323  forAll(alphaPhic1Bf, patchi)
324  {
325  fvsPatchScalarField& alphaPhic1p = alphaPhic1Bf[patchi];
326 
327  if (!alphaPhic1p.coupled())
328  {
329  const scalarField& phi1p = phi1.boundaryField()[patchi];
330  const scalarField& alpha1p = alpha1.boundaryField()[patchi];
331 
332  forAll(alphaPhic1p, facei)
333  {
334  if (phi1p[facei] < 0)
335  {
336  alphaPhic1p[facei] = alpha1p[facei]*phi1p[facei];
337  }
338  }
339  }
340  }
341 
342  if (nAlphaSubCycles > 1)
343  {
344  tmp<volScalarField> trSubDeltaT;
345 
346  if (LTS)
347  {
348  trSubDeltaT =
350  }
351 
352  for
353  (
354  subCycle<volScalarField> alphaSubCycle(alpha1, nAlphaSubCycles);
355  !(++alphaSubCycle).end();
356  )
357  {
358  surfaceScalarField alphaPhic10(alphaPhic1);
359 
361  (
362  geometricOneField(),
363  alpha1,
364  phi,
365  alphaPhic10,
366  (alphaSubCycle.index()*Sp)(),
367  (Su - (alphaSubCycle.index() - 1)*Sp*alpha1)(),
368  phase1_.alphaMax(),
369  0
370  );
371 
372  if (alphaSubCycle.index() == 1)
373  {
374  phase1_.alphaPhi() = alphaPhic10;
375  }
376  else
377  {
378  phase1_.alphaPhi() += alphaPhic10;
379  }
380  }
381 
382  phase1_.alphaPhi() /= nAlphaSubCycles;
383  }
384  else
385  {
387  (
388  geometricOneField(),
389  alpha1,
390  phi,
391  alphaPhic1,
392  Sp,
393  Su,
394  phase1_.alphaMax(),
395  0
396  );
397 
398  phase1_.alphaPhi() = alphaPhic1;
399  }
400 
401  if (alphaDbyA.valid())
402  {
403  fvScalarMatrix alpha1Eqn
404  (
405  fvm::ddt(alpha1) - fvc::ddt(alpha1)
406  - fvm::laplacian(alphaDbyA(), alpha1, "bounded")
407  );
408 
409  alpha1Eqn.relax();
410  alpha1Eqn.solve();
411 
412  phase1_.alphaPhi() += alpha1Eqn.flux();
413  }
414 
415  phase1_.alphaRhoPhi() =
416  fvc::interpolate(phase1_.rho())*phase1_.alphaPhi();
417 
418  phase2_.alphaPhi() = phi - phase1_.alphaPhi();
419  alpha2 = scalar(1) - alpha1;
420  phase2_.alphaRhoPhi() =
421  fvc::interpolate(phase2_.rho())*phase2_.alphaPhi();
422 
423  Info<< alpha1.name() << " volume fraction = "
424  << alpha1.weightedAverage(mesh_.V()).value()
425  << " Min(alpha1) = " << min(alpha1).value()
426  << " Max(alpha1) = " << max(alpha1).value()
427  << endl;
428  }
429 }
430 
431 
432 // ************************************************************************* //
fvsPatchField< scalar > fvsPatchScalarField
fvMatrix< scalar > fvScalarMatrix
Definition: fvMatricesFwd.H:42
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
tmp< volScalarField > Vm() const
Return the virtual mass coefficient.
const virtualMassModel & virtualMass(const phaseModel &phase) const
Return the virtual mass model for the given phase.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
tmp< surfaceScalarField > Ff() const
Return the combined face-force (lift + wall-lubrication)
tmp< volVectorField > F() const
Return the combined force (lift + wall-lubrication)
const double e
Elementary charge.
Definition: doubleFloat.H:78
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
const phaseModel & phase() const
Definition: IATEsource.H:138
tmp< volScalarField > D() const
Return the turbulent diffusivity.
tmp< GeometricField< Type, fvPatchField, volMesh > > div(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcDiv.C:47
static tmp< volScalarField > localRSubDeltaT(const fvMesh &mesh, const label nAlphaSubCycles)
Calculate and return the reciprocal of the local sub-cycling.
Definition: localEulerDdt.C:57
word alpharScheme("div(phirb,alpha)")
tmp< surfaceScalarField > Vmf() const
Return the face virtual mass coefficient.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
const dimensionedScalar sigma
Stefan-Boltzmann constant: default SI units: [W/m2/K4].
Calculate the matrix for the laplacian of the field.
tmp< GeometricField< Type, fvPatchField, volMesh > > Sp(const volScalarField &sp, const GeometricField< Type, fvPatchField, volMesh > &vf)
Definition: fvcSup.C:67
Calculate the snGrad of the given volField.
DimensionedField< scalar, volMesh > Internal
Type of the internal field from which this GeometricField is derived.
tmp< surfaceScalarField > Kdf() const
Return the face drag coefficient.
label nAlphaCorr(readLabel(alphaControls.lookup("nAlphaCorr")))
surfaceScalarField phir(phic *interface.nHatf())
tmp< volScalarField > sigma() const
Return the surface tension coefficient.
surfaceScalarField Ff(fluid.Ff())
tmp< GeometricField< Type, fvPatchField, volMesh > > ddt(const dimensioned< Type > dt, const fvMesh &mesh)
Definition: fvcDdt.C:45
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:52
surfaceScalarField Kdf("Kdf", fluid.Kdf())
Calculate the first temporal derivative.
volScalarField Kd(fluid.Kd())
static bool enabled(const fvMesh &mesh)
Return true if LTS is enabled.
Definition: localEulerDdt.C:36
bool transfersMass() const
Return true if there is mass transfer.
void explicitSolve(const RdeltaTType &rDeltaT, const RhoType &rho, volScalarField &psi, const surfaceScalarField &phiPsi, const SpType &Sp, const SuType &Su)
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Calculate the face-flux of the given field.
tmp< fvMatrix< Type > > ddt(const GeometricField< Type, fvPatchField, volMesh > &vf)
Definition: fvmDdt.C:46
Calulate the matrix for the first temporal derivative.
twoPhaseSystem(const fvMesh &)
Construct from fvMesh.
Calculate the field for explicit evaluation of implicit and explicit sources.
alpha2
Definition: alphaEqn.H:112
label readLabel(Istream &is)
Definition: label.H:64
phaseModel & phase1
Calculate the divergence of the given field.
defineRunTimeSelectionTable(reactionRateFlameArea, dictionary)
defineTypeNameAndDebug(combustionModel, 0)
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
volScalarField & alpha1
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
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.
const phaseModel & otherPhase() const
Definition: IATEsource.H:148
bool notNull(const T &t)
Return true if t is not a reference to the nullObject of type T.
Definition: nullObjectI.H:46
virtual void solve()
Solve for the phase fractions.
tmp< volScalarField > Kd() const
Return the drag coefficient.
label patchi
const dimensionSet dimless(0, 0, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:47
const dimensionedScalar F
Faraday constant: default SI units: [C/mol].
virtual ~twoPhaseSystem()
Destructor.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
tmp< fvMatrix< Type > > laplacian(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmLaplacian.C:46
const dimensionSet dimTime(0, 0, 1, 0, 0, 0, 0)
Definition: dimensionSets.H:51
void correctBoundaryConditions()
Correct boundary field.
messageStream Info
const dragModel & drag(const phaseModel &phase) const
Return the drag model for the given phase.
MULES: Multidimensional universal limiter for explicit solution.
tmp< volScalarField > dmdt() const
Return the interfacial mass flow rate.
surfaceScalarField Vmf("Vmf", fluid.Vmf())
phaseModel & phase2
A class for managing temporary objects.
Definition: PtrList.H:54
tmp< surfaceScalarField > flux(const volVectorField &vvf)
Return the face-flux field obtained from the given volVectorField.
Definition: fvcFlux.C:32
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
tmp< GeometricField< Type, fvPatchField, volMesh > > Su(const GeometricField< Type, fvPatchField, volMesh > &su, const GeometricField< Type, fvPatchField, volMesh > &vf)
Definition: fvcSup.C:44
tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > snGrad(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvcSnGrad.C:45
Calculate the matrix for implicit and explicit sources.
Namespace for OpenFOAM.
label nAlphaSubCycles(readLabel(alphaControls.lookup("nAlphaSubCycles")))