OpenFOAM 中使用 functionObject

使用 functionObject 进行后处理

In OpenFOAM, functionObjects are code snippets that can be loaded into any solver during run-time. This enables each solver to be coupled with some additional functionality, that is independent from the flow model. All functionObjects have to be included in system/controlDict like the following:

functions
{
<name>
{
type <type>;
functionObjectLibs ("<lib>");
writeControl timeStep;
outputInterval 1;
// Specific parameters for the functionObject
}
}

使用方法

大概是 OF-4.0 以前的版本

  • 运行时:
    先在 controlDict 中添加 functions,然后直接运行算例即可。支持并行算例。
  • 运行后:
    先在 controlDict 中添加 functions,然后执行这个命令 execFlowFunctionObjects -noFlow
    支持并行,使用命令 mpirun -np 2 execFlowFunctionObjects -noFlow -parallel

OF-4.0 以后的版本

  • controlDict 中添加 functions 之后,直接运行求解器即可。支持并行算例。

  • 运行后,在 controlDict 文件中添加 functions之后,运行 postProcess -fields '(T p U)'
    -fields 一定要加,因为这相当于输入的场信息,和 functionsfields 的不一样,那个是操作的场。输入的场要包含操作的场才行。

  • 运行后,还可以通过求解器来调用,这样可以载入更多的信息(如拉格朗日粒子):sprayFoam -postProcess -func writeCloudOldStyle
    这个 writeCloudOldStyle 是将 positions 转换成 paraview 可以读取的格式。

  • 特殊控制:运行后,可以只对某个(些)时间进行处理,如:postProcess -fields '(T p)' -time '1.75e-05'
    或者:postProcess -fields '(T p)' -time ':1.75e-05',冒号表示从最开始到 1.75e-05 所有的时间。
    另外还可以处理不连续的时间,如 postProcess -fields '(T p)' -time '1.25e-05,1.75e-05',用逗号隔开即可。

  • 支持并行,使用命令 mpirun -np 2 postProcess -fields '(T p U)' -parallel

functionObjects 分为两大类 libfieldFunctionObjectslibutilityFunctionObjects

所有可选的 type 可以通过这个命令获取:postProcess -list

目前运行 postProcess -list 会获得下列功能,官方配置文件在这个位置:https://github.com/OpenFOAM/OpenFOAM-dev/tree/master/etc/caseDicts/postProcessing/fields
Available configured functionObjects:

67
(
CourantNo
Lambda2
MachNo
PecletNo
Q
Qdot
R
XiReactionRate
add
age
boundaryProbes
cellMax
cellMin
components
ddt
div
dsmcFields
enstrophy
faceMax
faceMin
flowRateFaceZone
flowRatePatch
flowType
forceCoeffsCompressible
forceCoeffsIncompressible
forcesCompressible
forcesIncompressible
grad
icoUncoupledKinematicCloud
interfaceHeight
internalProbes
log
mag
magSqr
minMaxComponents
minMaxMagnitude
patchAverage
patchIntegrate
phaseScalarTransport
pressureDifferencePatch
pressureDifferenceSurface
probes
randomise
residuals
scalarTransport
scale
singleGraph
staticPressure
streamFunction
streamlines
subtract
surfaces
time
totalPressureCompressible
totalPressureIncompressible
turbulenceFields
turbulenceIntensity
volFlowRateSurface
vorticity
wallHeatFlux
wallHeatTransferCoeff
wallShearStress
writeCellCentres
writeCellVolumes
writeObjects
writeVTK
yPlus
)

直接运行即可,比如:

postProcess -func CourantNo

libfieldFunctionObjects

常用操作举例:

vol 场操作

functions
{
volFieldValue1
{
type volFieldValue;
libs ("libfieldFunctionObjects.so");

log true;
writeControl writeTime;
writeFields true;

regionType cellZone;
name c0;
operation volAverage;

//A single weight field can be specified as before:
weightField alpha1;
//or a list specified by:
//weightFields (alpha.water rho.water);

fields
(
p
U
);
}
}

operation 有:

operation说明代码
CoVCoefficient of variation: standard deviation/mean
averageEnsemble averagegSum(values)/nCells()
maxMaximumgMax(values)
minMinimumgMin(values)
noneNo operation
sumSumgSum(values)
sumMagSum of component magnitudesgSum(cmptMag(values))
volAverageVolume weighted averagegSum(V*values)/V_total
volIntegrateVolume integralgSum(V*values)
weightedAverageWeighted averagegSum(weightField*values)/gSum(weightField)
weightedSumWeighted sumgSum(weightField*values)
weightedVolAverageWeighted volume averagegSum(weightField*V*values)/gSum(weightField*V)
weightedVolIntegrateWeighted volume integralgSum(weightField*V*values)

Surface 场操作

operation:

operation说明代码
CoVCoefficient of variation: standard deviation/mean
averageensemble averagesum(values)/values.size()
maxmaximummax(values)
minminimummin(values)
noneno operation
sumsumsum(values)
sumMagsum of component magnitudessum(cmptMag(values))
areaAveragearea weighted averagesum(magSf*values)/sum(magSf)
areaIntegratearea integralsum(magSf*values)
areaNormalAveragearea weighted average in face normal directionvector( sum(values & Sf)/sum(mag(Sf)), 0.0, 0.0 )
areaNormalIntegratearea weighted integral in face normal directonvector( sum(values & Sf), 0.0, 0.0 )
weightedAreaAverageweighted area averagesum(weightField*magSf*values)/sum(magSf*weightField)
weightedAreaIntegrateweighted area integralsum(weightField*magSf*values)
weightedAverageweighted averagesum(weightField*values)/sum(weightField)
weightedSumweighted sumsum(weightField*values)
sumDirectionsum values which are positive in given direction
sumDirectionBalancesum of balance of values in given direction

Surface 场操作举例1

面平均,计算 f0 这个 faceZonezeta 的平均值

functions
{
poolHeight
{
type surfaceFieldValue;
libs ("libfieldFunctionObjects.so");
writeControl timeStep;
writeInterval 1;
log yes;
writeTotalArea no;
writeFields no;
regionType faceZone;
name f0;
operation areaAverage;
fields
(
zeta
);
}
};

Surface 场操作举例2

面求和,计算 inlet 这个 patchrhoPhi 的和

functions
{
inletFlux
{
type surfaceFieldValue;
libs ("libfieldFunctionObjects.so");
writeControl timeStep;
log true;
// Output field values as well
writeFields false;
regionType patch;
name inlet;
operation sum;
fields
(
rhoPhi
);
}
outletFlux
{
$inletFlux;
name outlet;
}
atmosphereFlux
{
$inletFlux;
name atmosphere;
}
}

surfaceInterpolate

Description
Linearly interpolates volume fields to generate surface fields.
Fields are stored
- every time step the field is updated with new values
- at output it writes the fields
This functionObject can either be used
- to calculate a new field as a post-processing step or
- since the fields are registered, used in another functionObject
Example of function object specification:

surfaceInterpolate1
{
type surfaceInterpolate;
libs ("libfieldFunctionObjects.so");
...
fields ((p pInterp)(U UInterp));
}

Usage
\table

PropertyDescriptionRequiredDefault value
typetype name: surfaceInterpolateyes
fieldslist of fields with corresponding output field namesyes

简便用法

e.g. given a vol pressure field p

functions
{
// Interpolate the pressure field to the faces
surfacep
{
type surfaceInterpolate;
libs ("libfieldFunctionObjects.so");
fields ((p surfacep));
writeControl none;
}

// Average the surface pressure field over the centre faceZone
#includeFunc faceZoneAverage(name=centre, surfacep)
}

时间平均

functions
{
field_average
{
type fieldAverage; // fieldAverage 是时间平均
functionObjectLibs ("libfieldFunctionObjects.so");
enabled true;
writeControl outputTime;
fields
(
U
{
mean on;
prime2Mean on;
base time;
}
k
{
mean on;
prime2Mean off;
base time;
}
);
}
}

简便用法

#includeFunc fieldAverage(U, p, prime2Mean = yes)
#includeFunc fieldAverage(U, p)

更多关于时间平均的细节请看这里

极值

这个好像前边的场操作 volFieldValue 也能实现。

functions
{
minMax
{
// Type of functionObject
type fieldMinMax;
// Where to load it from (if not already in solver)
functionObjectLibs ("libfieldFunctionObjects.so");
// Function object enabled flag
enabled true;
// Log to output (default: false)
log false;
// Write information to file (default: true)
write true;
location no;
// Fields to be monitored - runTime modifiable
fields (U p T);
//fields (T);
writeControl timeStep;
writeInterval 2;
}
}

shearStress

functions
{
shearStress
{
type shearStress;
libs ("libfieldFunctionObjects.so");

executeControl writeTime;
writeControl writeTime;
}
}

streamLine

functions
{
streamLines
{
type streamLine;
// Where to load it from (if not already in solver)
libs ("libfieldFunctionObjects.so");
// Output every
writeControl writeTime;
// writeInterval 10;
setFormat vtk; //gnuplot;//xmgr;//raw;//jplot;//csv;//ensight;
// Tracked forwards (+U) or backwards (-U)
trackForward true;
// Names of fields to sample. Should contain above velocity field!
fields (p k U);
// Steps particles can travel before being removed
lifeTime 10000;
// Number of steps per cell (estimate). Set to 1 to disable subcycling.
nSubCycle 5;
// Cloud name to use
cloudName particleTracks;
// Seeding method.
seedSampleSet
{
type uniform;
axis x; //distance;
start (-0.0205 0.001 0.00001);
end (-0.0205 0.0251 0.00001);
nPoints 10;
}
}
}

MachNo

functions
{
libs ("libfieldFunctionObjects.so");
Ma
{
type MachNo;
executeControl writeTime;
writeControl writeTime;
}
}

probes

functions
{
my_name
{
type probes;
probeLocations
(
(0.0 0.05 0.0)
);
functionObjectLibs ("libfieldFunctionObjects.so");
fields (T);
}
}

libutilityFunctionObjects

所有可选 type

abort
coded//使用代码
patchProbes
probes//检测某些点的某些物理量,需要指定 probeLocations fields,和上边重复了。。。
psiReactionThermoMoleFractions
removeRegisteredObject
residuals
rhoReactionThermoMoleFractions
setTimeStep//设置时间步长,如:从表格中读取,sine函数等。
sets
surfaces
systemCall
time
timeActivatedFileUpdate//可以设置多套controlDict,运行到某一时刻自动切换
writeDictionary
writeObjects//write一些计算过程中的对象,可以多输出一些信息

writeObjects

functions
{
writeFields // name of the function object
{
type writeObjects;
libs ( "libutilityFunctionObjects.so" );

objects
(
T U rho // list of fields/variables to be written
);

// E.g. write every 1e-5 seconds of simulation time only the specified fields
writeControl runTime;
writeInterval 1e-5; // write every 1e-5 seconds

writeOption autoWrite;// noWrite anyWrite
}
}

You can also define multiple function objects in order to write different subsets of fields at different times. You can also use wildcards in the list of fields- for example, in order to write out all fields starting with “RR_” you can add

"RR_.*"

可以输出每个组分的反应速率?放热率呢?如何输出?Qdot[1 -1 -3 0 0 0 0] 是dQ[1 2 -3 0 0 0 0]除以体积,dQ的单位是J/s。那么我们需要对Qdot进行volumeIntegrate 操作。

定义:fvc::volumeIntegrate(df)=df.mesh().V()*df.field()//df是被操作的场
使用:volScalarField dQ = fvc::volumeIntegrate(Qdot);//dQ的量纲是多少?

setTimeStep

functions
{
timeStepping
{
type setTimeStep;
functionObjectLibs ("libutilityFunctionObjects.so");
enabled yes;
deltaT tableFile;
file "system/deltaTvalues";
}
}

timeActivatedFileUpdate

运行时更改某些文件

Performs a file copy/replacement once a specified time has been reached.

Example usage to update the fvSolution dictionary at various times throughout the calculation:

\verbatim
fileUpdate1
{
type timeActivatedFileUpdate;
libs ("libutilityFunctionObjects.so");
writeControl timeStep;
writeInterval 1;
fileToUpdate "$FOAM_CASE/system/fvSolution";
timeVsFile
(
(-1 "$FOAM_CASE/system/fvSolution.0")
(0.10 "$FOAM_CASE/system/fvSolution.10")
(0.20 "$FOAM_CASE/system/fvSolution.20")
(0.35 "$FOAM_CASE/system/fvSolution.35")
);
}
\endverbatim

coded

functions
{
timeStep
{
type coded;
libs ("libutilityFunctionObjects.so");
name setDeltaT;
code
#{
#};
codeExecute
#{
const Time& runTime = mesh().time();
if (runTime.timeToUserTime(runTime.value()) >= -15.0)
{
const_cast<Time&>(runTime).setDeltaT
(
runTime.userTimeToTime(0.025)
);
}
#};
}
}
functions
{
error
{
// Load the library containing the 'coded' functionObject
libs ("libutilityFunctionObjects.so");
type coded;
// Name of on-the-fly generated functionObject
name error;
codeEnd
#{
// Lookup U
Info<< "Looking up field U\n" << endl;
const volVectorField& U = mesh().lookupObject<volVectorField>("U");
Info<< "Reading inlet velocity uInfX\n" << endl;
scalar ULeft = 0.0;
label leftI = mesh().boundaryMesh().findPatchID("left");
const fvPatchVectorField& fvp = U.boundaryField()[leftI];
if (fvp.size())
{
ULeft = fvp[0].x();
}
reduce(ULeft, maxOp<scalar>());
dimensionedScalar uInfX
(
"uInfx",
dimensionSet(0, 1, -1, 0, 0),
ULeft
);
Info << "U at inlet = " << uInfX.value() << " m/s" << endl;
scalar magCylinder = 0.0;
label cylI = mesh().boundaryMesh().findPatchID("cylinder");
const fvPatchVectorField& cylFvp = mesh().C().boundaryField()[cylI];
if (cylFvp.size())
{
magCylinder = mag(cylFvp[0]);
}
reduce(magCylinder, maxOp<scalar>());
dimensionedScalar radius
(
"radius",
dimensionSet(0, 1, 0, 0, 0),
magCylinder
);
Info << "Cylinder radius = " << radius.value() << " m" << endl;
volVectorField UA
(
IOobject
(
"UA",
mesh().time().timeName(),
U.mesh(),
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
U
);
Info<< "\nEvaluating analytical solution" << endl;
const volVectorField& centres = UA.mesh().C();
volScalarField magCentres(mag(centres));
volScalarField theta(acos((centres & vector(1,0,0))/magCentres));
volVectorField cs2theta
(
cos(2*theta)*vector(1,0,0)
+ sin(2*theta)*vector(0,1,0)
);
UA = uInfX*(dimensionedVector(vector(1,0,0))
- pow((radius/magCentres),2)*cs2theta);
// Force writing of UA (since time has not changed)
UA.write();
volScalarField error("error", mag(U-UA)/mag(UA));
Info<<"Writing relative error in U to " << error.objectPath()
<< endl;
error.write();
#};
}
}

Misc

probes 前面有另一种实现方法

functions
{
probes
{
type probes;
libs ("libsampling.so");
writeControl timeStep;
writeInterval 1;
probeLocations
(
(0 9.95 19.77)
(0 -9.95 19.77)
);
fixedLocations false;
fields
(
p
);
}
}

等值面

functions
{
surfaces
{
type surfaces;
libs ("libsampling.so");
writeControl adjustableRunTime;
writeInterval 0.01;
timeStart 10;
surfaceFormat vtk;
fields (p_rgh U);
interpolationScheme cellPoint;
surfaces
(
interface
{
type isoSurface;
isoField alpha.water;
isoValue 0.5;
interpolate true;
}
);
}
}

forces

functions
{
forces
{
type forces;
libs ("libforces.so");
writeControl writeTime;
patches (floatingObject);
rho rhoInf;
log yes;
rhoInf 1000;
CofR (0 0 0);
}
};

输出控制

这里分两种情况,分别是 solver 运行时和运行后。

  • 运行后,一定需要记住的是必须使用参数 -fields 指定此次后处理过程中涉及的所有场(作为输入信息)。可以使用前面提到的 -time 参数来控制需要处理的时间段。
  • 运行时
    在 solver 运行时可以手动控制输出时间间隔,通过这两个选项: writeControl writeInterval。
    writeControl 常用的可选项:
outputTime//同主程序输出间隔相同。
writeTime//每 writeInterval个输出步长写一次。这里的输出步长指主程序的write步长。即,如果主程序每秒write一次,这里的function就是每3秒写一次。
adjustableRunTime//每 writeInterval 秒物理时间写一次,但是对于可调节步长的话,会自动调节最后一次的时间步长,以便准确时间输出。

writeControl 所有的可选项:

outputTime//同主程序输出间隔相同。
runTime//每 writeInterval 秒物理时间写一次。
adjustableRunTime//每 writeInterval 秒物理时间写一次,但是对于可调节步长的话,会自动调节最后一次的时间步长,以便准确时间输出。
clockTime//每 writeInterval 秒实际时间写一次。
cpuTime//每 writeInteral 秒 cpu 时间写一次。
none//不输出。
writeTime//每 writeInterval个输出步长写一次。这里的输出步长指主程序的write步长。即,如果主程序每秒write一次,这里的function就是每3秒写一次。
timeStep//每 writeInterval 个时间步长写一次。

简便用法

functions
{
#includeFunc Qdot
#includeFunc writeObjects(RR.C7H16)
#includeFunc writeObjects(h)
#includeFunc fieldAverage(U, p)
#includeFunc fieldAverage(U, p, prime2Mean = yes)
}
文章作者: Yan Zhang
文章链接: https://openfoam.top/functionObject/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 OpenFOAM 成长之路
您的肯定会给我更大动力~