v2112: New and improved pre-processing

New Function1 entries

TOP

The Function1 entry provides a set of run-time selectable input options where, e.g. users can describe time-dependent functions using tables, polynomials, and many more. In this release the Function1 class now has access to a database, e.g. mesh or time, enabling the lookup and retrieval of many more objects, e.g. fields, dictionaries, physical models etc.

New functionObjectValue Function1

The new functionObjectValue Function1 sets its value according to the result of a functionObject. Many function objects store results that can be used for further processing, e.g.:

  • fieldMinMax: min, max, cell, position
  • forces: normalForce, tangentialForce, porousForce, normalMoment, tangentialMoment, porousMoment
  • forceCoeffs: Cd, Cs, Cl, CmRoll, CmPitch, CmYaw, Cd(f), Cd(r), Cs(f), Cs(r), Cl(f), Cl(r)
  • ... and many more ...

The example below relates to the new propellerInfo function object, where the reference velocity, URef, is set to the mean axial velocity result of the wake field surface, UzMean:

URef                 functionObjectValue;
functionObject       propellerInfo1; // name of this function object
functionObjectResult UzMean;

New sample Function1

The new sample Function1 sets the value to a field value at a sample location, e.g.

field               <field name>;
position            (0 0 0);
interpolationScheme cell;

New functionObjectTrigger Function1

The new functionObjectTrigger Function1 returns a 0 or 1 value corresponding to function object trigger levels, e.g.

myTrigger
{
    type        functionObjectTrigger
    triggers    (1 3 5);
}

It is possible to use this function directly or embed as a switch when evaluating an expression.

New coded Function1

With dynamic code compilation it is now possible to define an arbitrary Function1, e.g.

// massFlowRate constant 5;

massFlowRate
{
    type  coded;
    name  liquidIn;
    code
    #{
        // Receives 'x' as the argument
        static bool reported(false);
        if (!reported)
        {
            Info<< "Using coded value for massFlowRate" << nl;
            reported = true;
        }
        return 5;
    #};
}

New InputValueMapper

The new InputValueMapper Function1 is a wrapper that maps the input value prior to it being used by another Function1, e.g. to limit a polynomial

myValue
{
    type            inputValueMapper;
    mode            minMax;

    min             0.4;
    max             1.4;

    value polynomial
    (
        (5 1)
        (-2 2)
        (-2 3)
        (1 4)
    );
}

Here the return value will be:

  • poly(0.4) for x <= 0.4;
  • poly(1.4) for x >= 1.4; and
  • poly(x) for 0.4 < x < 1.4.

This can be combined with the new functionObjectValue to create very flexible set-ups, e.g. to supply a patch mass flux for a table lookup:

myValue
{
    type            inputValueMapper;
    mode            function;

    function
    {
        type            functionObjectValue;
        functionObject  surfaceFieldValue1;
        functionObjectResult sum(outlet,phi);
    }

    value
    {
        type        table;
        file        "<system>/fanCurve.txt";
    }
}

Source code

Tutorial

Improved expressions

TOP

This release includes several refinements and extensions to expressions to improve their flexibility. The core engine is more robust and now handles recursive functions.

In addition to regular builtin expression functions such as sin() etc, it is also possible to specify some additional user functions for expressions. These are defined in terms of an OpenFOAM Function1. Here is a simple example of some user functions:

functions<scalar>
{
    intakeType table ((0 0) (10 1.2));

    p_inlet
    {
        type        sine;
        frequency   3000;
        scale       50;
        level       101325;
    }

    myTrigger
    {
        type        functionObjectTrigger;
        triggers    (1 3 5);
    }
}

functions<vector>
{
    position table ((0 (0 0 0)) (10 (0 0 5)));
}

These can then be used in expressions, e.g.:

// Switch above/below datum
pos((pos() - fn:position()).z()) ? ... : ...

// Select based on trigger status
bool(fn:myTrigger()) ? ... : ...

The functions can also be combined with other scalar fields or other functions, e.g.

fn:intakeType(mag(U))

fn:p_inlet(fn:intakeType())

fn:position(2*time())

As the examples illustrate, the functions can be used with or without arguments. If called without any arguments, the function is evaluated at the current time and returns a single value. If called with a scalar argument, the function acts like a mapper or lookup function.

Improved blockMesh utility

TOP

The blockMesh application can be used on its own or to generate a background mesh for snappyHexMesh.

The blockMesh definition can now contain pre-scaling factors and a coordinate transformation, e.g.

prescale  (1.5 1 1);
transform
{
    origin   (0 0 0);
    rotation
    {
        type  axisAngle;
        axis  (0 0 1);
        angle 45;
    }
}

This specifies mesh stretching in one direction, followed by a rotation about a specified point. Both of these operations are performed before the uniform scale factor is applied.

Simpler face specification

The two component block face specification (block_number face_index) for mesh boundary faces now also works with curved faces, providing a simpler syntax, e.g.

hex (0 1 2 3 4 5 6 7) (10 20 30) grading (1 1 1)

boundary
(
    inlet
    {
        type patch;
        faces
        (
            (0 0)  // x-min
        )
    }
    outlet
    {
        type patch;
        faces
        (
            (0 1)  // x-max
        )
    }
    walls
    {
        type wall;
        faces
        (
            (0 2)  // y-min
            (0 3)  // y-max
            (0 4)  // z-min
            (0 5)  // z-max
        );
    }
);

 Tip: use blockMesh -help to display an ASCII-art view of the hex cell vertex and face numbering:

Block mesh generator.

  The ordering of vertex and face labels within a block as shown below.
  For the local vertex numbering in the sequence 0 to 7:
    Faces 0, 1 (x-direction) are left, right.
    Faces 2, 3 (y-direction) are front, back.
    Faces 4, 5 (z-direction) are bottom, top.

                        7 ---- 6
                 f5     |\     :\     f3
                 |      | 4 ---- 5     \
                 |      3.|....2 |      \
                 |       \|     \|      f2
                 f4       0 ---- 1
    Y  Z
     \ |                f0 ------ f1
      \|
       o--- X

Detection of wedge topologies

If collapsed block descriptions such as those that arise from wedge geometries are detected, the merge strategy changes from a topological merge to a geometric point merge. This only applied to blocks with duplicate vertex indices (not those with geometrically duplicate points) but helps increase overall robustness.

Additional blockMesh output

The blockMesh application now accepts a -verbose option, which overrides any entry that may exist in the blockMeshDict. The option can be specified multiple times to increase the verbosity, e.g.

blockMesh -verbose -verbose

When running blockMesh -write-vtk, it will also generate an additional blockFaces.vtp file with block/face information for boundary faces.

Source code

snappyHexMesh parallel consistency improvements

TOP

snappyHexMesh identifies and deletes cells that cannot be reached from the user-provided inside point(s) as early as possible. To account for, e.g. volume refinement resolving additional features, it preserves a 1-cell thick buffer layer. In this release a problem was fixed which affected this buffer layer calculation.

Note that there is a final pass after all refinement which will delete any left-over cells without a buffer layer so the problem was only present during intermediate levels.

The problem was observed in a very simple geometry (a cube) where the point-in-mesh was outside the cube. Serial runs performed correctly, deleting the unreachable mesh:

However, in parallel operation, some of the unreachable cells were preserved:

Here, the mesh has been coloured with the processor number where it can be seen that 'bleeding' occurred at processor interfaces.

The fix guarantees consistent behaviour across processor interfaces.

Source code

New zone handling for splitMeshRegions

TOP

splitMeshRegions splits a mesh into multiple regions to run e.g. conjugate heat-transfer simulations. In previous releases support was added to combine cellZones into a newly created cellZone. This release provides in-place addition to an existing cellZone, e.g.

splitMeshRegions \
    -addZones '((allSolids zoneA "zoneB.*")(allFluids none otherZone))'

This will add zoneA and zoneB.* to zone allSolids; similarly, all non-zoned cells (indicated by zone name none) and otherZone are added to the zone allFluids.

Note that the zone-to-add-to (the first element) must be a non-wildcard.

Source code