User Defined Postprocessing via UserDefinedField

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

double gamma = 1.40;....

A declaration of local variables that can be used in subsequent expression.

double Mach = sqrt(primit....

Still a declaration. But the Mach number is calculated locally even though it is a valid option for outputFields. This is an example that not all the pre-defined output variables are available to be used in the expression.

TotalPressureCoeff = (gamma*pri....

This assigns the final result to the total pressure coefficient.Note that the output variable name in the expression (TotalPressureCoeff) is exactly the same as its name entry in the JSON.

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:

(7.9.1)#\[\overrightarrow{\mathbf{f_p}} = \int {\color{Red} \left(p - p_{ref}\right )d\overrightarrow{\mathbf{A}}}\]

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.