MULESTemplates.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2015 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 "slicedSurfaceFields.H"
31 #include "wedgeFvPatch.H"
32 #include "syncTools.H"
33 
34 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
35 
36 template<class RdeltaTType, class RhoType, class SpType, class SuType>
38 (
39  const RdeltaTType& rDeltaT,
40  const RhoType& rho,
42  const surfaceScalarField& phiPsi,
43  const SpType& Sp,
44  const SuType& Su
45 )
46 {
47  Info<< "MULES: Solving for " << psi.name() << endl;
48 
49  const fvMesh& mesh = psi.mesh();
50 
51  scalarField& psiIf = psi;
52  const scalarField& psi0 = psi.oldTime();
53 
54  psiIf = 0.0;
55  fvc::surfaceIntegrate(psiIf, phiPsi);
56 
57  if (mesh.moving())
58  {
59  psiIf =
60  (
61  mesh.Vsc0()().field()*rho.oldTime().field()
62  *psi0*rDeltaT/mesh.Vsc()().field()
63  + Su.field()
64  - psiIf
65  )/(rho.field()*rDeltaT - Sp.field());
66  }
67  else
68  {
69  psiIf =
70  (
71  rho.oldTime().field()*psi0*rDeltaT
72  + Su.field()
73  - psiIf
74  )/(rho.field()*rDeltaT - Sp.field());
75  }
76 
77  psi.correctBoundaryConditions();
78 }
79 
80 
81 template<class RhoType, class SpType, class SuType>
83 (
84  const RhoType& rho,
86  const surfaceScalarField& phiPsi,
87  const SpType& Sp,
88  const SuType& Su
89 )
90 {
91  const fvMesh& mesh = psi.mesh();
92  const scalar rDeltaT = 1.0/mesh.time().deltaTValue();
93  explicitSolve(rDeltaT, rho, psi, phiPsi, Sp, Su);
94 }
95 
96 
97 template<class RhoType, class SpType, class SuType>
99 (
100  const RhoType& rho,
102  const surfaceScalarField& phi,
103  surfaceScalarField& phiPsi,
104  const SpType& Sp,
105  const SuType& Su,
106  const scalar psiMax,
107  const scalar psiMin
108 )
109 {
110  const fvMesh& mesh = psi.mesh();
111 
112  psi.correctBoundaryConditions();
113 
114  if (fv::localEulerDdt::enabled(mesh))
115  {
116  const volScalarField& rDeltaT = fv::localEulerDdt::localRDeltaT(mesh);
117 
118  limit
119  (
120  rDeltaT,
121  rho,
122  psi,
123  phi,
124  phiPsi,
125  Sp,
126  Su,
127  psiMax,
128  psiMin,
129  false
130  );
131 
132  explicitSolve(rDeltaT, rho, psi, phiPsi, Sp, Su);
133  }
134  else
135  {
136  const scalar rDeltaT = 1.0/mesh.time().deltaTValue();
137 
138  limit
139  (
140  rDeltaT,
141  rho,
142  psi,
143  phi,
144  phiPsi,
145  Sp,
146  Su,
147  psiMax,
148  psiMin,
149  false
150  );
151 
152  explicitSolve(rDeltaT, rho, psi, phiPsi, Sp, Su);
153  }
154 }
155 
156 
157 template<class RdeltaTType, class RhoType, class SpType, class SuType>
159 (
160  scalarField& allLambda,
161  const RdeltaTType& rDeltaT,
162  const RhoType& rho,
163  const volScalarField& psi,
164  const surfaceScalarField& phiBD,
165  const surfaceScalarField& phiCorr,
166  const SpType& Sp,
167  const SuType& Su,
168  const scalar psiMax,
169  const scalar psiMin
170 )
171 {
172  const scalarField& psiIf = psi;
173  const volScalarField::GeometricBoundaryField& psiBf = psi.boundaryField();
174 
175  const fvMesh& mesh = psi.mesh();
176 
177  const dictionary& MULEScontrols = mesh.solverDict(psi.name());
178 
179  label nLimiterIter
180  (
181  MULEScontrols.lookupOrDefault<label>("nLimiterIter", 3)
182  );
183 
184  scalar smoothLimiter
185  (
186  MULEScontrols.lookupOrDefault<scalar>("smoothLimiter", 0)
187  );
188 
189  const scalarField& psi0 = psi.oldTime();
190 
191  const labelUList& owner = mesh.owner();
192  const labelUList& neighb = mesh.neighbour();
194  const scalarField& V = tVsc();
195 
196  const scalarField& phiBDIf = phiBD;
198  phiBD.boundaryField();
199 
200  const scalarField& phiCorrIf = phiCorr;
202  phiCorr.boundaryField();
203 
205  (
206  IOobject
207  (
208  "lambda",
209  mesh.time().timeName(),
210  mesh,
211  IOobject::NO_READ,
212  IOobject::NO_WRITE,
213  false
214  ),
215  mesh,
216  dimless,
217  allLambda,
218  false // Use slices for the couples
219  );
220 
221  scalarField& lambdaIf = lambda;
223  lambda.boundaryField();
224 
225  scalarField psiMaxn(psiIf.size(), psiMin);
226  scalarField psiMinn(psiIf.size(), psiMax);
227 
228  scalarField sumPhiBD(psiIf.size(), 0.0);
229 
230  scalarField sumPhip(psiIf.size(), VSMALL);
231  scalarField mSumPhim(psiIf.size(), VSMALL);
232 
233  forAll(phiCorrIf, facei)
234  {
235  label own = owner[facei];
236  label nei = neighb[facei];
237 
238  psiMaxn[own] = max(psiMaxn[own], psiIf[nei]);
239  psiMinn[own] = min(psiMinn[own], psiIf[nei]);
240 
241  psiMaxn[nei] = max(psiMaxn[nei], psiIf[own]);
242  psiMinn[nei] = min(psiMinn[nei], psiIf[own]);
243 
244  sumPhiBD[own] += phiBDIf[facei];
245  sumPhiBD[nei] -= phiBDIf[facei];
246 
247  scalar phiCorrf = phiCorrIf[facei];
248 
249  if (phiCorrf > 0.0)
250  {
251  sumPhip[own] += phiCorrf;
252  mSumPhim[nei] += phiCorrf;
253  }
254  else
255  {
256  mSumPhim[own] -= phiCorrf;
257  sumPhip[nei] -= phiCorrf;
258  }
259  }
260 
261  forAll(phiCorrBf, patchi)
262  {
263  const fvPatchScalarField& psiPf = psiBf[patchi];
264  const scalarField& phiBDPf = phiBDBf[patchi];
265  const scalarField& phiCorrPf = phiCorrBf[patchi];
266 
267  const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
268 
269  if (psiPf.coupled())
270  {
271  const scalarField psiPNf(psiPf.patchNeighbourField());
272 
273  forAll(phiCorrPf, pFacei)
274  {
275  label pfCelli = pFaceCells[pFacei];
276 
277  psiMaxn[pfCelli] = max(psiMaxn[pfCelli], psiPNf[pFacei]);
278  psiMinn[pfCelli] = min(psiMinn[pfCelli], psiPNf[pFacei]);
279  }
280  }
281  else
282  {
283  forAll(phiCorrPf, pFacei)
284  {
285  label pfCelli = pFaceCells[pFacei];
286 
287  psiMaxn[pfCelli] = max(psiMaxn[pfCelli], psiPf[pFacei]);
288  psiMinn[pfCelli] = min(psiMinn[pfCelli], psiPf[pFacei]);
289  }
290  }
291 
292  forAll(phiCorrPf, pFacei)
293  {
294  label pfCelli = pFaceCells[pFacei];
295 
296  sumPhiBD[pfCelli] += phiBDPf[pFacei];
297 
298  scalar phiCorrf = phiCorrPf[pFacei];
299 
300  if (phiCorrf > 0.0)
301  {
302  sumPhip[pfCelli] += phiCorrf;
303  }
304  else
305  {
306  mSumPhim[pfCelli] -= phiCorrf;
307  }
308  }
309  }
310 
311  psiMaxn = min(psiMaxn, psiMax);
312  psiMinn = max(psiMinn, psiMin);
313 
314  if (smoothLimiter > SMALL)
315  {
316  psiMaxn =
317  min(smoothLimiter*psiIf + (1.0 - smoothLimiter)*psiMaxn, psiMax);
318  psiMinn =
319  max(smoothLimiter*psiIf + (1.0 - smoothLimiter)*psiMinn, psiMin);
320  }
321 
322  if (mesh.moving())
323  {
325 
326  psiMaxn =
327  V
328  *(
329  (rho.field()*rDeltaT - Sp.field())*psiMaxn
330  - Su.field()
331  )
332  - (V0().field()*rDeltaT)*rho.oldTime().field()*psi0
333  + sumPhiBD;
334 
335  psiMinn =
336  V
337  *(
338  Su.field()
339  - (rho.field()*rDeltaT - Sp.field())*psiMinn
340  )
341  + (V0().field()*rDeltaT)*rho.oldTime().field()*psi0
342  - sumPhiBD;
343  }
344  else
345  {
346  psiMaxn =
347  V
348  *(
349  (rho.field()*rDeltaT - Sp.field())*psiMaxn
350  - Su.field()
351  - (rho.oldTime().field()*rDeltaT)*psi0
352  )
353  + sumPhiBD;
354 
355  psiMinn =
356  V
357  *(
358  Su.field()
359  - (rho.field()*rDeltaT - Sp.field())*psiMinn
360  + (rho.oldTime().field()*rDeltaT)*psi0
361  )
362  - sumPhiBD;
363  }
364 
365  scalarField sumlPhip(psiIf.size());
366  scalarField mSumlPhim(psiIf.size());
367 
368  for (int j=0; j<nLimiterIter; j++)
369  {
370  sumlPhip = 0.0;
371  mSumlPhim = 0.0;
372 
373  forAll(lambdaIf, facei)
374  {
375  label own = owner[facei];
376  label nei = neighb[facei];
377 
378  scalar lambdaPhiCorrf = lambdaIf[facei]*phiCorrIf[facei];
379 
380  if (lambdaPhiCorrf > 0.0)
381  {
382  sumlPhip[own] += lambdaPhiCorrf;
383  mSumlPhim[nei] += lambdaPhiCorrf;
384  }
385  else
386  {
387  mSumlPhim[own] -= lambdaPhiCorrf;
388  sumlPhip[nei] -= lambdaPhiCorrf;
389  }
390  }
391 
392  forAll(lambdaBf, patchi)
393  {
394  scalarField& lambdaPf = lambdaBf[patchi];
395  const scalarField& phiCorrfPf = phiCorrBf[patchi];
396 
397  const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
398 
399  forAll(lambdaPf, pFacei)
400  {
401  label pfCelli = pFaceCells[pFacei];
402 
403  scalar lambdaPhiCorrf = lambdaPf[pFacei]*phiCorrfPf[pFacei];
404 
405  if (lambdaPhiCorrf > 0.0)
406  {
407  sumlPhip[pfCelli] += lambdaPhiCorrf;
408  }
409  else
410  {
411  mSumlPhim[pfCelli] -= lambdaPhiCorrf;
412  }
413  }
414  }
415 
416  forAll(sumlPhip, celli)
417  {
418  sumlPhip[celli] =
419  max(min
420  (
421  (sumlPhip[celli] + psiMaxn[celli])
422  /(mSumPhim[celli] - SMALL),
423  1.0), 0.0
424  );
425 
426  mSumlPhim[celli] =
427  max(min
428  (
429  (mSumlPhim[celli] + psiMinn[celli])
430  /(sumPhip[celli] + SMALL),
431  1.0), 0.0
432  );
433  }
434 
435  const scalarField& lambdam = sumlPhip;
436  const scalarField& lambdap = mSumlPhim;
437 
438  forAll(lambdaIf, facei)
439  {
440  if (phiCorrIf[facei] > 0.0)
441  {
442  lambdaIf[facei] = min
443  (
444  lambdaIf[facei],
445  min(lambdap[owner[facei]], lambdam[neighb[facei]])
446  );
447  }
448  else
449  {
450  lambdaIf[facei] = min
451  (
452  lambdaIf[facei],
453  min(lambdam[owner[facei]], lambdap[neighb[facei]])
454  );
455  }
456  }
457 
458 
459  forAll(lambdaBf, patchi)
460  {
461  fvsPatchScalarField& lambdaPf = lambdaBf[patchi];
462  const scalarField& phiCorrfPf = phiCorrBf[patchi];
463  const fvPatchScalarField& psiPf = psiBf[patchi];
464 
465  if (isA<wedgeFvPatch>(mesh.boundary()[patchi]))
466  {
467  lambdaPf = 0;
468  }
469  else if (psiPf.coupled())
470  {
471  const labelList& pFaceCells =
472  mesh.boundary()[patchi].faceCells();
473 
474  forAll(lambdaPf, pFacei)
475  {
476  label pfCelli = pFaceCells[pFacei];
477 
478  if (phiCorrfPf[pFacei] > 0.0)
479  {
480  lambdaPf[pFacei] =
481  min(lambdaPf[pFacei], lambdap[pfCelli]);
482  }
483  else
484  {
485  lambdaPf[pFacei] =
486  min(lambdaPf[pFacei], lambdam[pfCelli]);
487  }
488  }
489  }
490  else
491  {
492  const labelList& pFaceCells =
493  mesh.boundary()[patchi].faceCells();
494  const scalarField& phiBDPf = phiBDBf[patchi];
495  const scalarField& phiCorrPf = phiCorrBf[patchi];
496 
497  forAll(lambdaPf, pFacei)
498  {
499  // Limit outlet faces only
500  if ((phiBDPf[pFacei] + phiCorrPf[pFacei]) > SMALL*SMALL)
501  {
502  label pfCelli = pFaceCells[pFacei];
503 
504  if (phiCorrfPf[pFacei] > 0.0)
505  {
506  lambdaPf[pFacei] =
507  min(lambdaPf[pFacei], lambdap[pfCelli]);
508  }
509  else
510  {
511  lambdaPf[pFacei] =
512  min(lambdaPf[pFacei], lambdam[pfCelli]);
513  }
514  }
515  }
516  }
517  }
518 
519  syncTools::syncFaceList(mesh, allLambda, minEqOp<scalar>());
520  }
521 }
522 
523 
524 template<class RdeltaTType, class RhoType, class SpType, class SuType>
526 (
527  const RdeltaTType& rDeltaT,
528  const RhoType& rho,
529  const volScalarField& psi,
530  const surfaceScalarField& phi,
531  surfaceScalarField& phiPsi,
532  const SpType& Sp,
533  const SuType& Su,
534  const scalar psiMax,
535  const scalar psiMin,
536  const bool returnCorr
537 )
538 {
539  const fvMesh& mesh = psi.mesh();
540 
541  surfaceScalarField phiBD(upwind<scalar>(psi.mesh(), phi).flux(psi));
542 
543  surfaceScalarField& phiCorr = phiPsi;
544  phiCorr -= phiBD;
545 
546  scalarField allLambda(mesh.nFaces(), 1.0);
547 
549  (
550  IOobject
551  (
552  "lambda",
553  mesh.time().timeName(),
554  mesh,
555  IOobject::NO_READ,
556  IOobject::NO_WRITE,
557  false
558  ),
559  mesh,
560  dimless,
561  allLambda,
562  false // Use slices for the couples
563  );
564 
565  limiter
566  (
567  allLambda,
568  rDeltaT,
569  rho,
570  psi,
571  phiBD,
572  phiCorr,
573  Sp,
574  Su,
575  psiMax,
576  psiMin
577  );
578 
579  if (returnCorr)
580  {
581  phiCorr *= lambda;
582  }
583  else
584  {
585  phiPsi = phiBD + lambda*phiCorr;
586  }
587 }
588 
589 
590 template<class SurfaceScalarFieldList>
591 void Foam::MULES::limitSum(SurfaceScalarFieldList& phiPsiCorrs)
592 {
593  {
594  UPtrList<scalarField> phiPsiCorrsInternal(phiPsiCorrs.size());
595  forAll(phiPsiCorrs, phasei)
596  {
597  phiPsiCorrsInternal.set(phasei, &phiPsiCorrs[phasei]);
598  }
599 
600  limitSum(phiPsiCorrsInternal);
601  }
602 
604  phiPsiCorrs[0].boundaryField();
605 
606  forAll(bfld, patchi)
607  {
608  if (bfld[patchi].coupled())
609  {
610  UPtrList<scalarField> phiPsiCorrsPatch(phiPsiCorrs.size());
611  forAll(phiPsiCorrs, phasei)
612  {
613  phiPsiCorrsPatch.set
614  (
615  phasei,
616  &phiPsiCorrs[phasei].boundaryField()[patchi]
617  );
618  }
619 
620  limitSum(phiPsiCorrsPatch);
621  }
622  }
623 }
624 
625 
626 // ************************************************************************* //
Foam::fvPatchField
Abstract base class with a fat-interface to all derived classes covering all possible ways in which t...
Definition: fvPatchField.H:65
Foam::IOobject
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:91
Foam::dimless
const dimensionSet dimless(0, 0, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:47
Foam::MULES::explicitSolve
void explicitSolve(const RdeltaTType &rDeltaT, const RhoType &rho, volScalarField &psi, const surfaceScalarField &phiPsi, const SpType &Sp, const SuType &Su)
Definition: MULESTemplates.C:38
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:118
Foam::upwind
Upwind differencing scheme class.
Definition: upwind.H:51
phi
surfaceScalarField & phi
Definition: setRegionFluidFields.H:8
Foam::MULES::limiter
void limiter(scalarField &allLambda, const RdeltaTType &rDeltaT, const RhoType &rho, const volScalarField &psi, const surfaceScalarField &phiBD, const surfaceScalarField &phiCorr, const SpType &Sp, const SuType &Su, const scalar psiMax, const scalar psiMin)
Definition: MULESTemplates.C:159
Foam::fvsPatchField
An abstract base class with a fat-interface to all derived classes covering all possible ways in whic...
Definition: fvsPatchField.H:65
Foam::dictionary::lookupOrDefault
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
Definition: dictionaryTemplates.C:33
Foam::GeometricField::boundaryField
GeometricBoundaryField & boundaryField()
Return reference to GeometricBoundaryField.
Definition: GeometricField.C:735
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
syncTools.H
Foam::fvPatchField::coupled
virtual bool coupled() const
Return true if this patch field is coupled.
Definition: fvPatchField.H:342
localEulerDdtScheme.H
Foam::label
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
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
Foam::fvc::Su
tmp< GeometricField< Type, fvPatchField, volMesh > > Su(const GeometricField< Type, fvPatchField, volMesh > &su, const GeometricField< Type, fvPatchField, volMesh > &vf)
Definition: fvcSup.C:44
Foam::Info
messageStream Info
Foam::minEqOp
Definition: ops.H:78
Foam::MULES::limitSum
void limitSum(UPtrList< scalarField > &phiPsiCorrs)
Definition: MULES.C:51
upwind.H
Foam::UPtrList
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: UPtrList.H:53
fvcSurfaceIntegrate.H
Surface integrate surfaceField creating a volField. Surface sum a surfaceField creating a volField.
Foam::dictionary
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:137
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:18
boundaryField
cellIbMask *cellIbMaskExt *faceIbMask *cellIbMask boundaryField().evaluateCoupled()
Foam::MULES::limit
void limit(const RdeltaTType &rDeltaT, const RhoType &rho, const volScalarField &psi, const surfaceScalarField &phi, surfaceScalarField &phiPsi, const SpType &Sp, const SuType &Su, const scalar psiMax, const scalar psiMin, const bool returnCorr)
Definition: MULESTemplates.C:526
Foam::fvMesh
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
Foam::fvPatchField::patchNeighbourField
virtual tmp< Field< Type > > patchNeighbourField() const
Return patchField on the opposite patch of a coupled patch.
Definition: fvPatchField.H:408
rho
rho
Definition: pEqn.H:3
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
psi
const volScalarField & psi
Definition: setRegionFluidFields.H:13
phasei
label phasei
Definition: pEqn.H:37
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
Foam::fvc::surfaceIntegrate
void surfaceIntegrate(Field< Type > &ivf, const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcSurfaceIntegrate.C:44
Foam::UPtrList::set
bool set(const label) const
Is element set.
Foam::UList
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:60
patchi
label patchi
Definition: getPatchFieldScalar.H:1
slicedSurfaceFields.H
Foam::SlicedGeometricField
Specialization of GeometricField which holds slices of given complete fields in a form that they act ...
Definition: slicedSurfaceFieldsFwd.H:56
Foam::limitedSurfaceInterpolationScheme::flux
virtual tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > flux(const GeometricField< Type, fvPatchField, volMesh > &) const
Return the interpolation weighting factors.
Definition: limitedSurfaceInterpolationScheme.C:206
Foam::fvc::Sp
tmp< GeometricField< Type, fvPatchField, volMesh > > Sp(const volScalarField &sp, const GeometricField< Type, fvPatchField, volMesh > &vf)
Definition: fvcSup.C:67
Foam::GeometricField
Generic GeometricField class.
Definition: surfaceFieldsFwd.H:52
MULES.H
MULES: Multidimensional universal limiter for explicit solution.
Foam::min
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::GeometricField::GeometricBoundaryField
Definition: GeometricField.H:105
lambda
dimensionedScalar lambda(laminarTransport.lookup("lambda"))
wedgeFvPatch.H