Optimizing Outputs with OpenFOAM’s writeObjects

7 minute read

Published:

Efficient data handling is a cornerstone of successful computational fluid dynamics simulations, and OpenFOAM provides powerful tools to achieve this. Among them, the writeObjects function object stands out for its ability to specify different writing frequencies for various objects registered in the simulation database. This capability allows users to tailor output schedules for volume fields and other entities, optimizing disk usage and post-processing workflows. In this blog, we will explore how configuring and utilizing writeObjects can enhance simulation efficiency. Whether you’re optimizing a large-scale simulation or managing limited resources, this guide will help you make the most of OpenFOAM’s functionality.

In computational fluid dynamics, managing simulation data efficiently is as critical as running the simulation itself. OpenFOAM offers a robust feature set to help users optimize their workflows. Among these features, the writeObjects function object provides a simple yet powerful way to control the writing frequency of various objects registered in the simulation database. Whether you’re working with scalar fields, vector fields, or surface data, this functionality enables you to reduce redundant outputs and streamline post-processing without compromising on the data you need.

In this blog, we’ll explore how the writeObjects function object works, why it’s an essential tool for any OpenFOAM user, and how to configure it effectively for your simulations. By the end of this article, you’ll have a clear understanding of how to leverage writeObjects to balance simulation output precision with resource efficiency.

For this tutorial, I will again use the simulation of three-dimensional flow around a square cylinder at Reynolds number of 260. You can find a reference case setup here.

Lets Begin!!!

OpenFOAM Object Registry

Before diving into the writeObjects function, it’s crucial to understand the OpenFOAM object registry, as this is the source from which we will extract our fields of interest. The objectRegistry serves as a hierarchical database that OpenFOAM uses to organize case-related data. This structured database is maintained by OpenFOAM solvers at various levels:

  1. Primary Registry: This is the Time object or the runTime database, which acts as the root of the objectRegistry.
  2. Second-Tier Database: This level consists of mesh regions and global properties defined in the controlDict.
  3. Lower Levels: Sub-objects are registered here, such as individual mesh regions with their respective fvSchemes, fvSolution, mesh data, and fields created in files like createFields.H.

The objectRegistry is built around two main components:

  1. IOobject: This class standardizes input/output operations and provides access to runTime, the root of the objectRegistry.
  2. regIOobject: This class automates the registration and deregistration of objects within the objectRegistry.

By understanding the objectRegistry, we can better grasp how writeObjects interacts with these components to selectively output data from a simulation. For instance, in a standard solver, the objectRegistry might look like this:

* runTime         # objectRegistry
 |--> controlDict # regIOobject (can't have sub-entries attached to it)
 |--> mesh1       # objectRegistry (a database)
    |--> points, owner, neighbour, cellZones ...
    |--> fvSchemes, fvSolution
    |--> U, p
 |--> mesh2
    |--> points, owner, neighbour, cellZones ...
    |--> fvSchemes, fvSolution
    |--> U, p

For instance, let’s explore the objectRegistry or check the available objects in the database for a sample simulation. You can do this by running the following command in a terminal where OpenFOAM is sourced:

pimpleFoam -postProcess -func "writeObjects(banana)" -latestTime

In this example, since banana is not a valid object in the OpenFOAM simulation database, the executable will output a list of available objects that you can choose from. For example, the output in my case looks like this:

writeObjects writeObjects(banana) write:
--> FOAM Warning :
    From virtual bool Foam::functionObjects::writeObjects::write()
    in file writeObjects/writeObjects.C at line 162
    No corresponding selection for (banana)
Available objects in database:

20
(
MRFProperties
U
boundary
cellZones
data
faceZones
faces
fvOptions
fvSchemes
fvSolution
neighbour
nu
owner
p
phi
pointZones
points
solutionControl
transportProperties
turbulenceProperties
)

This approach is a straightforward way to inspect the objectRegistry and identify objects available for post-processing or output customization. The output reveals that there are 20 objects available in my simulation that can be written out. For example, velocity and pressure fields are commonly available for this purpose. Let’s use the same command as before but this time attempt to write the phi field:

pimpleFoam -postProcess -func "writeObjects(phi)" -latestTime

This command should create a phi field in your latestTime folder. If the phi field already exists in the folder, you can delete it and run the command again to ensure it’s correctly written out. This demonstrates how writeObjects can be used to selectively output specific fields from the simulation database.

Extracting fields using writeObjects

Imagine a scenario where you are running a simulation on an HPC system with limited storage. To conserve space, you might use the purgeWrite setting to retain only the last three time steps. However, what if you need full-domain velocity and pressure snapshots from the simulation? This is where the writeObjects function object becomes incredibly useful.

The writeObjects function object operates similarly to the writeControl setting in your controlDict. It allows you to write out specific fields of interest at a defined frequency. Let’s see how to configure it. Add the following lines of code to the <case>/controlDict/functions section:

  fieldofinterest
	{
	   type        writeObjects;
	   libs        ("libutilityFunctionObjects.so");
	   objects     (U p);
	   writeControl    timeStep;
	   writeInterval   25;
	   purgeWrite      0;
	   writeFormat     ascii;
	   writePrecision  8;
	   writeCompression uncompressed;
	   timeFormat      general;
	   timePrecision   8;
	   writeOption autoWrite;
	}

This configuration saves velocity (U) and pressure (p) fields every 25 time steps, which is significantly more frequent than the full simulation write interval. This allows you to collect detailed snapshots of the fields while keeping the size of your simulation directory manageable.

For instance, let’s compare the size of two time directories: one containing only the fields of interest and the other with the full simulation data:

du -sh 1996.85/ 1997.05/
## OUTPUT
## 21M     1996.85/
## 67M     1997.05/

The results clearly show that the directory containing only the fields of interest is significantly smaller, demonstrating the effectiveness of the writeObjects function in managing disk space without sacrificing data granularity.

Extended usage

The writeObjects function object can be further extended for more advanced use cases. Imagine a scenario where you want to exclude certain variables from being written to files while specifying others to be saved. This is particularly useful in multiphase simulations, where you might deal with multiple fields and want precise control over what gets written.

To achieve this, you can define multiple writeObjects function objects in your controlDict, specifying which fields to omit and which to write. Ensure that the controlDict/writeInterval is set appropriately to control the overall output frequency. For example:

functions
{
	  writeObjects1
		{
			type        writeObjects;
			libs        ("libutilityFunctionObjects.so");
			objects     (rho nut alphat alphaPhi0.water phi T.air T.water);
			writeOption noWrite;
		}
	  writeObjects2
		{
			type        writeObjects;
			libs        ("libutilityFunctionObjects.so");
			objects     (U p T alpha.water);
			writeOption autoWrite;
		}
}

In this setup:

  • The first function object, writeObjects1, excludes fields like rho, nut, and alphat using the noWrite option, ensuring they are not written to disk.
  • The second function object, writeObjects2, uses the autoWrite option for fields such as U, p, T, and alpha.water, following the output frequency specified in controlDict/writeInterval.

This flexibility allows you to optimize both storage usage and post-processing requirements by precisely managing what data is written out during your simulations.