Getting Started
The first runnable path from a fresh checkout to a verified TDSE step loop.
Use this chapter for the shortest trustworthy TDSE bring-up: build a minimal 3-port model from scratch, write one pack, load it into Runtime, and verify a small step loop.
Prerequisite: Complete the Installation chapter first.
This is the first-run chapter referenced elsewhere in the handbook as Hands-On Tutorial.
The tutorial has four steps:
- Create the Builder input data — a C program that defines an impulse response and writes a runtime pack.
- Compile and run the Builder — produce
tutorial.pack. - Run the Runtime step loop — load the pack, create a model, and execute five steps.
- Verify the output — confirm the model metadata and step results match expectations.
By the end, you will have exercised the core SDK pipeline: Builder -> pack -> Runtime -> step loop. All code is runnable as-is.
For most installed-package evaluations, this chapter should take about 15-30 minutes. If the installed SDK is already on your machine and the commands below run unchanged, you should end the session with one pack, one successful model create, and one clean create-step-destroy path.
Expected outputs from this chapter:
tutorial.pack- a successful
tdse_model_create(...) - five successful runtime steps
- a clean
tdse_model_destroy(...)
Before you start, confirm these are already true:
tdse sdk version --json-out -succeeds from the installed package- the tiny compile-and-link check from Installation already works
- you are using the same SDK prefix, compiler family, and library names from Installation
After Hands-On Tutorial, use the Examples Guide to choose the closest runnable reference for your real integration path.
Step 1: Create the Builder Input Data
This program does three things: (1) defines a 3-port impulse response with 4 taps,
(2) configures the Builder with shape parameters, and (3) writes a .pack file.
Create tutorial_data.c:
#include <tdse/tdse.h>
#include <tdse_builder.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
const size_t np = 3;
const size_t nh = 4;
const double dt = 1e-3;
/* Identity-like H: h[k] decays with k */
double h[4 * 3 * 3] = {
1, 0, 0, 0, 1, 0, 0, 0, 1, /* h[0]: instantaneous */
0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, /* h[1] */
0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, /* h[2] */
0.05, 0, 0, 0, 0.05, 0, 0, 0, 0.05 /* h[3] */
};
/* Uniform tap axis: tau[k] = k * dt */
double tau[4] = {0.0, 1.0e-3, 2.0e-3, 3.0e-3};
/* Configure and build */
tdse_builder_t* b = NULL;
tdse_builder_options_t opt = tdse_builder_options_init();
opt.dt = dt;
opt.nh = nh;
opt.np = np;
opt.nq = np;
if (tdse_builder_create(&b) != TDSE_BUILDER_OK) return 1;
tdse_h_desc_t h_desc;
memset(&h_desc, 0, sizeof(h_desc));
h_desc.struct_size = sizeof(h_desc);
h_desc.np = (int32_t)np;
h_desc.nq = (int32_t)np;
h_desc.nh = (uint64_t)nh;
h_desc.data = h;
h_desc.tau = tau; /* optional explicit tau; h must already match that axis */
if (tdse_builder_configure_ex(b, &opt) != TDSE_BUILDER_OK) return 1;
if (tdse_builder_apply_h(b, &h_desc) != TDSE_BUILDER_OK) return 1;
if (tdse_builder_write_pack(b, "tutorial.pack") != TDSE_BUILDER_OK) return 1;
tdse_builder_destroy(b);
printf("Pack written to tutorial.pack\n");
return 0;
}
This is a runnable example: compile it against the SDK headers and libraries.
Step 2: Run the Builder
Compile and run (assuming SDK is installed at /opt/tdse-sdk):
cc tutorial_data.c \
-I/opt/tdse-sdk/include \
-L/opt/tdse-sdk/lib \
-ltdse_builder -lm \
-o tutorial_build
LD_LIBRARY_PATH=/opt/tdse-sdk/lib ./tutorial_build
Windows (MSVC):
cl tutorial_data.c ^
/I"C:\tdse-sdk\include" ^
/link "C:\tdse-sdk\lib\tdse_builder.lib"
tutorial_build.exe
Success: you see Pack written to tutorial.pack.
Step 3: Run the Runtime Step Loop
Create tutorial_run.c:
#include <tdse/tdse.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
static int read_file(const char* path, unsigned char** out, size_t* out_len) {
FILE* f = fopen(path, "rb");
long sz; size_t n; unsigned char* p;
if (!f) return 1;
fseek(f, 0, SEEK_END); sz = ftell(f); fseek(f, 0, SEEK_SET);
p = (unsigned char*)malloc((size_t)sz);
n = fread(p, 1, (size_t)sz, f); fclose(f);
*out = p; *out_len = (size_t)sz;
return n != (size_t)sz;
}
int main(void) {
const size_t np = 3;
const double dt = 1e-3;
const double t0 = 0.0;
const size_t nsteps = 5;
unsigned char* pack = NULL;
size_t pack_len = 0;
tdse_model_t* m = NULL;
if (read_file("tutorial.pack", &pack, &pack_len) != 0) return 1;
/* Create model with diagnostics */
tdse_model_create_diagnostics_t diag = tdse_model_create_diagnostics_init();
tdse_status_t st = tdse_model_create(pack, pack_len, &diag, &m);
free(pack);
if (st != TDSE_OK || m == NULL) {
printf("Create failed: %s (pack_error=%u)\n",
tdse_status_message(st), diag.pack_error_code);
return 1;
}
/* Log metadata */
tdse_model_info_t info = tdse_model_info_init();
tdse_model_info(m, &info);
printf("Model: np=%zu nq=%zu nh=%zu dt=%.6f\n",
(size_t)info.np, (size_t)info.nq, (size_t)info.nh, info.dt);
/* Prime at n = -1 */
double primary0[3] = {0.0, 0.0, 0.0};
tdse_step_begin(m, t0 - dt, dt);
tdse_dense_block_t op_blk;
memset(&op_blk, 0, sizeof(op_blk));
double op[9] = {0};
op_blk.struct_size = sizeof(op_blk);
op_blk.rows = (int32_t)np; op_blk.cols = (int32_t)np;
op_blk.ld = (int32_t)np; op_blk.layout = TDSE_LAYOUT_ROW_MAJOR;
op_blk.data = op;
tdse_step_op(m, &op_blk);
tdse_step_commit(m, primary0);
/* Main step loop */
double hr[3], ir[3], dr[3], y[3];
for (size_t n = 0; n < nsteps; ++n) {
double primary[3] = {sin(0.1*n), cos(0.1*n), 0.5};
tdse_step_begin(m, t0 + n * dt, dt);
tdse_step_hr(m, hr);
tdse_step_ir(m, ir);
/* Host composes: y = op * primary + hr + ir */
for (size_t r = 0; r < np; ++r) {
y[r] = hr[r] + ir[r];
for (size_t c = 0; c < np; ++c)
y[r] += op[r * np + c] * primary[c];
}
tdse_step_commit(m, primary);
tdse_step_dr(m, dr);
printf("step=%zu y=[%+.6f %+.6f %+.6f] dr=[%+.6f %+.6f %+.6f]\n",
n, y[0], y[1], y[2], dr[0], dr[1], dr[2]);
}
/* Bounded shutdown */
tdse_model_destroy_options_t dopt = tdse_model_destroy_options_init();
tdse_model_destroy_result_t dres = tdse_model_destroy_result_init();
dopt.wait_timeout_ms = 250.0;
st = tdse_model_destroy(m, &dopt, &dres);
printf("Destroy: %s\n", tdse_status_message(st));
return st == TDSE_OK ? 0 : 1;
}
Compile and run (assuming SDK is installed at /opt/tdse-sdk):
cc tutorial_run.c \
-I/opt/tdse-sdk/include \
-L/opt/tdse-sdk/lib \
-ltdse -lm \
-o tutorial_run
LD_LIBRARY_PATH=/opt/tdse-sdk/lib ./tutorial_run
Windows (MSVC):
cl tutorial_run.c ^
/I"C:\tdse-sdk\include" ^
/link "C:\tdse-sdk\lib\tdse.lib"
tutorial_run.exe
Step 4: Verify the Output
Expected output:
Model: np=3 nq=3 nh=4 dt=0.001000
step=0 y=[+0.000000 +0.000000 +0.000000] dr=[+... +... +...]
step=1 y=[+... +... +...] dr=[+... +... +...]
step=2 y=[+... +... +...] dr=[+... +... +...]
step=3 y=[+... +... +...] dr=[+... +... +...]
step=4 y=[+... +... +...] dr=[+... +... +...]
Destroy: OK
Success checklist:
tdse_model_createreturnsTDSE_OKandm != NULLtdse_model_inforeportsnp=3, nq=3, nh=4, dt=0.001- Every step loop call returns
TDSE_OK tdse_model_destroyreturnsTDSE_OK
If any step fails, see the failure table in Common First-Run Failure Modes and Troubleshooting.
If all four steps succeed, do not add more complexity here. Move directly to Examples Guide and pick the closest real integration path.
After This Tutorial
Once the first run works, do not keep extending this file as your main reference. Switch to the chapter that matches your real starting point:
| Your next task | Go here next | Why |
|---|---|---|
| find the closest runnable reference | Examples Guide | fastest way to map from Hands-On Tutorial to real code |
package real H or IR data | Builder and Data Contracts | production Builder checks and handoff rules |
| wire Runtime into a host simulator | Runtime Lifecycle and Step Execution | lifecycle, ownership, and step semantics |
| convert netlists or RAW data | Adapter Circuit | end-to-end circuit workflow |
| investigate a failure | Troubleshooting | symptom-first triage |
For a compact mental model, keep these five handoffs in mind:
- source data becomes Builder input
- Builder writes a
.pack - Runtime creates a model from that pack
- the host runs prime, trial, and commit
- shutdown happens after the step loop is quiescent
Key Patterns
The tutorial above exercises two patterns you will use repeatedly.
The Builder → Runtime pipeline:
create builder → configure → apply H → write pack → create model → step loop → destroy
The step loop (minimal form):
tdse_step_begin(m, t0 - dt, dt); /* prime at n = -1 */
tdse_step_op(m, &op);
tdse_step_commit(m, primary_minus1);
for (uint64_t n = 0; n < nsteps; ++n) {
tdse_step_begin(m, t0 + n * dt, dt);
tdse_step_hr(m, hr);
tdse_step_ir(m, ir);
/* host solve: y = op * primary + hr + ir */
tdse_step_commit(m, primary);
}
Production shutdown: use bounded destroy with an explicit wait budget.
tdse_model_destroy_options_t opt = tdse_model_destroy_options_init();
opt.wait_timeout_ms = 250.0;
tdse_model_destroy(m, &opt, &result);
For the mathematical meaning behind H, IR, hr, ir, and op, see
Theory and Concepts.
C++ Wrapper
The C++ wrapper (tdse::Model) follows the same contract. See the
Examples Guide for runnable C++ examples.
Common First-Run Failure Modes
When the API bring-up fails, it is usually one of these:
| Symptom | Most Likely Cause | First Check |
|---|---|---|
| create fails immediately | bad pack bytes or missing diagnostics init | create_diag, pack validation, pack token |
step_ir fails mid-run | IR horizon too short | simulation step index and ir_nsteps |
destroy times out | another same-handle API is still active | thread ownership and wait budget |
INVALID_STATE on dr | dr queried before commit or during active trial step | lifecycle order |
