2. LS-DYNA input deck structure and paramet

An LS-DYNA input deck is not a single monolithic file. It is a keyword-driven text program whose execution semantics are defined by the order and nesting of *KEYWORD blocks, and whose practical maintainability depends almost entirely on how those blocks are split across included files. Before any automation layer can be trusted, the engineer must be able to answer three questions about a deck: which file physically owns each keyword block, in what order the solver will read them, and which numeric fields are meant to vary between runs. This chapter establishes that mental model and then builds the parameterization strategies that later automation stages depend on.

Keyword blocks and their fixed-field grammar

Every LS-DYNA keyword begins with an asterisk-prefixed name on its own line, optionally followed by a comma-separated parameter line, and then one or more fixed-width data cards. The fixed-field convention is the single most common source of silent corruption in generated decks: fields are ten characters wide, and a value that overflows its column will either be truncated or shift every subsequent field on the card. Consider a shell section definition:

*SECTION_SHELL
$#   secid    elform      shrf       nip     propt   qr/irid       icomp
         1         2       1.0         5       1.0       0.0         0
$#      t1        t2        t3        t4
       2.0       2.0       2.0       2.0

The $# lines are comments that document field names; LS-DYNA ignores them, but they are invaluable when a generator must map a named parameter to a column position. A robust generator never emits free-form numbers into these cards — it formats each value into a fixed ten-character field, typically right-aligned, and validates that the formatted string does not exceed the field width. For a thickness of 2.0 this is trivial; for a part ID of 12345678901 it is a hard error that must be caught before submission, not after a multi-hour run fails at initialization.

Keyword blocks fall into a few functional families that matter for automation: definition blocks (*PART, *SECTION_SHELL, *MAT_*, *ELEMENT_SHELL), control blocks (*CONTROL_TERMINATION, *CONTROL_TIMESTEP, *CONTROL_ENERGY), contact blocks (*CONTACT_AUTOMATIC_SINGLE_SURFACE), and output blocks (*DATABASE_BINARY_D3PLOT, *DATABASE_ASCII_*). Control and output blocks are almost always parameterized per study; definition blocks are usually generated from CAD/CAE metadata and should be treated as derived, not hand-edited.

Include hierarchies and read order

Large decks are assembled with *INCLUDE and *INCLUDE_PATH. The solver reads the main deck top to bottom and, on encountering an include, splices the referenced file's contents at that point. This means the include tree is a depth-first textual expansion, and the effective keyword order is the order of that expansion — not the order in which files appear in a directory listing. Two consequences follow immediately.

First, ID uniqueness is global across the expanded deck. If parts_upper.k and parts_lower.k are both included and both define part ID 101, the second definition silently overwrites or conflicts with the first depending on the keyword type. A generator must therefore allocate IDs from a single registry, not per-file counters. Second, relative paths inside *INCLUDE resolve against the working directory of the solver invocation, not against the location of the including file. Mixing absolute and relative includes is a reliable way to produce a deck that runs on the build machine and fails on the cluster.

Use *INCLUDE_PATH once at the top of the main deck to declare a search root, then reference all subordinate files with paths relative to that root. This keeps the deck relocatable between workstation, staging area, and compute node.

A practical hierarchy separates concerns by change frequency rather than by physical assembly. The main deck holds only control blocks, the include list, and study-level parameters. Geometry-derived definitions live in a generated include. Material and section libraries live in a shared, version-controlled include reused across studies. Contact definitions sit in their own include because they are frequently tuned between runs. The figure below shows this structure and the read-order expansion it produces.

Include tree and effective read order main.k *CONTROL_*, *INCLUDE_PATH, *INCLUDE list model_gen.k *PART, *ELEMENT materials.k *MAT_*, *SECTION contact.k *CONTACT_* output.k *DATABASE_* Expanded keyword order 1 *CONTROL_TERMINATION / _TIMESTEP 2 *PART, *ELEMENT_SHELL (model_gen.k) 3 *MAT_*, *SECTION_* (materials.k) 4 *CONTACT_* (contact.k) 5 *DATABASE_* (output.k) Single parameter registry → generated include study.yaml (source of truth) t_shell: 2.0 mat_id: 200 term_time: 0.045 d3plot_dt: 0.001 renderer (fixed-field) validate width ≤ 10 right-align numeric emit $# header lines allocate IDs from registry params_gen.k *SECTION_SHELL *CONTROL_TERMINATION *DATABASE_BINARY_D3PLOT included last, overrides

Parameterization strategies

There are three workable parameterization patterns, and the right choice depends on who changes the value and how often. The first is direct templating: the generator holds a template deck with placeholder tokens and substitutes values at render time. This is simple and transparent, but it requires the template to be re-rendered for every run, and any manual edit to a rendered deck is lost on the next render. It suits geometry-derived blocks that are always regenerated.

The second is override includes: the base deck is static and correct, and a small generated include at the end of the main deck redefines the keywords that vary. LS-DYNA's last-definition-wins behavior for most definition keywords makes this viable, and it keeps the base deck diffable and reviewable. The risk is that override semantics are not uniform across all keyword types — some keywords accumulate rather than replace — so override includes should be restricted to a known, tested set of keywords such as *CONTROL_TERMINATION, *CONTROL_TIMESTEP, and *DATABASE_BINARY_D3PLOT.

The third is parameterized keyword syntax, where LS-DYNA's own &parameter facility defines named values in the deck and references them in data cards. This keeps the deck self-contained and human-readable, but expression support is limited and debugging a failed parameter expansion is slower than debugging a generated file. For automated pipelines, the override-include pattern combined with a single external registry is usually the best balance: the registry is the source of truth, the renderer is deterministic, and the base deck remains a stable artifact under version control.

Building a minimal generator

A generator that is fit for HPC use needs four properties: deterministic output, fixed-field formatting, ID allocation from a registry, and a pre-submission validation pass. A compact Python sketch illustrates the core:

def card(values, width=10):
    out = "".join(f"{v:>{width}}" for v in values)
    assert len(out) == width * len(values)
    return out

def section_shell(secid, t):
    return "\n".join([
        "*SECTION_SHELL",
        "$#   secid    elform      shrf       nip     propt   qr/irid       icomp",
        card([secid, 2, 1.0, 5, 1.0, 0.0, 0]),
        "$#      t1        t2        t3        t4",
        card([t, t, t, t]),
    ])

The card helper enforces the ten-character contract and fails loudly rather than emitting a malformed line. The section_shell function emits the $# header so the generated file remains self-documenting. In a real pipeline the registry supplies secid and t, and a validation pass re-parses the generated deck to confirm that every referenced ID exists and that no field exceeds its width.

Verification before submission

Two checks catch the majority of deck-generation defects before a job consumes queue time. First, run the solver in a cheap initialization-only mode and inspect the echo of the expanded input; LS-DYNA reports the total number of keywords read and will flag unresolved includes and duplicate IDs. Second, diff the generated deck against the previous accepted deck and review only the changed cards — a parameter change intended to touch one section should not produce a diff across the entire model. If the diff is unexpectedly large, the renderer is non-deterministic, usually because it iterates over an unordered dictionary when emitting blocks.

Never let a generator write directly into a directory that a running job is reading. Render to a per-run staging directory, validate there, and only then submit. This prevents a partially written include from being picked up by a job that starts between two write operations.

With the deck structure understood, the include order fixed, and a deterministic renderer producing validated fixed-field output, the deck becomes a reliable interface rather than a fragile artifact. That interface is what the subsequent automation stages — job submission, parameter sweeps, and result harvesting — will operate against.