multiphaseMixtureThermo.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) 2013-2018 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 
27 #include "alphaContactAngleFvPatchScalarField.H"
28 #include "Time.H"
29 #include "subCycle.H"
30 #include "MULES.H"
31 #include "fvcDiv.H"
32 #include "fvcGrad.H"
33 #include "fvcSnGrad.H"
34 #include "fvcFlux.H"
35 #include "fvcMeshPhi.H"
36 #include "surfaceInterpolate.H"
37 
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
42  defineTypeNameAndDebug(multiphaseMixtureThermo, 0);
43 }
44 
45 
46 const Foam::scalar Foam::multiphaseMixtureThermo::convertToRad =
48 
49 
50 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
51 
52 void Foam::multiphaseMixtureThermo::calcAlphas()
53 {
54  scalar level = 0.0;
55  alphas_ == 0.0;
56 
57  forAllIter(PtrDictionary<phaseModel>, phases_, phase)
58  {
59  alphas_ += level*phase();
60  level += 1.0;
61  }
62 }
63 
64 
65 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
66 
68 (
69  const volVectorField& U,
70  const surfaceScalarField& phi
71 )
72 :
73  psiThermo(U.mesh(), word::null),
74  phases_(lookup("phases"), phaseModel::iNew(p_, T_)),
75 
76  mesh_(U.mesh()),
77  U_(U),
78  phi_(phi),
79 
80  rhoPhi_
81  (
82  IOobject
83  (
84  "rhoPhi",
85  mesh_.time().timeName(),
86  mesh_,
87  IOobject::NO_READ,
88  IOobject::NO_WRITE
89  ),
90  mesh_,
91  dimensionedScalar("rhoPhi", dimMass/dimTime, 0.0)
92  ),
93 
94  alphas_
95  (
96  IOobject
97  (
98  "alphas",
99  mesh_.time().timeName(),
100  mesh_,
101  IOobject::NO_READ,
102  IOobject::AUTO_WRITE
103  ),
104  mesh_,
105  dimensionedScalar("alphas", dimless, 0.0)
106  ),
107 
108  sigmas_(lookup("sigmas")),
109  dimSigma_(1, 0, -2, 0, 0),
110  deltaN_
111  (
112  "deltaN",
113  1e-8/pow(average(mesh_.V()), 1.0/3.0)
114  )
115 {
116  calcAlphas();
117  alphas_.write();
118  correct();
119 }
120 
121 
122 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
123 
125 {
126  forAllIter(PtrDictionary<phaseModel>, phases_, phasei)
127  {
128  phasei().correct();
129  }
130 
131  PtrDictionary<phaseModel>::iterator phasei = phases_.begin();
132 
133  psi_ = phasei()*phasei().thermo().psi();
134  mu_ = phasei()*phasei().thermo().mu();
135  alpha_ = phasei()*phasei().thermo().alpha();
136 
137  for (++phasei; phasei != phases_.end(); ++phasei)
138  {
139  psi_ += phasei()*phasei().thermo().psi();
140  mu_ += phasei()*phasei().thermo().mu();
141  alpha_ += phasei()*phasei().thermo().alpha();
142  }
143 }
144 
145 
147 {
148  forAllIter(PtrDictionary<phaseModel>, phases_, phasei)
149  {
150  phasei().thermo().rho() += phasei().thermo().psi()*dp;
151  }
152 }
153 
154 
156 {
157  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
158 
159  word name = phasei().thermo().thermoName();
160 
161  for (++ phasei; phasei != phases_.end(); ++ phasei)
162  {
163  name += ',' + phasei().thermo().thermoName();
164  }
165 
166  return name;
167 }
168 
169 
171 {
172  bool ico = true;
173 
174  forAllConstIter(PtrDictionary<phaseModel>, phases_, phase)
175  {
176  ico &= phase().thermo().incompressible();
177  }
178 
179  return ico;
180 }
181 
182 
184 {
185  bool iso = true;
186 
187  forAllConstIter(PtrDictionary<phaseModel>, phases_, phase)
188  {
189  iso &= phase().thermo().incompressible();
190  }
191 
192  return iso;
193 }
194 
195 
197 (
198  const volScalarField& p,
199  const volScalarField& T
200 ) const
201 {
202  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
203 
204  tmp<volScalarField> the(phasei()*phasei().thermo().he(p, T));
205 
206  for (++phasei; phasei != phases_.end(); ++phasei)
207  {
208  the.ref() += phasei()*phasei().thermo().he(p, T);
209  }
210 
211  return the;
212 }
213 
214 
216 (
217  const scalarField& p,
218  const scalarField& T,
219  const labelList& cells
220 ) const
221 {
222  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
223 
224  tmp<scalarField> the
225  (
226  scalarField(phasei(), cells)*phasei().thermo().he(p, T, cells)
227  );
228 
229  for (++phasei; phasei != phases_.end(); ++phasei)
230  {
231  the.ref() +=
232  scalarField(phasei(), cells)*phasei().thermo().he(p, T, cells);
233  }
234 
235  return the;
236 }
237 
238 
240 (
241  const scalarField& p,
242  const scalarField& T,
243  const label patchi
244 ) const
245 {
246  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
247 
248  tmp<scalarField> the
249  (
250  phasei().boundaryField()[patchi]*phasei().thermo().he(p, T, patchi)
251  );
252 
253  for (++phasei; phasei != phases_.end(); ++phasei)
254  {
255  the.ref() +=
256  phasei().boundaryField()[patchi]*phasei().thermo().he(p, T, patchi);
257  }
258 
259  return the;
260 }
261 
262 
264 {
265  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
266 
267  tmp<volScalarField> thc(phasei()*phasei().thermo().hc());
268 
269  for (++phasei; phasei != phases_.end(); ++phasei)
270  {
271  thc.ref() += phasei()*phasei().thermo().hc();
272  }
273 
274  return thc;
275 }
276 
277 
279 (
280  const scalarField& h,
281  const scalarField& p,
282  const scalarField& T0,
283  const labelList& cells
284 ) const
285 {
287  return T0;
288 }
289 
290 
292 (
293  const scalarField& h,
294  const scalarField& p,
295  const scalarField& T0,
296  const label patchi
297 ) const
298 {
300  return T0;
301 }
302 
303 
305 {
306  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
307 
308  tmp<volScalarField> trho(phasei()*phasei().thermo().rho());
309 
310  for (++phasei; phasei != phases_.end(); ++phasei)
311  {
312  trho.ref() += phasei()*phasei().thermo().rho();
313  }
314 
315  return trho;
316 }
317 
318 
320 (
321  const label patchi
322 ) const
323 {
324  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
325 
326  tmp<scalarField> trho
327  (
328  phasei().boundaryField()[patchi]*phasei().thermo().rho(patchi)
329  );
330 
331  for (++phasei; phasei != phases_.end(); ++phasei)
332  {
333  trho.ref() +=
334  phasei().boundaryField()[patchi]*phasei().thermo().rho(patchi);
335  }
336 
337  return trho;
338 }
339 
340 
342 {
343  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
344 
345  tmp<volScalarField> tCp(phasei()*phasei().thermo().Cp());
346 
347  for (++phasei; phasei != phases_.end(); ++phasei)
348  {
349  tCp.ref() += phasei()*phasei().thermo().Cp();
350  }
351 
352  return tCp;
353 }
354 
355 
357 (
358  const scalarField& p,
359  const scalarField& T,
360  const label patchi
361 ) const
362 {
363  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
364 
365  tmp<scalarField> tCp
366  (
367  phasei().boundaryField()[patchi]*phasei().thermo().Cp(p, T, patchi)
368  );
369 
370  for (++phasei; phasei != phases_.end(); ++phasei)
371  {
372  tCp.ref() +=
373  phasei().boundaryField()[patchi]*phasei().thermo().Cp(p, T, patchi);
374  }
375 
376  return tCp;
377 }
378 
379 
381 {
382  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
383 
384  tmp<volScalarField> tCv(phasei()*phasei().thermo().Cv());
385 
386  for (++phasei; phasei != phases_.end(); ++phasei)
387  {
388  tCv.ref() += phasei()*phasei().thermo().Cv();
389  }
390 
391  return tCv;
392 }
393 
394 
396 (
397  const scalarField& p,
398  const scalarField& T,
399  const label patchi
400 ) const
401 {
402  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
403 
404  tmp<scalarField> tCv
405  (
406  phasei().boundaryField()[patchi]*phasei().thermo().Cv(p, T, patchi)
407  );
408 
409  for (++phasei; phasei != phases_.end(); ++phasei)
410  {
411  tCv.ref() +=
412  phasei().boundaryField()[patchi]*phasei().thermo().Cv(p, T, patchi);
413  }
414 
415  return tCv;
416 }
417 
418 
420 {
421  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
422 
423  tmp<volScalarField> tgamma(phasei()*phasei().thermo().gamma());
424 
425  for (++phasei; phasei != phases_.end(); ++phasei)
426  {
427  tgamma.ref() += phasei()*phasei().thermo().gamma();
428  }
429 
430  return tgamma;
431 }
432 
433 
435 (
436  const scalarField& p,
437  const scalarField& T,
438  const label patchi
439 ) const
440 {
441  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
442 
443  tmp<scalarField> tgamma
444  (
445  phasei().boundaryField()[patchi]*phasei().thermo().gamma(p, T, patchi)
446  );
447 
448  for (++phasei; phasei != phases_.end(); ++phasei)
449  {
450  tgamma.ref() +=
451  phasei().boundaryField()[patchi]
452  *phasei().thermo().gamma(p, T, patchi);
453  }
454 
455  return tgamma;
456 }
457 
458 
460 {
461  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
462 
463  tmp<volScalarField> tCpv(phasei()*phasei().thermo().Cpv());
464 
465  for (++phasei; phasei != phases_.end(); ++phasei)
466  {
467  tCpv.ref() += phasei()*phasei().thermo().Cpv();
468  }
469 
470  return tCpv;
471 }
472 
473 
475 (
476  const scalarField& p,
477  const scalarField& T,
478  const label patchi
479 ) const
480 {
481  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
482 
483  tmp<scalarField> tCpv
484  (
485  phasei().boundaryField()[patchi]*phasei().thermo().Cpv(p, T, patchi)
486  );
487 
488  for (++phasei; phasei != phases_.end(); ++phasei)
489  {
490  tCpv.ref() +=
491  phasei().boundaryField()[patchi]
492  *phasei().thermo().Cpv(p, T, patchi);
493  }
494 
495  return tCpv;
496 }
497 
498 
500 {
501  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
502 
503  tmp<volScalarField> tCpByCpv(phasei()*phasei().thermo().CpByCpv());
504 
505  for (++phasei; phasei != phases_.end(); ++phasei)
506  {
507  tCpByCpv.ref() += phasei()*phasei().thermo().CpByCpv();
508  }
509 
510  return tCpByCpv;
511 }
512 
513 
515 (
516  const scalarField& p,
517  const scalarField& T,
518  const label patchi
519 ) const
520 {
521  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
522 
523  tmp<scalarField> tCpByCpv
524  (
525  phasei().boundaryField()[patchi]*phasei().thermo().CpByCpv(p, T, patchi)
526  );
527 
528  for (++phasei; phasei != phases_.end(); ++phasei)
529  {
530  tCpByCpv.ref() +=
531  phasei().boundaryField()[patchi]
532  *phasei().thermo().CpByCpv(p, T, patchi);
533  }
534 
535  return tCpByCpv;
536 }
537 
538 
540 {
541  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
542 
543  tmp<volScalarField> tW(phasei()*phasei().thermo().W());
544 
545  for (++phasei; phasei != phases_.end(); ++phasei)
546  {
547  tW.ref() += phasei()*phasei().thermo().W();
548  }
549 
550  return tW;
551 }
552 
553 
555 {
556  return mu()/rho();
557 }
558 
559 
561 (
562  const label patchi
563 ) const
564 {
565  return mu(patchi)/rho(patchi);
566 }
567 
568 
570 {
571  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
572 
573  tmp<volScalarField> tkappa(phasei()*phasei().thermo().kappa());
574 
575  for (++phasei; phasei != phases_.end(); ++phasei)
576  {
577  tkappa.ref() += phasei()*phasei().thermo().kappa();
578  }
579 
580  return tkappa;
581 }
582 
583 
585 (
586  const label patchi
587 ) const
588 {
589  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
590 
591  tmp<scalarField> tkappa
592  (
593  phasei().boundaryField()[patchi]*phasei().thermo().kappa(patchi)
594  );
595 
596  for (++phasei; phasei != phases_.end(); ++phasei)
597  {
598  tkappa.ref() +=
599  phasei().boundaryField()[patchi]*phasei().thermo().kappa(patchi);
600  }
601 
602  return tkappa;
603 }
604 
605 
607 {
608  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
609 
610  tmp<volScalarField> talphaEff(phasei()*phasei().thermo().alphahe());
611 
612  for (++phasei; phasei != phases_.end(); ++phasei)
613  {
614  talphaEff.ref() += phasei()*phasei().thermo().alphahe();
615  }
616 
617  return talphaEff;
618 }
619 
620 
622 (
623  const label patchi
624 ) const
625 {
626  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
627 
628  tmp<scalarField> talphaEff
629  (
630  phasei().boundaryField()[patchi]
631  *phasei().thermo().alphahe(patchi)
632  );
633 
634  for (++phasei; phasei != phases_.end(); ++phasei)
635  {
636  talphaEff.ref() +=
637  phasei().boundaryField()[patchi]
638  *phasei().thermo().alphahe(patchi);
639  }
640 
641  return talphaEff;
642 }
643 
644 
646 (
647  const volScalarField& alphat
648 ) const
649 {
650  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
651 
652  tmp<volScalarField> tkappaEff(phasei()*phasei().thermo().kappaEff(alphat));
653 
654  for (++phasei; phasei != phases_.end(); ++phasei)
655  {
656  tkappaEff.ref() += phasei()*phasei().thermo().kappaEff(alphat);
657  }
658 
659  return tkappaEff;
660 }
661 
662 
664 (
665  const scalarField& alphat,
666  const label patchi
667 ) const
668 {
669  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
670 
671  tmp<scalarField> tkappaEff
672  (
673  phasei().boundaryField()[patchi]
674  *phasei().thermo().kappaEff(alphat, patchi)
675  );
676 
677  for (++phasei; phasei != phases_.end(); ++phasei)
678  {
679  tkappaEff.ref() +=
680  phasei().boundaryField()[patchi]
681  *phasei().thermo().kappaEff(alphat, patchi);
682  }
683 
684  return tkappaEff;
685 }
686 
687 
689 (
690  const volScalarField& alphat
691 ) const
692 {
693  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
694 
695  tmp<volScalarField> talphaEff(phasei()*phasei().thermo().alphaEff(alphat));
696 
697  for (++phasei; phasei != phases_.end(); ++phasei)
698  {
699  talphaEff.ref() += phasei()*phasei().thermo().alphaEff(alphat);
700  }
701 
702  return talphaEff;
703 }
704 
705 
707 (
708  const scalarField& alphat,
709  const label patchi
710 ) const
711 {
712  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
713 
714  tmp<scalarField> talphaEff
715  (
716  phasei().boundaryField()[patchi]
717  *phasei().thermo().alphaEff(alphat, patchi)
718  );
719 
720  for (++phasei; phasei != phases_.end(); ++phasei)
721  {
722  talphaEff.ref() +=
723  phasei().boundaryField()[patchi]
724  *phasei().thermo().alphaEff(alphat, patchi);
725  }
726 
727  return talphaEff;
728 }
729 
730 
732 {
733  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
734 
735  tmp<volScalarField> trCv(phasei()/phasei().thermo().Cv());
736 
737  for (++phasei; phasei != phases_.end(); ++phasei)
738  {
739  trCv.ref() += phasei()/phasei().thermo().Cv();
740  }
741 
742  return trCv;
743 }
744 
745 
748 {
749  tmp<surfaceScalarField> tstf
750  (
752  (
753  IOobject
754  (
755  "surfaceTensionForce",
756  mesh_.time().timeName(),
757  mesh_
758  ),
759  mesh_,
761  (
762  "surfaceTensionForce",
763  dimensionSet(1, -2, -2, 0, 0),
764  0.0
765  )
766  )
767  );
768 
769  surfaceScalarField& stf = tstf.ref();
770 
771  forAllConstIter(PtrDictionary<phaseModel>, phases_, phase1)
772  {
773  const phaseModel& alpha1 = phase1();
774 
776  ++phase2;
777 
778  for (; phase2 != phases_.end(); ++phase2)
779  {
780  const phaseModel& alpha2 = phase2();
781 
782  sigmaTable::const_iterator sigma =
783  sigmas_.find(interfacePair(alpha1, alpha2));
784 
785  if (sigma == sigmas_.end())
786  {
788  << "Cannot find interface " << interfacePair(alpha1, alpha2)
789  << " in list of sigma values"
790  << exit(FatalError);
791  }
792 
793  stf += dimensionedScalar("sigma", dimSigma_, sigma())
794  *fvc::interpolate(K(alpha1, alpha2))*
795  (
796  fvc::interpolate(alpha2)*fvc::snGrad(alpha1)
797  - fvc::interpolate(alpha1)*fvc::snGrad(alpha2)
798  );
799  }
800  }
801 
802  return tstf;
803 }
804 
805 
807 {
808  const Time& runTime = mesh_.time();
809 
810  const dictionary& alphaControls = mesh_.solverDict("alpha");
811  label nAlphaSubCycles(readLabel(alphaControls.lookup("nAlphaSubCycles")));
812  scalar cAlpha(readScalar(alphaControls.lookup("cAlpha")));
813 
814  volScalarField& alpha = phases_.first();
815 
816  if (nAlphaSubCycles > 1)
817  {
818  surfaceScalarField rhoPhiSum(0.0*rhoPhi_);
819  dimensionedScalar totalDeltaT = runTime.deltaT();
820 
821  for
822  (
823  subCycle<volScalarField> alphaSubCycle(alpha, nAlphaSubCycles);
824  !(++alphaSubCycle).end();
825  )
826  {
827  solveAlphas(cAlpha);
828  rhoPhiSum += (runTime.deltaT()/totalDeltaT)*rhoPhi_;
829  }
830 
831  rhoPhi_ = rhoPhiSum;
832  }
833  else
834  {
835  solveAlphas(cAlpha);
836  }
837 }
838 
839 
840 Foam::tmp<Foam::surfaceVectorField> Foam::multiphaseMixtureThermo::nHatfv
841 (
842  const volScalarField& alpha1,
843  const volScalarField& alpha2
844 ) const
845 {
846  /*
847  // Cell gradient of alpha
848  volVectorField gradAlpha =
849  alpha2*fvc::grad(alpha1) - alpha1*fvc::grad(alpha2);
850 
851  // Interpolated face-gradient of alpha
852  surfaceVectorField gradAlphaf = fvc::interpolate(gradAlpha);
853  */
854 
855  surfaceVectorField gradAlphaf
856  (
858  - fvc::interpolate(alpha1)*fvc::interpolate(fvc::grad(alpha2))
859  );
860 
861  // Face unit interface normal
862  return gradAlphaf/(mag(gradAlphaf) + deltaN_);
863 }
864 
865 
866 Foam::tmp<Foam::surfaceScalarField> Foam::multiphaseMixtureThermo::nHatf
867 (
868  const volScalarField& alpha1,
869  const volScalarField& alpha2
870 ) const
871 {
872  // Face unit interface normal flux
873  return nHatfv(alpha1, alpha2) & mesh_.Sf();
874 }
875 
876 
877 // Correction for the boundary condition on the unit normal nHat on
878 // walls to produce the correct contact angle.
879 
880 // The dynamic contact angle is calculated from the component of the
881 // velocity on the direction of the interface, parallel to the wall.
882 
883 void Foam::multiphaseMixtureThermo::correctContactAngle
884 (
885  const phaseModel& alpha1,
886  const phaseModel& alpha2,
887  surfaceVectorField::Boundary& nHatb
888 ) const
889 {
890  const volScalarField::Boundary& gbf
891  = alpha1.boundaryField();
892 
893  const fvBoundaryMesh& boundary = mesh_.boundary();
894 
895  forAll(boundary, patchi)
896  {
897  if (isA<alphaContactAngleFvPatchScalarField>(gbf[patchi]))
898  {
899  const alphaContactAngleFvPatchScalarField& acap =
900  refCast<const alphaContactAngleFvPatchScalarField>(gbf[patchi]);
901 
902  vectorField& nHatPatch = nHatb[patchi];
903 
904  vectorField AfHatPatch
905  (
906  mesh_.Sf().boundaryField()[patchi]
907  /mesh_.magSf().boundaryField()[patchi]
908  );
909 
910  alphaContactAngleFvPatchScalarField::thetaPropsTable::
911  const_iterator tp =
912  acap.thetaProps().find(interfacePair(alpha1, alpha2));
913 
914  if (tp == acap.thetaProps().end())
915  {
917  << "Cannot find interface " << interfacePair(alpha1, alpha2)
918  << "\n in table of theta properties for patch "
919  << acap.patch().name()
920  << exit(FatalError);
921  }
922 
923  bool matched = (tp.key().first() == alpha1.name());
924 
925  scalar theta0 = convertToRad*tp().theta0(matched);
926  scalarField theta(boundary[patchi].size(), theta0);
927 
928  scalar uTheta = tp().uTheta();
929 
930  // Calculate the dynamic contact angle if required
931  if (uTheta > small)
932  {
933  scalar thetaA = convertToRad*tp().thetaA(matched);
934  scalar thetaR = convertToRad*tp().thetaR(matched);
935 
936  // Calculated the component of the velocity parallel to the wall
937  vectorField Uwall
938  (
939  U_.boundaryField()[patchi].patchInternalField()
940  - U_.boundaryField()[patchi]
941  );
942  Uwall -= (AfHatPatch & Uwall)*AfHatPatch;
943 
944  // Find the direction of the interface parallel to the wall
945  vectorField nWall
946  (
947  nHatPatch - (AfHatPatch & nHatPatch)*AfHatPatch
948  );
949 
950  // Normalise nWall
951  nWall /= (mag(nWall) + small);
952 
953  // Calculate Uwall resolved normal to the interface parallel to
954  // the interface
955  scalarField uwall(nWall & Uwall);
956 
957  theta += (thetaA - thetaR)*tanh(uwall/uTheta);
958  }
959 
960 
961  // Reset nHatPatch to correspond to the contact angle
962 
963  scalarField a12(nHatPatch & AfHatPatch);
964 
965  scalarField b1(cos(theta));
966 
967  scalarField b2(nHatPatch.size());
968 
969  forAll(b2, facei)
970  {
971  b2[facei] = cos(acos(a12[facei]) - theta[facei]);
972  }
973 
974  scalarField det(1.0 - a12*a12);
975 
976  scalarField a((b1 - a12*b2)/det);
977  scalarField b((b2 - a12*b1)/det);
978 
979  nHatPatch = a*AfHatPatch + b*nHatPatch;
980 
981  nHatPatch /= (mag(nHatPatch) + deltaN_.value());
982  }
983  }
984 }
985 
986 
987 Foam::tmp<Foam::volScalarField> Foam::multiphaseMixtureThermo::K
988 (
989  const phaseModel& alpha1,
990  const phaseModel& alpha2
991 ) const
992 {
993  tmp<surfaceVectorField> tnHatfv = nHatfv(alpha1, alpha2);
994 
995  correctContactAngle(alpha1, alpha2, tnHatfv.ref().boundaryFieldRef());
996 
997  // Simple expression for curvature
998  return -fvc::div(tnHatfv & mesh_.Sf());
999 }
1000 
1001 
1004 {
1005  tmp<volScalarField> tnearInt
1006  (
1007  new volScalarField
1008  (
1009  IOobject
1010  (
1011  "nearInterface",
1012  mesh_.time().timeName(),
1013  mesh_
1014  ),
1015  mesh_,
1016  dimensionedScalar("nearInterface", dimless, 0.0)
1017  )
1018  );
1019 
1020  forAllConstIter(PtrDictionary<phaseModel>, phases_, phase)
1021  {
1022  tnearInt.ref() =
1023  max(tnearInt(), pos0(phase() - 0.01)*pos0(0.99 - phase()));
1024  }
1025 
1026  return tnearInt;
1027 }
1028 
1029 
1030 void Foam::multiphaseMixtureThermo::solveAlphas
1031 (
1032  const scalar cAlpha
1033 )
1034 {
1035  static label nSolves=-1;
1036  nSolves++;
1037 
1038  word alphaScheme("div(phi,alpha)");
1039  word alpharScheme("div(phirb,alpha)");
1040 
1041  surfaceScalarField phic(mag(phi_/mesh_.magSf()));
1042  phic = min(cAlpha*phic, max(phic));
1043 
1044  PtrList<surfaceScalarField> alphaPhiCorrs(phases_.size());
1045  int phasei = 0;
1046 
1047  forAllIter(PtrDictionary<phaseModel>, phases_, phase)
1048  {
1049  phaseModel& alpha = phase();
1050 
1051  alphaPhiCorrs.set
1052  (
1053  phasei,
1054  new surfaceScalarField
1055  (
1056  phi_.name() + alpha.name(),
1057  fvc::flux
1058  (
1059  phi_,
1060  alpha,
1061  alphaScheme
1062  )
1063  )
1064  );
1065 
1066  surfaceScalarField& alphaPhiCorr = alphaPhiCorrs[phasei];
1067 
1068  forAllIter(PtrDictionary<phaseModel>, phases_, phase2)
1069  {
1070  phaseModel& alpha2 = phase2();
1071 
1072  if (&alpha2 == &alpha) continue;
1073 
1074  surfaceScalarField phir(phic*nHatf(alpha, alpha2));
1075 
1076  alphaPhiCorr += fvc::flux
1077  (
1078  -fvc::flux(-phir, alpha2, alpharScheme),
1079  alpha,
1080  alpharScheme
1081  );
1082  }
1083 
1084  MULES::limit
1085  (
1086  1.0/mesh_.time().deltaT().value(),
1087  geometricOneField(),
1088  alpha,
1089  phi_,
1090  alphaPhiCorr,
1091  zeroField(),
1092  zeroField(),
1093  oneField(),
1094  zeroField(),
1095  true
1096  );
1097 
1098  phasei++;
1099  }
1100 
1101  MULES::limitSum(alphaPhiCorrs);
1102 
1103  rhoPhi_ = dimensionedScalar("0", dimensionSet(1, 0, -1, 0, 0), 0);
1104 
1105  volScalarField sumAlpha
1106  (
1107  IOobject
1108  (
1109  "sumAlpha",
1110  mesh_.time().timeName(),
1111  mesh_
1112  ),
1113  mesh_,
1114  dimensionedScalar("sumAlpha", dimless, 0)
1115  );
1116 
1117 
1119 
1120 
1121  phasei = 0;
1122 
1123  forAllIter(PtrDictionary<phaseModel>, phases_, phase)
1124  {
1125  phaseModel& alpha = phase();
1126 
1127  surfaceScalarField& alphaPhi = alphaPhiCorrs[phasei];
1128  alphaPhi += upwind<scalar>(mesh_, phi_).flux(alpha);
1129 
1131  (
1132  IOobject
1133  (
1134  "Sp",
1135  mesh_.time().timeName(),
1136  mesh_
1137  ),
1138  mesh_,
1139  dimensionedScalar("Sp", alpha.dgdt().dimensions(), 0.0)
1140  );
1141 
1143  (
1144  IOobject
1145  (
1146  "Su",
1147  mesh_.time().timeName(),
1148  mesh_
1149  ),
1150  // Divergence term is handled explicitly to be
1151  // consistent with the explicit transport solution
1152  divU*min(alpha, scalar(1))
1153  );
1154 
1155  {
1156  const scalarField& dgdt = alpha.dgdt();
1157 
1158  forAll(dgdt, celli)
1159  {
1160  if (dgdt[celli] < 0.0 && alpha[celli] > 0.0)
1161  {
1162  Sp[celli] += dgdt[celli]*alpha[celli];
1163  Su[celli] -= dgdt[celli]*alpha[celli];
1164  }
1165  else if (dgdt[celli] > 0.0 && alpha[celli] < 1.0)
1166  {
1167  Sp[celli] -= dgdt[celli]*(1.0 - alpha[celli]);
1168  }
1169  }
1170  }
1171 
1172  forAllConstIter(PtrDictionary<phaseModel>, phases_, phase2)
1173  {
1174  const phaseModel& alpha2 = phase2();
1175 
1176  if (&alpha2 == &alpha) continue;
1177 
1178  const scalarField& dgdt2 = alpha2.dgdt();
1179 
1180  forAll(dgdt2, celli)
1181  {
1182  if (dgdt2[celli] > 0.0 && alpha2[celli] < 1.0)
1183  {
1184  Sp[celli] -= dgdt2[celli]*(1.0 - alpha2[celli]);
1185  Su[celli] += dgdt2[celli]*alpha[celli];
1186  }
1187  else if (dgdt2[celli] < 0.0 && alpha2[celli] > 0.0)
1188  {
1189  Sp[celli] += dgdt2[celli]*alpha2[celli];
1190  }
1191  }
1192  }
1193 
1195  (
1196  geometricOneField(),
1197  alpha,
1198  alphaPhi,
1199  Sp,
1200  Su
1201  );
1202 
1203  rhoPhi_ += fvc::interpolate(alpha.thermo().rho())*alphaPhi;
1204 
1205  Info<< alpha.name() << " volume fraction, min, max = "
1206  << alpha.weightedAverage(mesh_.V()).value()
1207  << ' ' << min(alpha).value()
1208  << ' ' << max(alpha).value()
1209  << endl;
1210 
1211  sumAlpha += alpha;
1212 
1213  phasei++;
1214  }
1215 
1216  Info<< "Phase-sum volume fraction, min, max = "
1217  << sumAlpha.weightedAverage(mesh_.V()).value()
1218  << ' ' << min(sumAlpha).value()
1219  << ' ' << max(sumAlpha).value()
1220  << endl;
1221 
1222  calcAlphas();
1223 }
1224 
1225 
1226 // ************************************************************************* //
volScalarField & he
Definition: YEEqn.H:51
void limit(const RdeltaTType &rDeltaT, const RhoType &rho, const volScalarField &psi, const surfaceScalarField &phi, surfaceScalarField &phiPsi, const SpType &Sp, const SuType &Su, const PsiMaxType &psiMax, const PsiMinType &psiMin, const bool returnCorr)
dimensionedScalar tanh(const dimensionedScalar &ds)
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcGrad.C:52
dimensionedScalar acos(const dimensionedScalar &ds)
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
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
zeroField Su
Definition: alphaSuSp.H:1
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
label phasei
Definition: pEqn.H:27
error FatalError
virtual tmp< volScalarField > gamma() const
Gamma = Cp/Cv [].
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
Info<< "Creating turbulence model\"<< endl;tmp< volScalarField > talphaEff
Definition: setAlphaEff.H:2
tmp< GeometricField< Type, fvPatchField, volMesh > > div(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcDiv.C:47
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:453
virtual tmp< volScalarField > hc() const
Chemical enthalpy [J/kg].
word alpharScheme("div(phirb,alpha)")
GeometricField< vector, fvsPatchField, surfaceMesh > surfaceVectorField
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
tmp< volScalarField > trho
const dimensionedScalar sigma
Stefan-Boltzmann constant: default SI units: [W/m2/K4].
Calculate the snGrad of the given volField.
dimensionedScalar det(const dimensionedSphericalTensor &dt)
rhoReactionThermo & thermo
Definition: createFields.H:28
friend class iterator
Definition: LPtrList.H:84
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:55
T & first()
Return the first element of the list.
Definition: UListI.H:114
DimensionedField< scalar, volMesh > Internal
Type of the internal field from which this GeometricField is derived.
CGAL::Exact_predicates_exact_constructions_kernel K
const dimensionedScalar kappa
Coulomb constant: default SI units: [N.m2/C2].
virtual tmp< volScalarField > Cp() const
Heat capacity at constant pressure [J/kg/K].
virtual tmp< volScalarField > CpByCpv() const
Heat capacity ratio [].
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:52
void correctRho(const volScalarField &dp)
Update densities for given pressure change.
void solve()
Solve for the mixture phase-fractions.
stressControl lookup("compactNormalStress") >> compactNormalStress
dynamicFvMesh & mesh
dimensionedScalar cos(const dimensionedScalar &ds)
void limitSum(UPtrList< scalarField > &phiPsiCorrs)
Definition: MULES.C:30
virtual tmp< volScalarField > alphahe() const
Thermal diffusivity for energy of mixture [kg/m/s].
virtual tmp< volScalarField > rho() const
Density [kg/m^3].
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Calculate the gradient of the given field.
surfaceScalarField phir(fvc::flux(UdmModel.Udm()))
tmp< volScalarField > rCv() const
Return the phase-averaged reciprocal Cv.
A class for handling words, derived from string.
Definition: word.H:59
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Calculate the face-flux of the given field.
const Type & value() const
Return const reference to value.
word timeName
Definition: getTimeIndex.H:3
List< label > labelList
A List of labels.
Definition: labelList.H:56
dimensioned< Type > average(const DimensionedField< Type, GeoMesh > &df)
faceListList boundary(nPatches)
bool readScalar(const char *buf, doubleScalar &s)
Read whole of buf as a scalar. Return true if successful.
Definition: doubleScalar.H:68
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
label readLabel(Istream &is)
Definition: label.H:64
phaseModel & phase1
Calculate the divergence of the given field.
dimensionedScalar pos0(const dimensionedScalar &ds)
Info<< "Predicted p max-min : "<< max(p).value()<< " "<< min(p).value()<< endl;rho==max(psi *p+alphal *rhol0+((alphav *psiv+alphal *psil) - psi) *pSat, rhoMin);# 1 "/home/ubuntu/OpenFOAM-6/applications/solvers/multiphase/cavitatingFoam/alphavPsi.H" 1{ alphav=max(min((rho - rholSat)/(rhovSat - rholSat), scalar(1)), scalar(0));alphal=1.0 - alphav;Info<< "max-min alphav: "<< max(alphav).value()<< " "<< min(alphav).value()<< endl;psiModel-> correct()
Definition: pEqn.H:72
defineTypeNameAndDebug(combustionModel, 0)
virtual tmp< volScalarField > nu() const
Kinematic viscosity of mixture [m^2/s].
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
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.
Calculate the mesh motion flux and convert fluxes from absolute to relative and back.
Internal & ref()
Return a reference to the dimensioned internal field.
const dimensionedScalar mu
Atomic mass unit.
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
virtual tmp< volScalarField > kappaEff(const volScalarField &alphat) const
Effective thermal diffusivity of mixture [J/m/s/K].
multiphaseMixtureThermo(const volVectorField &U, const surfaceScalarField &phi)
Construct from components.
label patchi
tmp< surfaceScalarField > absolute(const tmp< surfaceScalarField > &tphi, const volVectorField &U)
Return the given relative flux in absolute form.
Definition: fvcMeshPhi.C:188
const dimensionSet dimless(0, 0, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:47
volScalarField & h
Planck constant.
surfaceScalarField phic(mixture.cAlpha() *mag(phi/mesh.magSf()))
virtual tmp< volScalarField > W() const
Molecular weight [kg/kmol].
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
const scalarList W(::W(thermo))
const dimensionSet dimTime(0, 0, 1, 0, 0, 0, 0)
Definition: dimensionSets.H:51
tmp< volScalarField > nearInterface() const
Indicator of the proximity of the interface.
messageStream Info
dimensioned< scalar > mag(const dimensioned< Type > &)
Field< vector > vectorField
Specialisation of Field<T> for vector.
MULES: Multidimensional universal limiter for explicit solution.
virtual tmp< scalarField > THE(const scalarField &h, const scalarField &p, const scalarField &T0, const labelList &cells) const
Temperature from enthalpy/internal energy for cell-set.
const doubleScalar e
Elementary charge.
Definition: doubleScalar.H:98
virtual tmp< volScalarField > Cv() const
Heat capacity at constant volume [J/kg/K].
const dimensionSet dimMass(1, 0, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:49
zeroField divU
Definition: alphaSuSp.H:3
volScalarField alphaEff("alphaEff", turbulence->nu()/Pr+alphat)
phaseModel & phase2
A class for managing temporary objects.
Definition: PtrList.H:53
tmp< surfaceScalarField > surfaceTensionForce() const
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
virtual tmp< volScalarField > alphaEff(const volScalarField &alphat) const
Effective thermal diffusivity of mixture [J/m/s/K].
virtual tmp< volScalarField > Cpv() const
Heat capacity at constant pressure/volume [J/kg/K].
surfaceScalarField alphaPhi(phi.name()+alpha1.name(), fvc::flux(phi, alpha1, alphaScheme))
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
#define NotImplemented
Issue a FatalErrorIn for a function not currently implemented.
Definition: error.H:366
void explicitSolve(const RdeltaTType &rDeltaT, const RhoType &rho, volScalarField &psi, const surfaceScalarField &phiPsi, const SpType &Sp, const SuType &Su)
virtual tmp< volScalarField > kappa() const
Thermal diffusivity for temperature of mixture [J/m/s/K].
virtual bool isochoric() const
Return true if the equation of state is isochoric.
virtual word thermoName() const
Return the name of the thermo physics.
virtual volScalarField & he()
Enthalpy/Internal energy [J/kg].
tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > snGrad(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvcSnGrad.C:45
friend class const_iterator
Definition: LPtrList.H:87
Namespace for OpenFOAM.
virtual bool incompressible() const
Return true if the equation of state is incompressible.
label nAlphaSubCycles(readLabel(alphaControls.lookup("nAlphaSubCycles")))
virtual void correct()
Update properties.
zeroField Sp
Definition: alphaSuSp.H:2