Draft. This manual is new and still growing. If something here does not match what you see in the software, the software is right — tell us and we will fix the page.
Case directory layout
What the application writes to disk, and where.
The claim this product makes is that it writes an ordinary input deck for the solver that will run it — 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 belongs to the backend that solves it. Everything SHD Sim adds sits outside it, in the case directory around it.
Which backend depends on the analysis type, and most of this page is about the fluid one:
| Analysis family | The study directory holds |
|---|---|
| Every fluid family — flow, heat, multiphase, reacting, atmospheric, marine, and the OpenFOAM specialist solvers | A standard OpenFOAM case: 0/, constant/, system/ |
| Structural, and Thermal on the code_aster backend | A code_aster deck: case.comm and case.export |
| Electromagnetics, Acoustics, and Thermal on the Elmer backend | An Elmer deck: case.sif, ELMERSOLVER_STARTINFO and a mesh/ directory |
| Explicit dynamics | An OpenRadioss deck: case_0000.rad and case_0001.rad |
| Shape optimisation | SU2 configurations — direct.cfg, adjoint.cfg, and ffd.cfg / dot.cfg / deform.cfg as the run needs them — beside mesh.su2 |
| Coupled (preCICE) | Both participants' own directories, unchanged — an OpenFOAM case with a system/preciceDict on the fluid side, a code_aster deck on the solid side — plus precice-config.xml in run/ beside them |
There is no system/controlDict in a structural, thermal, electromagnetic,
acoustic, explicit-dynamics or shape study, and looking for one is the wrong
question. Analysis types and solvers says which
family an analysis type belongs to. The sections below, up to
Standard OpenFOAM, or ours, describe the fluid
case.
The library
Cases live in a workspace directory. The default is
Documents/SHD Sim/My Cases, it is remembered between sessions, and
--workspace=<dir> overrides it for one run.
My Cases/
└── Streamlined hull drag study (example)/ <- one directory per case
├── case.json SHD Sim
├── thumbnail.png SHD Sim
├── geometry/ SHD Sim
│ └── hull.step the imported file, copied in
└── run/ SHD Sim
└── case/ <- the study directory: an OpenFOAM case
here, a code_aster or Elmer deck for
the families listed above
A 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 solver's 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
| 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
A fluid study only. From here down, nothing is SHD Sim'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 request
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
| 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
| 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)
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>/fvSolution
constant/regionProperties is what tells the solver — and the application, when
it reads the case back — that this is a multi-region case.
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
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
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
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
The distinction this page exists to make.
The backend's own — everything inside run/<study>/. For a fluid study that
means standard OpenFOAM, below. For the other families it means a code_aster,
Elmer, OpenRadioss or SU2 deck, in that tool's own format and named as that tool
expects: code_aster's run-aster.bat given case.export is what runs a
structural or code_aster thermal study, and ElmerSolver reading
ELMERSOLVER_STARTINFO is what runs an Elmer one.
Standard OpenFOAM — a fluid study's 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'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 a concept any of the backends have |
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 SimandDo 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
Open the case directory from the log dock, or find it at
Documents/SHD Sim/My Cases/<case>/run/<study>/
On a fluid study, read system/controlDict and then run the solver named in its
application entry against that directory using the bundled binaries. On a
structural or code_aster thermal study, read case.comm and hand case.export
to the bundled run-aster.bat. On an Elmer study, read case.sif and run
ElmerSolver in that directory. If any of them behaves differently from the way it behaved inside
the application, that is a defect worth reporting.