1. CAE Project Directory Skeleton and Naming Convention
Why the directory skeleton comes first
A CAE project fails quietly long before the solver diverges. It fails when someone opens final_v2_new_mesh_ok.fem and cannot tell which geometry it was meshed from, which solver deck consumed it, or whether the results in the adjacent folder belong to that deck at all. Directory structure and naming are the cheapest controls you can put in place, and they are the only ones that every downstream tool — Git, LFS, CI runners, post-processing scripts — will inherit automatically.
This case builds a reusable skeleton for a single CAE model line and a naming convention that encodes variant and revision in every artifact name. The deliverable is a directory tree plus a small validation script that rejects non-conforming filenames, so the convention is enforced rather than merely documented.
Designing the skeleton around artifact lifecycle
Partition by artifact type, not by person or by date. A workable five-folder layout for one model line is:
geometry/— native CAD exports and neutral formats (.step,.iges), one file per source revision.mesh/— meshed models and meshing journals/scripts, tied to a specific geometry revision.decks/— solver input decks (boundary conditions, material cards, load steps), tied to a specific mesh revision.results/— solver output, post-processing extracts, and run logs. Treated as derived and largely disposable.docs/— assumptions, correlation notes, run manifests, and the naming convention itself.
The dependency direction is strictly one-way: geometry → mesh → deck → results. Each folder's contents reference the upstream revision they were built from, which is what makes the naming convention load-bearing rather than cosmetic.
Naming convention: encoding variant and revision
Use a fixed, parseable pattern with underscore-separated fields and no spaces:
<project>_<variant>_<artifact>_r<NN>.<ext>
Field rules:
| Field | Rule | Example |
|---|---|---|
project | Lowercase short code, 3–8 chars, stable for the model line | brkt |
variant | Design variant identifier; base for the reference configuration | base, v2rib |
artifact | Artifact class: geom, mesh, deck, res, doc | mesh |
r<NN> | Zero-padded two-digit revision, incremented on any content change | r03 |
So brkt_base_mesh_r03.cdb is the third revision of the baseline mesh for the bracket line. The revision number is per artifact class, not global: geometry can be at r05 while the mesh derived from it is at r02. This is intentional — it keeps each artifact's history independent and makes the upstream link explicit in the run manifest rather than in the filename.
r<NN> token in naive parsers and make glob patterns like *_r[0-9][0-9].* ambiguous.Building the skeleton and enforcing the convention
Create the tree and a validator in one pass. The script below is self-contained: it builds the folders, writes a .gitkeep in each so empty directories survive version control, and validates any filename passed to it against the pattern.
#!/usr/bin/env bash
set -euo pipefail
PROJECT="brkt"
ROOT="${PROJECT}_cae"
for d in geometry mesh decks results docs; do
mkdir -p "$ROOT/$d"
touch "$ROOT/$d/.gitkeep"
done
# Naming convention: <project>_<variant>_<artifact>_r<NN>.<ext>
PATTERN="^${PROJECT}_[a-z0-9]+_(geom|mesh|deck|res|doc)_r[0-9]{2}\.[A-Za-z0-9]+$"
validate() {
local f
for f in "$@"; do
if [[ ! "$(basename "$f")" =~ $PATTERN ]]; then
echo "REJECT: $(basename "$f") does not match convention" >&2
return 1
fi
echo "OK: $(basename "$f")"
done
}
validate \
"$ROOT/geometry/brkt_base_geom_r01.step" \
"$ROOT/mesh/brkt_base_mesh_r01.cdb" \
"$ROOT/decks/brkt_base_deck_r01.inp" \
"$ROOT/results/brkt_base_res_r01.rst" \
"$ROOT/docs/brkt_base_doc_r01.md"
Run it from an empty working directory. Expected output is five OK: lines and a tree containing brkt_cae/{geometry,mesh,decks,results,docs}. Now test the negative path — this is the part people skip:
validate "$ROOT/mesh/final_mesh_new.cdb"
Expected: REJECT: final_mesh_new.cdb does not match convention and a non-zero exit status. If the script prints OK here, your pattern is too permissive — check that the anchors ^ and $ survived shell quoting.
Reading the dependency chain
The diagram below shows how the five folders chain together and where the revision token does the linking work. Note that the run manifest in docs/ is the only place the full upstream set is recorded; filenames stay short and parseable.
Verification and common failure modes
Accept the skeleton when all of the following hold:
find brkt_cae -type d | sortlists exactly the five artifact folders plus the root.- Every file you intend to commit passes
validatewith exit status 0. - A deliberately malformed name (spaces, missing revision, wrong artifact token) is rejected with a non-zero status.
- The manifest in
docs/names the exact upstream revision for each downstream artifact.
Typical symptoms and their causes: a validator that accepts everything usually means the regex lost its anchors through unquoted shell expansion; a validator that rejects valid names usually means the variant token contains uppercase or a hyphen, which the [a-z0-9]+ class forbids. If git status shows empty folders as untracked-and-missing after a clone, the .gitkeep files were not created — rerun the loop.
Reusable checklist
| Check | Pass condition |
|---|---|
| Folder set | geometry/ mesh/ decks/ results/ docs/ present under brkt_cae/ |
| Empty-dir survival | .gitkeep in every folder |
| Pattern | ^brkt_[a-z0-9]+_(geom|mesh|deck|res|doc)_r[0-9]{2}\.[A-Za-z0-9]+$ |
| Positive test | Five sample names return OK, exit 0 |
| Negative test | final_mesh_new.cdb returns REJECT, exit 1 |
| Traceability | Manifest lists upstream revision per artifact |
With the skeleton and validator in place, every later step — committing a baseline deck, moving large geometry into LFS — operates on a tree whose names already carry variant and revision, so history stays readable without extra discipline.