2. LS-DYNA output architecture

LS-DYNA does not write a single monolithic result file. Instead, it distributes simulation results across several output families, each optimized for a different access pattern and data shape. Understanding this architecture is the prerequisite for writing correct Python post-processing code, because the file you choose determines the API you use, the memory profile of your script, and the granularity of the data you can retrieve.

The Four Output Families

At the top level, LS-DYNA results fall into four groups:

  • d3plot — the full-field state database. It stores nodal coordinates, displacements, velocities, accelerations, element stresses and strains, and shell/solid state variables for every node and element at discrete state times. It is written in a binary, record-based format and is the source for contour plots and animation.
  • binout — the binary time-history database. It stores scalar and low-dimensional vector time series for a selected set of entities: interface forces, rigid body kinematics, section forces, energy summaries, and similar reduced data.
  • ASCII time-history files — plain-text equivalents of selected binout content, controlled by *DATABASE_ASCII_* keywords. They are human-readable but slower to parse and larger on disk.
  • Specialized databases — nodout, elout, secforc, rcforc, glstat, matsum, and others. Some are ASCII, some binary, and several are also mirrored inside binout.

The key architectural point is that binout is a container, not a single dataset. One binout* file can hold dozens of independent time-history databases, each with its own entity list, time vector, and variable set.

Inside the binout Container

A binout file is organized as a hierarchy. At the root are named databases such as glstat, matsum, rcforc, secforc, nodout, elout, dbfsi, deforc, and sleout. Each database contains one or more entities — for example, rcforc contains one entity per defined rigid wall or contact interface, and secforc contains one entity per cross-section. Each entity exposes a set of named variables and a shared time vector.

This three-level structure — database → entity → variable — is exactly what the Python lasso-python reader mirrors. The typical access pattern is:

from lasso.dyna import Binout, D3plot

b = Binout("binout0000")

# List available databases
print(b.list_databases())
# ['glstat', 'matsum', 'rcforc', 'secforc', ...]

# List entities inside one database
print(b.list_entities("rcforc"))
# ['1', '2', '3']

# List variables for one entity
print(b.list_variables("rcforc", "1"))
# ['time', 'x_force', 'y_force', 'z_force', ...]

# Read a single variable as a NumPy array
t = b.read("rcforc", "1", "time")
fx = b.read("rcforc", "1", "x_force")

Note that read() returns a NumPy array whose first dimension is time. For vector variables such as nodal coordinates in nodout, the array shape is (n_times, n_entities, 3). This shape convention is consistent across the binout API and is worth memorizing before writing any aggregation code.

How binout Relates to d3plot

The two databases answer different questions. d3plot answers "what is the field at time t?" — it gives you the full spatial distribution. binout answers "how did this scalar evolve over time?" — it gives you a compact temporal record.

They are written on independent schedules. d3plot output is controlled by *DATABASE_BINARY_D3PLOT with a DT interval; binout output is controlled by *DATABASE_BINARY_D3THDT and by the individual *DATABASE_* keywords that populate each sub-database. As a result, the time vectors in binout and d3plot rarely coincide. A common mistake is to assume that binout time step i corresponds to d3plot state i. It does not. Always interpolate explicitly when you need to combine them.

A practical example: you want to plot the von Mises stress at a specific element alongside the section force from secforc. You read the element stress from d3plot at its native state times, read the section force from binout at its native times, then resample one onto the other using numpy.interp before plotting. The two time vectors are the bridge, not an assumed index alignment.

ASCII Outputs and When to Prefer Them

ASCII time-history files are produced when the corresponding *DATABASE_ASCII_* keyword is active. For example, *DATABASE_ASCII_ELOUT writes elout as text, and *DATABASE_ASCII_NODOUT writes nodout as text. These files are convenient for quick inspection with grep or a text editor, and they are portable across LS-DYNA versions. However, they are typically 5–20× larger than the equivalent binout content and parse much more slowly in Python.

The recommended workflow is: use binout for all programmatic analysis, and fall back to ASCII only when (a) the binout file is corrupted or truncated, (b) you need to verify that a keyword actually produced output, or (c) you are debugging a version-specific binout format change. The ASCII file is the ground truth for what LS-DYNA intended to write; binout is the efficient representation of the same data.

Version note: binout format has evolved across LS-DYNA releases (notably R7, R9, R11, and R13). The lasso-python reader handles the common variants, but if you encounter a Binout read error on a specific database, check the LS-DYNA version that produced the file and confirm the reader supports it. Reading the matching ASCII file is a reliable cross-check.

Choosing the Right Source in Python

The decision tree is straightforward:

GoalPrimary sourcePython API
Contour / animation of a fieldd3plotD3plot
Force, energy, or kinematics time seriesbinoutBinout
Cross-section resultant forcesbinout (secforc)Binout
Rigid wall / contact interface forcesbinout (rcforc)Binout
Global energy balance checkbinout (glstat)Binout
Quick text inspection or format verificationASCIIplain file I/O

One more architectural detail matters for performance: binout is memory-mapped by the reader, so reading a single variable does not load the entire file. This means you can open a multi-gigabyte binout and extract only the glstat energy curve in milliseconds. d3plot, by contrast, requires reading state records, and random access to a late state time is more expensive than sequential access. Design your scripts accordingly — stream d3plot states in order, and query binout variables on demand.

LS-DYNA Output Architecture Simulation writes four output families; binout is a multi-database container LS-DYNA Solver d3plot Full-field states nodes · elements · time binout Time-history container many sub-databases ASCII time history nodout · elout · secforc human-readable text Specialized DBs glstat · matsum rcforc · secforc binout0000 — internal hierarchy glstat rcforc secforc database level entity "1" entity "2" entity level time x_force variable level → NumPy array (n_times,) Python access pattern b = Binout("binout0000") b.list_databases() b.list_entities("rcforc") b.list_variables("rcforc","1") t = b.read("rcforc","1","time") fx = b.read("rcforc","1","x_force") memory-mapped: read only what you need binout and d3plot time vectors are independent — always interpolate explicitly before combining them

Practical Implications for Your Scripts

Three habits follow directly from this architecture. First, always inspect the binout hierarchy before writing extraction code — list_databases(), list_entities(), and list_variables() cost almost nothing and prevent silent key errors. Second, never assume index alignment between binout and d3plot; treat the time vectors as the authoritative bridge and resample with numpy.interp. Third, when a binout read fails, check the matching ASCII file to confirm whether the data was written at all — this distinguishes a reader problem from a keyword configuration problem in seconds.

With this architecture in mind, the next step is to load a real binout file and explore its contents interactively, which is the subject of the following section.