Initializing from the steady state#

drto.initialize_steady_state seeds a model from its own equilibrium: one function, both declared shapes. A dynamic, discretized model is initialized from a throwaway reduced clone, the equilibrium solved by pyomo-pounce’s fill, project, block-solve pipeline with the declared controls as the decisions, then broadcast flat across the horizon. A steady-state model (authored steady, or a drto.dynamic_to_steady_state reduction) is initialized in place by the same pipeline. Both return a report worth printing.

The model is the Hicks-Ray CSTR from models/hicks.py. Requires the pounce extra (pip install drto[pounce]).

The dynamic path: a flat starting trajectory#

import pyomo.environ as pyo
import drto
from models.hicks import hicks

m = hicks(N=5)
pyo.TransformationFactory("dae.collocation").apply_to(m, wrt=m.t, nfe=5, ncp=3, scheme="LAGRANGE-RADAU")
report = drto.initialize_steady_state(m, controls={m.v1: 0.57828, m.v2: 0.49989})
print(report)
print()
print(f"zc across the grid: {min(pyo.value(m.zc[t]) for t in m.t):.5f} "
      f"to {max(pyo.value(m.zc[t]) for t in m.t):.5f} (flat at the equilibrium)")
drto initialize_steady_state (reduce a clone -> solve -> broadcast)
  broadcast: 5 variables across 16 grid points, 32 derivatives zeroed
  pyomo-pounce initialize (fill -> repair -> block-solve)
    decisions held: 2
    values filled : 2
    projection    : optimal
    pyomo-pounce block_initialize
      decisions fixed   : 0
      system square     : True
      blocks solved     : 2 (1 by Newton 1x1, 1 subsystem solves)
      vars initialized  : 3
      left untouched    : 0 underdetermined, 0 overdetermined

zc across the grid: 0.64160 to 0.64160 (flat at the equilibrium)

The steady path: a reduced model, initialized in place#

The same call on a model with no horizon runs the pipeline directly and the solved equilibrium lands in the variable values.

ss = pyo.TransformationFactory("drto.dynamic_to_steady_state").create_using(hicks(N=5))
report = drto.initialize_steady_state(ss)
print(report)
print()
print(f"equilibrium: zc = {pyo.value(ss.zc):.5f}, zt = {pyo.value(ss.zt):.5f}")
pyomo-pounce initialize (fill -> repair -> block-solve)
  decisions held: 2
  values filled : 2
  projection    : optimal
  pyomo-pounce block_initialize
    decisions fixed   : 0
    system square     : True
    blocks solved     : 2 (1 by Newton 1x1, 1 subsystem solves)
    vars initialized  : 3
    left untouched    : 0 underdetermined, 0 overdetermined

equilibrium: zc = 0.64160, zt = 0.53870