7.9. User Defined Postprocessing via UserDefinedField
#
In Flow360, users can specify custom expressions to calculate outputs based on some solver variables. These variables can be used in the output_fields
of VolumeOutput
, SurfaceOutput
, SliceOutput
, IsosurfaceOutput
and ProbeOutput
.
We will illustrate how to use this feature using several examples.
Note
We provide a complete list of available functions and some guidelines in our knowledge base.
Custom Output Variable#
In this example, we compute the total pressure coefficient for the entire domain of an om6Wing simulation. For the definition of the total pressure coefficient please see here.
First we need to define the expression for total pressure coefficient.
1fl.UserDefinedField(
2 name="TotalPressureCoeff",
3 expression="double gamma = 1.40; double pow1 = gamma/(gamma-1); double pow2 = (gamma-1) / 2; double MachRefSq = MachRef * MachRef; "
4 + "double Mach = sqrt(primitiveVars[1] * primitiveVars[1] + primitiveVars[2] * primitiveVars[2] + primitiveVars[3] * primitiveVars[3]) / sqrt(gamma * primitiveVars[4] / primitiveVars[0]); double MachSq = Mach * Mach; "
5 + "TotalPressureCoeff = (gamma*primitiveVars[4]*pow((1+pow2*MachSq),pow1)-pow((1+pow2*MachRefSq),pow1))/(gamma/2*MachRefSq);",
6)
A statement-by-statement breakdown of the above expression is shown in following table:
Expression |
Explanation |
---|---|
|
A declaration of local variables that can be used in subsequent expression. |
|
Still a declaration. But the Mach number is calculated locally even though it is a valid option for |
|
This assigns the final result to the total pressure coefficient.Note that the output variable name in the expression ( |
Then we need to add TotalPressureCoeff
in one of the outputs. Here we use VolumeOutput
.
1fl.VolumeOutput(
2 output_format="paraview",
3 output_fields=["TotalPerssureCoeff"],
4)
Custom surface integral#
In Flow360 we have added a new type of monitor SurfaceIntegralOutput
in addition to the probe monitor which monitors quantities at a set of given coordinates. The surface-integral monitor will try to compute the surface integral of the given variable on given patches. Here we show an example of calculating the pressure force on a no-slip wall as an example. We first set up the user_defined_fields
as
1pressure_force_field = fl.UserDefinedField(
2 name="PressureForce",
3 expression="double prel = primitiveVars[4] - pressureFreestream; "
4 + "PressureForce[0] = prel * nodeNormals[0]; "
5 + "PressureForce[1] = prel * nodeNormals[1]; "
6 + "PressureForce[2] = prel * nodeNormals[2];",
7)
8
9fl.SimulationParams(
10 ...
11 user_defined_fields=[pressure_force_field]
12)
Note that the nodeNormals
is a vector whose direction is the normal of the given patch at each node and the magnitude is the area associated with the node. Therefore the right hand side of the PressureForce
corresponds to the red part of the following equation for pressure force:
where the \(\overrightarrow{\mathbf{f_p}}\) is the pressure force, \(p_{ref}\) is the free steam pressure. Surface integrals for scalar outputs should use magnitude(nodeNormals)
instead to include the area (\(dA\)) in integral. Otherwise the result will be a summation of the value over the nodes instead of surface area integral.
And we append to the outputs
to include:
1fl.SurfaceIntegralOutput(
2 surfaces=[volume_mesh["wing1"], volume_mesh["wing2"]], output_fields="PressureForce"
3)
which means that we want PressureForce
integral computed on patch wing1
and patch wing2
as a whole.