Case directory layout
What the application writes to disk, and where.
The claim this product makes is that it writes an ordinary OpenFOAM case — one you can open in a text editor, run from a shell with the bundled binaries, hand to a colleague who has never seen this application, or diff against a case somebody else built by hand. This page is here so you can check that rather than take it on trust.
The short version: everything under a study directory is standard OpenFOAM. Everything SHD Sim CFD adds sits outside it, in the case directory around it.
The library
Section titled “The library”Cases live in a workspace directory. The default is
Documents/SHD Sim CFD/My Cases, it is remembered between sessions, and
--workspace=<dir> overrides it for one run.
My Cases/└── Submerged body drag study/ <- one directory per case ├── case.json SHD Sim CFD ├── thumbnail.png SHD Sim CFD ├── geometry/ SHD Sim CFD │ └── hull.step the imported file, copied in └── run/ SHD Sim CFD └── case/ <- an ordinary OpenFOAM case from here downA case is a directory with a case.json in it — that is the test used on import,
and an archive with no case.json anywhere is rejected.
The OpenFOAM directories live inside the case, not under AppData. A case has to be the whole case or it cannot be shared, archived or backed up.
Where a study lands
Section titled “Where a study lands”| Case has | Directory |
|---|---|
| One study | run/case/ |
| More than one study | run/<study name>/, one per study |
Two studies of the same body have different meshes and different solutions, so
each gets its own directory rather than meshing over the other’s polyMesh.
Study names are sanitised for the filesystem: \ / : * ? " < > | become _,
whitespace runs become _, leading dots are stripped, and an empty result
becomes case.
--dump-case=<dir> writes to <dir>/golden/ instead. With no case open at all —
the dump and catalogue paths — the fallback root is runs/ under the
application’s local data directory.
The OpenFOAM case
Section titled “The OpenFOAM case”From here down, nothing is SHD Sim CFD’s own invention.
run/case/├── 0/ one file per field├── constant/│ ├── polyMesh/ written by the mesher│ ├── triSurface/ the geometry as ASCII STL│ └── … physical properties├── system/│ ├── controlDict│ ├── fvSchemes│ ├── fvSolution│ └── … utility dictionaries├── <time>/ written by the solver├── postProcessing/ written by function objects├── processor*/ written by decomposePar├── log.<application> one per utility and solver step└── <case name>.foam an empty ParaView marker, on requestAlways written
Section titled “Always written”| File | |
|---|---|
system/controlDict |
Run control, libs, and every function object |
system/fvSchemes |
Discretisation |
system/fvSolution |
Linear solvers and the SIMPLE/PIMPLE/PISO block |
system/decomposeParDict |
Parallel decomposition |
system/blockMeshDict |
The background block |
system/snappyHexMeshDict |
Body-fitted meshing |
system/surfaceFeatureExtractDict |
Feature edges — one entry per geometry part |
system/meshQualityDict |
#includeEtc the shipped defaults, then override maxNonOrtho and minTetQuality |
0/<field> |
One per field in the derived field set |
constant/turbulenceProperties is written except for the Euler-Euler,
electrostatic, magnetic, MHD, solid-stress, conduction and shallow-water
families.
constant/transportProperties or constant/thermophysicalProperties — never
both. They are alternatives: a solver that builds a thermophysical model reads
the latter and ignores the former, so shipping both leaves one silently unused.
Neither is written for the Euler-Euler, electrostatic, solid-stress or
shallow-water families.
Written when the physics asks for it
Section titled “Written when the physics asks for it”| Family | Adds |
|---|---|
| Marine & Waves | constant/waveProperties |
| Euler-Euler | constant/phaseProperties, and per phase constant/thermophysicalProperties.<phase> and constant/turbulenceProperties.<phase> |
| Lagrangian | constant/kinematicCloudProperties |
| Compressible multiphase | constant/thermophysicalProperties.<phase> per phase |
| Rotating frame (SRF) | constant/SRFProperties |
| Solid stress | constant/mechanicalProperties, constant/thermalProperties |
| Electrostatics, magnetostatics, MHD | constant/physicalProperties |
| Shallow water | constant/gravitationalProperties |
| Spray | constant/sprayCloudProperties, constant/combustionProperties, constant/chemistryProperties, constant/reactions, constant/thermo |
| Premixed combustion | constant/combustionProperties |
| Combustion / Reacting | constant/combustionProperties, constant/chemistryProperties, constant/reactions, constant/thermo, constant/radiationProperties |
Written when a setting asks for it
Section titled “Written when a setting asks for it”| Setting | Adds |
|---|---|
| Gravity on, or a solver that requires it | constant/g |
| A rotating zone | constant/MRFProperties |
| Any cell zone to cut | system/topoSetDict |
| A moving mesh | constant/dynamicMeshDict |
| A 6-DoF body | 0/pointDisplacement |
| An initialisation region, or a VoF fill level | system/setFieldsDict |
| Any fvOptions item, or Coriolis | constant/fvOptions |
Mesh operation mirrorMesh |
system/mirrorMeshDict |
Mesh operation extrudeMesh |
system/extrudeMeshDict |
Mesh operation createPatch |
system/createPatchDict |
Mesh operation refineMesh with a cell set |
system/refineMeshDict |
Mesh operations that can be driven entirely from the command line —
renumberMesh, subsetMesh and the rest — get no dictionary.
Multi-region (conjugate heat transfer)
Section titled “Multi-region (conjugate heat transfer)”A conjugate case has a different shape entirely: almost nothing at the top level, because nothing is solved there.
run/case/├── 0/<region>/<field>├── constant/│ ├── regionProperties│ ├── g│ └── <region>/thermophysicalProperties│ └── <region>/turbulenceProperties fluid regions only└── system/ ├── controlDict fvSchemes fvSolution decomposeParDict ├── blockMeshDict snappyHexMeshDict ├── surfaceFeatureExtractDict meshQualityDict └── <region>/fvSchemes └── <region>/fvSolutionconstant/regionProperties is what tells the solver — and the application, when
it reads the case back — that this is a multi-region case.
Field files
Section titled “Field files”One file per field in 0/. Which fields exist is derived from the analysis type
and the turbulence model, not chosen; see
Turbulence and viscosity models and
Analysis types and solvers.
Each file carries dimensions, internalField and a boundaryField with one
entry per patch. Dimensions are derived from the field name and are never asked
for. The patch entries are the fan-out described in
Boundary condition types.
What the mesher and the solver add
Section titled “What the mesher and the solver add”Nothing below is written by the application. It is what the bundled OpenFOAM utilities produce, in the places they normally produce them.
| Path | Written by |
|---|---|
constant/triSurface/body.stl, or one .stl per geometry part |
Written by the application before meshing, from the imported geometry |
constant/triSurface/*.eMesh |
surfaceFeatureExtract |
constant/polyMesh/ |
blockMesh, then snappyHexMesh |
constant/<region>/polyMesh/ |
splitMeshRegions |
<time>/ directories |
The solver |
postProcessing/<function>/<time>/<file>.dat |
The function objects in controlDict |
processor*/ |
decomposePar, run with -force so an earlier decomposition is replaced. reconstructPar reads them back afterwards |
system/data |
The solver, as a cache of the last run’s residuals |
log.<application> |
The application, capturing each step’s merged output |
log.checkMesh, log.blockMesh, log.snappyHexMesh, log.simpleFoam and so
on. This is the convention OpenFOAM users expect, and it is the only record left
once the log dock is cleared or the application is closed. It is also what the
application reads back to recover the mesh quality figures for a case it did not
mesh in this session.
system/data is deleted before every fresh run. A diverged run writes nan into
it and the next attempt then dies before its first iteration with
Wrong token type — expected scalar value, found on line 2: word 'nan', which
says nothing about the divergence that actually happened. The per-rank copies
under processor*/system/data are deleted too, because decomposePar does not
overwrite what is already in a processor directory.
The mesh consolidation step
Section titled “The mesh consolidation step”snappyHexMesh -overwrite writes its layer-added points into 0/polyMesh/ and
leaves the pre-layer positions in constant/. A time directory shadows
constant/ entirely, so the solver would read one and the utilities the other.
Immediately after snapping, the application moves 0/polyMesh/* into
constant/polyMesh/ — and 0/<region>/polyMesh/* into
constant/<region>/polyMesh/ — and says so in the log. Everything downstream
then reads the mesh the mesher actually produced.
This is a fix-up, not a format change. What ends up in constant/polyMesh is an
ordinary polyMesh.
Regeneration, and what survives it
Section titled “Regeneration, and what survives it”The case is regenerated in full on every write. Nothing is patched in place.
| Directory | On rewrite |
|---|---|
0/ |
Written, and pruned — any field file no longer part of the case is deleted |
constant/ |
Written over. Nothing is deleted |
system/ |
Written over. Nothing is deleted |
0/ is pruned because OpenFOAM reads every field in the start time directory. A
field left behind by an earlier configuration is still read: switching a case to
a laminar solver left 0/k, 0/omega and 0/nut on disk, and renumberMesh
then failed on 0/k because its boundaryField named patches the current mesh
no longer had.
constant/ and system/ are not pruned, deliberately. They can legitimately
hold a dictionary the application does not generate — a chemistry mechanism, an
optimisationDict — and deleting those would throw away work. A dictionary you
add by hand to constant/ or system/ survives; a field you add to 0/ does
not.
Fields are not written at all on the pass that imports a mesh. Until the converter has run, nobody knows what the patches are called.
Paths are sanitised before anything is written: absolute paths, drive letters,
UNC prefixes, .. traversal and the characters < > : " | ? * are all refused,
and the refused paths are reported rather than silently dropped.
Standard OpenFOAM, or ours
Section titled “Standard OpenFOAM, or ours”The distinction this page exists to make.
Standard OpenFOAM — everything inside run/<study>/. The dictionary names,
the directory structure, the FoamFile header, the keyword-and-semicolon syntax,
the dimension sets, log.<application>, postProcessing/, processor*/,
system/data, the time directories. A case copied out of run/ and run from a
shell with the bundled binaries behaves exactly as it does here.
SHD Sim CFD’s own — everything outside it.
case.json |
The case model: analysis type, every setting, every study, the post-processing pipeline. This is what the application reads; it does not reconstruct a case by parsing the dictionaries back |
thumbnail.png |
320 px render of the viewport, captured on save, so the library is scannable |
geometry/ |
The imported geometry file, copied into the case so the case is portable |
run/ |
The container for study directories. Not an OpenFOAM concept |
exports/ |
CSV, images and animation frames, stamped with the time they were written |
Two things inside the case are ours in content but standard in form:
- The banner comment at the top of every generated dictionary reads
Generated by SHD Sim CFDandDo not edit by hand. It is a comment. TheFoamFileblock below it is standard. - The
.foammarker file, written on request for ParaView, is named after the case rather thancase.foam. It is empty either way — ParaView reads the directory it sits in.
Nothing in the case directory is encrypted, compressed, binary-only or keyed to
an installation. writeFormat defaults to binary for the time directories,
which is an OpenFOAM setting and can be changed to ascii; every dictionary the
application writes is ASCII regardless.
Checking the claim
Section titled “Checking the claim”Open the case directory from the log dock, or find it at
Documents/SHD Sim CFD/My Cases/<case>/run/<study>/Read system/controlDict, then run the solver named in its application entry
against that directory using the bundled binaries. If it behaves differently from
the way it behaved inside the application, that is a defect worth reporting.