Note
Go to the end to download the full example code.
The four encodings#
The last field of every FRD block header is a format code, and there are four
of them: two ASCII widths and two binary ones. CalculiX writes binary
unconditionally from *REFINE MESH and on demand from a DOUBLE output
card, and a reader that handles only the ASCII codes returns an empty mesh for
those files without raising anything.
This package reads and writes all four, and can convert between them without going through a mesh at all.
pyvista_frd.convert() reads a document and writes it out again in
another encoding. Nothing is re-derived: the records are re-spelled and every
line the parser does not need to understand is copied through untouched.
source = DATA / 'cantilever.frd'
sizes = {'long ASCII (source)': source.stat().st_size}
for label, kwargs in (
('binary float64', {'binary': True}),
('long ASCII', {'binary': False}),
):
target = tmp / f'{label.replace(" ", "_")}.frd'
pyvista_frd.convert(source, target, **kwargs)
sizes[label] = target.stat().st_size
for label, size in sizes.items():
print(f'{label:22s} {size / 1024:8.0f} KB')
long ASCII (source) 330 KB
binary float64 181 KB
long ASCII 330 KB
Binary is about a third of the size, and exact: the values are the stored doubles rather than a six-significant-digit rendering of them.

The conversion is lossless in the direction that matters and the mesh is unchanged either way.
original = pyvista_frd.read(source)
converted = pyvista_frd.read(tmp / 'binary_float64.frd')
print(f'points {original.n_points} -> {converted.n_points}')
print(f'cells {original.n_cells} -> {converted.n_cells}')
print(f'arrays {len(original.point_data)} -> {len(converted.point_data)}')
points 900 -> 900
cells 600 -> 600
arrays 15 -> 15
Going the other way – binary to ASCII – is the conversion the format code has always implied and no tool offered. A binary FRD that no ASCII-only reader can open becomes one any of them can, including CalculiX’s own.
One caveat, recorded in doc/divergences.md: CalculiX casts every value to
float before printing it, and this writer does not. The text it produces
is the nearest six-digit decimal to the number actually held, which differs
from CalculiX’s own at a rounding tie – about 3% of record lines.
Total running time of the script: (0 minutes 0.105 seconds)