Method

The upper floors were perfectly tenable, and that was the problem

Every storey above the fire read ambient temperature and full visibility. Not "acceptable tenability" — exactly ambient, as though nothing had happened anywhere in the building.

That is a wonderful result if you are trying to get a scheme approved. It is also the single most alarming thing a smoke model can tell you, because real smoke does not respect a floor slab that carefully.

What a sealed shaft looks like in the output
upper storeysambient temperature, full visibility, throughout
fire flooroverheating — the smoke has nowhere to go
solvercompleted normally, exit 0, no warning
The tell is the pairing. Perfect upstairs AND hotter than expected downstairs is not good smoke control. It is a model in which the two are not connected.

What actually happened

The smoke shaft ran the full height of the building. The computational mesh did not: it was divided into blocks, and one of the horizontal boundaries between those blocks landed on a floor slab that the shaft passed through.

FDS is generally happy for meshes to abut. But a boundary lying across a vertical shaft, at the level of a slab, does not behave like an interface the flow can cross. The shaft was severed at that height. Smoke rose to the cut and stopped.

Nothing failed. The solver did exactly what the geometry described. The geometry described a building whose stair was blocked at fourth floor level by something invisible.

This is not a fringe case. Meshes get divided for entirely good reasons — to balance work across MPI ranks, to keep any single mesh small enough to fit in memory, to refine a region of interest. Every one of those decisions puts boundaries somewhere, and a tall narrow shaft is exactly the geometry most likely to be crossed by one.

Horizontal seals. Vertical does not.

The obvious fix is to forbid mesh boundaries anywhere near a shaft. We tried that and it was wrong — and the reason is worth understanding, because it is the difference between a usable model and an unusable one.

Cuts through a vertical shaft
horizontalSEALS IT.
verticalharmless.
A horizontal cut is across the flow: the shaft is severed and nothing rises past it. A vertical cut runs ALONG the flow — both halves remain full height, the smoke rises in both, and the interface is doing the ordinary job of a mesh boundary.

Forbidding both is safe and expensive. When we did it, each stair core became a single mesh of 145,152 cells, and the cell balance across 24 MPI ranks went from 1.5 to 3.2 — meaning the slowest rank now had more than three times the work of the fastest, and every other rank sat waiting for it.

A model that is correct and takes three times as long is not a fix. It is a different failure, paid for in wall-clock instead of physics.

So the rule the emitter now follows is narrower and harder to write: every shaft sits in a full-height mesh column. Vertical tiling cuts may fall inside a shaft interval freely. Horizontal cuts may not cross one at all. With no refinement the whole domain is full-height columns anyway; with refinement, only the plan columns carrying a shaft are exempt from the z-cuts.

The other way alignment bites

Mesh boundaries also have to agree with each other, and FDS is strict about how:

  • Integer ratios only. A refined mesh at 0.125 m against a 0.2 m background is a 1.6:1 ratio, and FDS refuses the deck with ERROR(431). We measured 1.5:1 and 2.5:1 being refused the same way. Only whole-number ratios work.
  • Faces must land on the coarse grid. A refinement whose boundary falls between background grid lines leaves a coarse cell partly covered by fine cells. Same error.
  • The fire must lie wholly inside one mesh. A burner straddling an interface is a burner that is not the one you specified.

The useful thing about this class of error is that FDS does catch it — loudly, with an error number. It is the opposite of the sealed shaft, which is caught by nothing.

Which is why the deck is emitted twice: once for the run, and once with CHECK_MESH_ALIGNMENT=T and T_END=0. That second deck does no physics at all. It exists purely so the solver can tell us the meshes disagree before anybody spends sixty hours finding out.

Both settings are required. With alignment checking on and a real T_END, you get a full simulation you did not want. With T_END=0 alone, you get nothing checked.

How to catch it in someone else's model

You will not see the mesh in a report. What you can do is read the results for the signature, which is distinctive once you know it:

  • An upper storey at exactly ambient while a lower one is in trouble. Real stratification is gradual and messy. A clean step between floors is a boundary, not a physical result.
  • A fire compartment hotter than the design fire suggests. If the smoke cannot leave, the energy stays.
  • Shaft flow that stops at a slab level. If velocity is reported in the shaft at all, look at where it goes to zero, and compare that height against the storey schedule.
  • Ask how many meshes there were and where the boundaries fell. A consultant who can answer immediately has thought about it. One who has to go and look may not have.

The general shape

Every failure we have written about here has the same structure. The sealed compartment reported an egress time from a pressure vessel. The cost model quoted 21.6 hours for a 60-hour job. Here, a numerical convenience — where to divide the mesh — silently changed the building.

In none of them did anything crash. In all of them, the result was specific, plausible, and describable to a client. That is what makes this class of defect expensive: it does not look like a bug, it looks like an answer.

Every shaft in a full-height column, and the deck checked before it runs

The alignment pass costs seconds and runs before every job. The shaft rule is in the emitter, not in a reviewer's memory.

Arrange a demonstration →