vector horizontalVelocityField::streamfunctionAt
(
        const point& p,
        const Time& t
) const
{
    const vector unitNormal(0, -1, 0);
    const dimensionedScalar z("z", dimLength, p.z());

    dimensionedScalar psi("psi", cmptMultiply(dimVelocity, dimLength), scalar(0));
    if (z.value() <= z1.value())
    {
        // psi is zero
    }
    else if (z.value() <= z2.value())
    {
        psi = -0.5*u0*(z - z1 - (z2-z1)/M_PI*Foam::sin(M_PI*(z-z1)/(z2-z1)));
    }
    else 
    {
        psi = -0.5*u0*(2*z - z2 - z1);
    }

    return unitNormal * psi.value();
}
void Foam::bound(volScalarField& vsf, const dimensionedScalar& vsf0)
{
    scalar minVsf = min(vsf).value();

    if (minVsf < vsf0.value())
    {
        Info<< "bounding " << vsf.name()
            << ", min: " << gMin(vsf.internalField())
            << " max: " << gMax(vsf.internalField())
            << " average: " << gAverage(vsf.internalField())
            << endl;

        vsf.internalField() = max
        (
            max
            (
                vsf.internalField(),
                fvc::average(max(vsf, vsf0))().internalField()
                // Bug fix: was assuming bound on zero.  HJ, 25/Nov/2008
                *pos(vsf0.value() - vsf.internalField())
            ),
            vsf0.value()
        );

        vsf.correctBoundaryConditions();
        vsf.boundaryField() = max(vsf.boundaryField(), vsf0.value());
    }
}
void geostrophicZeroFluxFvPatchScalarField::updateCoeffs()
{
    if (updated())
    {
        return;
    }

    const dictionary& environmentalProperties
        = db().lookupObject<IOdictionary>("environmentalProperties");

    const dimensionedScalar g(environmentalProperties.lookup("g"));
    const dimensionedScalar beta(environmentalProperties.lookup("beta"));
    const dimensionedScalar f0(environmentalProperties.lookup("f0"));
    const vector OmegaHat(environmentalProperties.lookup("OmegaHat"));

    const surfaceVectorField& Uf
        = db().lookupObject<surfaceVectorField>("Uf");
    const fvsPatchField<vector> Ufp
        = patch().patchField<surfaceVectorField, vector>(Uf);

    const surfaceVectorField& Cf = Uf.mesh().Cf();
    fvsPatchField<vector> Cfp =
        patch().patchField<surfaceVectorField, vector>(Cf);

    gradient() = -(f0.value() + beta.value()*Cfp.component(vector::Y))*
                 ((OmegaHat ^ Ufp) & patch().nf())/g.value();
    
    fixedGradientFvPatchScalarField::updateCoeffs();
}
tmp<fvMatrix<Type>>
EulerD2dt2Scheme<Type>::fvmD2dt2
(
    const dimensionedScalar& rho,
    const GeometricField<Type, fvPatchField, volMesh>& vf
)
{
    tmp<fvMatrix<Type>> tfvm
    (
        new fvMatrix<Type>
        (
            vf,
            rho.dimensions()*vf.dimensions()*dimVol
            /dimTime/dimTime
        )
    );

    fvMatrix<Type>& fvm = tfvm.ref();

    scalar deltaT = mesh().time().deltaTValue();
    scalar deltaT0 = mesh().time().deltaT0Value();

    scalar coefft   = (deltaT + deltaT0)/(2*deltaT);
    scalar coefft00 = (deltaT + deltaT0)/(2*deltaT0);

    scalar rDeltaT2 = 4.0/sqr(deltaT + deltaT0);

    if (mesh().moving())
    {
        scalar halfRdeltaT2 = 0.5*rDeltaT2;

        const scalarField VV0(mesh().V() + mesh().V0());
        const scalarField V0V00(mesh().V0() + mesh().V00());

        fvm.diag() = rho.value()*(coefft*halfRdeltaT2)*VV0;

        fvm.source() = halfRdeltaT2*rho.value()*
        (
            (coefft*VV0 + coefft00*V0V00)
           *vf.oldTime().primitiveField()

          - (coefft00*V0V00)*vf.oldTime().oldTime().primitiveField()
        );
    }
    else
    {
        fvm.diag() = (coefft*rDeltaT2)*mesh().V()*rho.value();

        fvm.source() = rDeltaT2*mesh().V()*rho.value()*
        (
            (coefft + coefft00)*vf.oldTime().primitiveField()
          - coefft00*vf.oldTime().oldTime().primitiveField()
        );
    }

    return tfvm;
}
tmp<GeometricField<Type, fvPatchField, volMesh> >
EulerLocalDdtScheme<Type>::fvcDdt
(
    const dimensionedScalar& rho,
    const GeometricField<Type, fvPatchField, volMesh>& vf
)
{
    const objectRegistry& registry = this->mesh();

    // get access to the scalar beta[i]
    const scalarField& beta =
        registry.lookupObject<scalarField>(deltaTName_);

    volScalarField rDeltaT =
        1.0/(beta[0]*registry.lookupObject<volScalarField>(deltaTauName_));

    IOobject ddtIOobject
    (
        "ddt("+rho.name()+','+vf.name()+')',
        mesh().time().timeName(),
        mesh()
    );

    if (mesh().moving())
    {
        return tmp<GeometricField<Type, fvPatchField, volMesh> >
        (
            new GeometricField<Type, fvPatchField, volMesh>
            (
                ddtIOobject,
                mesh(),
                rDeltaT.dimensions()*rho.dimensions()*vf.dimensions(),
                rDeltaT.internalField()*rho.value()*
                (
                    vf.internalField()
                  - vf.oldTime().internalField()*mesh().V0()/mesh().V()
                ),
                rDeltaT.boundaryField()*rho.value()*
                (
                    vf.boundaryField() - vf.oldTime().boundaryField()
                )
            )
        );
    }
    else
    {
        return tmp<GeometricField<Type, fvPatchField, volMesh> >
        (
            new GeometricField<Type, fvPatchField, volMesh>
            (
                ddtIOobject,
                rDeltaT*rho*(vf - vf.oldTime())
            )
        );
    }
}
Foam::tmp<Foam::volScalarField> Foam::SrivastavaSundaresanFrictionalStress::muf
(
    const volScalarField& alpha,
    const volScalarField& Theta,
    const dimensionedScalar& alphaMinFriction,
    const dimensionedScalar& alphaMax,
    const volScalarField& pf,
    const volSymmTensorField& D,
    const dimensionedScalar& phi
) const
{
    const scalar I2Dsmall = 1.0e-35;

    //Creating muf assuming it should be 0 on the boundary which may not be
    // true
    tmp<volScalarField> tmuf
    (
       new volScalarField
       (
          IOobject
          (
             "muf",
             alpha.mesh().time().timeName(),
             alpha.mesh()
          ),
          alpha.mesh(),
          dimensionedScalar("muf", dimensionSet(1, -1, -1, 0, 0), 1e30)
       )
    );
    
    volScalarField& muff = tmuf();
   
      forAll (D, celli)
    {
        if (alpha[celli] >= alphaMinFriction.value())
        {
            muff[celli] =
                0.5*pf[celli]*sin(phi.value())
               /(
                    sqrt(1.0/6.0*(sqr(D[celli].xx() - D[celli].yy())
                  + sqr(D[celli].yy() - D[celli].zz())
                  + sqr(D[celli].zz() - D[celli].xx()))
                  + sqr(D[celli].xy()) + sqr(D[celli].xz())
                  + sqr(D[celli].yz())) + I2Dsmall
                );
        }
        if (alpha[celli] < alphaMinFriction.value())
        {
            muff[celli] = 0.0;
        }
    }

    muff.correctBoundaryConditions();

    return tmuf;
}
Foam::tmp<Foam::volScalarField> Foam::SchaefferFrictionalStress::muf
(
    const volScalarField& alpha,
    const dimensionedScalar& alphaMax,
    const volScalarField& pf,
    const volTensorField& D,
    const dimensionedScalar& phi
) const
{
    const scalar I2Dsmall = 1.0e-15;

    // Creating muf assuming it should be 0 on the boundary which may not be
    // true
    tmp<volScalarField> tmuf
    (
        new volScalarField
        (
            IOobject
            (
                "muf",
                alpha.mesh().time().timeName(),
                alpha.mesh()
            ),
            alpha.mesh(),
            dimensionedScalar("muf", dimensionSet(1, -1, -1, 0, 0), 0.0)
        )
    );

    volScalarField& muff = tmuf();

    forAll (D, celli)
    {
        if (alpha[celli] > alphaMax.value()-5e-2)
        {
            muff[celli] =
                0.5*pf[celli]*sin(phi.value())
               /(
                    sqrt(1.0/6.0*(sqr(D[celli].xx() - D[celli].yy())
                  + sqr(D[celli].yy() - D[celli].zz())
                  + sqr(D[celli].zz() - D[celli].xx()))
                  + sqr(D[celli].xy()) + sqr(D[celli].xz())
                  + sqr(D[celli].yz())) + I2Dsmall
                );
        }
    }

    return tmuf;
}
tmp<DimensionedField<scalar, GeoMesh> > pow
(
    const dimensionedScalar& ds,
    const DimensionedField<scalar, GeoMesh>& dsf
)
{
    tmp<DimensionedField<scalar, GeoMesh> > tPow
    (
        new DimensionedField<scalar, GeoMesh>
        (
            IOobject
            (
                "pow(" + ds.name() + ',' + dsf.name() + ')',
                dsf.instance(),
                dsf.db()
            ),
            dsf.mesh(),
            pow(ds, dsf.dimensions())
        )
    );

    pow(tPow().getField(), ds.value(), dsf.getField());

    return tPow;
}
void fixedFluxBuoyantExnerFvPatchScalarField::updateCoeffs()
{
    if (updated())
    {
        return;
    }

    const dictionary& environmentalProperties
        = db().lookupObject<IOdictionary>("environmentalProperties");

    const dictionary& thermoProperties
        = db().lookupObject<IOdictionary>("thermophysicalProperties");

    dimensionedVector g(environmentalProperties.lookup("g"));

    const constTransport<hConstThermo<perfectGas<specie> > > air
    (
         thermoProperties.subDict("mixture")
    );

    const dimensionedScalar Cp("Cp", dimGasConstant, air.Cp(0,0));

    const fvsPatchField<scalar>& thetaf =
        patch().lookupPatchField<surfaceScalarField, scalar>("thetaf");

    gradient() = (g.value() & patch().nf())/(Cp.value()*thetaf);
    
    fixedGradientFvPatchScalarField::updateCoeffs();
}
tmp<DimensionedField<scalar, GeoMesh> > atan2
(
    const dimensionedScalar& ds,
    const DimensionedField<scalar, GeoMesh>& dsf
)
{
    tmp<DimensionedField<scalar, GeoMesh> > tAtan2
    (
        new DimensionedField<scalar, GeoMesh>
        (
            IOobject
            (
                "atan2(" + ds.name() + ',' + dsf.name() + ')',
                dsf.instance(),
                dsf.db()
            ),
            dsf.mesh(),
            atan2(ds, dsf.dimensions())
        )
    );

    atan2(tAtan2().getField(), ds.value(), dsf.getField());

    return tAtan2;
}
Beispiel #11
0
Foam::dimensionSet Foam::pow
(
    const dimensionSet& ds,
    const dimensionedScalar& dS
)
{
    if (dimensionSet::debug && !dS.dimensions().dimensionless())
    {
        FatalErrorInFunction
            << "Exponent of pow is not dimensionless"
            << abort(FatalError);
    }

    dimensionSet dimPow
    (
        ds[dimensionSet::MASS]*dS.value(),
        ds[dimensionSet::LENGTH]*dS.value(),
        ds[dimensionSet::TIME]*dS.value(),
        ds[dimensionSet::TEMPERATURE]*dS.value(),
        ds[dimensionSet::MOLES]*dS.value(),
        ds[dimensionSet::CURRENT]*dS.value(),
        ds[dimensionSet::LUMINOUS_INTENSITY]*dS.value()
    );

    return dimPow;
}
Foam::tmp<Foam::volScalarField>
Foam::kineticTheoryModels::frictionalStressModels::Schaeffer::nu
(
    const volScalarField& alpha1,
    const dimensionedScalar& alphaMax,
    const volScalarField& pf,
    const volSymmTensorField& D
) const
{
    const scalar I2Dsmall = 1.0e-15;

    // Creating nu assuming it should be 0 on the boundary which may not be
    // true
    tmp<volScalarField> tnu
    (
        new volScalarField
        (
            IOobject
            (
                "Schaeffer:nu",
                alpha1.mesh().time().timeName(),
                alpha1.mesh(),
                IOobject::NO_READ,
                IOobject::NO_WRITE,
                false
            ),
            alpha1.mesh(),
            dimensionedScalar("nu", dimensionSet(0, 2, -1, 0, 0), 0.0)
        )
    );

    volScalarField& nuf = tnu();

    forAll (D, celli)
    {
        if (alpha1[celli] > alphaMax.value() - 5e-2)
        {
            nuf[celli] =
                0.5*pf[celli]*sin(phi_.value())
               /(
                    sqrt(1.0/6.0*(sqr(D[celli].xx() - D[celli].yy())
                  + sqr(D[celli].yy() - D[celli].zz())
                  + sqr(D[celli].zz() - D[celli].xx()))
                  + sqr(D[celli].xy()) + sqr(D[celli].xz())
                  + sqr(D[celli].yz())) + I2Dsmall
                );
        }
    }

    // Correct coupled BCs
    nuf.correctBoundaryConditions();

    return tnu;
}
tmp<fvMatrix<Type> >
EulerLocalDdtScheme<Type>::fvmDdt
(
    const dimensionedScalar& rho,
    GeometricField<Type, fvPatchField, volMesh>& vf
)
{
    const objectRegistry& registry = this->mesh();

    // get access to the scalar beta[i]
    const scalarField& beta =
        registry.lookupObject<scalarField>(deltaTName_);

    tmp<fvMatrix<Type> > tfvm
    (
        new fvMatrix<Type>
        (
            vf,
            rho.dimensions()*vf.dimensions()*dimVol/dimTime
        )
    );
    fvMatrix<Type>& fvm = tfvm();

    scalarField rDeltaT =
        1.0/(beta[0]*registry.lookupObject<volScalarField>(deltaTauName_).internalField());

    fvm.diag() = rDeltaT*rho.value()*mesh().V();

    if (mesh().moving())
    {
        fvm.source() = rDeltaT
            *rho.value()*vf.oldTime().internalField()*mesh().V0();
    }
    else
    {
        fvm.source() = rDeltaT
            *rho.value()*vf.oldTime().internalField()*mesh().V();
    }

    return tfvm;
}
point horizontalVelocityField::initialPositionOf
(
    const point& p,
    const Time& t
) const
{
    const dimensionedScalar z("z", dimLength, p.z());

    if (z.value() <= z1.value())
    {
        return p;
    }
    else if (z.value() <= z2.value())
    {
        return point(p.x() - (u0*sqr(Foam::sin(0.5*M_PI*(z-z1)/(z2-z1)))*t).value(), p.y(), p.z());
    }
    else
    {
        return point(p.x() - u0.value()*t.value(), p.y(), p.z());
    }
}
vector geodesicSolidBodyVelocityField::streamfunctionAt
(
        const point& p,
        const Time& t
) const
{
    const dimensionedScalar T = (endTime.value() == -1 ) ? t.endTime() : endTime;
    const scalar u0 = 2 * M_PI * radius.value() / T.value();
    const polarPoint& polarp = convertToPolar(p);
    const scalar lat = polarp.lat();
    const scalar lon = polarp.lon();

    const scalar psi = - u0 * (Foam::sin(lat) * Foam::cos(alpha) - Foam::cos(lon) * Foam::cos(lat) * Foam::sin(alpha));

    return p/mag(p) * psi * radius.value();
}
point geodesicSolidBodyVelocityField::initialPositionOf
(
    const point& p,
    const Time& t
) const
{
    // assume alpha = 0
    
    const dimensionedScalar T = (endTime.value() == -1 ) ? t.endTime() : endTime;
    const scalar u0 = 2 * M_PI * radius.value() / T.value();
    const polarPoint& polarp = convertToPolar(p);
    const scalar lat = polarp.lat();
    scalar lon = polarp.lon();

    lon -= u0/radius.value() * t.value(); 

    const polarPoint departureP(lon, lat, radius.value());
    return departureP.cartesian();
}
tmp<DimensionedField<scalar, GeoMesh> > atan2
(
    const dimensionedScalar& ds,
    const tmp<DimensionedField<scalar, GeoMesh> >& tdsf
)
{
    const DimensionedField<scalar, GeoMesh>& dsf = tdsf();

    tmp<DimensionedField<scalar, GeoMesh> > tAtan2 =
        reuseTmpDimensionedField<scalar, scalar, GeoMesh>::New
        (
            tdsf,
            "atan2(" + ds.name() + ',' + dsf.name() + ')',
            atan2(ds, dsf.dimensions())
        );

    atan2(tAtan2().getField(), ds.value(), dsf.getField());

    reuseTmpDimensionedField<scalar, scalar, GeoMesh>::clear(tdsf);

    return tAtan2;
}
tmp<DimensionedField<scalar, GeoMesh> > pow
(
    const dimensionedScalar& ds,
    const tmp<DimensionedField<scalar, GeoMesh> >& tdsf
)
{
    const DimensionedField<scalar, GeoMesh>& dsf = tdsf();

    tmp<DimensionedField<scalar, GeoMesh> > tPow =
        reuseTmpDimensionedField<scalar, scalar, GeoMesh>::New
        (
            tdsf,
            "pow(" + ds.name() + ',' + dsf.name() + ')',
            pow(ds, dsf.dimensions())
        );

    pow(tPow().getField(), ds.value(), dsf.getField());

    reuseTmpDimensionedField<scalar, scalar, GeoMesh>::clear(tdsf);

    return tPow;
}
Beispiel #19
0
Foam::tmp<Foam::fvMatrix<Type>>
Foam::fvm::Sp
(
    const dimensionedScalar& sp,
    const GeometricField<Type, fvPatchField, volMesh>& vf
)
{
    const fvMesh& mesh = vf.mesh();

    tmp<fvMatrix<Type>> tfvm
    (
        new fvMatrix<Type>
        (
            vf,
            dimVol*sp.dimensions()*vf.dimensions()
        )
    );
    fvMatrix<Type>& fvm = tfvm.ref();

    fvm.diag() += mesh.V()*sp.value();

    return tfvm;
}
void Foam::kineticTheoryModel::solve(const volTensorField& gradUat, const volScalarField& kb,const volScalarField& epsilonb,const volScalarField& nutf,const dimensionedScalar& B, const dimensionedScalar& tt)
{
    if (!kineticTheory_)
    {
        return;
    }

    const scalar sqrtPi = sqrt(constant::mathematical::pi);

//    surfaceScalarField phi = 1.5*rhoa_*phia_*fvc::interpolate(max(alpha_,DiluteCut_));
    surfaceScalarField phi = 1.5*rhoa_*phia_*fvc::interpolate((alpha_+1e-8));
    volTensorField dUU = gradUat.T();         //that is fvc::grad(Ua_);
    volSymmTensorField D = symm(dUU);         //0.5*(dU + dU.T)
    volTensorField dU = dUU;//dev(dUU);

    // NB, drag = K*alpha*beta,
    // (the alpha and beta has been extracted from the drag function for
    // numerical reasons)
    // this is inconsistent with momentum equation, since the following form missed
    // the drift velocity
    volScalarField Ur_ = mag(Ua_ - Ub_);
//    volScalarField Ur = mag(Ua_ - Ub_ + nuft/(max(alpha_,1e-9)*(1.0-alpha_))*fvc::grad(alpha_));
//    volScalarField Ur = mag(Ua_ - Ub_ + nuft/(max(alpha_,1e-9))*fvc::grad(alpha_));    
    volScalarField betaPrim = (1.0 - alpha_)*draga_.K(Ur_);

    // Calculating the radial distribution function (solid volume fraction is
    //  limited close to the packing limit, but this needs improvements)
    //  The solution is higly unstable close to the packing limit.
    gs0_ = radialModel_->g0
    (
        min(alpha_, alphaMax_ - 1e-9),
        alphaMax_
    );

    // particle pressure - coefficient in front of Theta (Eq. 3.22, p. 45)
    volScalarField PsCoeff = granularPressureModel_->granularPressureCoeff
    (
        alpha_,
//        (alpha_+1e-12),
        gs0_,
        rhoa_,
        e_
    );

    // 'thermal' conductivity (Table 3.3, p. 49)
    kappa_ = conductivityModel_->kappa(alpha_, Theta_, gs0_, rhoa_, da_, e_);

    // particle viscosity (Table 3.2, p.47)
//    mua_ = viscosityModel_->mua(alpha_, Theta_, gs0_, rhoa_, da_, e_);

    dimensionedScalar Tsmall
    (
        "small",
        dimensionSet(0 , 2 ,-2 ,0 , 0, 0, 0),
        scalar(1.0e-40)
    );

    dimensionedScalar TsmallEqn
    (
        "small",
        dimensionSet(0 , 2 ,-2 ,0 , 0, 0, 0),
        scalar(1.0e-30)
    );

    dimensionedScalar TsmallSqrt = sqrt(Tsmall);

    volScalarField ThetaSqrt = sqrt(Theta_);

    volScalarField muaa = rhoa_*da_*
    (
        (4.0/5.0)*sqr(alpha_)*gs0_*(1.0 + e_)/sqrtPi
      + (1.0/15.0)*sqrtPi*gs0_*(1.0 + e_)*sqr(alpha_)
      + (1.0/6.0)*sqrtPi*alpha_
      + (10.0/96.0)*sqrtPi/((1.0 + e_)*gs0_)
    )/(ThetaSqrt+TsmallSqrt);

    // dissipation (Eq. 3.24, p.50)
    volScalarField gammaCoeff =
              3.0*(1.0 - sqr(e_))*sqr(alpha_)*rhoa_*gs0_*((4.0/da_)*ThetaSqrt/sqrtPi-tr(D));
//              3.0*(1.0 - sqr(e_))*sqr(alpha_)*rhoa_*gs0_*((4.0/da_)*ThetaSqrt/sqrtPi);
    // Eq. 3.25, p. 50 Js = J1 - J2

// The following is to calculate parameter tmf_ in u_f*u_s correlation
    dimensionedScalar Tpsmall_
    (
         "Tpsmall_",
         dimensionSet(1, -1, -3, 0, 0, 0, 0),
         scalar(1e-30)
    );
    volScalarField tmf_ = Foam::exp(-B*rhoa_*scalar(6.0)*epsilonb/(max(kb*betaPrim,Tpsmall_)));

    volScalarField J1 = 3.0*alpha_*betaPrim;
    volScalarField J2 =
        0.25*alpha_*sqr(betaPrim)*da_*sqr(Ur_)
       /(rhoa_*sqrtPi*(max(ThetaSqrt,TsmallSqrt)));

    // bulk viscosity  p. 45 (Lun et al. 1984).
//    lambda_ = (4.0/3.0)*sqr(alpha_)*rhoa_*da_*gs0_*(1.0+e_)*ThetaSqrt/sqrtPi;
    volScalarField lambdaa = (4.0/3.0)*sqr(alpha_)*rhoa_*da_*gs0_*(1.0+e_)/(sqrtPi*(ThetaSqrt+TsmallSqrt));

    // stress tensor, Definitions, Table 3.1, p. 43
//    volSymmTensorField tau = 2.0*mua_*D + (lambda_ - (2.0/3.0)*mua_)*tr(D)*I;
    volSymmTensorField tau = scalar(2.0)*muaa*D + (lambdaa - (scalar(2.0)/scalar(3.0))*muaa)*tr(D)*I;

    dimensionedScalar alphasmall
    (
           "alphasmall",
           dimensionSet(0, 0, 0, 0, 0, 0, 0),
           scalar(1e-9)
    );

    if (!equilibrium_)
    {
        // construct the granular temperature equation (Eq. 3.20, p. 44)
        // NB. note that there are two typos in Eq. 3.20
        // no grad infront of Ps
        // wrong sign infront of laplacian
        fvScalarMatrix ThetaEqn
        (
           fvm::ddt(1.5*(alpha_+1e-8)*rhoa_, Theta_)
         + fvm::div(phi, Theta_, "div(phi,Theta)")
         ==
            //Ps term.
            fvm::SuSp(-((PsCoeff*I) && dU), Theta_)
            //production due to shear.
          + fvm::SuSp((tau && dU),Theta_)
//          + (tau && dU)
            // granular temperature conduction.
          + fvm::laplacian(kappa_, Theta_, "laplacian(kappa,Theta)")
            //energy disipation due to inelastic collision.
          + fvm::SuSp(-gammaCoeff, Theta_)
            //
          + fvm::SuSp(-J1, Theta_)
          + (scalar(2.0)/scalar(3.0))*J1*tmf_*kb
        );

        ThetaEqn.relax();
        ThetaEqn.solve();
    }
    else
    {
        // equilibrium => dissipation == production
        // Eq. 4.14, p.82
        volScalarField K1 = 2.0*(1.0 + e_)*rhoa_*gs0_;
        volScalarField K3 = 0.5*da_*rhoa_*
            (
                (sqrtPi/(3.0*(3.0-e_)))
               *(1.0 + 0.4*(1.0 + e_)*(3.0*e_ - 1.0)*alpha_*gs0_)
               +1.6*alpha_*gs0_*(1.0 + e_)/sqrtPi
            );

        volScalarField K2 =
            4.0*da_*rhoa_*(1.0 + e_)*alpha_*gs0_/(3.0*sqrtPi) - 2.0*K3/3.0;

        volScalarField K4 = 12.0*(1.0 - sqr(e_))*rhoa_*gs0_/(da_*sqrtPi);

        volScalarField trD = tr(D);
        volScalarField tr2D = sqr(trD);
        volScalarField trD2 = tr(D & D);

        volScalarField t1 = K1*alpha_;
        volScalarField l1 = -t1*trD;
        volScalarField l2 = sqr(t1)*tr2D;
        volScalarField l3 = 4.0*K4*alpha_*(2.0*K3*trD2 + K2*tr2D);

        Theta_ = sqr((l1 + sqrt(l2 + l3))/(2.0*(alpha_ + 1.0e-4)*K4));
    }

    forAll(alpha_, cellk)
    {
// for initial stability
       if(tt.value() <= ttzero.value() && alpha_[cellk]>= 0)
       {
          Theta_[cellk] = 0.0*Theta_[cellk];
       }
       if(tt.value() <= ttone.value() && alpha_[cellk] >= 0.5)
       {
          Theta_[cellk] = 0.0*Theta_[cellk];
       }
// to cut off in dilute limit, set DiluteCut < 0 to turn this off
       if(tt.value()>=ttone.value() && alpha_[cellk] <= DiluteCut_.value())
       {
          Theta_[cellk] = 0.0*Theta_[cellk];
       }
    }

    Theta_.max(0.0e-40);
    Theta_.min(MaxTheta);

// need to update after solving Theta Equation.
    PsCoeff = granularPressureModel_->granularPressureCoeff
    (
        alpha_,
        gs0_,
        rhoa_,
        e_
    );
// update bulk viscosity and shear viscosity
// bulk viscosity  p. 45 (Lun et al. 1984).
    lambda_ = (4.0/3.0)*sqr(alpha_)*rhoa_*da_*gs0_*(1.0+e_)*sqrt(Theta_)/sqrtPi;
// particle viscosity (Table 3.2, p.47)
    mua_ = viscosityModel_->mua(alpha_, Theta_, gs0_, rhoa_, da_, e_);

    pf = frictionalStressModel_->frictionalPressure
    (
        alpha_,
        alphaMinFriction_,
        alphaMax_,
        Fr_,
        eta_,
        p_
    );
//  yes, after solving Theta, because frictional stress is not a part of kinetic theoty
//    PsCoeff = PsCoeff + pf/(max(Theta_,Tsmall));

    PsCoeff.min(1e+6);
    PsCoeff.max(-1e+6);

    // update particle pressure, just from the kinetic part
    pa_ = PsCoeff*Theta_;

    // frictional shear stress, Eq. 3.30, p. 52
    volScalarField muf = frictionalStressModel_->muf
    (
        alpha_,
        Theta_,
        alphaMinFriction_,
        alphaMax_,
        pf,
        D,
        phi_
    );

   // add frictional stress
    mua_ = mua_+muf;
    mua_.max(0.0);
    Info<< "kinTheory: max(Theta) = " << max(Theta_).value() <<" min(Theta) = "<<min(Theta_).value()<< endl;

    volScalarField ktn = mua_/rhoa_;

    Info<< "kinTheory: min(nua) = " << min(ktn).value()
        << ", max(nua) = " << max(ktn).value() << endl;

    Info<< "kinTheory: min(pa) = " << min(pa_).value()
        << ", max(pa) = " << max(pa_).value() << endl;
}
void Foam::boundMinMax
(
    volScalarField& vsf,
    const dimensionedScalar& vsf0,
    const dimensionedScalar& vsf1
)
{
    scalar minVsf = min(vsf).value();
    scalar maxVsf = max(vsf).value();

    if (minVsf < vsf0.value() || maxVsf > vsf1.value())
    {
        Info<< "bounding " << vsf.name()
            << ", min: " << gMin(vsf.internalField())
            << " max: " << gMax(vsf.internalField())
            << " average: " << gAverage(vsf.internalField())
            << endl;
    }

    if (minVsf < vsf0.value())
    {
        vsf.internalField() = max
        (
            max
            (
                vsf.internalField(),
                fvc::average(max(vsf, vsf0))().internalField()
                *pos(vsf0.value() - vsf.internalField())
            ),
            vsf0.value()
        );

        vsf.correctBoundaryConditions();
        vsf.boundaryField() = max(vsf.boundaryField(), vsf0.value());
    }

    if (maxVsf > vsf1.value())
    {
        vsf.internalField() = min
        (
            min
            (
                vsf.internalField(),
                fvc::average(min(vsf, vsf1))().internalField()
                *neg(vsf1.value() - vsf.internalField())
                // This is needed when all values are above max
                // HJ, 18/Apr/2009
              + pos(vsf1.value() - vsf.internalField())*vsf1.value()
            ),
            vsf1.value()
        );

        vsf.correctBoundaryConditions();
        vsf.boundaryField() = min(vsf.boundaryField(), vsf1.value());
    }
}