All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MomentumTransferPhaseSystem.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2015-2022 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 
28 #include "dragModel.H"
29 #include "virtualMassModel.H"
30 #include "liftModel.H"
31 #include "wallLubricationModel.H"
33 
34 #include "HashPtrTable.H"
35 
36 #include "fvmDdt.H"
37 #include "fvmDiv.H"
38 #include "fvmSup.H"
39 #include "fvcAverage.H"
40 #include "fvcDdt.H"
41 #include "fvcDiv.H"
42 #include "fvcFlux.H"
43 #include "fvcSnGrad.H"
44 #include "fvcMeshPhi.H"
45 #include "fvMatrix.H"
46 
47 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
48 
49 template<class BasePhaseSystem>
51 (
52  const phaseSystem::dmdtfTable& dmdtfs,
53  phaseSystem::momentumTransferTable& eqns
54 )
55 {
56  forAllConstIter(phaseSystem::dmdtfTable, dmdtfs, dmdtfIter)
57  {
58  const phaseInterface interface(*this, dmdtfIter.key());
59 
60  const volScalarField& dmdtf = *dmdtfIter();
61  const volScalarField dmdtf21(posPart(dmdtf));
62  const volScalarField dmdtf12(negPart(dmdtf));
63 
64  phaseModel& phase1 = this->phases()[interface.phase1().name()];
65  phaseModel& phase2 = this->phases()[interface.phase2().name()];
66 
67  if (!phase1.stationary())
68  {
69  *eqns[phase1.name()] +=
70  dmdtf21*phase2.U() + fvm::Sp(dmdtf12, phase1.URef());
71  }
72 
73  if (!phase2.stationary())
74  {
75  *eqns[phase2.name()] -=
76  dmdtf12*phase1.U() + fvm::Sp(dmdtf21, phase2.URef());
77  }
78  }
79 }
80 
81 
82 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
83 
84 template<class BasePhaseSystem>
87 (
88  const fvMesh& mesh
89 )
90 :
91  BasePhaseSystem(mesh)
92 {
93  this->generateInterfacialModels(dragModels_);
94  this->generateInterfacialModels(virtualMassModels_);
95  this->generateInterfacialModels(liftModels_);
96  this->generateInterfacialModels(wallLubricationModels_);
97  this->generateInterfacialModels(turbulentDispersionModels_);
98 
100  (
101  dragModelTable,
102  dragModels_,
103  dragModelIter
104  )
105  {
106  const phaseInterface& interface = dragModelIter()->interface();
107 
108  Kds_.insert
109  (
110  dragModelIter.key(),
111  new volScalarField
112  (
113  IOobject
114  (
115  IOobject::groupName("Kd", interface.name()),
116  this->mesh().time().timeName(),
117  this->mesh()
118  ),
119  this->mesh(),
121  )
122  );
123 
124  Kdfs_.insert
125  (
126  dragModelIter.key(),
128  (
129  IOobject
130  (
131  IOobject::groupName("Kdf", interface.name()),
132  this->mesh().time().timeName(),
133  this->mesh()
134  ),
135  this->mesh(),
137  )
138  );
139  }
140 
142  (
143  virtualMassModelTable,
144  virtualMassModels_,
145  virtualMassModelIter
146  )
147  {
148  const phaseInterface& interface = virtualMassModelIter()->interface();
149 
150  Vms_.insert
151  (
152  interface,
153  new volScalarField
154  (
155  IOobject
156  (
157  IOobject::groupName("Vm", interface.name()),
158  this->mesh().time().timeName(),
159  this->mesh()
160  ),
161  this->mesh(),
163  )
164  );
165 
166  Vmfs_.insert
167  (
168  interface,
170  (
171  IOobject
172  (
173  IOobject::groupName("Vmf", interface.name()),
174  this->mesh().time().timeName(),
175  this->mesh()
176  ),
177  this->mesh(),
179  )
180  );
181  }
182 }
183 
184 
185 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
186 
187 template<class BasePhaseSystem>
190 {}
191 
192 
193 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
194 
195 template<class BasePhaseSystem>
198 {
199  // Create a momentum transfer matrix for each phase
200  autoPtr<phaseSystem::momentumTransferTable> eqnsPtr
201  (
203  );
204 
205  phaseSystem::momentumTransferTable& eqns = eqnsPtr();
206 
207  forAll(this->movingPhases(), movingPhasei)
208  {
209  const phaseModel& phase = this->movingPhases()[movingPhasei];
210 
211  eqns.insert
212  (
213  phase.name(),
214  new fvVectorMatrix(phase.U(), dimMass*dimVelocity/dimTime)
215  );
216  }
217 
218  // Update the drag coefficients
220  (
221  dragModelTable,
222  dragModels_,
223  dragModelIter
224  )
225  {
226  *Kds_[dragModelIter.key()] = dragModelIter()->K();
227  *Kdfs_[dragModelIter.key()] = dragModelIter()->Kf();
228  }
229 
230  // Add the implicit part of the drag force
231  forAllConstIter(KdTable, Kds_, KdIter)
232  {
233  const volScalarField& K(*KdIter());
234  const phaseInterface interface(*this, KdIter.key());
235 
236  forAllConstIter(phaseInterface, interface, iter)
237  {
238  if (!iter().stationary())
239  {
240  fvVectorMatrix& eqn = *eqns[iter().name()];
241 
242  eqn -= fvm::Sp(K, eqn.psi());
243  }
244  }
245  }
246 
247  // Update the virtual mass coefficients
249  (
250  virtualMassModelTable,
251  virtualMassModels_,
252  virtualMassModelIter
253  )
254  {
255  *Vms_[virtualMassModelIter.key()] = virtualMassModelIter()->K();
256  *Vmfs_[virtualMassModelIter.key()] = virtualMassModelIter()->Kf();
257  }
258 
259  // Add the virtual mass force
260  forAllConstIter(VmTable, Vms_, VmIter)
261  {
262  const volScalarField& Vm(*VmIter());
263  const phaseInterface interface(*this, VmIter.key());
264 
265  forAllConstIter(phaseInterface, interface, iter)
266  {
267  const phaseModel& phase = iter();
268  const phaseModel& otherPhase = iter.otherPhase();
269 
270  if (!phase.stationary())
271  {
272  fvVectorMatrix& eqn = *eqns[phase.name()];
273 
274  const volVectorField& U = eqn.psi();
275  const surfaceScalarField& phi = phase.phi();
276  const tmp<surfaceScalarField> taphi(fvc::absolute(phi, U));
277  const surfaceScalarField& aphi(taphi());
278 
279  eqn -=
280  Vm
281  *(
282  fvm::ddt(U)
283  + fvm::div(aphi, U) - fvm::Sp(fvc::div(aphi), U)
284  - otherPhase.DUDt()
285  )
286  + this->MRF_.DDt(Vm, U - otherPhase.U());
287  }
288  }
289  }
290 
291  return eqnsPtr;
292 }
293 
294 
295 template<class BasePhaseSystem>
298 {
299  // Create a momentum transfer matrix for each phase
300  autoPtr<phaseSystem::momentumTransferTable> eqnsPtr
301  (
303  );
304 
305  phaseSystem::momentumTransferTable& eqns = eqnsPtr();
306 
307  forAll(this->movingPhases(), movingPhasei)
308  {
309  const phaseModel& phase = this->movingPhases()[movingPhasei];
310 
311  eqns.insert
312  (
313  phase.name(),
314  new fvVectorMatrix(phase.U(), dimMass*dimVelocity/dimTime)
315  );
316  }
317 
318  // Create U & grad(U) fields
319  PtrList<fvVectorMatrix> UgradUs(this->phaseModels_.size());
320  forAll(this->phaseModels_, phasei)
321  {
322  const phaseModel& phase = this->phaseModels_[phasei];
323 
324  if (!phase.stationary())
325  {
326  const volVectorField& U = phase.U();
327  const surfaceScalarField& phi = phase.phi();
328  const tmp<surfaceScalarField> taphi(fvc::absolute(phi, U));
329  const surfaceScalarField& aphi(taphi());
330 
331  UgradUs.set
332  (
333  phasei,
334  new fvVectorMatrix
335  (
336  fvm::div(aphi, U) - fvm::Sp(fvc::div(aphi), U)
337  + this->MRF().DDt(U)
338  )
339  );
340  }
341  }
342 
343  // Add the virtual mass force
344  forAllConstIter(VmTable, Vms_, VmIter)
345  {
346  const volScalarField& Vm(*VmIter());
347  const phaseInterface interface(*this, VmIter.key());
348 
349  forAllConstIter(phaseInterface, interface, iter)
350  {
351  const phaseModel& phase = iter();
352  const phaseModel& otherPhase = iter.otherPhase();
353 
354  if (!phase.stationary())
355  {
356  *eqns[phase.name()] -=
357  Vm
358  *(
359  UgradUs[phase.index()]
360  - (UgradUs[otherPhase.index()] & otherPhase.U())
361  );
362  }
363  }
364  }
365 
366  return eqnsPtr;
367 }
368 
369 
370 template<class BasePhaseSystem>
373 {
374  PtrList<surfaceScalarField> AFfs(this->phaseModels_.size());
375 
376  // Add the implicit part of the drag force
377  forAllConstIter(KdfTable, Kdfs_, KdfIter)
378  {
379  const surfaceScalarField& Kf(*KdfIter());
380  const phaseInterface interface(*this, KdfIter.key());
381 
382  forAllConstIter(phaseInterface, interface, iter)
383  {
384  addField(iter(), "AFf", Kf, AFfs);
385  }
386  }
387 
388  // Add the implicit part of the virtual mass force
389  forAllConstIter(VmfTable, Vmfs_, VmfIter)
390  {
391  const surfaceScalarField& Vmf(*VmfIter());
392  const phaseInterface interface(*this, VmfIter.key());
393 
394  forAllConstIter(phaseInterface, interface, iter)
395  {
396  addField(iter(), "AFf", byDt(Vmf), AFfs);
397  }
398  }
399 
400  this->fillFields("AFf", dimDensity/dimTime, AFfs);
401 
402  return AFfs;
403 }
404 
405 
406 template<class BasePhaseSystem>
409 (
410  const PtrList<volScalarField>& rAUs
411 )
412 {
413  PtrList<surfaceScalarField> phiFs(this->phaseModels_.size());
414 
415  // Add the lift force
417  (
418  liftModelTable,
419  liftModels_,
420  liftModelIter
421  )
422  {
423  const phaseInterface& interface = liftModelIter()->interface();
424 
425  const volVectorField F(liftModelIter()->F());
426 
427  addField
428  (
429  interface.phase1(),
430  "phiF",
431  fvc::flux(rAUs[interface.phase1().index()]*F),
432  phiFs
433  );
434  addField
435  (
436  interface.phase2(),
437  "phiF",
438  -fvc::flux(rAUs[interface.phase2().index()]*F),
439  phiFs
440  );
441  }
442 
443  // Add the wall lubrication force
445  (
446  wallLubricationModelTable,
447  wallLubricationModels_,
448  wallLubricationModelIter
449  )
450  {
451  const phaseInterface& interface =
452  wallLubricationModelIter()->interface();
453 
454  const volVectorField F(wallLubricationModelIter()->F());
455 
456  addField
457  (
458  interface.phase1(),
459  "phiF",
460  fvc::flux(rAUs[interface.phase1().index()]*F),
461  phiFs
462  );
463  addField
464  (
465  interface.phase2(),
466  "phiF",
467  -fvc::flux(rAUs[interface.phase2().index()]*F),
468  phiFs
469  );
470  }
471 
472  // Add the phase pressure
473  forAll(this->phaseModels_, phasei)
474  {
475  const phaseModel& phase = this->phaseModels_[phasei];
476 
477  const surfaceScalarField pPrimeByAf
478  (
479  fvc::interpolate(rAUs[phasei]*phase.pPrime())
480  );
481 
482  const surfaceScalarField snGradAlpha1
483  (
484  fvc::snGrad(phase)*this->mesh_.magSf()
485  );
486 
487  addField(phase, "phiF", pPrimeByAf*snGradAlpha1, phiFs);
488  }
489 
490  // Add the turbulent dispersion force
492  (
493  turbulentDispersionModelTable,
494  turbulentDispersionModels_,
495  turbulentDispersionModelIter
496  )
497  {
498  const phaseInterface& interface =
499  turbulentDispersionModelIter()->interface();
500 
501  const volScalarField D(turbulentDispersionModelIter()->D());
502 
503  const surfaceScalarField DByA1f
504  (
505  fvc::interpolate(rAUs[interface.phase1().index()]*D)
506  );
507  const surfaceScalarField DByA2f
508  (
509  fvc::interpolate(rAUs[interface.phase2().index()]*D)
510  );
511 
512  const volScalarField alpha12(interface.phase1() + interface.phase2());
513  const surfaceScalarField snGradAlpha1By12
514  (
516  (
517  interface.phase1()
518  /max(alpha12, interface.phase1().residualAlpha())
519  )*this->mesh_.magSf()
520  );
521  const surfaceScalarField snGradAlpha2By12
522  (
524  (
525  interface.phase2()
526  /max(alpha12, interface.phase2().residualAlpha())
527  )*this->mesh_.magSf()
528  );
529 
530  addField(interface.phase1(), "phiF", DByA1f*snGradAlpha1By12, phiFs);
531  addField(interface.phase2(), "phiF", DByA2f*snGradAlpha2By12, phiFs);
532  }
533 
534  if (this->fillFields_)
535  {
537  }
538 
539  return phiFs;
540 }
541 
542 
543 template<class BasePhaseSystem>
546 (
547  const PtrList<surfaceScalarField>& rAUfs
548 )
549 {
550  PtrList<surfaceScalarField> phiFfs(this->phaseModels_.size());
551 
552  // Add the explicit part of the virtual mass force
553  forAllConstIter(VmfTable, Vmfs_, VmfIter)
554  {
555  const surfaceScalarField& Vmf(*VmfIter());
556  const phaseInterface interface(*this, VmfIter.key());
557 
558  forAllConstIter(phaseInterface, interface, iter)
559  {
560  addField
561  (
562  iter(),
563  "phiFf",
564  -rAUfs[iter().index()]*Vmf
565  *(
566  byDt
567  (
569  (
570  this->MRF().absolute(iter().phi()().oldTime()),
571  iter().U()
572  )
573  )
574  + iter.otherPhase().DUDtf()
575  ),
576  phiFfs
577  );
578  }
579  }
580 
581  // Add the lift force
583  (
584  liftModelTable,
585  liftModels_,
586  liftModelIter
587  )
588  {
589  const phaseInterface& interface = liftModelIter()->interface();
590 
591  const surfaceScalarField Ff(liftModelIter()->Ff());
592 
593  addField
594  (
595  interface.phase1(),
596  "phiFf",
597  rAUfs[interface.phase1().index()]*Ff,
598  phiFfs
599  );
600  addField
601  (
602  interface.phase2(),
603  "phiFf",
604  -rAUfs[interface.phase2().index()]*Ff,
605  phiFfs
606  );
607  }
608 
609  // Add the wall lubrication force
611  (
612  wallLubricationModelTable,
613  wallLubricationModels_,
614  wallLubricationModelIter
615  )
616  {
617  const phaseInterface& interface =
618  wallLubricationModelIter()->interface();
619 
620  const surfaceScalarField Ff(wallLubricationModelIter()->Ff());
621 
622  addField
623  (
624  interface.phase1(),
625  "phiFf",
626  rAUfs[interface.phase1().index()]*Ff,
627  phiFfs
628  );
629  addField
630  (
631  interface.phase2(),
632  "phiFf",
633  -rAUfs[interface.phase2().index()]*Ff,
634  phiFfs
635  );
636  }
637 
638  // Add the phase pressure
639  forAll(this->phaseModels_, phasei)
640  {
641  const phaseModel& phase = this->phaseModels_[phasei];
642 
643  const surfaceScalarField pPrimeByAf
644  (
645  rAUfs[phasei]*fvc::interpolate(phase.pPrime())
646  );
647 
648  const surfaceScalarField snGradAlpha1
649  (
650  fvc::snGrad(phase)*this->mesh_.magSf()
651  );
652 
653  addField(phase, "phiFf", pPrimeByAf*snGradAlpha1, phiFfs);
654  }
655 
656  // Add the turbulent dispersion force
658  (
659  turbulentDispersionModelTable,
660  turbulentDispersionModels_,
661  turbulentDispersionModelIter
662  )
663  {
664  const phaseInterface& interface =
665  turbulentDispersionModelIter()->interface();
666 
667  const surfaceScalarField Df
668  (
669  fvc::interpolate(turbulentDispersionModelIter()->D())
670  );
671 
672  const surfaceScalarField DByA1f(rAUfs[interface.phase1().index()]*Df);
673  const surfaceScalarField DByA2f(rAUfs[interface.phase2().index()]*Df);
674 
675  const volScalarField alpha12(interface.phase1() + interface.phase2());
676  const surfaceScalarField snGradAlpha1By12
677  (
679  (
680  interface.phase1()
681  /max(alpha12, interface.phase1().residualAlpha())
682  )*this->mesh_.magSf()
683  );
684  const surfaceScalarField snGradAlpha2By12
685  (
687  (
688  interface.phase2()
689  /max(alpha12, interface.phase2().residualAlpha())
690  )*this->mesh_.magSf()
691  );
692 
693  addField(interface.phase1(), "phiF", DByA1f*snGradAlpha1By12, phiFfs);
694  addField(interface.phase2(), "phiF", DByA2f*snGradAlpha2By12, phiFfs);
695  }
696 
697  if (this->fillFields_)
698  {
700  }
701 
702  return phiFfs;
703 }
704 
705 
706 template<class BasePhaseSystem>
709 (
710  const PtrList<volScalarField>& rAUs
711 ) const
712 {
713  PtrList<surfaceScalarField> phiKdPhis(this->phaseModels_.size());
714 
715  // Add the explicit part of the drag force
716  forAllConstIter(KdTable, Kds_, KdIter)
717  {
718  const volScalarField& K(*KdIter());
719  const phaseInterface interface(*this, KdIter.key());
720 
721  forAllConstIter(phaseInterface, interface, iter)
722  {
723  addField
724  (
725  iter(),
726  "phiKdPhi",
727  -fvc::interpolate(rAUs[iter().index()]*K)
729  (
730  this->MRF().absolute(iter.otherPhase().phi()),
731  iter.otherPhase().U()
732  ),
733  phiKdPhis
734  );
735  }
736  }
737 
738  if (this->fillFields_)
739  {
740  this->fillFields
741  (
742  "phiKdPhi",
744  phiKdPhis
745  );
746  }
747 
748  return phiKdPhis;
749 }
750 
751 
752 template<class BasePhaseSystem>
755 (
756  const PtrList<surfaceScalarField>& rAUfs
757 ) const
758 {
759  PtrList<surfaceScalarField> phiKdPhifs(this->phaseModels_.size());
760 
761  // Add the explicit part of the drag force
762  forAllConstIter(KdfTable, Kdfs_, KdfIter)
763  {
764  const surfaceScalarField& Kf(*KdfIter());
765  const phaseInterface interface(*this, KdfIter.key());
766 
767  forAllConstIter(phaseInterface, interface, iter)
768  {
769  addField
770  (
771  iter(),
772  "phiKdPhif",
773  -rAUfs[iter().index()]*Kf
775  (
776  this->MRF().absolute(iter.otherPhase().phi()),
777  iter.otherPhase().U()
778  ),
779  phiKdPhifs
780  );
781  }
782  }
783 
784  if (this->fillFields_)
785  {
786  this->fillFields
787  (
788  "phiKdPhif",
790  phiKdPhifs
791  );
792  }
793 
794  return phiKdPhifs;
795 }
796 
797 
798 template<class BasePhaseSystem>
801 (
802  const PtrList<volScalarField>& rAUs
803 ) const
804 {
805  PtrList<volVectorField> KdUByAs(this->phaseModels_.size());
806 
807  // Add the explicit part of the drag force
808  forAllConstIter(KdTable, Kds_, KdIter)
809  {
810  const volScalarField& K(*KdIter());
811  const phaseInterface interface(*this, KdIter.key());
812 
813  forAllConstIter(phaseInterface, interface, iter)
814  {
815  addField
816  (
817  iter(),
818  "KdUByA",
819  -rAUs[iter().index()]*K*iter.otherPhase().U(),
820  KdUByAs
821  );
822  }
823  }
824 
825  if (this->fillFields_)
826  {
827  this->fillFields("KdUByA", dimVelocity, KdUByAs);
828  }
829 
830  return KdUByAs;
831 }
832 
833 
834 template<class BasePhaseSystem>
836 implicitPhasePressure(const phaseModel& phase) const
837 {
838  return
839  this->mesh_.solution().solverDict(phase.volScalarField::name()).
840  template lookupOrDefault<Switch>
841  (
842  "implicitPhasePressure",
843  false
844  );
845 }
846 
847 
848 template<class BasePhaseSystem>
850 implicitPhasePressure() const
851 {
852  bool implicitPressure = false;
853 
854  forAll(this->phaseModels_, phasei)
855  {
856  const phaseModel& phase = this->phaseModels_[phasei];
857 
858  implicitPressure = implicitPressure || implicitPhasePressure(phase);
859  }
860 
861  return implicitPressure;
862 }
863 
864 
865 template<class BasePhaseSystem>
868 (
869  const PtrList<volScalarField>& rAUs,
870  const PtrList<surfaceScalarField>& rAUfs
871 ) const
872 {
873  PtrList<surfaceScalarField> DByAfs(this->phaseModels_.size());
874 
875  if (rAUfs.size())
876  {
877  // Add the phase pressure
878  forAll(this->phaseModels_, phasei)
879  {
880  const phaseModel& phase = this->phaseModels_[phasei];
881 
882  const surfaceScalarField pPrimeByAf
883  (
884  rAUfs[phasei]*fvc::interpolate(phase.pPrime())
885  );
886 
887  addField(phase, "DByAf", pPrimeByAf, DByAfs);
888 
889  forAll(this->phaseModels_, phasej)
890  {
891  if (phasej != phasei)
892  {
893  const phaseModel& phase2 = this->phaseModels_[phasej];
894 
895  addField
896  (
897  phase2,
898  "DByAf",
900  (
901  phase2
902  /max(1 - phase, phase2.residualAlpha())
903  )*pPrimeByAf,
904  DByAfs
905  );
906  }
907  }
908  }
909 
910  // Add the turbulent dispersion
912  (
913  turbulentDispersionModelTable,
914  turbulentDispersionModels_,
915  turbulentDispersionModelIter
916  )
917  {
918  const phaseInterface& interface =
919  turbulentDispersionModelIter()->interface();
920 
921  const surfaceScalarField Df
922  (
923  fvc::interpolate(turbulentDispersionModelIter()->D())
924  );
925 
926  const surfaceScalarField alpha12f
927  (
928  fvc::interpolate(interface.phase1() + interface.phase2())
929  );
930 
931  addField
932  (
933  interface.phase1(),
934  "DByAf",
935  rAUfs[interface.phase1().index()]*Df
936  /max(alpha12f, interface.phase1().residualAlpha()),
937  DByAfs
938  );
939  addField
940  (
941  interface.phase2(),
942  "DByAf",
943  rAUfs[interface.phase2().index()]*Df
944  /max(alpha12f, interface.phase2().residualAlpha()),
945  DByAfs
946  );
947  }
948  }
949  else
950  {
951  // Add the phase pressure
952  forAll(this->phaseModels_, phasei)
953  {
954  const phaseModel& phase = this->phaseModels_[phasei];
955 
956  const surfaceScalarField pPrimeByAf
957  (
958  fvc::interpolate(rAUs[phasei]*phase.pPrime())
959  );
960 
961  addField(phase, "DByAf", pPrimeByAf, DByAfs);
962 
963  forAll(this->phaseModels_, phasej)
964  {
965  if (phasej != phasei)
966  {
967  const phaseModel& phase2 = this->phaseModels_[phasej];
968 
969  addField
970  (
971  phase2,
972  "DByAf",
974  (
975  phase2
976  /max(1 - phase, phase2.residualAlpha())
977  )*pPrimeByAf,
978  DByAfs
979  );
980  }
981  }
982  }
983 
984  // Add the turbulent dispersion
986  (
987  turbulentDispersionModelTable,
988  turbulentDispersionModels_,
989  turbulentDispersionModelIter
990  )
991  {
992  const phaseInterface& interface =
993  turbulentDispersionModelIter()->interface();
994 
995  const volScalarField D(turbulentDispersionModelIter()->D());
996 
997  const volScalarField alpha12
998  (
999  interface.phase1() + interface.phase2()
1000  );
1001 
1002  addField
1003  (
1004  interface.phase1(),
1005  "DByAf",
1007  (
1008  rAUs[interface.phase1().index()]*D
1009  /max(alpha12, interface.phase1().residualAlpha())
1010  ),
1011  DByAfs
1012  );
1013  addField
1014  (
1015  interface.phase2(),
1016  "DByAf",
1018  (
1019  rAUs[interface.phase2().index()]*D
1020  /max(alpha12, interface.phase2().residualAlpha())
1021  ),
1022  DByAfs
1023  );
1024  }
1025  }
1026 
1027  return DByAfs;
1028 }
1029 
1030 
1031 template<class BasePhaseSystem>
1034 (
1035  const PtrList<volScalarField>& rAUs,
1036  const bool includeVirtualMass
1037 ) const
1038 {
1039  PtrList<surfaceScalarField> ddtCorrByAs(this->phaseModels_.size());
1040 
1041  // Construct phi differences
1042  PtrList<surfaceScalarField> phiCorrs(this->phaseModels_.size());
1043 
1044  forAll(this->movingPhases(), movingPhasei)
1045  {
1046  const phaseModel& phase = this->movingPhases()[movingPhasei];
1047  const label phasei = phase.index();
1048 
1049  phiCorrs.set
1050  (
1051  phasei,
1052  this->MRF().zeroFilter
1053  (
1054  (
1055  phase.Uf().valid()
1056  ? (this->mesh_.Sf() & phase.Uf()().oldTime())()
1057  : phase.phi()().oldTime()
1058  )
1059  - fvc::flux(phase.U()().oldTime())
1060  )()
1061  );
1062  }
1063 
1064  // Add correction
1065  forAll(this->movingPhases(), movingPhasei)
1066  {
1067  const phaseModel& phase = this->movingPhases()[movingPhasei];
1068  const label phasei = phase.index();
1069  const volScalarField& alpha = phase;
1070 
1071  // Apply ddtPhiCorr filter in pure(ish) phases
1072  surfaceScalarField alphafBar
1073  (
1075  );
1076 
1077  tmp<surfaceScalarField> phiCorrCoeff = pos0(alphafBar - 0.99);
1078 
1079  surfaceScalarField::Boundary& phiCorrCoeffBf =
1080  phiCorrCoeff.ref().boundaryFieldRef();
1081 
1082  forAll(this->mesh_.boundary(), patchi)
1083  {
1084  // Set ddtPhiCorr to 0 on non-coupled boundaries
1085  if
1086  (
1087  !this->mesh_.boundary()[patchi].coupled()
1088  || isA<cyclicAMIFvPatch>(this->mesh_.boundary()[patchi])
1089  )
1090  {
1091  phiCorrCoeffBf[patchi] = 0;
1092  }
1093  }
1094 
1095  addField
1096  (
1097  phase,
1098  "ddtCorrByA",
1099  -phiCorrCoeff*phiCorrs[phasei]*fvc::interpolate
1100  (
1101  byDt(alpha.oldTime()*phase.rho()().oldTime()*rAUs[phasei])
1102  ),
1103  ddtCorrByAs
1104  );
1105  }
1106 
1107  // Add virtual mass correction
1108  if (includeVirtualMass)
1109  {
1110  forAllConstIter(VmTable, Vms_, VmIter)
1111  {
1112  const volScalarField& Vm(*VmIter());
1113  const phaseInterface interface(*this, VmIter.key());
1114 
1115  forAllConstIter(phaseInterface, interface, iter)
1116  {
1117  const phaseModel& phase = iter();
1118  const phaseModel& otherPhase = iter.otherPhase();
1119 
1120  addField
1121  (
1122  iter(),
1123  "ddtCorrByA",
1124  -fvc::interpolate(Vm*byDt(rAUs[phase.index()]))
1125  *(
1126  phiCorrs[phase.index()]
1127  + fvc::absolute
1128  (
1129  this->MRF().absolute(otherPhase.phi()),
1130  otherPhase.U()
1131  )
1132  - fvc::flux(otherPhase.U())
1133  - phiCorrs[otherPhase.index()]
1134  ),
1135  ddtCorrByAs
1136  );
1137  }
1138  }
1139  }
1140 
1141  return ddtCorrByAs;
1142 }
1143 
1144 
1145 template<class BasePhaseSystem>
1147 (
1148  const PtrList<volScalarField>& rAUs,
1149  const PtrList<volVectorField>& KdUByAs,
1150  const PtrList<surfaceScalarField>& alphafs,
1151  const PtrList<surfaceScalarField>& phiKdPhis
1152 )
1153 {
1154  Info<< "Inverting drag systems: ";
1155 
1156  phaseSystem::phaseModelList& phases = this->phaseModels_;
1157 
1158  // Calculate the mean velocity from the current velocity
1159  // of the moving phases
1160  volVectorField Um(this->movingPhases()[0]*this->movingPhases()[0].U());
1161 
1162  for
1163  (
1164  label movingPhasei=1;
1165  movingPhasei<this->movingPhases().size();
1166  movingPhasei++
1167  )
1168  {
1169  Um +=
1170  this->movingPhases()[movingPhasei]
1171  *this->movingPhases()[movingPhasei].U();
1172  }
1173 
1174  // Remove the drag contributions from the velocity and flux of the phases
1175  // in preparation for the partial elimination of these terms
1176  forAll(phases, i)
1177  {
1178  if (!phases[i].stationary())
1179  {
1180  phases[i].URef() += KdUByAs[i];
1181  phases[i].phiRef() += phiKdPhis[i];
1182  }
1183  }
1184 
1185  {
1186  // Create drag coefficient matrices
1187  PtrList<PtrList<volScalarField>> KdByAs(phases.size());
1188  PtrList<PtrList<surfaceScalarField>> phiKds(phases.size());
1189 
1190  forAll(phases, i)
1191  {
1192  KdByAs.set
1193  (
1194  i,
1195  new PtrList<volScalarField>(phases.size())
1196  );
1197 
1198  phiKds.set
1199  (
1200  i,
1201  new PtrList<surfaceScalarField>(phases.size())
1202  );
1203  }
1204 
1205  forAllConstIter(KdTable, Kds_, KdIter)
1206  {
1207  const volScalarField& K(*KdIter());
1208  const phaseInterface interface(*this, KdIter.key());
1209 
1210  const label phase1i = interface.phase1().index();
1211  const label phase2i = interface.phase2().index();
1212 
1213  addField
1214  (
1215  interface.phase2(),
1216  "KdByA",
1217  -rAUs[phase1i]*K,
1218  KdByAs[phase1i]
1219  );
1220  addField
1221  (
1222  interface.phase1(),
1223  "KdByA",
1224  -rAUs[phase2i]*K,
1225  KdByAs[phase2i]
1226  );
1227 
1228  addField
1229  (
1230  interface.phase2(),
1231  "phiKd",
1232  fvc::interpolate(KdByAs[phase1i][phase2i]),
1233  phiKds[phase1i]
1234  );
1235  addField
1236  (
1237  interface.phase1(),
1238  "phiKd",
1239  fvc::interpolate(KdByAs[phase2i][phase1i]),
1240  phiKds[phase2i]
1241  );
1242  }
1243 
1244  forAll(phases, i)
1245  {
1246  this->fillFields("KdByAs", dimless, KdByAs[i]);
1247  this->fillFields("phiKds", dimless, phiKds[i]);
1248 
1249  KdByAs[i][i] = 1;
1250  phiKds[i][i] = 1;
1251  }
1252 
1253  // Decompose
1254  for (label i = 0; i < phases.size(); i++)
1255  {
1256  for (label j = i + 1; j < phases.size(); j++)
1257  {
1258  KdByAs[i][j] /= KdByAs[i][i];
1259  phiKds[i][j] /= phiKds[i][i];
1260  for (label k = i + 1; k < phases.size(); ++ k)
1261  {
1262  KdByAs[j][k] -= KdByAs[j][i]*KdByAs[i][k];
1263  phiKds[j][k] -= phiKds[j][i]*phiKds[i][k];
1264  }
1265  }
1266  }
1267 
1268  {
1269  volScalarField detKdByAs(KdByAs[0][0]);
1270  surfaceScalarField detPhiKdfs(phiKds[0][0]);
1271 
1272  for (label i = 1; i < phases.size(); i++)
1273  {
1274  detKdByAs *= KdByAs[i][i];
1275  detPhiKdfs *= phiKds[i][i];
1276  }
1277 
1278  Info<< "Min cell/face det = " << gMin(detKdByAs.primitiveField())
1279  << "/" << gMin(detPhiKdfs.primitiveField()) << endl;
1280  }
1281 
1282  // Solve for the velocities and fluxes
1283  for (label i = 1; i < phases.size(); i++)
1284  {
1285  if (!phases[i].stationary())
1286  {
1287  for (label j = 0; j < i; j ++)
1288  {
1289  phases[i].URef() -= KdByAs[i][j]*phases[j].U();
1290  phases[i].phiRef() -= phiKds[i][j]*phases[j].phi();
1291  }
1292  }
1293  }
1294  for (label i = phases.size() - 1; i >= 0; i--)
1295  {
1296  if (!phases[i].stationary())
1297  {
1298  for (label j = phases.size() - 1; j > i; j--)
1299  {
1300  phases[i].URef() -= KdByAs[i][j]*phases[j].U();
1301  phases[i].phiRef() -= phiKds[i][j]*phases[j].phi();
1302  }
1303  phases[i].URef() /= KdByAs[i][i];
1304  phases[i].phiRef() /= phiKds[i][i];
1305  }
1306  }
1307  }
1308 
1309  this->setMixtureU(Um);
1310  this->setMixturePhi(alphafs, this->phi());
1311 }
1312 
1313 
1314 template<class BasePhaseSystem>
1316 (
1317  const PtrList<surfaceScalarField>& rAUfs,
1318  const PtrList<surfaceScalarField>& alphafs,
1319  const PtrList<surfaceScalarField>& phiKdPhifs
1320 )
1321 {
1322  Info<< "Inverting drag system: ";
1323 
1324  phaseSystem::phaseModelList& phases = this->phaseModels_;
1325 
1326  // Remove the drag contributions from the flux of the phases
1327  // in preparation for the partial elimination of these terms
1328  forAll(phases, i)
1329  {
1330  if (!phases[i].stationary())
1331  {
1332  phases[i].phiRef() += phiKdPhifs[i];
1333  }
1334  }
1335 
1336  {
1337  // Create drag coefficient matrix
1338  PtrList<PtrList<surfaceScalarField>> phiKdfs(phases.size());
1339 
1340  forAll(phases, phasei)
1341  {
1342  phiKdfs.set
1343  (
1344  phasei,
1345  new PtrList<surfaceScalarField>(phases.size())
1346  );
1347  }
1348 
1349  forAllConstIter(KdfTable, Kdfs_, KdfIter)
1350  {
1351  const surfaceScalarField& Kf(*KdfIter());
1352  const phaseInterface interface(*this, KdfIter.key());
1353 
1354  const label phase1i = interface.phase1().index();
1355  const label phase2i = interface.phase2().index();
1356 
1357  addField
1358  (
1359  interface.phase2(),
1360  "phiKdf",
1361  -rAUfs[phase1i]*Kf,
1362  phiKdfs[phase1i]
1363  );
1364  addField
1365  (
1366  interface.phase1(),
1367  "phiKdf",
1368  -rAUfs[phase2i]*Kf,
1369  phiKdfs[phase2i]
1370  );
1371  }
1372 
1373  forAll(phases, phasei)
1374  {
1375  this->fillFields("phiKdf", dimless, phiKdfs[phasei]);
1376 
1377  phiKdfs[phasei][phasei] = 1;
1378  }
1379 
1380  // Decompose
1381  for (label i = 0; i < phases.size(); i++)
1382  {
1383  for (label j = i + 1; j < phases.size(); j++)
1384  {
1385  phiKdfs[i][j] /= phiKdfs[i][i];
1386  for (label k = i + 1; k < phases.size(); ++ k)
1387  {
1388  phiKdfs[j][k] -= phiKdfs[j][i]*phiKdfs[i][k];
1389  }
1390  }
1391  }
1392 
1393  {
1394  surfaceScalarField detPhiKdfs(phiKdfs[0][0]);
1395 
1396  for (label i = 1; i < phases.size(); i++)
1397  {
1398  detPhiKdfs *= phiKdfs[i][i];
1399  }
1400 
1401  Info<< "Min face det = "
1402  << gMin(detPhiKdfs.primitiveField()) << endl;
1403  }
1404 
1405  // Solve for the fluxes
1406  for (label i = 1; i < phases.size(); i++)
1407  {
1408  if (!phases[i].stationary())
1409  {
1410  for (label j = 0; j < i; j ++)
1411  {
1412  phases[i].phiRef() -= phiKdfs[i][j]*phases[j].phi();
1413  }
1414  }
1415  }
1416  for (label i = phases.size() - 1; i >= 0; i--)
1417  {
1418  if (!phases[i].stationary())
1419  {
1420  for (label j = phases.size() - 1; j > i; j--)
1421  {
1422  phases[i].phiRef() -= phiKdfs[i][j]*phases[j].phi();
1423  }
1424  phases[i].phiRef() /= phiKdfs[i][i];
1425  }
1426  }
1427  }
1428 
1429  this->setMixturePhi(alphafs, this->phi());
1430 }
1431 
1432 
1433 template<class BasePhaseSystem>
1435 {
1436  if (BasePhaseSystem::read())
1437  {
1438  bool readOK = true;
1439 
1440  // Read models ...
1441 
1442  return readOK;
1443  }
1444  else
1445  {
1446  return false;
1447  }
1448 }
1449 
1450 
1451 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
tmp< GeometricField< Type, fvPatchField, volMesh > > DDt(const surfaceScalarField &phi, const GeometricField< Type, fvPatchField, volMesh > &psi)
Definition: fvcDDt.C:45
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
virtual PtrList< surfaceScalarField > phiFs(const PtrList< volScalarField > &rAUs)
Return the explicit force fluxes for the cell-based algorithm, that.
const dimensionedScalar F
Faraday constant: default SI units: [C/mol].
label phasei
Definition: pEqn.H:27
U
Definition: pEqn.H:72
IOMRFZoneList & MRF
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
Type gMin(const FieldField< Field, Type > &f)
HashPtrTable< fvVectorMatrix > momentumTransferTable
Definition: phaseSystem.H:76
virtual autoPtr< phaseSystem::momentumTransferTable > momentumTransferf()
As momentumTransfer, but for the face-based algorithm.
tmp< GeometricField< Type, fvPatchField, volMesh > > div(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcDiv.C:47
virtual bool read()
Read base phaseProperties dictionary.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
fluid fillFields("rAU", dimTime/dimDensity, rAUs)
MomentumTransferPhaseSystem(const fvMesh &)
Construct from fvMesh.
Calculate the snGrad of the given volField.
GeometricBoundaryField< scalar, fvsPatchField, surfaceMesh > Boundary
Type of the boundary field.
const dimensionSet dimless
label k
Boltzmann constant.
void read(Istream &, label &, const dictionary &)
In-place read with dictionary lookup.
tmp< fvMatrix< Type > > Sp(const volScalarField::Internal &, const GeometricField< Type, fvPatchField, volMesh > &)
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:59
fvMesh & mesh
CGAL::Exact_predicates_exact_constructions_kernel K
static const dimensionSet dimK
Coefficient dimensions.
dimensionedScalar posPart(const dimensionedScalar &ds)
Area-weighted average a surfaceField creating a volField.
virtual bool implicitPhasePressure() const
Returns true if the phase pressure is treated implicitly.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:58
Calculate the first temporal derivative.
const dimensionSet dimTime
PtrList< surfaceScalarField > phiFs(fluid.phiFs(rAUs))
Calculate the face-flux of the given field.
static word groupName(Name name, const word &group)
virtual void partialEliminationf(const PtrList< surfaceScalarField > &rAUfs, const PtrList< surfaceScalarField > &alphafs, const PtrList< surfaceScalarField > &phiKdPhifs)
As partialElimination, but for the face-based algorithm. Only solves.
const dimensionSet dimDensity
tmp< fvMatrix< Type > > ddt(const GeometricField< Type, fvPatchField, volMesh > &vf)
Definition: fvmDdt.C:46
Calculate the matrix for the first temporal derivative.
PtrListDictionary< phaseModel > phaseModelList
Definition: phaseSystem.H:82
phi
Definition: correctPhi.H:3
virtual PtrList< volVectorField > KdUByAs(const PtrList< volScalarField > &rAUs) const
Return the explicit part of the drag force for the cell-based.
const dimensionSet dimForce
virtual PtrList< surfaceScalarField > phiKdPhis(const PtrList< volScalarField > &rAUs) const
Return the explicit drag force fluxes for the cell-based algorithm.
Calculate the divergence of the given field.
dimensionedScalar pos0(const dimensionedScalar &ds)
PtrList< surfaceScalarField > phiFfs(fluid.phiFfs(rAUfs))
tmp< fvMatrix< Type > > div(const surfaceScalarField &flux, const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmDiv.C:46
const dimensionSet dimVelocity
const dimensionSet dimMass
virtual PtrList< surfaceScalarField > ddtCorrByAs(const PtrList< volScalarField > &rAUs, const bool includeVirtualMass=false) const
Return the flux corrections for the cell-based algorithm. These.
tmp< volScalarField > byDt(const volScalarField &vf)
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 tmp< volScalarField::Internal > & Sp
Definition: alphaSuSp.H:7
Calculate the mesh motion flux and convert fluxes from absolute to relative and back.
rho oldTime()
Calculate the matrix for the divergence of the given field and flux.
virtual ~MomentumTransferPhaseSystem()
Destructor.
virtual PtrList< surfaceScalarField > phiFfs(const PtrList< surfaceScalarField > &rAUfs)
As phiFs, but for the face-based algorithm.
label patchi
tmp< surfaceScalarField > absolute(const tmp< surfaceScalarField > &tphi, const volVectorField &U)
Return the given relative flux in absolute form.
Definition: fvcMeshPhi.C:202
static const dimensionSet dimK
Coefficient dimensions.
Definition: dragModel.H:83
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: List.H:70
virtual void partialElimination(const PtrList< volScalarField > &rAUs, const PtrList< volVectorField > &KdUByAs, const PtrList< surfaceScalarField > &alphafs, const PtrList< surfaceScalarField > &phiKdPhis)
Solve the drag system for the velocities and fluxes.
fvMatrix< vector > fvVectorMatrix
Definition: fvMatricesFwd.H:45
phaseSystem::phaseModelList & phases
Definition: createFields.H:12
messageStream Info
tmp< GeometricField< Type, fvPatchField, volMesh > > average(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Area-weighted average a surfaceField creating a volField.
Definition: fvcAverage.C:46
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
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 PtrList< surfaceScalarField > AFfs() const
Return implicit force coefficients on the faces, for the face-based.
virtual PtrList< surfaceScalarField > DByAfs(const PtrList< volScalarField > &rAUs, const PtrList< surfaceScalarField > &rAUfs) const
Return the phase diffusivity.
void addDmdtUfs(const phaseSystem::dmdtfTable &dmdtfs, phaseSystem::momentumTransferTable &eqns)
Add momentum transfer terms which result from bulk mass transfers.
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.
dimensionedScalar negPart(const dimensionedScalar &ds)
virtual autoPtr< phaseSystem::momentumTransferTable > momentumTransfer()
Return the momentum transfer matrices for the cell-based algorithm.
virtual PtrList< surfaceScalarField > phiKdPhifs(const PtrList< surfaceScalarField > &rAUfs) const
As phiKdPhis, but for the face-based algorithm.