LS-DYNA binary output (binout)
The binary file LS-DYNA writes in place of its ASCII databases when *DATABASE_<name> asks for BINARY = 2 or 3: nodout (node histories), glstat (global energies), matsum (per-part energies), elout (element histories), rcforc, secforc, rbdout and the others, all in one file (binout, continued in binout%001...; an MPP run writes one per processor, binout0000...). It is an LSDA file (Livermore Software Data Archival), the container lasso-python and LS-PrePost read. New in v16.12.0.
| Format name | lsdyna_binout |
| Extensions | none: found by its file name, binout or binout0000... (any case), or by its LSDA header |
| Read / Write | ✓ / ✓ (one file, or %001 continuation files with split_size; see Writing for what it leaves out) |
| Extra dependencies | none |
Reading
import meshioplusplus
mesh = meshioplusplus.read("run/binout") # the first output
last = meshioplusplus.read("run/binout", time_step=-1) # the last one
last.points # the nodout nodes where they are now
last.point_data["lsdyna:nid"] # their ids
last.point_data["displacement"] # (n, 3); also rotation, velocity, ...
last.field_data["binout:glstat:kinetic_energy"]
last.field_data["binout:matsum:internal_energy"] # one value per matsum id
last.field_data["binout:matsum:ids"]
meshioplusplus.lsdyna_binout.time_values("run/binout")meshioplusplus convert run/binout 'nodes_{step}.vtu' # one point cloud per output
meshioplusplus info run/binoutBoth engines read the whole format: the C++ core, and a Python reference reader the core falls back to. The writer is below.
The file
An LSDA file starts with an 8-byte header: its size, the sizes of its length, offset, command and type fields, and its byte order. Records are a length and a command; a chain of symbol tables (reached through offset records) holds directory (CD) and variable (VARIABLE: type, offset, count) entries, and each variable's values sit in a DATA record. The continuation files binout%001... beside the file are read with it. Variable types are 1-, 2-, 4- and 8-byte integers (signed and unsigned), 4- and 8-byte reals, and links to other variables; 1-byte variables are text (titles, dates) and are not read.
Each database is a directory holding metadata (ids, title, legend...) and one folder per output time, d000001, d000002..., each with its time and the variables of that output. elout and jntforc nest one level deeper (elout/beam, elout/shell...).
Steps and data
The steps are nodout's outputs or, in a file without nodout, those of the first database with any (in path order). time_step picks one; read_metadata(...).time_values lists the times; read_sequence walks them.
- Points. With
nodout: its nodes (metadata/ids, aspoint_data["lsdyna:nid"]) at their current coordinates (x_coordinate,y_coordinate,z_coordinate), onevertexcell each. Without it, no points. - Point data.
displacement,rotation,velocity,rotational_velocity,acceleration,rotational_accelerationfromnodout'sx_/y_/z_andrx_/ry_/rz_variables; any other per-nodenodoutvariable under its own name. - Field data.
meshio:time; every othernodoutvariable asbinout:nodout:<variable>; and every other database's latest output at or before the step's time (their times compared in single precision, as the file stores them) asbinout:<database>:<variable>(binout:glstat:kinetic_energy,binout:elout/beam:axial), with that output's own time asbinout:<database>:timeand the database's metadata ids asbinout:<database>:ids. The databases write at their own intervals (glstatevery second,nodoutevery tenth of one), so a step can carry an olderglstat. Integers stay integers.
Writing
import meshioplusplus
meshioplusplus.write("binout", mesh) # one output, named by its file name
meshioplusplus.write("run.bin", mesh, file_format="lsdyna_binout") # or by the format
with meshioplusplus.lsdyna_binout.SeriesWriter("binout") as w: # one file, an output per step
for time, mesh in steps:
w.write(time, mesh)
meshioplusplus.write_sequence("binout", steps, file_format="lsdyna_binout") # the sameThe writer is the reader's inverse. It writes one LSDA file (8-byte lengths and offsets, little-endian, the DATA records first and the one symbol table behind them), with reals stored as float32 and integers as int32, as LS-DYNA writes them. meshio:time is the output's time (0 when absent).
nodoutcomes from the mesh./nodout/metadata/idsispoint_data["lsdyna:nid"](else 1 to n, and an id outside the 32-bit range is aWriteError). Each output is a folder/nodout/d000001,d000002... holdingtime, the points asx_coordinate,y_coordinate,z_coordinate(a 2-D point set getsz = 0), the vectorsdisplacement,rotation,velocity,rotational_velocity,accelerationandrotational_acceleration(each(n, 3), asx_displacement,rx_displacement...), every other one-dimensional per-point array under its own name, and everybinout:nodout:<variable>field data as a variable of its own. A per-point array is read back as point data only for two or more nodes: with one node it comes back as field data, and a mesh with one node drops such an array with a warning.- Every other database comes from the field data
binout:<database>:<variable>(a nested database asbinout:elout/beam:axial): its folders holdtime(binout:<database>:time, else the step's time) and the variables, andbinout:<database>:idsis/<database>/metadata/ids. A database name that is a step folder (d000001) ormetadata, or a name with an empty part, or a variable name that is empty, over 255 characters, not ASCII or holding a/is aWriteError. - A mesh with no point is a binout with no
nodout: its first database's outputs are the steps, as the reader takes them. A mesh with no point and nobinout:*field data is aWriteError. - Not written, and named in one warning: cells (the points are a
vertexcloud on the way back), regions, cell data, field data that is notmeshio:timeor underbinout:, and per-point arrays that are not one value or three per point.
A series writes nodout's ids once and an output folder per step. A database gets a new folder only when its own binout:<database>:time changes, which is the inverse of what read attaches (the latest output at or before the step's time): a database written every second beside a nodout written every tenth keeps its cadence, and write_sequence(read_sequence(...)) round trips. A database may be absent from a step and appear later; once it has appeared its variables must match its first output's. Every step must have the first step's number of points and ids and nodout variables, or the step is a WriteError naming it (and {step} in the path writes one file per step instead). A step's time is the argument of write (or the pair's first item in write_sequence), not its meshio:time. One step is write's bytes. The file is assembled when the series closes. Both engines write the same bytes: the C++ write_lsdyna_binout and LsdynaBinoutSeriesWriter and their Python twins, which the test suite compares, and a hand-built file spells out.
Metadata text. A database's metadata titles, legends and dates (1-byte integers) are field data binout:<database>:@<name>, as uint8 bytes (binout:nodout:@title); written back as 1-byte integers beside ids, from the first step. Continuation files. split_size (bytes; write, SeriesWriter, write_sequence(..., split_size=...), 0 for one file) starts binout%001, binout%002... once the data written to the current file would pass it; an output folder stays whole in one file, a folder larger than the split makes a file of its own, and the symbol tables add a little more, so the size is a target. The reader merges the files. Word size and byte order. word_size=4 writes 4-byte lengths and offsets (a file under 4 GiB; the default is 8) and big_endian=True the big-endian records and data the header's order byte announces; both go through write, SeriesWriter and write_sequence, and the reader and lasso-python read every combination. Links. A variable of type 11 in a step folder reads as its target's values (the link is followed), and field_data["binout:<database>:@link=<variable>"] holds the target path as uint8 bytes. The writer turns a variable that carries such a marker into a link record (type 11, the path as its bytes) instead of values, in every step folder; the path must be absolute and name a variable the written file holds (a path such as /glstat/d000001/kinetic_energy in a one-step file), or the write is refused, since a link without a target cannot be read back. lasso-python's own writer cannot write links and its relative-link resolution is incomplete, so the written links are checked against a hand-built file and the reader, not against lasso.
lasso-python 2.0.4 reads the written files (Binout): the databases, nodout's ids, times and coordinates, and the glstat and elout/beam outputs of a series, each database with its own number of outputs. They were not opened in LS-PrePost.
Not read
- Metadata text of any type but 1-byte integers (revisions, version records).
- An MPP run's per-processor files together: each
binout0000... reads on its own.
Verification
The layout follows lasso-python's lsda_py3 (BSD 3-Clause), itself LSTC's. The test suite reads a binout LS-DYNA wrote (glstat and rwforc, from Ansys' example data, MIT) and a subset of another (a Hybrid III dummy's nodout, elout/beam, glstat and matsum, rewritten with lasso-python's LSDA writer from the 15 MB original), and every value equals lasso-python's Binout reading; the two engines agree exactly. The full 15 MB original (1001 nodout outputs, 13 databases) and qd-cae's swforc binout were checked outside the suite.