v2312: New and improved post-processing

New Abaqus sampled set

TOP

The new abaqusMesh set derives sample positions from file using the Abaqus mesh point format. Example usage:

sets
{
    cone25 // user-specified set name
    {
        type        abaqusMesh;
        file        "abaqusMesh.inp";

        // Optional entries

        // Scale, e.g. mm to m
        scale       0.001;

        // Search distance when the sample point is not located in a cell
        maxDist     0.25;

        ...
    }
}

Tutorials

  • TBA

Source code

New Abaqus set writer

TOP

The new Abaqus set writer converts OpenFOAM set data to Abaqus format. Example usage:

T
{
    type sets;
    setFormat abaqus;
    fields (T);
    sets
    {
        ...
    }
}

Optional format options are provided in an abaqus sub-dictionary within the formatOptions dictionary:

formatOptions
{
    abaqus
    {
        format      ascii;

        // Optional entries

        // Custom header: $ entries are substituions
        header
        (
            "** OpenFOAM abaqus output"
            "** Project $FOAM_CASE"
            "** File $FILE_NAME"
            "** $FIELD_NAME Time t=$TIME"
        );

        // Write geometry in addition to field data
        writeGeometry yes;

        // Null value when sample value is not found
        // Default is scalar::min
        nullValue   0;

        // Insert additional time sub-directory in the output path
        // - yes : postProcessing/<fo-name>/<time>/<file>
        // - no : postProcessing/<fo-name>/<file>
        useTimeDir  no;

        // Available when 'useTimeDir' is 'no' to disambiguate file names

        // Time base for output file names:
        // - 'time' : <base>.inp_<field>.<time>
        // - 'iteration' : <base>.inp_<field>.<iteration>
        timeBase    iteration;

        // Optional start counters when using timeBase iteration
        writeIndex
        (
            T 1
        );

        ...
    }
}

Tutorials

  • TBA

Source code

Improved patch seed set

TOP

The patchSeed sampled set now computes sample seeds uniformly across the patch. The earlier implementation sampled the face index uniformly across the patch, with the side effect of a bias towards smaller faces.

streamline5
{
    type                streamLine;
    libs                (fieldFunctionObjects);
    U                   U;
    fields              (U p);
    setFormat           vtk;
    direction           forward;
    lifeTime            20000;
    cloud               particleTracks;
    seedSampleSet
    {
        type            patchSeed;
        axis            xyz;
        patches         ("inlet1");
        maxPoints       40;
    }
    interpolationScheme cellPoint;
    trackLength         0.001;
}

 

Tutorial

Source code

Merge request

  • Merge request 647

New case information function object

TOP

The new caseInfo function object generates solver and case information at runtime, or as part of  post-processing. Data collected includes:

  • Meta data: case name, path, number of time directories etc.
  • Dictionary entries : extract all/selection from any input dictionaries
    • optionally use scoping, e.g. 'solvers/U/solver' to get the U linear solver from fvSolution
    • supports wildcards, e.g. if the fvSolution U solver keyword used "(U|k|epsilon)"
    • limit selections using 'include' or 'exclude' lists of entry names to include/exclude
  • Mesh statistics : number of points, faces, cells; bounds; zone names etc.
  • Function object results : e.g. cached values for function objects results

Example usage:

caseInfo1
{
    type        caseInfo;
    libs        (utilityFunctionObjects);

    writeFormat json; // josn | dictionary

    // List of dictionaries - retrieve using 'path' or registered 'name'
    dictionaries
    {
        fvSolution
        {
            name        "fvSolution";

            // include all entries by default
        }
        controlDict
        {
            path        "system/controlDict";
            include
            (
                "application"
                "deltaT"
                "startTime"
                "endTime"
            );
        }
    }

    // Extract function object results
    functionObjects (pressureDifference sample1);
}

Example output

{
    "meta" : {
        "case" : "heatExchanger",
        "path" : "chtMultiRegionSimpleFoam/heatExchanger",
        "regions" : ["air", "porous"],
        "nTimes" : 7,
        "nProc" : 1
    },
    "regions" : {
        "air" : {
            "mesh" : {
                "nGeometricD" : 3,
                "nSolutionD" : 3,
                "nPoints" : 252991,
                "nFaces" : 739260,
                "nCells" : 243000,
                "nPatches" : 4,
                "pointZones" : [],
                "faceZones" : ["rotorBlades", "baffleFaces"],
                "cellZones" : ["cylinder", "innerCylinder", "rotor"],
                "boundsMin" : [0, 0, 0],
                "boundsMax" : [5.000000e-01, 5.000000e-01, 5.000000e-01],
                "clouds" : []
            },
            "boundary" : {
                "types" : {
                    "walls" : "wall",
                    "inlet" : "patch",
                    "outlet" : "patch",
                    "blades" : "wall"
                },
                "fields" : {
                    "alphat" : {
                        "walls" : "compressible::alphatWallFunction",
                        "inlet" : "calculated",
                        "outlet" : "calculated",
                        "blades" : "compressible::alphatWallFunction"
                    },
                    "nut" : {
                        "walls" : "nutkWallFunction",
                        "inlet" : "calculated",
                        "outlet" : "calculated",
                        "blades" : "nutkWallFunction"
                    },
                    "p" : {
                        "walls" : "calculated",
                        "inlet" : "calculated",
                        "outlet" : "calculated",
                        "blades" : "calculated"
...

Source code

New reduced-order modelling field reconstruction with DMD

TOP

Dynamic Mode Decomposition (DMD) functionality was introduced in OpenFOAM v2006 and later extended in OpenFOAM v2106. With this release, OpenFOAM learns one of the key advantages of DMD: the capability to generate a field based on given modes and their associated dynamics, without the need for any CFD computations at arbitrary intermediate and/or future time points.

This functionality allows users to condense an entire simulation into a few modes and mode dynamics, and subsequently generate fields at any desired time or predict their future states, all without the need for additional CFD analyses.

Another potential advantage is the ability for users to shorten their simulations and forecast the future states of the flow field without the need for extensive simulations. This can be achieved by using the modes and mode dynamics obtained from a shorter-duration simulation.

It should be noted that the quality of results depends on the capabilities of the underlying reduced-order model, and the quality of the input data. To improve the reconstruction results, one needs to make sure that modes are correctly extracted from the flow.

A minimal example by using system/ROMfieldsDict is as follows:

// Mandatory entries
ROMmodel        <word>;
field           <word>;
object          <word>;
deltaT          <scalar>;
time            <scalar>;
modes           <labelList>;
amplitudes      <complexList>;
eigenvalues     <complexList>;

// Optional entries
startTime       <scalar>;
dimensions      <dimensionSet>;

// Inherited entries
...

The illustration below shows the velocity field obtained from the two-dimensional cylinder tutorial, and its reconstruction by using the DMD modes and dynamics without running the simulation:

Source code

Tutorial

References

  • Kiewat, M. (2019). Streaming modal decomposition approaches for vehicle aerodynamics. PhD thesis. Munich: Technical University of Munich. URL:mediatum.ub.tum.de/doc/1482652/1482652.pdf

Attribution

  • OpenCFD would like to acknowledge and thank Marco Kiewat for his contributions, elaborate suggestions and help, and critical recommendations.

Merge request

  • Merge request 639

Improved noise utility

TOP

The noise utility now supports a user-defined sampling frequency (keyword: sampleFreq) as well as the default automatic calculation from the time information. For improved readability, the upper and lower frequency limits are now specified as minFreq and maxFreq (the old keywords continue to be supported), i.e.

// Lower frequency limit, default 25 Hz, former name 'fl'
minFreq 25;

// Upper frequency limit, default 10 kHz, former name 'fu'
maxFreq 10000;

// OPTIONAL - Sample frequency
sampleFreq 100;

If the time is assessed to be non-uniform when calculating the frequency from the sampled times, the utility now emits a warning instead of an error since in many cases the non-uniformity is a spurious error when the deltaT is very small.

Source code

Tutorial

Issue

Improved Ensight output

TOP

Time values for EnSight writers can now be specified by the user instead of using the default fixed format and precision. For example,

formatOptions
{
    ensight
    {
        timeFormat      general; // Format for time directory names (general | fixed | scientific); default scientific
        timePrecision   12;      // Default = 5
    }
}

These new format options are particularly useful when using small time-steps, e.g. in combination with pressure sampling for the noise utility.

Source code

Issue

  • Merge request 634

New Lagrangian function object: Weber Number

TOP

The Lagrangian function object WeberNumber is introduced for kinematic parcels to monitor the relative importance of a particle's inertia compared to its surface tension.

A minimal example usage is as follows:

cloudFunctions
{
    KinematicWeberNumber1
    {
        // Mandatory entries
        type             WeberNumber;
        sigma            <scalar>;
    }
 
    ...

Source code

Tutorial

Merge request

  • Merge request 648

Improved handling of empty surfaces (surfaceFieldValue)

TOP

In some workflows the sampled surfaces may depend on quantities such as face zones that appear and disappear during the course of the simulation. So although evaluating for a surface field value on an empty surface would normally indicate a serious error in the setup, in other cases this is expected. The additional keyword empty-surface allows the user to specify the desired behaviour when an empty surface is encountered.

A minimal example:

surfaceFieldValueFaceZone1
{
    type            surfaceFieldValue;
    libs            (fieldFunctionObjects);
    ...
    regionType      faceZone;

    empty-surface   warn;  // default | warn | ignore | strict
}

Source code

Issue