OutWit.Controller.OpenFOAM 1.1.0

dotnet add package OutWit.Controller.OpenFOAM --version 1.1.0
                    
NuGet\Install-Package OutWit.Controller.OpenFOAM -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OutWit.Controller.OpenFOAM" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OutWit.Controller.OpenFOAM" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="OutWit.Controller.OpenFOAM" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add OutWit.Controller.OpenFOAM --version 1.1.0
                    
#r "nuget: OutWit.Controller.OpenFOAM, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package OutWit.Controller.OpenFOAM@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=OutWit.Controller.OpenFOAM&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=OutWit.Controller.OpenFOAM&version=1.1.0
                    
Install as a Cake Tool

OutWit.Controller.OpenFOAM

Runs complete OpenFOAM® cases on WitCloud compute nodes. One run = one whole case on one node - meshing, decomposition, the solver and the post step, through an allow-listed recipe; case support is whatever the pinned kit solves. The win is throughput across many independent runs, which is what the companion OutWit.Controller.Sweep orchestrates into parameter studies (its SweepOpenFOAM.wit fans a case study out to Foam.Run); any script can also drive Foam.Run directly through Grid.ForEach.

Activity

Activity Side Purpose
Foam.Run(FoamTask) → FoamResult node Materialise the variant's case from the base files and its token substitutions, refuse it by name if it carries run-time code or an unknown step, run the recipe under the bundled kit in a scratch directory (parallel steps under the kit's MPI on the controller-written decomposeParDict, scotch), read the convergence facts from the solver log and the requested responses from postProcessing/, zip and upload what the artifact policy asks for. A failed step, a diverged solve or a refused case is data in the result, not a task failure.

A task (FoamTaskData) is a case and a variant: the case (FoamCaseData, the same for every variant of a study) carries the base tree as blob references (fetched once per node), the recipe, the rank policy, the response request, the artifact policy, and the cell count and solver class as scalars so work estimation never opens a file; the variant adds only its token values. Results return in completion order - consumers map by VariantIndex, never positionally.

The rules a case obeys - the allow-list, the recipe grammar, the case paths, the response request, the token coverage - live in OutWit.Controller.OpenFOAM.Model (Rules/), so the node, the Sweep host and an initiator's preflight refuse the same things with the same sentences. What needs the kit or the materialised files (executables, libraries, run-time code) is checked here, on the node. The whole of it - the build and its platforms, the allow-list, what a case may not carry, the responses, the solver classes - is published, held to the rules by the tests, in SUPPORTED-INPUTS.md.

What a case may contain

The kit ships no compiler, so anything that compiles C++ at run time is refused before the first process starts, with file and line: codeStream, #codeStream, #calc (#eval is the in-built evaluator and is allowed), coded* conditions and function objects, a dynamicCode/ directory. Also refused: libs entries naming libraries outside the kit, include directives (#include, #sinclude, #includeIfPresent, #includeEtc, #includeFunc) whose target leaves the case, a decomposed-only case, a recipe step outside the allow-list (FoamAllowList in the Model), an argument the allow-list's grammar does not accept, a path with a space (OpenFOAM strips whitespace from paths), and leftovers of an earlier run in the base case (log.*, postProcessing/, processor*/), which would pass for this run's. A response name that collides with a file the case ships under system/ is refused rather than overwritten.

A response is read from the last row of each file in its function object's latest postProcessing/<name>/<time>/ directory. A file whose last row is not at the run's final time - a function object that stopped writing before the run ended - is not reported: the node names it in log.responses, which travels with the step logs.

The controller's own steps

Two steps of a recipe are the controller's rather than the kit's. Neither runs under MPI; each writes its log like any step's (log.restore0Dir, log.includeFunc) and reports 0 ranks, as a step no process ran.

restore0Dir -processor, named after OpenFOAM's RunFunctions. A case meshed on its decomposed form - decomposePar over the background mesh, then snappyHexMesh in parallel, as the motorBike tutorial does - needs its initial fields put into every processor directory afterwards: the fields decomposePar split were cut for a mesh that no longer exists. The step replaces each processor*/0 with the initial fields: 0.orig/ when the case carries one, as in OpenFOAM, otherwise 0/ as it was before the first step (kept in 0.orig/ for the purpose). It needs a decomposePar before it and never runs under MPI; on a node without MPI the run is serial, there are no processor directories, and the step logs that it has nothing to do. A decomposed run without processor<N> directories (a case whose controlDict sets a collated file handler) or without initial fields fails at this step, by name.

includeFunc <response> measures a response during the solve instead of after it. It is the one change the controller makes to a case's own files, made only when a recipe asks for it and only in the node's copy: one line, #includeFunc <response>, at the end of the top-level functions block of system/controlDict (a block of its own when the case has none), so the solver runs the response's function object, system/<response>, while it solves. The reason is a force on a wall a rotating zone (MRF) turns: OpenFOAM moves such a wall only inside the solve, so the same force measured afterwards (<solver> -postProcess) sees it at rest - the torque on the inner cylinder of a Couette flow comes out about fourteen times too large and of the wrong sign (the kit oracle test holds both numbers). The step needs a solve after it, names only a response of the task, and fails by line - the copy left as it was - when functions is not a block the controller can add a line to (#includeEtc, a $ reference). Its log says what was added, where, and why.

The mesh a run reports (CellCount) is the one it ended with: read from the header OpenFOAM writes on every mesh (the processor meshes summed for a decomposed solve), else the last count a step's log reports - the mesh snappyHexMesh wrote, not the background mesh blockMesh made for it.

Bundled kit

The module carries pinned OpenFOAM v2606 kits for win-x64, linux-x64 and osx-arm64 as controller data assets, produced and mirrored by OmnibusCloud/OpenFOAM. Nodes need no preinstalled OpenFOAM: the Linux and macOS kits bundle Open MPI 4.1.8, scotch and fftw, and every kit is relocatable by environment - the kit's KIT.env records the exact environment its build established, the controller substitutes the kit folder and the task's scratch and sets the result on the solver process, with HOME and TMPDIR inside the scratch. The scratch is a scope of the temp folder the host hands the controller (on a node, the client's controllers' temp folder, Settings > Storage), never a folder of the controller's own, and it goes back to that folder however the run ends. On Windows the scratch must leave room for the case's own paths below it: a temp folder so deep that a run's folder there passes 139 characters (259 minus 120 kept for the deepest paths a decomposed case writes) is refused with the reason, and the benchmark fails the same way, so the node leaves the OpenFOAM pool. Nothing is sourced on a node; a run writes into the case directory and the scratch and nowhere else (the kit folder itself changes only once, when the kit is first resolved on a node: the Unix executable bits a zip does not keep are restored, and on Windows the Pstream swap below is made). The Windows kit is cross-compiled from the same pinned source with MinGW-w64 and ships two Pstream libraries: the serial one is in place as shipped, and when the node has Microsoft MPI installed (MS-MPI is the machine owner's to install; its licence allows redistributing only its installer) the controller copies the MS-MPI one over it on the first resolution of the kit (idempotent) and runs parallel steps under the node's mpiexec; a node without MS-MPI runs every step serially. Before a kit is used the controller spot-checks it against its own BUILDINFO.txt (a sample of the listed hashes) and refuses a kit that is short of a file or carries an altered one, naming the file (a file another process, such as a scanner, holds for a moment is read again first). It also refuses, with the reason in words, a kit that is incomplete (no usable KIT.env, no solver) and a kit it cannot run from where it is installed: under a folder with a space on Linux or macOS (OpenFOAM rejects whitespace in a path and dies on its own executable path), or on Windows so deep that a kit file would pass 259 characters (the Windows binaries are not long-path aware). A node with such a kit fails the Foam.Run benchmark with the reason and so leaves the OpenFOAM pool, instead of failing every variant; only a node with no kit folder at all (an unsupported platform) keeps the default score. OpenFOAM is GPL-3.0: the kit ships the licence text and the written source offer, and the corresponding source is publicly mirrored in that repository's releases.

Node benchmark: Foam.Run is ranked by pitzDaily from the kit's own tutorials, meshed once and then solved serially for a fixed 50 iterations, in unit foam-simple@pitzDaily50-v1: one untimed warm-up, the rate from the median of three to five timed runs. Parallel steps run with at most 16 ranks (FoamDecomposition.MAX_DEFAULT_RANKS) when the task asks for all cores.

OpenFOAM® is a registered trademark of OpenCFD Limited. This offering is not approved or endorsed by OpenCFD Limited, producer and distributor of the OpenFOAM software via www.openfoam.com, and owner of the OPENFOAM® and OpenCFD® trade marks.

Dependencies

Variables (module dependency). The shared data types and the case rules live in OutWit.Controller.OpenFOAM.Model, consumed by this controller, by the Sweep orchestration controller (an OpenFOAM study carries a FoamCaseData; its manifest rows carry the FoamResultData verbatim) and by client applications composing case sweeps.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 0 9/29/2026
1.0.6 61 9/27/2026
1.0.5 60 9/26/2026
1.0.4 56 9/26/2026
1.0.3 54 9/26/2026
1.0.2 65 9/25/2026