MULESTemplates.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) 2011-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 "MULES.H"
27 #include "upwind.H"
28 #include "fvcSurfaceIntegrate.H"
29 #include "localEulerDdtScheme.H"
30 #include "wedgeFvPatch.H"
31 #include "linear.H"
32 
33 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
34 
35 template<class RdeltaTType, class RhoType, class SpType, class SuType>
37 (
38  const RdeltaTType& rDeltaT,
39  const RhoType& rho,
41  const surfaceScalarField& psiPhi,
42  const SpType& Sp,
43  const SuType& Su
44 )
45 {
46  Info<< "MULES: Solving for " << psi.name() << endl;
47 
48  const fvMesh& mesh = psi.mesh();
49 
50  scalarField& psiIf = psi;
51  const scalarField& psi0 = psi.oldTime();
52 
53  psiIf = 0.0;
54  fvc::surfaceIntegrate(psiIf, psiPhi);
55 
56  if (mesh.moving())
57  {
58  psiIf =
59  (
60  mesh.Vsc0()().primitiveField()*rho.oldTime().primitiveField()
61  *psi0*rDeltaT/mesh.Vsc()().primitiveField()
62  + Su.primitiveField()
63  - psiIf
64  )/(rho.primitiveField()*rDeltaT - Sp.primitiveField());
65  }
66  else
67  {
68  psiIf =
69  (
70  rho.oldTime().primitiveField()*psi0*rDeltaT
71  + Su.primitiveField()
72  - psiIf
73  )/(rho.primitiveField()*rDeltaT - Sp.primitiveField());
74  }
75 
76  psi.correctBoundaryConditions();
77 }
78 
79 
80 template<class RhoType>
82 (
83  const RhoType& rho,
85  const surfaceScalarField& psiPhi
86 )
87 {
88  explicitSolve(rho, psi, psiPhi, zeroField(), zeroField());
89 }
90 
91 
92 template<class RhoType, class SpType, class SuType>
94 (
95  const RhoType& rho,
97  const surfaceScalarField& psiPhi,
98  const SpType& Sp,
99  const SuType& Su
100 )
101 {
102  const fvMesh& mesh = psi.mesh();
103 
104  if (fv::localEulerDdt::enabled(mesh))
105  {
106  const volScalarField& rDeltaT = fv::localEulerDdt::localRDeltaT(mesh);
107  explicitSolve(rDeltaT, rho, psi, psiPhi, Sp, Su);
108  }
109  else
110  {
111  const scalar rDeltaT = 1.0/mesh.time().deltaTValue();
112  explicitSolve(rDeltaT, rho, psi, psiPhi, Sp, Su);
113  }
114 }
115 
116 
117 template<class RhoType, class PsiMaxType, class PsiMinType>
119 (
120  const control& controls,
121  const RhoType& rho,
123  const surfaceScalarField& phiBD,
124  surfaceScalarField& psiPhi,
125  const PsiMaxType& psiMax,
126  const PsiMinType& psiMin
127 )
128 {
130  (
131  controls,
132  rho,
133  psi,
134  phiBD,
135  psiPhi,
136  zeroField(),
137  zeroField(),
138  psiMax,
139  psiMin
140  );
141 }
142 
143 
144 template
145 <
146  class RhoType,
147  class SpType,
148  class SuType,
149  class PsiMaxType,
150  class PsiMinType
151 >
153 (
154  const control& controls,
155  const RhoType& rho,
157  const surfaceScalarField& phi,
158  surfaceScalarField& psiPhi,
159  const SpType& Sp,
160  const SuType& Su,
161  const PsiMaxType& psiMax,
162  const PsiMinType& psiMin
163 )
164 {
165  const fvMesh& mesh = psi.mesh();
166 
167  psi.correctBoundaryConditions();
168 
169  if (fv::localEulerDdt::enabled(mesh))
170  {
171  const volScalarField& rDeltaT = fv::localEulerDdt::localRDeltaT(mesh);
172  limit
173  (
174  controls,
175  rDeltaT,
176  rho,
177  psi,
178  phi,
179  psiPhi,
180  Sp,
181  Su,
182  psiMax,
183  psiMin,
184  false
185  );
186  explicitSolve(rDeltaT, rho, psi, psiPhi, Sp, Su);
187  }
188  else
189  {
190  const scalar rDeltaT = 1.0/mesh.time().deltaTValue();
191  limit
192  (
193  controls,
194  rDeltaT,
195  rho,
196  psi,
197  phi,
198  psiPhi,
199  Sp,
200  Su,
201  psiMax,
202  psiMin,
203  false
204  );
205  explicitSolve(rDeltaT, rho, psi, psiPhi, Sp, Su);
206  }
207 }
208 
209 
210 template
211 <
212  class RdeltaTType,
213  class RhoType,
214  class SpType,
215  class SuType,
216  class PsiMaxType,
217  class PsiMinType
218 >
220 (
221  const control& controls,
222  const RdeltaTType& rDeltaT,
223  const RhoType& rho,
224  const volScalarField& psi,
225  const surfaceScalarField& phi,
226  surfaceScalarField& psiPhi,
227  const SpType& Sp,
228  const SuType& Su,
229  const PsiMaxType& psiMax,
230  const PsiMinType& psiMin,
231  const bool returnCorr
232 )
233 {
234  surfaceScalarField phiBD(upwind<scalar>(psi.mesh(), phi).flux(psi));
235 
237  const surfaceScalarField::Boundary& psiPhiBf = psiPhi.boundaryField();
238 
239  forAll(phiBDBf, patchi)
240  {
241  fvsPatchScalarField& phiBDPf = phiBDBf[patchi];
242 
243  if (!phiBDPf.coupled())
244  {
245  phiBDPf = psiPhiBf[patchi];
246  }
247  }
248 
249  limit
250  (
251  controls,
252  rDeltaT,
253  rho,
254  psi,
255  phi,
256  phiBD,
257  psiPhi,
258  Sp,Su,
259  psiMax,
260  psiMin,
261  returnCorr
262  );
263 }
264 
265 
266 template
267 <
268  class RdeltaTType,
269  class RhoType,
270  class SpType,
271  class SuType,
272  class PsiMaxType,
273  class PsiMinType
274 >
276 (
277  const control& controls,
278  const RdeltaTType& rDeltaT,
279  const RhoType& rho,
280  const volScalarField& psi,
281  const surfaceScalarField& phi,
282  const surfaceScalarField& phiBD,
283  surfaceScalarField& psiPhi,
284  const SpType& Sp,
285  const SuType& Su,
286  const PsiMaxType& psiMax,
287  const PsiMinType& psiMin,
288  const bool returnCorr
289 )
290 {
291  const fvMesh& mesh = psi.mesh();
292 
293  const labelUList& owner = mesh.owner();
294  const labelUList& neighb = mesh.neighbour();
295 
296  const scalarField& phiBDIf = phiBD;
297  const surfaceScalarField::Boundary& phiBDBf = phiBD.boundaryField();
298 
299  surfaceScalarField& phiCorr = psiPhi;
300  phiCorr -= phiBD;
301 
303  const scalarField& V = tVsc();
304 
305  // Correction equation source
306  scalarField SuCorr
307  (
308  mesh.moving()
309  ? (mesh.Vsc0()().primitiveField()*rDeltaT*rho.oldTime().primitiveField())
310  *psi.oldTime().primitiveField()
311  + V*Su.primitiveField()
312  : V
313  *(
314  (rho.oldTime().primitiveField()*rDeltaT)
315  *psi.oldTime().primitiveField()
316  + Su.primitiveField()
317  )
318  );
319 
320  // Subtract the sum of the bounded fluxes
321  // from the correction equation source
322  forAll(phiBDIf, facei)
323  {
324  SuCorr[owner[facei]] -= phiBDIf[facei];
325  SuCorr[neighb[facei]] += phiBDIf[facei];
326  }
327 
328  forAll(phiBDBf, patchi)
329  {
330  const scalarField& phiBDPf = phiBDBf[patchi];
331  const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
332 
333  forAll(phiBDPf, pFacei)
334  {
335  SuCorr[pFaceCells[pFacei]] -= phiBDPf[pFacei];
336  }
337  }
338 
340  (
341  IOobject
342  (
343  "lambda",
344  mesh.time().name(),
345  mesh,
346  IOobject::NO_READ,
347  IOobject::NO_WRITE,
348  false
349  ),
350  mesh,
352  );
353 
354  limiter
355  (
356  controls,
357  lambda,
358  rDeltaT,
359  rho,
360  psi,
361  SuCorr,
362  phiBD,
363  phiCorr,
364  Sp,
365  psiMax,
366  psiMin
367  );
368 
369  if (returnCorr)
370  {
371  phiCorr *= lambda;
372  }
373  else
374  {
375  psiPhi = phiBD + lambda*phiCorr;
376  }
377 }
378 
379 
380 template
381 <
382  class RhoType,
383  class SpType,
384  class SuType,
385  class PsiMaxType,
386  class PsiMinType
387 >
389 (
390  const control& controls,
391  const RhoType& rho,
392  const volScalarField& psi,
393  const surfaceScalarField& phi,
394  surfaceScalarField& psiPhi,
395  const SpType& Sp,
396  const SuType& Su,
397  const PsiMaxType& psiMax,
398  const PsiMinType& psiMin,
399  const bool rtnCorr
400 )
401 {
402  const fvMesh& mesh = psi.mesh();
403 
404  if (fv::localEulerDdt::enabled(mesh))
405  {
406  const volScalarField& rDeltaT = fv::localEulerDdt::localRDeltaT(mesh);
407  limit
408  (
409  controls,
410  rDeltaT,
411  rho,
412  psi,
413  phi,
414  psiPhi,
415  Sp,
416  Su,
417  psiMax,
418  psiMin,
419  rtnCorr
420  );
421  }
422  else
423  {
424  const scalar rDeltaT = 1.0/mesh.time().deltaTValue();
425  limit
426  (
427  controls,
428  rDeltaT,
429  rho,
430  psi,
431  phi,
432  psiPhi,
433  Sp,
434  Su,
435  psiMax,
436  psiMin,
437  rtnCorr
438  );
439  }
440 }
441 
442 
443 template
444 <
445  class RhoType,
446  class SpType,
447  class SuType,
448  class PsiMaxType,
449  class PsiMinType
450 >
452 (
453  const control& controls,
454  const RhoType& rho,
455  const volScalarField& psi,
456  const surfaceScalarField& phi,
457  const surfaceScalarField& phiBD,
458  surfaceScalarField& psiPhi,
459  const SpType& Sp,
460  const SuType& Su,
461  const PsiMaxType& psiMax,
462  const PsiMinType& psiMin,
463  const bool rtnCorr
464 )
465 {
466  const fvMesh& mesh = psi.mesh();
467 
468  if (fv::localEulerDdt::enabled(mesh))
469  {
470  const volScalarField& rDeltaT = fv::localEulerDdt::localRDeltaT(mesh);
471  limit
472  (
473  controls,
474  rDeltaT,
475  rho,
476  psi,
477  phi,
478  phiBD,
479  psiPhi,
480  Sp,
481  Su,
482  psiMax,
483  psiMin,
484  rtnCorr
485  );
486  }
487  else
488  {
489  const scalar rDeltaT = 1.0/mesh.time().deltaTValue();
490  limit
491  (
492  controls,
493  rDeltaT,
494  rho,
495  psi,
496  phi,
497  phiBD,
498  psiPhi,
499  Sp,
500  Su,
501  psiMax,
502  psiMin,
503  rtnCorr
504  );
505  }
506 }
507 
508 
509 // ************************************************************************* //
MULES: Multidimensional universal limiter for explicit solution.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
Generic GeometricBoundaryField class.
Generic GeometricField class.
const Boundary & boundaryField() const
Return const-reference to the boundary field.
Boundary & boundaryFieldRef()
Return a reference to the boundary field.
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
scalar deltaTValue() const
Return time step value.
Definition: TimeStateI.H:34
const word & name() const
Return const reference to name.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:96
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:420
const labelUList & owner() const
Internal face owner.
Definition: fvMesh.H:471
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:962
const labelUList & neighbour() const
Internal face neighbour.
Definition: fvMesh.H:477
tmp< DimensionedField< scalar, volMesh > > Vsc0() const
Return sub-cycle old-time cell volumes.
tmp< DimensionedField< scalar, volMesh > > Vsc() const
Return sub-cycle cell volumes.
An abstract base class with a fat-interface to all derived classes covering all possible ways in whic...
Definition: fvsPatchField.H:86
virtual bool coupled() const
Return true if this patch field is coupled.
virtual tmp< SurfaceField< Type > > flux(const VolField< Type > &) const
Return the interpolation weighting factors.
bool moving() const
Is mesh moving.
Definition: polyMesh.H:473
A class for managing temporary objects.
Definition: tmp.H:55
A class representing the concept of a field of 0 used to avoid unnecessary manipulations for objects ...
Definition: zeroField.H:53
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
Surface integrate surfaceField creating a volField. Surface sum a surfaceField creating a volField.
label patchi
const volScalarField & psi
dimensionedScalar lambda(viscosity->lookup("lambda"))
void limiter(const control &controls, surfaceScalarField &lambda, const RdeltaTType &rDeltaT, const RhoType &rho, const volScalarField &psi, const scalarField &SuCorr, const surfaceScalarField &phi, const surfaceScalarField &phiCorr, const SpType &Sp, const PsiMaxType &psiMax, const PsiMinType &psiMin)
Definition: MULESlimiter.C:42
void explicitSolve(const RdeltaTType &rDeltaT, const RhoType &rho, volScalarField &psi, const surfaceScalarField &psiPhi, const SpType &Sp, const SuType &Su)
void limit(const control &controls, const RdeltaTType &rDeltaT, const RhoType &rho, const volScalarField &psi, const surfaceScalarField &phi, surfaceScalarField &psiPhi, const SpType &Sp, const SuType &Su, const PsiMaxType &psiMax, const PsiMinType &psiMin, const bool returnCorr)
void surfaceIntegrate(Field< Type > &ivf, const SurfaceField< Type > &ssf)
tmp< VolField< Type > > Su(const VolField< Type > &su, const VolField< Type > &vf)
Definition: fvcSup.C:44
tmp< VolField< Type > > Sp(const volScalarField &sp, const VolField< Type > &vf)
Definition: fvcSup.C:67
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:258
const dimensionSet dimless
messageStream Info