1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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.
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
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/>.
24 \*---------------------------------------------------------------------------*/
28 #include "uncorrectedSnGrad.H"
29 #include "gaussConvectionScheme.H"
30 #include "gaussLaplacianScheme.H"
31 #include "uncorrectedSnGrad.H"
32 #include "surfaceInterpolate.H"
33 #include "fvcSurfaceIntegrate.H"
34 #include "slicedSurfaceFields.H"
35 #include "syncTools.H"
39 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
41 template<class RhoType, class SpType, class SuType>
42 void Foam::MULES::explicitSolve
46 const surfaceScalarField& phi,
47 surfaceScalarField& phiPsi,
54 Info<< "MULES: Solving for " << psi.name() << endl;
56 const fvMesh& mesh = psi.mesh();
57 psi.correctBoundaryConditions();
59 surfaceScalarField phiBD(upwind<scalar>(psi.mesh(), phi).flux(psi));
61 surfaceScalarField& phiCorr = phiPsi;
64 scalarField allLambda(mesh.nFaces(), 1.0);
66 slicedSurfaceScalarField lambda
71 mesh.time().timeName(),
80 false // Use slices for the couples
97 phiPsi = phiBD + lambda*phiCorr;
99 scalarField& psiIf = psi;
100 const scalarField& psi0 = psi.oldTime();
101 const scalar deltaT = mesh.time().deltaTValue();
104 fvc::surfaceIntegrate(psiIf, phiPsi);
110 mesh.Vsc0()().field()*rho.oldTime().field()
111 *psi0/(deltaT*mesh.Vsc()().field())
114 )/(rho.field()/deltaT - Sp.field());
120 rho.oldTime().field()*psi0/deltaT
123 )/(rho.field()/deltaT - Sp.field());
126 psi.correctBoundaryConditions();
130 template<class RhoType, class SpType, class SuType>
131 void Foam::MULES::implicitSolve
135 const surfaceScalarField& phi,
136 surfaceScalarField& phiPsi,
143 const fvMesh& mesh = psi.mesh();
145 const dictionary& MULEScontrols = mesh.solverDict(psi.name());
149 readLabel(MULEScontrols.lookup("maxIter"))
154 readLabel(MULEScontrols.lookup("nLimiterIter"))
157 scalar maxUnboundedness
159 readScalar(MULEScontrols.lookup("maxUnboundedness"))
164 readScalar(MULEScontrols.lookup("CoCoeff"))
167 scalarField allCoLambda(mesh.nFaces());
170 tmp<surfaceScalarField> Cof =
171 mesh.time().deltaT()*mesh.surfaceInterpolation::deltaCoeffs()
172 *mag(phi)/mesh.magSf();
174 slicedSurfaceScalarField CoLambda
179 mesh.time().timeName(),
188 false // Use slices for the couples
191 CoLambda == 1.0/max(CoCoeff*Cof, scalar(1));
194 scalarField allLambda(allCoLambda);
195 //scalarField allLambda(mesh.nFaces(), 1.0);
197 slicedSurfaceScalarField lambda
202 mesh.time().timeName(),
211 false // Use slices for the couples
214 linear<scalar> CDs(mesh);
215 upwind<scalar> UDs(mesh, phi);
216 //fv::uncorrectedSnGrad<scalar> snGrads(mesh);
218 fvScalarMatrix psiConvectionDiffusion
221 + fv::gaussConvectionScheme<scalar>(mesh, phi, UDs).fvmDiv(phi, psi)
222 //- fv::gaussLaplacianScheme<scalar, scalar>(mesh, CDs, snGrads)
223 //.fvmLaplacian(Dpsif, psi)
228 surfaceScalarField phiBD(psiConvectionDiffusion.flux());
230 surfaceScalarField& phiCorr = phiPsi;
233 for (label i=0; i<maxIter; i++)
237 allLambda = allCoLambda;
256 psiConvectionDiffusion + fvc::div(lambda*phiCorr),
260 scalar maxPsiM1 = gMax(psi.internalField()) - 1.0;
261 scalar minPsi = gMin(psi.internalField());
263 scalar unboundedness = max(max(maxPsiM1, 0.0), -min(minPsi, 0.0));
265 if (unboundedness < maxUnboundedness)
271 Info<< "MULES: max(" << psi.name() << " - 1) = " << maxPsiM1
272 << " min(" << psi.name() << ") = " << minPsi << endl;
274 phiBD = psiConvectionDiffusion.flux();
277 word gammaScheme("div(phi,gamma)");
278 word gammarScheme("div(phirb,gamma)");
280 const surfaceScalarField& phir =
281 mesh.lookupObject<surfaceScalarField>("phir");
292 -fvc::flux(-phir, scalar(1) - psi, gammarScheme),
301 phiPsi = psiConvectionDiffusion.flux() + lambda*phiCorr;
305 template<class RhoType, class SpType, class SuType>
306 void Foam::MULES::limiter
308 scalarField& allLambda,
310 const volScalarField& psi,
311 const surfaceScalarField& phiBD,
312 const surfaceScalarField& phiCorr,
317 const label nLimiterIter
320 const scalarField& psiIf = psi;
321 const volScalarField::GeometricBoundaryField& psiBf = psi.boundaryField();
323 const scalarField& psi0 = psi.oldTime();
325 const fvMesh& mesh = psi.mesh();
327 const labelUList& owner = mesh.owner();
328 const labelUList& neighb = mesh.neighbour();
329 tmp<volScalarField::DimensionedInternalField> tVsc = mesh.Vsc();
330 const scalarField& V = tVsc();
331 const scalar deltaT = mesh.time().deltaTValue();
333 const scalarField& phiBDIf = phiBD;
334 const surfaceScalarField::GeometricBoundaryField& phiBDBf =
335 phiBD.boundaryField();
337 const scalarField& phiCorrIf = phiCorr;
338 const surfaceScalarField::GeometricBoundaryField& phiCorrBf =
339 phiCorr.boundaryField();
341 slicedSurfaceScalarField lambda
346 mesh.time().timeName(),
355 false // Use slices for the couples
358 scalarField& lambdaIf = lambda;
359 surfaceScalarField::GeometricBoundaryField& lambdaBf =
360 lambda.boundaryField();
362 scalarField psiMaxn(psiIf.size(), psiMin);
363 scalarField psiMinn(psiIf.size(), psiMax);
365 scalarField sumPhiBD(psiIf.size(), 0.0);
367 scalarField sumPhip(psiIf.size(), VSMALL);
368 scalarField mSumPhim(psiIf.size(), VSMALL);
370 forAll(phiCorrIf, facei)
372 label own = owner[facei];
373 label nei = neighb[facei];
375 psiMaxn[own] = max(psiMaxn[own], psiIf[nei]);
376 psiMinn[own] = min(psiMinn[own], psiIf[nei]);
378 psiMaxn[nei] = max(psiMaxn[nei], psiIf[own]);
379 psiMinn[nei] = min(psiMinn[nei], psiIf[own]);
381 sumPhiBD[own] += phiBDIf[facei];
382 sumPhiBD[nei] -= phiBDIf[facei];
384 scalar phiCorrf = phiCorrIf[facei];
388 sumPhip[own] += phiCorrf;
389 mSumPhim[nei] += phiCorrf;
393 mSumPhim[own] -= phiCorrf;
394 sumPhip[nei] -= phiCorrf;
398 forAll(phiCorrBf, patchi)
400 const fvPatchScalarField& psiPf = psiBf[patchi];
401 const scalarField& phiBDPf = phiBDBf[patchi];
402 const scalarField& phiCorrPf = phiCorrBf[patchi];
404 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
408 const scalarField psiPNf(psiPf.patchNeighbourField());
410 forAll(phiCorrPf, pFacei)
412 label pfCelli = pFaceCells[pFacei];
414 psiMaxn[pfCelli] = max(psiMaxn[pfCelli], psiPNf[pFacei]);
415 psiMinn[pfCelli] = min(psiMinn[pfCelli], psiPNf[pFacei]);
420 forAll(phiCorrPf, pFacei)
422 label pfCelli = pFaceCells[pFacei];
424 psiMaxn[pfCelli] = max(psiMaxn[pfCelli], psiPf[pFacei]);
425 psiMinn[pfCelli] = min(psiMinn[pfCelli], psiPf[pFacei]);
429 forAll(phiCorrPf, pFacei)
431 label pfCelli = pFaceCells[pFacei];
433 sumPhiBD[pfCelli] += phiBDPf[pFacei];
435 scalar phiCorrf = phiCorrPf[pFacei];
439 sumPhip[pfCelli] += phiCorrf;
443 mSumPhim[pfCelli] -= phiCorrf;
448 psiMaxn = min(psiMaxn, psiMax);
449 psiMinn = max(psiMinn, psiMin);
451 //scalar smooth = 0.5;
452 //psiMaxn = min((1.0 - smooth)*psiIf + smooth*psiMaxn, psiMax);
453 //psiMinn = max((1.0 - smooth)*psiIf + smooth*psiMinn, psiMin);
457 tmp<volScalarField::DimensionedInternalField> V0 = mesh.Vsc0();
462 (rho.field()/deltaT - Sp.field())*psiMaxn
465 - (V0().field()/deltaT)*rho.oldTime().field()*psi0
472 - (rho.field()/deltaT - Sp.field())*psiMinn
474 + (V0().field()/deltaT)*rho.oldTime().field()*psi0
482 (rho.field()/deltaT - Sp.field())*psiMaxn
484 - (rho.oldTime().field()/deltaT)*psi0
492 - (rho.field()/deltaT - Sp.field())*psiMinn
493 + (rho.oldTime().field()/deltaT)*psi0
498 scalarField sumlPhip(psiIf.size());
499 scalarField mSumlPhim(psiIf.size());
501 for (int j=0; j<nLimiterIter; j++)
506 forAll(lambdaIf, facei)
508 label own = owner[facei];
509 label nei = neighb[facei];
511 scalar lambdaPhiCorrf = lambdaIf[facei]*phiCorrIf[facei];
513 if (lambdaPhiCorrf > 0.0)
515 sumlPhip[own] += lambdaPhiCorrf;
516 mSumlPhim[nei] += lambdaPhiCorrf;
520 mSumlPhim[own] -= lambdaPhiCorrf;
521 sumlPhip[nei] -= lambdaPhiCorrf;
525 forAll(lambdaBf, patchi)
527 scalarField& lambdaPf = lambdaBf[patchi];
528 const scalarField& phiCorrfPf = phiCorrBf[patchi];
530 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
532 forAll(lambdaPf, pFacei)
534 label pfCelli = pFaceCells[pFacei];
536 scalar lambdaPhiCorrf = lambdaPf[pFacei]*phiCorrfPf[pFacei];
538 if (lambdaPhiCorrf > 0.0)
540 sumlPhip[pfCelli] += lambdaPhiCorrf;
544 mSumlPhim[pfCelli] -= lambdaPhiCorrf;
549 forAll(sumlPhip, celli)
554 (sumlPhip[celli] + psiMaxn[celli])/mSumPhim[celli],
561 (mSumlPhim[celli] + psiMinn[celli])/sumPhip[celli],
566 const scalarField& lambdam = sumlPhip;
567 const scalarField& lambdap = mSumlPhim;
569 forAll(lambdaIf, facei)
571 if (phiCorrIf[facei] > 0.0)
573 lambdaIf[facei] = min
576 min(lambdap[owner[facei]], lambdam[neighb[facei]])
581 lambdaIf[facei] = min
584 min(lambdam[owner[facei]], lambdap[neighb[facei]])
590 forAll(lambdaBf, patchi)
592 fvsPatchScalarField& lambdaPf = lambdaBf[patchi];
593 const scalarField& phiCorrfPf = phiCorrBf[patchi];
595 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
597 forAll(lambdaPf, pFacei)
599 label pfCelli = pFaceCells[pFacei];
601 if (phiCorrfPf[pFacei] > 0.0)
603 lambdaPf[pFacei] = min(lambdaPf[pFacei], lambdap[pfCelli]);
607 lambdaPf[pFacei] = min(lambdaPf[pFacei], lambdam[pfCelli]);
612 syncTools::syncFaceList(mesh, allLambda, minEqOp<scalar>());
617 // ************************************************************************* //