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 = 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 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 unallocLabelList& owner = mesh.owner();
328 const unallocLabelList& neighb = mesh.neighbour();
329 const scalarField& V = mesh.V();
330 const scalar deltaT = mesh.time().deltaT().value();
332 const scalarField& phiBDIf = phiBD;
333 const surfaceScalarField::GeometricBoundaryField& phiBDBf =
334 phiBD.boundaryField();
336 const scalarField& phiCorrIf = phiCorr;
337 const surfaceScalarField::GeometricBoundaryField& phiCorrBf =
338 phiCorr.boundaryField();
340 slicedSurfaceScalarField lambda
345 mesh.time().timeName(),
354 false // Use slices for the couples
357 scalarField& lambdaIf = lambda;
358 surfaceScalarField::GeometricBoundaryField& lambdaBf =
359 lambda.boundaryField();
361 scalarField psiMaxn(psiIf.size(), psiMin);
362 scalarField psiMinn(psiIf.size(), psiMax);
364 scalarField sumPhiBD(psiIf.size(), 0.0);
366 scalarField sumPhip(psiIf.size(), VSMALL);
367 scalarField mSumPhim(psiIf.size(), VSMALL);
369 forAll(phiCorrIf, facei)
371 label own = owner[facei];
372 label nei = neighb[facei];
374 psiMaxn[own] = max(psiMaxn[own], psiIf[nei]);
375 psiMinn[own] = min(psiMinn[own], psiIf[nei]);
377 psiMaxn[nei] = max(psiMaxn[nei], psiIf[own]);
378 psiMinn[nei] = min(psiMinn[nei], psiIf[own]);
380 sumPhiBD[own] += phiBDIf[facei];
381 sumPhiBD[nei] -= phiBDIf[facei];
383 scalar phiCorrf = phiCorrIf[facei];
387 sumPhip[own] += phiCorrf;
388 mSumPhim[nei] += phiCorrf;
392 mSumPhim[own] -= phiCorrf;
393 sumPhip[nei] -= phiCorrf;
397 forAll(phiCorrBf, patchi)
399 const fvPatchScalarField& psiPf = psiBf[patchi];
400 const scalarField& phiBDPf = phiBDBf[patchi];
401 const scalarField& phiCorrPf = phiCorrBf[patchi];
403 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
407 scalarField psiPNf = psiPf.patchNeighbourField();
409 forAll(phiCorrPf, pFacei)
411 label pfCelli = pFaceCells[pFacei];
413 psiMaxn[pfCelli] = max(psiMaxn[pfCelli], psiPNf[pFacei]);
414 psiMinn[pfCelli] = min(psiMinn[pfCelli], psiPNf[pFacei]);
419 forAll(phiCorrPf, pFacei)
421 label pfCelli = pFaceCells[pFacei];
423 psiMaxn[pfCelli] = max(psiMaxn[pfCelli], psiPf[pFacei]);
424 psiMinn[pfCelli] = min(psiMinn[pfCelli], psiPf[pFacei]);
428 forAll(phiCorrPf, pFacei)
430 label pfCelli = pFaceCells[pFacei];
432 sumPhiBD[pfCelli] += phiBDPf[pFacei];
434 scalar phiCorrf = phiCorrPf[pFacei];
438 sumPhip[pfCelli] += phiCorrf;
442 mSumPhim[pfCelli] -= phiCorrf;
447 psiMaxn = min(psiMaxn, psiMax);
448 psiMinn = max(psiMinn, psiMin);
450 //scalar smooth = 0.5;
451 //psiMaxn = min((1.0 - smooth)*psiIf + smooth*psiMaxn, psiMax);
452 //psiMinn = max((1.0 - smooth)*psiIf + smooth*psiMinn, psiMin);
457 V*((rho/deltaT - Sp)*psiMaxn - Su)
458 - (mesh.V0()/deltaT)*rho.oldTime()*psi0
462 V*(Su - (rho/deltaT - Sp)*psiMinn)
463 + (mesh.V0()/deltaT)*rho.oldTime()*psi0
469 V*((rho/deltaT - Sp)*psiMaxn - (rho.oldTime()/deltaT)*psi0 - Su)
473 V*((rho/deltaT)*psi0 - (rho.oldTime()/deltaT - Sp)*psiMinn + Su)
477 scalarField sumlPhip(psiIf.size());
478 scalarField mSumlPhim(psiIf.size());
480 for(int j=0; j<nLimiterIter; j++)
485 forAll(lambdaIf, facei)
487 label own = owner[facei];
488 label nei = neighb[facei];
490 scalar lambdaPhiCorrf = lambdaIf[facei]*phiCorrIf[facei];
492 if (lambdaPhiCorrf > 0.0)
494 sumlPhip[own] += lambdaPhiCorrf;
495 mSumlPhim[nei] += lambdaPhiCorrf;
499 mSumlPhim[own] -= lambdaPhiCorrf;
500 sumlPhip[nei] -= lambdaPhiCorrf;
504 forAll(lambdaBf, patchi)
506 scalarField& lambdaPf = lambdaBf[patchi];
507 const scalarField& phiCorrfPf = phiCorrBf[patchi];
509 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
511 forAll(lambdaPf, pFacei)
513 label pfCelli = pFaceCells[pFacei];
515 scalar lambdaPhiCorrf = lambdaPf[pFacei]*phiCorrfPf[pFacei];
517 if (lambdaPhiCorrf > 0.0)
519 sumlPhip[pfCelli] += lambdaPhiCorrf;
523 mSumlPhim[pfCelli] -= lambdaPhiCorrf;
528 forAll (sumlPhip, celli)
533 (sumlPhip[celli] + psiMaxn[celli])/mSumPhim[celli],
540 (mSumlPhim[celli] + psiMinn[celli])/sumPhip[celli],
545 const scalarField& lambdam = sumlPhip;
546 const scalarField& lambdap = mSumlPhim;
548 forAll(lambdaIf, facei)
550 if (phiCorrIf[facei] > 0.0)
552 lambdaIf[facei] = min
555 min(lambdap[owner[facei]], lambdam[neighb[facei]])
560 lambdaIf[facei] = min
563 min(lambdam[owner[facei]], lambdap[neighb[facei]])
569 forAll(lambdaBf, patchi)
571 fvsPatchScalarField& lambdaPf = lambdaBf[patchi];
572 const scalarField& phiCorrfPf = phiCorrBf[patchi];
574 const labelList& pFaceCells = mesh.boundary()[patchi].faceCells();
576 forAll(lambdaPf, pFacei)
578 label pfCelli = pFaceCells[pFacei];
580 if (phiCorrfPf[pFacei] > 0.0)
582 lambdaPf[pFacei] = min(lambdaPf[pFacei], lambdap[pfCelli]);
586 lambdaPf[pFacei] = min(lambdaPf[pFacei], lambdam[pfCelli]);
591 syncTools::syncFaceList(mesh, allLambda, minEqOp<scalar>(), false);
596 // ************************************************************************* //