cellPressureCorrector.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) 2022-2025 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 "multiphaseEuler.H"
27 #include "constrainHbyA.H"
28 #include "constrainPressure.H"
29 #include "findRefCell.H"
30 #include "fvcDdt.H"
31 #include "fvcDiv.H"
32 #include "fvcSup.H"
33 #include "fvcSnGrad.H"
34 #include "fvmDdt.H"
35 #include "fvmDiv.H"
36 #include "fvmLaplacian.H"
37 #include "fvmSup.H"
38 #include "fvcFlux.H"
39 #include "fvcMeshPhi.H"
40 #include "fvcReconstruct.H"
41 
42 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
43 
44 void Foam::solvers::multiphaseEuler::cellPressureCorrector()
45 {
48 
49  volScalarField rho("rho", fluid.rho());
50 
51  // Correct p_rgh for consistency with the current density
53 
54  // Face volume fractions
55  PtrList<surfaceScalarField> alphafs(phases.size());
56  forAll(phases, phasei)
57  {
58  const phaseModel& phase = phases[phasei];
59  const volScalarField& alpha = phase;
60 
61  alphafs.set(phasei, fvc::interpolate(max(alpha, scalar(0))).ptr());
62  alphafs[phasei].rename("pEqn" + alphafs[phasei].name());
63  }
64 
65  // Diagonal coefficients
66  rAs.clear();
68  {
69  rAs.setSize(phases.size());
70  }
71 
72  PtrList<volVectorField> HVms(movingPhases.size());
73  PtrList<PtrList<volScalarField>> invADVs;
74  PtrList<PtrList<surfaceScalarField>> invADVfs;
75  {
76  PtrList<volScalarField> As(movingPhases.size());
77  forAll(movingPhases, movingPhasei)
78  {
79  const phaseModel& phase = movingPhases[movingPhasei];
80  const volScalarField& alpha = phase;
81 
82  As.set
83  (
84  movingPhasei,
85  UEqns[phase.index()].A()
86  + byDt
87  (
88  max(phase.residualAlpha() - alpha, scalar(0))
89  *phase.rho()
90  )
91  );
92 
94  {
95  rAs.set
96  (
97  phase.index(),
98  new volScalarField
99  (
100  IOobject::groupName("rA", phase.name()),
101  1/As[movingPhasei]
102  )
103  );
104  }
105  }
106 
107  momentumTransferSystem_.invADVs(As, HVms, invADVs, invADVfs);
108  }
109 
110  // Explicit force fluxes
111  PtrList<surfaceScalarField> alphaByADfs;
112  PtrList<surfaceScalarField> FgByADfs;
113  {
114  PtrList<surfaceScalarField> Ffs(momentumTransferSystem_.Fs());
115 
116  const surfaceScalarField ghSnGradRho
117  (
118  "ghSnGradRho",
120  );
121 
122  UPtrList<surfaceScalarField> movingAlphafs(movingPhases.size());
123  PtrList<surfaceScalarField> Fgfs(movingPhases.size());
124 
125  forAll(movingPhases, movingPhasei)
126  {
127  const phaseModel& phase = movingPhases[movingPhasei];
128 
129  movingAlphafs.set(movingPhasei, &alphafs[phase.index()]);
130 
131  Fgfs.set
132  (
133  movingPhasei,
134  Ffs[phase.index()]
135  + alphafs[phase.index()]
136  *(
137  ghSnGradRho
138  - fluid.surfaceTension(phase)*mesh.magSf()
139  )
140  - fvc::interpolate(max(phase, phase.residualAlpha()))
141  *fvc::interpolate(phase.rho() - rho)*(buoyancy.g & mesh.Sf())
142  );
143  }
144 
145  alphaByADfs = invADVfs & movingAlphafs;
146  FgByADfs = invADVfs & Fgfs;
147  }
148 
149  // Mass transfer rates
150  PtrList<volScalarField::Internal> dmdts(populationBalanceSystem_.dmdts());
151 
152  // --- Optional momentum predictor
153  if (predictMomentum)
154  {
155  PtrList<volVectorField> HbyADs;
156  {
157  PtrList<volVectorField> Hs(movingPhases.size());
158 
159  forAll(movingPhases, movingPhasei)
160  {
161  const phaseModel& phase = movingPhases[movingPhasei];
162  const volScalarField& alpha = phase;
163 
164  Hs.set
165  (
166  movingPhasei,
167  UEqns[phase.index()].H()
168  + byDt
169  (
170  max(phase.residualAlpha() - alpha, scalar(0))
171  *phase.rho()
172  )
173  *phase.U()().oldTime()
174  );
175 
176  if (HVms.set(movingPhasei))
177  {
178  Hs[movingPhasei] += HVms[movingPhasei];
179  }
180  }
181 
182  HbyADs = invADVs & Hs;
183  }
184 
185  forAll(movingPhases, movingPhasei)
186  {
187  const phaseModel& phase = movingPhases[movingPhasei];
188  constrainHbyA(HbyADs[movingPhasei], phase.U(), p_rgh);
189  }
190 
191  const surfaceScalarField mSfGradp(-mesh.magSf()*fvc::snGrad(p_rgh));
192 
193  forAll(movingPhases, movingPhasei)
194  {
195  phaseModel& phase = movingPhases_[movingPhasei];
196 
197  phase.URef() =
198  HbyADs[movingPhasei]
200  (
201  alphaByADfs[movingPhasei]*mSfGradp
202  - FgByADfs[movingPhasei]
203  );
204 
205  phase.URef().correctBoundaryConditions();
206  fvConstraints().constrain(phase.URef());
207  }
208  }
209 
210  // --- Pressure corrector loop
211  while (pimple.correct())
212  {
213  // Correct fixed-flux BCs to be consistent with the velocity BCs
215 
216  PtrList<volVectorField> HbyADs;
217  PtrList<surfaceScalarField> phiHbyADs;
218  {
219  // Predicted velocities and fluxes for each phase
220  PtrList<volVectorField> Hs(movingPhases.size());
221  PtrList<surfaceScalarField> phiHs(movingPhases.size());
222 
223  // Correction force fluxes
224  PtrList<surfaceScalarField> ddtCorrs
225  (
227  );
228 
229  forAll(movingPhases, movingPhasei)
230  {
231  const phaseModel& phase = movingPhases[movingPhasei];
232  const volScalarField& alpha = phase;
233 
234  Hs.set
235  (
236  movingPhasei,
237  UEqns[phase.index()].H()
238  + byDt
239  (
240  max(phase.residualAlpha() - alpha, scalar(0))
241  *phase.rho()
242  )
243  *phase.U()().oldTime()
244  );
245 
246  if (HVms.set(movingPhasei))
247  {
248  Hs[movingPhasei] += HVms[movingPhasei];
249  }
250 
251  phiHs.set
252  (
253  movingPhasei,
254  fvc::flux(Hs[movingPhasei]) + ddtCorrs[phase.index()]
255  );
256  }
257 
258  HbyADs = invADVs & Hs;
259  phiHbyADs = invADVfs & phiHs;
260  }
261 
262  forAll(movingPhases, movingPhasei)
263  {
264  const phaseModel& phase = movingPhases[movingPhasei];
265 
266  constrainHbyA(HbyADs[movingPhasei], phase.U(), p_rgh);
267  constrainPhiHbyA(phiHbyADs[movingPhasei], phase.U(), p_rgh);
268 
269  phiHbyADs[movingPhasei] -= FgByADfs[movingPhasei];
270  }
271 
272  // Total predicted flux
274  (
275  IOobject
276  (
277  "phiHbyA",
278  runTime.name(),
279  mesh
280  ),
281  mesh,
283  );
284 
285  forAll(movingPhases, movingPhasei)
286  {
287  const phaseModel& phase = movingPhases[movingPhasei];
288 
289  phiHbyA += alphafs[phase.index()]*phiHbyADs[movingPhasei];
290  }
291 
294 
295  // Pressure "diffusivity"
297  (
298  IOobject
299  (
300  "rAf",
301  runTime.name(),
302  mesh
303  ),
304  mesh,
306  );
307 
308  forAll(movingPhases, movingPhasei)
309  {
310  const phaseModel& phase = movingPhases[movingPhasei];
311 
312  rAf += alphafs[phase.index()]*alphaByADfs[movingPhasei];
313  }
314 
315  // Update the fixedFluxPressure BCs to ensure flux consistency
316  {
318  (
321  );
322  phib = 0;
323 
324  forAll(movingPhases, movingPhasei)
325  {
326  phaseModel& phase = movingPhases_[movingPhasei];
327 
328  phib +=
329  alphafs[phase.index()].boundaryField()
330  *phase.phi()().boundaryField();
331  }
332 
333  setSnGrad<fixedFluxPressureFvPatchScalarField>
334  (
336  (
337  phiHbyA.boundaryField() - phib
338  )/(mesh.magSf().boundaryField()*rAf.boundaryField())
339  );
340  }
341 
342  // Compressible pressure equations
343  PtrList<fvScalarMatrix> pEqnComps(compressibilityEqns(dmdts));
344 
345  // Cache p prior to solve for density update
346  volScalarField p_rgh_0(p_rgh);
347 
348  // Iterate over the pressure equation to correct for non-orthogonality
349  while (pimple.correctNonOrthogonal())
350  {
351  // Construct the transport part of the pressure equation
352  fvScalarMatrix pEqnIncomp
353  (
355  - fvm::laplacian(rAf, p_rgh)
356  );
357 
358  // Solve
359  {
360  fvScalarMatrix pEqn(pEqnIncomp);
361 
362  forAll(phases, phasei)
363  {
364  pEqn += pEqnComps[phasei];
365  }
366 
367  if (fluid.incompressible())
368  {
369  pEqn.setReference
370  (
373  );
374  }
375 
376  fvConstraints().constrain(pEqn);
377 
378  pEqn.solve();
379  }
380 
381  // Correct fluxes and velocities on last non-orthogonal iteration
383  {
384  phi_ = phiHbyA + pEqnIncomp.flux();
385 
386  surfaceScalarField mSfGradp("mSfGradp", pEqnIncomp.flux()/rAf);
387 
388  forAll(movingPhases, movingPhasei)
389  {
390  phaseModel& phase = movingPhases_[movingPhasei];
391 
392  phase.phiRef() =
393  phiHbyADs[movingPhasei]
394  + alphaByADfs[movingPhasei]*mSfGradp;
395 
396  // Set the phase dilatation rate
397  phase.divU(-pEqnComps[phase.index()] & p_rgh);
398 
399  MRF.makeRelative(phase.phiRef());
400  fvc::makeRelative(phase.phiRef(), phase.U());
401  }
402 
403  // Optionally relax pressure for velocity correction
404  p_rgh.relax();
405 
406  mSfGradp = pEqnIncomp.flux()/rAf;
407 
408  if (dragCorrection)
409  {
410  PtrList<volVectorField> dragCorrs(movingPhases.size());
411  PtrList<surfaceScalarField> dragCorrfs(movingPhases.size());
412  momentumTransferSystem_.dragCorrs(dragCorrs, dragCorrfs);
413 
414  PtrList<volVectorField> dragCorrByADs
415  (
416  invADVs & dragCorrs
417  );
418 
419  PtrList<surfaceScalarField> dragCorrByADfs
420  (
421  invADVfs & dragCorrfs
422  );
423 
424  forAll(movingPhases, movingPhasei)
425  {
426  phaseModel& phase = movingPhases_[movingPhasei];
427 
428  phase.URef() =
429  HbyADs[movingPhasei]
431  (
432  alphaByADfs[movingPhasei]*mSfGradp
433  - FgByADfs[movingPhasei]
434  + dragCorrByADfs[movingPhasei]
435  )
436  - dragCorrByADs[movingPhasei];
437  }
438  }
439  else
440  {
441  forAll(movingPhases, movingPhasei)
442  {
443  phaseModel& phase = movingPhases_[movingPhasei];
444 
445  phase.URef() =
446  HbyADs[movingPhasei]
448  (
449  alphaByADfs[movingPhasei]*mSfGradp
450  - FgByADfs[movingPhasei]
451  );
452  }
453  }
454 
455  forAll(movingPhases, movingPhasei)
456  {
457  phaseModel& phase = movingPhases_[movingPhasei];
458 
459  phase.URef().correctBoundaryConditions();
460  phase.correctUf();
461  fvConstraints().constrain(phase.URef());
462  }
463  }
464  }
465 
466  // Update and limit the static pressure
469 
470  // Account for static pressure reference
472  {
474  (
475  "p",
476  p.dimensions(),
479  );
480  }
481 
482  // Limit p_rgh
484 
485  // Update densities from change in p_rgh
486  forAll(phases, phasei)
487  {
488  phaseModel& phase = phases_[phasei];
489  if (!phase.incompressible())
490  {
491  phase.rho() += phase.fluidThermo().psi()*(p_rgh - p_rgh_0);
492  }
493  }
494 
495  // Correct p_rgh for consistency with p and the updated densities
496  rho = fluid.rho();
498  }
499 
500  UEqns.clear();
501 }
502 
503 
504 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
static const DimensionedField< Type, GeoMesh, PrimitiveField > & null()
Return a null DimensionedField.
const dimensionSet & dimensions() const
Return dimensions.
void relax(const scalar alpha)
Relax field (for steady-state solution).
const Boundary & boundaryField() const
Return const-reference to the boundary field.
bool needReference() const
Does the field need a reference level for solution.
GeometricBoundaryField< Type, GeoMesh, PrimitiveField > Boundary
Type of the boundary field.
Boundary & boundaryFieldRef()
Return a reference to the boundary field.
IOobject(const word &name, const fileName &instance, const objectRegistry &registry, readOption r=NO_READ, writeOption w=NO_WRITE, bool registerObject=true)
Construct from name, instance, registry, io options.
Definition: IOobject.C:164
const word & name() const
Return name.
Definition: IOobject.H:307
static word groupName(Name name, const word &group)
void makeRelative(volVectorField &U) const
Make the given absolute velocity relative within the MRF region.
Definition: MRFZoneList.C:157
bool set(const label) const
Is element set.
Definition: UPtrListI.H:87
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
const word & name() const
Return const reference to name.
bool constrain(fvMatrix< Type > &eqn) const
Apply constraints to an equation.
const surfaceVectorField & Sf() const
Return cell face area vectors.
const surfaceScalarField & magSf() const
Return cell face area magnitudes.
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.
PtrList< surfaceScalarField > Fs() const
Return the explicit force fluxes for the cell-based algorithm, that.
bool finalNonOrthogonalIter() const
Flag to indicate the last non-orthogonal iteration.
tmp< surfaceScalarField > surfaceTension(const phaseModel &) const
Return the surface tension force.
Definition: phaseSystem.C:569
void correctBoundaryFlux()
Correct fixed-flux BCs to be consistent with the velocity BCs.
Definition: phaseSystem.C:761
bool implicitPhasePressure() const
Returns true if the phase pressure is treated implicitly.
tmp< volScalarField > rho() const
Return the mixture density.
Definition: phaseSystem.C:452
bool incompressible() const
Return incompressibility.
Definition: phaseSystem.C:607
bool correct()
Piso loop within outer loop.
bool correctNonOrthogonal()
Non-orthogonal corrector loop.
PtrList< volScalarField::Internal > dmdts() const
Return the mass transfer rates for each phase.
scalar refValue() const
Return the pressure reference level.
label refCell() const
Return the cell in which the reference pressure is set.
pimpleNoLoopControl pimple
PIMPLE inner-loop controls.
Definition: solver.H:107
Foam::fvConstraints & fvConstraints() const
Return the fvConstraints that are created on demand.
Definition: solver.C:107
const Time & runTime
Time.
Definition: solver.H:104
const fvMesh & mesh
Region mesh.
Definition: solver.H:101
uniformDimensionedVectorField g
Gravitational acceleration.
Definition: buoyancy.H:83
volScalarField gh
(g & h) - ghRef
Definition: buoyancy.H:95
uniformDimensionedScalarField pRef
Reference pressure.
Definition: buoyancy.H:89
surfaceScalarField ghf
(g & hf) - ghRef
Definition: buoyancy.H:98
const surfaceScalarField & phi
Reference to the mass-flux field.
const volScalarField & p_rgh
Reference to the buoyant pressure for buoyant cases.
solvers::buoyancy buoyancy
Buoyancy force.
phaseSystem::phaseModelList & phases_
PtrList< fvVectorMatrix > UEqns
Temporary phase momentum matrices.
const phaseSystem::phaseModelPartialList & movingPhases
Reference to the moving phases.
Switch predictMomentum
Momentum equation predictor switch.
momentumTransferSystem momentumTransferSystem_
Switch dragCorrection
Cell/face drag correction for cell momentum corrector.
volScalarField & p_rgh_
Reference to the buoyant pressure for buoyant cases.
Foam::pressureReference pressureReference
Pressure reference.
PtrList< volScalarField > rAs
Temporary storage for the reciprocal momentum equation diagonal.
const phaseSystem::phaseModelList & phases
Reference to the phases.
phaseSystem::phaseModelPartialList & movingPhases_
const volScalarField & p
Reference to the pressure field.
populationBalanceSystem populationBalanceSystem_
const phaseSystem & fluid
Reference to the multiphase fluid.
Find the reference cell nearest (in index) to the given cell but which is not on a cyclic,...
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 field for explicit evaluation of implicit and explicit sources.
Calculate the matrix for the first temporal derivative.
Calculate the matrix for the divergence of the given field and flux.
Calculate the matrix for the laplacian of the field.
Calculate the matrix for implicit and explicit sources.
U
Definition: pEqn.H:72
surfaceScalarField phiHbyA("phiHbyA", fvc::interpolate(rho) *fvc::flux(HbyA))
volScalarField alpha(IOobject("alpha", runTime.name(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE), lambda *max(Ua &U, zeroSensitivity))
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< VolField< Type > > div(const SurfaceField< Type > &ssf)
Definition: fvcDiv.C:47
void makeRelative(surfaceScalarField &phi, const volVectorField &U)
Make the given flux relative.
Definition: fvcMeshPhi.C:89
tmp< SurfaceField< Type > > snGrad(const VolField< Type > &vf, const word &name)
Definition: fvcSnGrad.C:45
tmp< fvMatrix< Type > > laplacian(const VolField< Type > &vf, const word &name)
Definition: fvmLaplacian.C:47
fvMatrix< scalar > fvScalarMatrix
Definition: fvMatricesFwd.H:42
const dimensionSet dimVolumetricFlux
SurfaceField< scalar > surfaceScalarField
tmp< volScalarField > byDt(const volScalarField &vf)
Definition: phaseSystem.C:927
void constrainHbyA(volVectorField &HbyA, const volVectorField &U, const volScalarField &p)
Definition: constrainHbyA.C:34
const dimensionSet dimTime
const dimensionSet dimDensity
VolField< scalar > volScalarField
Definition: volFieldsFwd.H:62
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
scalar getRefCellValue(const volScalarField &field, const label refCelli)
Return the current value of field in the reference cell.
Definition: findRefCell.C:136
void constrainPhiHbyA(surfaceScalarField &phiHbyA, const volVectorField &U, const volScalarField &p)
Definition: constrainHbyA.C:60
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.