drto
DRTO is a unified framework for dynamic real-time optimization built on Pyomo.
Status
Alpha. The registry (drto.info), the declaration surface, objective
assembly, the control-profile application, and the infinite-horizon terminal
segment (features 001-004 and 017) are implemented and tested; the mode
transforms, initializers, and closed-loop frameworks follow. The feature
statuses live in features/README.md, and DESIGN.md
remains the design record.
Install
pip install drto
The pounce solver and pyomo-pounce are needed for full functionality (sensitivity updates, the advanced-step frameworks); any NLP solver runs the open-loop modes.
Spec-driven development
drto is built spec-first: every feature is specified under
features/ before it is implemented, as a short doc with a
status, a user-story description, a benefit hypothesis, and acceptance
criteria that drive the tests. See features/README.md.
A feature request may be made by opening a pull request that adds a feature
file under features/ in the template format.
Modes
drto runs one declared model in any of six modes, the 2x3 grid of {steady-state, dynamic} by {simulation, optimization, estimation}. You write the model once; the mode fixes what is free and what the objective is.
| Simulation | Optimization | Estimation | |
|---|---|---|---|
| Steady-state | solve the model at equilibrium | economic RTO | data reconciliation |
| Dynamic | integrate the model forward | NMPC / D-RTO | moving horizon estimation |
Down the columns: simulation frees nothing and solves the model as given; optimization frees the controls and adds a cost; estimation frees the states and fits them to measurements. Across the rows: the steady-state modes solve at a single equilibrium point, the dynamic modes keep the time horizon. A dynamic model is collapsed to that equilibrium, and a model authored directly as steady-state, with no time or dynamics, runs in the steady-state modes as it stands, so a user can define the model either way and still use it across the modes. The optimization and estimation columns are duals (NMPC with MHE, RTO with reconciliation), so one declaration surface serves both.
The near-term focus is the optimization column: dynamic NMPC/D-RTO, whose ideal, nonideal, and advanced-step execution variants are the headline, plus steady-state RTO. Estimation is the planned follow-on.
Transformations
The six modes above are each a single solve exposed
as a Pyomo transformation under the drto. namespace, alongside the
lower-level transformations they compose. You build one declared model and
apply the transformation you want, the same way you apply any Pyomo
transformation.
| Transformation | Registered as |
|---|---|
| Steady-state simulation | drto.steady_state_simulation |
| Steady-state optimization | drto.steady_state_optimization |
| Steady-state estimation | drto.steady_state_estimation |
| Dynamic simulation | drto.dynamic_simulation |
| Dynamic optimization | drto.dynamic_optimization |
| Dynamic estimation | drto.dynamic_estimation |
| Objective assembly | drto.build_objective |
| Steady-state reduction | drto.dynamic_to_steady_state |
| Infinite-horizon terminal segment | drto.infinite_horizon |
| Control profile application | drto.parameterize |
Closed-loop frameworks
Separately from the modes come the closed-loop frameworks: the dynamic optimization loop in ideal, nonideal, and advanced-step forms (drafted as features 014-016), and the estimation loops, specced later.
| Ideal | Nonideal | Advanced Step | |
|---|---|---|---|
| Optimization | ideal_nmpc |
nonideal_nmpc |
asnmpc |
| Estimation | MHE |
asMHE |
The advanced-step column, asnmpc and asMHE, is built on
drto.advanced_step_controller: it solves the horizon at a predicted state and
then corrects to the actual state with a fast pounce sensitivity update rather
than a re-solve.
Initialization routines
A good initial guess is often the difference between an IPOPT solve that
converges and one that stalls, so drto provides named initializers rather than
leaving each user to hand-roll one. These are plain functions, not
transformations: they leave the model structure alone and only populate the
variable values (the initial guess), so there is no apply_to or
create_using form.
| Initializer | What it does |
|---|---|
initialize_steady_state |
Solve the steady-state form and broadcast that equilibrium across every time point: a flat starting trajectory. |
cold_start_dynamic |
Simulate the model forward from the initial condition under nominal controls, a feasible starting trajectory for the first solve with no history. |
warm_start_dynamic |
Shift the previous horizon's solution forward one step and fill the tail: the standard receding-horizon warm start. |
warm_start_dynamic is really a loop operation that belongs with the
closed-loop frameworks, listed here alongside its siblings for completeness.
Declaring an optimization or simulation problem
drto is declaration-first, and each declaration tags a Pyomo component you
already wrote: a Variable, a Constraint, a Parameter, or a Set. You build your dynamic model as
an ordinary Pyomo model, then point the declarations at its pieces;
drto assembles the horizon problem and runs the loop. It bolts onto an
existing model rather than replacing how you build one. The same functions
also wrap construction (m.z = state(pyo.Var(m.t)) registers at
attachment), and the constraint-role declarations double as decorators
(@drto.dynamics(m, m.t)); the styles mix freely per component (feature
002 shows both in full). The pieces are the
object types of a dynamic optimization or simulation problem:
| DRTO object type | Pyomo object type | Declaration | What it is |
|---|---|---|---|
| Time set | Set | horizon(m.t) |
The moving-horizon dimension. A pyomo.dae ContinuousSet, the root handle for the horizon. Dynamics are declared separately, below. |
| State | Variable | state(m.z, ...) |
A state variable. In a dynamic model it carries a DerivativeVar, with its dynamics declared separately below. In a steady-state model it need not have one. |
| Dynamics | Constraint | dynamics(m.ode_con) |
Equality ODE; one side is the state's DerivativeVar (dz/dt). |
| Control | Variable | control(m.u, ..., profile=...) |
A manipulated input, the decision variable. The profile flag sets its parameterization (piecewise-constant, ...) via pyomo-cvp, over the declared time set. |
| Tracking stage cost | Constraint | tracking_stage_cost(m.tracking_stage_con) |
Per-sample equality for the setpoint-tracking running cost; drto sums its cost var over the samples in the objective. |
| Economic stage cost | Constraint | economic_stage_cost(m.economic_stage_con) |
Per-sample equality for the economic running cost; its single-point steady-state form is the RTO objective. |
| Tracking terminal cost | Constraint | tracking_terminal_cost(m.tracking_terminal_con) |
Equality defining the terminal tracking cost; its scalar cost var goes in the objective. |
| Initial condition | Constraint | initial_condition(m.init_con) |
Equality anchoring the initial state; the state at t0 on one side, the feedback Param on the other. |
| Terminal constraint | Constraint | terminal_constraint(m.terminal_con) |
Constraint on the states at the final time; the terminal set the final state must lie in. |
| Steady-state target | Parameter | steady_state(m.z, m.z_ss) |
The state setpoint the tracking costs drive toward, paired with its state so the steady-state/RTO solve knows which target to populate. |
| Steady-state control target | Parameter | steady_state_control(m.u, m.u_ss) |
The control setpoint the tracking costs drive toward, paired with its control the same way. |
Conventions drto enforces on those constraints: the cost and initial-condition constraints are equalities with the scalar the declaration is about (the cost term, or the anchored state) on one side, either orientation; a stage cost applies at every sample point except the final one, where only the terminal cost applies; a terminal constraint may reference only states at the final time, which is what separates it from a path constraint. The objective is drto's own: it sums the declared cost terms that are live in the current mode, so a mode drops a term just by leaving out its constraint.
One modeling practice worth following: leave cost variables unbounded. The
defining equality already fixes each cost value (a sum of squares is
nonnegative without being told), and a NonNegativeReals bound puts the
optimum exactly on the bound wherever the cost vanishes, at settled samples
on long horizons or through an infinite-horizon tail at equilibrium, which
drags interior-point solvers (measured on the Hicks example at N = 50: 43
ipopt iterations bounded, 6 unbounded, identical solutions).
One thing you never declare, because it already lives in the model: the path constraints are the state variables' own upper and lower bounds.
The vocabulary is the optimal-control literature's own (stage cost, terminal cost, terminal constraint), so a model reads the way the theory does. The other modes reuse the same model: simulation drops the cost, and estimation swaps the initial condition for a soft arrival cost and adds the estimation pieces below.
Declaring an estimation problem
Estimation is the dual half (moving horizon estimation, the planned follow-on), and it declares its own pieces the same way. MHE fits the model to a moving window of measurements, so the free variables and the objective terms differ, but the conventions carry over: each declaration tags a Var, a Constraint, or a Param, and drto assembles the estimation objective from the live cost terms.
| DRTO object type | Pyomo object type | Declaration | What it is |
|---|---|---|---|
| Estimated parameter | Variable | estimated_parameter(m.theta, ...) |
Unknown model parameters to estimate, constant over the window. Shared with steady-state data reconciliation. |
| Disturbance | Variable | disturbance(m.w, ...) |
Process-noise variables (dz/dt = f + w) the estimator adjusts to fit the data, penalized by their covariance. |
| Measurement | Parameter | measurement(m.y_meas, ...) |
The measured values in the estimation cost residuals; a mutable Param drto refreshes each step. |
| Estimation stage cost | Constraint | estimation_stage_cost(m.est_stage_con) |
Equality defining the running estimation cost: measurement residual plus process-noise penalty over the window. |
| Estimation terminal cost | Constraint | estimation_terminal_cost(m.est_terminal_con) |
Equality for the current-time measurement residual (no process noise leads out of the last point). |
| Arrival cost | Constraint | arrival_cost(m.arrival_con) |
Equality for the soft prior on the window's initial state; its weight is updated by covariance propagation. |
The arrival cost is the soft dual of the control side's initial condition, and the estimation stage and terminal costs are the measurement-fitting counterparts of the tracking costs.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file drto-0.1.2.tar.gz.
File metadata
- Download URL: drto-0.1.2.tar.gz
- Upload date:
- Size: 742.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa1dd822d0bb473e6f7cc8b34a5bfa179e901be09f4d27b89b4b8f29a658b5b8
|
|
| MD5 |
b7b24fe3615d6f18b2f234ffc18ee6cc
|
|
| BLAKE2b-256 |
448e399a60433b2b54008597a79b0a06b3df77db359859d1f033c74b964fb404
|
Provenance
The following attestation bundles were made for drto-0.1.2.tar.gz:
Publisher:
publish.yml on devin-griff/drto
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
drto-0.1.2.tar.gz -
Subject digest:
fa1dd822d0bb473e6f7cc8b34a5bfa179e901be09f4d27b89b4b8f29a658b5b8 - Sigstore transparency entry: 2193359605
- Sigstore integration time:
-
Permalink:
devin-griff/drto@2c65f1936080e63f7a6c334543487f899cd66c7e -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/devin-griff
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2c65f1936080e63f7a6c334543487f899cd66c7e -
Trigger Event:
push
-
Statement type:
File details
Details for the file drto-0.1.2-py3-none-any.whl.
File metadata
- Download URL: drto-0.1.2-py3-none-any.whl
- Upload date:
- Size: 28.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f93a3ffb79437c9b9939eeff6ffa3199ba49d42eec53798ee03d40367d82695
|
|
| MD5 |
b0bcd5c7ae26e374c8e34174af2aec50
|
|
| BLAKE2b-256 |
45266d50e35ccbfee0ad5e37735709fdcdbdd951a157e18abdd6cc77f323ef4d
|
Provenance
The following attestation bundles were made for drto-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on devin-griff/drto
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
drto-0.1.2-py3-none-any.whl -
Subject digest:
4f93a3ffb79437c9b9939eeff6ffa3199ba49d42eec53798ee03d40367d82695 - Sigstore transparency entry: 2193359612
- Sigstore integration time:
-
Permalink:
devin-griff/drto@2c65f1936080e63f7a6c334543487f899cd66c7e -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/devin-griff
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2c65f1936080e63f7a6c334543487f899cd66c7e -
Trigger Event:
push
-
Statement type: