1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
29 #include "uncorrectedSnGrad.H"
30 #include "gaussConvectionScheme.H"
31 #include "gaussLaplacianScheme.H"
32 #include "uncorrectedSnGrad.H"
33 #include "surfaceInterpolate.H"
34 #include "fvcSurfaceIntegrate.H"
35 #include "slicedSurfaceFields.H"
36 #include "syncTools.H"
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 template<class RhoType, class SpType, class SuType>
43 void Foam::MULES::explicitSolve
47 const surfaceScalarField& phi,
48 surfaceScalarField& phiPsi,
55 Info<< "MULES: Solving for " << psi.name() << endl;
57 const fvMesh& mesh = psi.mesh();
58 psi.correctBoundaryConditions();
60 surfaceScalarField phiBD = upwind<scalar>(psi.mesh(), phi).flux(psi);
62 surfaceScalarField& phiCorr = phiPsi;
65 scalarField allLambda(mesh.nFaces(), 1.0);
67 slicedSurfaceScalarField lambda
72 mesh.time().timeName(),
81 false // Use slices for the couples
98 phiPsi = phiBD + lambda*phiCorr;
100 scalarField& psiIf = psi;
101 const scalarField& psi0 = psi.oldTime();
102 const scalar deltaT = mesh.time().deltaT().value();
105 fvc::surfaceIntegrate(psiIf, phiPsi);
111 mesh.V0()*rho.oldTime()*psi0/(deltaT*mesh.V())
114 )/(rho/deltaT - Sp.field());
120 rho.oldTime()*psi0/deltaT
123 )/(rho/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 =
146 mesh.solverDict(psi.name()).subDict("MULESImplicit");
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 =
172 mesh.time().deltaT()*mesh.surfaceInterpolation::deltaCoeffs()
173 *mag(phi)/mesh.magSf();
175 slicedSurfaceScalarField CoLambda
180 mesh.time().timeName(),
189 false // Use slices for the couples
192 CoLambda == 1.0/max(CoCoeff*Cof, scalar(1));
195 scalarField allLambda(allCoLambda);
196 //scalarField allLambda(mesh.nFaces(), 1.0);
198 slicedSurfaceScalarField lambda
203 mesh.time().timeName(),
212 false // Use slices for the couples
215 linear<scalar> CDs(mesh);
216 upwind<scalar> UDs(mesh, phi);
217 //fv::uncorrectedSnGrad<scalar> snGrads(mesh);
219 fvScalarMatrix psiConvectionDiffusion
222 + fv::gaussConvectionScheme<scalar>(mesh, phi, UDs).fvmDiv(phi, psi)
223 //- fv::gaussLaplacianScheme<scalar, scalar>(mesh, CDs, snGrads)
224 //.fvmLaplacian(Dpsif, psi)
229 surfaceScalarField phiBD = psiConvectionDiffusion.flux();
231 surfaceScalarField& phiCorr = phiPsi;
234 for (label i=0; i<maxIter; i++)
238 allLambda = allCoLambda;
257 psiConvectionDiffusion + fvc::div(lambda*phiCorr),
258 MULEScontrols.lookup("solver")
261 scalar maxPsiM1 = gMax(psi.internalField()) - 1.0;
262 scalar minPsi = gMin(psi.internalField());
264 scalar unboundedness = max(max(maxPsiM1, 0.0), -min(minPsi, 0.0));
266 if (unboundedness < maxUnboundedness)
272 Info<< "MULES: max(" << psi.name() << " - 1) = " << maxPsiM1
273 << " min(" << psi.name() << ") = " << minPsi << endl;
275 phiBD = psiConvectionDiffusion.flux();
278 word gammaScheme("div(phi,gamma)");
279 word gammarScheme("div(phirb,gamma)");
281 const surfaceScalarField& phir =
282 mesh.lookupObject<surfaceScalarField>("phir");
293 -fvc::flux(-phir, scalar(1) - psi, gammarScheme),
302 phiPsi = psiConvectionDiffusion.flux() + lambda*phiCorr;
306 template<class RhoType, class SpType, class SuType>
307 void Foam::MULES::limiter
309 scalarField& allLambda,
311 const volScalarField& psi,
312 const surfaceScalarField& phiBD,
313 const surfaceScalarField& phiCorr,
318 const label nLimiterIter
321 const scalarField& psiIf = psi;
322 const volScalarField::GeometricBoundaryField& psiBf = psi.boundaryField();
324 const scalarField& psi0 = psi.oldTime();
326 const fvMesh& mesh = psi.mesh();
328 const unallocLabelList& owner = mesh.owner();
329 const unallocLabelList& neighb = mesh.neighbour();
330 const scalarField& V = mesh.V();
331 const scalar deltaT = mesh.time().deltaT().value();
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 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);
458 V*((rho/deltaT - Sp)*psiMaxn - Su)
459 - (mesh.V0()/deltaT)*rho.oldTime()*psi0
463 V*(Su - (rho/deltaT - Sp)*psiMinn)
464 + (mesh.V0()/deltaT)*rho.oldTime()*psi0
470 V*((rho/deltaT - Sp)*psiMaxn - (rho.oldTime()/deltaT)*psi0 - Su)
474 V*((rho/deltaT)*psi0 - (rho.oldTime()/deltaT - Sp)*psiMinn + Su)
478 scalarField sumlPhip(psiIf.size());
479 scalarField mSumlPhim(psiIf.size());
481 for(int j=0; j<nLimiterIter; j++)
486 forAll(lambdaIf, facei)
488 label own = owner[facei];
489 label nei = neighb[facei];
491 scalar lambdaPhiCorrf = lambdaIf[facei]*phiCorrIf[facei];
493 if (lambdaPhiCorrf > 0.0)
495 sumlPhip[own] += lambdaPhiCorrf;
496 mSumlPhim[nei] += lambdaPhiCorrf;
500 mSumlPhim[own] -= lambdaPhiCorrf;
501 sumlPhip[nei] -= lambdaPhiCorrf;
505 forAll(lambdaBf, patchi)
507 scalarField& lambdaPf = lambdaBf[patchi];
508 const scalarField& phiCorrfPf = phiCorrBf[patchi];
510 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
512 forAll(lambdaPf, pFacei)
514 label pfCelli = pFaceCells[pFacei];
516 scalar lambdaPhiCorrf = lambdaPf[pFacei]*phiCorrfPf[pFacei];
518 if (lambdaPhiCorrf > 0.0)
520 sumlPhip[pfCelli] += lambdaPhiCorrf;
524 mSumlPhim[pfCelli] -= lambdaPhiCorrf;
529 forAll (sumlPhip, celli)
534 (sumlPhip[celli] + psiMaxn[celli])/mSumPhim[celli],
541 (mSumlPhim[celli] + psiMinn[celli])/sumPhip[celli],
546 const scalarField& lambdam = sumlPhip;
547 const scalarField& lambdap = mSumlPhim;
549 forAll(lambdaIf, facei)
551 if (phiCorrIf[facei] > 0.0)
553 lambdaIf[facei] = min
556 min(lambdap[owner[facei]], lambdam[neighb[facei]])
561 lambdaIf[facei] = min
564 min(lambdam[owner[facei]], lambdap[neighb[facei]])
570 forAll(lambdaBf, patchi)
572 fvsPatchScalarField& lambdaPf = lambdaBf[patchi];
573 const scalarField& phiCorrfPf = phiCorrBf[patchi];
575 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
577 forAll(lambdaPf, pFacei)
579 label pfCelli = pFaceCells[pFacei];
581 if (phiCorrfPf[pFacei] > 0.0)
583 lambdaPf[pFacei] = min(lambdaPf[pFacei], lambdap[pfCelli]);
587 lambdaPf[pFacei] = min(lambdaPf[pFacei], lambdam[pfCelli]);
592 syncTools::syncFaceList(mesh, allLambda, minEqOp<scalar>(), false);
597 // ************************************************************************* //