Architecture¶
The implementation uses a narrow numerical core and task-specific adapters. The process core is separate from the reinforcement-learning environment, trajectory dataset object, optimizer, and validation runner. This prevents downstream workflows from inventing their own naming, action, event, or termination conventions.
Layer Overview¶
| Layer | Module or artifact | Responsibility |
|---|---|---|
| Native TEP kernel | native.py, _cffi_build.py, temexd_mod/temexd_mod.c |
Wrap the legacy modified TEP equations, reset state, derivative calls, output calls, shutdown status, and model-byte snapshots. |
| Machine-readable schema | schema.py |
Define names, roles, units, indices, bounds, descriptions, and online availability. |
| Simulator core | core.py |
Provide reset, advance, snapshot, restore, and validate. |
| Online interaction adapter | gym_env.py |
Expose a Gymnasium-compatible reset/step interface. |
| Trajectory adapter | dataset.py |
Convert AdvanceResult objects into pandas, NumPy, CSV, and Parquet data products. |
| Optimization adapter | optimization.py |
Support finite-horizon rollout and finite-difference gradients. |
| Control layer | control/ |
Decentralized multiloop PI controller (Ricker 1996) that closes the loop on published measurements only. |
| Interface | ui/ |
Dash + Plotly "Simulation Studio" over a Dash-free, importable backend (ui/service.py) for runs, disturbances, and dataset generation. |
| Validation framework | validation/ (writes the gitignored, generated validation_outputs/) |
Run validation suites and write metrics, figures, reports, trajectories, and manifests. |
Dependency Direction¶
temexd_mod.c -> native.py -> core.py -> gym_env.py
| -> dataset.py
schema.py --------------------| -> optimization.py
-> control/ -> ui/
-> validation/
native.py and schema.py feed core.py. The Gymnasium, dataset, optimization, control, UI, and validation layers consume the core. The UI's backend (ui/service.py) sits on top of both the core and the control layer. Task-specific adapters are not the source of process truth.
Control Layer¶
The control/ package is a consumer of the core, not part of it, following the same separation the design principles call for. It drives the documented advance(action, action_level="direct_mv") interface and reads only AdvanceResult.measurements, never state (no plant-state leakage).
| Module | Responsibility |
|---|---|
pi.py |
Positional and velocity discrete-PI primitives with saturated-state anti-windup. |
loops.py, registry.py |
Declarative Mode-1 loop table (RICKER_MODE1): gains, reset times, pairings, overrides, resolved by schema name. |
controller.py |
RickerMultiLoopController: per-step orchestration and bumpless initialization. |
runner.py |
ClosedLoopSimulation: couples controller and core; records a trajectory and full-resolution metrics; separates termination from truncation. |
views.py |
Causal online_control_view vs offline diagnostic_view. |
metrics.py, experiment.py, config.py |
IAE/ISE/violation metrics and a reproducible experiment record (source revision, hashes, seed, solver, model-leakage policy). |
See Closed-Loop Control for usage.
Interface Layer¶
The ui/ package is the "Simulation Studio", a Dash + Plotly web app over a deliberately Dash-free, importable backend, so the same runs and exports are scriptable without a browser.
| Module | Responsibility |
|---|---|
config.py |
ScenarioConfig/BatchSpec — the JSON-round-trippable unit of save/load and batch sweeps, validated against the schema. |
service.py |
UI-agnostic backend: run_scenario, run_mv_step_test, run_setpoint_step_test, build_dataset, run_batch. |
figures.py |
Plotly figure builders (trajectory grid, MV panel, compare overlay, step response). |
results.py, store.py |
Compact RunResult artifacts and a server-side run cache. |
app.py, layout.py, widgets.py, callbacks.py |
The thin Dash app: create_app, schema-driven widgets, and callbacks. Dash is imported lazily so import tep_studio works without the ui extra. |
See Interface (Studio) for usage.
Native Boundary¶
The native layer preserves the legacy model and exposes only the functions needed by the Python simulator:
| Native function | Purpose |
|---|---|
tep_create, tep_destroy |
Allocate and free native model state. |
tep_reset |
Initialize the modified TEP model with optional initial state, seed, and measurement/noise flag. |
tep_set_inputs |
Set 12 manipulated variables and 28 disturbance activations. |
tep_derivatives |
Evaluate the 50-state derivative vector. |
tep_outputs |
Evaluate standard measurements and monitor arrays. |
tep_shutdown_code, tep_shutdown_message |
Read process shutdown status. |
tep_model_size, tep_get_model_bytes, tep_set_model_bytes |
Snapshot and restore native model memory. |
The C layer remains responsible for derivatives, outputs, internal model state, and shutdown status. The Python layer is responsible for names, metadata, trajectory formats, interaction semantics, and experiment records.
Advance Result¶
Every successful advance call returns an AdvanceResult. It is the typed contract between the core simulator and its adapters.
| Field | Meaning |
|---|---|
time, time_end |
End time of the interval in hours. time is a compatibility alias. |
time_start, control_interval |
Start time and length of the control interval. |
state |
50-element state vector at time_end. |
measurements |
41 standard TEP measurements. |
additional_measurements |
32 additional modified-TEP outputs. |
disturbance_monitors |
21 noise-free disturbance monitor outputs. |
process_monitors |
62 process monitor outputs. |
concentration_monitors |
96 component concentration monitor outputs. |
requested_action, implemented_action |
Raw requested action and clipped action applied to the process. |
disturbances |
28-element disturbance vector used for the interval. |
constraint_margins |
Named safety margins. |
events, shutdown_status |
Structured process events and shutdown status. |
solver_stats |
Integration method, success flag, message, and evaluation counts. |
objective_terms |
Cost-related monitor terms exposed by the process core. |