OpenFOAM-2.3.x版本中的DPMFoam与MPPICFoam求解器无法对用户自定义源操作(即fvOptions)进行处理,需要修改DPMFoam以及MPPICFoam求解器的源码,以实现其对fvOptions的处理。
在对OpenFOAM中给定的算例进行分析时发现,$FOAM_TUTORIALS/incompressible/pimpleFoam
算例的
而DPMFoam及MPPICFoam中流体求解部分采取的是PIMPLE方法,因此可以借鉴pimpleFoam求解器对于fvOptions的处理,并对照pimpleFoam求解器的源码将fvOptions加入到DPMFoam以及MPPICFoam求解器中。
实际上,MPPICFoam求解器与DPMFoam求解器基本一致,只是对颗粒的部分处理方式不一样,这从MPPICFoam求解器源码也可以看出:
// MPPICFoam.C
#define MPPIC
#include "DPMFoam.C"
因此,对DPMFoam求解器的修改也就自然包含了对MPPICFoam求解器的修改。DPMFoam求解器的主程序如下:
// DPMFoam.C
#include "fvCFD.H"
#include "singlePhaseTransportModel.H"
#include "PhaseIncompressibleTurbulenceModel.H"
#include "pimpleControl.H"
#include "fixedFluxPressureFvPatchScalarField.H"
#ifdef MPPIC
#include "basicKinematicMPPICCloud.H"
#define basicKinematicTypeCloud basicKinematicMPPICCloud
#else
#include "basicKinematicCollidingCloud.H"
#define basicKinematicTypeCloud basicKinematicCollidingCloud
#endif
int main(int argc, char *argv[])
{
argList::addOption
(
"cloudName",
"name",
"specify alternative cloud name. default is 'kinematicCloud'"
);
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
#include "readGravitationalAcceleration.H"
#include "createFields.H"
#include "initContinuityErrs.H"
pimpleControl pimple(mesh);
Info<< "\nStarting time loop\n" << endl;
while (runTime.run())
{
#include "readTimeControls.H"
#include "CourantNo.H"
#include "setDeltaT.H"
runTime++;
Info<< "Time = " << runTime.timeName() << nl << endl;
continuousPhaseTransport.correct();
muc = rhoc*continuousPhaseTransport.nu();
Info<< "Evolving " << kinematicCloud.name() << endl;
kinematicCloud.evolve();
// Update continuous phase volume fraction field
alphac = max(1.0 - kinematicCloud.theta(), alphacMin);
alphac.correctBoundaryConditions();
alphacf = fvc::interpolate(alphac);
alphaPhic = alphacf*phic;
fvVectorMatrix cloudSU(kinematicCloud.SU(Uc));
volVectorField cloudVolSUSu
(
IOobject
(
"cloudVolSUSu",
runTime.timeName(),
mesh
),
mesh,
dimensionedVector
(
"0",
cloudSU.dimensions()/dimVolume,
vector::zero
),
zeroGradientFvPatchVectorField::typeName
);
cloudVolSUSu.internalField() = -cloudSU.source()/mesh.V();
cloudVolSUSu.correctBoundaryConditions();
cloudSU.source() = vector::zero;
// --- Pressure-velocity PIMPLE corrector loop
while (pimple.loop())
{
#include "UcEqn.H"
// --- PISO loop
while (pimple.correct())
{
#include "pEqn.H"
}
if (pimple.turbCorr())
{
continuousPhaseTurbulence->correct();
}
}
runTime.write();
Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
<< nl << endl;
}
Info<< "End\n" << endl;
return 0;
}
可以发现其中并不包含对fvOptions的处理。此外可以发现DPMFoam求解器在对流场进行求解时使用的是PIMPLE算法,而OpenFOAM的不可压缩流体求解器pimpleFoam是可以对fvOptions进行处理的,因而可以借鉴pimpleFoam源码中对fvOptions的处理方式,对DPMFoam源码进行修改。
pimpleFoam求解器的主程序如下,程序中为了处理fvOptions所添加的头文件已通过注释标示出:
// pimpleFoam.C
#include "fvCFD.H"
#include "singlePhaseTransportModel.H"
#include "turbulenceModel.H"
#include "pimpleControl.H"
// !!! Here
#include "fvIOoptionList.H"
#include "IOporosityModelList.H"
#include "IOMRFZoneList.H"
#include "fixedFluxPressureFvPatchScalarField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
#include "createFields.H"
// !!! Here
#include "createFvOptions.H"
#include "initContinuityErrs.H"
pimpleControl pimple(mesh);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Info<< "\nStarting time loop\n" << endl;
while (runTime.run())
{
#include "readTimeControls.H"
#include "CourantNo.H"
#include "setDeltaT.H"
runTime++;
Info<< "Time = " << runTime.timeName() << nl << endl;
// --- Pressure-velocity PIMPLE corrector loop
while (pimple.loop())
{
#include "UEqn.H"
// --- Pressure corrector loop
while (pimple.correct())
{
#include "pEqn.H"
}
if (pimple.turbCorr())
{
turbulence->correct();
}
}
runTime.write();
Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
<< nl << endl;
}
Info<< "End\n" << endl;
return 0;
}
此外,PIMPLE算法循环中的速度方程UEqn.H
以及压力方程pEqn.H
中均对fvOptions进行了处理,因此在对DPMFoam求解器进行修改的时候,也需要考虑速度方程以及压力方程的修改。
首先需要将OpenFOAM初始的DPMFoam求解器备份:
cd $FOAM_APP/solvers/lagrangian
cp -rfv DPMFoam DPMFoam-bak
然后再修改DPMFoam求解器。
DPMFoam.C
对照pimpleFoam.C
,可以初步将fvOptions相关的头文件加入到DPMFoam.C
中,如下:
// DPMFoam.C
#include "fvCFD.H"
#include "singlePhaseTransportModel.H"
#include "PhaseIncompressibleTurbulenceModel.H"
#include "pimpleControl.H"
#include "fvIOoptionList.H"
#include "IOporosityModelList.H"
#include "IOMRFZoneList.H"
#include "fixedFluxPressureFvPatchScalarField.H"
#ifdef MPPIC
#include "basicKinematicMPPICCloud.H"
#define basicKinematicTypeCloud basicKinematicMPPICCloud
#else
#include "basicKinematicCollidingCloud.H"
#define basicKinematicTypeCloud basicKinematicCollidingCloud
#endif
int main(int argc, char *argv[])
{
argList::addOption
(
"cloudName",
"name",
"specify alternative cloud name. default is 'kinematicCloud'"
);
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
#include "readGravitationalAcceleration.H"
#include "createFields.H"
#include "createFvOptions.H"
#include "initContinuityErrs.H"
pimpleControl pimple(mesh);
// ......
}
UEqn.H
对照pimpleFoam中包含的UEqn.H
文件:
// Solve the Momentum equation
tmp<fvVectorMatrix> UEqn
(
fvm::ddt(U)
+ fvm::div(phi, U)
+ turbulence->divDevReff(U)
==
fvOptions(U)
);
UEqn().relax();
fvOptions.constrain(UEqn());
volScalarField rAU(1.0/UEqn().A());
if (pimple.momentumPredictor())
{
solve(UEqn() == -fvc::grad(p));
fvOptions.correct(U);
}
可以将DPMFoam中包含的UEqn.H
文件修改为:
// fvOptions is added in the UcEqn.
fvVectorMatrix UcEqn
(
fvm::ddt(alphac, Uc) + fvm::div(alphaPhic, Uc)
- fvm::Sp(fvc::ddt(alphac) + fvc::div(alphaPhic), Uc)
+ continuousPhaseTurbulence->divDevRhoReff(Uc)
==
(1.0/rhoc)*cloudSU
+ fvOptions(Uc)
);
UcEqn.relax();
// fvOptions is added here.
fvOptions.constrain(UcEqn);
volScalarField rAUc(1.0/UcEqn.A());
surfaceScalarField rAUcf("Dp", fvc::interpolate(rAUc));
surfaceScalarField phicForces
(
(fvc::interpolate(rAUc*cloudVolSUSu/rhoc) & mesh.Sf())
+ rAUcf*(g & mesh.Sf())
);
if (pimple.momentumPredictor())
{
solve
(
UcEqn
==
fvc::reconstruct
(
phicForces/rAUcf - fvc::snGrad(p)*mesh.magSf()
)
);
// fvOptions is added here.
fvOptions.correct(Uc);
}
pEqn.H
对照pimpleFoam中包含的pEqn.H
文件:
surfaceScalarField rAUf("rAUf", fvc::interpolate(rAU));
volVectorField HbyA("HbyA", U);
HbyA = rAU*UEqn().H();
if (pimple.nCorrPISO() <= 1)
{
UEqn.clear();
}
surfaceScalarField phiHbyA
(
"phiHbyA",
(fvc::interpolate(HbyA) & mesh.Sf())
+ rAUf*fvc::ddtCorr(U, phi)
);
fvOptions.makeRelative(phiHbyA);
adjustPhi(phiHbyA, U, p);
// Update the fixedFluxPressure BCs to ensure flux consistency
setSnGrad<fixedFluxPressureFvPatchScalarField>
(
p.boundaryField(),
(
phiHbyA.boundaryField()
- fvOptions.relative(mesh.Sf().boundaryField() & U.boundaryField())
)/(mesh.magSf().boundaryField()*rAUf.boundaryField())
);
// Non-orthogonal pressure corrector loop
while (pimple.correctNonOrthogonal())
{
// Pressure corrector
fvScalarMatrix pEqn
(
fvm::laplacian(rAUf, p) == fvc::div(phiHbyA)
);
pEqn.setReference(pRefCell, pRefValue);
pEqn.solve(mesh.solver(p.select(pimple.finalInnerIter())));
if (pimple.finalNonOrthogonalIter())
{
phi = phiHbyA - pEqn.flux();
}
}
#include "continuityErrs.H"
// Explicitly relax pressure for momentum corrector
p.relax();
U = HbyA - rAU*fvc::grad(p);
U.correctBoundaryConditions();
fvOptions.correct(U);
可以将DPMFoam中包含的pEqn.H
文件修改为:
{
volVectorField HbyA("HbyA", Uc);
HbyA = rAUc*UcEqn.H();
surfaceScalarField phiHbyA
(
"phiHbyA",
(
(fvc::interpolate(HbyA) & mesh.Sf())
+ alphacf*rAUcf*fvc::ddtCorr(Uc, phic)
+ phicForces
)
);
// fvOptions is added here.
fvOptions.makeRelative(phiHbyA);
// fvOptions is added here.
// Update the fixedFluxPressure BCs to ensure flux consistency
setSnGrad<fixedFluxPressureFvPatchScalarField>
(
p.boundaryField(),
(
phiHbyA.boundaryField()
- fvOptions.relative(mesh.Sf().boundaryField() & Uc.boundaryField())
)/(mesh.magSf().boundaryField()*rAUcf.boundaryField())
);
// Non-orthogonal pressure corrector loop
while (pimple.correctNonOrthogonal())
{
fvScalarMatrix pEqn
(
fvm::laplacian(alphacf*rAUcf, p)
==
fvc::ddt(alphac) + fvc::div(alphacf*phiHbyA)
);
pEqn.setReference(pRefCell, pRefValue);
pEqn.solve(mesh.solver(p.select(pimple.finalInnerIter())));
if (pimple.finalNonOrthogonalIter())
{
phic = phiHbyA - pEqn.flux()/alphacf;
p.relax();
Uc = HbyA
+ rAUc*fvc::reconstruct((phicForces - pEqn.flux()/alphacf)/rAUcf);
Uc.correctBoundaryConditions();
// fvOptions is added here.
fvOptions.correct(Uc);
}
}
}
#include "continuityErrs.H"
Make/options
在该文件中的EXE_INC
选项中添加-I$(LIB_SRC)/fvOptions/lnInclude
及-I$(LIB_SRC)/sampling/lnInclude
。在该文件中的EXE_LIBS
选项中添加-lfvOptions
及-lsamping
。这里要注意每行行尾的转义字符\
。
添加这些选项的原因是使用OpenFOAM自带的编译工具wmake进行编译时,可以通过EXE_INC
及EXE_LIBS
来寻找需要包含的源文件以及需要链接的库文件。增加fvOptions相关的源文件及库文件路径可以保证编译的顺利进行。
MPPICFoam/make/options
该文件的修改方式与Make/options
文件的修改方式相同。
在DPMFoam目录中执行如下命令:
./Allwclean
./Allwmake
即可以实现修改后求解器的编译。