{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": [
"remove-input",
"active-ipynb",
"remove-output"
]
},
"outputs": [],
"source": [
"try:\n",
" from openmdao.utils.notebook_utils import notebook_mode\n",
"except ImportError:\n",
" !python -m pip install openmdao[notebooks]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# The Newton Solver Isn’t Converging\n",
"\n",
"If you think that the [NewtonSolver](../building_blocks/solvers/newton.ipynb) is not properly converging your model, then there are several things you can do to debug it. The very first thing you need to do is set [iprint=2](../core_features/controlling_solver_behavior/solver_options) on the solver so you can see what is actually going on.\n",
"\n",
"There are two broad reasons why [NewtonSolver](../building_blocks/solvers/newton.ipynb) might fail:\n",
"\n",
" - The linear solver isn’t able to solve for an update step\n",
" - The nonlinear solver is not able to find a solution\n",
"\n",
"## Failing Linear Solve\n",
"\n",
"Before you try any other debugging method, you need to check to make sure that you’ve correctly defined all the partial derivatives in all components inside the relevant group. You can use the [check_partials()](../core_features/working_with_derivatives/basic_check_partials.ipynb) method to have OpenMDAO compare your analytic derivatives against finite-difference or complex-step approximations.\n",
"\n",
"\n",
"### Iterative Linear Solvers\n",
"\n",
"If you are using one of the iterative linear solvers (e.g. [PETScKrylov](../building_blocks/solvers/petsc_krylov.ipynb), [ScipyKrylov](../building_blocks/solvers/scipy_iter_solver.ipynb)), try switching to the [DirectSolver](../building_blocks/solvers/direct_solver.ipynb) instead. This solver will compute an LU factorization and then use it to solve for the Newton update. Alternatively, you could try adding the [DirectSolver](../building_blocks/solvers/direct_solver.ipynb) as a [preconditioner](petsckrylov-precon) on one of the Krylov solvers.\n",
"\n",
"You should set [options['iprint']=2](../core_features/controlling_solver_behavior/solver_options) setting on any iterative linear solver. You can use the [set_solver_print](solver-options-set_solver-print) helper method to set `iprint` on every solver in the model.\n",
"\n",
"\n",
"### Direct Linear Solver\n",
"\n",
"If you are seeing `NAN` in the output, then you need to resolve that. You can’t have `NAN` values in either the residual calculation or any of the partial derivative values.\n",
"\n",
"If you are getting errors complaining about `Singular Matrix`, then you have at least one row or column of your Jacobian that has all zeros in it. This can be caused by several different things:\n",
"\n",
" - You did run [check_partials()](../core_features/working_with_derivatives/basic_check_partials.ipynb), right?!!!\n",
" - Check for missing or incorrect data connections to one or more components.\n",
" - Use the [N2 diagram](om-command-n2) to inspect your model hierarchy and connections in a matrix format.\n",
" - Use the [connection viewer](om-command-view-connections) in a list format.\n",
" - Use [list_outputs()](list-inputs) to look at the state variable values and see if anything has taken on a bad value (e.g. 0 or 1e500) that causes the derivative to be ill-defined.\n",
" - Seriously, run [check_partials()](../core_features/working_with_derivatives/basic_check_partials.ipynb) and look carefully at the output!\n",
"\n",
"\n",
"## Failing Nonlinear Solve\n",
"\n",
"Sometimes the linear solver is working fine, but the solver just cannot find the right answer. There are a number of things to look at at this point.\n",
"\n",
"\n",
"### Bad initial guess\n",
"\n",
"Newton solvers are notorious for requiring a reasonably good starting guess in order to converge. Try turning on the [solve_subsystems](../building_blocks/solvers/newton.ipynb) option. This lets the components in the model help the Newton solver out by providing better values for some of the variables via the `compute` and `solve_nonlinear` methods on `ExplicitComponent` and `ImplicitComponent` respectively. If all the components in your system are explicit, you probably want to turn this on.\n",
"\n",
"If the initial residual value is massive (set [options['iprint']=2](../core_features/controlling_solver_behavior/solver_options), so you can see the residuals), set [options['maxiter']=0](../building_blocks/solvers/newton.ipynb) and then call [run_model()](../core_features/running_your_models/run_model.ipynb). This will let you see what the solver sees as values and residuals at the very start. Then call [list_outputs()](listing_variables) to take a look at which residuals are way off and try to give a better guess for the associated state variables.\n",
"\n",
"### Things to try to help convergence\n",
"\n",
" - You might need to give it more iterations ([maxiter](../building_blocks/solvers/newton.ipynb) option).\n",
" - The default value is 10, which is not enough for some models.\n",
" - You might need to use a [linesearch](linesearch-section) algorithm to help things behave better.\n",
"\n",
"### Use the BoundsEnforceLS line search to enforce upper and lower bounds\n",
"\n",
"Sometimes the Newton solver will take bad steps along the way to convergence. For example, you might have a pressure value in your model that needs to stay positive always. In that case you can [set upper and lower bounds](../core_features/working_with_components/continuous_variables.ipynb) on that specific output value and then add the [BoundsEnforceLS line search](../building_blocks/solvers/bounds_enforce.ipynb) to the newton solver so it will respect those bounds.\n",
"\n",
"### Check if you’re running into a variable bound\n",
"\n",
"If you’ve set the `lower` or `upper` bounds on any output values and added a [linesearch](linesearch-section) to the [NewtonSolver](../building_blocks/solvers/newton.ipynb), then the solver might be getting stuck on one of those bounds. You might want to try changing the [bounds enforcement method](../building_blocks/solvers/bounds_enforce.ipynb).\n",
"\n",
"It’s also possible that you have set the bound to be too restrictive. If you see many iterations where the residual norm isn’t changing at all, that is an indication that the Newton step is repeatedly bumping into the same bound over and over again. You can set [options['print_bound_enforce']=True](../building_blocks/solvers/bounds_enforce.ipynb) to have the linesearch report which variables are hitting their bounds.\n",
"\n",
"If you see that you are butting up against a variable bound, then you have to consider if that bound is really necessary. Sometimes a newton solver needs to pass through that invalid space on the way to finding the answer, and if can’t then it won’t be able to converge. If you have something like pressure, that really can’t be negative ever perhaps because you are taking a log of it, then you have no choice but to make a lower bound of 0. However, if you just set the bounds to be something that is physically realistic, its possible that the bounds are overly constrictive and you need to loosen them up in order to get convergence."
]
}
],
"metadata": {
"celltoolbar": "Tags",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
},
"orphan": true
},
"nbformat": 4,
"nbformat_minor": 4
}