momentumTransferSystem.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-2026 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "momentumTransferSystem.H"
27 
28 #include "dragModel.H"
29 #include "virtualMassModel.H"
30 #include "liftModel.H"
31 #include "wallLubricationModel.H"
34 
35 #include "fvmDdt.H"
36 #include "fvmDiv.H"
37 #include "fvmSup.H"
38 #include "fvcDdt.H"
39 #include "fvcDiv.H"
40 #include "fvcFlux.H"
41 #include "fvcSnGrad.H"
42 #include "fvcMeshPhi.H"
43 #include "fvcReconstruct.H"
44 
45 #include "scalarMatrices.H"
46 #include "pimpleNoLoopControl.H"
47 
48 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
49 
50 namespace Foam
51 {
53 }
54 
55 
57 (
58  "momentumTransfer"
59 );
60 
61 
62 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
63 
64 Foam::IOobject Foam::momentumTransferSystem::io(const phaseSystem& fluid) const
65 {
66  typeIOobject<IOdictionary> result
67  (
69  fluid.mesh().time().constant(),
70  fluid.mesh(),
73  );
74 
75  // Check for and warn about momentum transfer models being in the old
76  // location in constant/phaseProperties
77  const wordList modelEntries
78  ({
79  modelName<blendedDragModel>(),
80  modelName<blendedVirtualMassModel>(),
81  modelName<blendedLiftModel>(),
82  modelName<blendedWallLubricationModel>(),
83  modelName<blendedTurbulentDispersionModel>()
84  });
85 
86  OStringStream modelEntriesString;
87  forAll(modelEntries, i)
88  {
89  modelEntriesString<< modelEntries[i];
90  if (i < modelEntries.size() - 2) modelEntriesString<< ", ";
91  if (i == modelEntries.size() - 2) modelEntriesString<< " and ";
92  }
93 
94  if (!result.headerOk())
95  {
96  result.readOpt() = IOobject::NO_READ;
97 
99  << "Specifying momentum transfer model entries - "
100  << modelEntriesString.str().c_str() << " - in "
101  << fluid.relativeObjectPath() << " is deprecated. These "
102  << "entries should now be specified in "
103  << result.relativeObjectPath() << "." << endl;
104  }
105  else
106  {
107  forAll(modelEntries, i)
108  {
109  if (!fluid.found(modelEntries[i])) continue;
110 
112  << "Momentum transfer model entries - "
113  << modelEntriesString.str().c_str() << " - in "
114  << fluid.relativeObjectPath() << " are no longer used. These "
115  << "entries are now read from " << result.relativeObjectPath()
116  << "." << endl;
117 
118  break;
119  }
120  }
121 
122  return result;
123 }
124 
125 
126 template<class ModelType>
127 const Foam::dictionary& Foam::momentumTransferSystem::modelsDict() const
128 {
129  const word key = modelName<ModelType>();
130 
131  return
132  readOpt() == IOobject::NO_READ && fluid_.found(key)
133  ? fluid_.subDict(key)
134  : subDict(key);
135 }
136 
137 
138 void Foam::momentumTransferSystem::readModels()
139 {
140  dragModels_ =
141  generateBlendedInterfacialModels<blendedDragModel>
142  (
143  fluid_,
144  modelsDict<blendedDragModel>()
145  );
146 
147  virtualMassModels_ =
148  generateBlendedInterfacialModels<blendedVirtualMassModel>
149  (
150  fluid_,
151  modelsDict<blendedVirtualMassModel>()
152  );
153 
154  liftModels_ =
155  generateBlendedInterfacialModels<blendedLiftModel>
156  (
157  fluid_,
158  modelsDict<blendedLiftModel>()
159  );
160 
161  wallLubricationModels_ =
162  generateBlendedInterfacialModels<blendedWallLubricationModel>
163  (
164  fluid_,
165  modelsDict<blendedWallLubricationModel>()
166  );
167 
168  turbulentDispersionModels_ =
169  generateBlendedInterfacialModels<blendedTurbulentDispersionModel>
170  (
171  fluid_,
172  modelsDict<blendedTurbulentDispersionModel>()
173  );
174 }
175 
176 
177 void Foam::momentumTransferSystem::addTmpField
178 (
179  tmp<surfaceScalarField>& result,
180  const tmp<surfaceScalarField>& field
181 ) const
182 {
183  if (result.valid())
184  {
185  result.ref() += field;
186  }
187  else
188  {
189  if (field.isTmp())
190  {
191  result = field;
192  }
193  else
194  {
195  result = field().clone();
196  }
197  }
198 }
199 
200 
201 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
202 
204 :
205  IOdictionary(io(fluid)),
206  fluid_(fluid)
207 {
208  Info<< indentOrNl << "Constructing " << typeName << " from "
209  << relativeObjectPath().c_str() << endl;
210 
211  printDictionary print(*this);
212 
213  readModels();
214 }
215 
216 
217 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
218 
220 {}
221 
222 
223 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
224 
227 {
228  PtrList<surfaceScalarField> Fs(fluid_.phases().size());
229 
230  // Add the lift force
232  (
234  liftModels_,
235  liftModelIter
236  )
237  {
238  const phaseInterface& interface = liftModelIter()->interface();
239 
240  const volVectorField F(liftModelIter()->F());
241 
242  addField
243  (
244  interface.phase1(),
245  "F",
246  fvc::flux(F),
247  Fs
248  );
249  addField
250  (
251  interface.phase2(),
252  "F",
253  -fvc::flux(F),
254  Fs
255  );
256  }
257 
258  // Add the wall lubrication force
260  (
262  wallLubricationModels_,
263  wallLubricationModelIter
264  )
265  {
266  const phaseInterface& interface =
267  wallLubricationModelIter()->interface();
268 
269  const volVectorField F(wallLubricationModelIter()->F());
270 
271  addField
272  (
273  interface.phase1(),
274  "F",
275  fvc::flux(F),
276  Fs
277  );
278  addField
279  (
280  interface.phase2(),
281  "F",
282  -fvc::flux(F),
283  Fs
284  );
285  }
286 
287  // Add the phase pressure
288  forAll(fluid_.movingPhases(), movingPhasei)
289  {
290  const phaseModel& phase = fluid_.movingPhases()[movingPhasei];
291 
292  addField
293  (
294  phase,
295  "F",
296  phase.pPrimef()*fvc::snGrad(phase)*fluid_.mesh().magSf(),
297  Fs
298  );
299  }
300 
301  // Add the turbulent dispersion force
303  (
305  turbulentDispersionModels_,
306  turbulentDispersionModelIter
307  )
308  {
309  const phaseInterface& interface =
310  turbulentDispersionModelIter()->interface();
311 
312  const surfaceScalarField Df
313  (
314  fvc::interpolate(turbulentDispersionModelIter()->D())
315  );
316 
317  const volScalarField alpha12(interface.phase1() + interface.phase2());
318  const surfaceScalarField snGradAlpha1By12
319  (
321  (
322  interface.phase1()
323  /max(alpha12, interface.phase1().residualAlpha())
324  )*fluid_.mesh().magSf()
325  );
326  const surfaceScalarField snGradAlpha2By12
327  (
329  (
330  interface.phase2()
331  /max(alpha12, interface.phase2().residualAlpha())
332  )*fluid_.mesh().magSf()
333  );
334 
335  addField(interface.phase1(), "F", Df*snGradAlpha1By12, Fs);
336  addField(interface.phase2(), "F", Df*snGradAlpha2By12, Fs);
337  }
338 
339  return Fs;
340 }
341 
342 
345 {
346  PtrList<surfaceScalarField> Ffs(fluid_.phases().size());
347 
348  // Add the lift force
350  (
352  liftModels_,
353  liftModelIter
354  )
355  {
356  const phaseInterface& interface = liftModelIter()->interface();
357 
358  const surfaceScalarField Ff(liftModelIter()->Ff());
359 
360  addField
361  (
362  interface.phase1(),
363  "Ff",
364  Ff,
365  Ffs
366  );
367  addField
368  (
369  interface.phase2(),
370  "Ff",
371  -Ff,
372  Ffs
373  );
374  }
375 
376  // Add the wall lubrication force
378  (
380  wallLubricationModels_,
381  wallLubricationModelIter
382  )
383  {
384  const phaseInterface& interface =
385  wallLubricationModelIter()->interface();
386 
387  const surfaceScalarField Ff(wallLubricationModelIter()->Ff());
388 
389  addField
390  (
391  interface.phase1(),
392  "Ff",
393  Ff,
394  Ffs
395  );
396  addField
397  (
398  interface.phase2(),
399  "Ff",
400  -Ff,
401  Ffs
402  );
403  }
404 
405  // Add the phase pressure
406  forAll(fluid_.movingPhases(), movingPhasei)
407  {
408  const phaseModel& phase = fluid_.movingPhases()[movingPhasei];
409 
410  addField
411  (
412  phase,
413  "Ff",
414  phase.pPrimef()*fvc::snGrad(phase)*fluid_.mesh().magSf(),
415  Ffs
416  );
417  }
418 
419  // Add the turbulent dispersion force
421  (
423  turbulentDispersionModels_,
424  turbulentDispersionModelIter
425  )
426  {
427  const phaseInterface& interface =
428  turbulentDispersionModelIter()->interface();
429 
430  const surfaceScalarField Df
431  (
432  fvc::interpolate(turbulentDispersionModelIter()->D())
433  );
434 
435  const volScalarField alpha12(interface.phase1() + interface.phase2());
436  const surfaceScalarField snGradAlpha1By12
437  (
439  (
440  interface.phase1()
441  /max(alpha12, interface.phase1().residualAlpha())
442  )*fluid_.mesh().magSf()
443  );
444  const surfaceScalarField snGradAlpha2By12
445  (
447  (
448  interface.phase2()
449  /max(alpha12, interface.phase2().residualAlpha())
450  )*fluid_.mesh().magSf()
451  );
452 
453  addField(interface.phase1(), "F", Df*snGradAlpha1By12, Ffs);
454  addField(interface.phase2(), "F", Df*snGradAlpha2By12, Ffs);
455  }
456 
457  return Ffs;
458 }
459 
460 
461 void Foam::momentumTransferSystem::invADVs
462 (
464 ) const
465 {
466  const label n = ADVs.size();
467 
468  scalarSquareMatrix AD(n);
469  scalarField source(n);
470  labelList pivotIndices(n);
471 
472  forAll(ADVs[0][0], ci)
473  {
474  for (label i=0; i<n; i++)
475  {
476  for (label j=0; j<n; j++)
477  {
478  AD(i, j) = ADVs[i][j][ci];
479  }
480  }
481 
482  // Calculate the inverse of AD using LD decomposition
483  // and back-substitution
484  LUDecompose(AD, pivotIndices);
485 
486  for (label j=0; j<n; j++)
487  {
488  source = Zero;
489  source[j] = 1;
490 
491  LUBacksubstitute(AD, pivotIndices, source);
492 
493  for (label i=0; i<n; i++)
494  {
495  ADVs[i][j][ci] = source[i];
496  }
497  }
498  }
499 }
500 
501 
502 template<class GeoMesh>
503 void Foam::momentumTransferSystem::invADVs
504 (
505  PtrList<PtrList<GeometricField<scalar, GeoMesh>>>& ADVs
506 ) const
507 {
508  const label n = ADVs.size();
509 
511 
512  for (label i=0; i<n; i++)
513  {
514  ADps[i].setSize(n);
515 
516  for (label j=0; j<n; j++)
517  {
518  ADps[i].set(j, &ADVs[i][j]);
519 
520  ADVs[i][j].dimensions().reset(dimless/ADVs[i][j].dimensions());
521  }
522  }
523 
524  invADVs(ADps);
525 
526  forAll(ADVs[0][0].boundaryField(), patchi)
527  {
528  for (label i=0; i<n; i++)
529  {
530  for (label j=0; j<n; j++)
531  {
532  ADps[i].set(j, &ADVs[i][j].boundaryFieldRef()[patchi]);
533  }
534  }
535 
536  invADVs(ADps);
537  }
538 }
539 
540 
541 void Foam::momentumTransferSystem::invADVs
542 (
543  const PtrList<volScalarField>& As,
547 ) const
548 {
549  const label n = As.size();
550 
551  invADVs.setSize(n);
552  invADVfs.setSize(n);
553 
554  forAll(invADVs, i)
555  {
556  invADVs.set(i, new PtrList<volScalarField>(n));
557  invADVs[i].set(i, As[i].clone());
558 
559  invADVfs.set(i, new PtrList<surfaceScalarField>(n));
560  invADVfs[i].set(i, fvc::interpolate(As[i]));
561  }
562 
563  labelList movingPhases(fluid_.phases().size(), -1);
564  forAll(fluid_.movingPhases(), movingPhasei)
565  {
566  movingPhases[fluid_.movingPhases()[movingPhasei].index()] =
567  movingPhasei;
568  }
569 
570  Kds_.clear();
571 
572  // Update the drag coefficients
574  (
576  dragModels_,
577  dragModelIter
578  )
579  {
580  const phaseInterface& interface = dragModelIter()->interface();
581 
582  tmp<volScalarField> tKd(dragModelIter()->K());
583  volScalarField& Kd = tKd.ref();
584  Kds_.insert(dragModelIter.key(), tKd.ptr());
585 
586  // Zero-gradient the drag coefficient to boundaries with fixed velocity
588  {
589  if
590  (
591  (
592  !interface.phase1().stationary()
593  && interface.phase1().U()()
594  .boundaryField()[patchi].fixesValue()
595  )
596  && (
597  !interface.phase2().stationary()
598  && interface.phase2().U()()
599  .boundaryField()[patchi].fixesValue()
600  )
601  )
602  {
603  Kd.boundaryFieldRef()[patchi] =
604  Kd.boundaryField()[patchi].patchInternalField();
605  }
606  }
607 
608  forAllConstIter(phaseInterface, interface, iter)
609  {
610  const phaseModel& phase = iter();
611  const phaseModel& otherPhase = iter.otherPhase();
612 
613  const label i = movingPhases[phase.index()];
614 
615  if (i != -1)
616  {
617  const volScalarField Kdij
618  (
619  (otherPhase/max(otherPhase, otherPhase.residualAlpha()))*Kd
620  );
621 
622  const surfaceScalarField Kdijf(fvc::interpolate(Kdij));
623 
624  invADVs[i][i] += Kdij;
625  invADVfs[i][i] += Kdijf;
626 
627  const label j = movingPhases[otherPhase.index()];
628 
629  if (j != -1)
630  {
631  invADVs[i].set(j, -Kdij);
632  invADVfs[i].set(j, -Kdijf);
633  }
634  }
635  }
636  }
637 
638  // Clear the Kds_ if they are not needed for the optional dragCorrection
639  const pimpleNoLoopControl& pimple = fluid_.pimple();
640  if (!pimple.dict().lookupOrDefault<Switch>("dragCorrection", false))
641  {
642  Kds_.clear();
643  }
644 
645  for (label i=0; i<n; i++)
646  {
647  for (label j=0; j<n; j++)
648  {
649  if (!invADVs[i].set(j))
650  {
651  invADVs[i].set
652  (
653  j,
655  (
656  "0",
657  fluid_.mesh(),
658  dimensionedScalar(As[0].dimensions(), 0)
659  )
660  );
661 
662  invADVfs[i].set
663  (
664  j,
666  (
667  "0",
668  fluid_.mesh(),
669  dimensionedScalar(As[0].dimensions(), 0)
670  )
671  );
672  }
673  }
674  }
675 
676  // Cache the phase acceleration As and Hs
677  PtrList<volScalarField> ADUDts(movingPhases.size());
678  PtrList<volVectorField> HDUDts(movingPhases.size());
679 
681  (
683  virtualMassModels_,
684  VmIter
685  )
686  {
687  const phaseInterface& interface = VmIter()->interface();
688 
689  forAllConstIter(phaseInterface, interface, iter)
690  {
691  const phaseModel& phase = iter();
692  const label i = movingPhases[phase.index()];
693 
694  if (i != -1 && !ADUDts.set(i))
695  {
696  const fvVectorMatrix DUDt(phase.DUDt());
697  ADUDts.set(i, DUDt.A());
698  HDUDts.set(i, DUDt.H());
699  }
700  }
701  }
702 
703  // Add the virtual mass contributions
705  (
707  virtualMassModels_,
708  VmIter
709  )
710  {
711  const phaseInterface& interface = VmIter()->interface();
712  const volScalarField Vm(VmIter()->K());
713 
714  forAllConstIter(phaseInterface, interface, iter)
715  {
716  const phaseModel& phase = iter();
717  const phaseModel& otherPhase = iter.otherPhase();
718 
719  const label i = movingPhases[phase.index()];
720 
721  if (i != -1)
722  {
723  const volScalarField VmPhase
724  (
725  (otherPhase/max(otherPhase, otherPhase.residualAlpha()))*Vm
726  );
727 
728  {
729  const volScalarField AVm(VmPhase*ADUDts[i]);
730 
731  invADVs[i][i] += AVm;
732  invADVfs[i][i] += fvc::interpolate(AVm);
733 
734  addField
735  (
736  i,
737  IOobject::groupName("HVm", phase.name()),
738  VmPhase*HDUDts[i],
739  HVms
740  );
741  }
742 
743  const label j = movingPhases[otherPhase.index()];
744 
745  if (j != -1)
746  {
747  const volScalarField AVm(VmPhase*ADUDts[j]);
748 
749  invADVs[i][j] -= AVm;
750  invADVfs[i][j] -= fvc::interpolate(AVm);
751 
752  addField
753  (
754  i,
755  IOobject::groupName("HVm", phase.name()),
756  -VmPhase*HDUDts[j],
757  HVms
758  );
759  }
760  }
761  }
762  }
763 
764  momentumTransferSystem::invADVs(invADVs);
765  momentumTransferSystem::invADVs(invADVfs);
766 }
767 
768 
771 (
772  const PtrList<surfaceScalarField>& Afs,
774 ) const
775 {
776  const label n = Afs.size();
777 
779 
780  forAll(invADVfs, i)
781  {
782  invADVfs.set(i, new PtrList<surfaceScalarField>(n));
783  invADVfs[i].set(i, Afs[i].clone());
784  }
785 
786  labelList movingPhases(fluid_.phases().size(), -1);
787  forAll(fluid_.movingPhases(), movingPhasei)
788  {
789  movingPhases[fluid_.movingPhases()[movingPhasei].index()] =
790  movingPhasei;
791  }
792 
794  (
796  dragModels_,
797  dragModelIter
798  )
799  {
800  const phaseInterface& interface = dragModelIter()->interface();
801  const surfaceScalarField Kdf(dragModelIter()->Kf());
802 
803  forAllConstIter(phaseInterface, interface, iter)
804  {
805  const phaseModel& phase = iter();
806  const phaseModel& otherPhase = iter.otherPhase();
807 
808  const label i = movingPhases[phase.index()];
809 
810  if (i != -1)
811  {
812  const surfaceScalarField alphaf
813  (
814  fvc::interpolate(otherPhase)
815  );
816 
817  const surfaceScalarField Kdfij
818  (
819  (alphaf/max(alphaf, otherPhase.residualAlpha()))*Kdf
820  );
821 
822  invADVfs[i][i] += Kdfij;
823 
824  const label j = movingPhases[otherPhase.index()];
825 
826  if (j != -1)
827  {
828  invADVfs[i].set(j, -Kdfij);
829  }
830  }
831  }
832  }
833 
834  for (label i=0; i<n; i++)
835  {
836  for (label j=0; j<n; j++)
837  {
838  if (!invADVfs[i].set(j))
839  {
840  invADVfs[i].set
841  (
842  j,
844  (
845  "0",
846  fluid_.mesh(),
847  dimensionedScalar(Afs[0].dimensions(), 0)
848  )
849  );
850  }
851  }
852  }
853 
854  // Cache the phase acceleration Afs and Hs
855  PtrList<volScalarField> AUgradUs(movingPhases.size());
856  PtrList<volVectorField> HUgradUs(movingPhases.size());
857 
859  (
861  virtualMassModels_,
862  VmIter
863  )
864  {
865  const phaseInterface& interface = VmIter()->interface();
866 
867  forAllConstIter(phaseInterface, interface, iter)
868  {
869  const phaseModel& phase = iter();
870  const label i = movingPhases[phase.index()];
871 
872  if (i != -1 && !AUgradUs.set(i))
873  {
874  const fvVectorMatrix UgradU(phase.UgradU());
875  AUgradUs.set(i, UgradU.A());
876  HUgradUs.set(i, UgradU.H());
877  }
878  }
879  }
880 
881  // Add the virtual mass contributions
883  (
885  virtualMassModels_,
886  VmIter
887  )
888  {
889  const phaseInterface& interface = VmIter()->interface();
890  const volScalarField Vm(VmIter()->K());
891 
892  forAllConstIter(phaseInterface, interface, iter)
893  {
894  const phaseModel& phase = iter();
895  const phaseModel& otherPhase = iter.otherPhase();
896 
897  const label i = movingPhases[phase.index()];
898 
899  if (i != -1)
900  {
901  const volScalarField VmPhase
902  (
903  (otherPhase/max(otherPhase, otherPhase.residualAlpha()))
904  *Vm
905  );
906 
907  const surfaceScalarField VmPhasef(fvc::interpolate(VmPhase));
908 
909  invADVfs[i][i] +=
910  byDt(VmPhasef) + fvc::interpolate(VmPhase*AUgradUs[i]);
911 
912  addField
913  (
914  i,
915  IOobject::groupName("HVmf", phase.name()),
916  VmPhasef
917  *byDt
918  (
920  (
921  fluid_.MRF().absolute
922  (
923  phase.phi()().oldTime()
924  ),
925  phase.U()
926  )
927  )
928  + fvc::flux(VmPhase*HUgradUs[i]),
929  HVmfs
930  );
931 
932  const label j = movingPhases[otherPhase.index()];
933 
934  if (j != -1)
935  {
936  invADVfs[i][j] -=
937  byDt(VmPhasef) + fvc::interpolate(VmPhase*AUgradUs[j]);
938 
939  addField
940  (
941  i,
942  IOobject::groupName("HVmf", phase.name()),
943  -VmPhasef
944  *byDt
945  (
947  (
948  fluid_.MRF().absolute
949  (
950  otherPhase.phi()().oldTime()
951  ),
952  otherPhase.U()
953  )
954  )
955  - fvc::flux(VmPhase*HUgradUs[j]),
956  HVmfs
957  );
958  }
959  }
960  }
961  }
962 
963  invADVs(invADVfs);
964 
965  return invADVfs;
966 }
967 
968 
971 (
972  const PtrList<volScalarField>& rAs
973 ) const
974 {
975  tmp<surfaceScalarField> alphaDByAf;
976 
977  // Add the phase pressure
978  forAll(fluid_.movingPhases(), movingPhasei)
979  {
980  const phaseModel& phase = fluid_.movingPhases()[movingPhasei];
981 
982  addTmpField
983  (
984  alphaDByAf,
985  fvc::interpolate(max(phase, scalar(0)))
986  *fvc::interpolate(rAs[phase.index()])
987  *phase.pPrimef()
988  );
989  }
990 
991  // Add the turbulent dispersion
993  (
995  turbulentDispersionModels_,
996  turbulentDispersionModelIter
997  )
998  {
999  const phaseInterface& interface =
1000  turbulentDispersionModelIter()->interface();
1001 
1002  const surfaceScalarField alpha1f
1003  (
1004  fvc::interpolate(max(interface.phase1(), scalar(0)))
1005  );
1006 
1007  const surfaceScalarField alpha2f
1008  (
1009  fvc::interpolate(max(interface.phase2(), scalar(0)))
1010  );
1011 
1012  addTmpField
1013  (
1014  alphaDByAf,
1015  alpha1f*alpha2f
1016  /max(alpha1f + alpha2f, interface.phase1().residualAlpha())
1018  (
1019  max
1020  (
1021  rAs[interface.phase1().index()],
1022  rAs[interface.phase2().index()]
1023  )
1024  *turbulentDispersionModelIter()->D()
1025  )
1026  );
1027  }
1028 
1029  return alphaDByAf;
1030 }
1031 
1032 
1035 {
1036  PtrList<surfaceScalarField> ddtCorrs(fluid_.phases().size());
1037 
1038  // Add correction
1039  forAll(fluid_.movingPhases(), movingPhasei)
1040  {
1041  const phaseModel& phase = fluid_.movingPhases()[movingPhasei];
1042 
1043  addField
1044  (
1045  phase,
1046  "ddtCorr",
1047  fvc::ddtCorr
1048  (
1049  phase,
1050  phase.rho(),
1051  phase.U()(),
1052  phase.phi()(),
1053  phase.Uf()
1054  ),
1055  ddtCorrs
1056  );
1057  }
1058 
1059 
1060  const pimpleNoLoopControl& pimple = fluid_.pimple();
1061  const Switch VmDdtCorr
1062  (
1063  pimple.dict().lookupOrDefault<Switch>("VmDdtCorrection", false)
1064  );
1065 
1066  // Optionally ddd virtual mass correction
1067  if (VmDdtCorr)
1068  {
1069  PtrList<volScalarField> VmDdtCoeffs(fluid_.phases().size());
1070  PtrList<surfaceScalarField> VmDdtCorrs(fluid_.phases().size());
1071 
1072  forAll(fluid_.movingPhases(), movingPhasei)
1073  {
1074  const phaseModel& phase = fluid_.movingPhases()[movingPhasei];
1075  const label phasei = phase.index();
1076 
1077  VmDdtCorrs.set
1078  (
1079  phasei,
1080  fvc::ddtCorr
1081  (
1082  phase.U()(),
1083  phase.phi()(),
1084  phase.Uf()
1085  )
1086  );
1087  }
1088 
1090  (
1092  virtualMassModels_,
1093  VmIter
1094  )
1095  {
1096  const phaseInterface& interface = VmIter()->interface();
1097  const volScalarField Vm(VmIter()->K());
1098 
1099  forAllConstIter(phaseInterface, interface, iter)
1100  {
1101  const phaseModel& phase = iter();
1102  const label phasei = phase.index();
1103  const phaseModel& otherPhase = iter.otherPhase();
1104  const label otherPhasei = otherPhase.index();
1105 
1106  const volScalarField VmPhase
1107  (
1108  (otherPhase/max(otherPhase, otherPhase.residualAlpha()))
1109  *Vm
1110  );
1111 
1112  addField
1113  (
1114  phase,
1115  "ddtCorr",
1116  fvc::interpolate(VmPhase)
1117  *(VmDdtCorrs[phasei] - VmDdtCorrs[otherPhasei]),
1118  ddtCorrs
1119  );
1120  }
1121  }
1122  }
1123 
1124  return ddtCorrs;
1125 }
1126 
1127 
1129 (
1130  PtrList<volVectorField>& dragCorrs,
1131  PtrList<surfaceScalarField>& dragCorrfs
1132 ) const
1133 {
1134  labelList movingPhases(fluid_.phases().size(), -1);
1135  forAll(fluid_.movingPhases(), movingPhasei)
1136  {
1137  movingPhases[fluid_.movingPhases()[movingPhasei].index()] =
1138  movingPhasei;
1139  }
1140 
1141  PtrList<volVectorField> Uphis(fluid_.movingPhases().size());
1142  forAll(fluid_.movingPhases(), movingPhasei)
1143  {
1144  Uphis.set
1145  (
1146  movingPhasei,
1147  fvc::reconstruct(fluid_.movingPhases()[movingPhasei].phi())
1148  );
1149  }
1150 
1151  forAllConstIter(KdTable, Kds_, KdIter)
1152  {
1153  const volScalarField& K(*KdIter());
1154  const phaseInterface interface(fluid_, KdIter.key());
1155 
1156  forAllConstIter(phaseInterface, interface, iter)
1157  {
1158  const phaseModel& phase = iter();
1159  const phaseModel& otherPhase = iter.otherPhase();
1160 
1161  const label i = movingPhases[phase.index()];
1162  const label j = movingPhases[otherPhase.index()];
1163 
1164  if (i != -1)
1165  {
1166  const volScalarField K1
1167  (
1168  (otherPhase/max(otherPhase, otherPhase.residualAlpha()))*K
1169  );
1170 
1171  addField
1172  (
1173  i,
1174  IOobject::groupName("dragCorr", phase.name()),
1175  K1*(j == -1 ? -Uphis[i] : (Uphis[j] - Uphis[i])),
1176  dragCorrs
1177  );
1178 
1179  addField
1180  (
1181  i,
1182  IOobject::groupName("dragCorrf", phase.name()),
1184  *(j == -1 ? -phase.phi() : (otherPhase.phi() - phase.phi())),
1185  dragCorrfs
1186  );
1187  }
1188  }
1189  }
1190 }
1191 
1192 
1194 {
1195  if (regIOobject::read())
1196  {
1197  Kds_.clear();
1198 
1199  readModels();
1200 
1201  return true;
1202  }
1203  else
1204  {
1205  return false;
1206  }
1207 }
1208 
1209 
1210 // ************************************************************************* //
#define K1
Definition: SHA1.C:167
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:492
Generic GeometricField class.
const Boundary & boundaryField() const
Return const-reference to the boundary field.
Boundary & boundaryFieldRef()
Return a reference to the boundary field.
static tmp< GeometricField< Type, GeoMesh, PrimitiveField > > New(const word &name, const Internal &, const PtrList< Patch > &, const HashPtrTable< Source > &=HashPtrTable< Source >())
Return a temporary field constructed from name,.
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:57
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
@ MUST_READ_IF_MODIFIED
Definition: IOobject.H:119
fileName relativeObjectPath() const
Return complete relativePath + object name.
Definition: IOobject.H:420
static word groupName(Name name, const word &group)
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:125
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: PtrList.H:75
bool set(const label) const
Is element set.
Definition: PtrListI.H:62
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:61
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: UPtrList.H:66
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
T lookupOrDefault(const word &, const T &) const
Find and return a T, if not found return the given default.
A special matrix type and solver, designed for finite volume solutions of scalar equations....
Definition: fvMatrix.H:118
tmp< volScalarField > A() const
Return the central coefficient.
Definition: fvMatrix.C:807
tmp< VolField< Type > > H() const
Return the H operation source.
Definition: fvMatrix.C:867
Class which provides interfacial momentum transfer between a number of phases. Drag,...
static const word propertiesName
Default name of the phase properties dictionary.
void dragCorrs(PtrList< volVectorField > &dragCorrs, PtrList< surfaceScalarField > &dragCorrf) const
Set the cell and faces drag correction fields.
PtrList< surfaceScalarField > ddtCorrs() const
Return the flux corrections for the cell-based algorithm. These.
momentumTransferSystem(const phaseSystem &)
Construct from a phase system.
PtrList< surfaceScalarField > Ffs() const
As Fs, but for the face-based algorithm.
PtrList< surfaceScalarField > Fs() const
Return the explicit force fluxes for the cell-based algorithm, that.
virtual ~momentumTransferSystem()
Destructor.
PtrList< PtrList< surfaceScalarField > > invADVfs(const PtrList< surfaceScalarField > &Afs, PtrList< surfaceScalarField > &HVmfs) const
Return the inverse of the central + drag + virtual mass.
virtual tmp< surfaceScalarField > alphaDByAf(const PtrList< volScalarField > &rAs) const
Return the phase diffusivity.
virtual bool read()
Read base phaseProperties dictionary.
Class to represent an interface between phases. Derivations can further specify the configuration of ...
virtual const autoPtr< surfaceVectorField > & Uf() const =0
Return the face velocity.
const dimensionedScalar & residualAlpha() const
Return the residual phase-fraction for given phase.
Definition: phaseModel.C:116
virtual tmp< fvVectorMatrix > DUDt() const =0
Return the substantive acceleration matrix.
virtual tmp< surfaceScalarField > phi() const =0
Return the volumetric flux.
label index() const
Return the index of the phase.
Definition: phaseModel.C:104
virtual tmp< volVectorField > U() const =0
Return the velocity.
virtual tmp< fvVectorMatrix > UgradU() const =0
Return the velocity transport matrix.
const word & name() const
Return the name of this phase.
Definition: phaseModel.C:92
virtual tmp< surfaceScalarField > pPrimef() const =0
Return the face-phase-pressure'.
virtual const volScalarField & rho() const =0
Return the density field.
Class to represent a system of phases.
Definition: phaseSystem.H:74
Pimple no-loop control class. Implements various option flags, but leaves loop controls to the deriva...
static const dictionary & dict(const fvMesh &mesh, const word &algorithmName="PIMPLE")
Return the solution dictionary.
Motion of the mesh specified as a list of pointMeshMovers.
Enables the printing of a dictionary and subsequently looked-up defaulted entries.
virtual bool read()
Read object.
A class for managing temporary objects.
Definition: tmp.H:55
Template function which returns the un-mangled name of a given type. Useful for types which do not ha...
A class for handling words, derived from string.
Definition: word.H:63
pimpleControl pimple(mesh)
Calculate the first temporal derivative.
Calculate the divergence of the given field.
Calculate the face-flux of the given field.
Calculate the mesh motion flux and convert fluxes from absolute to relative and back.
Reconstruct volField from a face flux field.
Calculate the snGrad of the given volField.
Calculate the matrix for the first temporal derivative.
Calculate the matrix for the divergence of the given field and flux.
Calculate the matrix for implicit and explicit sources.
label patchi
K
Definition: pEqn.H:75
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar F
Faraday constant: default SI units: [C/mol].
tmp< SurfaceField< typename innerProduct< vector, Type >::type > > flux(const VolField< Type > &vf)
Return the face-flux field obtained from the given volVectorField.
static tmp< SurfaceField< Type > > interpolate(const VolField< Type > &tvf, const surfaceScalarField &faceFlux, Istream &schemeData)
Interpolate field onto faces using scheme given by Istream.
tmp< VolField< typename outerProduct< vector, Type >::type > > reconstruct(const SurfaceField< Type > &ssf)
tmp< surfaceScalarField > absolute(const tmp< surfaceScalarField > &tphi, const volVectorField &U)
Return the given relative flux in absolute form.
Definition: fvcMeshPhi.C:202
tmp< SurfaceField< Type > > snGrad(const VolField< Type > &vf, const word &name)
Definition: fvcSnGrad.C:45
tmp< SurfaceField< typename Foam::flux< Type >::type > > ddtCorr(const VolField< Type > &U, const SurfaceField< Type > &Uf)
Definition: fvcDdt.C:196
static const coefficient D("D", dimTemperature, 257.14)
Namespace for OpenFOAM.
static const zero Zero
Definition: zero.H:97
List< word > wordList
A List of words.
Definition: fileName.H:54
const dimensionSet & dimless
Definition: dimensions.C:138
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
void addField(const label phasei, const word &name, tmp< GeoField > field, PtrList< GeoField > &fieldList)
Definition: phaseSystemI.H:265
void LUBacksubstitute(const scalarSquareMatrix &luMmatrix, const labelList &pivotIndices, List< Type > &source)
LU back-substitution with given source, returning the solution.
void LUDecompose(scalarSquareMatrix &matrix, labelList &pivotIndices)
LU decompose the matrix with pivoting.
tmp< volScalarField > byDt(const volScalarField &vf)
Definition: phaseSystem.C:945
messageStream Info
T clone(const T &t)
Definition: List.H:55
Ostream & indentOrNl(Ostream &os)
Indent stream or add newline if indent level == 0.
Definition: Ostream.H:250
defineTypeNameAndDebug(atmosphericBoundaryLayer, 0)
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)