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::explicitLTSSolve
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();
102 const volScalarField& rDeltaT =
103 mesh.objectRegistry::lookupObject<volScalarField>("rSubDeltaT");
106 fvc::surfaceIntegrate(psiIf, phiPsi);
112 mesh.Vsc0()*rho.oldTime()*psi0*rDeltaT/mesh.Vsc()
115 )/(rho*rDeltaT - Sp.field());
121 rho.oldTime()*psi0*rDeltaT
124 )/(rho*rDeltaT - Sp.field());
127 psi.correctBoundaryConditions();
131 template<class RhoType, class SpType, class SuType>
132 void Foam::MULES::implicitSolve
136 const surfaceScalarField& phi,
137 surfaceScalarField& phiPsi,
144 const fvMesh& mesh = psi.mesh();
146 const dictionary& MULEScontrols = mesh.solverDict(psi.name());
150 readLabel(MULEScontrols.lookup("maxIter"))
155 readLabel(MULEScontrols.lookup("nLimiterIter"))
158 scalar maxUnboundedness
160 readScalar(MULEScontrols.lookup("maxUnboundedness"))
165 readScalar(MULEScontrols.lookup("CoCoeff"))
168 scalarField allCoLambda(mesh.nFaces());
171 surfaceScalarField Cof
173 mesh.time().deltaT()*mesh.surfaceInterpolation::deltaCoeffs()
174 *mag(phi)/mesh.magSf()
177 slicedSurfaceScalarField CoLambda
182 mesh.time().timeName(),
191 false // Use slices for the couples
194 CoLambda == 1.0/max(CoCoeff*Cof, scalar(1));
197 scalarField allLambda(allCoLambda);
198 //scalarField allLambda(mesh.nFaces(), 1.0);
200 slicedSurfaceScalarField lambda
205 mesh.time().timeName(),
214 false // Use slices for the couples
217 linear<scalar> CDs(mesh);
218 upwind<scalar> UDs(mesh, phi);
219 //fv::uncorrectedSnGrad<scalar> snGrads(mesh);
221 fvScalarMatrix psiConvectionDiffusion
224 + fv::gaussConvectionScheme<scalar>(mesh, phi, UDs).fvmDiv(phi, psi)
225 //- fv::gaussLaplacianScheme<scalar, scalar>(mesh, CDs, snGrads)
226 //.fvmLaplacian(Dpsif, psi)
231 surfaceScalarField phiBD(psiConvectionDiffusion.flux());
233 surfaceScalarField& phiCorr = phiPsi;
236 for (label i=0; i<maxIter; i++)
240 allLambda = allCoLambda;
259 psiConvectionDiffusion + fvc::div(lambda*phiCorr),
263 scalar maxPsiM1 = gMax(psi.internalField()) - 1.0;
264 scalar minPsi = gMin(psi.internalField());
266 scalar unboundedness = max(max(maxPsiM1, 0.0), -min(minPsi, 0.0));
268 if (unboundedness < maxUnboundedness)
274 Info<< "MULES: max(" << psi.name() << " - 1) = " << maxPsiM1
275 << " min(" << psi.name() << ") = " << minPsi << endl;
277 phiBD = psiConvectionDiffusion.flux();
280 word gammaScheme("div(phi,gamma)");
281 word gammarScheme("div(phirb,gamma)");
283 const surfaceScalarField& phir =
284 mesh.lookupObject<surfaceScalarField>("phir");
295 -fvc::flux(-phir, scalar(1) - psi, gammarScheme),
304 phiPsi = psiConvectionDiffusion.flux() + lambda*phiCorr;
308 template<class RhoType, class SpType, class SuType>
309 void Foam::MULES::limiter
311 scalarField& allLambda,
313 const volScalarField& psi,
314 const surfaceScalarField& phiBD,
315 const surfaceScalarField& phiCorr,
320 const label nLimiterIter
323 const scalarField& psiIf = psi;
324 const volScalarField::GeometricBoundaryField& psiBf = psi.boundaryField();
326 const scalarField& psi0 = psi.oldTime();
328 const fvMesh& mesh = psi.mesh();
330 const labelUList& owner = mesh.owner();
331 const labelUList& neighb = mesh.neighbour();
332 tmp<volScalarField::DimensionedInternalField> tVsc = mesh.Vsc();
333 const scalarField& V = tVsc();
335 const volScalarField& rDeltaT =
336 mesh.objectRegistry::lookupObject<volScalarField>("rSubDeltaT");
338 const scalarField& phiBDIf = phiBD;
339 const surfaceScalarField::GeometricBoundaryField& phiBDBf =
340 phiBD.boundaryField();
342 const scalarField& phiCorrIf = phiCorr;
343 const surfaceScalarField::GeometricBoundaryField& phiCorrBf =
344 phiCorr.boundaryField();
346 slicedSurfaceScalarField lambda
351 mesh.time().timeName(),
360 false // Use slices for the couples
363 scalarField& lambdaIf = lambda;
364 surfaceScalarField::GeometricBoundaryField& lambdaBf =
365 lambda.boundaryField();
367 scalarField psiMaxn(psiIf.size(), psiMin);
368 scalarField psiMinn(psiIf.size(), psiMax);
370 scalarField sumPhiBD(psiIf.size(), 0.0);
372 scalarField sumPhip(psiIf.size(), VSMALL);
373 scalarField mSumPhim(psiIf.size(), VSMALL);
375 forAll(phiCorrIf, facei)
377 label own = owner[facei];
378 label nei = neighb[facei];
380 psiMaxn[own] = max(psiMaxn[own], psiIf[nei]);
381 psiMinn[own] = min(psiMinn[own], psiIf[nei]);
383 psiMaxn[nei] = max(psiMaxn[nei], psiIf[own]);
384 psiMinn[nei] = min(psiMinn[nei], psiIf[own]);
386 sumPhiBD[own] += phiBDIf[facei];
387 sumPhiBD[nei] -= phiBDIf[facei];
389 scalar phiCorrf = phiCorrIf[facei];
393 sumPhip[own] += phiCorrf;
394 mSumPhim[nei] += phiCorrf;
398 mSumPhim[own] -= phiCorrf;
399 sumPhip[nei] -= phiCorrf;
403 forAll(phiCorrBf, patchi)
405 const fvPatchScalarField& psiPf = psiBf[patchi];
406 const scalarField& phiBDPf = phiBDBf[patchi];
407 const scalarField& phiCorrPf = phiCorrBf[patchi];
409 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
413 scalarField psiPNf(psiPf.patchNeighbourField());
415 forAll(phiCorrPf, pFacei)
417 label pfCelli = pFaceCells[pFacei];
419 psiMaxn[pfCelli] = max(psiMaxn[pfCelli], psiPNf[pFacei]);
420 psiMinn[pfCelli] = min(psiMinn[pfCelli], psiPNf[pFacei]);
425 forAll(phiCorrPf, pFacei)
427 label pfCelli = pFaceCells[pFacei];
429 psiMaxn[pfCelli] = max(psiMaxn[pfCelli], psiPf[pFacei]);
430 psiMinn[pfCelli] = min(psiMinn[pfCelli], psiPf[pFacei]);
434 forAll(phiCorrPf, pFacei)
436 label pfCelli = pFaceCells[pFacei];
438 sumPhiBD[pfCelli] += phiBDPf[pFacei];
440 scalar phiCorrf = phiCorrPf[pFacei];
444 sumPhip[pfCelli] += phiCorrf;
448 mSumPhim[pfCelli] -= phiCorrf;
453 psiMaxn = min(psiMaxn, psiMax);
454 psiMinn = max(psiMinn, psiMin);
456 //scalar smooth = 0.5;
457 //psiMaxn = min((1.0 - smooth)*psiIf + smooth*psiMaxn, psiMax);
458 //psiMinn = max((1.0 - smooth)*psiIf + smooth*psiMinn, psiMin);
462 tmp<volScalarField::DimensionedInternalField> V0 = mesh.Vsc0();
465 V*((rho*rDeltaT - Sp)*psiMaxn - Su)
466 - (V0()*rDeltaT)*rho.oldTime()*psi0
470 V*(Su - (rho*rDeltaT - Sp)*psiMinn)
471 + (V0*rDeltaT)*rho.oldTime()*psi0
477 V*((rho*rDeltaT - Sp)*psiMaxn - (rho.oldTime()*rDeltaT)*psi0 - Su)
481 V*((rho*rDeltaT)*psi0 - (rho.oldTime()*rDeltaT - Sp)*psiMinn + Su)
485 scalarField sumlPhip(psiIf.size());
486 scalarField mSumlPhim(psiIf.size());
488 for(int j=0; j<nLimiterIter; j++)
493 forAll(lambdaIf, facei)
495 label own = owner[facei];
496 label nei = neighb[facei];
498 scalar lambdaPhiCorrf = lambdaIf[facei]*phiCorrIf[facei];
500 if (lambdaPhiCorrf > 0.0)
502 sumlPhip[own] += lambdaPhiCorrf;
503 mSumlPhim[nei] += lambdaPhiCorrf;
507 mSumlPhim[own] -= lambdaPhiCorrf;
508 sumlPhip[nei] -= lambdaPhiCorrf;
512 forAll(lambdaBf, patchi)
514 scalarField& lambdaPf = lambdaBf[patchi];
515 const scalarField& phiCorrfPf = phiCorrBf[patchi];
517 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
519 forAll(lambdaPf, pFacei)
521 label pfCelli = pFaceCells[pFacei];
523 scalar lambdaPhiCorrf = lambdaPf[pFacei]*phiCorrfPf[pFacei];
525 if (lambdaPhiCorrf > 0.0)
527 sumlPhip[pfCelli] += lambdaPhiCorrf;
531 mSumlPhim[pfCelli] -= lambdaPhiCorrf;
536 forAll (sumlPhip, celli)
541 (sumlPhip[celli] + psiMaxn[celli])/mSumPhim[celli],
548 (mSumlPhim[celli] + psiMinn[celli])/sumPhip[celli],
553 const scalarField& lambdam = sumlPhip;
554 const scalarField& lambdap = mSumlPhim;
556 forAll(lambdaIf, facei)
558 if (phiCorrIf[facei] > 0.0)
560 lambdaIf[facei] = min
563 min(lambdap[owner[facei]], lambdam[neighb[facei]])
568 lambdaIf[facei] = min
571 min(lambdam[owner[facei]], lambdap[neighb[facei]])
577 forAll(lambdaBf, patchi)
579 fvsPatchScalarField& lambdaPf = lambdaBf[patchi];
580 const scalarField& phiCorrfPf = phiCorrBf[patchi];
582 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
584 forAll(lambdaPf, pFacei)
586 label pfCelli = pFaceCells[pFacei];
588 if (phiCorrfPf[pFacei] > 0.0)
590 lambdaPf[pFacei] = min(lambdaPf[pFacei], lambdap[pfCelli]);
594 lambdaPf[pFacei] = min(lambdaPf[pFacei], lambdam[pfCelli]);
599 syncTools::syncFaceList(mesh, allLambda, minEqOp<scalar>());
604 // ************************************************************************* //