jkitchin's picture
Upload folder using huggingface_hub
f5f42f3 verified
# TEP Simulator API Reference
This document provides detailed API documentation for the Tennessee Eastman Process (TEP) Python simulator.
## Table of Contents
- [TEPSimulator](#tepsimulator)
- [SimulationResult](#simulationresult)
- [Controllers](#controllers)
- [FortranTEProcess](#fortranteprocess)
- [PythonTEProcess](#pythonteprocess)
- [Backend Selection](#backend-selection)
- [Constants](#constants)
---
## TEPSimulator
The main simulator class providing a high-level interface for running TEP simulations.
### Import
```python
from tep import TEPSimulator
from tep.simulator import ControlMode
```
### Constructor
```python
TEPSimulator(
random_seed: int = None,
control_mode: ControlMode = ControlMode.CLOSED_LOOP,
backend: str = None
)
```
**Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `random_seed` | `int` | `1431655765` | Random seed for reproducible simulations |
| `control_mode` | `ControlMode` | `CLOSED_LOOP` | Control mode (see below) |
| `backend` | `str` | `None` (auto) | Simulation backend: `None`, `"fortran"`, or `"python"` |
**Backend Options:**
| Backend | Description |
|---------|-------------|
| `None` | Auto-select best available (Fortran if installed, otherwise Python) |
| `"python"` | Pure Python implementation (default install, no compilation needed) |
| `"fortran"` | Original Fortran code via f2py (~5-10x faster, requires gfortran) |
**Note:** The default installation uses the Python backend. To enable Fortran acceleration, install with: `pip install . --config-settings=setup-args=-Dfortran=enabled`
**Control Modes:**
| Mode | Description |
|------|-------------|
| `ControlMode.OPEN_LOOP` | No automatic control - MVs remain fixed |
| `ControlMode.CLOSED_LOOP` | Decentralized PI control active |
| `ControlMode.MANUAL` | User sets MVs directly via `set_mv()` |
### Methods
#### initialize()
Initialize or reset the simulator to steady-state conditions. **Must be called before simulation.**
```python
sim = TEPSimulator()
sim.initialize()
```
#### simulate()
Run a complete simulation and return results.
```python
result = sim.simulate(
duration_hours: float = 1.0,
dt_hours: float = None,
disturbances: Dict[int, Tuple[float, int]] = None,
record_interval: int = 1,
progress_callback: Callable[[float], None] = None
) -> SimulationResult
```
**Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `duration_hours` | `float` | `1.0` | Simulation duration in hours |
| `dt_hours` | `float` | `1/3600` | Time step (default 1 second) |
| `disturbances` | `dict` | `None` | Scheduled disturbances `{idv: (time, value)}` |
| `record_interval` | `int` | `1` | Record every N steps |
| `progress_callback` | `callable` | `None` | Called with progress (0.0-1.0) |
**Returns:** `SimulationResult` object
**Example:**
```python
# Simple simulation
result = sim.simulate(duration_hours=2.0)
# With disturbance at t=0.5h
result = sim.simulate(
duration_hours=4.0,
disturbances={1: (0.5, 1)} # IDV(1) at 0.5 hours
)
# Multiple disturbances
result = sim.simulate(
duration_hours=8.0,
disturbances={
1: (1.0, 1), # IDV(1) at 1 hour
4: (2.0, 1), # IDV(4) at 2 hours
}
)
```
#### step()
Advance simulation by N steps.
```python
running = sim.step(n_steps: int = 1) -> bool
```
**Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `n_steps` | `int` | `1` | Number of integration steps |
**Returns:** `True` if running, `False` if shutdown occurred
#### set_disturbance()
Activate or deactivate a process disturbance.
```python
sim.set_disturbance(idv_index: int, value: int = 1)
```
**Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `idv_index` | `int` | Disturbance index (1-20) |
| `value` | `int` | 0 = off, 1 = on |
#### clear_disturbances()
Turn off all active disturbances.
```python
sim.clear_disturbances()
```
#### set_mv()
Set a manipulated variable (for manual control mode).
```python
sim.set_mv(index: int, value: float)
```
**Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `index` | `int` | MV index (1-12) |
| `value` | `float` | Valve position (0-100%) |
#### get_measurements()
Get current process measurements.
```python
measurements = sim.get_measurements() -> np.ndarray # Shape: (41,)
```
#### get_manipulated_vars()
Get current manipulated variable values.
```python
mvs = sim.get_manipulated_vars() -> np.ndarray # Shape: (12,)
```
#### get_states()
Get current state vector.
```python
states = sim.get_states() -> np.ndarray # Shape: (50,)
```
#### is_shutdown()
Check if process is in safety shutdown state.
```python
shutdown = sim.is_shutdown() -> bool
```
### Streaming Interface
For real-time dashboard integration:
#### start_stream()
Initialize streaming mode with history buffer.
```python
sim.start_stream(history_size: int = 1000)
```
#### stream_step()
Take one step and return current state.
```python
data = sim.stream_step() -> dict
```
**Returns:**
```python
{
'time': float, # Current time (hours)
'time_seconds': float, # Current time (seconds)
'measurements': np.ndarray, # Shape: (41,)
'mvs': np.ndarray, # Shape: (12,)
'shutdown': bool
}
```
#### get_stream_history()
Get historical data for plotting.
```python
history = sim.get_stream_history() -> dict
```
**Returns:**
```python
{
'time': np.ndarray, # Time points
'time_seconds': np.ndarray, # Time in seconds
'measurements': np.ndarray, # Shape: (n_points, 41)
'mvs': np.ndarray # Shape: (n_points, 12)
}
```
### Properties
| Property | Type | Description |
|----------|------|-------------|
| `time` | `float` | Current simulation time (hours) |
| `step_count` | `int` | Number of steps taken |
| `initialized` | `bool` | Whether simulator is initialized |
| `control_mode` | `ControlMode` | Current control mode |
---
## SimulationResult
Container for simulation results returned by `simulate()`.
### Attributes
| Attribute | Type | Description |
|-----------|------|-------------|
| `time` | `np.ndarray` | Time points in hours |
| `states` | `np.ndarray` | State trajectories (n_steps, 50) |
| `measurements` | `np.ndarray` | Measurements (n_steps, 41) |
| `manipulated_vars` | `np.ndarray` | MVs (n_steps, 12) |
| `shutdown` | `bool` | Whether shutdown occurred |
| `shutdown_time` | `float` | Time of shutdown (if any) |
### Properties
| Property | Type | Description |
|----------|------|-------------|
| `time_seconds` | `np.ndarray` | Time in seconds |
| `time_minutes` | `np.ndarray` | Time in minutes |
### Example
```python
result = sim.simulate(duration_hours=1.0)
# Access data
print(f"Simulation ended at {result.time[-1]:.2f} hours")
print(f"Shutdown: {result.shutdown}")
# Plot reactor temperature
import matplotlib.pyplot as plt
plt.plot(result.time_minutes, result.measurements[:, 8])
plt.xlabel('Time (min)')
plt.ylabel('Reactor Temperature (C)')
plt.show()
```
---
## Controllers
### PIController
Proportional-Integral controller using velocity form.
```python
from tep.controllers import PIController
controller = PIController(
setpoint: float,
gain: float,
taui: float = 0.0, # Reset time (hours), 0 = P-only
output_min: float = 0.0,
output_max: float = 100.0,
scale: float = 1.0
)
# Calculate new output
new_output = controller.calculate(
measurement: float,
current_output: float,
dt: float # Time step (hours)
)
```
### DecentralizedController
Multi-loop control system implementing the temain_mod.f control scheme.
```python
from tep.controllers import DecentralizedController
controller = DecentralizedController()
# Calculate all MV updates
new_xmv = controller.calculate(
xmeas: np.ndarray, # 41 measurements
xmv: np.ndarray, # 12 MVs
time_step: int # Step number
)
# Reset to initial state
controller.reset()
```
### ManualController
Holds MVs at user-specified values.
```python
from tep.controllers import ManualController
controller = ManualController()
controller.set_mv(1, 50.0) # Set MV 1 to 50%
# Returns stored values
new_xmv = controller.calculate(xmeas, xmv, step)
```
### Custom Controllers
You can use any callable as a controller:
```python
def my_controller(xmeas, xmv, step):
"""Custom control law."""
new_xmv = xmv.copy()
# Your control logic here
return new_xmv
result = sim.simulate_with_controller(
duration_hours=1.0,
controller=my_controller
)
```
---
## FortranTEProcess
Low-level Fortran process interface via f2py (direct TEINIT/TEFUNC wrapper).
```python
from tep import FortranTEProcess
process = FortranTEProcess(random_seed=12345)
process._initialize()
# Evaluate derivatives
yp = process.evaluate(time=0.0, yy=process.state.yy)
# Get/set measurements and MVs
xmeas = process.get_xmeas()
xmv = process.get_xmv()
process.set_xmv(1, 50.0)
process.set_idv(1, 1)
```
This class wraps the original Fortran subroutines `TEINIT` and `TEFUNC` via f2py, providing exact numerical results matching the original TEP benchmark.
---
## PythonTEProcess
Low-level pure Python process interface (reimplementation of Fortran TEINIT/TEFUNC).
```python
from tep import PythonTEProcess
process = PythonTEProcess(random_seed=12345)
process.teinit()
# Evaluate derivatives
process.tefunc(time=0.0)
yp = process.yp # Derivative array
# Get/set measurements and MVs
xmeas = process.get_xmeas()
xmv = process.get_xmv()
process.set_xmv(1, 50.0)
process.set_idv(1, 1)
```
This class provides a pure Python implementation of the TEP simulator, matching the Fortran code's behavior without requiring compilation. See [Python Backend Documentation](python_backend.md) for details.
---
## Backend Selection
Utility functions for backend selection:
```python
from tep import (
get_available_backends, # Returns ['fortran', 'python'] or ['python']
get_default_backend, # Returns 'fortran' if available, else 'python'
is_fortran_available, # Returns True if Fortran backend was compiled
)
# Example usage
if is_fortran_available():
sim = TEPSimulator(backend='fortran')
else:
sim = TEPSimulator(backend='python')
# Or let the library choose
sim = TEPSimulator(backend=get_default_backend())
```
---
## Constants
### Dimensions
```python
from tep.constants import (
NUM_STATES, # 50
NUM_MEASUREMENTS, # 41
NUM_MANIPULATED_VARS, # 12
NUM_DISTURBANCES, # 20
)
```
### Names
```python
from tep import (
COMPONENT_NAMES, # ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
MEASUREMENT_NAMES, # List of 41 measurement descriptions
MANIPULATED_VAR_NAMES, # List of 12 MV descriptions
DISTURBANCE_NAMES, # List of 20 disturbance descriptions
)
```
### Initial Conditions
```python
from tep.constants import INITIAL_STATES # np.ndarray of 50 steady-state values
```
---
## Measurement Index Reference
| Index | Variable | Description | Units |
|-------|----------|-------------|-------|
| 0 | XMEAS(1) | A Feed Flow | kscmh |
| 1 | XMEAS(2) | D Feed Flow | kg/hr |
| 2 | XMEAS(3) | E Feed Flow | kg/hr |
| 3 | XMEAS(4) | A and C Feed Flow | kscmh |
| 4 | XMEAS(5) | Recycle Flow | kscmh |
| 5 | XMEAS(6) | Reactor Feed Rate | kscmh |
| 6 | XMEAS(7) | Reactor Pressure | kPa gauge |
| 7 | XMEAS(8) | Reactor Level | % |
| 8 | XMEAS(9) | Reactor Temperature | deg C |
| 9 | XMEAS(10) | Purge Rate | kscmh |
| 10 | XMEAS(11) | Separator Temperature | deg C |
| 11 | XMEAS(12) | Separator Level | % |
| 12 | XMEAS(13) | Separator Pressure | kPa gauge |
| 13 | XMEAS(14) | Separator Underflow | m3/hr |
| 14 | XMEAS(15) | Stripper Level | % |
| 15 | XMEAS(16) | Stripper Pressure | kPa gauge |
| 16 | XMEAS(17) | Stripper Underflow | m3/hr |
| 17 | XMEAS(18) | Stripper Temperature | deg C |
| 18 | XMEAS(19) | Stripper Steam Flow | kg/hr |
| 19 | XMEAS(20) | Compressor Work | kW |
| 20 | XMEAS(21) | Reactor CW Outlet Temp | deg C |
| 21 | XMEAS(22) | Separator CW Outlet Temp | deg C |
| 22-27 | XMEAS(23-28) | Reactor Feed Composition | mol% A-F |
| 28-35 | XMEAS(29-36) | Purge Gas Composition | mol% A-H |
| 36-40 | XMEAS(37-41) | Product Composition | mol% D-H |
## Manipulated Variable Index Reference
| Index | Variable | Description |
|-------|----------|-------------|
| 0 | XMV(1) | D Feed Flow Valve |
| 1 | XMV(2) | E Feed Flow Valve |
| 2 | XMV(3) | A Feed Flow Valve |
| 3 | XMV(4) | A and C Feed Flow Valve |
| 4 | XMV(5) | Compressor Recycle Valve |
| 5 | XMV(6) | Purge Valve |
| 6 | XMV(7) | Separator Liquid Flow Valve |
| 7 | XMV(8) | Stripper Product Flow Valve |
| 8 | XMV(9) | Stripper Steam Valve |
| 9 | XMV(10) | Reactor Cooling Water Valve |
| 10 | XMV(11) | Condenser Cooling Water Valve |
| 11 | XMV(12) | Agitator Speed |
## Disturbance Index Reference
| Index | Variable | Type | Description |
|-------|----------|------|-------------|
| 0 | IDV(1) | Step | A/C Feed Ratio Change |
| 1 | IDV(2) | Step | B Composition Change |
| 2 | IDV(3) | Step | D Feed Temperature |
| 3 | IDV(4) | Step | Reactor CW Inlet Temp |
| 4 | IDV(5) | Step | Condenser CW Inlet Temp |
| 5 | IDV(6) | Step | A Feed Loss |
| 6 | IDV(7) | Step | C Header Pressure Loss |
| 7 | IDV(8) | Random | A,B,C Feed Composition |
| 8 | IDV(9) | Random | D Feed Temperature |
| 9 | IDV(10) | Random | C Feed Temperature |
| 10 | IDV(11) | Random | Reactor CW Inlet Temp |
| 11 | IDV(12) | Random | Condenser CW Inlet Temp |
| 12 | IDV(13) | Drift | Reaction Kinetics |
| 13 | IDV(14) | Sticking | Reactor CW Valve |
| 14 | IDV(15) | Sticking | Condenser CW Valve |
| 15-19 | IDV(16-20) | Unknown | Reserved |