Builder and Data Contracts
Builder inputs, data contracts, pack creation, and the main integration flow.
Use this chapter when you already have validated H data, optional IR data, or source data that Builder can convert, and you need to produce a pack that Runtime can load. It explains the Builder setup flow, the shape rules that matter at the handoff, and the checks worth running before you blame Runtime for a bad pack. This chapter stops at the pack-to-runtime handoff; the full runtime lifecycle and step loop live in their own chapters.
If your starting point is already FRF data, impulse-response data, or a Builder-ready workflow output, start here. If your starting point is a circuit netlist, RAW case, or Touchstone-driven circuit flow, start with Adapter Circuit instead.
Related Chapters For Runtime lifecycle semantics after pack creation, see Runtime Lifecycle. For step execution inside the simulation loop, see Step Execution.
Use this chapter when your integration starts from one of these Builder-side artifacts:
| Starting artifact | Builder role |
|---|---|
validated H tensor | attach H, write pack, hand off to Runtime |
validated H plus optional IR | attach both, preserve shape and horizon contracts |
| matrix or circuit workflow output | accept Builder-ready handoff from Adapter or workflow API |
Prerequisites
- Built SDK artifacts (Runtime
tdse, Buildertdse_builder, headers). - A generated pack input (
Hrequired,IRoptional). - Build/test workspace ready:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
Quick Start
Both paths below end with a written pack and a small handoff check. Use the minimal path for prototyping; switch to the production path before release.
Minimal path
tdse_builder_t* b = NULL;
tdse_builder_options_t cfg = tdse_builder_options_init();
cfg.dt = dt;
cfg.nh = nh;
cfg.np = np;
cfg.nq = nq;
tdse_builder_create(&b);
tdse_builder_configure_ex(b, &cfg); /* np/nq/nh/dt */
tdse_builder_apply_h(b, &h_desc); /* required */
tdse_builder_apply_ir(b, &ir_desc); /* optional */
tdse_builder_write_pack(b, "model.pack");
tdse_builder_destroy(b);
Then hand the pack to Runtime Lifecycle for create/destroy behavior and to Step Execution for the simulation loop.
Minimal host-side interpretation:
- Builder owns pack construction and pack metadata
- Runtime owns create, step, and destroy after pack bytes are handed off
- the host owns artifact selection, pack storage, and when to start Runtime
Production path
For production integration, add these practices on top of the minimal flow:
- Validate pack bytes before runtime create (
tdse_pack_validate). - Inspect the pack summary before create so shape and metadata mismatches are visible early.
- Archive a Builder snapshot (
tdse_builder_info(...)) next to the pack or release artifact. - Run one deterministic runtime smoke check: create the model, read
tdse_model_info(...), and verify a known-good step path. - Archive
tdse_model_create_diagnostics_ton non-OK create paths. - Run threading stress and contract tests before promoting binaries.
Runtime handoff note:
- use Runtime Lifecycle for
create,close,destroy, andrelease - use Step Execution for prime, trial, commit, and post-commit queries
- use Runtime API Summary when you need a fast symbol map instead of a narrative walkthrough
Smallest Supported Builder -> Runtime Handoff
If your team needs the shortest credible integration contract, treat the handoff as these four checks:
- Builder writes one pack successfully
tdse_pack_validateaccepts that pack- Runtime create succeeds and
tdse_model_info(...)matches expectednp,nq,nh, anddt - one prime-and-step smoke path completes without status errors
Validation Checklist
-
tdse_pack_validatepasses on release pack. - Minimal step loop returns
TDSE_OKend-to-end. - One failure-injection case per major status is covered.
- Threading stress case is green on target build.
- Runtime outputs are stable across repeated runs with same input.
- Linux deployment claims match the current RuntimeCore Linux support scope when shipping on Linux.
Parameter Cookbook
| Parameter | Meaning | Recommended Baseline | Notes |
|---|---|---|---|
np | primary input count | system-dependent | Must match host primary vector width. |
nq | operator row count | >= np | Use full rectangular view when nq > np. |
nh | history taps | start with calibrated value | Higher nh raises history cost. |
dt | step interval | fixed per model | Keep builder/runtime dt consistent. |
IR length | independent sequence horizon | cover whole simulation window | Out-of-range returns TDSE_ERR_IR_STEP_OUT_OF_RANGE. |
| runtime handles | parallel threads | one handle per worker | Never step same handle concurrently. |
Data Contracts
TDSE Core is strict about dimensions, layout, and ownership. Most early integration failures are shape mistakes rather than numerical mistakes.
Primary Dimensions
Four dimensions define most Builder-to-Runtime compatibility:
| Symbol | Meaning | Practical Rule |
|---|---|---|
np | primary input count | must match host primary vector width |
nq | output-equation count | must satisfy nq >= np |
nh | history tap length | must match the supplied H tensor depth |
dt | model step interval | must be consistent across Builder and Runtime expectations |
API Families
At the Builder boundary, the main API families are:
Builder lifecycle
tdse_builder_createtdse_builder_configure_extdse_builder_apply_htdse_builder_apply_irtdse_builder_write_packtdse_builder_destroy
Pack validation and inspection
tdse_pack_validatetdse_pack_inspecttdse_pack_inspect_extdse_pack_error_token
Runtime handoff surface
tdse_model_createtdse_model_info
For full Runtime lifecycle and step APIs, switch to Runtime Lifecycle, Step Execution, or Runtime API Summary.
Ownership Model
- Builder descriptors such as
tdse_h_desc_tandtdse_ir_desc_tare borrowed views - Pack-validation and pack-inspection outputs are caller-owned result structs
- No Core API transfers ownership of caller-owned
H,IR, or step-output buffers
Compatibility Equation
Builder-side and Runtime-side assumptions are compatible only when all of these are true:
- Builder
np,nq,nh, anddtmatch the intended runtime model His laid out exactly as declared by its descriptor- optional
IRis laid out exactly as declared by its descriptor - runtime host buffers are sized from runtime-reported dimensions rather than from memory or guesswork
H Tensor Contract
H uses tap-major row-major storage: shape [nh][nq][np], linear index tap * nq * np + row * np + col, layout enum TDSE_H_LAYOUT_TAP_MAJOR_ROW_MAJOR.
H[0]is the instantaneous operator returned bytdse_step_op(...)H[1..nh-1]contribute to the delayed-history term returned bytdse_step_hr(...)
Explicit-tau contract:
h_desc.tau == NULLmeans delayed taps live on the implicit uniform axistau[k] = k * dth_desc.tau != NULLmeans Runtime evaluates history on the supplied explicit time axis- when
tauis explicit,H[1..nh-1]must already be weighted for that axis - if your source taps came from a uniform grid, convert them first with
tdse_h_uniform_to_tau_1d(...)ortdse_h_uniform_to_piecewise_tau_1d(...)
IR Sequence Contract
IR is step-major: shape [nsteps][nq], linear index step * nq + row, layout enum TDSE_IR_LAYOUT_STEP_MAJOR. Runtime queries IR by current step time. If the query falls outside the configured support window, tdse_step_ir(...) returns TDSE_ERR_IR_STEP_OUT_OF_RANGE.
Dense Operator Contract
tdse_step_op(...) writes into a tdse_dense_block_t. Supported views: square (np x np) or full (nq x np). cols must always equal np; rows must equal either np or nq.
Shape Worked Example
Assume np = 3, nq = 4, nh = 8, ir_nsteps = 100. Then:
| Query | Required Length / Shape |
|---|---|
primary vector passed to commit | length np = 3 |
hr_out buffer | length nq = 4 |
ir_out buffer | length nq = 4 |
square op view | 3 x 3 |
full op view | 4 x 3 |
committed dr_out buffer | length nq = 4 |
The common bug: sizing hr, ir, or dr buffers to np because the host thinks in terms of ports rather than equations. These buffers are nq-sized outputs.
Step-Term Contract
For the mathematical definitions, see Theory and Concepts.
| Term | Meaning | Side Effect |
|---|---|---|
op | instantaneous operator | none |
hr | delayed-history contribution | none |
ir | independent-response contribution | none |
dr | committed-step direct response | query-only, post-commit |
Read these equations literally: y_trial = op * primary_trial + hr + ir; dr[n] = op * primary_accepted[n]. dr is the direct-response slice on the committed step, not "the whole committed output."
Runtime Handoff Contract
Builder is done once the pack is internally consistent, validated, and clearly labeled. The runtime handoff should answer three questions before any simulation work starts:
- does the pack validate cleanly
- do inspected dimensions and metadata match what the host expects
- does Runtime create the model without reporting pack or compatibility errors
After that point, move to Runtime Lifecycle and Step Execution instead of continuing to reason about Runtime behavior from the Builder chapter.
Host-Side Assertions
In production, assert these once near the integration boundary:
model_info.npmatches host primary-vector widthmodel_info.nqmatches host equation/output widthmodel_info.nhmatches intended history depthmodel_info.dtmatches host time-step contract
Common Shape Mistakes
- host primary vector width does not match
np hr/irbuffers sized tonpinstead ofnq- square operator storage used when host required
nq x np - Builder
dtand simulationdtassumed to match without verification - inferring
np/nqfrom old code paths instead oftdse_model_info(...) - treating
IRas a runtime side channel instead of packaged model content
Power Systems Guide
Typical Parameters by Scenario
| Scenario | dt (s) | nh | nfft | np | nq | Notes |
|---|---|---|---|---|---|---|
| Transmission line (100 km, 500 kV) | 1e-6 to 10e-6 | 1000-5000 | 2 × nh | 2 (1 port) or 4 (2-port) | np or np+1 | Large nh for propagation delay |
| Transformer (50 MVA) | 1e-6 to 50e-6 | 200-1000 | 2 × nh | 2-6 | np | Moderate nh for winding capacitance |
| Distribution cable (underground) | 1e-6 to 10e-6 | 500-2000 | 2 × nh | 2-4 | np | nh depends on cable length |
| EMI/EMC (wideband) | 10e-9 to 100e-9 | 1000-4000 | 4 × nh | 1-10 | np | Very fine dt for high-frequency content |
| Power electronics (switching ~100 kHz) | 10e-9 to 100e-9 | 500-2000 | 2 × nh | 1-4 | np | Fine dt for switching transients |
Choosing nh
The history depth nh must be large enough that H[nh-1] has decayed to near zero:
- Build the pack with an initial
nhestimate - Inspect
H[k]for the last few taps (k near nh-1) - If
|H[nh-1]|is not negligible compared to|H[0]|, increasenh - Typical transmission lines:
nh ≈ round(propagation_delay / dt) + margin
For a 500 kV, 100 km line with propagation speed ~2.8×10⁸ m/s and dt = 50 μs: propagation delay ≈ 357 μs → nh ≈ 9. For dt = 1 μs: nh ≈ 367.
When to Use nq > np
Set nq > np when the model needs measurement equations beyond the port count: multi-port models with internal measurements, mixed Y/Z representations, or host simulators needing both terminal currents and internal state outputs. For standard Y+ISC or Z+VOC, nq = np is typical.
Builder Flow
Builder is the handoff layer between validated source artifacts and Runtime. A clear Builder boundary makes later debugging much easier: you can tell whether a problem comes from the source data, Builder configuration, pack generation, or Runtime execution.
Builder Responsibility
Builder owns the configured dimensions and dt, attachment of required H and optional IR, optional conversion from frequency-domain data into time-domain H, optional Builder-side shaping such as IRC, and the final pack metadata and pack write.
Builder does not own upstream artifact validity beyond descriptor and shape checks, host-specific port order or matrix-family interpretation, Runtime step execution, or Runtime shutdown and concurrency policy.
The main rule is simple: Builder should emit the final artifact, and Runtime should execute it as-is. Runtime is not expected to reconstruct or repair pack content later.
Builder State Machine
Important rules: tdse_builder_configure_ex(...) is the recommended configure entrypoint, re-configuring replaces dimensions and clears previously attached H and IR, tdse_builder_info(...) is the best snapshot of the current Builder state, and a successful pack write does not transfer handle ownership.
Builder Contract Table
| Contract Item | Set By | Why It Matters Downstream |
|---|---|---|
dt | tdse_builder_configure_ex(...) | Runtime timing and IR step addressing |
np | tdse_builder_configure_ex(...) | host primary vector width must match |
nq | tdse_builder_configure_ex(...) | hr, ir, dr, and full op row count |
nh | tdse_builder_configure_ex(...) | delayed-history horizon and H tensor depth |
H layout | tdse_h_desc_t | wrong layout produces plausible but incorrect packs |
explicit tau axis | tdse_h_desc_t | malformed nonuniform timing rejected before pack write |
IR layout and horizon | tdse_ir_desc_t | runtime tdse_step_ir(...) legality |
| pack form/domain metadata | tdse_builder_set_pack_meta(...) | support and consuming hosts interpret the pack |
Direct H Ingestion
Use when the upstream artifact is already a validated time-domain kernel. Sequence: configure → populate tdse_h_desc_t → tdse_builder_apply_h(...) → snapshot with tdse_builder_info(...) → write pack. Post-apply: verify info.configured, info.has_h, and dimension/tau expectations match.
Spectrum-to-H Conversion
Use tdse_builder_h_from_spectrum(...) when the upstream artifact is frequency-domain data.
The sequence: define positive-frequency grid → map source matrix into tdse_builder_cplx_mat_view_t → choose correction method → run conversion → attach → snapshot before write.
Correction methods:
TDSE_BUILDER_CORRECTION_NONE_RECONSTRUCT_FROM_REAL_RECONSTRUCT_FROM_IMAG_RECONSTRUCT_FROM_MAG_RECONSTRUCT_FROM_PHASE
These options change how Builder computes H; Runtime only sees the
finished pack. When this path looks wrong, ask two separate questions:
did Builder produce the intended H, and did Runtime execute that pack
correctly?
Grid Planning: dt, nh, and nfft
These three parameters must satisfy nfft >= 2 * nh (FFT covers full impulse response without aliasing), dt must capture the highest source frequency, and nh * dt must capture full decay. Use tdse_builder_compute_consistent_grid(&grid) to compute consistent values from hints.
| Scenario | dt | nh | nfft | Rationale |
|---|---|---|---|---|
| Power electronics (~100 kHz) | 10-100 ns | 500-2000 | 2 × nh | Fine dt for switching edges |
| Transmission line (long delay) | 0.1-1 ns | 2000-10000 | 2 × nh | Large nh for delay + reflections |
| Structural dynamics (< 1 kHz) | 1-10 us | 200-1000 | 2 × nh | Coarse dt sufficient |
| EMI/EMC (wideband) | 0.01-0.1 ns | 1000-4000 | 4 × nh | Large nfft for spectral resolution |
Common mistakes: nh too small → truncated impulse response; dt too large → aliasing; nfft < 2*nh → wrap-around corruption.
FRF Data Layout
The source frequency-domain data must be organized as a row-major complex matrix: H_frf[freq_idx * np * nq + row * np + col]. The grid must be monotonically increasing, include near-DC, and use approximately uniform spacing. The Builder expects Y or Z parameters (not S-parameters). Multi-port ordering must be consistent across all frequency points.
Builder IRC (Impulse Response Compression)
IRC reduces effective history depth by compressing the tail of the impulse-response tensor. Two modes: V1 (single decay rate, most common) and V2 (per-tap adaptive decay, higher fidelity). Both retain the first prefix_len taps exactly and fit an exponential envelope to the tail.
tdse_builder_irc_options_t irc_opt = tdse_builder_irc_options_init();
irc_opt.mode = TDSE_BUILDER_IRC_MODE_V1;
irc_opt.prefix_len = 64;
irc_opt.tail_tolerance = 1e-8;
tdse_builder_apply_irc(b, &irc_opt);
Keep the IRC parameters next to the pack so later comparisons are reproducible. Use the Profiler IRC scan to explore compression quality before production use.
Optional IR
IR is optional, but once attached it becomes part of the pack Runtime will load. Keep Builder dt and IR dt aligned, keep IR dimensions aligned with np and nq, make sure the IR support length covers the simulation horizon, and set pack form metadata intentionally (FLOW_FROM_EFFORT = Y+ISC, EFFORT_FROM_FLOW = Z+VOC, UNKNOWN only for packs without IR).
Builder Inspection
tdse_builder_info(...) is the fastest way to confirm what Builder currently has attached. Use it after configure and after every attach or clear. Fields worth logging are configured, dt/nh/np/nq, has_h/has_h_tau/h_layout, has_ir/ir_nsteps/ir_dt/ir_layout, and pack_form/pack_domain. Once the pack is written, tdse_model_info(...) becomes the matching Runtime-side confirmation point.
Write Gate Checklist
Before tdse_builder_write_pack(...), confirm that Builder is configured, H is attached, dimensions match, optional IR is either absent or correctly attached, pack metadata is explicit, and the output path is stable. After the write, validate the pack, inspect it, then hand off to Runtime for create and loop verification.
Worked Paths
Path A: Direct-H Pack
Highest-confidence path: configure once → attach H → inspect → write → validate → create Runtime model. Fewest transformations; easiest to isolate failures.
Path B: Frequency-Domain Source To Pack
Archive the frequency grid and matrix family → run tdse_builder_h_from_spectrum(...) → attach → inspect → write → validate. Needs more release discipline because a successful write does not prove the conversion policy was correct.
Path C: H + IR With Explicit Pack Meaning
Configure → attach H → attach IR → tdse_builder_set_pack_meta(...) intentionally → inspect → write → validate → create. Most likely to confuse downstream users if metadata is omitted.
Triage
Failure Modes
| Failure | Symptom | Root Cause | Fix |
|---|---|---|---|
TDSE_ERR_IR_STEP_OUT_OF_RANGE | tdse_step_ir fails mid-run | Simulation time exceeds IR support window | Extend IR sequence or clamp simulation horizon |
TDSE_ERR_CONCURRENT_API_USE | sporadic non-OK in multi-thread run | same handle stepped by multiple threads | Serialize per handle; one handle per thread |
TDSE_ERR_INVALID_ARG | immediate failure on create/step | null/shape mismatch in inputs | Validate pointers, dimensions, struct sizes |
| pack validation failure | create rejects model bytes | corrupted or incompatible pack | regenerate pack, inspect tdse_model_create_diagnostics_t |
Builder Failure Classes Worth Catching Early
| Failure Class | Typical Root Cause | Best Stage | Support Clue |
|---|---|---|---|
| dimension mismatch | np/nq/nh disagreement | configure/apply | Builder snapshot vs. source planning sheet |
| malformed descriptor | null pointer, bad struct size, invalid layout | apply | attach call fails immediately |
| tau-axis issue | invalid explicit nonuniform timing | apply H | has_h_tau vs. source timing mismatch |
| wrong matrix family | host supplied wrong physical meaning | preflight | pack validates but numerical behavior is wrong |
| IR horizon issue | sequence shorter than intended run | preflight/attach | Runtime fails at tdse_step_ir(...) |
| metadata ambiguity | form/domain not set intentionally | pre-write review | cannot tell Y+ISC from Z+VOC |
| write-path issue | unstable output path or file handling | pack write | configure/attach succeeded but no artifact exists |
Builder-To-Runtime Failure Isolation
When a runtime test fails after a fresh pack write, split the investigation: did Builder produce the intended artifact, or did Runtime execute it incorrectly? This separation keeps teams from debugging the wrong layer.
Troubleshooting Decision Flow
Rapid checks: prefer tdse_model_create(...) over process-global create diagnostics; log tdse_model_info once at model create; log t, dt, and step index on each failed call; keep one deterministic repro input for local and automated runs.
Anti-Patterns
- re-configuring a handle and assuming previous
H/IRis still attached - treating
tdse_builder_write_pack(...)as proof of semantic correctness - attaching
IRwithout deciding pack representation metadata - debugging Runtime first when Builder snapshots were never captured
- letting Runtime compensate for Builder-side source interpretation mistakes
- using ad hoc output paths that break pack provenance
Pack Incident Triage
When a pack validation or create issue is reported, collect:
- Builder configure inputs (
dt,nh,np,nq) - Builder snapshot from
tdse_builder_info(...) - whether the pack came from direct
Hor spectrum conversion - any conversion or tail-processing settings
- whether
IRwas attached and what pack-form metadata was used - result of
tdse_pack_validate(...) - result and diagnostics from
tdse_model_create(...)
If the first five items are missing, do not start by blaming Runtime.
