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:

\[\frac{dN_e}{dt} = F_{aq}^{in} c_e^{feed} - F_{aq}\, c_e^{aq} + F_{og}^{in} c_{e,o}^{feed} - F_{og}\, c_e^{og}, \qquad N_e = n_e^{aq} + n_e^{og}.\]

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:

\[N_H = n_H + n_{HSO_4} - \sum_e z_e\, n_e^{og}, \qquad N_S = n_{SO_4} + n_{HSO_4}, \qquad N_A = n_{DEHPA} + \sum_e z_e\, n_e^{og}.\]

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}\)):

\[\theta_{aq} + \theta_{og} = 1, \qquad \theta_{aq}\, F^{og} = \theta_{og}\, F^{aq}.\]

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:

\[c_{H_2O} = 10^6\ \mathrm{mg/L}, \qquad c_{Kerosene} = 8.2\times 10^5\ \mathrm{mg/L}.\]

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):

\[K_{a2}\, c_{HSO_4} = c_H\, c_{SO_4}, \qquad 10^{-\mathrm{pH}} = c_H\ [\mathrm{mol/L}].\]

The metal transfer. Per element \(e\), the phases sit on the distribution equilibrium in molar concentrations:

\[\frac{c_e^{og}}{M_{e,o}} = D_e\, \frac{c_e^{aq}}{M_e}, \qquad \log_{10} D_e = (m_{0,e} + m_{1,e}\,d)\,\mathrm{pH} + B_{0,e} + B_{1,e}\log_{10} d\]

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:

\[A\,\Delta x\,\frac{dc_i}{dt} = F\,(c_{i-1} - c_i),\]

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)
drto registry
states: 129, controls: 2
horizontime (ContinuousSet, 6 points)
statesnt_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)
dynamicsdnt_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
dynamicsdnt_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
dynamicsdnt_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
dynamicsdnt_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
dynamicsdn_aq[t,Cl] == (1e-07*aq_feed[t] - F_aq[t]*c_aq[t,Cl])/35.452999999999996 + w_cl[t] for t in time
dynamicsdn_aq[t,H2O] == (1000000.0*aq_feed[t] - F_aq[t]*c_aq[t,H2O])/18.0 + w_h2o[t] for t in time
dynamicsdsn_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
dynamicsdsnt_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
dynamicsdsnt_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
dynamicsdsn_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
controlsog_feed (piecewise_constant, free), aq_feed (piecewise_constant, free)
tracking stage costcost[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 costterm == ((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 conditionsic_metal[e] == nt_metal[0.0,e] for e in OrderedScalarSet
initial conditionsnt_h[0.0] == ic_h
initial conditionsnt_s[0.0] == ic_s
initial conditionsnt_a[0.0] == ic_a
initial conditionsn_aq[0.0,H2O] == ic_h2o
initial conditionsn_aq[0.0,Cl] == ic_cl
initial conditionsic_sa[i,j] == sn_aq[0.0,i,j] for i in OrderedScalarSet, j in OrderedScalarSet
initial conditionsic_sh[i] == snt_h[0.0,i] for i in OrderedScalarSet
initial conditionsic_ss[i] == snt_s[0.0,i] for i in OrderedScalarSet
initial conditionsic_so[i,j] == sn_og[0.0,i,j] for i in OrderedScalarSet, j in OrderedScalarSet
steady-state targetsss_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 targetsss_fog (of og_feed), ss_faq (of aq_feed)
disturbancesw_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)
transformations (none)

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",
])
../_images/8108b72f0e1132ca33011977731e7687c0d03636ca6661fc6bbe4f8cf2340c00.png
axes = drto.plot_controls(m)
../_images/5bd2b068de3c0ea705374cee9f87626196907f79154540982ae64228955e5464.png
axes = drto.plot_stage_cost(m)
../_images/7d1b99dc1195399eb18478469ca5279ccfdbfa643dcedf78c365a6f9802d012a.png