3. Extract element stress tensor for a solid part from d3plot

Task scope: solid element stress tensor extraction

This case extracts the full six-component stress tensor for a selected solid element set from a d3plot database and writes one structured CSV row per element per state. The critical engineering detail is not the file I/O — it is getting the component ordering and sign convention right, because LS-DYNA stores solid stress in a specific order that differs from what many post-processors display, and because LS-DYNA's stress sign convention (tension positive) must be confirmed against the documentation rather than assumed.

We use lasso-python (the LS-DYNA Python reader) because it exposes the raw per-element tensor without post-processing transformations, which is exactly what we need to verify ordering. The same workflow applies if you read the binary directly, but lasso-python handles the state/part bookkeeping for you.

Component ordering and sign convention

For solid (hex/tet) elements, LS-DYNA writes the stress tensor in the order sig-xx, sig-yy, sig-zz, sig-xy, sig-yz, sig-zx. Note the shear ordering: xy, yz, zx — not the xy, yz, xz that some tools report. The zx component is the same physical quantity as xz (symmetry of the Cauchy stress tensor), but the storage order matters when you index into the array. Getting this wrong silently swaps two shear components and corrupts any downstream invariant (von Mises, principal stresses, pressure).

Sign convention: LS-DYNA reports stress with tension positive and compression negative. This is the opposite of some geomechanics and soil codes, where compression is positive. Confirm this in the LS-DYNA Keyword User's Manual (the *DATABASE_EXTENT_BINARY and output variable sections) before trusting any sign-dependent result. A quick sanity check: a uniaxially compressed solid should show a negative normal stress along the load axis.

Do not assume the component order from a different solver or from a GUI's column headers. LS-PrePost may reorder or relabel components in its display. Always verify against the raw array and the manual for your LS-DYNA version.

Extraction workflow

The script below opens the database, selects a part by its part ID, gathers the solid elements belonging to that part, and loops over every state. For each state it pulls the element stress array, slices the six components for the chosen elements, and appends rows to a CSV. The output columns are explicit about ordering so the file is self-documenting.

import csv
import lasso

D3PLOT = "run01/d3plot"
PART_ID = 12          # solid part to extract
OUT_CSV = "solid_stress_part12.csv"

# Open the database and read the state inventory
db = lasso.Dyna.D3plot(D3PLOT)
n_states = db.get_number_of_states()
times = db.get_timesteps()

# Map part -> solid element IDs (solid elements only)
part = db.get_part(PART_ID)
solid_ids = [eid for eid in part.element_ids
             if db.get_element_type(eid) in (lasso.Dyna.ElementType.SOLID,)]

# Element index lookup: d3plot arrays are indexed by element order, not ID
# Build id -> array index from the solid element block
solid_block = db.get_solid_element_array()   # shape (n_solid, ...)
id_to_index = {eid: i for i, eid in enumerate(solid_block.element_ids)}
target_idx = [id_to_index[eid] for eid in solid_ids]

# LS-DYNA solid stress order: xx, yy, zz, xy, yz, zx  (tension positive)
COMPONENTS = ["sig_xx", "sig_yy", "sig_zz", "sig_xy", "sig_yz", "sig_zx"]

with open(OUT_CSV, "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["state", "time"] + ["element_id"] + COMPONENTS)
    for state in range(n_states):
        stress = db.get_element_stress(state)   # (n_solid, 6)
        t = times[state]
        for eid, idx in zip(solid_ids, target_idx):
            row = stress[idx, :6]
            writer.writerow([state, f"{t:.6e}", eid] +
                            [f"{v:.6e}" for v in row])

print(f"Wrote {len(solid_ids)} elements x {n_states} states to {OUT_CSV}")

Two implementation points deserve attention. First, get_element_stress returns an array indexed by the internal solid-element order, not by element ID, so the id_to_index map is mandatory — indexing directly with the element ID will read the wrong element. Second, the slice stress[idx, :6] assumes the array's last axis is the six-component tensor in LS-DYNA order; verify this once by printing the shape and comparing a single element against LS-PrePost's fringe value at the same state.

Verification against LS-PrePost

Before trusting the CSV, run a spot check. Pick one element and one state, read its six components from the CSV, and compare against LS-PrePost: select the element, open the stress fringe, and read the component values at that state. The normal stresses should match to display precision. For the shear components, confirm that the value you labeled sig_zx matches LS-PrePost's zx (or xz) reading — if it matches yz instead, your ordering is off by one position.

A second, stronger check is invariant-based: compute the trace sig_xx + sig_yy + sig_zz and confirm it equals three times the mean stress (pressure with sign flip) reported by LS-PrePost for the same element and state. The trace is invariant under any correct component ordering, so a mismatch here points to a sign or indexing error rather than a labeling issue.

Solid stress tensor: storage order, extraction path, and verification d3plot database states: 0 … N-1 solid element block part 12 → element IDs stress array (n_solid, 6) LS-DYNA solid stress order tension positive · compression negative sig_xx sig_yy sig_zz sig_xy sig_yz sig_zx normal (blue) · shear (orange) — note zx, not xz index 0..2 normal, 3..5 shear wrong order → swapped shear → bad invariants structured CSV state, time, element_id, sig_xx … sig_zx one row per element per state self-documenting columns Verification chain (do this before trusting the CSV) 1. Spot check one element, one state vs LS-PrePost fringe 2. Shear label sig_zx matches zx not yz 3. Trace check xx+yy+zz = 3·mean invariant to order 4. Sign sanity compressed axis → negative normal stress

Common failure symptoms

  • Shear components swapped: von Mises or principal stresses computed downstream disagree with LS-PrePost even though normal stresses match. Recheck the xy, yz, zx order and the array slice.
  • Wrong element values: the CSV row for an element ID does not match that element's fringe in LS-PrePost. Almost always an ID-to-index mapping error — the stress array is indexed by internal order, not by element ID.
  • Sign flipped: a compressed region shows positive normal stress. Confirm the tension-positive convention in the manual and check whether any intermediate tool inverted the sign.
  • Missing states: fewer rows than expected. Verify get_number_of_states() against the state inventory from the previous inspection task; some databases write extra states for initial conditions.
Keep the component order and sign convention documented in the CSV header itself (as done above with explicit sig_xx … sig_zx names). Anyone consuming the file downstream then has the ordering baked in, and a future reader cannot silently misinterpret the columns.