Fields and results¶
The solver writes its results as field files in time directories: 3600/air/T, 3600/buildings/Ts,
often gzip-compressed (writeCompression on) and, for big runs, in binary. umcfGui reads them all.
What is read¶
| Classes | vol…Field, surface…Field, point…Field and anything else with nonuniform List<T> data |
| Formats | ASCII and binary, any arch (LSB/MSB, 32- or 64-bit labels and scalars) |
| Compression | .gz files are read transparently; T is found as T or T.gz |
| Value types | scalar, vector, sphericalTensor, symmTensor, tensor, label |
| List forms | N (…), N{value} (all elements equal), 0(), and untyped nonuniform N (…) |
| Directories | time directories sorted by time (0, 0.5, 3600, 1e+06), processorN, collated processorsN |
The small parts of a field file (header, dimensions, every patch of boundaryField with its
type and parameters) keep their full structure, the same way as dictionaries.
A patch value such as $internalField is reported as written.
Checked against the mesh and against OpenFOAM¶
- Every internal field of a volume field has as many values as the mesh has cells (
nCellsin the mesh'sownerheader), and every patchvaluelist as many as the patch has faces (nFacesinboundary). This holds for every field in the test projects, OpenFOAM-8 and OpenFOAM-12. - Cases converted to binary by OpenFOAM-8's and OpenFOAM-12's own
foamFormatConvertread back bit for bit the same as their ASCII originals.
Safety and speed¶
Field files are treated as hostile input. A list that claims two billion elements but holds
two, binary data that ends early, a gzip "bomb" or a nan from a diverged run produce an error
or a value, never a crash or a runaway allocation.
Reading runs at about 370 MB/s of field text and decompression at about 235 MB/s, on one core.
The largest file of a real project time step (597 MB of U, 16 million vectors) takes about
four seconds.
Opening a case reads only the outline of each start-time field file: the file is read as a
stream, and of each list only its type and length are kept. Its numbers are still checked as
they go by, as a whole read checks them. So a file's numbers are never held, whatever its size,
and every field up to 8 GB (decompressed) has its boundary conditions. What is kept is
bounded: 4 MB of text outside the lists (a real field's is kilobytes), counting 64 bytes for
each list. A file over either limit, a hostile one say, is listed without its conditions.
Commands still edit only files up to 256 MB (decompressed): a bigger one gets a note, bc.set
refuses it, and patch.set and patch.create leave it out and say so.
The files are read in parallel, one per core and 16 at most. The Hong Kong project opens at its
latest time (16 fields of up to 600 MB, gzipped) in 2.6 s, against 11 s when each file was read
whole one after the other. Its U and phi used to be listed without their boundary
conditions. Decompressing is most of the time: a gzipped file of several GB takes seconds, and
Cancel stops it.
Setting boundary conditions¶
bc.set sets the condition of one or more patches in a field of the start time (0/air/U),
in the desktop app's condition card or as a command:
umcf-cli run --case my-case \
--cmd 'bc.set={"field": "T", "type": "fixedValue", "value": 290, "patches": [{"region": "air", "patch": "north"}]}' \
--cmd 'case.save={}'
- A patch whose own entry has that type already keeps its entry: the value and entries given
are set in it, and its other keys, comments and
#includes stay. So does an entry whose type comes from an#includeor a$macroin it: the type and entries are set after what it brings in. Keys given asdefaultsgo into new entries only: a patch keeping its entry keeps its own (its value, say). One whose entry brings text in from elsewhere (with or without a type of its own) gets none either, since that text may hold the value; when a default was given that isn't also an entry, the command warns (bc.unfilled) so that you can check it. Otherwise the patch gets a new entry,{ type …; <entries>; value …; }, in place of its own one, or after the others when it had none (a condition from a group or a pattern then still applies to the other patches). - Nothing else in the file changes, byte for byte: not the other entries, the comments, the
layout nor the data lists, ASCII or binary. A file that wouldn't come back unchanged without
an edit is refused rather than rewritten. Every field file of the test projects comes back
byte for byte. A
.gzfile is compressed again: its text is kept byte for byte, its compressed bytes generally not. - A uniform value must fit the field: one number for a scalar field, three for a vector
(
uniform (2 0 0)), and so on, forvalueand the…Valueentries (inletValue); a mismatch is refused. A field of another class (volVector2DField) is not checked. - A new entry replacing one that took text from an
#includeor a$macrois reported (bc.replaced): that text no longer applies to the patch. A value in the old entry that names a variable (value $internalField;) is not reported. - When
boundaryFielditself takes entries from an#includeor a$macro, the command warns (bc.indirect): one of them may set the same patches after the entries set here. - A field whose
boundaryFieldcomes from elsewhere (boundaryField $common;, an#include) is not edited: the condition is in that other file. - The edit is one step in the undo history, and is written by
case.saveafter a backup. An undo after the save is a change to save again: saving writes the file as it was. - Text OpenFOAM reads as a list's data while the file is edited (
__umcfList…) and comments in a value are refused. - The command returns the case check's findings for those patches and that field: a
type the solver doesn't have for the case's OpenFOAM version, or a constraint patch (
empty,cyclic) given another type.