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_,
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_,
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  const label patchi
557 ) const
558 {
559  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
560 
561  tmp<scalarField> tW
562  (
563  phasei().boundaryField()[patchi]*phasei().thermo().W(patchi)
564  );
565 
566  for (++phasei; phasei != phases_.end(); ++phasei)
567  {
568  tW.ref() +=
569  phasei().boundaryField()[patchi]*phasei().thermo().W(patchi);
570  }
571 
572  return tW;
573 }
574 
575 
577 {
578  return mu()/rho();
579 }
580 
581 
583 (
584  const label patchi
585 ) const
586 {
587  return mu(patchi)/rho(patchi);
588 }
589 
590 
592 {
593  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
594 
595  tmp<volScalarField> tkappa(phasei()*phasei().thermo().kappa());
596 
597  for (++phasei; phasei != phases_.end(); ++phasei)
598  {
599  tkappa.ref() += phasei()*phasei().thermo().kappa();
600  }
601 
602  return tkappa;
603 }
604 
605 
607 (
608  const label patchi
609 ) const
610 {
611  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
612 
613  tmp<scalarField> tkappa
614  (
615  phasei().boundaryField()[patchi]*phasei().thermo().kappa(patchi)
616  );
617 
618  for (++phasei; phasei != phases_.end(); ++phasei)
619  {
620  tkappa.ref() +=
621  phasei().boundaryField()[patchi]*phasei().thermo().kappa(patchi);
622  }
623 
624  return tkappa;
625 }
626 
627 
629 {
630  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
631 
632  tmp<volScalarField> talphaEff(phasei()*phasei().thermo().alphahe());
633 
634  for (++phasei; phasei != phases_.end(); ++phasei)
635  {
636  talphaEff.ref() += phasei()*phasei().thermo().alphahe();
637  }
638 
639  return talphaEff;
640 }
641 
642 
644 (
645  const label patchi
646 ) const
647 {
648  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
649 
650  tmp<scalarField> talphaEff
651  (
652  phasei().boundaryField()[patchi]
653  *phasei().thermo().alphahe(patchi)
654  );
655 
656  for (++phasei; phasei != phases_.end(); ++phasei)
657  {
658  talphaEff.ref() +=
659  phasei().boundaryField()[patchi]
660  *phasei().thermo().alphahe(patchi);
661  }
662 
663  return talphaEff;
664 }
665 
666 
668 (
669  const volScalarField& alphat
670 ) const
671 {
672  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
673 
674  tmp<volScalarField> tkappaEff(phasei()*phasei().thermo().kappaEff(alphat));
675 
676  for (++phasei; phasei != phases_.end(); ++phasei)
677  {
678  tkappaEff.ref() += phasei()*phasei().thermo().kappaEff(alphat);
679  }
680 
681  return tkappaEff;
682 }
683 
684 
686 (
687  const scalarField& alphat,
688  const label patchi
689 ) const
690 {
691  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
692 
693  tmp<scalarField> tkappaEff
694  (
695  phasei().boundaryField()[patchi]
696  *phasei().thermo().kappaEff(alphat, patchi)
697  );
698 
699  for (++phasei; phasei != phases_.end(); ++phasei)
700  {
701  tkappaEff.ref() +=
702  phasei().boundaryField()[patchi]
703  *phasei().thermo().kappaEff(alphat, patchi);
704  }
705 
706  return tkappaEff;
707 }
708 
709 
711 (
712  const volScalarField& alphat
713 ) const
714 {
715  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
716 
717  tmp<volScalarField> talphaEff(phasei()*phasei().thermo().alphaEff(alphat));
718 
719  for (++phasei; phasei != phases_.end(); ++phasei)
720  {
721  talphaEff.ref() += phasei()*phasei().thermo().alphaEff(alphat);
722  }
723 
724  return talphaEff;
725 }
726 
727 
729 (
730  const scalarField& alphat,
731  const label patchi
732 ) const
733 {
734  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
735 
736  tmp<scalarField> talphaEff
737  (
738  phasei().boundaryField()[patchi]
739  *phasei().thermo().alphaEff(alphat, patchi)
740  );
741 
742  for (++phasei; phasei != phases_.end(); ++phasei)
743  {
744  talphaEff.ref() +=
745  phasei().boundaryField()[patchi]
746  *phasei().thermo().alphaEff(alphat, patchi);
747  }
748 
749  return talphaEff;
750 }
751 
752 
754 {
755  PtrDictionary<phaseModel>::const_iterator phasei = phases_.begin();
756 
757  tmp<volScalarField> trCv(phasei()/phasei().thermo().Cv());
758 
759  for (++phasei; phasei != phases_.end(); ++phasei)
760  {
761  trCv.ref() += phasei()/phasei().thermo().Cv();
762  }
763 
764  return trCv;
765 }
766 
767 
770 {
771  tmp<surfaceScalarField> tstf
772  (
774  (
775  "surfaceTensionForce",
776  mesh_,
777  dimensionedScalar(dimensionSet(1, -2, -2, 0, 0), 0)
778  )
779  );
780 
781  surfaceScalarField& stf = tstf.ref();
782 
783  forAllConstIter(PtrDictionary<phaseModel>, phases_, phase1)
784  {
785  const phaseModel& alpha1 = phase1();
786 
788  ++phase2;
789 
790  for (; phase2 != phases_.end(); ++phase2)
791  {
792  const phaseModel& alpha2 = phase2();
793 
794  sigmaTable::const_iterator sigma =
795  sigmas_.find(interfacePair(alpha1, alpha2));
796 
797  if (sigma == sigmas_.end())
798  {
800  << "Cannot find interface " << interfacePair(alpha1, alpha2)
801  << " in list of sigma values"
802  << exit(FatalError);
803  }
804 
805  stf += dimensionedScalar(dimSigma_, sigma())
806  *fvc::interpolate(K(alpha1, alpha2))*
807  (
808  fvc::interpolate(alpha2)*fvc::snGrad(alpha1)
809  - fvc::interpolate(alpha1)*fvc::snGrad(alpha2)
810  );
811  }
812  }
813 
814  return tstf;
815 }
816 
817 
819 {
820  const Time& runTime = mesh_.time();
821 
822  const dictionary& alphaControls = mesh_.solverDict("alpha");
823  label nAlphaSubCycles(readLabel(alphaControls.lookup("nAlphaSubCycles")));
824  scalar cAlpha(readScalar(alphaControls.lookup("cAlpha")));
825 
826  volScalarField& alpha = phases_.first();
827 
828  if (nAlphaSubCycles > 1)
829  {
830  surfaceScalarField rhoPhiSum(0.0*rhoPhi_);
831  dimensionedScalar totalDeltaT = runTime.deltaT();
832 
833  for
834  (
835  subCycle<volScalarField> alphaSubCycle(alpha, nAlphaSubCycles);
836  !(++alphaSubCycle).end();
837  )
838  {
839  solveAlphas(cAlpha);
840  rhoPhiSum += (runTime.deltaT()/totalDeltaT)*rhoPhi_;
841  }
842 
843  rhoPhi_ = rhoPhiSum;
844  }
845  else
846  {
847  solveAlphas(cAlpha);
848  }
849 }
850 
851 
852 Foam::tmp<Foam::surfaceVectorField> Foam::multiphaseMixtureThermo::nHatfv
853 (
854  const volScalarField& alpha1,
855  const volScalarField& alpha2
856 ) const
857 {
858  /*
859  // Cell gradient of alpha
860  volVectorField gradAlpha =
861  alpha2*fvc::grad(alpha1) - alpha1*fvc::grad(alpha2);
862 
863  // Interpolated face-gradient of alpha
864  surfaceVectorField gradAlphaf = fvc::interpolate(gradAlpha);
865  */
866 
867  surfaceVectorField gradAlphaf
868  (
870  - fvc::interpolate(alpha1)*fvc::interpolate(fvc::grad(alpha2))
871  );
872 
873  // Face unit interface normal
874  return gradAlphaf/(mag(gradAlphaf) + deltaN_);
875 }
876 
877 
878 Foam::tmp<Foam::surfaceScalarField> Foam::multiphaseMixtureThermo::nHatf
879 (
880  const volScalarField& alpha1,
881  const volScalarField& alpha2
882 ) const
883 {
884  // Face unit interface normal flux
885  return nHatfv(alpha1, alpha2) & mesh_.Sf();
886 }
887 
888 
889 // Correction for the boundary condition on the unit normal nHat on
890 // walls to produce the correct contact angle.
891 
892 // The dynamic contact angle is calculated from the component of the
893 // velocity on the direction of the interface, parallel to the wall.
894 
895 void Foam::multiphaseMixtureThermo::correctContactAngle
896 (
897  const phaseModel& alpha1,
898  const phaseModel& alpha2,
899  surfaceVectorField::Boundary& nHatb
900 ) const
901 {
902  const volScalarField::Boundary& gbf
903  = alpha1.boundaryField();
904 
905  const fvBoundaryMesh& boundary = mesh_.boundary();
906 
907  forAll(boundary, patchi)
908  {
909  if (isA<alphaContactAngleFvPatchScalarField>(gbf[patchi]))
910  {
911  const alphaContactAngleFvPatchScalarField& acap =
912  refCast<const alphaContactAngleFvPatchScalarField>(gbf[patchi]);
913 
914  vectorField& nHatPatch = nHatb[patchi];
915 
916  vectorField AfHatPatch
917  (
918  mesh_.Sf().boundaryField()[patchi]
919  /mesh_.magSf().boundaryField()[patchi]
920  );
921 
922  alphaContactAngleFvPatchScalarField::thetaPropsTable::
923  const_iterator tp =
924  acap.thetaProps().find(interfacePair(alpha1, alpha2));
925 
926  if (tp == acap.thetaProps().end())
927  {
929  << "Cannot find interface " << interfacePair(alpha1, alpha2)
930  << "\n in table of theta properties for patch "
931  << acap.patch().name()
932  << exit(FatalError);
933  }
934 
935  bool matched = (tp.key().first() == alpha1.name());
936 
937  scalar theta0 = convertToRad*tp().theta0(matched);
938  scalarField theta(boundary[patchi].size(), theta0);
939 
940  scalar uTheta = tp().uTheta();
941 
942  // Calculate the dynamic contact angle if required
943  if (uTheta > small)
944  {
945  scalar thetaA = convertToRad*tp().thetaA(matched);
946  scalar thetaR = convertToRad*tp().thetaR(matched);
947 
948  // Calculated the component of the velocity parallel to the wall
949  vectorField Uwall
950  (
951  U_.boundaryField()[patchi].patchInternalField()
952  - U_.boundaryField()[patchi]
953  );
954  Uwall -= (AfHatPatch & Uwall)*AfHatPatch;
955 
956  // Find the direction of the interface parallel to the wall
957  vectorField nWall
958  (
959  nHatPatch - (AfHatPatch & nHatPatch)*AfHatPatch
960  );
961 
962  // Normalise nWall
963  nWall /= (mag(nWall) + small);
964 
965  // Calculate Uwall resolved normal to the interface parallel to
966  // the interface
967  scalarField uwall(nWall & Uwall);
968 
969  theta += (thetaA - thetaR)*tanh(uwall/uTheta);
970  }
971 
972 
973  // Reset nHatPatch to correspond to the contact angle
974 
975  scalarField a12(nHatPatch & AfHatPatch);
976 
977  scalarField b1(cos(theta));
978 
979  scalarField b2(nHatPatch.size());
980 
981  forAll(b2, facei)
982  {
983  b2[facei] = cos(acos(a12[facei]) - theta[facei]);
984  }
985 
986  scalarField det(1.0 - a12*a12);
987 
988  scalarField a((b1 - a12*b2)/det);
989  scalarField b((b2 - a12*b1)/det);
990 
991  nHatPatch = a*AfHatPatch + b*nHatPatch;
992 
993  nHatPatch /= (mag(nHatPatch) + deltaN_.value());
994  }
995  }
996 }
997 
998 
999 Foam::tmp<Foam::volScalarField> Foam::multiphaseMixtureThermo::K
1000 (
1001  const phaseModel& alpha1,
1002  const phaseModel& alpha2
1003 ) const
1004 {
1005  tmp<surfaceVectorField> tnHatfv = nHatfv(alpha1, alpha2);
1006 
1007  correctContactAngle(alpha1, alpha2, tnHatfv.ref().boundaryFieldRef());
1008 
1009  // Simple expression for curvature
1010  return -fvc::div(tnHatfv & mesh_.Sf());
1011 }
1012 
1013 
1016 {
1017  tmp<volScalarField> tnearInt
1018  (
1020  (
1021  "nearInterface",
1022  mesh_,
1024  )
1025  );
1026 
1027  forAllConstIter(PtrDictionary<phaseModel>, phases_, phase)
1028  {
1029  tnearInt.ref() =
1030  max(tnearInt(), pos0(phase() - 0.01)*pos0(0.99 - phase()));
1031  }
1032 
1033  return tnearInt;
1034 }
1035 
1036 
1037 void Foam::multiphaseMixtureThermo::solveAlphas
1038 (
1039  const scalar cAlpha
1040 )
1041 {
1042  static label nSolves=-1;
1043  nSolves++;
1044 
1045  word alphaScheme("div(phi,alpha)");
1046  word alpharScheme("div(phirb,alpha)");
1047 
1048  surfaceScalarField phic(mag(phi_/mesh_.magSf()));
1049  phic = min(cAlpha*phic, max(phic));
1050 
1051  PtrList<surfaceScalarField> alphaPhiCorrs(phases_.size());
1052  int phasei = 0;
1053 
1054  forAllIter(PtrDictionary<phaseModel>, phases_, phase)
1055  {
1056  phaseModel& alpha = phase();
1057 
1058  alphaPhiCorrs.set
1059  (
1060  phasei,
1061  new surfaceScalarField
1062  (
1063  phi_.name() + alpha.name(),
1064  fvc::flux
1065  (
1066  phi_,
1067  alpha,
1068  alphaScheme
1069  )
1070  )
1071  );
1072 
1073  surfaceScalarField& alphaPhiCorr = alphaPhiCorrs[phasei];
1074 
1075  forAllIter(PtrDictionary<phaseModel>, phases_, phase2)
1076  {
1077  phaseModel& alpha2 = phase2();
1078 
1079  if (&alpha2 == &alpha) continue;
1080 
1081  surfaceScalarField phir(phic*nHatf(alpha, alpha2));
1082 
1083  alphaPhiCorr += fvc::flux
1084  (
1085  -fvc::flux(-phir, alpha2, alpharScheme),
1086  alpha,
1087  alpharScheme
1088  );
1089  }
1090 
1091  MULES::limit
1092  (
1093  1.0/mesh_.time().deltaT().value(),
1094  geometricOneField(),
1095  alpha,
1096  phi_,
1097  alphaPhiCorr,
1098  zeroField(),
1099  zeroField(),
1100  oneField(),
1101  zeroField(),
1102  true
1103  );
1104 
1105  phasei++;
1106  }
1107 
1108  MULES::limitSum(alphaPhiCorrs);
1109 
1110  rhoPhi_ = dimensionedScalar(dimensionSet(1, 0, -1, 0, 0), 0);
1111 
1112  volScalarField sumAlpha
1113  (
1114  IOobject
1115  (
1116  "sumAlpha",
1117  mesh_.time().timeName(),
1118  mesh_
1119  ),
1120  mesh_,
1122  );
1123 
1124 
1126 
1127 
1128  phasei = 0;
1129 
1130  forAllIter(PtrDictionary<phaseModel>, phases_, phase)
1131  {
1132  phaseModel& alpha = phase();
1133 
1134  surfaceScalarField& alphaPhi = alphaPhiCorrs[phasei];
1135  alphaPhi += upwind<scalar>(mesh_, phi_).flux(alpha);
1136 
1138  (
1139  IOobject
1140  (
1141  "Sp",
1142  mesh_.time().timeName(),
1143  mesh_
1144  ),
1145  mesh_,
1146  dimensionedScalar(alpha.dgdt().dimensions(), 0)
1147  );
1148 
1150  (
1151  IOobject
1152  (
1153  "Su",
1154  mesh_.time().timeName(),
1155  mesh_
1156  ),
1157  // Divergence term is handled explicitly to be
1158  // consistent with the explicit transport solution
1159  divU*min(alpha, scalar(1))
1160  );
1161 
1162  {
1163  const scalarField& dgdt = alpha.dgdt();
1164 
1165  forAll(dgdt, celli)
1166  {
1167  if (dgdt[celli] < 0.0 && alpha[celli] > 0.0)
1168  {
1169  Sp[celli] += dgdt[celli]*alpha[celli];
1170  Su[celli] -= dgdt[celli]*alpha[celli];
1171  }
1172  else if (dgdt[celli] > 0.0 && alpha[celli] < 1.0)
1173  {
1174  Sp[celli] -= dgdt[celli]*(1.0 - alpha[celli]);
1175  }
1176  }
1177  }
1178 
1179  forAllConstIter(PtrDictionary<phaseModel>, phases_, phase2)
1180  {
1181  const phaseModel& alpha2 = phase2();
1182 
1183  if (&alpha2 == &alpha) continue;
1184 
1185  const scalarField& dgdt2 = alpha2.dgdt();
1186 
1187  forAll(dgdt2, celli)
1188  {
1189  if (dgdt2[celli] > 0.0 && alpha2[celli] < 1.0)
1190  {
1191  Sp[celli] -= dgdt2[celli]*(1.0 - alpha2[celli]);
1192  Su[celli] += dgdt2[celli]*alpha[celli];
1193  }
1194  else if (dgdt2[celli] < 0.0 && alpha2[celli] > 0.0)
1195  {
1196  Sp[celli] += dgdt2[celli]*alpha2[celli];
1197  }
1198  }
1199  }
1200 
1202  (
1203  geometricOneField(),
1204  alpha,
1205  alphaPhi,
1206  Sp,
1207  Su
1208  );
1209 
1210  rhoPhi_ += fvc::interpolate(alpha.thermo().rho())*alphaPhi;
1211 
1212  Info<< alpha.name() << " volume fraction, min, max = "
1213  << alpha.weightedAverage(mesh_.V()).value()
1214  << ' ' << min(alpha).value()
1215  << ' ' << max(alpha).value()
1216  << endl;
1217 
1218  sumAlpha += alpha;
1219 
1220  phasei++;
1221  }
1222 
1223  Info<< "Phase-sum volume fraction, min, max = "
1224  << sumAlpha.weightedAverage(mesh_.V()).value()
1225  << ' ' << min(sumAlpha).value()
1226  << ' ' << max(sumAlpha).value()
1227  << endl;
1228 
1229  calcAlphas();
1230 }
1231 
1232 
1233 // ************************************************************************* //
volScalarField & he
Definition: YEEqn.H:50
scalar Cv(const scalar p, const scalar T) const
Definition: HtoEthermo.H:2
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:434
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:459
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/m^2/K^4].
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 [].
static tmp< GeometricField< scalar, fvsPatchField, surfaceMesh > > New(const word &name, const Mesh &, const dimensionSet &, const word &patchFieldType=fvsPatchField< scalar >::calculatedType())
Return a temporary field constructed from name, mesh, dimensionSet.
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(rho0+psi *p, rhoMin);# 1 "/home/ubuntu/OpenFOAM-7/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:68
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 [W/m/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))
scalar Cp(const scalar p, const scalar T) const
Definition: EtoHthermo.H:2
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
volScalarField alpha(IOobject("alpha", runTime.timeName(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE), lambda *max(Ua &U, zeroSensitivity))
zeroField divU
Definition: alphaSuSp.H:3
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 [W/m/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))
#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 [W/m/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