2. Audit Input Deck and Material Calibration Traceability
Why Traceability Is the First Real Validation Gate
An injury-prediction CAE model is only as defensible as the weakest input it contains. Before any solver run can be trusted, every material parameter, boundary condition, and contact definition must be answerable to a source: a coupon test, a calibration record, a supplier datasheet, a regulatory reference, or an explicit engineering assumption. This case builds a traceability matrix that maps each input to its provenance and classifies it as validated, assumed, or unsupported. The output is not a report for its own sake — it is the audit trail that later cases (mesh convergence, solver verification, correlation) will lean on.
The distinction that matters throughout is between three provenance states:
- Validated — the value is traceable to a test or calibration record with a documented method, specimen, and date, and the value used in the deck matches that record within a stated tolerance.
- Assumed — the value is a deliberate engineering estimate (literature default, conservative bound, or expert judgment) with a stated rationale and a sensitivity note. Assumed inputs are acceptable if flagged and bounded.
- Unsupported — the value has no identifiable source, or the deck value disagrees with the cited source beyond tolerance. Unsupported inputs block validation sign-off until resolved.
The Traceability Matrix Structure
A workable matrix has one row per input instance, not one row per material. The same material used in two body regions with different strain rates is two rows. Each row carries the fields below; the granularity is what makes the audit reproducible.
| Field | Content | Example |
|---|---|---|
| Input ID | Stable identifier referenced by the deck | MAT-LIVER-01 |
| Deck location | Keyword, part, or set where the value appears | *MAT_ELASTIC, part 1042 |
| Parameter | Named quantity and units | Young's modulus, MPa |
| Deck value | Value as written in the input deck | 12.5 |
| Source record | Test/calibration ID, report, or datasheet | CAL-2023-07, Table 3 |
| Source value | Value in the source, converted to deck units | 12.8 |
| Delta / tolerance | Absolute and relative difference vs. allowed tolerance | −0.3 MPa, 2.3% (tol 5%) |
| Status | Validated / Assumed / Unsupported | Validated |
| Rationale / action | Why assumed, or what resolves an unsupported flag | — |
The delta / tolerance column is the audit's teeth. A value that matches its source to within tolerance is validated; a value that drifts beyond tolerance is unsupported even if a source exists, because the deck no longer represents the test. Tolerances should be set per parameter class — modulus and density are typically tight (2–5%), while rate-dependent failure strains may legitimately carry 10–15% scatter from the underlying test.
Extracting Inputs from the Deck
The audit starts by enumerating every parameter the deck actually consumes, not by trusting a material summary someone wrote earlier. For a typical LS-DYNA injury model, the relevant keyword blocks are *MAT_* (material), *BOUNDARY_* (constraints and prescribed motion), and *CONTACT_* (contact definitions). A minimal extraction pass can be scripted so the matrix is regenerated whenever the deck changes:
import re, csv
DECK = "injury_model_v3.k"
KEYWORDS = ("*MAT_", "*BOUNDARY_", "*CONTACT_")
def extract_blocks(path):
blocks, current = [], None
with open(path) as f:
for line in f:
s = line.rstrip("\n")
if s.startswith("*"):
if current:
blocks.append(current)
current = {"keyword": s.strip(), "lines": []}
elif current is not None and s.strip():
current["lines"].append(s)
if current:
blocks.append(current)
return [b for b in blocks if b["keyword"].upper().startswith(KEYWORDS)]
def to_rows(blocks):
rows = []
for b in blocks:
kw = b["keyword"].split()[0].upper()
for i, ln in enumerate(b["lines"]):
rows.append({"keyword": kw, "line_no": i + 1, "raw": ln.strip()})
return rows
if __name__ == "__main__":
rows = to_rows(extract_blocks(DECK))
with open("deck_inputs.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=["keyword", "line_no", "raw"])
w.writeheader()
w.writerows(rows)
print(f"extracted {len(rows)} input lines from {DECK}")
This produces deck_inputs.csv — a flat, reviewable list of every material, boundary, and contact line. The script does not interpret values; it guarantees completeness so nothing is silently skipped. Interpretation (which field is modulus, which is density) is done by the auditor against the keyword manual, and the resulting parameter rows are appended to the traceability matrix. Running the script on a revised deck and diffing the CSV against the previous run is the fastest way to catch an input that changed without a corresponding source update.
Reading the Audit at a Glance
The SVG below shows how the three input classes flow from deck extraction through provenance lookup to a status decision, and how the statuses aggregate into the sign-off gate. It is the mental model the matrix encodes.
Worked Audit Example
Consider three representative rows from a liver-region model. The deck uses a linear-elastic material for the capsule, a rate-dependent failure strain for the parenchyma, and a tied contact between capsule and parenchyma.
| Input ID | Parameter | Deck value | Source | Source value | Delta | Status |
|---|---|---|---|---|---|---|
| MAT-CAP-01 | E, MPa | 12.5 | CAL-2023-07 T3 | 12.8 | −2.3% (tol 5%) | Validated |
| MAT-PAR-02 | ε_fail @ 10 s⁻¹ | 0.28 | CAL-2023-11 T5 | 0.31 | −9.7% (tol 15%) | Validated |
| CNT-CAP-PAR-01 | Tiebreak stress, MPa | 0.9 | none | — | — | Unsupported |
The first two rows pass because the deck value sits inside the parameter-class tolerance of its source. The third row is the audit's real product: a contact tiebreak stress of 0.9 MPa with no cited record. It may be a reasonable guess, but it is currently unsupported, and the sign-off gate cannot close while it remains so. The resolution is either to locate a peel or lap-shear test that bounds the tiebreak stress, or to reclassify it as assumed with an explicit rationale (e.g., "bounded by capsule tensile strength; sensitivity run at 0.5 and 1.5 MPa planned") and a sensitivity note. Only the second path is acceptable if no test exists — and it must be written down, not remembered.
Deliverable: Traceability Matrix and Sign-off Record
The audit closes with two artifacts. The first is the matrix itself, exported as CSV with the nine fields above, one row per input instance, sorted by status so unsupported rows surface first. The second is a short sign-off record that states the counts and the disposition of every non-validated row:
TRACEABILITY SIGN-OFF — injury_model_v3.k
Audit date: (fill) Auditor: (fill)
Total input rows: 142
Validated: 118
Assumed: 21 (all with rationale + sensitivity note)
Unsupported: 3 (blocking)
Blocking rows:
CNT-CAP-PAR-01 tiebreak stress 0.9 MPa -> locate peel test or reclassify assumed
BND-IMP-04 prescribed velocity 7.2 m/s -> confirm against sled test S-2023-02
MAT-PAR-07 damping 0.15 -> no source; propose assumed w/ bound
Gate status: OPEN — 3 unsupported rows must be resolved or reclassified.
Next action: re-run deck_inputs.csv diff after corrections; re-audit changed rows only.
Two practical habits keep the matrix alive. First, regenerate deck_inputs.csv on every deck revision and diff it against the audited version — only changed rows need re-auditing, which keeps the cost of maintaining traceability proportional to the change, not the model size. Second, never let the matrix live only in a spreadsheet on one engineer's machine; version it alongside the deck so that the validation cases that follow can cite a specific matrix revision. When the mesh convergence and solver verification cases run, they inherit a model whose inputs are already classified, and any correlation gap can be attributed to modeling rather than to an undocumented material guess.