None
import sys
if "google.colab" in sys.modules:
!wget "https://raw.githubusercontent.com/ndcbe/CBE60499/main/notebooks/helper.py"
import helper
!pip install casadi
helper.install_idaes()
#helper.install_ipopt()
Chapter 8: Dynamic Optimization Introduction (Biegler, 2010)
Chapter 9: Sequential Methods (Biegler, 2010)
Chapter 10: Simultaneous Methods (Biegler, 2010)


Excerpts from Chapter 8 of Biegler (2010).


Pyomo.dae documentation:
Pendulum example:
CasADi (need to integrate DAEs):
pip install casadi. Warning: installing CasADi with conda will install an "okay" version of Ipopt. If you really want to install CasADi with conda, you'll likely need to add import idaes to your notebook to load the "good" version of Ipopt (Linux and Windows users).DAE simulation example:
## Load libraries
from pyomo.environ import *
from pyomo.dae import *
from pyomo.dae.simulator import Simulator
import matplotlib.pyplot as plt
import numpy as np
## Define function for plotting results
def plot_results(sim, tsim, profiles):
'''
time = list(m.t)
x = [value(m.x[t]) for t in m.t]
y = [value(m.y[t]) for t in m.t]
plt.plot(time, x, '-b', label='x')
plt.plot(time, y, '-r', label='y')
plt.xlabel('Time')
plt.ylabel('Position')
plt.legend(loc='best')
plt.show()
'''
plt.figure(1)
varorder = sim.get_variable_order()
algorder = sim.get_variable_order(vartype='algebraic')
# Create empty dictionary
results = {}
for idx1, v in enumerate(varorder):
i = idx1
v_ = str(v)
results[v_] = profiles[:, i]
plt.plot(tsim, results[v_], label=v)
for idx2, v in enumerate(algorder):
i = len(varorder) + idx2
v_ = str(v)
results[v_] = profiles[:, i]
plt.plot(tsim, results[v_], label=v)
plt.xlabel('t')
plt.legend(loc='best')
plt.show()
plt.figure(2)
x_ = results['x[{t}]']
y_ = results['y[{t}]']
plt.plot(tsim, np.sqrt(x_**2 + y_**2), '-b', label='length')
plt.xlabel('t')
plt.ylabel('$\sqrt{x^2 + y^2}$')
plt.show()
#return results
Consider the following model:
$$\begin{align} \frac{d x}{dt} &= u \\ \frac{d y}{dt} &= v \\ \frac{d u}{dt} &= -T x \\ \frac{d v}{dt} &= g - Ty \\ & x^2 + y^2 = 1 \end{align}$$This assumes mass and length of unity.
def create_model_index3():
m = ConcreteModel()
# Declare time
m.t = ContinuousSet(bounds=(0.0, 1))
# Declare parameter - acceleration due to gravity
m.g = Param(initialize=9.81) # m/s^2
# Declare variables indexed over time
m.x = Var(m.t) # horizontal position
m.y = Var(m.t) # vertical position
m.u = Var(m.t) # horizontal velocity
m.v = Var(m.t) # vertical velocity
m.T = Var(m.t) # tension
# Declare derivative variables
m.dx = DerivativeVar(m.x) # with respect to t is implied
m.dy = DerivativeVar(m.y)
m.du = DerivativeVar(m.u)
m.dv = DerivativeVar(m.v)
# Declare differential equations
def _dx_eqn(m, t):
return m.dx[t] == m.u[t]
m.dx_eqn = Constraint(m.t, rule=_dx_eqn)
def _dy_eqn(m, t):
return m.dy[t] == m.v[t]
m.dy_eqn = Constraint(m.t, rule=_dy_eqn)
def _du_eqn(m, t):
return m.du[t] == -m.T[t]*m.x[t]
m.du_eqn = Constraint(m.t, rule=_du_eqn)
def _dv_eqn(m, t):
return m.dv[t] == m.g -m.T[t]*m.y[t]
m.dv_eqn = Constraint(m.t, rule=_dv_eqn)
# Declare algebraic equation
def _alg_eqn(m, t):
return m.x[t]**2 + m.y[t]**2 == 1
m.alg_eqn = Constraint(m.t, rule=_alg_eqn)
# Specify initial conditions
m.x[0] = 0
m.y[0] = 1
m.u[0] = 1
m.v[0] = 0
m.T[0] = 1 + m.g
return m
index3 = create_model_index3()
# Specify integrator options
int_ops = {'print_stats':True,"abstol":1E-8,"reltol":1E-6}
# Solve DAEs
sim = Simulator(index3, package='casadi')
tsim, profiles = sim.simulate(numpoints=100, integrator='idas',integrator_options=int_ops)
# Plot solution
plot_results(sim, tsim, profiles)
psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed At t = 0 and h = 1.06624e-14, the corrector convergence failed repeatedly or with |h| = hmin.
--------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) <ipython-input-2-6df9f09067d7> in <module> 60 # Solve DAEs 61 sim = Simulator(index3, package='casadi') ---> 62 tsim, profiles = sim.simulate(numpoints=100, integrator='idas',integrator_options=int_ops) 63 64 # Plot solution /anaconda3/envs/spring2021/lib/python3.8/site-packages/pyomo/dae/simulator.py in simulate(self, numpoints, tstep, integrator, varying_inputs, initcon, integrator_options) 905 else: 906 tsim, profile = \ --> 907 self._simulate_with_casadi_no_inputs(initcon, tsim, 908 integrator, 909 integrator_options) /anaconda3/envs/spring2021/lib/python3.8/site-packages/pyomo/dae/simulator.py in _simulate_with_casadi_no_inputs(self, initcon, tsim, integrator, integrator_options) 967 integrator_options['output_t0'] = True 968 F = casadi.integrator('F', integrator, dae, integrator_options) --> 969 sol = F(x0=initcon) 970 profile = sol['xf'].full().T 971 /anaconda3/envs/spring2021/lib/python3.8/site-packages/casadi/casadi.py in __call__(self, *args, **kwargs) 13451 else: 13452 # Named inputs -> return dictionary > 13453 return self.call(kwargs) 13454 13455 def buffer(self): /anaconda3/envs/spring2021/lib/python3.8/site-packages/casadi/casadi.py in call(self, *args) 12322 12323 """ > 12324 return _casadi.Function_call(self, *args) 12325 12326 RuntimeError: .../casadi/interfaces/sundials/idas_interface.cpp:591: IDASolve returned "IDA_CONV_FAIL". Consult IDAS documentation.
Warning: If you run this notebook in Colab, you may get the following runtime error and your kernel may crash:


Why did the IDAS integrator in SUNDIALS fail? It is only meant for index 0 or 1 DAEs! Integrating high index DAEs is really hard!
def create_model_ode():
m = ConcreteModel()
# Declare time
m.t = ContinuousSet(bounds=(0.0, 5.0))
# Declare parameter - acceleration due to gravity
m.g = Param(initialize=9.81) # m/s^2
# Declare variables indexed over time
m.x = Var(m.t) # horizontal position
m.y = Var(m.t) # vertical position
m.u = Var(m.t) # horizontal velocity
m.v = Var(m.t) # vertical velocity
m.T = Var(m.t) # tension
# Declare derivative variables
m.dx = DerivativeVar(m.x) # with respect to t is implied
m.dy = DerivativeVar(m.y)
m.du = DerivativeVar(m.u)
m.dv = DerivativeVar(m.v)
m.dT = DerivativeVar(m.T)
# Declare differential equations
def _dx_eqn(m, t):
return m.dx[t] == m.u[t]
m.dx_eqn = Constraint(m.t, rule=_dx_eqn)
def _dy_eqn(m, t):
return m.dy[t] == m.v[t]
m.dy_eqn = Constraint(m.t, rule=_dy_eqn)
def _du_eqn(m, t):
return m.du[t] == -m.T[t]*m.x[t]
m.du_eqn = Constraint(m.t, rule=_du_eqn)
def _dv_eqn(m, t):
return m.dv[t] == m.g -m.T[t]*m.y[t]
m.dv_eqn = Constraint(m.t, rule=_dv_eqn)
def _dT_eqn(m, t):
return m.dT[t] == 4*m.T[t]*(m.x[t]*m.u[t] + m.y[t]*m.v[t]) + 3*m.g*m.v[t]
m.dT_eqn = Constraint(m.t, rule=_dT_eqn)
# Specify initial conditions
m.x[0] = 0
m.y[0] = 1
m.u[0] = 1
m.v[0] = 0
m.T[0] = 1 + m.g
return m
ode = create_model_ode()
# Specify integrator options
int_ops = {'print_stats':True,"abstol":1E-6,"reltol":1E-4}
# Solve DAEs
sim = Simulator(ode, package='casadi')
tsim, profiles = sim.simulate(numpoints=100, integrator='idas',integrator_options=int_ops)
# Plot solution
results = plot_results(sim, tsim, profiles)
FORWARD INTEGRATION: Number of steps taken by SUNDIALS: 167 Number of calls to the user’s f function: 242 Number of calls made to the linear solver setup function: 31 Number of error test failures: 7 Method order used on the last internal step: 5 Method order to be used on the next internal step: 5 Actual value of initial step size: 7.90569e-07 Step size taken on the last internal step: 0.00246466 Step size to be attempted on the next internal step: 0.00492933 Current internal time reached: 0.00492933 Number of nonlinear iterations performed: 240 Number of nonlinear convergence failures: 0
Discussion
(This reformulation is NOT unique... could have written $\frac{dx}{dt}$ and $\frac{du}{dt}$ instead.)
Consistent initial conditions:
def create_model_index1():
m = ConcreteModel()
# Declare time
m.t = ContinuousSet(bounds=(0, 5))
# Declare parameter - acceleration due to gravity
m.g = Param(initialize=9.81) # m/s^2
# Declare variables indexed over time
m.x = Var(m.t) # horizontal position
m.y = Var(m.t) # vertical position
m.u = Var(m.t) # horizontal velocity
m.v = Var(m.t) # vertical velocity
m.T = Var(m.t) # tension
# Declare derivative variables
m.dy = DerivativeVar(m.y)
m.dv = DerivativeVar(m.v)
# Declare differential equations
def _dy_eqn(m, t):
return m.dy[t] == m.v[t]
m.dy_eqn = Constraint(m.t, rule=_dy_eqn)
def _dv_eqn(m, t):
return m.dv[t] == m.g - m.T[t]*m.y[t]
m.dv_eqn = Constraint(m.t, rule=_dv_eqn)
# Declare algebraic equations
def _alg_eqn1(m, t):
return m.x[t]**2 + m.y[t]**2 == 1
m.alg_eqn1 = Constraint(m.t, rule=_alg_eqn1)
def _alg_eqn2(m, t):
return m.x[t]*m.u[t] + m.y[t]*m.v[t] == 0
m.alg_eqn2 = Constraint(m.t, rule=_alg_eqn2)
def _alg_eqn3(m, t):
return m.u[t]**2 + m.v[t]**2 - m.T[t]*(m.x[t]**2 + m.y[t]**2) + m.g*m.y[t] == 0
m.alg_eqn3 = Constraint(m.t, rule=_alg_eqn3)
# Specify initial conditions
m.x[0] = 0
m.y[0] = 1
m.u[0] = 1
m.v[0] = 0
m.T[0] = 1 + m.g
return m
def index1_check_constraints(m):
""" Check if the three constraints are feasible.
"""
print("Constraint 1:")
r1 = m.x[0]()**2 + m.y[0]()**2 - 1
print(r1)
print("\nConstraint 2:")
r2 = m.x[0]()*m.u[0]() + m.y[0]()*m.v[0]()
print(r2)
print("\nConstraint 3:")
r3 = m.u[0]()**2 + m.v[0]()**2 - m.T[0]() + m.g*m.y[0]()
print(r3)
index1 = create_model_index1()
# Check initial condition
index1_check_constraints(index1)
# Specify integrator options
int_ops = {'print_stats':True,"abstol":1E-6,"reltol":1E-4}
# Solve DAEs
sim = Simulator(index1, package='casadi')
tsim, profiles = sim.simulate(numpoints=100, integrator='idas',integrator_options=int_ops)
# tsim, profiles = sim.simulate(numpoints=100, integrator='collocation')
Constraint 1: 0 Constraint 2: 0 Constraint 3: 0.0
psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed The residual routine or the linear setup or solve routine had a recoverable error, but IDACalcIC was unable to recover.
--------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) <ipython-input-4-302b44bce341> in <module> 77 # Solve DAEs 78 sim = Simulator(index1, package='casadi') ---> 79 tsim, profiles = sim.simulate(numpoints=100, integrator='idas',integrator_options=int_ops) 80 # tsim, profiles = sim.simulate(numpoints=100, integrator='collocation') /anaconda3/envs/spring2021/lib/python3.8/site-packages/pyomo/dae/simulator.py in simulate(self, numpoints, tstep, integrator, varying_inputs, initcon, integrator_options) 905 else: 906 tsim, profile = \ --> 907 self._simulate_with_casadi_no_inputs(initcon, tsim, 908 integrator, 909 integrator_options) /anaconda3/envs/spring2021/lib/python3.8/site-packages/pyomo/dae/simulator.py in _simulate_with_casadi_no_inputs(self, initcon, tsim, integrator, integrator_options) 967 integrator_options['output_t0'] = True 968 F = casadi.integrator('F', integrator, dae, integrator_options) --> 969 sol = F(x0=initcon) 970 profile = sol['xf'].full().T 971 /anaconda3/envs/spring2021/lib/python3.8/site-packages/casadi/casadi.py in __call__(self, *args, **kwargs) 13451 else: 13452 # Named inputs -> return dictionary > 13453 return self.call(kwargs) 13454 13455 def buffer(self): /anaconda3/envs/spring2021/lib/python3.8/site-packages/casadi/casadi.py in call(self, *args) 12322 12323 """ > 12324 return _casadi.Function_call(self, *args) 12325 12326 RuntimeError: .../casadi/interfaces/sundials/idas_interface.cpp:591: IDACalcIC returned "IDA_NO_RECOVERY". Consult IDAS documentation.
What happened? Point singularity at $x=0$.
Let's try $x=0.1$ as the initial point.
index1_again = create_model_index1()
# Specify alternative initial conditions
small_number = 0.1
index1_again.x[0] = small_number
index1_again.y[0] = 1
index1_again.u[0] = 1
index1_again.v[0] = 0
index1_again.T[0] = 1 + index1_again.g
# Check initial condition
index1_check_constraints(index1_again)
# Solve DAEs
sim = Simulator(index1_again, package='casadi')
# Simulator
tsim, profiles = sim.simulate(numpoints=100, integrator='idas',integrator_options=int_ops)
Constraint 1: 0.010000000000000009 Constraint 2: 0.1 Constraint 3: 0.0
psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed The residual routine or the linear setup or solve routine had a recoverable error, but IDACalcIC was unable to recover.
--------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) <ipython-input-5-d7e5a0955a84> in <module> 17 18 # Simulator ---> 19 tsim, profiles = sim.simulate(numpoints=100, integrator='idas',integrator_options=int_ops) /anaconda3/envs/spring2021/lib/python3.8/site-packages/pyomo/dae/simulator.py in simulate(self, numpoints, tstep, integrator, varying_inputs, initcon, integrator_options) 905 else: 906 tsim, profile = \ --> 907 self._simulate_with_casadi_no_inputs(initcon, tsim, 908 integrator, 909 integrator_options) /anaconda3/envs/spring2021/lib/python3.8/site-packages/pyomo/dae/simulator.py in _simulate_with_casadi_no_inputs(self, initcon, tsim, integrator, integrator_options) 967 integrator_options['output_t0'] = True 968 F = casadi.integrator('F', integrator, dae, integrator_options) --> 969 sol = F(x0=initcon) 970 profile = sol['xf'].full().T 971 /anaconda3/envs/spring2021/lib/python3.8/site-packages/casadi/casadi.py in __call__(self, *args, **kwargs) 13451 else: 13452 # Named inputs -> return dictionary > 13453 return self.call(kwargs) 13454 13455 def buffer(self): /anaconda3/envs/spring2021/lib/python3.8/site-packages/casadi/casadi.py in call(self, *args) 12322 12323 """ > 12324 return _casadi.Function_call(self, *args) 12325 12326 RuntimeError: .../casadi/interfaces/sundials/idas_interface.cpp:591: IDACalcIC returned "IDA_NO_RECOVERY". Consult IDAS documentation.
Our initial point does not satisfy the algebraic constraints! We need a consistent initial point.
Given $x = \epsilon$, solve $x^2 + y^2 = 1$ for $y$:
$$ y = \sqrt{1^2 - \epsilon^2}$$Then, assume $u = 1$ and solve $2 x u + 2 y v = 0$ for $v$:
$$v = \frac{-x u}{y}$$Finally, we can solve $(u^2 + v^2) - T (x^2 + y^2) + g y = 0$ for $T$:
$$ T = \frac{(u^2 + v^2) + gy}{x^2 + y^2} = \frac{(u^2 + v^2) + gy}{1} $$index1_take_two = create_model_index1()
# Specify alternative initial conditions
small_number = 0.1
index1_take_two.x[0] = small_number
index1_take_two.y[0] = np.sqrt(1 - small_number**2)
index1_take_two.u[0] = 1
index1_take_two.v[0] = -index1_take_two.x[0]()*index1_take_two.u[0]()/index1_take_two.y[0]()
index1_take_two.T[0] = (index1_take_two.u[0]()**2 + index1_take_two.v[0]()**2
+ index1_take_two.g*index1_take_two.y[0]())
# Check initial condition
index1_check_constraints(index1_take_two)
# Solve DAEs
sim = Simulator(index1_take_two, package='casadi')
# Specify integrator options
int_ops2 = {'print_stats':True,"abstol":1E-6,"reltol":1E-4,
"verbose":False,"calc_ic":True}
# Simulator
tsim, profiles = sim.simulate(numpoints=20, integrator='idas',integrator_options=int_ops2)
Constraint 1: 0.0 Constraint 2: 0.0 Constraint 3: 0.0
psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed psetup failed: .../casadi/interfaces/sundials/idas_interface.cpp:852: Linear solve failed The residual routine or the linear setup or solve routine had a recoverable error, but IDACalcIC was unable to recover.
--------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) <ipython-input-6-1f152c98c30e> in <module> 22 23 # Simulator ---> 24 tsim, profiles = sim.simulate(numpoints=20, integrator='idas',integrator_options=int_ops2) /anaconda3/envs/spring2021/lib/python3.8/site-packages/pyomo/dae/simulator.py in simulate(self, numpoints, tstep, integrator, varying_inputs, initcon, integrator_options) 905 else: 906 tsim, profile = \ --> 907 self._simulate_with_casadi_no_inputs(initcon, tsim, 908 integrator, 909 integrator_options) /anaconda3/envs/spring2021/lib/python3.8/site-packages/pyomo/dae/simulator.py in _simulate_with_casadi_no_inputs(self, initcon, tsim, integrator, integrator_options) 967 integrator_options['output_t0'] = True 968 F = casadi.integrator('F', integrator, dae, integrator_options) --> 969 sol = F(x0=initcon) 970 profile = sol['xf'].full().T 971 /anaconda3/envs/spring2021/lib/python3.8/site-packages/casadi/casadi.py in __call__(self, *args, **kwargs) 13451 else: 13452 # Named inputs -> return dictionary > 13453 return self.call(kwargs) 13454 13455 def buffer(self): /anaconda3/envs/spring2021/lib/python3.8/site-packages/casadi/casadi.py in call(self, *args) 12322 12323 """ > 12324 return _casadi.Function_call(self, *args) 12325 12326 RuntimeError: .../casadi/interfaces/sundials/idas_interface.cpp:591: IDACalcIC returned "IDA_NO_RECOVERY". Consult IDAS documentation.
Consistent initial conditions:
def create_model_index1_b():
m = ConcreteModel()
# Declare time
m.t = ContinuousSet(bounds=(0.0, 5))
# Declare parameter - acceleration due to gravity
m.g = Param(initialize=9.81) # m/s^2
# Declare variables indexed over time
m.x = Var(m.t) # horizontal position
m.y = Var(m.t) # vertical position
m.u = Var(m.t) # horizontal velocity
m.v = Var(m.t) # vertical velocity
m.T = Var(m.t) # tension
# Declare derivative variables
m.dx = DerivativeVar(m.x) # with respect to t is implied
m.dy = DerivativeVar(m.y)
m.du = DerivativeVar(m.u)
m.dv = DerivativeVar(m.v)
# Declare differential equations
def _dx_eqn(m, t):
return m.dx[t] == m.u[t]
m.dx_eqn = Constraint(m.t, rule=_dx_eqn)
def _dy_eqn(m, t):
return m.dy[t] == m.v[t]
m.dy_eqn = Constraint(m.t, rule=_dy_eqn)
def _du_eqn(m, t):
return m.du[t] == -m.T[t]*m.x[t]
m.du_eqn = Constraint(m.t, rule=_du_eqn)
def _dv_eqn(m, t):
return m.dv[t] == m.g -m.T[t]*m.y[t]
m.dv_eqn = Constraint(m.t, rule=_dv_eqn)
def _alg_eqn3(m, t):
return m.u[t]**2 + m.v[t]**2 - m.T[t]*(m.x[t]**2 + m.y[t]**2) + m.g*m.y[t] == 0
m.alg_eqn3 = Constraint(m.t, rule=_alg_eqn3)
# Specify initial conditions
m.x[0] = 0
m.y[0] = 1
m.u[0] = 1
m.v[0] = 0
m.T[0] = 1 + m.g
return m
index1_b = create_model_index1_b()
# Specify integrator options
int_ops = {'print_stats':True,"abstol":1E-8,"reltol":1E-6}
# Solve DAEs
sim = Simulator(index1_b, package='casadi')
tsim, profiles = sim.simulate(numpoints=100, integrator='idas',integrator_options=int_ops)
# Plot solution
plot_results(sim, tsim, profiles)
FORWARD INTEGRATION: Number of steps taken by SUNDIALS: 379 Number of calls to the user’s f function: 485 Number of calls made to the linear solver setup function: 31 Number of error test failures: 3 Method order used on the last internal step: 5 Method order to be used on the next internal step: 5 Actual value of initial step size: 7.90569e-09 Step size taken on the last internal step: 0.0120795 Step size to be attempted on the next internal step: 0.0120795 Current internal time reached: 0.0120795 Number of nonlinear iterations performed: 483 Number of nonlinear convergence failures: 0