-
Notifications
You must be signed in to change notification settings - Fork 7
Concepts
Five ideas explain most of the pyfdstools API. Reading this page once will save you guessing at argument names later.
Every pyfdstools reader takes the same two arguments first:
fds.query2dAxisValue(workingDir, chid, ...)
fds.readSLCF3Ddata(chid, workingDir, ...) # note: this one is reversed
fds.load_csv(workingDir, chid, ...)-
chidis theCHIDfrom the&HEADline of the input file. FDS names every output file after it. -
workingDiris the directory holding those output files.
The argument order is not consistent across the package —
readSLCF3Ddata and readPlot3Ddata take chid first, the rest take
the directory first. Check the signature if a call misbehaves.
Anywhere a directory is accepted, a zip archive of that directory works too:
workingDir = '/path/to/results'
workingDir = '/path/to/results.zip'pyfdstools reads members out of the archive without extracting it, which
is convenient for keeping a run's output compressed. Internally, files
inside an archive are named
<archive>.zip<separator><name inside the archive>; if you see a path
like that in an error message, that is what it means.
Reading from an archive is slower for large slice files, because a compressed member has to be decompressed from the start rather than seeked into. For repeated queries over a big case, extract it first.
If the input file sets RESULTS_DIR on &DUMP, FDS writes its output
into that subdirectory rather than next to the input file. Point
pyfdstools at the directory holding the input file; it reads the
input file and follows RESULTS_DIR itself. This only works for
directories, not archives.
An FDS case is divided into meshes, and each mesh writes its own output files. A slice through a multi-mesh case is therefore spread across several files with different grids.
The high-level readers hide this. query2dAxisValue,
readSLCF3Ddata, readPlot3Ddata and queryBndf each:
- find every file that contributes to what you asked for,
- build an absolute grid spanning all of them,
- interpolate each mesh's data onto it,
- return one array.
Cells not covered by any mesh come back as NaN, so use np.nanmax,
np.nanmean and friends rather than their plain counterparts:
peak = np.nanmax(data['datas'])The absolute grid is built from the union of the mesh coordinates, so a
case with meshes of different resolutions gets a non-uniform absolute
grid. Pass makeUniform=True to getAbsoluteGrid if you need a
rectangular one at the finest resolution.
When you want the raw per-mesh data instead, the lower-level readers give it to you:
for slcfFile in fds.getFileList(workingDir, chid, 'sf'):
lims, data, times = fds.readSingleSlcfFile(slcfFile)A plane is named by the axis it is normal to and its coordinate along that axis:
axis |
Plane | In-plane coordinates returned as |
|---|---|---|
| 1 | x = value |
x is y, z is z |
| 2 | y = value |
x is x, z is z |
| 3 | z = value |
x is x, z is y |
The returned coordinate arrays are always called x and z whichever
plane you asked for; for a horizontal slice (axis=3) the array named
z holds y coordinates. plotSlice takes the same axis argument and
labels the figure accordingly.
Boundary queries also accept a signed axis, where the sign selects
which side of a surface to read: axis=-2 reads the faces whose outward
normal points in −y. See Boundary Data.
Every reader takes the same pair of optional arguments:
time |
dt |
Result |
|---|---|---|
| omitted | omitted | every frame in the file |
| given | omitted | the single frame nearest time
|
| given | given | the mean of the frames within time ± dt/2
|
| omitted | given | a running mean of width dt at every frame |
The last form is only supported by read2dSliceFile and
query2dAxisValue.
Frames are selected by timestamp, not by counting records, so a case whose output interval changed part way through is handled correctly.
# every frame
data, units = fds.query2dAxisValue(workingDir, chid, qty, 1, 2.55)
# the frame nearest t = 30 s
data, units = fds.query2dAxisValue(workingDir, chid, qty, 1, 2.55, time=30)
# the mean over 0 s to 60 s
data, units = fds.query2dAxisValue(workingDir, chid, qty, 1, 2.55,
time=30, dt=60)FDS writes slices either at cell nodes or at cell centers, depending on
whether CELL_CENTERED=.TRUE. was set on the &SLCF line. Smokeview
records which in its own file, and pyfdstools reads that flag rather
than guessing:
quantities, files, dims, meshes, centers, units = \
fds.readSLCFquantities(chid, workingDir)
for f, c in zip(files, centers):
print(os.path.basename(f), 'cell-centered' if c else 'node-centered')A cell-centered slice has one fewer value per axis than the node grid, so the coordinates are shifted by half a cell before the data are mapped onto the absolute grid.
FDS writes its binary output in the byte order of the machine it ran on
and records that order in a .end file. pyfdstools reads it
automatically via getEndianness, so results produced on a different
architecture read back correctly. Little-endian is assumed when no
.end file is present, which is right for every mainstream platform.
Getting started
Reading results
Working with results
Building models
Reference