The infinite horizon on the PrOMMiS mixer-settler#
Rare earth elements are recovered from an acidic leach solution by liquid-liquid extraction: the aqueous leachate is contacted with an organic solvent, kerosene carrying the extractant DEHPA, which pulls the rare earth ions across the phase boundary and leaves the impurities behind. The model is the mixer-settler solvent extraction unit from PrOMMiS, posed directly on PrOMMiS’s chemistry: one extraction stage, with the feed composition of a coal-refuse leachate carrying nine rare earths (Sc, Y, La, Ce, Pr, Nd, Sm, Gd, Dy) at milligram-per-liter levels under percent-level Al, Ca, and Fe impurities in sulfuric acid.
This page solves one infinite-horizon problem on that stage: a single sampling element of finite horizon with the terminal segment carrying the rest of the transient. The setpoint comes from the model’s own steady state, reached by initializing block by block and solving from there.
The process#
One stage is three vessels. The two phases meet only in the mixer, a stirred tank both phases share; each effluent then passes through its own settler, modeled as four well-mixed tanks in series, the disengagement lag between the mixer and the outlets carried as a residence-time distribution.
+--------------+ aqueous settler
aqueous feed ----->| |--aq-->[T1]-[T2]-[T3]-[T4]--> raffinate
(leachate) | mixer |
organic feed ----->| (2 phases) |--org->[T1]-[T2]-[T3]-[T4]--> loaded solvent
(kerosene+DEHPA) | | organic settler
+--------------+
In the mixer the metals distribute between the phases through the DEHPA complexation equilibria, metal ions trading places with protons, so extraction pushes acid back into the aqueous phase. The aqueous effluent (the raffinate) carries what was not extracted out through its settler cascade; the organic effluent (the loaded solvent) carries the rare earth complexes out through the other. In a multi-stage train the organic stream runs backward through the stage sequence, making the train counter-current; this example runs one stage.
The dynamics#
Every equation the model solves, mixer first. For phase \(p\) (aqueous or organic) with volume fraction \(\theta_p\) of the vessel volume \(V\), species \(j\) with molar holdup \(n_j\) and mass concentration \(c_j\), and phase volumetric flows \(F_{in}\) and \(F\):
Inventories. The states are the amounts the reactions cannot change. Transfer moves a metal between phases without changing its total, so each element \(e\) carries one balance for its total across both phases, closed by flows alone:
Hydrogen, sulfur, and the extractant get the same treatment through their reaction invariants — extraction trades \(z_e\) protons per metal ion and binds \(z_e\) extractant molecules per complex, and the bisulfate dissociation trades within the acid system:
Water and chloride are inert and keep their plain holdup balances. Each holdup ties to its concentration and phase volume, \(n_j = V \theta_p c_j / M_j\).
The vessel and the withdrawal. The phases fill the tank, and they leave it in proportion to their fractions (the outlet flows \(F^{aq}\), \(F^{og}\)):
The second equation is a modeling choice, not conservation: it says the dispersion is drawn off uniformly. Through it the phase split tracks the flow ratio, so moving the two feeds apart re-partitions the tank; within this example’s control bounds the aqueous fraction can range from 0.375 to 0.625.
The solvents. Both bulk concentrations are constants by assumption:
With \(c_{H_2O}\) constant, the water holdup is \(V\,\theta_{aq}\,c_{H_2O}\): proportional to the phase fraction, which is why it is the inventory that remembers the split. The kerosene holdup is locked to the water holdup through the split, so its balance reduces to an algebraic row that determines the organic outlet flow.
The acid chemistry (aqueous, molar concentrations):
The metal transfer. Per element \(e\), the phases sit on the distribution equilibrium in molar concentrations:
with the correlation in pH and the extractant dosage \(d\) (volume percent) for the rare earths except scandium; Sc, Al, Ca, and Fe carry constant fitted coefficients. There is no rate law anywhere, and no transfer variable either: given each total, the equilibrium splits it between the phases algebraically at every instant. Extraction trades metal ions for protons, so the equilibria couple back into the acid chemistry through pH.
The settlers. Four well-mixed tanks in series per phase, transport only, each tank of volume \(A\,\Delta x\) fed by the one before it:
one balance per species per tank; the aqueous tanks also carry the dissociation, so hydrogen and sulfur ride their combinations there too.
Which inventories are states. The 129 states are the mixer’s twelve metal totals, its hydrogen, sulfur, and extractant combinations, its water and chloride holdups, and per settler tank the metals, chloride, and the hydrogen and sulfur combinations on the aqueous side, every species but kerosene on the organic side. Everything else — concentrations, per-phase holdups, flows, the phase split — is algebra the solver reconstructs at each instant.
The declared model#
models/prommis_sx_index_one.py writes the stage
directly in Pyomo, with PrOMMiS supplying the chemistry: the feed
compositions, molar masses, distribution correlations, dissociation
constant, and reaction stoichiometry are read out of PrOMMiS’s own
parameter and reaction packages at build time. Posing the balances on
the reaction invariants makes the model an index-one DAE — no
transfer extents, and nothing undetermined at the first time point.
The module declares the 129 states above, both feed flows as the
manipulated inputs (with their operating limits as bounds), and
additive zero-mean noise terms in the state balances as the declared
disturbances.
import pyomo.environ as pyo
import pyomo_pounce # registers the pounce solver with Pyomo
from pyomo.contrib.solver.common.factory import SolverFactory
import drto
from models.prommis_sx_index_one import build, F_AQ, F_OG
declared = build(N=5, h=0.1)
drto.info(declared)
| states: 129, controls: 2 | |
| horizon | time (ContinuousSet, 6 points) |
| states | nt_metal_La (free), nt_metal_Y (free), nt_metal_Pr (free), nt_metal_Ce (free), nt_metal_Nd (free), nt_metal_Sm (free), nt_metal_Gd (free), nt_metal_Dy (free), nt_metal_Al (free), nt_metal_Ca (free), nt_metal_Fe (free), nt_metal_Sc (free), nt_h (free), nt_s (free), nt_a (free), n_aq_H2O (free), n_aq_Cl (free), sn_aq_1_La (free), sn_aq_1_Y (free), sn_aq_1_Pr (free), sn_aq_1_Ce (free), sn_aq_1_Nd (free), sn_aq_1_Sm (free), sn_aq_1_Gd (free), sn_aq_1_Dy (free), sn_aq_1_Al (free), sn_aq_1_Ca (free), sn_aq_1_Fe (free), sn_aq_1_Sc (free), sn_aq_1_Cl (free), sn_aq_2_La (free), sn_aq_2_Y (free), sn_aq_2_Pr (free), sn_aq_2_Ce (free), sn_aq_2_Nd (free), sn_aq_2_Sm (free), sn_aq_2_Gd (free), sn_aq_2_Dy (free), sn_aq_2_Al (free), sn_aq_2_Ca (free), sn_aq_2_Fe (free), sn_aq_2_Sc (free), sn_aq_2_Cl (free), sn_aq_3_La (free), sn_aq_3_Y (free), sn_aq_3_Pr (free), sn_aq_3_Ce (free), sn_aq_3_Nd (free), sn_aq_3_Sm (free), sn_aq_3_Gd (free), sn_aq_3_Dy (free), sn_aq_3_Al (free), sn_aq_3_Ca (free), sn_aq_3_Fe (free), sn_aq_3_Sc (free), sn_aq_3_Cl (free), sn_aq_4_La (free), sn_aq_4_Y (free), sn_aq_4_Pr (free), sn_aq_4_Ce (free), sn_aq_4_Nd (free), sn_aq_4_Sm (free), sn_aq_4_Gd (free), sn_aq_4_Dy (free), sn_aq_4_Al (free), sn_aq_4_Ca (free), sn_aq_4_Fe (free), sn_aq_4_Sc (free), sn_aq_4_Cl (free), snt_h_1 (free), snt_h_2 (free), snt_h_3 (free), snt_h_4 (free), snt_s_1 (free), snt_s_2 (free), snt_s_3 (free), snt_s_4 (free), sn_og_1_DEHPA (free), sn_og_1_Al_o (free), sn_og_1_Ca_o (free), sn_og_1_Fe_o (free), sn_og_1_Sc_o (free), sn_og_1_Y_o (free), sn_og_1_La_o (free), sn_og_1_Ce_o (free), sn_og_1_Pr_o (free), sn_og_1_Nd_o (free), sn_og_1_Sm_o (free), sn_og_1_Gd_o (free), sn_og_1_Dy_o (free), sn_og_2_DEHPA (free), sn_og_2_Al_o (free), sn_og_2_Ca_o (free), sn_og_2_Fe_o (free), sn_og_2_Sc_o (free), sn_og_2_Y_o (free), sn_og_2_La_o (free), sn_og_2_Ce_o (free), sn_og_2_Pr_o (free), sn_og_2_Nd_o (free), sn_og_2_Sm_o (free), sn_og_2_Gd_o (free), sn_og_2_Dy_o (free), sn_og_3_DEHPA (free), sn_og_3_Al_o (free), sn_og_3_Ca_o (free), sn_og_3_Fe_o (free), sn_og_3_Sc_o (free), sn_og_3_Y_o (free), sn_og_3_La_o (free), sn_og_3_Ce_o (free), sn_og_3_Pr_o (free), sn_og_3_Nd_o (free), sn_og_3_Sm_o (free), sn_og_3_Gd_o (free), sn_og_3_Dy_o (free), sn_og_4_DEHPA (free), sn_og_4_Al_o (free), sn_og_4_Ca_o (free), sn_og_4_Fe_o (free), sn_og_4_Sc_o (free), sn_og_4_Y_o (free), sn_og_4_La_o (free), sn_og_4_Ce_o (free), sn_og_4_Pr_o (free), sn_og_4_Nd_o (free), sn_og_4_Sm_o (free), sn_og_4_Gd_o (free), sn_og_4_Dy_o (free) |
| dynamics | dnt_metal[t,e] == (0.986*aq_feed[t] - F_aq[t]*c_aq[t,e])/138.905 + (0.000105*og_feed[t] - F_og[t]*c_og[t,La_o])/138.905 + w_metal[t,e] for t in time, e in E |
| dynamics | dnt_h[t] == 10.75*aq_feed[t] - F_aq[t]*c_aq[t,H] + (10000.0*aq_feed[t] - F_aq[t]*c_aq[t,HSO4])/97.0 - (3*((0.000105*og_feed[t] - F_og[t]*c_og[t,La_o])/138.905) + 3*((2.179e-05*og_feed[t] - F_og[t]*c_og[t,Y_o])/88.905) + 3*((3.711e-05*og_feed[t] - F_og[t]*c_og[t,Pr_o])/140.907) + 3*((0.00031*og_feed[t] - F_og[t]*c_og[t,Ce_o])/140.11599999999999) + 3*((0.000165*og_feed[t] - F_og[t]*c_og[t,Nd_o])/144.24200000000002) + 3*((1.701e-05*og_feed[t] - F_og[t]*c_og[t,Sm_o])/150.35999999999999) + 3*((3.357e-05*og_feed[t] - F_og[t]*c_og[t,Gd_o])/157.25) + 3*((8.008e-06*og_feed[t] - F_og[t]*c_og[t,Dy_o])/162.5) + 3*((1.267e-05*og_feed[t] - F_og[t]*c_og[t,Al_o])/26.982) + 2*((2.684e-05*og_feed[t] - F_og[t]*c_og[t,Ca_o])/40.078) + 3*((2.873e-06*og_feed[t] - F_og[t]*c_og[t,Fe_o])/55.845) + 3*((1.734*og_feed[t] - F_og[t]*c_og[t,Sc_o])/44.946)) + w_h[t] for t in time |
| dynamics | dnt_s[t] == (100*aq_feed[t] - F_aq[t]*c_aq[t,SO4])/96.0 + (10000.0*aq_feed[t] - F_aq[t]*c_aq[t,HSO4])/97.0 + w_s[t] for t in time |
| dynamics | dnt_a[t] == 3*((0.000105*og_feed[t] - F_og[t]*c_og[t,La_o])/138.905) + 3*((2.179e-05*og_feed[t] - F_og[t]*c_og[t,Y_o])/88.905) + 3*((3.711e-05*og_feed[t] - F_og[t]*c_og[t,Pr_o])/140.907) + 3*((0.00031*og_feed[t] - F_og[t]*c_og[t,Ce_o])/140.11599999999999) + 3*((0.000165*og_feed[t] - F_og[t]*c_og[t,Nd_o])/144.24200000000002) + 3*((1.701e-05*og_feed[t] - F_og[t]*c_og[t,Sm_o])/150.35999999999999) + 3*((3.357e-05*og_feed[t] - F_og[t]*c_og[t,Gd_o])/157.25) + 3*((8.008e-06*og_feed[t] - F_og[t]*c_og[t,Dy_o])/162.5) + 3*((1.267e-05*og_feed[t] - F_og[t]*c_og[t,Al_o])/26.982) + 2*((2.684e-05*og_feed[t] - F_og[t]*c_og[t,Ca_o])/40.078) + 3*((2.873e-06*og_feed[t] - F_og[t]*c_og[t,Fe_o])/55.845) + 3*((1.734*og_feed[t] - F_og[t]*c_og[t,Sc_o])/44.946) + (48790.0*og_feed[t] - F_og[t]*c_og[t,DEHPA])/322.43100000000004 + w_a[t] for t in time |
| dynamics | dn_aq[t,Cl] == (1e-07*aq_feed[t] - F_aq[t]*c_aq[t,Cl])/35.452999999999996 + w_cl[t] for t in time |
| dynamics | dn_aq[t,H2O] == (1000000.0*aq_feed[t] - F_aq[t]*c_aq[t,H2O])/18.0 + w_h2o[t] for t in time |
| dynamics | dsn_aq[t,i,e] == F_aq[t]*(c_aq[t,e] - sc_aq[t,i,e])/138.905 + w_sa[t,i,e] for t in time, i in TK, e in OrderedScalarSet |
| dynamics | dsnt_h[t,i] == F_aq[t]*(c_aq[t,H] - sc_aq[t,i,H]) + F_aq[t]*(c_aq[t,HSO4] - sc_aq[t,i,HSO4])/97.0 + w_sh[t,i] for t in time, i in TK |
| dynamics | dsnt_s[t,i] == F_aq[t]*(c_aq[t,SO4] - sc_aq[t,i,SO4])/96.0 + F_aq[t]*(c_aq[t,HSO4] - sc_aq[t,i,HSO4])/97.0 + w_ss[t,i] for t in time, i in TK |
| dynamics | dsn_og[t,i,j] == F_og[t]*(c_og[t,j] - sc_og[t,i,j])/322.43100000000004 + w_so[t,i,j] for t in time, i in TK, j in OG |
| controls | og_feed (piecewise_constant, free), aq_feed (piecewise_constant, free) |
| tracking stage cost | cost[t] == ((nt_metal[t,'Sc'] - ss_metal_Sc)/scale_n)**2 + ((nt_metal[t,'Y'] - ss_metal_Y)/scale_n)**2 + ((nt_metal[t,'La'] - ss_metal_La)/scale_n)**2 + ((nt_metal[t,'Ce'] - ss_metal_Ce)/scale_n)**2 + ((nt_metal[t,'Pr'] - ss_metal_Pr)/scale_n)**2 + ((nt_metal[t,'Nd'] - ss_metal_Nd)/scale_n)**2 + ((nt_metal[t,'Sm'] - ss_metal_Sm)/scale_n)**2 + ((nt_metal[t,'Gd'] - ss_metal_Gd)/scale_n)**2 + ((nt_metal[t,'Dy'] - ss_metal_Dy)/scale_n)**2 + ((og_feed[t] - ss_fog)/scale_F)**2 + ((aq_feed[t] - ss_faq)/scale_F)**2 + ((nt_metal[t,'Al'] - ss_metal_Al)/scale_naq)**2 + ((nt_metal[t,'Ca'] - ss_metal_Ca)/scale_naq)**2 + ((nt_metal[t,'Fe'] - ss_metal_Fe)/scale_naq)**2 + ((nt_h[t] - ss_h)/scale_naq)**2 + ((nt_s[t] - ss_s)/scale_naq)**2 + ((nt_a[t] - ss_a)/scale_naq)**2 + ((n_aq[t,'H2O'] - ss_h2o)/scale_naq)**2 + ((n_aq[t,'Cl'] - ss_cl)/scale_naq)**2 + ((sn_aq[t,1,'La'] - ss_sa1_La)/scale_sett)**2 + ((sn_aq[t,1,'Y'] - ss_sa1_Y)/scale_sett)**2 + ((sn_aq[t,1,'Pr'] - ss_sa1_Pr)/scale_sett)**2 + ((sn_aq[t,1,'Ce'] - ss_sa1_Ce)/scale_sett)**2 + ((sn_aq[t,1,'Nd'] - ss_sa1_Nd)/scale_sett)**2 + ((sn_aq[t,1,'Sm'] - ss_sa1_Sm)/scale_sett)**2 + ((sn_aq[t,1,'Gd'] - ss_sa1_Gd)/scale_sett)**2 + ((sn_aq[t,1,'Dy'] - ss_sa1_Dy)/scale_sett)**2 + ((sn_aq[t,1,'Al'] - ss_sa1_Al)/scale_sett)**2 + ((sn_aq[t,1,'Ca'] - ss_sa1_Ca)/scale_sett)**2 + ((sn_aq[t,1,'Fe'] - ss_sa1_Fe)/scale_sett)**2 + ((sn_aq[t,1,'Sc'] - ss_sa1_Sc)/scale_sett)**2 + ((sn_aq[t,1,'Cl'] - ss_sa1_Cl)/scale_sett)**2 + ((sn_aq[t,2,'La'] - ss_sa2_La)/scale_sett)**2 + ((sn_aq[t,2,'Y'] - ss_sa2_Y)/scale_sett)**2 + ((sn_aq[t,2,'Pr'] - ss_sa2_Pr)/scale_sett)**2 + ((sn_aq[t,2,'Ce'] - ss_sa2_Ce)/scale_sett)**2 + ((sn_aq[t,2,'Nd'] - ss_sa2_Nd)/scale_sett)**2 + ((sn_aq[t,2,'Sm'] - ss_sa2_Sm)/scale_sett)**2 + ((sn_aq[t,2,'Gd'] - ss_sa2_Gd)/scale_sett)**2 + ((sn_aq[t,2,'Dy'] - ss_sa2_Dy)/scale_sett)**2 + ((sn_aq[t,2,'Al'] - ss_sa2_Al)/scale_sett)**2 + ((sn_aq[t,2,'Ca'] - ss_sa2_Ca)/scale_sett)**2 + ((sn_aq[t,2,'Fe'] - ss_sa2_Fe)/scale_sett)**2 + ((sn_aq[t,2,'Sc'] - ss_sa2_Sc)/scale_sett)**2 + ((sn_aq[t,2,'Cl'] - ss_sa2_Cl)/scale_sett)**2 + ((sn_aq[t,3,'La'] - ss_sa3_La)/scale_sett)**2 + ((sn_aq[t,3,'Y'] - ss_sa3_Y)/scale_sett)**2 + ((sn_aq[t,3,'Pr'] - ss_sa3_Pr)/scale_sett)**2 + ((sn_aq[t,3,'Ce'] - ss_sa3_Ce)/scale_sett)**2 + ((sn_aq[t,3,'Nd'] - ss_sa3_Nd)/scale_sett)**2 + ((sn_aq[t,3,'Sm'] - ss_sa3_Sm)/scale_sett)**2 + ((sn_aq[t,3,'Gd'] - ss_sa3_Gd)/scale_sett)**2 + ((sn_aq[t,3,'Dy'] - ss_sa3_Dy)/scale_sett)**2 + ((sn_aq[t,3,'Al'] - ss_sa3_Al)/scale_sett)**2 + ((sn_aq[t,3,'Ca'] - ss_sa3_Ca)/scale_sett)**2 + ((sn_aq[t,3,'Fe'] - ss_sa3_Fe)/scale_sett)**2 + ((sn_aq[t,3,'Sc'] - ss_sa3_Sc)/scale_sett)**2 + ((sn_aq[t,3,'Cl'] - ss_sa3_Cl)/scale_sett)**2 + ((sn_aq[t,4,'La'] - ss_sa4_La)/scale_sett)**2 + ((sn_aq[t,4,'Y'] - ss_sa4_Y)/scale_sett)**2 + ((sn_aq[t,4,'Pr'] - ss_sa4_Pr)/scale_sett)**2 + ((sn_aq[t,4,'Ce'] - ss_sa4_Ce)/scale_sett)**2 + ((sn_aq[t,4,'Nd'] - ss_sa4_Nd)/scale_sett)**2 + ((sn_aq[t,4,'Sm'] - ss_sa4_Sm)/scale_sett)**2 + ((sn_aq[t,4,'Gd'] - ss_sa4_Gd)/scale_sett)**2 + ((sn_aq[t,4,'Dy'] - ss_sa4_Dy)/scale_sett)**2 + ((sn_aq[t,4,'Al'] - ss_sa4_Al)/scale_sett)**2 + ((sn_aq[t,4,'Ca'] - ss_sa4_Ca)/scale_sett)**2 + ((sn_aq[t,4,'Fe'] - ss_sa4_Fe)/scale_sett)**2 + ((sn_aq[t,4,'Sc'] - ss_sa4_Sc)/scale_sett)**2 + ((sn_aq[t,4,'Cl'] - ss_sa4_Cl)/scale_sett)**2 + ((snt_h[t,1] - ss_sh1)/scale_sett)**2 + ((snt_h[t,2] - ss_sh2)/scale_sett)**2 + ((snt_h[t,3] - ss_sh3)/scale_sett)**2 + ((snt_h[t,4] - ss_sh4)/scale_sett)**2 + ((snt_s[t,1] - ss_ss1)/scale_sett)**2 + ((snt_s[t,2] - ss_ss2)/scale_sett)**2 + ((snt_s[t,3] - ss_ss3)/scale_sett)**2 + ((snt_s[t,4] - ss_ss4)/scale_sett)**2 + ((sn_og[t,1,'DEHPA'] - ss_so1_DEHPA)/scale_sett)**2 + ((sn_og[t,1,'Al_o'] - ss_so1_Al_o)/scale_sett)**2 + ((sn_og[t,1,'Ca_o'] - ss_so1_Ca_o)/scale_sett)**2 + ((sn_og[t,1,'Fe_o'] - ss_so1_Fe_o)/scale_sett)**2 + ((sn_og[t,1,'Sc_o'] - ss_so1_Sc_o)/scale_sett)**2 + ((sn_og[t,1,'Y_o'] - ss_so1_Y_o)/scale_sett)**2 + ((sn_og[t,1,'La_o'] - ss_so1_La_o)/scale_sett)**2 + ((sn_og[t,1,'Ce_o'] - ss_so1_Ce_o)/scale_sett)**2 + ((sn_og[t,1,'Pr_o'] - ss_so1_Pr_o)/scale_sett)**2 + ((sn_og[t,1,'Nd_o'] - ss_so1_Nd_o)/scale_sett)**2 + ((sn_og[t,1,'Sm_o'] - ss_so1_Sm_o)/scale_sett)**2 + ((sn_og[t,1,'Gd_o'] - ss_so1_Gd_o)/scale_sett)**2 + ((sn_og[t,1,'Dy_o'] - ss_so1_Dy_o)/scale_sett)**2 + ((sn_og[t,2,'DEHPA'] - ss_so2_DEHPA)/scale_sett)**2 + ((sn_og[t,2,'Al_o'] - ss_so2_Al_o)/scale_sett)**2 + ((sn_og[t,2,'Ca_o'] - ss_so2_Ca_o)/scale_sett)**2 + ((sn_og[t,2,'Fe_o'] - ss_so2_Fe_o)/scale_sett)**2 + ((sn_og[t,2,'Sc_o'] - ss_so2_Sc_o)/scale_sett)**2 + ((sn_og[t,2,'Y_o'] - ss_so2_Y_o)/scale_sett)**2 + ((sn_og[t,2,'La_o'] - ss_so2_La_o)/scale_sett)**2 + ((sn_og[t,2,'Ce_o'] - ss_so2_Ce_o)/scale_sett)**2 + ((sn_og[t,2,'Pr_o'] - ss_so2_Pr_o)/scale_sett)**2 + ((sn_og[t,2,'Nd_o'] - ss_so2_Nd_o)/scale_sett)**2 + ((sn_og[t,2,'Sm_o'] - ss_so2_Sm_o)/scale_sett)**2 + ((sn_og[t,2,'Gd_o'] - ss_so2_Gd_o)/scale_sett)**2 + ((sn_og[t,2,'Dy_o'] - ss_so2_Dy_o)/scale_sett)**2 + ((sn_og[t,3,'DEHPA'] - ss_so3_DEHPA)/scale_sett)**2 + ((sn_og[t,3,'Al_o'] - ss_so3_Al_o)/scale_sett)**2 + ((sn_og[t,3,'Ca_o'] - ss_so3_Ca_o)/scale_sett)**2 + ((sn_og[t,3,'Fe_o'] - ss_so3_Fe_o)/scale_sett)**2 + ((sn_og[t,3,'Sc_o'] - ss_so3_Sc_o)/scale_sett)**2 + ((sn_og[t,3,'Y_o'] - ss_so3_Y_o)/scale_sett)**2 + ((sn_og[t,3,'La_o'] - ss_so3_La_o)/scale_sett)**2 + ((sn_og[t,3,'Ce_o'] - ss_so3_Ce_o)/scale_sett)**2 + ((sn_og[t,3,'Pr_o'] - ss_so3_Pr_o)/scale_sett)**2 + ((sn_og[t,3,'Nd_o'] - ss_so3_Nd_o)/scale_sett)**2 + ((sn_og[t,3,'Sm_o'] - ss_so3_Sm_o)/scale_sett)**2 + ((sn_og[t,3,'Gd_o'] - ss_so3_Gd_o)/scale_sett)**2 + ((sn_og[t,3,'Dy_o'] - ss_so3_Dy_o)/scale_sett)**2 + ((sn_og[t,4,'DEHPA'] - ss_so4_DEHPA)/scale_sett)**2 + ((sn_og[t,4,'Al_o'] - ss_so4_Al_o)/scale_sett)**2 + ((sn_og[t,4,'Ca_o'] - ss_so4_Ca_o)/scale_sett)**2 + ((sn_og[t,4,'Fe_o'] - ss_so4_Fe_o)/scale_sett)**2 + ((sn_og[t,4,'Sc_o'] - ss_so4_Sc_o)/scale_sett)**2 + ((sn_og[t,4,'Y_o'] - ss_so4_Y_o)/scale_sett)**2 + ((sn_og[t,4,'La_o'] - ss_so4_La_o)/scale_sett)**2 + ((sn_og[t,4,'Ce_o'] - ss_so4_Ce_o)/scale_sett)**2 + ((sn_og[t,4,'Pr_o'] - ss_so4_Pr_o)/scale_sett)**2 + ((sn_og[t,4,'Nd_o'] - ss_so4_Nd_o)/scale_sett)**2 + ((sn_og[t,4,'Sm_o'] - ss_so4_Sm_o)/scale_sett)**2 + ((sn_og[t,4,'Gd_o'] - ss_so4_Gd_o)/scale_sett)**2 + ((sn_og[t,4,'Dy_o'] - ss_so4_Dy_o)/scale_sett)**2 for t in sorted(time)[:-1] |
| terminal cost | term == ((nt_metal[0.5,Sc] - ss_metal_Sc)/scale_n)**2 + ((nt_metal[0.5,Y] - ss_metal_Y)/scale_n)**2 + ((nt_metal[0.5,La] - ss_metal_La)/scale_n)**2 + ((nt_metal[0.5,Ce] - ss_metal_Ce)/scale_n)**2 + ((nt_metal[0.5,Pr] - ss_metal_Pr)/scale_n)**2 + ((nt_metal[0.5,Nd] - ss_metal_Nd)/scale_n)**2 + ((nt_metal[0.5,Sm] - ss_metal_Sm)/scale_n)**2 + ((nt_metal[0.5,Gd] - ss_metal_Gd)/scale_n)**2 + ((nt_metal[0.5,Dy] - ss_metal_Dy)/scale_n)**2 + ((nt_metal[0.5,Al] - ss_metal_Al)/scale_naq)**2 + ((nt_metal[0.5,Ca] - ss_metal_Ca)/scale_naq)**2 + ((nt_metal[0.5,Fe] - ss_metal_Fe)/scale_naq)**2 + ((nt_h[0.5] - ss_h)/scale_naq)**2 + ((nt_s[0.5] - ss_s)/scale_naq)**2 + ((nt_a[0.5] - ss_a)/scale_naq)**2 + ((n_aq[0.5,H2O] - ss_h2o)/scale_naq)**2 + ((n_aq[0.5,Cl] - ss_cl)/scale_naq)**2 + ((sn_aq[0.5,1,La] - ss_sa1_La)/scale_sett)**2 + ((sn_aq[0.5,1,Y] - ss_sa1_Y)/scale_sett)**2 + ((sn_aq[0.5,1,Pr] - ss_sa1_Pr)/scale_sett)**2 + ((sn_aq[0.5,1,Ce] - ss_sa1_Ce)/scale_sett)**2 + ((sn_aq[0.5,1,Nd] - ss_sa1_Nd)/scale_sett)**2 + ((sn_aq[0.5,1,Sm] - ss_sa1_Sm)/scale_sett)**2 + ((sn_aq[0.5,1,Gd] - ss_sa1_Gd)/scale_sett)**2 + ((sn_aq[0.5,1,Dy] - ss_sa1_Dy)/scale_sett)**2 + ((sn_aq[0.5,1,Al] - ss_sa1_Al)/scale_sett)**2 + ((sn_aq[0.5,1,Ca] - ss_sa1_Ca)/scale_sett)**2 + ((sn_aq[0.5,1,Fe] - ss_sa1_Fe)/scale_sett)**2 + ((sn_aq[0.5,1,Sc] - ss_sa1_Sc)/scale_sett)**2 + ((sn_aq[0.5,1,Cl] - ss_sa1_Cl)/scale_sett)**2 + ((sn_aq[0.5,2,La] - ss_sa2_La)/scale_sett)**2 + ((sn_aq[0.5,2,Y] - ss_sa2_Y)/scale_sett)**2 + ((sn_aq[0.5,2,Pr] - ss_sa2_Pr)/scale_sett)**2 + ((sn_aq[0.5,2,Ce] - ss_sa2_Ce)/scale_sett)**2 + ((sn_aq[0.5,2,Nd] - ss_sa2_Nd)/scale_sett)**2 + ((sn_aq[0.5,2,Sm] - ss_sa2_Sm)/scale_sett)**2 + ((sn_aq[0.5,2,Gd] - ss_sa2_Gd)/scale_sett)**2 + ((sn_aq[0.5,2,Dy] - ss_sa2_Dy)/scale_sett)**2 + ((sn_aq[0.5,2,Al] - ss_sa2_Al)/scale_sett)**2 + ((sn_aq[0.5,2,Ca] - ss_sa2_Ca)/scale_sett)**2 + ((sn_aq[0.5,2,Fe] - ss_sa2_Fe)/scale_sett)**2 + ((sn_aq[0.5,2,Sc] - ss_sa2_Sc)/scale_sett)**2 + ((sn_aq[0.5,2,Cl] - ss_sa2_Cl)/scale_sett)**2 + ((sn_aq[0.5,3,La] - ss_sa3_La)/scale_sett)**2 + ((sn_aq[0.5,3,Y] - ss_sa3_Y)/scale_sett)**2 + ((sn_aq[0.5,3,Pr] - ss_sa3_Pr)/scale_sett)**2 + ((sn_aq[0.5,3,Ce] - ss_sa3_Ce)/scale_sett)**2 + ((sn_aq[0.5,3,Nd] - ss_sa3_Nd)/scale_sett)**2 + ((sn_aq[0.5,3,Sm] - ss_sa3_Sm)/scale_sett)**2 + ((sn_aq[0.5,3,Gd] - ss_sa3_Gd)/scale_sett)**2 + ((sn_aq[0.5,3,Dy] - ss_sa3_Dy)/scale_sett)**2 + ((sn_aq[0.5,3,Al] - ss_sa3_Al)/scale_sett)**2 + ((sn_aq[0.5,3,Ca] - ss_sa3_Ca)/scale_sett)**2 + ((sn_aq[0.5,3,Fe] - ss_sa3_Fe)/scale_sett)**2 + ((sn_aq[0.5,3,Sc] - ss_sa3_Sc)/scale_sett)**2 + ((sn_aq[0.5,3,Cl] - ss_sa3_Cl)/scale_sett)**2 + ((sn_aq[0.5,4,La] - ss_sa4_La)/scale_sett)**2 + ((sn_aq[0.5,4,Y] - ss_sa4_Y)/scale_sett)**2 + ((sn_aq[0.5,4,Pr] - ss_sa4_Pr)/scale_sett)**2 + ((sn_aq[0.5,4,Ce] - ss_sa4_Ce)/scale_sett)**2 + ((sn_aq[0.5,4,Nd] - ss_sa4_Nd)/scale_sett)**2 + ((sn_aq[0.5,4,Sm] - ss_sa4_Sm)/scale_sett)**2 + ((sn_aq[0.5,4,Gd] - ss_sa4_Gd)/scale_sett)**2 + ((sn_aq[0.5,4,Dy] - ss_sa4_Dy)/scale_sett)**2 + ((sn_aq[0.5,4,Al] - ss_sa4_Al)/scale_sett)**2 + ((sn_aq[0.5,4,Ca] - ss_sa4_Ca)/scale_sett)**2 + ((sn_aq[0.5,4,Fe] - ss_sa4_Fe)/scale_sett)**2 + ((sn_aq[0.5,4,Sc] - ss_sa4_Sc)/scale_sett)**2 + ((sn_aq[0.5,4,Cl] - ss_sa4_Cl)/scale_sett)**2 + ((snt_h[0.5,1] - ss_sh1)/scale_sett)**2 + ((snt_h[0.5,2] - ss_sh2)/scale_sett)**2 + ((snt_h[0.5,3] - ss_sh3)/scale_sett)**2 + ((snt_h[0.5,4] - ss_sh4)/scale_sett)**2 + ((snt_s[0.5,1] - ss_ss1)/scale_sett)**2 + ((snt_s[0.5,2] - ss_ss2)/scale_sett)**2 + ((snt_s[0.5,3] - ss_ss3)/scale_sett)**2 + ((snt_s[0.5,4] - ss_ss4)/scale_sett)**2 + ((sn_og[0.5,1,DEHPA] - ss_so1_DEHPA)/scale_sett)**2 + ((sn_og[0.5,1,Al_o] - ss_so1_Al_o)/scale_sett)**2 + ((sn_og[0.5,1,Ca_o] - ss_so1_Ca_o)/scale_sett)**2 + ((sn_og[0.5,1,Fe_o] - ss_so1_Fe_o)/scale_sett)**2 + ((sn_og[0.5,1,Sc_o] - ss_so1_Sc_o)/scale_sett)**2 + ((sn_og[0.5,1,Y_o] - ss_so1_Y_o)/scale_sett)**2 + ((sn_og[0.5,1,La_o] - ss_so1_La_o)/scale_sett)**2 + ((sn_og[0.5,1,Ce_o] - ss_so1_Ce_o)/scale_sett)**2 + ((sn_og[0.5,1,Pr_o] - ss_so1_Pr_o)/scale_sett)**2 + ((sn_og[0.5,1,Nd_o] - ss_so1_Nd_o)/scale_sett)**2 + ((sn_og[0.5,1,Sm_o] - ss_so1_Sm_o)/scale_sett)**2 + ((sn_og[0.5,1,Gd_o] - ss_so1_Gd_o)/scale_sett)**2 + ((sn_og[0.5,1,Dy_o] - ss_so1_Dy_o)/scale_sett)**2 + ((sn_og[0.5,2,DEHPA] - ss_so2_DEHPA)/scale_sett)**2 + ((sn_og[0.5,2,Al_o] - ss_so2_Al_o)/scale_sett)**2 + ((sn_og[0.5,2,Ca_o] - ss_so2_Ca_o)/scale_sett)**2 + ((sn_og[0.5,2,Fe_o] - ss_so2_Fe_o)/scale_sett)**2 + ((sn_og[0.5,2,Sc_o] - ss_so2_Sc_o)/scale_sett)**2 + ((sn_og[0.5,2,Y_o] - ss_so2_Y_o)/scale_sett)**2 + ((sn_og[0.5,2,La_o] - ss_so2_La_o)/scale_sett)**2 + ((sn_og[0.5,2,Ce_o] - ss_so2_Ce_o)/scale_sett)**2 + ((sn_og[0.5,2,Pr_o] - ss_so2_Pr_o)/scale_sett)**2 + ((sn_og[0.5,2,Nd_o] - ss_so2_Nd_o)/scale_sett)**2 + ((sn_og[0.5,2,Sm_o] - ss_so2_Sm_o)/scale_sett)**2 + ((sn_og[0.5,2,Gd_o] - ss_so2_Gd_o)/scale_sett)**2 + ((sn_og[0.5,2,Dy_o] - ss_so2_Dy_o)/scale_sett)**2 + ((sn_og[0.5,3,DEHPA] - ss_so3_DEHPA)/scale_sett)**2 + ((sn_og[0.5,3,Al_o] - ss_so3_Al_o)/scale_sett)**2 + ((sn_og[0.5,3,Ca_o] - ss_so3_Ca_o)/scale_sett)**2 + ((sn_og[0.5,3,Fe_o] - ss_so3_Fe_o)/scale_sett)**2 + ((sn_og[0.5,3,Sc_o] - ss_so3_Sc_o)/scale_sett)**2 + ((sn_og[0.5,3,Y_o] - ss_so3_Y_o)/scale_sett)**2 + ((sn_og[0.5,3,La_o] - ss_so3_La_o)/scale_sett)**2 + ((sn_og[0.5,3,Ce_o] - ss_so3_Ce_o)/scale_sett)**2 + ((sn_og[0.5,3,Pr_o] - ss_so3_Pr_o)/scale_sett)**2 + ((sn_og[0.5,3,Nd_o] - ss_so3_Nd_o)/scale_sett)**2 + ((sn_og[0.5,3,Sm_o] - ss_so3_Sm_o)/scale_sett)**2 + ((sn_og[0.5,3,Gd_o] - ss_so3_Gd_o)/scale_sett)**2 + ((sn_og[0.5,3,Dy_o] - ss_so3_Dy_o)/scale_sett)**2 + ((sn_og[0.5,4,DEHPA] - ss_so4_DEHPA)/scale_sett)**2 + ((sn_og[0.5,4,Al_o] - ss_so4_Al_o)/scale_sett)**2 + ((sn_og[0.5,4,Ca_o] - ss_so4_Ca_o)/scale_sett)**2 + ((sn_og[0.5,4,Fe_o] - ss_so4_Fe_o)/scale_sett)**2 + ((sn_og[0.5,4,Sc_o] - ss_so4_Sc_o)/scale_sett)**2 + ((sn_og[0.5,4,Y_o] - ss_so4_Y_o)/scale_sett)**2 + ((sn_og[0.5,4,La_o] - ss_so4_La_o)/scale_sett)**2 + ((sn_og[0.5,4,Ce_o] - ss_so4_Ce_o)/scale_sett)**2 + ((sn_og[0.5,4,Pr_o] - ss_so4_Pr_o)/scale_sett)**2 + ((sn_og[0.5,4,Nd_o] - ss_so4_Nd_o)/scale_sett)**2 + ((sn_og[0.5,4,Sm_o] - ss_so4_Sm_o)/scale_sett)**2 + ((sn_og[0.5,4,Gd_o] - ss_so4_Gd_o)/scale_sett)**2 + ((sn_og[0.5,4,Dy_o] - ss_so4_Dy_o)/scale_sett)**2 |
| initial conditions | ic_metal[e] == nt_metal[0.0,e] for e in OrderedScalarSet |
| initial conditions | nt_h[0.0] == ic_h |
| initial conditions | nt_s[0.0] == ic_s |
| initial conditions | nt_a[0.0] == ic_a |
| initial conditions | n_aq[0.0,H2O] == ic_h2o |
| initial conditions | n_aq[0.0,Cl] == ic_cl |
| initial conditions | ic_sa[i,j] == sn_aq[0.0,i,j] for i in OrderedScalarSet, j in OrderedScalarSet |
| initial conditions | ic_sh[i] == snt_h[0.0,i] for i in OrderedScalarSet |
| initial conditions | ic_ss[i] == snt_s[0.0,i] for i in OrderedScalarSet |
| initial conditions | ic_so[i,j] == sn_og[0.0,i,j] for i in OrderedScalarSet, j in OrderedScalarSet |
| steady-state targets | ss_metal_La (of nt_metal_La), ss_metal_Y (of nt_metal_Y), ss_metal_Pr (of nt_metal_Pr), ss_metal_Ce (of nt_metal_Ce), ss_metal_Nd (of nt_metal_Nd), ss_metal_Sm (of nt_metal_Sm), ss_metal_Gd (of nt_metal_Gd), ss_metal_Dy (of nt_metal_Dy), ss_metal_Al (of nt_metal_Al), ss_metal_Ca (of nt_metal_Ca), ss_metal_Fe (of nt_metal_Fe), ss_metal_Sc (of nt_metal_Sc), ss_h (of nt_h), ss_s (of nt_s), ss_a (of nt_a), ss_h2o (of n_aq_H2O), ss_cl (of n_aq_Cl), ss_sa1_La (of sn_aq_1_La), ss_sa1_Y (of sn_aq_1_Y), ss_sa1_Pr (of sn_aq_1_Pr), ss_sa1_Ce (of sn_aq_1_Ce), ss_sa1_Nd (of sn_aq_1_Nd), ss_sa1_Sm (of sn_aq_1_Sm), ss_sa1_Gd (of sn_aq_1_Gd), ss_sa1_Dy (of sn_aq_1_Dy), ss_sa1_Al (of sn_aq_1_Al), ss_sa1_Ca (of sn_aq_1_Ca), ss_sa1_Fe (of sn_aq_1_Fe), ss_sa1_Sc (of sn_aq_1_Sc), ss_sa1_Cl (of sn_aq_1_Cl), ss_sh1 (of snt_h_1), ss_ss1 (of snt_s_1), ss_so1_DEHPA (of sn_og_1_DEHPA), ss_so1_Al_o (of sn_og_1_Al_o), ss_so1_Ca_o (of sn_og_1_Ca_o), ss_so1_Fe_o (of sn_og_1_Fe_o), ss_so1_Sc_o (of sn_og_1_Sc_o), ss_so1_Y_o (of sn_og_1_Y_o), ss_so1_La_o (of sn_og_1_La_o), ss_so1_Ce_o (of sn_og_1_Ce_o), ss_so1_Pr_o (of sn_og_1_Pr_o), ss_so1_Nd_o (of sn_og_1_Nd_o), ss_so1_Sm_o (of sn_og_1_Sm_o), ss_so1_Gd_o (of sn_og_1_Gd_o), ss_so1_Dy_o (of sn_og_1_Dy_o), ss_sa2_La (of sn_aq_2_La), ss_sa2_Y (of sn_aq_2_Y), ss_sa2_Pr (of sn_aq_2_Pr), ss_sa2_Ce (of sn_aq_2_Ce), ss_sa2_Nd (of sn_aq_2_Nd), ss_sa2_Sm (of sn_aq_2_Sm), ss_sa2_Gd (of sn_aq_2_Gd), ss_sa2_Dy (of sn_aq_2_Dy), ss_sa2_Al (of sn_aq_2_Al), ss_sa2_Ca (of sn_aq_2_Ca), ss_sa2_Fe (of sn_aq_2_Fe), ss_sa2_Sc (of sn_aq_2_Sc), ss_sa2_Cl (of sn_aq_2_Cl), ss_sh2 (of snt_h_2), ss_ss2 (of snt_s_2), ss_so2_DEHPA (of sn_og_2_DEHPA), ss_so2_Al_o (of sn_og_2_Al_o), ss_so2_Ca_o (of sn_og_2_Ca_o), ss_so2_Fe_o (of sn_og_2_Fe_o), ss_so2_Sc_o (of sn_og_2_Sc_o), ss_so2_Y_o (of sn_og_2_Y_o), ss_so2_La_o (of sn_og_2_La_o), ss_so2_Ce_o (of sn_og_2_Ce_o), ss_so2_Pr_o (of sn_og_2_Pr_o), ss_so2_Nd_o (of sn_og_2_Nd_o), ss_so2_Sm_o (of sn_og_2_Sm_o), ss_so2_Gd_o (of sn_og_2_Gd_o), ss_so2_Dy_o (of sn_og_2_Dy_o), ss_sa3_La (of sn_aq_3_La), ss_sa3_Y (of sn_aq_3_Y), ss_sa3_Pr (of sn_aq_3_Pr), ss_sa3_Ce (of sn_aq_3_Ce), ss_sa3_Nd (of sn_aq_3_Nd), ss_sa3_Sm (of sn_aq_3_Sm), ss_sa3_Gd (of sn_aq_3_Gd), ss_sa3_Dy (of sn_aq_3_Dy), ss_sa3_Al (of sn_aq_3_Al), ss_sa3_Ca (of sn_aq_3_Ca), ss_sa3_Fe (of sn_aq_3_Fe), ss_sa3_Sc (of sn_aq_3_Sc), ss_sa3_Cl (of sn_aq_3_Cl), ss_sh3 (of snt_h_3), ss_ss3 (of snt_s_3), ss_so3_DEHPA (of sn_og_3_DEHPA), ss_so3_Al_o (of sn_og_3_Al_o), ss_so3_Ca_o (of sn_og_3_Ca_o), ss_so3_Fe_o (of sn_og_3_Fe_o), ss_so3_Sc_o (of sn_og_3_Sc_o), ss_so3_Y_o (of sn_og_3_Y_o), ss_so3_La_o (of sn_og_3_La_o), ss_so3_Ce_o (of sn_og_3_Ce_o), ss_so3_Pr_o (of sn_og_3_Pr_o), ss_so3_Nd_o (of sn_og_3_Nd_o), ss_so3_Sm_o (of sn_og_3_Sm_o), ss_so3_Gd_o (of sn_og_3_Gd_o), ss_so3_Dy_o (of sn_og_3_Dy_o), ss_sa4_La (of sn_aq_4_La), ss_sa4_Y (of sn_aq_4_Y), ss_sa4_Pr (of sn_aq_4_Pr), ss_sa4_Ce (of sn_aq_4_Ce), ss_sa4_Nd (of sn_aq_4_Nd), ss_sa4_Sm (of sn_aq_4_Sm), ss_sa4_Gd (of sn_aq_4_Gd), ss_sa4_Dy (of sn_aq_4_Dy), ss_sa4_Al (of sn_aq_4_Al), ss_sa4_Ca (of sn_aq_4_Ca), ss_sa4_Fe (of sn_aq_4_Fe), ss_sa4_Sc (of sn_aq_4_Sc), ss_sa4_Cl (of sn_aq_4_Cl), ss_sh4 (of snt_h_4), ss_ss4 (of snt_s_4), ss_so4_DEHPA (of sn_og_4_DEHPA), ss_so4_Al_o (of sn_og_4_Al_o), ss_so4_Ca_o (of sn_og_4_Ca_o), ss_so4_Fe_o (of sn_og_4_Fe_o), ss_so4_Sc_o (of sn_og_4_Sc_o), ss_so4_Y_o (of sn_og_4_Y_o), ss_so4_La_o (of sn_og_4_La_o), ss_so4_Ce_o (of sn_og_4_Ce_o), ss_so4_Pr_o (of sn_og_4_Pr_o), ss_so4_Nd_o (of sn_og_4_Nd_o), ss_so4_Sm_o (of sn_og_4_Sm_o), ss_so4_Gd_o (of sn_og_4_Gd_o), ss_so4_Dy_o (of sn_og_4_Dy_o) |
| steady-state control targets | ss_fog (of og_feed), ss_faq (of aq_feed) |
| disturbances | w_metal (piecewise_constant), w_h (piecewise_constant), w_s (piecewise_constant), w_a (piecewise_constant), w_h2o (piecewise_constant), w_cl (piecewise_constant), w_sa (piecewise_constant), w_sh (piecewise_constant), w_ss (piecewise_constant), w_so (piecewise_constant) |
The setpoint#
The operating point comes from the model itself, in three steps.
drto.steady_state_simulation reduces a clone to the fixed-input
equilibrium: time collapses through drto.dynamic_to_steady_state, every
accumulation is pinned at zero, the two feeds are fixed at their nominal
rates, the tracking costs and terminal constraint leave, and a constant
zero objective goes in. What remains is the square problem whose solution
is the equilibrium at those inputs.
drto.initialize_steady_state fills it block by block, ordering the
equations by what determines what and solving each group in turn, so
every group starts from values the preceding ones produced. The chemistry
spans twelve orders of magnitude in concentration, so a solve from the
build’s crude guesses has nowhere to start.
The system is then solved from that point, and the tracking targets and
the initial condition are read off the solution through the
declarations: each steady_state pairing names a state and the Param
holding its setpoint, and each initial-condition constraint names a state
member and the Param a loop overwrites. The dynamic model keeps its own
values; the cold start fills them in the next cell.
# reduce to the fixed-input equilibrium: the controls are held, the
# costs and terminal constraint leave, and the zero objective goes in
sm = pyo.TransformationFactory("drto.steady_state_simulation").create_using(
declared, controls={declared.og_feed: F_OG, declared.aq_feed: F_AQ})
# initialize
print(drto.initialize_steady_state(sm))
# solve
res = SolverFactory("pounce").solve(sm, tee=True)
print("steady solve:", res.termination_condition.name)
reg, reg_s = drto.info(declared), drto.info(sm)
t0 = declared.time.first()
# each steady_state pairing names a state and the Param holding its
# setpoint, and the reduced model's records line up by declaration order
steady, setpoint = {}, {}
for kind in ("steady_state", "steady_state_control"):
for here, there in zip(reg.declarations(kind), reg_s.declarations(kind)):
v = there["of"]
value = pyo.value(next(iter(v.values())) if v.is_indexed() else v)
here["component"].set_value(value)
setpoint[here["component"].name] = value
steady[id(here["of"][t0])] = value
# each initial-condition constraint equates a state member with the Param
# a loop overwrites: start the run at the operating point
for con in reg.components("initial_condition"):
for cd in (con.values() if con.is_indexed() else (con,)):
lhs, rhs = cd.expr.args
param, state = (rhs, lhs) if rhs.is_parameter_type() else (lhs, rhs)
param.set_value(steady[id(state)])
setpoint[param.name] = steady[id(state)]
print()
print(f"aqueous fraction {pyo.value(sm.th_aq):.4f}, "
f"pH {pyo.value(sm.pH):.4f}, "
f"Sc total {pyo.value(declared.ss_metal_Sc):.6e} mol")
WARNING: Loading a SolverResults object with a warning status into
model.name="unknown";
- termination condition: maxIterations
- message from solver: POUNCE 0.11.0\x3a MaximumIterationsExceeded
pyomo-pounce initialize (fill -> repair -> block-solve)
decisions held: 0
values filled : 0
projection : maxIterations
warning: projection ended maxIterations; continuing with the unrepaired point
pyomo-pounce block_initialize
decisions fixed : 0
system square : True
blocks solved : 295 (285 by Newton 1x1, 10 subsystem solves)
vars initialized : 344
left untouched : 0 underdetermined, 0 overdetermined
block outcomes : 294 initialized, 1 fallback, 0 failed, 0 skipped
diagnostic: 25x25 block at 'molar[H]' is structurally square but numerically near-singular (rcond 3.61e-09 < 1.00e-08); routed to the regularized least-squares fallback
[79] 25x25 at 'molar[H]': fallback, rcond=3.61e-09
********************************************************************************
#### ### / # /# #/ #### #####
# # # # /# #/ ## / # #
#### # #/ # / # #/# # ####
# # / # /# # /## # #
# ##/ #/# #/ # #### #####
********************************************************************************
This program contains POUNCE, a pure-Rust interior-point optimization solver
for nonlinear, conic, and global problems (its NLP core is ported from Ipopt).
Released under the Eclipse Public License (EPL) — drop-in compatible with Ipopt.
For more information visit https://github.com/jkitchin/pounce
********************************************************************************
This is POUNCE version 0.11.0, running with linear solver FERAL.
Reading C:\Users\Devin\AppData\Local\Temp\tmpaob94m2_\unknown6qr8l5v1.nl...
Parsed 195 vars, 195 cons, jac_nnz=517, h_nnz=47 in 0.01s
Problem class: NLP. Selected solver: NLP filter line-search interior-point (pounce-nlp) [solver_selection=auto].
Number of nonzeros in equality constraint Jacobian...: 517
Number of nonzeros in inequality constraint Jacobian.: 0
Number of nonzeros in Lagrangian Hessian.............: 47
Total number of variables............................: 195
variables with only lower bounds: 141
variables with lower and upper bounds: 1
variables with only upper bounds: 0
Total number of equality constraints.................: 195
Total number of inequality constraints...............: 0
inequality constraints with only lower bounds: 0
inequality constraints with lower and upper bounds: 0
inequality constraints with only upper bounds: 0
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 0.0000000e+00 5.97e+02 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 0.0000000e+00 2.68e+02 3.11e+01 -1.0 3.61e+00 - 8.05e-02 5.50e-01h 1
2 0.0000000e+00 2.68e+00 3.08e+02 -1.0 6.00e-01 - 9.90e-01 9.90e-01h 1
3 0.0000000e+00 2.03e-02 9.94e+01 -1.0 2.57e-01 - 9.90e-01 9.92e-01h 1
4 0.0000000e+00 5.26e-06 2.23e+00 -1.0 4.79e-03 - 1.00e+00 1.00e+00h 1
5 0.0000000e+00 1.89e-10 0.00e+00 -3.8 2.31e-04 - 1.00e+00 1.00e+00h 1
Number of Iterations....: 5
(scaled) (unscaled)
Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00
Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00
Constraint violation....: 1.8879485605069468e-10 1.8879485605069468e-10
Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00
Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00
Overall NLP error.......: 1.8879485605069468e-10 1.8879485605069468e-10
Number of objective function evaluations = 6
Number of objective gradient evaluations = 1
Number of equality constraint evaluations = 6
Number of inequality constraint evaluations = 6
Number of equality constraint Jacobian evaluations = 6
Number of inequality constraint Jacobian evaluations = 6
Number of Lagrangian Hessian evaluations = 6
Total seconds in POUNCE = 0.008
EXIT: Optimal Solution Found.
POUNCE 0.11.0: Optimal Solution Found.
Status: Solve_Succeeded
pounce: wrote C:\Users\Devin\AppData\Local\Temp\tmpaob94m2_\unknown6qr8l5v1.sol
steady solve: convergenceCriteriaSatisfied
aqueous fraction 0.5000, pH 1.4098, Sc total 7.858319e-03 mol
The infinite-horizon problem#
An off-spec start: every inventory sits away from the operating point,
an upstream upset that just cleared. drto.dynamic_optimization takes
the builder rather than a model and reaches the controller in one call,
discretizing the horizon at one finite element per declared sample,
appending the terminal segment, and assembling the objective. The
builder fixes the feed compositions at the declared sample points, which
is all an undiscretized model has, and the call fixes the members
collocation adds to them. The setpoint read off above is written onto
that model, the initial condition is knocked off spec, the model is cold
started onto the targets, and the horizon is solved once, a single
sampling element of finite horizon with the infinite tail carrying the
rest of the transient.
# the horizon discretized, the terminal segment appended, and the
# objective assembled, from the builder in one call
m = drto.dynamic_optimization(
build, N=5, h=0.1,
infinite_horizon={
"nfe": 3, # finite elements on the terminal segment
"ncp": 5, # Gauss-Legendre points per element
"beta": 1.2, # tail overestimation factor, > 1
"gamma": "rule", # the mesh rule, tanh(gamma*dt) = tau_11;
# pass a number to override
"profile": "collocation", # segment control profile (pyomo-cvp)
},
)
for name, value in setpoint.items():
m.find_component(name).set_value(value)
# every state starts away from its steady inventory: each
# initial-condition constraint names a state member and the Param a
# loop overwrites, so the perturbation goes through the declarations
for con in drto.info(m).components("initial_condition"):
for cd in (con.values() if con.is_indexed() else (con,)):
lhs, rhs = cd.expr.args
param = rhs if rhs.is_parameter_type() else lhs
param.set_value(1.1 * pyo.value(param))
drto.cold_start_dynamic(m, profile="exponential", time_constant=.3)
res = SolverFactory("pounce").solve(m, tee=True, solver_options={"tol": 1e-6})
print(res.termination_condition.name)
********************************************************************************
#### ### / # /# #/ #### #####
# # # # /# #/ ## / # #
#### # #/ # / # #/# # ####
# # / # /# # /## # #
# ##/ #/# #/ # #### #####
********************************************************************************
This program contains POUNCE, a pure-Rust interior-point optimization solver
for nonlinear, conic, and global problems (its NLP core is ported from Ipopt).
Released under the Eclipse Public License (EPL) — drop-in compatible with Ipopt.
For more information visit https://github.com/jkitchin/pounce
********************************************************************************
This is POUNCE version 0.11.0, running with linear solver FERAL.
Number of nonzeros in equality constraint Jacobian...: 65008
Number of nonzeros in inequality constraint Jacobian.: 40
Number of nonzeros in Lagrangian Hessian.............: 8871
Total number of variables............................: 16088
variables with only lower bounds: 5311
variables with lower and upper bounds: 102
variables with only upper bounds: 0
Total number of equality constraints.................: 15919
Total number of inequality constraints...............: 8
inequality constraints with only lower bounds: 0
inequality constraints with lower and upper bounds: 8
inequality constraints with only upper bounds: 0
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 2.7312094e+03 3.19e+05 1.01e+02 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 2.6311769e+03 3.18e+05 1.01e+02 -1.0 8.93e+04 - 1.08e-04 1.25e-03f 1
2 2.6121710e+03 3.18e+05 1.01e+02 -1.0 8.90e+04 - 1.40e-03 2.47e-04h 1
3 2.1964859e+03 3.16e+05 1.01e+02 -1.0 8.86e+04 - 1.75e-03 5.95e-03f 1
4 1.7163096e+03 3.13e+05 1.05e+02 -1.0 8.60e+04 - 5.71e-03 1.20e-02f 1
5 1.6789172e+03 3.05e+05 1.10e+02 -1.0 8.58e+04 - 2.66e-03 2.39e-02h 1
6 3.9498549e+03 2.92e+05 1.67e+02 -1.0 1.11e+05 - 1.11e-02 4.45e-02h 1
7 4.0328310e+03 2.91e+05 1.67e+02 -1.0 9.70e+04 - 7.75e-03 1.35e-03h 1
8 4.4807154e+03 2.89e+05 1.69e+02 -1.0 8.13e+04 - 3.55e-03 8.82e-03h 1
9 7.7459354e+03 2.74e+05 3.04e+02 -1.0 8.08e+04 - 4.75e-03 5.14e-02h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
10 8.7805647e+03 2.69e+05 3.12e+02 -1.0 8.26e+04 - 1.86e-02 1.57e-02h 1
11 1.0006702e+04 2.64e+05 3.22e+02 -1.0 7.64e+04 - 1.23e-02 1.85e-02h 1
12 1.3266851e+04 2.52e+05 4.03e+02 -1.0 7.30e+04 - 9.73e-03 4.57e-02h 1
13 1.4223064e+04 2.49e+05 4.06e+02 -1.0 6.11e+04 - 7.79e-03 1.52e-02h 1
14 1.4742947e+04 2.46e+05 4.06e+02 -1.0 5.19e+04 - 2.04e-02 8.48e-03h 1
15 1.7738256e+04 2.32e+05 5.24e+02 -1.0 5.57e+04 - 7.71e-03 6.00e-02h 1
16 1.7756948e+04 2.31e+05 5.23e+02 -1.0 6.80e+04 - 2.61e-03 9.27e-04h 1
17 1.7758645e+04 2.31e+05 5.23e+02 -1.0 8.83e+04 - 1.19e-03 6.78e-04h 1
18 1.7755419e+04 2.31e+05 5.23e+02 -1.0 6.72e+04 - 2.14e-04 3.63e-04h 1
19 1.7744742e+04 2.31e+05 5.22e+02 -1.0 6.49e+04 - 6.50e-04 9.88e-04h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
20 1.7742929e+04 2.31e+05 5.22e+02 -1.0 2.42e+05 - 1.01e-04 1.16e-04h 1
21 1.7568960e+04 2.28e+05 5.16e+02 -1.0 4.68e+04 - 2.08e-04 1.10e-02f 1
22 1.7492484e+04 2.28e+05 5.14e+02 -1.0 9.97e+04 - 1.12e-02 3.42e-03f 1
23 1.7490570e+04 2.28e+05 5.14e+02 -1.0 1.41e+06 - 1.21e-04 7.82e-05h 1
24 1.7466777e+04 2.27e+05 5.13e+02 -1.0 2.89e+05 - 1.09e-04 9.15e-04h 1
25 1.3422878e+04 1.88e+05 1.17e+03 -1.0 2.39e+05 - 1.12e-03 1.74e-01f 1
26 1.0144545e+04 1.43e+05 3.72e+03 -1.0 2.43e+05 - 3.04e-02 2.36e-01f 1
27 9.6199715e+03 1.35e+05 3.50e+03 -1.0 3.10e+05 - 4.20e-02 5.96e-02f 1
28 8.6065319e+03 1.14e+05 3.02e+03 -1.0 6.68e+05 - 3.01e-02 1.52e-01f 1
29 8.5803695e+03 1.14e+05 3.01e+03 -1.0 1.86e+03 -4.0 8.76e-03 6.16e-03h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
30 8.5296238e+03 1.13e+05 2.98e+03 -1.0 3.30e+04 - 1.67e-03 8.20e-03h 1
31 8.3680301e+03 1.09e+05 2.88e+03 -1.0 5.03e+03 -4.5 3.10e-03 3.39e-02f 1
32 8.2555101e+03 1.06e+05 2.81e+03 -1.0 3.54e+03 -5.0 1.01e-01 2.37e-02h 1
33 5.5491086e+03 6.15e+04 9.66e+02 -1.0 7.22e+03 -5.4 1.43e-02 4.22e-01f 1
34 4.5829599e+03 3.98e+04 4.77e+02 -1.0 8.40e+03 -5.9 6.03e-02 3.53e-01f 1
35 3.7323827e+03 2.03e+04 5.07e+02 -1.0 1.28e+04 -6.4 6.38e-02 4.90e-01f 1
36 3.0279270e+03 1.08e+04 2.94e+02 -1.0 1.62e+04 -6.9 2.26e-01 4.67e-01f 1
37 1.9118417e+03 3.01e+03 7.77e+02 -1.0 2.68e+04 -7.3 8.37e-02 7.22e-01f 1
38 1.5739059e+03 2.11e+03 3.46e+03 -1.0 3.87e+04 - 4.36e-01 2.99e-01f 1
39 1.5413500e+03 2.03e+03 3.09e+05 -1.0 2.81e+04 - 2.29e-01 3.79e-02h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
40 9.2128771e+02 4.45e+02 8.92e+05 -1.0 4.97e+04 - 2.04e-01 7.81e-01f 1
41 8.8601504e+02 3.82e+02 1.81e+06 -1.0 2.62e+04 - 6.88e-01 1.43e-01h 1
42 7.0402069e+02 1.04e+02 4.11e+06 -1.0 1.97e+04 - 2.18e-02 7.28e-01h 1
43 7.5464988e+02 2.73e+00 1.60e+07 -1.0 4.31e+01 -2.4 1.95e-01 9.74e-01h 1
44 7.4464361e+02 3.79e+00 1.61e+07 -1.0 4.49e+01 -2.9 2.52e-03 7.64e-01f 1
45 7.4397867e+02 3.73e+00 1.58e+07 -1.0 1.86e+01 -1.5 9.86e-01 1.51e-02h 7
46 7.4398087e+02 3.72e+00 1.59e+07 -1.0 6.77e+02 -0.2 1.71e-04 3.81e-03f 3
47r 7.4398087e+01 3.82e-02 1.00e+03 -1.0 0.00e+00 1.1 0.00e+00 9.71e-07R 8
48r 7.4473650e+01 7.76e-03 1.17e+03 -1.0 6.26e+03 - 4.01e-01 2.59e-03f 1
48 7.4473650e+02 2.69e+00 5.76e+03 -1.0 3.88e+03 1.1 0.00e+00 9.71e-07R 8
49 5.9516642e+02 3.55e-01 1.46e+05 -1.0 1.79e+04 - 3.92e-01 9.89e-01H 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
50 5.3237890e+02 1.12e+01 1.15e+05 -1.0 1.75e+04 - 2.11e-01 8.85e-01f 1
51 4.1829835e+02 8.11e+00 4.23e+04 -1.0 1.08e+04 - 6.31e-01 4.99e-01h 1
52 3.2758381e+02 1.24e+01 8.77e+03 -1.0 9.29e+03 - 7.92e-01 7.38e-01f 1
53 3.1770423e+02 6.89e+00 1.78e+02 -1.0 7.41e+03 - 9.81e-01 1.00e+00f 1
54 3.3678945e+02 1.25e-01 9.98e+00 -1.0 1.06e+03 - 9.92e-01 1.00e+00h 1
55 9.2561856e+01 5.62e-01 4.07e+01 -2.5 3.54e+03 - 8.79e-01 9.59e-01f 1
56 8.3891827e+01 8.24e-03 1.83e+01 -2.5 2.15e+02 - 9.11e-01 1.00e+00h 1
57 8.3921335e+01 2.12e-03 1.87e+01 -2.5 3.65e+01 - 6.25e-01 1.00e+00f 1
58 8.3921361e+01 4.39e-05 1.30e-03 -2.5 2.06e+01 - 1.00e+00 1.00e+00f 1
59 7.7129660e+01 3.98e-04 4.24e+02 -5.7 8.99e+01 - 4.15e-01 9.30e-01f 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
60 7.6733412e+01 8.73e-05 9.70e+02 -5.7 1.61e+01 - 1.08e-01 7.89e-01f 1
61 7.6656032e+01 2.35e-05 1.11e+03 -5.7 7.42e+00 - 2.69e-01 7.35e-01f 1
62 7.6628769e+01 3.76e-06 1.77e+03 -5.7 3.64e+00 - 1.04e-01 1.00e+00f 1
63 7.6630821e+01 8.49e-07 2.79e+03 -5.7 1.05e+00 - 2.00e-01 1.00e+00H 1
64 7.6633074e+01 2.45e-07 2.14e+03 -5.7 3.26e+00 - 4.31e-01 7.45e-01H 1
65 7.6633154e+01 2.47e-07 6.03e+02 -5.7 7.02e+00 - 5.14e-01 1.56e-02f 7
66 7.6635506e+01 8.99e-07 6.88e+02 -5.7 9.30e+00 - 7.08e-01 1.00e+00H 1
67 7.6640197e+01 1.86e-07 1.47e+03 -5.7 2.03e+00 - 6.31e-02 1.00e+00h 1
68 7.6643295e+01 7.31e-07 6.22e-04 -5.7 8.18e+00 - 1.00e+00 1.00e+00H 1
69 7.6638446e+01 1.84e-07 1.75e+02 -7.0 8.50e-01 - 8.78e-01 9.72e-01h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
70 7.6638450e+01 1.84e-07 1.83e+03 -7.0 6.17e-01 - 1.00e+00 1.56e-02f 7
71 7.6638685e+01 1.85e-07 5.77e+00 -7.0 5.82e-01 - 8.09e-01 1.00e+00h 1
72 7.6638746e+01 1.86e-07 6.05e+02 -7.0 5.30e-01 - 6.78e-01 1.00e+00h 1
73 7.6638798e+01 1.86e-07 8.49e+02 -7.0 5.76e-01 - 6.57e-01 1.00e+00h 1
74 7.6638935e+01 1.86e-07 1.53e+03 -7.0 4.73e-01 - 4.37e-01 1.00e+00h 1
75 7.6639017e+01 1.86e-07 1.49e-04 -7.0 2.70e-01 - 1.00e+00 1.00e+00h 1
76 7.6638955e+01 1.86e-07 9.70e-05 -7.0 4.17e-01 - 1.00e+00 1.00e+00h 1
77 7.6638960e+01 1.86e-07 1.07e-04 -7.0 3.83e-01 - 1.00e+00 1.00e+00h 1
78 7.6638968e+01 1.84e-07 1.64e+03 -7.0 3.74e-01 - 1.09e-01 1.00e+00h 1
79 7.6638968e+01 1.84e-07 1.67e+03 -7.0 3.68e-01 - 4.34e-01 2.26e-04h 13
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
80 7.6638953e+01 1.64e-07 1.90e+03 -7.0 3.68e-01 - 2.43e-02 1.00e+00h 1
81 7.6638964e+01 1.58e-07 1.80e+03 -7.0 3.60e-01 - 5.16e-02 1.25e-01h 4
82 7.6638934e+01 1.76e-07 2.54e+03 -7.0 3.59e-01 - 2.21e-01 1.00e+00h 1
83 7.6638936e+01 1.71e-07 2.42e+03 -7.0 3.49e-01 - 5.62e-01 6.25e-02h 5
84 7.6638936e+01 1.69e-07 2.35e+03 -7.0 3.47e-01 - 7.92e-02 1.56e-02h 7
85 7.6638937e+01 1.69e-07 2.33e+03 -7.0 3.46e-01 - 7.14e-01 7.81e-03h 8
86 7.6638937e+01 1.69e-07 2.33e+03 -7.0 3.45e-01 - 1.04e-01 9.77e-04h 11
87 7.6638951e+01 1.48e-07 1.76e+03 -7.0 3.45e-01 - 2.42e-01 2.42e-01s 1
88 7.6638985e+01 1.24e-07 7.27e+02 -7.0 3.42e-01 - 5.88e-01 5.88e-01s 1
89 7.6639008e+01 1.19e-07 3.46e+02 -7.0 3.37e-01 - 5.24e-01 5.24e-01s 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
90 7.6639008e+01 1.12e-07 2.25e+02 -7.0 3.33e-01 - 3.48e-01 3.48e-01s 1
91 7.6639021e+01 1.01e-07 1.00e+02 -7.0 3.31e-01 - 5.55e-01 5.55e-01s 1
92 7.6639030e+01 1.01e-07 6.04e-05 -7.0 3.28e-01 - 1.00e+00 1.00e+00s 1
93 7.6639032e+01 1.02e-07 5.93e-05 -7.0 3.21e-01 - 1.00e+00 1.00e+00s 1
94 7.6639032e+01 1.02e-07 5.81e-05 -7.0 3.13e-01 - 1.00e+00 1.00e+00s 1
95 7.6639034e+01 1.02e-07 5.67e-05 -7.0 3.01e-01 - 1.00e+00 1.00e+00s 1
96 7.6639037e+01 1.02e-07 5.48e-05 -7.0 2.86e-01 - 1.00e+00 1.00e+00s 1
97 7.6639041e+01 1.02e-07 5.21e-05 -7.0 2.63e-01 - 1.00e+00 1.00e+00s 1
98r 7.6639041e+00 1.02e-07 1.00e+03 -7.0 0.00e+00 - 0.00e+00 0.00e+00R 0
99r 7.6639028e+00 1.79e-07 9.95e+02 -7.0 1.30e-02 -4.0 5.44e-03 4.60e-03f 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
100r 7.6639024e+00 2.29e-07 9.88e+02 -7.0 2.43e-02 -4.5 2.21e-02 6.26e-03f 1
101r 8.0603395e+00 2.53e-06 9.66e+02 -7.0 8.57e+00 - 2.19e-02 2.21e-02f 1
102r 1.0493871e+01 6.28e-06 9.30e+02 -7.0 8.31e+00 - 5.59e-02 3.79e-02h 1
103r 1.0554415e+01 5.67e-06 8.38e+02 -7.0 6.83e-02 -5.0 1.51e-01 9.84e-02h 1
104r 1.1357546e+02 4.72e-05 5.66e+02 -7.0 1.52e+01 - 3.23e-01 3.25e-01h 1
105r 2.4339620e+02 3.38e-05 4.69e+02 -7.0 1.05e+01 - 2.23e-01 2.90e-01h 1
106r 2.4619979e+02 2.16e-05 5.80e+02 -7.0 1.52e-01 -5.4 1.88e-01 3.61e-01h 1
107r 2.6619599e+02 1.06e-06 1.01e+03 -7.0 4.22e-01 -5.9 8.59e-02 1.00e+00h 1
108r 2.1484363e+02 9.68e-07 1.01e+03 -7.0 7.14e+00 -6.4 1.70e-02 9.79e-02f 1
109r 2.1377626e+02 9.67e-07 1.01e+03 -7.0 6.78e+01 -5.1 6.89e-04 6.44e-04f 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
110r 2.1087144e+02 9.67e-07 1.00e+03 -7.0 1.14e+02 -5.5 1.37e-03 6.26e-04f 1
111r 2.0689741e+02 9.64e-07 9.85e+02 -7.0 2.72e+01 -6.0 8.99e-03 2.66e-03f 1
112r 2.0677955e+02 9.62e-07 9.93e+02 -7.0 1.45e+01 -4.7 1.09e-03 1.60e-03f 1
113r 2.0676380e+02 9.62e-07 9.03e+02 -7.0 7.82e-01 -5.2 8.04e-02 9.71e-04h 1
114r 2.0505457e+02 8.71e-07 9.03e+02 -7.0 8.34e-01 -5.6 4.49e-03 9.45e-02h 1
115r 2.0339560e+02 8.57e-07 8.95e+02 -7.0 1.96e+01 -6.1 8.23e-03 1.62e-02h 1
116r 2.0327141e+02 8.56e-07 8.69e+02 -7.0 2.06e+01 -6.6 2.65e-02 1.10e-03h 1
117r 2.0323070e+02 8.48e-07 8.66e+02 -7.0 1.26e+00 -4.4 3.66e-03 1.01e-02h 1
118r 2.0323045e+02 8.48e-07 8.45e+02 -7.0 3.54e-01 -3.9 2.24e-02 1.52e-04h 1
119r 2.0305878e+02 8.29e-07 8.40e+02 -7.0 4.53e-01 -4.4 6.88e-03 2.24e-02f 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
120r 2.0305791e+02 8.29e-07 8.39e+02 -7.0 3.10e+00 -4.0 1.55e-03 5.31e-05h 1
121r 2.0305318e+02 8.27e-07 8.35e+02 -7.0 5.81e-01 -3.6 4.06e-03 1.65e-03f 1
122r 2.0117656e+02 8.23e-07 8.45e+02 -7.0 1.73e+01 - 9.40e-02 5.04e-03h 1
123r 1.9113130e+02 8.13e-07 7.48e+02 -7.0 1.78e+02 - 3.21e-04 1.27e-02h 1
124r 1.9067533e+02 8.12e-07 1.09e+03 -7.0 1.85e+01 - 2.91e-01 1.42e-03h 1
125r 9.5705517e+01 4.68e-06 6.15e+02 -7.0 5.94e+00 - 3.37e-02 3.91e-01h 1
126r 9.5704138e+01 4.63e-06 6.09e+02 -7.0 4.75e-02 -4.0 1.59e-02 1.05e-02h 1
127r 9.4475085e+01 4.59e-06 5.96e+02 -7.0 4.52e+00 - 8.02e-02 8.05e-03h 1
128r 6.9329039e+01 3.80e-06 6.71e+02 -7.0 2.91e+00 - 1.45e-02 1.81e-01h 1
129r 6.8670338e+01 3.77e-06 5.04e+02 -7.0 2.76e+00 - 3.02e-02 6.05e-03h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
130r 6.6798264e+01 3.71e-06 5.98e+02 -7.0 2.73e+00 - 6.91e-02 1.74e-02h 1
131r 5.6075948e+01 3.32e-06 5.58e+02 -7.0 2.67e+00 - 1.09e-01 1.07e-01h 1
132r 5.2850729e+01 3.20e-06 4.35e+02 -7.0 6.40e+00 - 1.59e-03 3.52e-02h 1
133r 5.2440832e+01 3.19e-06 4.09e+02 -7.0 1.26e+01 - 3.74e-02 4.41e-03h 1
134r 5.2440493e+01 3.10e-06 4.18e+02 -7.0 2.56e-01 -4.5 6.36e-03 2.77e-02h 1
135r 5.2246550e+01 3.10e-06 4.10e+02 -7.0 9.90e+01 - 6.32e-03 1.20e-03h 1
136r 5.2244445e+01 3.08e-06 4.08e+02 -7.0 2.20e+00 -5.0 6.54e-03 4.75e-03h 1
137r 5.1081405e+01 2.97e-06 4.07e+02 -7.0 4.63e+01 - 1.13e-02 1.44e-02h 1
138r 5.0262791e+01 2.94e-06 3.96e+02 -7.0 3.42e+01 - 1.74e-02 1.08e-02h 1
139r 4.9056624e+01 2.90e-06 7.58e+02 -7.0 2.67e+00 - 9.82e-02 1.58e-02h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
140r 4.3386963e+01 2.89e-06 6.87e+02 -7.0 2.95e+00 - 6.71e-03 7.79e-02h 1
141r 4.3003966e+01 3.05e-06 4.60e+02 -7.0 2.79e+00 - 4.27e-02 5.86e-03h 1
142r 3.5727329e+01 3.07e-06 4.14e+02 -7.0 2.92e+00 - 1.21e-01 1.19e-01h 1
143r 2.6959152e+01 3.49e-06 8.78e+02 -7.0 6.04e+00 - 4.44e-02 1.92e-01h 1
144r 2.6932793e+01 3.41e-06 8.77e+02 -7.0 1.47e+00 -5.5 1.26e-02 2.20e-02h 1
145r 2.6892789e+01 3.36e-06 7.99e+02 -7.0 3.35e+00 -5.9 5.08e-02 1.32e-02h 1
146r 2.6848542e+01 3.24e-06 7.76e+02 -7.0 1.47e+00 -5.5 3.31e-02 3.79e-02h 1
147r 2.6846390e+01 3.08e-06 7.41e+02 -7.0 1.61e-01 -4.2 4.70e-02 4.86e-02h 1
148r 2.6845844e+01 2.96e-06 7.03e+02 -7.0 4.98e-02 -3.8 4.71e-02 4.00e-02h 1
149r 2.6836843e+01 2.47e-06 7.35e+02 -7.0 7.11e-02 -4.2 3.46e-02 1.64e-01h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
150r 2.6821178e+01 2.24e-06 6.51e+02 -7.0 4.71e-02 -4.7 1.07e-01 9.39e-02h 1
151r 2.5183208e+01 3.31e-06 6.40e+02 -7.0 6.50e+00 - 1.04e-02 6.38e-02h 1
152r 2.0053704e+01 8.39e-06 8.28e+02 -7.0 5.53e+00 - 7.35e-02 2.00e-01h 1
153r 1.4425030e+01 5.98e-06 7.94e+02 -7.0 2.37e+00 - 2.30e-01 3.36e-01h 1
154r 1.4397743e+01 4.88e-06 8.21e+02 -7.0 9.67e-02 -5.2 2.66e-02 1.84e-01h 1
155r 1.4396069e+01 3.60e-06 5.13e+02 -7.0 3.43e-03 -3.9 3.17e-01 2.63e-01h 1
156r 1.2261358e+01 3.18e-06 4.10e+02 -7.0 2.54e+00 - 1.99e-01 1.94e-01h 1
157r 1.2258852e+01 2.43e-06 4.25e+02 -7.0 1.41e-02 -4.3 2.62e-02 2.35e-01h 1
158r 1.1540973e+01 9.02e-06 3.96e+02 -7.0 6.17e+00 - 6.29e-02 9.80e-02h 1
159r 1.0023447e+01 1.13e-04 3.33e+02 -7.0 2.99e+00 - 9.53e-02 3.15e-01h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
160r 1.0021798e+01 1.02e-04 2.45e+02 -7.0 2.29e-02 -4.8 2.14e-01 9.23e-02h 1
161r 1.0011881e+01 8.51e-05 2.17e+02 -7.0 4.58e-02 -5.3 1.16e-01 1.69e-01h 1
162r 8.8390596e+00 6.30e-05 2.14e+02 -7.0 2.17e+00 - 1.52e-01 3.02e-01h 1
163r 8.5005230e+00 5.39e-05 1.74e+02 -7.0 1.73e+00 - 1.82e-01 1.48e-01h 1
164r 8.5000050e+00 4.73e-05 1.57e+02 -7.0 9.26e-03 -4.9 1.02e-01 1.22e-01h 1
165r 8.5007704e+00 4.10e-05 1.41e+02 -7.0 7.07e-03 -3.5 5.68e-02 1.33e-01h 1
166r 8.3545290e+00 3.65e-05 1.62e+02 -7.0 1.41e+00 - 5.50e-02 1.16e-01h 1
167r 8.2008626e+00 3.10e-05 2.40e+02 -7.0 1.25e+00 - 3.28e-01 1.57e-01h 1
168r 8.2022939e+00 2.33e-05 2.11e+02 -7.0 4.29e-03 -4.0 1.22e-01 2.50e-01h 1
169r 8.0662303e+00 1.95e-05 1.91e+02 -7.0 1.55e+00 - 8.26e-02 1.83e-01h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
170r 7.8306744e+00 1.20e-05 4.16e+02 -7.0 8.89e-01 - 9.82e-02 5.49e-01h 1
171r 7.8341414e+00 6.76e-06 2.99e+02 -7.0 2.14e-03 -4.5 2.82e-01 4.36e-01h 1
172r 7.7107241e+00 6.42e-06 2.25e+02 -7.0 1.72e+00 - 2.54e-01 4.75e-01h 1
173r 7.7265978e+00 2.81e-08 4.67e+01 -7.0 2.85e-03 -5.0 8.08e-01 1.00e+00h 1
173 7.7265978e+01 4.07e-06 9.90e+01 -7.0 2.28e-01 - 0.00e+00 0.00e+00R 0
174 7.7042349e+01 4.06e-06 7.64e+01 -7.0 6.33e+01 - 9.96e-01 5.66e-03f 1
175 7.5893012e+01 5.58e+00 2.54e+02 -7.0 1.32e+03 - 1.49e-01 7.63e-01f 1
176 6.3597901e+01 5.39e+00 6.25e+01 -7.0 1.29e+03 - 7.01e-01 6.08e-01f 1
177 7.2055131e+01 1.82e+00 1.60e+01 -7.0 2.35e+02 - 9.41e-01 6.90e-01h 1
178 7.5625242e+01 4.00e-01 5.08e+00 -7.0 5.66e+01 - 8.32e-01 7.85e-01h 1
179 7.6463439e+01 7.00e-02 7.09e+00 -7.0 1.04e+01 - 9.50e-01 8.26e-01h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
180 7.6482271e+01 6.25e-02 2.51e+00 -7.0 1.73e+00 - 1.00e+00 1.07e-01h 4
181 7.6641391e+01 1.26e-05 6.92e-03 -7.0 1.20e+00 - 1.00e+00 1.00e+00h 1
182 7.6641472e+01 5.69e-10 2.03e-08 -7.0 8.69e-02 - 1.00e+00 1.00e+00h 1
Number of Iterations....: 182
(scaled) (unscaled)
Objective...............: 7.6641471661321878e+00 7.6641471661321873e+01
Dual infeasibility......: 2.0298143915093424e-08 2.0298143915093424e-07
Constraint violation....: 1.9623058733486687e-10 5.6934368330985308e-10
Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00
Complementarity.........: 9.5699194593778796e-08 9.5699194593778788e-07
Overall NLP error.......: 9.5699194593778796e-08 9.5699194593778788e-07
Number of objective function evaluations = 330
Number of objective gradient evaluations = 108
Number of equality constraint evaluations = 332
Number of inequality constraint evaluations = 332
Number of equality constraint Jacobian evaluations = 187
Number of inequality constraint Jacobian evaluations = 187
Number of Lagrangian Hessian evaluations = 183
Number of restoration iterations = 78 (in 2 calls)
Number of linear solver quality escalations = 13
Total seconds in POUNCE = 231.810
EXIT: Optimal Solution Found.
POUNCE 0.11.0: Optimal Solution Found.
convergenceCriteriaSatisfied
The planned trajectories#
The horizon drives the rare earth inventories from the upset back toward the operating point, the two feed flows doing the work. Filled markers are the finite horizon, open markers the terminal segment mapped back to real time, and the dotted lines the setpoints.
# six of the 129, at the two outlets where the separation shows:
# scandium and dysprosium in the loaded solvent leaving the
# organic settler, the same two in the raffinate leaving the
# aqueous settler, and the mixer's extractant and acid, which the
# transfer trades against
axes = drto.plot_states(m, states=[
"sn_og_4_Sc_o", "sn_aq_4_Sc",
"sn_og_4_Dy_o", "sn_aq_4_Dy",
"nt_a", "nt_h",
])
axes = drto.plot_controls(m)
axes = drto.plot_stage_cost(m)