Wire pyOFTools into system/controlDict¶
This recipe shows how to attach a PostProcessorBase subclass as an
OpenFOAM function object so it runs every write interval during the solver
loop. Use this when you have a working post-processor (see
Your first in-situ post-processor) and want to execute it
in-situ.
Prerequisites¶
OpenFOAM is sourced and pybFoam is installed.
A running case directory with
system/controlDict,constant/,0.orig/.libembeddingPython.sois available — this is what lets OpenFOAM load a Python function object (ships with pybFoam-based builds).
Recipe¶
Write the post-processor. Save as
postProcess.pyin the case root (next tosystem/):from pyOFTools.postprocessor import PostProcessorBase from pyOFTools.builders import field, iso_surface, residuals from pyOFTools.aggregators import VolIntegrate, Sum postProcess = PostProcessorBase() @postProcess.Table("vol_alpha.csv") def vol_alpha(mesh): return field(mesh, "alpha.water") | VolIntegrate() @postProcess.Table("free_surface_area.csv") def free_surface_area(mesh): return iso_surface(mesh, "alpha.water", 0.5) | Sum() @postProcess.Table("residuals.csv") def solver_residuals(mesh): return residuals(mesh)
The module-level instance must be called
postProcessif you use the defaultpyClassNamebelow — otherwise change the class name to match.Register the function object in
system/controlDict:functions { pyPostProcessing { libs ("libembeddingPython.so"); type pyPostProcessing; writeControl timeStep; writeInterval 1; pyFileName postProcess; // postProcess.py pyClassName postProcess; // module-level instance name } }
pyFileNameis the Python module (no.pyextension).pyClassNameis the name of the ``PostProcessorBase`` instance in that module, not a class. The embedding loader looks uppostProcess.postProcessin this example.
Run the solver from the case directory:
blockMesh setFields # if the case needs it interFoam # or your solver
Read the output from
postProcessing/:postProcessing/ ├── vol_alpha.csv ├── free_surface_area.csv └── residuals.csv
Each file has a
timecolumn and one column per aggregated value.
Parallel runs¶
Run as usual:
decomposePar
mpirun -np 4 interFoam -parallel
TableWriter runs the workflow on every rank (so internal Foam::reduce
calls see all cells) but only writes on rank 0, so you get one CSV per
output file — not one per processor.
Picking writeControl¶
timeStep+writeInterval 1— write every step. Highest cost, best time resolution. Good for statistics.writeTime— write only when the solver writes fields. Cheapest, same cadence as the fields on disk.adjustableRunTime+writeInterval 0.05— fixed wall-clock cadence, useful whenadjustTimeStep yes.
See also¶
Troubleshooting —
pyFileName/pyClassNamemistakes, CSV files not appearing, SIGFPE on numpy import.Migrate from the raw-WorkFlow API to @PostProcessorBase — porting a pre-decorator post-processor to this pattern.
Architecture — what
@Tableactually registers and howPostProcessorBasebecomes a function object.